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  }