github.com/greenboxal/deis@v1.12.1/deisctl/client/client.go (about)

     1  package client
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"strconv"
     8  
     9  	"github.com/deis/deis/deisctl/backend"
    10  	"github.com/deis/deis/deisctl/backend/fleet"
    11  	"github.com/deis/deis/deisctl/cmd"
    12  	"github.com/deis/deis/deisctl/config"
    13  	"github.com/deis/deis/deisctl/config/etcd"
    14  	"github.com/deis/deis/deisctl/units"
    15  
    16  	docopt "github.com/docopt/docopt-go"
    17  )
    18  
    19  // DeisCtlClient manages Deis components, configuration, and related tasks.
    20  type DeisCtlClient interface {
    21  	Config(argv []string) error
    22  	Install(argv []string) error
    23  	Journal(argv []string) error
    24  	List(argv []string) error
    25  	Machines(argv []string) error
    26  	RefreshUnits(argv []string) error
    27  	Restart(argv []string) error
    28  	Scale(argv []string) error
    29  	SSH(argv []string) error
    30  	Start(argv []string) error
    31  	Status(argv []string) error
    32  	Stop(argv []string) error
    33  	Uninstall(argv []string) error
    34  	UpgradePrep(argv []string) error
    35  	UpgradeTakeover(argv []string) error
    36  	RollingRestart(argv []string) error
    37  }
    38  
    39  // Client uses a backend to implement the DeisCtlClient interface.
    40  type Client struct {
    41  	Backend       backend.Backend
    42  	configBackend config.Backend
    43  }
    44  
    45  // NewClient returns a Client using the requested backend.
    46  // The only backend currently supported is "fleet".
    47  func NewClient(requestedBackend string) (*Client, error) {
    48  	var backend backend.Backend
    49  
    50  	cb, err := etcd.NewConfigBackend()
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  
    55  	if requestedBackend == "" {
    56  		requestedBackend = "fleet"
    57  	}
    58  
    59  	switch requestedBackend {
    60  	case "fleet":
    61  		b, err := fleet.NewClient(cb)
    62  		if err != nil {
    63  			return nil, err
    64  		}
    65  		backend = b
    66  	default:
    67  		return nil, errors.New("invalid backend")
    68  	}
    69  
    70  	return &Client{Backend: backend, configBackend: cb}, nil
    71  }
    72  
    73  // UpgradePrep prepares a running cluster to be upgraded
    74  func (c *Client) UpgradePrep(argv []string) error {
    75  	usage := `Prepare platform for graceful upgrade.
    76  
    77  Usage:
    78    deisctl upgrade-prep [--stateless]
    79  
    80  Options:
    81    --stateless  Use when the target platform is stateless
    82  `
    83  	args, err := docopt.Parse(usage, argv, true, "", false)
    84  	if err != nil {
    85  		return err
    86  	}
    87  
    88  	stateless, _ := args["--stateless"].(bool)
    89  
    90  	return cmd.UpgradePrep(stateless, c.Backend)
    91  }
    92  
    93  // UpgradeTakeover gracefully restarts a cluster prepared with upgrade-prep
    94  func (c *Client) UpgradeTakeover(argv []string) error {
    95  	usage := `Complete the upgrade of a prepped cluster.
    96  
    97  Usage:
    98    deisctl upgrade-takeover [--stateless]
    99  
   100  Options:
   101    --stateless  Use when the target platform is stateless
   102  `
   103  	args, err := docopt.Parse(usage, argv, true, "", false)
   104  	if err != nil {
   105  		return err
   106  	}
   107  
   108  	stateless, _ := args["--stateless"].(bool)
   109  
   110  	return cmd.UpgradeTakeover(stateless, c.Backend, c.configBackend)
   111  }
   112  
   113  // RollingRestart attempts a rolling restart of an instance unit
   114  func (c *Client) RollingRestart(argv []string) error {
   115  	usage := `Perform a rolling restart of an instance unit.
   116  
   117  Usage:
   118    deisctl rolling-restart <target>
   119  `
   120  	args, err := docopt.Parse(usage, argv, true, "", false)
   121  	if err != nil {
   122  		return err
   123  	}
   124  
   125  	return cmd.RollingRestart(args["<target>"].(string), c.Backend)
   126  }
   127  
   128  // Config gets or sets a configuration value from the cluster.
   129  //
   130  // A configuration value is stored and retrieved from a key/value store (in this case, etcd)
   131  // at /deis/<component>/<config>. Configuration values are typically used for component-level
   132  // configuration, such as enabling TLS for the routers.
   133  func (c *Client) Config(argv []string) error {
   134  	usage := `Gets or sets a configuration value from the cluster.
   135  
   136  A configuration value is stored and retrieved from a key/value store
   137  (in this case, etcd) at /deis/<component>/<config>. Configuration
   138  values are typically used for component-level configuration, such as
   139  enabling TLS for the routers.
   140  
   141  Note: "deisctl config platform set sshPrivateKey=" expects a path
   142  to a private key.
   143  
   144  Usage:
   145    deisctl config <target> get [<key>...]
   146    deisctl config <target> set <key=val>...
   147    deisctl config <target> rm [<key>...]
   148  
   149  Examples:
   150    deisctl config platform set domain=mydomain.com
   151    deisctl config platform set sshPrivateKey=$HOME/.ssh/deis
   152    deisctl config controller get webEnabled
   153    deisctl config controller rm webEnabled
   154  `
   155  	// parse command-line arguments
   156  	args, err := docopt.Parse(usage, argv, true, "", false)
   157  	if err != nil {
   158  		return err
   159  	}
   160  
   161  	var action string
   162  	var key []string
   163  
   164  	switch {
   165  	case args["set"] == true:
   166  		action = "set"
   167  		key = args["<key=val>"].([]string)
   168  	case args["rm"] == true:
   169  		action = "rm"
   170  		key = args["<key>"].([]string)
   171  	default:
   172  		action = "get"
   173  		key = args["<key>"].([]string)
   174  	}
   175  
   176  	return cmd.Config(args["<target>"].(string), action, key, c.configBackend)
   177  }
   178  
   179  // Install loads the definitions of components from local unit files.
   180  // After Install, the components will be available to Start.
   181  func (c *Client) Install(argv []string) error {
   182  	usage := fmt.Sprintf(`Loads the definitions of components from local unit files.
   183  
   184  After install, the components will be available to start.
   185  
   186  "deisctl install" looks for unit files in these directories, in this order:
   187  - the $DEISCTL_UNITS environment variable, if set
   188  - $HOME/.deis/units
   189  - /var/lib/deis/units
   190  
   191  Usage:
   192    deisctl install [<target>...] [options]
   193  
   194  Options:
   195    --router-mesh-size=<num>  Number of routers to be loaded when installing the platform [default: %d].
   196  `, cmd.DefaultRouterMeshSize)
   197  	// parse command-line arguments
   198  	args, err := docopt.Parse(usage, argv, true, "", false)
   199  	if err != nil {
   200  		return err
   201  	}
   202  
   203  	meshSizeArg, _ := args["--router-mesh-size"].(string)
   204  	parsedValue, err := strconv.ParseUint(meshSizeArg, 0, 8)
   205  	if err != nil || parsedValue < 1 {
   206  		fmt.Print("Error: argument --router-mesh-size: invalid value, make sure the value is an integer between 1 and 255.\n")
   207  		return err
   208  	}
   209  	cmd.RouterMeshSize = uint8(parsedValue)
   210  
   211  	return cmd.Install(args["<target>"].([]string), c.Backend, c.configBackend, cmd.CheckRequiredKeys)
   212  }
   213  
   214  // Journal prints log output for the specified components.
   215  func (c *Client) Journal(argv []string) error {
   216  	usage := `Prints log output for the specified components.
   217  
   218  Usage:
   219    deisctl journal [<target>...]
   220  `
   221  	// parse command-line arguments
   222  	args, err := docopt.Parse(usage, argv, true, "", false)
   223  	if err != nil {
   224  		return err
   225  	}
   226  
   227  	return cmd.Journal(args["<target>"].([]string), c.Backend)
   228  }
   229  
   230  // List prints a summary of installed components.
   231  func (c *Client) List(argv []string) error {
   232  	usage := `Prints a list of installed units.
   233  
   234  Usage:
   235    deisctl list
   236  `
   237  	// parse command-line arguments
   238  	if _, err := docopt.Parse(usage, argv, true, "", false); err != nil {
   239  		return err
   240  	}
   241  	return cmd.ListUnits(c.Backend)
   242  }
   243  
   244  func (c *Client) Machines(argv []string) error {
   245  	usage := `List the current hosts in the cluster
   246  
   247  
   248  Usage:
   249    deisctl machines
   250  `
   251  	// parse command-line arguments
   252  	if _, err := docopt.Parse(usage, argv, true, "", false); err != nil {
   253  		return err
   254  	}
   255  	return cmd.ListMachines(c.Backend)
   256  }
   257  
   258  // RefreshUnits overwrites local unit files with those requested.
   259  func (c *Client) RefreshUnits(argv []string) error {
   260  	usage := `Overwrites local unit files with those requested.
   261  
   262  Downloading from the Deis project GitHub URL by tag or SHA is the only mechanism
   263  currently supported.
   264  
   265  "deisctl install" looks for unit files in these directories, in this order:
   266  - the $DEISCTL_UNITS environment variable, if set
   267  - $HOME/.deis/units
   268  - /var/lib/deis/units
   269  
   270  Usage:
   271    deisctl refresh-units [-p <target>] [-t <tag>]
   272  
   273  Options:
   274    -p --path=<target>   where to save unit files [default: $HOME/.deis/units]
   275    -t --tag=<tag>       git tag, branch, or SHA to use when downloading unit files
   276                         [default: v1.12.1]
   277  `
   278  	// parse command-line arguments
   279  	args, err := docopt.Parse(usage, argv, true, "", false)
   280  	if err != nil {
   281  		fmt.Printf("Error: %v\n", err)
   282  		os.Exit(2)
   283  	}
   284  
   285  	return cmd.RefreshUnits(args["--path"].(string), args["--tag"].(string), units.URL)
   286  }
   287  
   288  // Restart stops and then starts components.
   289  func (c *Client) Restart(argv []string) error {
   290  	usage := `Stops and then starts the specified components.
   291  
   292  Usage:
   293    deisctl restart [<target>...]
   294  `
   295  	// parse command-line arguments
   296  	args, err := docopt.Parse(usage, argv, true, "", false)
   297  	if err != nil {
   298  		return err
   299  	}
   300  
   301  	return cmd.Restart(args["<target>"].([]string), c.Backend)
   302  }
   303  
   304  // Scale grows or shrinks the number of running components.
   305  func (c *Client) Scale(argv []string) error {
   306  	usage := `Grows or shrinks the number of running components.
   307  
   308  Currently "router", "registry" and "store-gateway" are the only types that can be scaled.
   309  
   310  Usage:
   311    deisctl scale [<target>...]
   312  `
   313  	// parse command-line arguments
   314  	args, err := docopt.Parse(usage, argv, true, "", false)
   315  	if err != nil {
   316  		return err
   317  	}
   318  
   319  	return cmd.Scale(args["<target>"].([]string), c.Backend)
   320  }
   321  
   322  // SSH opens an interactive shell with a machine in the cluster.
   323  func (c *Client) SSH(argv []string) error {
   324  	usage := `Open an interactive shell on a machine in the cluster given a unit or machine id.
   325  
   326  If an optional <command> is provided, that command is run remotely, and the results returned.
   327  
   328  Usage:
   329    deisctl ssh <target> [<command>...]
   330  `
   331  	// parse command-line arguments
   332  	args, err := docopt.Parse(usage, argv, true, "", true)
   333  	if err != nil {
   334  		return err
   335  	}
   336  
   337  	target := args["<target>"].(string)
   338  	// handle help explicitly since docopt parsing is relaxed
   339  	if target == "--help" {
   340  		fmt.Println(usage)
   341  		os.Exit(0)
   342  	}
   343  
   344  	var vargs []string
   345  	if v, ok := args["<command>"]; ok {
   346  		vargs = v.([]string)
   347  	}
   348  
   349  	return cmd.SSH(target, vargs, c.Backend)
   350  }
   351  
   352  func (c *Client) Dock(argv []string) error {
   353  	usage := `Connect to the named docker container and run commands on it.
   354  
   355  This is equivalent to running 'docker exec -it <target> <command>'.
   356  
   357  Usage:
   358    deisctl dock <target> [<command>...]
   359  `
   360  	// parse command-line arguments
   361  	args, err := docopt.Parse(usage, argv, true, "", true)
   362  	if err != nil {
   363  		return err
   364  	}
   365  
   366  	target := args["<target>"].(string)
   367  	// handle help explicitly since docopt parsing is relaxed
   368  	if target == "--help" {
   369  		fmt.Println(usage)
   370  		os.Exit(0)
   371  	}
   372  
   373  	var vargs []string
   374  	if v, ok := args["<command>"]; ok {
   375  		vargs = v.([]string)
   376  	}
   377  
   378  	return cmd.Dock(target, vargs, c.Backend)
   379  }
   380  
   381  // Start activates the specified components.
   382  func (c *Client) Start(argv []string) error {
   383  	usage := `Activates the specified components.
   384  
   385  Usage:
   386    deisctl start [<target>...]
   387  `
   388  	// parse command-line arguments
   389  	args, err := docopt.Parse(usage, argv, true, "", false)
   390  	if err != nil {
   391  		return err
   392  	}
   393  
   394  	return cmd.Start(args["<target>"].([]string), c.Backend)
   395  }
   396  
   397  // Status prints the current status of components.
   398  func (c *Client) Status(argv []string) error {
   399  	usage := `Prints the current status of components.
   400  
   401  Usage:
   402    deisctl status [<target>...]
   403  `
   404  	// parse command-line arguments
   405  	args, err := docopt.Parse(usage, argv, true, "", false)
   406  	if err != nil {
   407  		return err
   408  	}
   409  
   410  	return cmd.Status(args["<target>"].([]string), c.Backend)
   411  }
   412  
   413  // Stop deactivates the specified components.
   414  func (c *Client) Stop(argv []string) error {
   415  	usage := `Deactivates the specified components.
   416  
   417  Usage:
   418    deisctl stop [<target>...]
   419  `
   420  	// parse command-line arguments
   421  	args, err := docopt.Parse(usage, argv, true, "", false)
   422  	if err != nil {
   423  		return err
   424  	}
   425  
   426  	return cmd.Stop(args["<target>"].([]string), c.Backend)
   427  }
   428  
   429  // Uninstall unloads the definitions of the specified components.
   430  // After Uninstall, the components will be unavailable until Install is called.
   431  func (c *Client) Uninstall(argv []string) error {
   432  	usage := `Unloads the definitions of the specified components.
   433  
   434  After uninstall, the components will be unavailable until install is called.
   435  
   436  Usage:
   437    deisctl uninstall [<target>...]
   438  `
   439  	// parse command-line arguments
   440  	args, err := docopt.Parse(usage, argv, true, "", false)
   441  	if err != nil {
   442  		return err
   443  	}
   444  
   445  	return cmd.Uninstall(args["<target>"].([]string), c.Backend)
   446  }