github.com/wasbazi/deis@v1.7.1-0.20150609203025-5765871615de/deisctl/deisctl.go (about) 1 // +build !windows 2 3 package main 4 5 import ( 6 "fmt" 7 "os" 8 "strconv" 9 "strings" 10 11 "github.com/deis/deis/deisctl/backend/fleet" 12 "github.com/deis/deis/deisctl/client" 13 "github.com/deis/deis/deisctl/utils" 14 "github.com/deis/deis/version" 15 16 docopt "github.com/docopt/docopt-go" 17 ) 18 19 // main exits with the return value of Command(os.Args[1:]), deferring all logic to 20 // a func we can test. 21 func main() { 22 os.Exit(Command(nil)) 23 } 24 25 // Command executes the given deisctl command line. 26 func Command(argv []string) int { 27 deisctlMotd := utils.DeisIfy("Deis Control Utility") 28 usage := deisctlMotd + ` 29 Usage: deisctl [options] <command> [<args>...] 30 31 Commands, use "deisctl help <command>" to learn more: 32 install install components, or the entire platform 33 uninstall uninstall components 34 list list installed components 35 start start components 36 stop stop components 37 restart stop, then start components 38 scale grow or shrink the number of routers, registries or store gateways 39 journal print the log output of a component 40 config set platform or component values 41 refresh-units refresh unit files from GitHub 42 ssh open an interacive shell on a machine in the cluster 43 help show the help screen for a command 44 45 Options: 46 -h --help show this help screen 47 --endpoint=<url> etcd endpoint for fleet [default: http://127.0.0.1:4001] 48 --etcd-cafile=<path> etcd CA file authentication [default: ] 49 --etcd-certfile=<path> etcd cert file authentication [default: ] 50 --etcd-key-prefix=<path> keyspace for fleet data in etcd [default: /_coreos.com/fleet/] 51 --etcd-keyfile=<path> etcd key file authentication [default: ] 52 --known-hosts-file=<path> where to store remote fingerprints [default: ~/.ssh/known_hosts] 53 --request-timeout=<secs> seconds before a request is considered failed [default: 10.0] 54 --ssh-timeout=<secs> seconds before SSH connection is considered failed [default: 10.0] 55 --strict-host-key-checking verify SSH host keys [default: true] 56 --tunnel=<host> SSH tunnel for communication with fleet and etcd [default: ] 57 --version print the version of deisctl 58 ` 59 // pre-parse command-line arguments 60 argv, helpFlag := parseArgs(argv) 61 // give docopt an optional final false arg so it doesn't call os.Exit() 62 args, err := docopt.Parse(usage, argv, false, version.Version, true, false) 63 if err != nil || len(args) == 0 { 64 if helpFlag { 65 fmt.Print(usage) 66 return 0 67 } 68 return 1 69 } 70 command := args["<command>"] 71 setTunnel := true 72 // "--help" and "refresh-units" doesn't need SSH tunneling 73 if helpFlag || command == "refresh-units" { 74 setTunnel = false 75 } 76 setGlobalFlags(args, setTunnel) 77 // clean up the args so subcommands don't need to reparse them 78 argv = removeGlobalArgs(argv) 79 // construct a client 80 c, err := client.NewClient("fleet") 81 if err != nil { 82 fmt.Printf("Error: %v\n", err) 83 return 1 84 } 85 // Dispatch the command, passing the argv through so subcommands can 86 // re-parse it according to their usage strings. 87 switch command { 88 case "list": 89 err = c.List(argv) 90 case "scale": 91 err = c.Scale(argv) 92 case "start": 93 err = c.Start(argv) 94 case "restart": 95 err = c.Restart(argv) 96 case "stop": 97 err = c.Stop(argv) 98 case "status": 99 err = c.Status(argv) 100 case "journal": 101 err = c.Journal(argv) 102 case "install": 103 err = c.Install(argv) 104 case "uninstall": 105 err = c.Uninstall(argv) 106 case "config": 107 err = c.Config(argv) 108 case "refresh-units": 109 err = c.RefreshUnits(argv) 110 case "ssh": 111 err = c.SSH(argv) 112 case "help": 113 fmt.Print(usage) 114 return 0 115 default: 116 fmt.Println(`Found no matching command, try "deisctl help" 117 Usage: deisctl <command> [<args>...] [options]`) 118 return 1 119 } 120 if err != nil { 121 fmt.Printf("Error: %v\n", err) 122 return 1 123 } 124 return 0 125 } 126 127 // isGlobalArg returns true if a string looks like it is a global deisctl option flag, 128 // such as "--tunnel". 129 func isGlobalArg(arg string) bool { 130 prefixes := []string{ 131 "--endpoint=", 132 "--etcd-key-prefix=", 133 "--etcd-keyfile=", 134 "--etcd-certfile=", 135 "--etcd-cafile=", 136 // "--experimental-api=", 137 "--known-hosts-file=", 138 "--request-timeout=", 139 "--ssh-timeout=", 140 "--strict-host-key-checking=", 141 "--tunnel=", 142 } 143 for _, p := range prefixes { 144 if strings.HasPrefix(arg, p) { 145 return true 146 } 147 } 148 return false 149 } 150 151 // parseArgs returns the provided args with "--help" as the last arg if need be, 152 // and a boolean to indicate whether help was requested. 153 func parseArgs(argv []string) ([]string, bool) { 154 if argv == nil { 155 argv = os.Args[1:] 156 } 157 158 if len(argv) == 1 { 159 // rearrange "deisctl --help" as "deisctl help" 160 if argv[0] == "--help" || argv[0] == "-h" { 161 argv[0] = "help" 162 } 163 } 164 165 if len(argv) >= 2 { 166 // rearrange "deisctl help <command>" as "deisctl <command> --help" 167 if argv[0] == "help" || argv[0] == "--help" || argv[0] == "-h" { 168 argv = append(argv[1:], "--help") 169 } 170 } 171 172 helpFlag := false 173 for _, a := range argv { 174 if a == "help" || a == "--help" || a == "-h" { 175 helpFlag = true 176 break 177 } 178 } 179 180 return argv, helpFlag 181 } 182 183 // removeGlobalArgs returns the given args without any global option flags, to make 184 // re-parsing by subcommands easier. 185 func removeGlobalArgs(argv []string) []string { 186 var v []string 187 for _, a := range argv { 188 if !isGlobalArg(a) { 189 v = append(v, a) 190 } 191 } 192 return v 193 } 194 195 // setGlobalFlags sets fleet provider options based on deisctl global flags. 196 func setGlobalFlags(args map[string]interface{}, setTunnel bool) { 197 fleet.Flags.Endpoint = args["--endpoint"].(string) 198 fleet.Flags.EtcdKeyPrefix = args["--etcd-key-prefix"].(string) 199 fleet.Flags.EtcdKeyFile = args["--etcd-keyfile"].(string) 200 fleet.Flags.EtcdCertFile = args["--etcd-certfile"].(string) 201 fleet.Flags.EtcdCAFile = args["--etcd-cafile"].(string) 202 //fleet.Flags.UseAPI = args["--experimental-api"].(bool) 203 fleet.Flags.KnownHostsFile = args["--known-hosts-file"].(string) 204 fleet.Flags.StrictHostKeyChecking = args["--strict-host-key-checking"].(bool) 205 timeout, _ := strconv.ParseFloat(args["--request-timeout"].(string), 64) 206 fleet.Flags.RequestTimeout = timeout 207 sshTimeout, _ := strconv.ParseFloat(args["--ssh-timeout"].(string), 64) 208 fleet.Flags.SSHTimeout = sshTimeout 209 if setTunnel == true { 210 tunnel := args["--tunnel"].(string) 211 if tunnel != "" { 212 fleet.Flags.Tunnel = tunnel 213 } else { 214 fleet.Flags.Tunnel = os.Getenv("DEISCTL_TUNNEL") 215 } 216 } 217 }