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 }