1/* 2Copyright (c) 2015 VMware, Inc. All Rights Reserved. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package property 18 19import ( 20 "context" 21 "errors" 22 23 "github.com/vmware/govmomi/vim25" 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 30// Collector models the PropertyCollector managed object. 31// 32// For more information, see: 33// http://pubs.vmware.com/vsphere-60/index.jsp?topic=%2Fcom.vmware.wssdk.apiref.doc%2Fvmodl.query.PropertyCollector.html 34// 35type Collector struct { 36 roundTripper soap.RoundTripper 37 reference types.ManagedObjectReference 38} 39 40// DefaultCollector returns the session's default property collector. 41func DefaultCollector(c *vim25.Client) *Collector { 42 p := Collector{ 43 roundTripper: c, 44 reference: c.ServiceContent.PropertyCollector, 45 } 46 47 return &p 48} 49 50func (p Collector) Reference() types.ManagedObjectReference { 51 return p.reference 52} 53 54// Create creates a new session-specific Collector that can be used to 55// retrieve property updates independent of any other Collector. 56func (p *Collector) Create(ctx context.Context) (*Collector, error) { 57 req := types.CreatePropertyCollector{ 58 This: p.Reference(), 59 } 60 61 res, err := methods.CreatePropertyCollector(ctx, p.roundTripper, &req) 62 if err != nil { 63 return nil, err 64 } 65 66 newp := Collector{ 67 roundTripper: p.roundTripper, 68 reference: res.Returnval, 69 } 70 71 return &newp, nil 72} 73 74// Destroy destroys this Collector. 75func (p *Collector) Destroy(ctx context.Context) error { 76 req := types.DestroyPropertyCollector{ 77 This: p.Reference(), 78 } 79 80 _, err := methods.DestroyPropertyCollector(ctx, p.roundTripper, &req) 81 if err != nil { 82 return err 83 } 84 85 p.reference = types.ManagedObjectReference{} 86 return nil 87} 88 89func (p *Collector) CreateFilter(ctx context.Context, req types.CreateFilter) error { 90 req.This = p.Reference() 91 92 _, err := methods.CreateFilter(ctx, p.roundTripper, &req) 93 if err != nil { 94 return err 95 } 96 97 return nil 98} 99 100func (p *Collector) WaitForUpdates(ctx context.Context, v string) (*types.UpdateSet, error) { 101 req := types.WaitForUpdatesEx{ 102 This: p.Reference(), 103 Version: v, 104 } 105 106 res, err := methods.WaitForUpdatesEx(ctx, p.roundTripper, &req) 107 if err != nil { 108 return nil, err 109 } 110 111 return res.Returnval, nil 112} 113 114func (p *Collector) CancelWaitForUpdates(ctx context.Context) error { 115 req := &types.CancelWaitForUpdates{This: p.Reference()} 116 _, err := methods.CancelWaitForUpdates(ctx, p.roundTripper, req) 117 return err 118} 119 120func (p *Collector) RetrieveProperties(ctx context.Context, req types.RetrieveProperties) (*types.RetrievePropertiesResponse, error) { 121 req.This = p.Reference() 122 return methods.RetrieveProperties(ctx, p.roundTripper, &req) 123} 124 125// Retrieve loads properties for a slice of managed objects. The dst argument 126// must be a pointer to a []interface{}, which is populated with the instances 127// of the specified managed objects, with the relevant properties filled in. If 128// the properties slice is nil, all properties are loaded. 129// Note that pointer types are optional fields that may be left as a nil value. 130// The caller should check such fields for a nil value before dereferencing. 131func (p *Collector) Retrieve(ctx context.Context, objs []types.ManagedObjectReference, ps []string, dst interface{}) error { 132 if len(objs) == 0 { 133 return errors.New("object references is empty") 134 } 135 136 kinds := make(map[string]bool) 137 138 var propSet []types.PropertySpec 139 var objectSet []types.ObjectSpec 140 141 for _, obj := range objs { 142 if _, ok := kinds[obj.Type]; !ok { 143 spec := types.PropertySpec{ 144 Type: obj.Type, 145 } 146 if ps == nil { 147 spec.All = types.NewBool(true) 148 } else { 149 spec.PathSet = ps 150 } 151 propSet = append(propSet, spec) 152 kinds[obj.Type] = true 153 } 154 155 objectSpec := types.ObjectSpec{ 156 Obj: obj, 157 Skip: types.NewBool(false), 158 } 159 160 objectSet = append(objectSet, objectSpec) 161 } 162 163 req := types.RetrieveProperties{ 164 SpecSet: []types.PropertyFilterSpec{ 165 { 166 ObjectSet: objectSet, 167 PropSet: propSet, 168 }, 169 }, 170 } 171 172 res, err := p.RetrieveProperties(ctx, req) 173 if err != nil { 174 return err 175 } 176 177 if d, ok := dst.(*[]types.ObjectContent); ok { 178 *d = res.Returnval 179 return nil 180 } 181 182 return mo.LoadRetrievePropertiesResponse(res, dst) 183} 184 185// RetrieveWithFilter populates dst as Retrieve does, but only for entities matching the given filter. 186func (p *Collector) RetrieveWithFilter(ctx context.Context, objs []types.ManagedObjectReference, ps []string, dst interface{}, filter Filter) error { 187 if len(filter) == 0 { 188 return p.Retrieve(ctx, objs, ps, dst) 189 } 190 191 var content []types.ObjectContent 192 193 err := p.Retrieve(ctx, objs, filter.Keys(), &content) 194 if err != nil { 195 return err 196 } 197 198 objs = filter.MatchObjectContent(content) 199 200 if len(objs) == 0 { 201 return nil 202 } 203 204 return p.Retrieve(ctx, objs, ps, dst) 205} 206 207// RetrieveOne calls Retrieve with a single managed object reference via Collector.Retrieve(). 208func (p *Collector) RetrieveOne(ctx context.Context, obj types.ManagedObjectReference, ps []string, dst interface{}) error { 209 var objs = []types.ManagedObjectReference{obj} 210 return p.Retrieve(ctx, objs, ps, dst) 211} 212