github.com/didip/deis@v1.4.1/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 help show the help screen for a command 43 44 Options: 45 -h --help show this help screen 46 --endpoint=<url> etcd endpoint for fleet [default: http://127.0.0.1:4001] 47 --etcd-cafile=<path> etcd CA file authentication [default: ] 48 --etcd-certfile=<path> etcd cert file authentication [default: ] 49 --etcd-key-prefix=<path> keyspace for fleet data in etcd [default: /_coreos.com/fleet/] 50 --etcd-keyfile=<path> etcd key file authentication [default: ] 51 --known-hosts-file=<path> where to store remote fingerprints [default: ~/.ssh/known_hosts] 52 --request-timeout=<secs> seconds before a request is considered failed [default: 10.0] 53 --ssh-timeout=<secs> seconds before SSH connection is considered failed [default: 10.0] 54 --strict-host-key-checking verify SSH host keys [default: true] 55 --tunnel=<host> SSH tunnel for communication with fleet and etcd [default: ] 56 --version print the version of deisctl 57 ` 58 // pre-parse command-line arguments 59 argv, helpFlag := parseArgs(argv) 60 // give docopt an optional final false arg so it doesn't call os.Exit() 61 args, err := docopt.Parse(usage, argv, false, version.Version, true, false) 62 if err != nil || len(args) == 0 { 63 if helpFlag { 64 fmt.Print(usage) 65 return 0 66 } 67 return 1 68 } 69 command := args["<command>"] 70 setTunnel := true 71 // "--help" and "refresh-units" doesn't need SSH tunneling 72 if helpFlag || command == "refresh-units" { 73 setTunnel = false 74 } 75 setGlobalFlags(args, setTunnel) 76 // clean up the args so subcommands don't need to reparse them 77 argv = removeGlobalArgs(argv) 78 // construct a client 79 c, err := client.NewClient("fleet") 80 if err != nil { 81 fmt.Printf("Error: %v\n", err) 82 return 1 83 } 84 // Dispatch the command, passing the argv through so subcommands can 85 // re-parse it according to their usage strings. 86 switch command { 87 case "list": 88 err = c.List(argv) 89 case "scale": 90 err = c.Scale(argv) 91 case "start": 92 err = c.Start(argv) 93 case "restart": 94 err = c.Restart(argv) 95 case "stop": 96 err = c.Stop(argv) 97 case "status": 98 err = c.Status(argv) 99 case "journal": 100 err = c.Journal(argv) 101 case "install": 102 err = c.Install(argv) 103 case "uninstall": 104 err = c.Uninstall(argv) 105 case "config": 106 err = c.Config(argv) 107 case "refresh-units": 108 err = c.RefreshUnits(argv) 109 case "help": 110 fmt.Print(usage) 111 return 0 112 default: 113 fmt.Println(`Found no matching command, try "deisctl help" 114 Usage: deisctl <command> [<args>...] [options]`) 115 return 1 116 } 117 if err != nil { 118 fmt.Printf("Error: %v\n", err) 119 return 1 120 } 121 return 0 122 } 123 124 // isGlobalArg returns true if a string looks like it is a global deisctl option flag, 125 // such as "--tunnel". 126 func isGlobalArg(arg string) bool { 127 prefixes := []string{ 128 "--endpoint=", 129 "--etcd-key-prefix=", 130 "--etcd-keyfile=", 131 "--etcd-certfile=", 132 "--etcd-cafile=", 133 // "--experimental-api=", 134 "--known-hosts-file=", 135 "--request-timeout=", 136 "--ssh-timeout=", 137 "--strict-host-key-checking=", 138 "--tunnel=", 139 } 140 for _, p := range prefixes { 141 if strings.HasPrefix(arg, p) { 142 return true 143 } 144 } 145 return false 146 } 147 148 // parseArgs returns the provided args with "--help" as the last arg if need be, 149 // and a boolean to indicate whether help was requested. 150 func parseArgs(argv []string) ([]string, bool) { 151 if argv == nil { 152 argv = os.Args[1:] 153 } 154 155 if len(argv) == 1 { 156 // rearrange "deisctl --help" as "deisctl help" 157 if argv[0] == "--help" || argv[0] == "-h" { 158 argv[0] = "help" 159 } 160 } 161 162 if len(argv) >= 2 { 163 // rearrange "deisctl help <command>" as "deisctl <command> --help" 164 if argv[0] == "help" || argv[0] == "--help" || argv[0] == "-h" { 165 argv = append(argv[1:], "--help") 166 } 167 } 168 169 helpFlag := false 170 for _, a := range argv { 171 if a == "help" || a == "--help" || a == "-h" { 172 helpFlag = true 173 break 174 } 175 } 176 177 return argv, helpFlag 178 } 179 180 // removeGlobalArgs returns the given args without any global option flags, to make 181 // re-parsing by subcommands easier. 182 func removeGlobalArgs(argv []string) []string { 183 var v []string 184 for _, a := range argv { 185 if !isGlobalArg(a) { 186 v = append(v, a) 187 } 188 } 189 return v 190 } 191 192 // setGlobalFlags sets fleet provider options based on deisctl global flags. 193 func setGlobalFlags(args map[string]interface{}, setTunnel bool) { 194 fleet.Flags.Endpoint = args["--endpoint"].(string) 195 fleet.Flags.EtcdKeyPrefix = args["--etcd-key-prefix"].(string) 196 fleet.Flags.EtcdKeyFile = args["--etcd-keyfile"].(string) 197 fleet.Flags.EtcdCertFile = args["--etcd-certfile"].(string) 198 fleet.Flags.EtcdCAFile = args["--etcd-cafile"].(string) 199 //fleet.Flags.UseAPI = args["--experimental-api"].(bool) 200 fleet.Flags.KnownHostsFile = args["--known-hosts-file"].(string) 201 fleet.Flags.StrictHostKeyChecking = args["--strict-host-key-checking"].(bool) 202 timeout, _ := strconv.ParseFloat(args["--request-timeout"].(string), 64) 203 fleet.Flags.RequestTimeout = timeout 204 sshTimeout, _ := strconv.ParseFloat(args["--ssh-timeout"].(string), 64) 205 fleet.Flags.SSHTimeout = sshTimeout 206 if setTunnel == true { 207 tunnel := args["--tunnel"].(string) 208 if tunnel != "" { 209 fleet.Flags.Tunnel = tunnel 210 } else { 211 fleet.Flags.Tunnel = os.Getenv("DEISCTL_TUNNEL") 212 } 213 } 214 }