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