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