github.com/vmware/govmomi@v0.51.0/property/wait.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 property
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  
    11  	"github.com/vmware/govmomi/vim25/types"
    12  )
    13  
    14  // WaitOptions defines options for a property collector's WaitForUpdatesEx
    15  // method.
    16  type WaitOptions struct {
    17  	Options          *types.WaitOptions
    18  	PropagateMissing bool
    19  	Truncated        bool
    20  }
    21  
    22  // WaitFilter provides helpers to construct a types.CreateFilter for use with property.Wait
    23  type WaitFilter struct {
    24  	types.CreateFilter
    25  	WaitOptions
    26  }
    27  
    28  // Add a new ObjectSpec and PropertySpec to the WaitFilter
    29  func (f *WaitFilter) Add(obj types.ManagedObjectReference, kind string, ps []string, set ...types.BaseSelectionSpec) *WaitFilter {
    30  	spec := types.ObjectSpec{
    31  		Obj:       obj,
    32  		SelectSet: set,
    33  	}
    34  
    35  	pset := types.PropertySpec{
    36  		Type:    kind,
    37  		PathSet: ps,
    38  	}
    39  
    40  	if len(ps) == 0 {
    41  		pset.All = types.NewBool(true)
    42  	}
    43  
    44  	f.Spec.ObjectSet = append(f.Spec.ObjectSet, spec)
    45  
    46  	f.Spec.PropSet = append(f.Spec.PropSet, pset)
    47  
    48  	return f
    49  }
    50  
    51  // Wait creates a new WaitFilter and calls the specified function for each ObjectUpdate via WaitForUpdates
    52  func Wait(ctx context.Context, c *Collector, obj types.ManagedObjectReference, ps []string, f func([]types.PropertyChange) bool) error {
    53  	filter := new(WaitFilter).Add(obj, obj.Type, ps)
    54  
    55  	return WaitForUpdates(ctx, c, filter, func(updates []types.ObjectUpdate) bool {
    56  		for _, update := range updates {
    57  			if f(update.ChangeSet) {
    58  				return true
    59  			}
    60  		}
    61  
    62  		return false
    63  	})
    64  }
    65  
    66  // WaitForUpdates waits for any of the specified properties of the specified
    67  // managed object to change. It calls the specified function for every update it
    68  // receives. If this function returns false, it continues waiting for
    69  // subsequent updates. If this function returns true, it stops waiting and
    70  // returns.
    71  //
    72  // To only receive updates for the specified managed object, the function
    73  // creates a new property collector and calls CreateFilter. A new property
    74  // collector is required because filters can only be added, not removed.
    75  //
    76  // If the Context is canceled, a call to CancelWaitForUpdates() is made and its
    77  // error value is returned. The newly created collector is destroyed before this
    78  // function returns (both in case of success or error).
    79  //
    80  // By default, ObjectUpdate.MissingSet faults are not propagated to the returned
    81  // error, set WaitFilter.PropagateMissing=true to enable MissingSet fault
    82  // propagation.
    83  func WaitForUpdates(
    84  	ctx context.Context,
    85  	c *Collector,
    86  	filter *WaitFilter,
    87  	onUpdatesFn func([]types.ObjectUpdate) bool) (result error) {
    88  
    89  	pc, err := c.Create(ctx)
    90  	if err != nil {
    91  		return err
    92  	}
    93  
    94  	// Attempt to destroy the collector using the background context, as the
    95  	// specified context may have timed out or have been canceled.
    96  	defer func() {
    97  		if err := pc.Destroy(context.Background()); err != nil {
    98  			if result == nil {
    99  				result = err
   100  			} else {
   101  				result = fmt.Errorf(
   102  					"destroy property collector failed with %s after failing to wait for updates: %w",
   103  					err,
   104  					result)
   105  			}
   106  		}
   107  	}()
   108  
   109  	// Create a property filter for the property collector.
   110  	if _, err := pc.CreateFilter(ctx, filter.CreateFilter); err != nil {
   111  		return err
   112  	}
   113  
   114  	return pc.WaitForUpdatesEx(ctx, &filter.WaitOptions, onUpdatesFn)
   115  }
   116  
   117  // WaitForUpdates waits for any of the specified properties of the specified
   118  // managed object to change. It calls the specified function for every update it
   119  // receives. If this function returns false, it continues waiting for
   120  // subsequent updates. If this function returns true, it stops waiting and
   121  // returns.
   122  //
   123  // If the Context is canceled, a call to CancelWaitForUpdates() is made and its
   124  // error value is returned.
   125  //
   126  // By default, ObjectUpdate.MissingSet faults are not propagated to the returned
   127  // error, set WaitFilter.PropagateMissing=true to enable MissingSet fault
   128  // propagation.
   129  func WaitForUpdatesEx(
   130  	ctx context.Context,
   131  	pc *Collector,
   132  	filter *WaitFilter,
   133  	onUpdatesFn func([]types.ObjectUpdate) bool) (result error) {
   134  
   135  	// Create a property filter for the property collector.
   136  	pf, err := pc.CreateFilter(ctx, filter.CreateFilter)
   137  	if err != nil {
   138  		return err
   139  	}
   140  
   141  	// Destroy the filter using the background context, as the specified context
   142  	// may have timed out or have been canceled.
   143  	defer func() {
   144  		if err := pf.Destroy(context.Background()); err != nil {
   145  			if result == nil {
   146  				result = err
   147  			} else {
   148  				result = fmt.Errorf(
   149  					"destroy property filter failed with %s after failing to wait for updates: %w",
   150  					err,
   151  					result)
   152  			}
   153  		}
   154  
   155  	}()
   156  
   157  	return pc.WaitForUpdatesEx(ctx, &filter.WaitOptions, onUpdatesFn)
   158  }