github.com/vmware/govmomi@v0.37.1/property/example_test.go (about) 1 /* 2 Copyright (c) 2019 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 property_test 18 19 import ( 20 "context" 21 "fmt" 22 "time" 23 24 "github.com/vmware/govmomi/find" 25 "github.com/vmware/govmomi/property" 26 "github.com/vmware/govmomi/simulator" 27 "github.com/vmware/govmomi/vim25" 28 "github.com/vmware/govmomi/vim25/mo" 29 "github.com/vmware/govmomi/vim25/types" 30 ) 31 32 // Example to retrieve properties from a single object 33 func ExampleCollector_RetrieveOne() { 34 simulator.Run(func(ctx context.Context, c *vim25.Client) error { 35 pc := property.DefaultCollector(c) 36 37 obj, err := find.NewFinder(c).VirtualMachine(ctx, "DC0_H0_VM0") 38 if err != nil { 39 return err 40 } 41 42 var vm mo.VirtualMachine 43 err = pc.RetrieveOne(ctx, obj.Reference(), []string{"config.version"}, &vm) 44 if err != nil { 45 return err 46 } 47 48 fmt.Printf("hardware version %s", vm.Config.Version) 49 return nil 50 }) 51 // Output: hardware version vmx-13 52 } 53 54 func ExampleCollector_Retrieve() { 55 simulator.Run(func(ctx context.Context, c *vim25.Client) error { 56 pc := property.DefaultCollector(c) 57 58 obj, err := find.NewFinder(c).HostSystem(ctx, "DC0_H0") 59 if err != nil { 60 return err 61 } 62 63 var host mo.HostSystem 64 err = pc.RetrieveOne(ctx, obj.Reference(), []string{"vm"}, &host) 65 if err != nil { 66 return err 67 } 68 69 var vms []mo.VirtualMachine 70 err = pc.Retrieve(ctx, host.Vm, []string{"name"}, &vms) 71 if err != nil { 72 return err 73 } 74 75 fmt.Printf("host has %d vms:", len(vms)) 76 for i := range vms { 77 fmt.Print(" ", vms[i].Name) 78 } 79 80 return nil 81 }) 82 // Output: host has 2 vms: DC0_H0_VM0 DC0_H0_VM1 83 } 84 85 func ExampleWait() { 86 simulator.Run(func(ctx context.Context, c *vim25.Client) error { 87 pc := property.DefaultCollector(c) 88 89 vm, err := find.NewFinder(c).VirtualMachine(ctx, "DC0_H0_VM0") 90 if err != nil { 91 return err 92 } 93 94 // power off VM after some time 95 go func() { 96 time.Sleep(time.Millisecond * 100) 97 _, err := vm.PowerOff(ctx) 98 if err != nil { 99 panic(err) 100 } 101 }() 102 103 return property.Wait(ctx, pc, vm.Reference(), []string{"runtime.powerState"}, func(changes []types.PropertyChange) bool { 104 for _, change := range changes { 105 state := change.Val.(types.VirtualMachinePowerState) 106 fmt.Println(state) 107 if state == types.VirtualMachinePowerStatePoweredOff { 108 return true 109 } 110 } 111 112 // continue polling 113 return false 114 }) 115 }) 116 // Output: 117 // poweredOn 118 // poweredOff 119 } 120 121 func ExampleCollector_WaitForUpdatesEx_addingRemovingPropertyFilters() { 122 model := simulator.VPX() 123 model.Datacenter = 1 124 model.Cluster = 0 125 model.Pool = 0 126 model.Machine = 1 127 model.Autostart = false 128 129 simulator.Run(func(ctx context.Context, c *vim25.Client) error { 130 // Set up the finder and get a VM. 131 finder := find.NewFinder(c, true) 132 datacenter, err := finder.DefaultDatacenter(ctx) 133 if err != nil { 134 return fmt.Errorf("default datacenter not found: %w", err) 135 } 136 finder.SetDatacenter(datacenter) 137 vmList, err := finder.VirtualMachineList(ctx, "*") 138 if len(vmList) == 0 { 139 return fmt.Errorf("vmList == 0") 140 } 141 vm := vmList[0] 142 143 pc, err := property.DefaultCollector(c).Create(ctx) 144 if err != nil { 145 return fmt.Errorf("failed to create new property collector: %w", err) 146 } 147 148 // Start a goroutine to wait for power state changes to the VM. They 149 // should not be triggered as there is no property filter yet defined. 150 chanResult := make(chan any) 151 cancelCtx, cancel := context.WithCancel(ctx) 152 defer cancel() 153 go func() { 154 if err := pc.WaitForUpdatesEx( 155 cancelCtx, 156 property.WaitOptions{}, 157 func(updates []types.ObjectUpdate) bool { 158 return waitForPowerStateChanges( 159 cancelCtx, 160 vm, 161 chanResult, 162 updates, 163 types.VirtualMachinePowerStatePoweredOff) 164 }); err != nil { 165 166 chanResult <- err 167 return 168 } 169 }() 170 171 // Power on the VM to cause a property change. 172 if _, err := vm.PowerOn(ctx); err != nil { 173 return fmt.Errorf("error while powering on vm: %w", err) 174 } 175 176 // The power change should be ignored. 177 select { 178 case <-time.After(3 * time.Second): 179 fmt.Println("poweredOn event not received") 180 case result := <-chanResult: 181 switch tResult := result.(type) { 182 case types.VirtualMachinePowerState: 183 return fmt.Errorf("update should not have been received without a property filter") 184 case error: 185 return fmt.Errorf("error while waiting for updates: %v", tResult) 186 } 187 } 188 189 // Now create a property filter that will catch the update. 190 pf, err := pc.CreateFilter( 191 ctx, 192 types.CreateFilter{Spec: getDatacenterToVMFolderFilter(datacenter)}, 193 ) 194 if err != nil { 195 return fmt.Errorf("failed to create dc2vm property filter: %w", err) 196 } 197 198 // Power off the VM to cause a property change. 199 if _, err := vm.PowerOff(ctx); err != nil { 200 return fmt.Errorf("error while powering off vm: %w", err) 201 } 202 203 // The power change should now be noticed. 204 select { 205 case <-time.After(3 * time.Second): 206 return fmt.Errorf("timed out while waiting for property update") 207 case result := <-chanResult: 208 switch tResult := result.(type) { 209 case types.VirtualMachinePowerState: 210 if tResult != types.VirtualMachinePowerStatePoweredOff { 211 return fmt.Errorf("unexpected power state: %v", tResult) 212 } 213 fmt.Println("poweredOff event received") 214 case error: 215 return fmt.Errorf("error while waiting for updates: %w", tResult) 216 } 217 } 218 219 // Destroy the property filter and repeat, and the power change should 220 // once again be ignored. 221 if err := pf.Destroy(ctx); err != nil { 222 return fmt.Errorf("failed to destroy property filter: %w", err) 223 } 224 225 // Power on the VM to cause a property change. 226 if _, err := vm.PowerOn(ctx); err != nil { 227 return fmt.Errorf("error while powering on vm: %w", err) 228 } 229 230 // The power change should be ignored. 231 select { 232 case <-time.After(3 * time.Second): 233 fmt.Println("poweredOn event not received") 234 case result := <-chanResult: 235 switch tResult := result.(type) { 236 case types.VirtualMachinePowerState: 237 return fmt.Errorf("update should not have been received after property filter was destroyed") 238 case error: 239 return fmt.Errorf("error while waiting for updates: %v", tResult) 240 } 241 } 242 243 return nil 244 }, model) 245 246 // Output: 247 // poweredOn event not received 248 // poweredOff event received 249 // poweredOn event not received 250 } 251 252 func ExampleCollector_WaitForUpdatesEx_errConcurrentCollector() { 253 simulator.Run(func(ctx context.Context, c *vim25.Client) error { 254 pc := property.DefaultCollector(c) 255 256 waitOptions := property.WaitOptions{ 257 Options: &types.WaitOptions{ 258 MaxWaitSeconds: addrOf(int32(1)), 259 }, 260 } 261 262 onUpdatesFn := func(_ []types.ObjectUpdate) bool { 263 return false 264 } 265 266 waitForChanges := func(chanErr chan error) { 267 defer close(chanErr) 268 chanErr <- pc.WaitForUpdatesEx(ctx, waitOptions, onUpdatesFn) 269 } 270 271 // Start two goroutines that wait for changes, but only one will begin 272 // waiting -- the other will return property.ErrConcurrentCollector. 273 chanErr1, chanErr2 := make(chan error), make(chan error) 274 go waitForChanges(chanErr1) 275 go waitForChanges(chanErr2) 276 277 err1 := <-chanErr1 278 err2 := <-chanErr2 279 280 if err1 == nil && err2 == nil { 281 return fmt.Errorf( 282 "one of the WaitForUpdate calls should have returned %s", 283 property.ErrConcurrentCollector) 284 } 285 286 if err1 == property.ErrConcurrentCollector && 287 err2 == property.ErrConcurrentCollector { 288 289 return fmt.Errorf( 290 "both of the WaitForUpdate calls returned %s", 291 property.ErrConcurrentCollector) 292 } 293 294 fmt.Println("WaitForUpdatesEx call succeeded") 295 fmt.Println("WaitForUpdatesEx call returned ErrConcurrentCollector") 296 297 // The third WaitForUpdatesEx call should be able to successfully obtain 298 // the lock since the other two calls are completed. 299 if err := pc.WaitForUpdatesEx(ctx, waitOptions, onUpdatesFn); err != nil { 300 return fmt.Errorf( 301 "unexpected error from third call to WaitForUpdatesEx: %s", err) 302 } 303 304 fmt.Println("WaitForUpdatesEx call succeeded") 305 306 return nil 307 }) 308 309 // Output: 310 // WaitForUpdatesEx call succeeded 311 // WaitForUpdatesEx call returned ErrConcurrentCollector 312 // WaitForUpdatesEx call succeeded 313 }