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) RetrieveProperties(ctx context.Context, req types.RetrieveProperties) (*types.RetrievePropertiesResponse, error) { 115 req.This = p.Reference() 116 return methods.RetrieveProperties(ctx, p.roundTripper, &req) 117} 118 119// Retrieve loads properties for a slice of managed objects. The dst argument 120// must be a pointer to a []interface{}, which is populated with the instances 121// of the specified managed objects, with the relevant properties filled in. If 122// the properties slice is nil, all properties are loaded. 123func (p *Collector) Retrieve(ctx context.Context, objs []types.ManagedObjectReference, ps []string, dst interface{}) error { 124 if len(objs) == 0 { 125 return errors.New("object references is empty") 126 } 127 128 var propSpec *types.PropertySpec 129 var objectSet []types.ObjectSpec 130 131 for _, obj := range objs { 132 // Ensure that all object reference types are the same 133 if propSpec == nil { 134 propSpec = &types.PropertySpec{ 135 Type: obj.Type, 136 } 137 138 if ps == nil { 139 propSpec.All = types.NewBool(true) 140 } else { 141 propSpec.PathSet = ps 142 } 143 } else { 144 if obj.Type != propSpec.Type { 145 return errors.New("object references must have the same type") 146 } 147 } 148 149 objectSpec := types.ObjectSpec{ 150 Obj: obj, 151 Skip: types.NewBool(false), 152 } 153 154 objectSet = append(objectSet, objectSpec) 155 } 156 157 req := types.RetrieveProperties{ 158 SpecSet: []types.PropertyFilterSpec{ 159 { 160 ObjectSet: objectSet, 161 PropSet: []types.PropertySpec{*propSpec}, 162 }, 163 }, 164 } 165 166 res, err := p.RetrieveProperties(ctx, req) 167 if err != nil { 168 return err 169 } 170 171 if d, ok := dst.(*[]types.ObjectContent); ok { 172 *d = res.Returnval 173 return nil 174 } 175 176 return mo.LoadRetrievePropertiesResponse(res, dst) 177} 178 179// RetrieveWithFilter populates dst as Retrieve does, but only for entities matching the given filter. 180func (p *Collector) RetrieveWithFilter(ctx context.Context, objs []types.ManagedObjectReference, ps []string, dst interface{}, filter Filter) error { 181 if len(filter) == 0 { 182 return p.Retrieve(ctx, objs, ps, dst) 183 } 184 185 var content []types.ObjectContent 186 187 err := p.Retrieve(ctx, objs, filter.Keys(), &content) 188 if err != nil { 189 return err 190 } 191 192 objs = filter.MatchObjectContent(content) 193 194 if len(objs) == 0 { 195 return nil 196 } 197 198 return p.Retrieve(ctx, objs, ps, dst) 199} 200 201// RetrieveOne calls Retrieve with a single managed object reference. 202func (p *Collector) RetrieveOne(ctx context.Context, obj types.ManagedObjectReference, ps []string, dst interface{}) error { 203 var objs = []types.ManagedObjectReference{obj} 204 return p.Retrieve(ctx, objs, ps, dst) 205} 206