github.com/vmware/govmomi@v0.43.0/govc/flags/search.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 flags 18 19 import ( 20 "context" 21 "errors" 22 "flag" 23 "fmt" 24 "strings" 25 26 "github.com/vmware/govmomi/find" 27 "github.com/vmware/govmomi/object" 28 "github.com/vmware/govmomi/vim25" 29 "github.com/vmware/govmomi/vim25/soap" 30 "github.com/vmware/govmomi/vim25/types" 31 ) 32 33 const ( 34 SearchVirtualMachines = iota + 1 35 SearchHosts 36 SearchVirtualApps 37 ) 38 39 type SearchFlag struct { 40 common 41 42 *ClientFlag 43 *DatacenterFlag 44 45 t int 46 entity string 47 48 byDatastorePath string 49 byDNSName string 50 byInventoryPath string 51 byIP string 52 byUUID string 53 54 isset bool 55 } 56 57 func NewSearchFlag(ctx context.Context, t int) (*SearchFlag, context.Context) { 58 searchFlagKey := flagKey(fmt.Sprintf("search%d", t)) 59 60 if v := ctx.Value(searchFlagKey); v != nil { 61 return v.(*SearchFlag), ctx 62 } 63 64 v := &SearchFlag{ 65 t: t, 66 } 67 68 v.ClientFlag, ctx = NewClientFlag(ctx) 69 v.DatacenterFlag, ctx = NewDatacenterFlag(ctx) 70 71 switch t { 72 case SearchVirtualMachines: 73 v.entity = "VM" 74 case SearchHosts: 75 v.entity = "host" 76 case SearchVirtualApps: 77 v.entity = "vapp" 78 default: 79 panic("invalid search type") 80 } 81 82 ctx = context.WithValue(ctx, searchFlagKey, v) 83 return v, ctx 84 } 85 86 func (flag *SearchFlag) Register(ctx context.Context, fs *flag.FlagSet) { 87 flag.RegisterOnce(func() { 88 flag.ClientFlag.Register(ctx, fs) 89 flag.DatacenterFlag.Register(ctx, fs) 90 91 register := func(v *string, f string, d string) { 92 f = fmt.Sprintf("%s.%s", strings.ToLower(flag.entity), f) 93 d = fmt.Sprintf(d, flag.entity) 94 fs.StringVar(v, f, "", d) 95 } 96 97 switch flag.t { 98 case SearchVirtualMachines: 99 register(&flag.byDatastorePath, "path", "Find %s by path to .vmx file") 100 } 101 102 switch flag.t { 103 case SearchVirtualMachines, SearchHosts: 104 register(&flag.byDNSName, "dns", "Find %s by FQDN") 105 register(&flag.byIP, "ip", "Find %s by IP address") 106 register(&flag.byUUID, "uuid", "Find %s by UUID") 107 } 108 109 register(&flag.byInventoryPath, "ipath", "Find %s by inventory path") 110 }) 111 } 112 113 func (flag *SearchFlag) Process(ctx context.Context) error { 114 return flag.ProcessOnce(func() error { 115 if err := flag.ClientFlag.Process(ctx); err != nil { 116 return err 117 } 118 if err := flag.DatacenterFlag.Process(ctx); err != nil { 119 return err 120 } 121 122 flags := []string{ 123 flag.byDatastorePath, 124 flag.byDNSName, 125 flag.byInventoryPath, 126 flag.byIP, 127 flag.byUUID, 128 } 129 130 flag.isset = false 131 for _, f := range flags { 132 if f != "" { 133 if flag.isset { 134 return errors.New("cannot use more than one search flag") 135 } 136 flag.isset = true 137 } 138 } 139 140 return nil 141 }) 142 } 143 144 func (flag *SearchFlag) IsSet() bool { 145 return flag.isset 146 } 147 148 func (flag *SearchFlag) searchIndex(c *vim25.Client) *object.SearchIndex { 149 return object.NewSearchIndex(c) 150 } 151 152 func (flag *SearchFlag) searchByDatastorePath(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) { 153 ctx := context.TODO() 154 switch flag.t { 155 case SearchVirtualMachines: 156 return flag.searchIndex(c).FindByDatastorePath(ctx, dc, flag.byDatastorePath) 157 default: 158 panic("unsupported type") 159 } 160 } 161 162 func (flag *SearchFlag) searchByDNSName(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) { 163 ctx := context.TODO() 164 switch flag.t { 165 case SearchVirtualMachines: 166 return flag.searchIndex(c).FindByDnsName(ctx, dc, flag.byDNSName, true) 167 case SearchHosts: 168 return flag.searchIndex(c).FindByDnsName(ctx, dc, flag.byDNSName, false) 169 default: 170 panic("unsupported type") 171 } 172 } 173 174 func (flag *SearchFlag) searchByInventoryPath(c *vim25.Client) (object.Reference, error) { 175 ctx := context.TODO() 176 return flag.searchIndex(c).FindByInventoryPath(ctx, flag.byInventoryPath) 177 } 178 179 func (flag *SearchFlag) searchByIP(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) { 180 ctx := context.TODO() 181 switch flag.t { 182 case SearchVirtualMachines: 183 return flag.searchIndex(c).FindByIp(ctx, dc, flag.byIP, true) 184 case SearchHosts: 185 return flag.searchIndex(c).FindByIp(ctx, dc, flag.byIP, false) 186 default: 187 panic("unsupported type") 188 } 189 } 190 191 func (flag *SearchFlag) searchByUUID(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) { 192 ctx := context.TODO() 193 isVM := false 194 switch flag.t { 195 case SearchVirtualMachines: 196 isVM = true 197 case SearchHosts: 198 default: 199 panic("unsupported type") 200 } 201 202 var ref object.Reference 203 var err error 204 205 for _, iu := range []*bool{nil, types.NewBool(true)} { 206 ref, err = flag.searchIndex(c).FindByUuid(ctx, dc, flag.byUUID, isVM, iu) 207 if err != nil { 208 if soap.IsSoapFault(err) { 209 fault := soap.ToSoapFault(err).VimFault() 210 if _, ok := fault.(types.InvalidArgument); ok { 211 continue 212 } 213 } 214 return nil, err 215 } 216 if ref != nil { 217 break 218 } 219 } 220 221 return ref, nil 222 } 223 224 func (flag *SearchFlag) search() (object.Reference, error) { 225 ctx := context.TODO() 226 var ref object.Reference 227 var err error 228 var dc *object.Datacenter 229 230 c, err := flag.Client() 231 if err != nil { 232 return nil, err 233 } 234 235 isPath := flag.byInventoryPath != "" 236 if !isPath { 237 // All other SearchIndex methods require a Datacenter param 238 dc, err = flag.Datacenter() 239 if err != nil { 240 return nil, err 241 } 242 } 243 244 switch { 245 case isPath: 246 ref, err = flag.searchByInventoryPath(c) 247 case flag.byDatastorePath != "": 248 ref, err = flag.searchByDatastorePath(c, dc) 249 case flag.byDNSName != "": 250 ref, err = flag.searchByDNSName(c, dc) 251 case flag.byIP != "": 252 ref, err = flag.searchByIP(c, dc) 253 case flag.byUUID != "": 254 ref, err = flag.searchByUUID(c, dc) 255 default: 256 err = errors.New("no search flag specified") 257 } 258 259 if err != nil { 260 return nil, err 261 } 262 263 if ref == nil { 264 return nil, fmt.Errorf("no such %s", flag.entity) 265 } 266 267 // set the InventoryPath field 268 finder, err := flag.Finder() 269 if err != nil { 270 return nil, err 271 } 272 ref, err = finder.ObjectReference(ctx, ref.Reference()) 273 if err != nil { 274 return nil, err 275 } 276 277 return ref, nil 278 } 279 280 func (flag *SearchFlag) VirtualMachine() (*object.VirtualMachine, error) { 281 ref, err := flag.search() 282 if err != nil { 283 return nil, err 284 } 285 286 vm, ok := ref.(*object.VirtualMachine) 287 if !ok { 288 return nil, fmt.Errorf("expected VirtualMachine entity, got %s", ref.Reference().Type) 289 } 290 291 return vm, nil 292 } 293 294 func (flag *SearchFlag) VirtualMachines(args []string) ([]*object.VirtualMachine, error) { 295 ctx := context.TODO() 296 var out []*object.VirtualMachine 297 298 if flag.IsSet() { 299 vm, err := flag.VirtualMachine() 300 if err != nil { 301 return nil, err 302 } 303 304 out = append(out, vm) 305 return out, nil 306 } 307 308 // List virtual machines 309 if len(args) == 0 { 310 return nil, errors.New("no argument") 311 } 312 313 finder, err := flag.Finder() 314 if err != nil { 315 return nil, err 316 } 317 318 var nfe error 319 320 // List virtual machines for every argument 321 for _, arg := range args { 322 vms, err := finder.VirtualMachineList(ctx, arg) 323 if err != nil { 324 if _, ok := err.(*find.NotFoundError); ok { 325 // Let caller decide how to handle NotFoundError 326 nfe = err 327 continue 328 } 329 return nil, err 330 } 331 332 out = append(out, vms...) 333 } 334 335 return out, nfe 336 } 337 338 func (flag *SearchFlag) VirtualApp() (*object.VirtualApp, error) { 339 ref, err := flag.search() 340 if err != nil { 341 return nil, err 342 } 343 344 app, ok := ref.(*object.VirtualApp) 345 if !ok { 346 return nil, fmt.Errorf("expected VirtualApp entity, got %s", ref.Reference().Type) 347 } 348 349 return app, nil 350 } 351 352 func (flag *SearchFlag) VirtualApps(args []string) ([]*object.VirtualApp, error) { 353 ctx := context.TODO() 354 var out []*object.VirtualApp 355 356 if flag.IsSet() { 357 app, err := flag.VirtualApp() 358 if err != nil { 359 return nil, err 360 } 361 362 out = append(out, app) 363 return out, nil 364 } 365 366 // List virtual apps 367 if len(args) == 0 { 368 return nil, errors.New("no argument") 369 } 370 371 finder, err := flag.Finder() 372 if err != nil { 373 return nil, err 374 } 375 376 // List virtual apps for every argument 377 for _, arg := range args { 378 apps, err := finder.VirtualAppList(ctx, arg) 379 if err != nil { 380 return nil, err 381 } 382 383 out = append(out, apps...) 384 } 385 386 return out, nil 387 } 388 389 func (flag *SearchFlag) HostSystem() (*object.HostSystem, error) { 390 ref, err := flag.search() 391 if err != nil { 392 return nil, err 393 } 394 395 host, ok := ref.(*object.HostSystem) 396 if !ok { 397 return nil, fmt.Errorf("expected HostSystem entity, got %s", ref.Reference().Type) 398 } 399 400 return host, nil 401 } 402 403 func (flag *SearchFlag) HostSystems(args []string) ([]*object.HostSystem, error) { 404 ctx := context.TODO() 405 var out []*object.HostSystem 406 407 if flag.IsSet() { 408 host, err := flag.HostSystem() 409 if err != nil { 410 return nil, err 411 } 412 413 out = append(out, host) 414 return out, nil 415 } 416 417 // List host system 418 if len(args) == 0 { 419 return nil, errors.New("no argument") 420 } 421 422 finder, err := flag.Finder() 423 if err != nil { 424 return nil, err 425 } 426 427 // List host systems for every argument 428 for _, arg := range args { 429 vms, err := finder.HostSystemList(ctx, arg) 430 if err != nil { 431 return nil, err 432 } 433 434 out = append(out, vms...) 435 } 436 437 return out, nil 438 }