github.com/vmware/govmomi@v0.51.0/view/example_test.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 view_test 6 7 import ( 8 "context" 9 "fmt" 10 "log" 11 "sort" 12 "sync" 13 "time" 14 15 "github.com/vmware/govmomi/find" 16 "github.com/vmware/govmomi/object" 17 "github.com/vmware/govmomi/property" 18 "github.com/vmware/govmomi/simulator" 19 "github.com/vmware/govmomi/view" 20 "github.com/vmware/govmomi/vim25" 21 "github.com/vmware/govmomi/vim25/methods" 22 "github.com/vmware/govmomi/vim25/mo" 23 "github.com/vmware/govmomi/vim25/types" 24 ) 25 26 // Create a view of all hosts in the inventory, printing host names that belong to a cluster and excluding standalone hosts. 27 func ExampleContainerView_Retrieve() { 28 model := simulator.VPX() 29 model.Datacenter = 2 30 31 simulator.Run(func(ctx context.Context, c *vim25.Client) error { 32 m := view.NewManager(c) 33 kind := []string{"HostSystem"} 34 35 v, err := m.CreateContainerView(ctx, c.ServiceContent.RootFolder, kind, true) 36 if err != nil { 37 log.Fatal(err) 38 } 39 40 var hosts []mo.HostSystem 41 var names []string 42 43 err = v.Retrieve(ctx, kind, []string{"summary.config.name", "parent"}, &hosts) 44 if err != nil { 45 return err 46 } 47 48 for _, host := range hosts { 49 if host.Parent.Type != "ClusterComputeResource" { 50 continue 51 } 52 names = append(names, host.Summary.Config.Name) 53 } 54 55 sort.Strings(names) 56 fmt.Println(names) 57 58 return v.Destroy(ctx) 59 }, model) 60 // Output: [DC0_C0_H0 DC0_C0_H1 DC0_C0_H2 DC1_C0_H0 DC1_C0_H1 DC1_C0_H2] 61 } 62 63 func ExampleContainerView_retrieveClusters() { 64 model := simulator.VPX() 65 model.Cluster = 3 66 67 simulator.Run(func(ctx context.Context, c *vim25.Client) error { 68 m := view.NewManager(c) 69 kind := []string{"ClusterComputeResource"} 70 71 v, err := m.CreateContainerView(ctx, c.ServiceContent.RootFolder, kind, true) 72 if err != nil { 73 log.Fatal(err) 74 } 75 76 var clusters []mo.ClusterComputeResource 77 var names []string 78 79 err = v.Retrieve(ctx, kind, []string{"name"}, &clusters) 80 if err != nil { 81 return err 82 } 83 84 for _, cluster := range clusters { 85 names = append(names, cluster.Name) 86 } 87 88 sort.Strings(names) 89 fmt.Println(names) 90 91 return v.Destroy(ctx) 92 }, model) 93 // Output: [DC0_C0 DC0_C1 DC0_C2] 94 } 95 96 // Create a view of all VMs in the inventory, printing VM names that end with "_VM1". 97 func ExampleContainerView_RetrieveWithFilter() { 98 simulator.Run(func(ctx context.Context, c *vim25.Client) error { 99 m := view.NewManager(c) 100 kind := []string{"VirtualMachine"} 101 102 v, err := m.CreateContainerView(ctx, c.ServiceContent.RootFolder, kind, true) 103 if err != nil { 104 log.Fatal(err) 105 } 106 107 var vms []mo.VirtualMachine 108 var names []string 109 110 err = v.RetrieveWithFilter(ctx, kind, []string{"name"}, &vms, property.Match{"name": "*_VM1"}) 111 if err != nil { 112 return err 113 } 114 115 for _, vm := range vms { 116 names = append(names, vm.Name) 117 } 118 119 sort.Strings(names) 120 fmt.Println(names) 121 122 return v.Destroy(ctx) 123 }) 124 // Output: [DC0_C0_RP0_VM1 DC0_H0_VM1] 125 } 126 127 // Create a view of all VMs in a specific subfolder, powering off all VMs within 128 func ExampleContainerView_Find() { 129 model := simulator.VPX() 130 model.Folder = 1 // put everything inside subfolders 131 132 simulator.Run(func(ctx context.Context, c *vim25.Client) error { 133 folder, err := object.NewSearchIndex(c).FindByInventoryPath(ctx, "/F0/DC0/vm/F0") 134 if err != nil { 135 return err 136 } 137 138 m := view.NewManager(c) 139 kind := []string{"VirtualMachine"} // include VMs only, ignoring other object types 140 141 // Root of the view is the subfolder moid (true == recurse into any subfolders of the root) 142 v, err := m.CreateContainerView(ctx, folder.Reference(), kind, true) 143 if err != nil { 144 log.Fatal(err) 145 } 146 147 vms, err := v.Find(ctx, kind, property.Match{}) 148 if err != nil { 149 return err 150 } 151 152 for _, id := range vms { 153 vm := object.NewVirtualMachine(c, id) 154 task, err := vm.PowerOff(ctx) 155 if err != nil { 156 return err 157 } 158 159 if err = task.Wait(ctx); err != nil { 160 return err 161 } 162 } 163 164 fmt.Println(len(vms)) 165 166 return v.Destroy(ctx) 167 }, model) 168 // Output: 4 169 } 170 171 // This example uses a single PropertyCollector with ListView for waiting on updates to N tasks 172 func ExampleListView_tasks() { 173 simulator.Run(func(ctx context.Context, c *vim25.Client) error { 174 list, err := view.NewManager(c).CreateListView(ctx, nil) 175 if err != nil { 176 return err 177 } 178 179 defer list.Destroy(ctx) 180 181 vms, err := find.NewFinder(c).VirtualMachineList(ctx, "*") 182 if err != nil { 183 return err 184 } 185 186 result := map[types.TaskInfoState]int{} 187 n := len(vms) 188 p := property.DefaultCollector(c) 189 190 // wait for any updates to tasks in our list view 191 filter := new(property.WaitFilter).Add(list.Reference(), "Task", []string{"info"}, list.TraversalSpec()) 192 193 var werr error 194 var wg sync.WaitGroup 195 wg.Add(1) 196 go func() { // WaitForUpdates blocks until func returns true 197 defer wg.Done() 198 werr = property.WaitForUpdates(ctx, p, filter, func(updates []types.ObjectUpdate) bool { 199 for _, update := range updates { 200 for _, change := range update.ChangeSet { 201 info := change.Val.(types.TaskInfo) 202 203 switch info.State { 204 case types.TaskInfoStateSuccess, types.TaskInfoStateError: 205 _, _ = list.Remove(ctx, []types.ManagedObjectReference{update.Obj}) 206 result[info.State]++ 207 n-- 208 if n == 0 { 209 return true 210 } 211 } 212 } 213 } 214 215 return false 216 }) 217 }() 218 219 for _, vm := range vms { 220 task, err := vm.PowerOff(ctx) 221 if err != nil { 222 return err 223 } 224 _, err = list.Add(ctx, []types.ManagedObjectReference{task.Reference()}) 225 if err != nil { 226 return err 227 } 228 } 229 230 wg.Wait() // wait until all tasks complete and WaitForUpdates returns 231 232 for state, n := range result { 233 fmt.Printf("%s=%d", state, n) 234 } 235 236 return werr 237 }) 238 // Output: success=4 239 } 240 241 // viewOfVM returns a spec to traverse a ListView of ContainerView, for tracking VM updates. 242 func viewOfVM(ref types.ManagedObjectReference, pathSet []string) types.CreateFilter { 243 return types.CreateFilter{ 244 Spec: types.PropertyFilterSpec{ 245 ObjectSet: []types.ObjectSpec{{ 246 Obj: ref, 247 Skip: types.NewBool(true), 248 SelectSet: []types.BaseSelectionSpec{ 249 // ListView --> ContainerView 250 &types.TraversalSpec{ 251 Type: "ListView", 252 Path: "view", 253 SelectSet: []types.BaseSelectionSpec{ 254 &types.SelectionSpec{ 255 Name: "visitViews", 256 }, 257 }, 258 }, 259 // ContainerView --> VM 260 &types.TraversalSpec{ 261 SelectionSpec: types.SelectionSpec{ 262 Name: "visitViews", 263 }, 264 Type: "ContainerView", 265 Path: "view", 266 }, 267 }, 268 }}, 269 PropSet: []types.PropertySpec{{ 270 Type: "VirtualMachine", 271 PathSet: pathSet, 272 }}, 273 }, 274 } 275 } 276 277 // Example of using WaitForUpdates with a ListView of ContainerView. 278 // Each container root is a Cluster view of VirtualMachines. 279 // Modifying the ListView changes which VirtualMachine updates are returned by WaitForUpdates. 280 func ExampleListView_ofContainerView() { 281 model := simulator.VPX() 282 model.Cluster = 3 283 284 simulator.Run(func(ctx context.Context, c *vim25.Client) error { 285 m := view.NewManager(c) 286 287 kind := []string{"ClusterComputeResource"} 288 root, err := m.CreateContainerView(ctx, c.ServiceContent.RootFolder, kind, true) 289 if err != nil { 290 return err 291 } 292 293 clusters, err := root.Find(ctx, kind, property.Match{}) 294 if err != nil { 295 return err 296 } 297 298 list, err := m.CreateListView(ctx, nil) 299 if err != nil { 300 return err 301 } 302 303 kind = []string{"VirtualMachine"} 304 views := make(map[types.ManagedObjectReference]*view.ContainerView) 305 306 for _, cluster := range clusters { 307 cv, err := m.CreateContainerView(ctx, cluster, kind, true) 308 if err != nil { 309 return err 310 } 311 312 _, err = list.Add(ctx, []types.ManagedObjectReference{cv.Reference()}) 313 314 views[cluster] = cv 315 } 316 317 pc := property.DefaultCollector(c) 318 319 pathSet := []string{"config.extraConfig"} 320 pf, err := pc.CreateFilter(ctx, viewOfVM(list.Reference(), pathSet)) 321 if err != nil { 322 return err 323 } 324 defer pf.Destroy(ctx) 325 326 // MaxWaitSeconds value of 0 causes WaitForUpdatesEx to do one update calculation and return any results. 327 req := types.WaitForUpdatesEx{ 328 This: pc.Reference(), 329 Options: &types.WaitOptions{ 330 MaxWaitSeconds: types.NewInt32(0), 331 }, 332 } 333 334 updates := func() ([]types.ObjectUpdate, error) { 335 res, err := methods.WaitForUpdatesEx(ctx, c.Client, &req) 336 if err != nil { 337 return nil, err 338 } 339 340 set := res.Returnval 341 342 if set == nil { 343 return nil, nil 344 } 345 346 req.Version = set.Version 347 348 if len(set.FilterSet) == 0 { 349 return nil, nil 350 } 351 352 return set.FilterSet[0].ObjectSet, nil 353 } 354 355 set, err := updates() 356 if err != nil { 357 return err 358 } 359 360 all := make([]types.ManagedObjectReference, len(set)) 361 for i := range set { 362 all[i] = set[i].Obj 363 } 364 365 fmt.Printf("Initial updates=%d\n", len(all)) 366 367 reconfig := func() { 368 spec := types.VirtualMachineConfigSpec{ 369 ExtraConfig: []types.BaseOptionValue{ 370 &types.OptionValue{Key: "time", Value: time.Now().String()}, 371 }, 372 } 373 // Change state of all VMs in all Clusters 374 for _, ref := range all { 375 task, err := object.NewVirtualMachine(c, ref).Reconfigure(ctx, spec) 376 if err != nil { 377 panic(err) 378 } 379 if err = task.Wait(ctx); err != nil { 380 panic(err) 381 } 382 } 383 384 set, err := updates() 385 if err != nil { 386 panic(err) 387 } 388 389 fmt.Printf("Reconfig updates=%d\n", len(set)) 390 } 391 392 reconfig() 393 394 cluster := views[clusters[0]].Reference() 395 _, err = list.Remove(ctx, []types.ManagedObjectReference{cluster}) 396 if err != nil { 397 return err 398 } 399 400 reconfig() 401 402 _, err = list.Add(ctx, []types.ManagedObjectReference{cluster}) 403 if err != nil { 404 return err 405 } 406 407 reconfig() 408 409 return nil 410 }, model) 411 412 // Output: 413 // Initial updates=6 414 // Reconfig updates=6 415 // Reconfig updates=4 416 // Reconfig updates=6 417 }