Blame vendor/github.com/vmware/govmomi/property/wait.go

Packit 63bb0d
/*
Packit 63bb0d
Copyright (c) 2015-2017 VMware, Inc. All Rights Reserved.
Packit 63bb0d
Packit 63bb0d
Licensed under the Apache License, Version 2.0 (the "License");
Packit 63bb0d
you may not use this file except in compliance with the License.
Packit 63bb0d
You may obtain a copy of the License at
Packit 63bb0d
Packit 63bb0d
    http://www.apache.org/licenses/LICENSE-2.0
Packit 63bb0d
Packit 63bb0d
Unless required by applicable law or agreed to in writing, software
Packit 63bb0d
distributed under the License is distributed on an "AS IS" BASIS,
Packit 63bb0d
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 63bb0d
See the License for the specific language governing permissions and
Packit 63bb0d
limitations under the License.
Packit 63bb0d
*/
Packit 63bb0d
Packit 63bb0d
package property
Packit 63bb0d
Packit 63bb0d
import (
Packit 63bb0d
	"context"
Packit 63bb0d
Packit 63bb0d
	"github.com/vmware/govmomi/vim25/methods"
Packit 63bb0d
	"github.com/vmware/govmomi/vim25/soap"
Packit 63bb0d
	"github.com/vmware/govmomi/vim25/types"
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
// WaitFilter provides helpers to construct a types.CreateFilter for use with property.Wait
Packit 63bb0d
type WaitFilter struct {
Packit 63bb0d
	types.CreateFilter
Packit 63bb0d
	Options          *types.WaitOptions
Packit 63bb0d
	PropagateMissing bool
Packit 63bb0d
	Truncated        bool
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// Add a new ObjectSpec and PropertySpec to the WaitFilter
Packit 63bb0d
func (f *WaitFilter) Add(obj types.ManagedObjectReference, kind string, ps []string, set ...types.BaseSelectionSpec) *WaitFilter {
Packit 63bb0d
	spec := types.ObjectSpec{
Packit 63bb0d
		Obj:       obj,
Packit 63bb0d
		SelectSet: set,
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	pset := types.PropertySpec{
Packit 63bb0d
		Type:    kind,
Packit 63bb0d
		PathSet: ps,
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if len(ps) == 0 {
Packit 63bb0d
		pset.All = types.NewBool(true)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	f.Spec.ObjectSet = append(f.Spec.ObjectSet, spec)
Packit 63bb0d
Packit 63bb0d
	f.Spec.PropSet = append(f.Spec.PropSet, pset)
Packit 63bb0d
Packit 63bb0d
	return f
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// Wait creates a new WaitFilter and calls the specified function for each ObjectUpdate via WaitForUpdates
Packit 63bb0d
func Wait(ctx context.Context, c *Collector, obj types.ManagedObjectReference, ps []string, f func([]types.PropertyChange) bool) error {
Packit 63bb0d
	filter := new(WaitFilter).Add(obj, obj.Type, ps)
Packit 63bb0d
Packit 63bb0d
	return WaitForUpdates(ctx, c, filter, func(updates []types.ObjectUpdate) bool {
Packit 63bb0d
		for _, update := range updates {
Packit 63bb0d
			if f(update.ChangeSet) {
Packit 63bb0d
				return true
Packit 63bb0d
			}
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		return false
Packit 63bb0d
	})
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// WaitForUpdates waits for any of the specified properties of the specified managed
Packit 63bb0d
// object to change. It calls the specified function for every update it
Packit 63bb0d
// receives. If this function returns false, it continues waiting for
Packit 63bb0d
// subsequent updates. If this function returns true, it stops waiting and
Packit 63bb0d
// returns.
Packit 63bb0d
//
Packit 63bb0d
// To only receive updates for the specified managed object, the function
Packit 63bb0d
// creates a new property collector and calls CreateFilter. A new property
Packit 63bb0d
// collector is required because filters can only be added, not removed.
Packit 63bb0d
//
Packit 63bb0d
// If the Context is canceled, a call to CancelWaitForUpdates() is made and its error value is returned.
Packit 63bb0d
// The newly created collector is destroyed before this function returns (both
Packit 63bb0d
// in case of success or error).
Packit 63bb0d
//
Packit 63bb0d
// By default, ObjectUpdate.MissingSet faults are not propagated to the returned error,
Packit 63bb0d
// set WaitFilter.PropagateMissing=true to enable MissingSet fault propagation.
Packit 63bb0d
func WaitForUpdates(ctx context.Context, c *Collector, filter *WaitFilter, f func([]types.ObjectUpdate) bool) error {
Packit 63bb0d
	p, err := c.Create(ctx)
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Attempt to destroy the collector using the background context, as the
Packit 63bb0d
	// specified context may have timed out or have been canceled.
Packit 63bb0d
	defer func() {
Packit 63bb0d
		_ = p.Destroy(context.Background())
Packit 63bb0d
	}()
Packit 63bb0d
Packit 63bb0d
	err = p.CreateFilter(ctx, filter.CreateFilter)
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	req := types.WaitForUpdatesEx{
Packit 63bb0d
		This:    p.Reference(),
Packit 63bb0d
		Options: filter.Options,
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	for {
Packit 63bb0d
		res, err := methods.WaitForUpdatesEx(ctx, p.roundTripper, &req)
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			if ctx.Err() == context.Canceled {
Packit 63bb0d
				werr := p.CancelWaitForUpdates(context.Background())
Packit 63bb0d
				return werr
Packit 63bb0d
			}
Packit 63bb0d
			return err
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		set := res.Returnval
Packit 63bb0d
		if set == nil {
Packit 63bb0d
			if req.Options != nil && req.Options.MaxWaitSeconds != nil {
Packit 63bb0d
				return nil // WaitOptions.MaxWaitSeconds exceeded
Packit 63bb0d
			}
Packit 63bb0d
			// Retry if the result came back empty
Packit 63bb0d
			continue
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		req.Version = set.Version
Packit 63bb0d
		filter.Truncated = false
Packit 63bb0d
		if set.Truncated != nil {
Packit 63bb0d
			filter.Truncated = *set.Truncated
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		for _, fs := range set.FilterSet {
Packit 63bb0d
			if filter.PropagateMissing {
Packit 63bb0d
				for i := range fs.ObjectSet {
Packit 63bb0d
					for _, p := range fs.ObjectSet[i].MissingSet {
Packit 63bb0d
						// Same behavior as mo.ObjectContentToType()
Packit 63bb0d
						return soap.WrapVimFault(p.Fault.Fault)
Packit 63bb0d
					}
Packit 63bb0d
				}
Packit 63bb0d
			}
Packit 63bb0d
Packit 63bb0d
			if f(fs.ObjectSet) {
Packit 63bb0d
				return nil
Packit 63bb0d
			}
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
}