github.com/vmware/govmomi@v0.43.0/govc/cli/command.go (about) 1 /* 2 Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package cli 18 19 import ( 20 "context" 21 "flag" 22 "fmt" 23 "io" 24 "os" 25 "path/filepath" 26 "sort" 27 "strings" 28 "text/tabwriter" 29 30 "github.com/vmware/govmomi/vim25/types" 31 ) 32 33 type HasFlags interface { 34 // Register may be called more than once and should be idempotent. 35 Register(ctx context.Context, f *flag.FlagSet) 36 37 // Process may be called more than once and should be idempotent. 38 Process(ctx context.Context) error 39 } 40 41 type Command interface { 42 HasFlags 43 44 Run(ctx context.Context, f *flag.FlagSet) error 45 } 46 47 func generalHelp(w io.Writer, filter string) { 48 var cmds, matches []string 49 for name := range commands { 50 cmds = append(cmds, name) 51 52 if filter != "" && strings.Contains(name, filter) { 53 matches = append(matches, name) 54 } 55 } 56 57 if len(matches) == 0 { 58 fmt.Fprintf(w, `Usage: %[1]s <COMMAND> [COMMON OPTIONS] [PATH]... 59 60 govmomi is a Go library for interacting with VMware vSphere APIs (ESXi and/or 61 vCenter Server). 62 It is licensed under the Apache License, Version 2.0 63 64 %[1]s is the CLI for govmomi. 65 66 The available commands are listed below. A detailed description of each 67 command can be displayed with "govc <COMMAND> -h". The description of all 68 commands can be also found at https://via.vmw.com/GJ98hk . 69 70 Examples: 71 show usage of a command: govc <COMMAND> -h 72 show toplevel structure: govc ls 73 show datacenter summary: govc datacenter.info 74 show all VMs: govc find -type m 75 upload a ISO file: govc datastore.upload -ds datastore1 ./config.iso vm-name/config.iso 76 77 Common options: 78 -h Show this message 79 -cert= Certificate [GOVC_CERTIFICATE] 80 -debug=false Store debug logs [GOVC_DEBUG] 81 -trace=false Write SOAP/REST traffic to stderr 82 -verbose=false Write request/response data to stderr 83 -dump=false Enable output dump 84 -json=false Enable JSON output 85 -xml=false Enable XML output 86 -k=false Skip verification of server certificate [GOVC_INSECURE] 87 -key= Private key [GOVC_PRIVATE_KEY] 88 -persist-session=true Persist session to disk [GOVC_PERSIST_SESSION] 89 -tls-ca-certs= TLS CA certificates file [GOVC_TLS_CA_CERTS] 90 -tls-known-hosts= TLS known hosts file [GOVC_TLS_KNOWN_HOSTS] 91 -u= ESX or vCenter URL [GOVC_URL] 92 -vim-namespace=urn:vim25 Vim namespace [GOVC_VIM_NAMESPACE] 93 -vim-version=6.0 Vim version [GOVC_VIM_VERSION] 94 -dc= Datacenter [GOVC_DATACENTER] 95 -host.dns= Find host by FQDN 96 -host.ip= Find host by IP address 97 -host.ipath= Find host by inventory path 98 -host.uuid= Find host by UUID 99 -vm.dns= Find VM by FQDN 100 -vm.ip= Find VM by IP address 101 -vm.ipath= Find VM by inventory path 102 -vm.path= Find VM by path to .vmx file 103 -vm.uuid= Find VM by UUID 104 105 Available commands: 106 `, filepath.Base(os.Args[0])) 107 108 } else { 109 fmt.Fprintf(w, "%s: command '%s' not found, did you mean:\n", os.Args[0], filter) 110 cmds = matches 111 } 112 113 sort.Strings(cmds) 114 for _, name := range cmds { 115 fmt.Fprintf(w, " %s\n", name) 116 } 117 } 118 119 func commandHelp(w io.Writer, name string, cmd Command, f *flag.FlagSet) { 120 type HasUsage interface { 121 Usage() string 122 } 123 124 fmt.Fprintf(w, "Usage: %s %s [OPTIONS]", os.Args[0], name) 125 if u, ok := cmd.(HasUsage); ok { 126 fmt.Fprintf(w, " %s", u.Usage()) 127 } 128 fmt.Fprintf(w, "\n") 129 130 type HasDescription interface { 131 Description() string 132 } 133 134 if u, ok := cmd.(HasDescription); ok { 135 fmt.Fprintf(w, "\n%s\n", u.Description()) 136 } 137 138 n := 0 139 f.VisitAll(func(_ *flag.Flag) { 140 n += 1 141 }) 142 143 if n > 0 { 144 fmt.Fprintf(w, "\nOptions:\n") 145 tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0) 146 f.VisitAll(func(f *flag.Flag) { 147 fmt.Fprintf(tw, "\t-%s=%s\t%s\n", f.Name, f.DefValue, f.Usage) 148 }) 149 tw.Flush() 150 } 151 } 152 153 func clientLogout(ctx context.Context, cmd Command) error { 154 type logout interface { 155 Logout(context.Context) error 156 } 157 158 if l, ok := cmd.(logout); ok { 159 return l.Logout(ctx) 160 } 161 162 return nil 163 } 164 165 func Run(args []string) int { 166 hw := os.Stderr 167 rc := 1 168 hwrc := func(arg string) { 169 arg = strings.TrimLeft(arg, "-") 170 if arg == "h" || arg == "help" { 171 hw = os.Stdout 172 rc = 0 173 } 174 } 175 176 var err error 177 178 if len(args) == 0 { 179 generalHelp(hw, "") 180 return rc 181 } 182 183 // Look up real command name in aliases table. 184 name, ok := aliases[args[0]] 185 if !ok { 186 name = args[0] 187 } 188 189 cmd, ok := commands[name] 190 if !ok { 191 hwrc(name) 192 generalHelp(hw, name) 193 return rc 194 } 195 196 fs := flag.NewFlagSet("", flag.ContinueOnError) 197 fs.SetOutput(io.Discard) 198 199 ctx := context.Background() 200 201 if id := os.Getenv("GOVC_OPERATION_ID"); id != "" { 202 ctx = context.WithValue(ctx, types.ID{}, id) 203 } 204 205 cmd.Register(ctx, fs) 206 207 if err = fs.Parse(args[1:]); err != nil { 208 goto error 209 } 210 211 if err = cmd.Process(ctx); err != nil { 212 goto error 213 } 214 215 if err = cmd.Run(ctx, fs); err != nil { 216 goto error 217 } 218 219 if err = clientLogout(ctx, cmd); err != nil { 220 goto error 221 } 222 223 return 0 224 225 error: 226 if err == flag.ErrHelp { 227 if len(args) == 2 { 228 hwrc(args[1]) 229 } 230 commandHelp(hw, args[0], cmd, fs) 231 } else { 232 if x, ok := err.(interface{ ExitCode() int }); ok { 233 // propagate exit code, e.g. from guest.run 234 rc = x.ExitCode() 235 } else { 236 w, ok := cmd.(interface{ WriteError(error) bool }) 237 if ok { 238 ok = w.WriteError(err) 239 } 240 if !ok { 241 fmt.Fprintf(os.Stderr, "%s: %s\n", os.Args[0], err) 242 } 243 } 244 } 245 246 _ = clientLogout(ctx, cmd) 247 248 return rc 249 }