wait.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. Copyright (c) 2015-2024 VMware, Inc. All Rights Reserved.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package property
  14. import (
  15. "context"
  16. "fmt"
  17. "github.com/vmware/govmomi/vim25/types"
  18. )
  19. // WaitOptions defines options for a property collector's WaitForUpdatesEx
  20. // method.
  21. type WaitOptions struct {
  22. Options *types.WaitOptions
  23. PropagateMissing bool
  24. Truncated bool
  25. }
  26. // WaitFilter provides helpers to construct a types.CreateFilter for use with property.Wait
  27. type WaitFilter struct {
  28. types.CreateFilter
  29. WaitOptions
  30. }
  31. // Add a new ObjectSpec and PropertySpec to the WaitFilter
  32. func (f *WaitFilter) Add(obj types.ManagedObjectReference, kind string, ps []string, set ...types.BaseSelectionSpec) *WaitFilter {
  33. spec := types.ObjectSpec{
  34. Obj: obj,
  35. SelectSet: set,
  36. }
  37. pset := types.PropertySpec{
  38. Type: kind,
  39. PathSet: ps,
  40. }
  41. if len(ps) == 0 {
  42. pset.All = types.NewBool(true)
  43. }
  44. f.Spec.ObjectSet = append(f.Spec.ObjectSet, spec)
  45. f.Spec.PropSet = append(f.Spec.PropSet, pset)
  46. return f
  47. }
  48. // Wait creates a new WaitFilter and calls the specified function for each ObjectUpdate via WaitForUpdates
  49. func Wait(ctx context.Context, c *Collector, obj types.ManagedObjectReference, ps []string, f func([]types.PropertyChange) bool) error {
  50. filter := new(WaitFilter).Add(obj, obj.Type, ps)
  51. return WaitForUpdates(ctx, c, filter, func(updates []types.ObjectUpdate) bool {
  52. for _, update := range updates {
  53. if f(update.ChangeSet) {
  54. return true
  55. }
  56. }
  57. return false
  58. })
  59. }
  60. // WaitForUpdates waits for any of the specified properties of the specified
  61. // managed object to change. It calls the specified function for every update it
  62. // receives. If this function returns false, it continues waiting for
  63. // subsequent updates. If this function returns true, it stops waiting and
  64. // returns.
  65. //
  66. // To only receive updates for the specified managed object, the function
  67. // creates a new property collector and calls CreateFilter. A new property
  68. // collector is required because filters can only be added, not removed.
  69. //
  70. // If the Context is canceled, a call to CancelWaitForUpdates() is made and its
  71. // error value is returned. The newly created collector is destroyed before this
  72. // function returns (both in case of success or error).
  73. //
  74. // By default, ObjectUpdate.MissingSet faults are not propagated to the returned
  75. // error, set WaitFilter.PropagateMissing=true to enable MissingSet fault
  76. // propagation.
  77. func WaitForUpdates(
  78. ctx context.Context,
  79. c *Collector,
  80. filter *WaitFilter,
  81. onUpdatesFn func([]types.ObjectUpdate) bool) (result error) {
  82. pc, err := c.Create(ctx)
  83. if err != nil {
  84. return err
  85. }
  86. // Attempt to destroy the collector using the background context, as the
  87. // specified context may have timed out or have been canceled.
  88. defer func() {
  89. if err := pc.Destroy(context.Background()); err != nil {
  90. if result == nil {
  91. result = err
  92. } else {
  93. result = fmt.Errorf(
  94. "destroy property collector failed with %s after failing to wait for updates: %w",
  95. err,
  96. result)
  97. }
  98. }
  99. }()
  100. // Create a property filter for the property collector.
  101. if _, err := pc.CreateFilter(ctx, filter.CreateFilter); err != nil {
  102. return err
  103. }
  104. return pc.WaitForUpdatesEx(ctx, filter.WaitOptions, onUpdatesFn)
  105. }
  106. // WaitForUpdates waits for any of the specified properties of the specified
  107. // managed object to change. It calls the specified function for every update it
  108. // receives. If this function returns false, it continues waiting for
  109. // subsequent updates. If this function returns true, it stops waiting and
  110. // returns.
  111. //
  112. // If the Context is canceled, a call to CancelWaitForUpdates() is made and its
  113. // error value is returned.
  114. //
  115. // By default, ObjectUpdate.MissingSet faults are not propagated to the returned
  116. // error, set WaitFilter.PropagateMissing=true to enable MissingSet fault
  117. // propagation.
  118. func WaitForUpdatesEx(
  119. ctx context.Context,
  120. pc *Collector,
  121. filter *WaitFilter,
  122. onUpdatesFn func([]types.ObjectUpdate) bool) (result error) {
  123. // Create a property filter for the property collector.
  124. pf, err := pc.CreateFilter(ctx, filter.CreateFilter)
  125. if err != nil {
  126. return err
  127. }
  128. // Destroy the filter using the background context, as the specified context
  129. // may have timed out or have been canceled.
  130. defer func() {
  131. if err := pf.Destroy(context.Background()); err != nil {
  132. if result == nil {
  133. result = err
  134. } else {
  135. result = fmt.Errorf(
  136. "destroy property filter failed with %s after failing to wait for updates: %w",
  137. err,
  138. result)
  139. }
  140. }
  141. }()
  142. return pc.WaitForUpdatesEx(ctx, filter.WaitOptions, onUpdatesFn)
  143. }