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