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