github.com/vmware/govmomi@v0.43.0/govc/host/esxcli/esxcli.go (about) 1 /* 2 Copyright (c) 2014-2023 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 esxcli 18 19 import ( 20 "context" 21 "errors" 22 "flag" 23 "fmt" 24 "io" 25 "sort" 26 "strings" 27 "text/tabwriter" 28 29 "github.com/vmware/govmomi/govc/cli" 30 "github.com/vmware/govmomi/govc/flags" 31 ) 32 33 type esxcli struct { 34 *flags.HostSystemFlag 35 36 hints bool 37 } 38 39 func init() { 40 cli.Register("host.esxcli", &esxcli{}) 41 } 42 43 func (cmd *esxcli) Usage() string { 44 return "COMMAND [ARG]..." 45 } 46 47 func (cmd *esxcli) Register(ctx context.Context, f *flag.FlagSet) { 48 cmd.HostSystemFlag, ctx = flags.NewHostSystemFlag(ctx) 49 cmd.HostSystemFlag.Register(ctx, f) 50 51 f.BoolVar(&cmd.hints, "hints", true, "Use command info hints when formatting output") 52 } 53 54 func (cmd *esxcli) Description() string { 55 return `Invoke esxcli command on HOST. 56 57 Output is rendered in table form when possible, unless disabled with '-hints=false'. 58 59 Examples: 60 govc host.esxcli network ip connection list 61 govc host.esxcli system settings advanced set -o /Net/GuestIPHack -i 1 62 govc host.esxcli network firewall ruleset set -r remoteSerialPort -e true 63 govc host.esxcli network firewall set -e false 64 govc host.esxcli hardware platform get` 65 } 66 67 func (cmd *esxcli) Process(ctx context.Context) error { 68 if err := cmd.HostSystemFlag.Process(ctx); err != nil { 69 return err 70 } 71 return nil 72 } 73 74 func (cmd *esxcli) Run(ctx context.Context, f *flag.FlagSet) error { 75 if f.NArg() == 0 { 76 return flag.ErrHelp 77 } 78 79 c, err := cmd.Client() 80 if err != nil { 81 return err 82 } 83 84 host, err := cmd.HostSystem() 85 if err != nil { 86 return err 87 } 88 89 e, err := NewExecutor(c, host) 90 if err != nil { 91 return err 92 } 93 94 res, err := e.Run(f.Args()) 95 if err != nil { 96 if f, ok := err.(*Fault); ok { 97 return errors.New(f.messageDetail()) 98 } 99 return err 100 } 101 102 if len(res.Values) == 0 { 103 if res.String != "" { 104 fmt.Print(res.String) 105 if !strings.HasSuffix(res.String, "\n") { 106 fmt.Println() 107 } 108 } 109 return nil 110 } 111 112 return cmd.WriteResult(&result{res, cmd}) 113 } 114 115 type result struct { 116 *Response 117 cmd *esxcli 118 } 119 120 func (r *result) Write(w io.Writer) error { 121 var formatType string 122 if r.cmd.hints { 123 formatType = r.Info.Hints.Formatter() 124 } 125 126 switch formatType { 127 case "table": 128 r.cmd.formatTable(w, r.Response) 129 default: 130 r.cmd.formatSimple(w, r.Response) 131 } 132 133 return nil 134 } 135 136 func (cmd *esxcli) formatSimple(w io.Writer, res *Response) { 137 var keys []string 138 for key := range res.Values[0] { 139 keys = append(keys, key) 140 } 141 sort.Strings(keys) 142 143 tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0) 144 145 for i, rv := range res.Values { 146 if i > 0 { 147 fmt.Fprintln(tw) 148 _ = tw.Flush() 149 } 150 for _, key := range keys { 151 fmt.Fprintf(tw, "%s:\t%s\n", key, strings.Join(rv[key], ", ")) 152 } 153 } 154 155 _ = tw.Flush() 156 } 157 158 func (cmd *esxcli) formatTable(w io.Writer, res *Response) { 159 fields := res.Info.Hints.Fields() 160 if len(fields) == 0 { 161 cmd.formatSimple(w, res) 162 return 163 } 164 tw := tabwriter.NewWriter(w, len(fields), 0, 2, ' ', 0) 165 166 var hr []string 167 for _, name := range fields { 168 hr = append(hr, strings.Repeat("-", len(name))) 169 } 170 171 fmt.Fprintln(tw, strings.Join(fields, "\t")) 172 fmt.Fprintln(tw, strings.Join(hr, "\t")) 173 174 for _, vals := range res.Values { 175 var row []string 176 177 for _, name := range fields { 178 key := strings.Replace(name, " ", "", -1) 179 if val, ok := vals[key]; ok { 180 row = append(row, strings.Join(val, ", ")) 181 } else { 182 row = append(row, "") 183 } 184 } 185 186 fmt.Fprintln(tw, strings.Join(row, "\t")) 187 } 188 189 _ = tw.Flush() 190 }