property_collector.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. /*
  2. Copyright (c) 2017 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 simulator
  14. import (
  15. "context"
  16. "errors"
  17. "log"
  18. "path"
  19. "reflect"
  20. "strings"
  21. "sync"
  22. "time"
  23. "github.com/vmware/govmomi/object"
  24. "github.com/vmware/govmomi/vim25/methods"
  25. "github.com/vmware/govmomi/vim25/mo"
  26. "github.com/vmware/govmomi/vim25/soap"
  27. "github.com/vmware/govmomi/vim25/types"
  28. )
  29. type PropertyCollector struct {
  30. mo.PropertyCollector
  31. nopLocker
  32. updates []types.ObjectUpdate
  33. mu sync.Mutex
  34. cancel context.CancelFunc
  35. }
  36. func NewPropertyCollector(ref types.ManagedObjectReference) object.Reference {
  37. s := &PropertyCollector{}
  38. s.Self = ref
  39. return s
  40. }
  41. var errMissingField = errors.New("missing field")
  42. var errEmptyField = errors.New("empty field")
  43. func getObject(ctx *Context, ref types.ManagedObjectReference) (reflect.Value, bool) {
  44. var obj mo.Reference
  45. if ctx.Session == nil {
  46. // Even without permissions to access an object or specific fields, RetrieveProperties
  47. // returns an ObjectContent response as long as the object exists. See retrieveResult.add()
  48. obj = Map.Get(ref)
  49. } else {
  50. obj = ctx.Session.Get(ref)
  51. }
  52. if obj == nil {
  53. return reflect.Value{}, false
  54. }
  55. if ctx.Session == nil && ref.Type == "SessionManager" {
  56. // RetrieveProperties on SessionManager without a session always returns empty,
  57. // rather than MissingSet + Fault.NotAuthenticated for each field.
  58. obj = &mo.SessionManager{Self: ref}
  59. }
  60. // For objects that use internal types that differ from that of the vim25/mo field types.
  61. // See EventHistoryCollector for example.
  62. type get interface {
  63. Get() mo.Reference
  64. }
  65. if o, ok := obj.(get); ok {
  66. obj = o.Get()
  67. }
  68. return getManagedObject(obj), true
  69. }
  70. func getManagedObject(obj mo.Reference) reflect.Value {
  71. rval := reflect.ValueOf(obj).Elem()
  72. rtype := rval.Type()
  73. // PropertyCollector is for Managed Object types only (package mo).
  74. // If the registry object is not in the mo package, assume it is a wrapper
  75. // type where the first field is an embedded mo type.
  76. // We need to dig out the mo type for PropSet.All to work properly and
  77. // for the case where the type has a field of the same name, for example:
  78. // mo.ResourcePool.ResourcePool
  79. for {
  80. if path.Base(rtype.PkgPath()) == "mo" {
  81. break
  82. }
  83. if rtype.Kind() != reflect.Struct || rtype.NumField() == 0 {
  84. log.Panicf("%#v does not have an embedded mo type", obj.Reference())
  85. }
  86. rval = rval.Field(0)
  87. rtype = rval.Type()
  88. }
  89. return rval
  90. }
  91. // wrapValue converts slice types to the appropriate ArrayOf type used in property collector responses.
  92. func wrapValue(rval reflect.Value, rtype reflect.Type) interface{} {
  93. pval := rval.Interface()
  94. if rval.Kind() == reflect.Slice {
  95. // Convert slice to types.ArrayOf*
  96. switch v := pval.(type) {
  97. case []string:
  98. pval = &types.ArrayOfString{
  99. String: v,
  100. }
  101. case []uint8:
  102. pval = &types.ArrayOfByte{
  103. Byte: v,
  104. }
  105. case []int16:
  106. pval = &types.ArrayOfShort{
  107. Short: v,
  108. }
  109. case []int32:
  110. pval = &types.ArrayOfInt{
  111. Int: v,
  112. }
  113. case []int64:
  114. pval = &types.ArrayOfLong{
  115. Long: v,
  116. }
  117. default:
  118. kind := rtype.Elem().Name()
  119. // Remove govmomi interface prefix name
  120. if strings.HasPrefix(kind, "Base") {
  121. kind = kind[4:]
  122. }
  123. akind, _ := defaultMapType("ArrayOf" + kind)
  124. a := reflect.New(akind)
  125. a.Elem().FieldByName(kind).Set(rval)
  126. pval = a.Interface()
  127. }
  128. }
  129. return pval
  130. }
  131. func fieldValueInterface(f reflect.StructField, rval reflect.Value) interface{} {
  132. if rval.Kind() == reflect.Ptr {
  133. rval = rval.Elem()
  134. }
  135. return wrapValue(rval, f.Type)
  136. }
  137. func fieldValue(rval reflect.Value, p string) (interface{}, error) {
  138. var value interface{}
  139. fields := strings.Split(p, ".")
  140. for i, name := range fields {
  141. kind := rval.Type().Kind()
  142. if kind == reflect.Interface {
  143. if rval.IsNil() {
  144. continue
  145. }
  146. rval = rval.Elem()
  147. kind = rval.Type().Kind()
  148. }
  149. if kind == reflect.Ptr {
  150. if rval.IsNil() {
  151. continue
  152. }
  153. rval = rval.Elem()
  154. }
  155. x := ucFirst(name)
  156. val := rval.FieldByName(x)
  157. if !val.IsValid() {
  158. return nil, errMissingField
  159. }
  160. if isEmpty(val) {
  161. return nil, errEmptyField
  162. }
  163. if i == len(fields)-1 {
  164. ftype, _ := rval.Type().FieldByName(x)
  165. value = fieldValueInterface(ftype, val)
  166. break
  167. }
  168. rval = val
  169. }
  170. return value, nil
  171. }
  172. func fieldRefs(f interface{}) []types.ManagedObjectReference {
  173. switch fv := f.(type) {
  174. case types.ManagedObjectReference:
  175. return []types.ManagedObjectReference{fv}
  176. case *types.ArrayOfManagedObjectReference:
  177. return fv.ManagedObjectReference
  178. case nil:
  179. // empty field
  180. }
  181. return nil
  182. }
  183. func isEmpty(rval reflect.Value) bool {
  184. switch rval.Kind() {
  185. case reflect.Ptr:
  186. return rval.IsNil()
  187. case reflect.String:
  188. return rval.Len() == 0
  189. }
  190. return false
  191. }
  192. func isTrue(v *bool) bool {
  193. return v != nil && *v
  194. }
  195. func isFalse(v *bool) bool {
  196. return v == nil || *v == false
  197. }
  198. func lcFirst(s string) string {
  199. return strings.ToLower(s[:1]) + s[1:]
  200. }
  201. func ucFirst(s string) string {
  202. return strings.ToUpper(s[:1]) + s[1:]
  203. }
  204. type retrieveResult struct {
  205. *types.RetrieveResult
  206. req *types.RetrievePropertiesEx
  207. collected map[types.ManagedObjectReference]bool
  208. specs map[string]*types.TraversalSpec
  209. }
  210. func (rr *retrieveResult) add(ctx *Context, name string, val types.AnyType, content *types.ObjectContent) {
  211. if ctx.Session != nil {
  212. content.PropSet = append(content.PropSet, types.DynamicProperty{
  213. Name: name,
  214. Val: val,
  215. })
  216. return
  217. }
  218. content.MissingSet = append(content.MissingSet, types.MissingProperty{
  219. Path: name,
  220. Fault: types.LocalizedMethodFault{Fault: &types.NotAuthenticated{
  221. NoPermission: types.NoPermission{
  222. Object: content.Obj,
  223. PrivilegeId: "System.Read",
  224. }},
  225. },
  226. })
  227. }
  228. func (rr *retrieveResult) collectAll(ctx *Context, rval reflect.Value, rtype reflect.Type, content *types.ObjectContent) {
  229. for i := 0; i < rval.NumField(); i++ {
  230. val := rval.Field(i)
  231. f := rtype.Field(i)
  232. if isEmpty(val) || f.Name == "Self" {
  233. continue
  234. }
  235. if f.Anonymous {
  236. // recurse into embedded field
  237. rr.collectAll(ctx, val, f.Type, content)
  238. continue
  239. }
  240. rr.add(ctx, lcFirst(f.Name), fieldValueInterface(f, val), content)
  241. }
  242. }
  243. func (rr *retrieveResult) collectFields(ctx *Context, rval reflect.Value, fields []string, content *types.ObjectContent) {
  244. seen := make(map[string]bool)
  245. for i := range content.PropSet {
  246. seen[content.PropSet[i].Name] = true // mark any already collected via embedded field
  247. }
  248. for _, name := range fields {
  249. if seen[name] {
  250. // rvc 'ls' includes the "name" property twice, then fails with no error message or stack trace
  251. // in RbVmomi::VIM::ObjectContent.to_hash_uncached when it sees the 2nd "name" property.
  252. continue
  253. }
  254. seen[name] = true
  255. val, err := fieldValue(rval, name)
  256. switch err {
  257. case nil, errEmptyField:
  258. rr.add(ctx, name, val, content)
  259. case errMissingField:
  260. content.MissingSet = append(content.MissingSet, types.MissingProperty{
  261. Path: name,
  262. Fault: types.LocalizedMethodFault{Fault: &types.InvalidProperty{
  263. Name: name,
  264. }},
  265. })
  266. }
  267. }
  268. }
  269. func (rr *retrieveResult) collect(ctx *Context, ref types.ManagedObjectReference) {
  270. if rr.collected[ref] {
  271. return
  272. }
  273. content := types.ObjectContent{
  274. Obj: ref,
  275. }
  276. rval, ok := getObject(ctx, ref)
  277. if !ok {
  278. // Possible if a test uses Map.Remove instead of Destroy_Task
  279. log.Printf("object %s no longer exists", ref)
  280. return
  281. }
  282. rtype := rval.Type()
  283. match := false
  284. for _, spec := range rr.req.SpecSet {
  285. for _, p := range spec.PropSet {
  286. if p.Type != ref.Type {
  287. // e.g. ManagedEntity, ComputeResource
  288. field, ok := rtype.FieldByName(p.Type)
  289. if !(ok && field.Anonymous) {
  290. continue
  291. }
  292. }
  293. match = true
  294. if isTrue(p.All) {
  295. rr.collectAll(ctx, rval, rtype, &content)
  296. continue
  297. }
  298. rr.collectFields(ctx, rval, p.PathSet, &content)
  299. }
  300. }
  301. if match {
  302. rr.Objects = append(rr.Objects, content)
  303. }
  304. rr.collected[ref] = true
  305. }
  306. func (rr *retrieveResult) selectSet(ctx *Context, obj reflect.Value, s []types.BaseSelectionSpec, refs *[]types.ManagedObjectReference) types.BaseMethodFault {
  307. for _, ss := range s {
  308. ts, ok := ss.(*types.TraversalSpec)
  309. if ok {
  310. if ts.Name != "" {
  311. rr.specs[ts.Name] = ts
  312. }
  313. }
  314. }
  315. for _, ss := range s {
  316. ts, ok := ss.(*types.TraversalSpec)
  317. if !ok {
  318. ts = rr.specs[ss.GetSelectionSpec().Name]
  319. if ts == nil {
  320. return &types.InvalidArgument{InvalidProperty: "undefined TraversalSpec name"}
  321. }
  322. }
  323. f, _ := fieldValue(obj, ts.Path)
  324. for _, ref := range fieldRefs(f) {
  325. if isFalse(ts.Skip) {
  326. *refs = append(*refs, ref)
  327. }
  328. rval, ok := getObject(ctx, ref)
  329. if ok {
  330. if err := rr.selectSet(ctx, rval, ts.SelectSet, refs); err != nil {
  331. return err
  332. }
  333. }
  334. }
  335. }
  336. return nil
  337. }
  338. func (pc *PropertyCollector) collect(ctx *Context, r *types.RetrievePropertiesEx) (*types.RetrieveResult, types.BaseMethodFault) {
  339. var refs []types.ManagedObjectReference
  340. rr := &retrieveResult{
  341. RetrieveResult: &types.RetrieveResult{},
  342. req: r,
  343. collected: make(map[types.ManagedObjectReference]bool),
  344. specs: make(map[string]*types.TraversalSpec),
  345. }
  346. // Select object references
  347. for _, spec := range r.SpecSet {
  348. for _, o := range spec.ObjectSet {
  349. var rval reflect.Value
  350. ok := false
  351. ctx.WithLock(o.Obj, func() { rval, ok = getObject(ctx, o.Obj) })
  352. if !ok {
  353. if isFalse(spec.ReportMissingObjectsInResults) {
  354. return nil, &types.ManagedObjectNotFound{Obj: o.Obj}
  355. }
  356. continue
  357. }
  358. if o.SelectSet == nil || isFalse(o.Skip) {
  359. refs = append(refs, o.Obj)
  360. }
  361. if err := rr.selectSet(ctx, rval, o.SelectSet, &refs); err != nil {
  362. return nil, err
  363. }
  364. }
  365. }
  366. for _, ref := range refs {
  367. ctx.WithLock(ref, func() { rr.collect(ctx, ref) })
  368. }
  369. return rr.RetrieveResult, nil
  370. }
  371. func (pc *PropertyCollector) CreateFilter(ctx *Context, c *types.CreateFilter) soap.HasFault {
  372. body := &methods.CreateFilterBody{}
  373. filter := &PropertyFilter{
  374. pc: pc,
  375. refs: make(map[types.ManagedObjectReference]struct{}),
  376. }
  377. filter.PartialUpdates = c.PartialUpdates
  378. filter.Spec = c.Spec
  379. pc.Filter = append(pc.Filter, ctx.Session.Put(filter).Reference())
  380. body.Res = &types.CreateFilterResponse{
  381. Returnval: filter.Self,
  382. }
  383. return body
  384. }
  385. func (pc *PropertyCollector) CreatePropertyCollector(ctx *Context, c *types.CreatePropertyCollector) soap.HasFault {
  386. body := &methods.CreatePropertyCollectorBody{}
  387. cpc := &PropertyCollector{}
  388. body.Res = &types.CreatePropertyCollectorResponse{
  389. Returnval: ctx.Session.Put(cpc).Reference(),
  390. }
  391. return body
  392. }
  393. func (pc *PropertyCollector) DestroyPropertyCollector(ctx *Context, c *types.DestroyPropertyCollector) soap.HasFault {
  394. pc.CancelWaitForUpdates(&types.CancelWaitForUpdates{This: c.This})
  395. body := &methods.DestroyPropertyCollectorBody{}
  396. for _, ref := range pc.Filter {
  397. filter := ctx.Session.Get(ref).(*PropertyFilter)
  398. filter.DestroyPropertyFilter(ctx, &types.DestroyPropertyFilter{This: ref})
  399. }
  400. ctx.Session.Remove(c.This)
  401. ctx.Map.Remove(c.This)
  402. body.Res = &types.DestroyPropertyCollectorResponse{}
  403. return body
  404. }
  405. func (pc *PropertyCollector) RetrievePropertiesEx(ctx *Context, r *types.RetrievePropertiesEx) soap.HasFault {
  406. body := &methods.RetrievePropertiesExBody{}
  407. res, fault := pc.collect(ctx, r)
  408. if fault != nil {
  409. switch fault.(type) {
  410. case *types.ManagedObjectNotFound:
  411. body.Fault_ = Fault("The object has already been deleted or has not been completely created", fault)
  412. default:
  413. body.Fault_ = Fault("", fault)
  414. }
  415. } else {
  416. objects := res.Objects[:0]
  417. for _, o := range res.Objects {
  418. propSet := o.PropSet[:0]
  419. for _, p := range o.PropSet {
  420. if p.Val != nil {
  421. propSet = append(propSet, p)
  422. }
  423. }
  424. o.PropSet = propSet
  425. objects = append(objects, o)
  426. }
  427. res.Objects = objects
  428. body.Res = &types.RetrievePropertiesExResponse{
  429. Returnval: res,
  430. }
  431. }
  432. return body
  433. }
  434. // RetrieveProperties is deprecated, but govmomi is still using it at the moment.
  435. func (pc *PropertyCollector) RetrieveProperties(ctx *Context, r *types.RetrieveProperties) soap.HasFault {
  436. body := &methods.RetrievePropertiesBody{}
  437. res := pc.RetrievePropertiesEx(ctx, &types.RetrievePropertiesEx{
  438. This: r.This,
  439. SpecSet: r.SpecSet,
  440. })
  441. if res.Fault() != nil {
  442. body.Fault_ = res.Fault()
  443. } else {
  444. body.Res = &types.RetrievePropertiesResponse{
  445. Returnval: res.(*methods.RetrievePropertiesExBody).Res.Returnval.Objects,
  446. }
  447. }
  448. return body
  449. }
  450. func (pc *PropertyCollector) CancelWaitForUpdates(r *types.CancelWaitForUpdates) soap.HasFault {
  451. pc.mu.Lock()
  452. if pc.cancel != nil {
  453. pc.cancel()
  454. }
  455. pc.mu.Unlock()
  456. return &methods.CancelWaitForUpdatesBody{Res: new(types.CancelWaitForUpdatesResponse)}
  457. }
  458. func (pc *PropertyCollector) update(u types.ObjectUpdate) {
  459. pc.mu.Lock()
  460. pc.updates = append(pc.updates, u)
  461. pc.mu.Unlock()
  462. }
  463. func (pc *PropertyCollector) PutObject(o mo.Reference) {
  464. pc.update(types.ObjectUpdate{
  465. Obj: o.Reference(),
  466. Kind: types.ObjectUpdateKindEnter,
  467. ChangeSet: nil,
  468. })
  469. }
  470. func (pc *PropertyCollector) UpdateObject(o mo.Reference, changes []types.PropertyChange) {
  471. pc.update(types.ObjectUpdate{
  472. Obj: o.Reference(),
  473. Kind: types.ObjectUpdateKindModify,
  474. ChangeSet: changes,
  475. })
  476. }
  477. func (pc *PropertyCollector) RemoveObject(ref types.ManagedObjectReference) {
  478. pc.update(types.ObjectUpdate{
  479. Obj: ref,
  480. Kind: types.ObjectUpdateKindLeave,
  481. ChangeSet: nil,
  482. })
  483. }
  484. func (pc *PropertyCollector) apply(ctx *Context, update *types.UpdateSet) types.BaseMethodFault {
  485. for _, ref := range pc.Filter {
  486. filter := ctx.Session.Get(ref).(*PropertyFilter)
  487. r := &types.RetrievePropertiesEx{}
  488. r.SpecSet = append(r.SpecSet, filter.Spec)
  489. res, fault := pc.collect(ctx, r)
  490. if fault != nil {
  491. return fault
  492. }
  493. fu := types.PropertyFilterUpdate{
  494. Filter: ref,
  495. }
  496. for _, o := range res.Objects {
  497. if _, ok := filter.refs[o.Obj]; ok {
  498. continue
  499. }
  500. filter.refs[o.Obj] = struct{}{}
  501. ou := types.ObjectUpdate{
  502. Obj: o.Obj,
  503. Kind: types.ObjectUpdateKindEnter,
  504. }
  505. for _, p := range o.PropSet {
  506. ou.ChangeSet = append(ou.ChangeSet, types.PropertyChange{
  507. Op: types.PropertyChangeOpAssign,
  508. Name: p.Name,
  509. Val: p.Val,
  510. })
  511. }
  512. fu.ObjectSet = append(fu.ObjectSet, ou)
  513. }
  514. if len(fu.ObjectSet) != 0 {
  515. update.FilterSet = append(update.FilterSet, fu)
  516. }
  517. }
  518. return nil
  519. }
  520. func (pc *PropertyCollector) WaitForUpdatesEx(ctx *Context, r *types.WaitForUpdatesEx) soap.HasFault {
  521. wait, cancel := context.WithCancel(context.Background())
  522. oneUpdate := false
  523. if r.Options != nil {
  524. if max := r.Options.MaxWaitSeconds; max != nil {
  525. // A value of 0 causes WaitForUpdatesEx to do one update calculation and return any results.
  526. oneUpdate = (*max == 0)
  527. if *max > 0 {
  528. wait, cancel = context.WithTimeout(context.Background(), time.Second*time.Duration(*max))
  529. }
  530. }
  531. }
  532. pc.mu.Lock()
  533. pc.cancel = cancel
  534. pc.mu.Unlock()
  535. body := &methods.WaitForUpdatesExBody{}
  536. set := &types.UpdateSet{
  537. Version: r.Version,
  538. }
  539. body.Res = &types.WaitForUpdatesExResponse{
  540. Returnval: set,
  541. }
  542. apply := func() bool {
  543. if fault := pc.apply(ctx, set); fault != nil {
  544. body.Fault_ = Fault("", fault)
  545. body.Res = nil
  546. return false
  547. }
  548. return true
  549. }
  550. if r.Version == "" {
  551. apply() // Collect current state
  552. set.Version = "-" // Next request with Version set will wait via loop below
  553. ctx.Map.AddHandler(pc) // Listen for create, update, delete of managed objects
  554. return body
  555. }
  556. ticker := time.NewTicker(250 * time.Millisecond) // allow for updates to accumulate
  557. defer ticker.Stop()
  558. // Start the wait loop, returning on one of:
  559. // - Client calls CancelWaitForUpdates
  560. // - MaxWaitSeconds was specified and has been exceeded
  561. // - We have updates to send to the client
  562. for {
  563. select {
  564. case <-wait.Done():
  565. body.Res.Returnval = nil
  566. switch wait.Err() {
  567. case context.Canceled:
  568. log.Printf("%s: WaitForUpdates canceled", pc.Self)
  569. body.Fault_ = Fault("", new(types.RequestCanceled)) // CancelWaitForUpdates was called
  570. body.Res = nil
  571. case context.DeadlineExceeded:
  572. log.Printf("%s: WaitForUpdates MaxWaitSeconds exceeded", pc.Self)
  573. }
  574. return body
  575. case <-ticker.C:
  576. pc.mu.Lock()
  577. updates := pc.updates
  578. pc.updates = nil // clear updates collected by the managed object CRUD listeners
  579. pc.mu.Unlock()
  580. if len(updates) == 0 {
  581. if oneUpdate == true {
  582. body.Res.Returnval = nil
  583. return body
  584. }
  585. continue
  586. }
  587. log.Printf("%s: applying %d updates to %d filters", pc.Self, len(updates), len(pc.Filter))
  588. for _, f := range pc.Filter {
  589. filter := ctx.Session.Get(f).(*PropertyFilter)
  590. fu := types.PropertyFilterUpdate{Filter: f}
  591. for _, update := range updates {
  592. switch update.Kind {
  593. case types.ObjectUpdateKindEnter: // Create
  594. if !apply() {
  595. return body
  596. }
  597. case types.ObjectUpdateKindModify: // Update
  598. log.Printf("%s has %d changes", update.Obj, len(update.ChangeSet))
  599. if !apply() { // An update may apply to collector traversal specs
  600. return body
  601. }
  602. if _, ok := filter.refs[update.Obj]; ok {
  603. // This object has already been applied by the filter,
  604. // now check if the property spec applies for this update.
  605. update = filter.apply(ctx, update)
  606. if len(update.ChangeSet) != 0 {
  607. fu.ObjectSet = append(fu.ObjectSet, update)
  608. }
  609. }
  610. case types.ObjectUpdateKindLeave: // Delete
  611. if _, ok := filter.refs[update.Obj]; !ok {
  612. continue
  613. }
  614. delete(filter.refs, update.Obj)
  615. fu.ObjectSet = append(fu.ObjectSet, update)
  616. }
  617. }
  618. if len(fu.ObjectSet) != 0 {
  619. set.FilterSet = append(set.FilterSet, fu)
  620. }
  621. }
  622. if len(set.FilterSet) != 0 {
  623. return body
  624. }
  625. if oneUpdate == true {
  626. body.Res.Returnval = nil
  627. return body
  628. }
  629. }
  630. }
  631. }
  632. // WaitForUpdates is deprecated, but pyvmomi is still using it at the moment.
  633. func (pc *PropertyCollector) WaitForUpdates(ctx *Context, r *types.WaitForUpdates) soap.HasFault {
  634. body := &methods.WaitForUpdatesBody{}
  635. res := pc.WaitForUpdatesEx(ctx, &types.WaitForUpdatesEx{
  636. This: r.This,
  637. Version: r.Version,
  638. })
  639. if res.Fault() != nil {
  640. body.Fault_ = res.Fault()
  641. } else {
  642. body.Res = &types.WaitForUpdatesResponse{
  643. Returnval: *res.(*methods.WaitForUpdatesExBody).Res.Returnval,
  644. }
  645. }
  646. return body
  647. }