github.com/vmware/govmomi@v0.43.0/simulator/view_manager.go (about) 1 /* 2 Copyright (c) 2017-2023 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 simulator 18 19 import ( 20 "reflect" 21 22 "github.com/vmware/govmomi/vim25/methods" 23 "github.com/vmware/govmomi/vim25/mo" 24 "github.com/vmware/govmomi/vim25/soap" 25 "github.com/vmware/govmomi/vim25/types" 26 ) 27 28 type ViewManager struct { 29 mo.ViewManager 30 31 entities map[string]bool 32 } 33 34 var entities = []struct { 35 Type reflect.Type 36 Container bool 37 }{ 38 {reflect.TypeOf((*mo.ManagedEntity)(nil)).Elem(), true}, 39 {reflect.TypeOf((*mo.Folder)(nil)).Elem(), true}, 40 {reflect.TypeOf((*mo.StoragePod)(nil)).Elem(), true}, 41 {reflect.TypeOf((*mo.Datacenter)(nil)).Elem(), true}, 42 {reflect.TypeOf((*mo.ComputeResource)(nil)).Elem(), true}, 43 {reflect.TypeOf((*mo.ClusterComputeResource)(nil)).Elem(), true}, 44 {reflect.TypeOf((*mo.HostSystem)(nil)).Elem(), true}, 45 {reflect.TypeOf((*mo.ResourcePool)(nil)).Elem(), true}, 46 {reflect.TypeOf((*mo.VirtualApp)(nil)).Elem(), true}, 47 {reflect.TypeOf((*mo.VirtualMachine)(nil)).Elem(), false}, 48 {reflect.TypeOf((*mo.Datastore)(nil)).Elem(), false}, 49 {reflect.TypeOf((*mo.Network)(nil)).Elem(), false}, 50 {reflect.TypeOf((*mo.OpaqueNetwork)(nil)).Elem(), false}, 51 {reflect.TypeOf((*mo.DistributedVirtualPortgroup)(nil)).Elem(), false}, 52 {reflect.TypeOf((*mo.DistributedVirtualSwitch)(nil)).Elem(), false}, 53 {reflect.TypeOf((*mo.VmwareDistributedVirtualSwitch)(nil)).Elem(), false}, 54 } 55 56 func (m *ViewManager) init(*Registry) { 57 m.entities = make(map[string]bool, len(entities)) 58 for _, e := range entities { 59 m.entities[e.Type.Name()] = e.Container 60 } 61 } 62 63 func destroyView(ref types.ManagedObjectReference) soap.HasFault { 64 return &methods.DestroyViewBody{ 65 Res: &types.DestroyViewResponse{}, 66 } 67 } 68 69 func (m *ViewManager) CreateContainerView(ctx *Context, req *types.CreateContainerView) soap.HasFault { 70 body := &methods.CreateContainerViewBody{} 71 72 root := ctx.Map.Get(req.Container) 73 if root == nil { 74 body.Fault_ = Fault("", &types.ManagedObjectNotFound{Obj: req.Container}) 75 return body 76 } 77 78 if !m.entities[root.Reference().Type] { 79 body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "container"}) 80 return body 81 } 82 83 container := &ContainerView{ 84 mo.ContainerView{ 85 Container: root.Reference(), 86 Recursive: req.Recursive, 87 Type: req.Type, 88 }, 89 root, 90 make(map[string]bool), 91 } 92 93 for _, ctype := range container.Type { 94 if _, ok := m.entities[ctype]; !ok { 95 body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "type"}) 96 return body 97 } 98 99 container.types[ctype] = true 100 101 for _, e := range entities { 102 // Check for embedded types 103 if f, ok := e.Type.FieldByName(ctype); ok && f.Anonymous { 104 container.types[e.Type.Name()] = true 105 } 106 } 107 } 108 109 ctx.Session.setReference(container) 110 111 body.Res = &types.CreateContainerViewResponse{ 112 Returnval: container.Self, 113 } 114 115 seen := make(map[types.ManagedObjectReference]bool) 116 container.add(root, seen) 117 118 ctx.Session.Registry.Put(container) 119 ctx.Map.AddHandler(container) 120 121 return body 122 } 123 124 type ContainerView struct { 125 mo.ContainerView 126 127 root mo.Reference 128 types map[string]bool 129 } 130 131 func (v *ContainerView) DestroyView(ctx *Context, c *types.DestroyView) soap.HasFault { 132 ctx.Map.RemoveHandler(v) 133 ctx.Session.Remove(ctx, c.This) 134 return destroyView(c.This) 135 } 136 137 func (v *ContainerView) include(o types.ManagedObjectReference) bool { 138 if len(v.types) == 0 { 139 return true 140 } 141 142 return v.types[o.Type] 143 } 144 145 func walk(root mo.Reference, f func(child types.ManagedObjectReference)) { 146 if _, ok := root.(types.ManagedObjectReference); ok || root == nil { 147 return 148 } 149 150 var children []types.ManagedObjectReference 151 152 switch e := getManagedObject(root).Addr().Interface().(type) { 153 case *mo.Datacenter: 154 children = []types.ManagedObjectReference{e.VmFolder, e.HostFolder, e.DatastoreFolder, e.NetworkFolder} 155 case *mo.Folder: 156 children = e.ChildEntity 157 case *mo.StoragePod: 158 children = e.ChildEntity 159 case *mo.ComputeResource: 160 children = e.Host 161 children = append(children, *e.ResourcePool) 162 case *mo.ClusterComputeResource: 163 children = e.Host 164 children = append(children, *e.ResourcePool) 165 case *mo.ResourcePool: 166 children = e.ResourcePool 167 children = append(children, e.Vm...) 168 case *mo.VirtualApp: 169 children = e.ResourcePool.ResourcePool 170 children = append(children, e.Vm...) 171 case *mo.HostSystem: 172 children = e.Vm 173 } 174 175 for _, child := range children { 176 f(child) 177 } 178 } 179 180 func (v *ContainerView) add(root mo.Reference, seen map[types.ManagedObjectReference]bool) { 181 walk(root, func(child types.ManagedObjectReference) { 182 if v.include(child) { 183 if !seen[child] { 184 seen[child] = true 185 v.View = append(v.View, child) 186 } 187 } 188 189 if v.Recursive { 190 v.add(Map.Get(child), seen) 191 } 192 }) 193 } 194 195 func (v *ContainerView) find(root mo.Reference, ref types.ManagedObjectReference, found *bool) bool { 196 walk(root, func(child types.ManagedObjectReference) { 197 if *found { 198 return 199 } 200 if child == ref { 201 *found = true 202 return 203 } 204 if v.Recursive { 205 *found = v.find(Map.Get(child), ref, found) 206 } 207 }) 208 209 return *found 210 } 211 212 func (v *ContainerView) PutObject(obj mo.Reference) { 213 ref := obj.Reference() 214 215 if v.include(ref) && v.find(v.root, ref, types.NewBool(false)) { 216 Map.Update(v, []types.PropertyChange{{Name: "view", Val: append(v.View, ref)}}) 217 } 218 } 219 220 func (v *ContainerView) RemoveObject(ctx *Context, obj types.ManagedObjectReference) { 221 ctx.Map.RemoveReference(ctx, v, &v.View, obj) 222 } 223 224 func (*ContainerView) UpdateObject(mo.Reference, []types.PropertyChange) {} 225 226 func (m *ViewManager) CreateListView(ctx *Context, req *types.CreateListView) soap.HasFault { 227 body := new(methods.CreateListViewBody) 228 list := new(ListView) 229 230 if refs := list.add(ctx, req.Obj); len(refs) != 0 { 231 body.Fault_ = Fault("", &types.ManagedObjectNotFound{Obj: refs[0]}) 232 return body 233 } 234 235 ctx.Session.Put(list) 236 237 body.Res = &types.CreateListViewResponse{ 238 Returnval: list.Self, 239 } 240 241 return body 242 } 243 244 type ListView struct { 245 mo.ListView 246 } 247 248 func (v *ListView) update(ctx *Context) { 249 ctx.Map.Update(v, []types.PropertyChange{{Name: "view", Val: v.View}}) 250 } 251 252 func (v *ListView) add(ctx *Context, refs []types.ManagedObjectReference) []types.ManagedObjectReference { 253 var unresolved []types.ManagedObjectReference 254 for _, ref := range refs { 255 obj := ctx.Session.Get(ref) 256 if obj == nil { 257 unresolved = append(unresolved, ref) 258 } 259 v.View = append(v.View, ref) 260 } 261 return unresolved 262 } 263 264 func (v *ListView) DestroyView(ctx *Context, c *types.DestroyView) soap.HasFault { 265 ctx.Session.Remove(ctx, c.This) 266 return destroyView(c.This) 267 } 268 269 func (v *ListView) ModifyListView(ctx *Context, req *types.ModifyListView) soap.HasFault { 270 body := &methods.ModifyListViewBody{ 271 Res: new(types.ModifyListViewResponse), 272 } 273 274 body.Res.Returnval = v.add(ctx, req.Add) 275 276 for _, ref := range req.Remove { 277 RemoveReference(&v.View, ref) 278 if ctx.Map.Get(ref) == nil { 279 body.Res.Returnval = append(body.Res.Returnval, ref) 280 } 281 } 282 283 if len(req.Remove) != 0 || len(req.Add) != 0 { 284 v.update(ctx) 285 } 286 287 return body 288 } 289 290 func (v *ListView) ResetListView(ctx *Context, req *types.ResetListView) soap.HasFault { 291 body := &methods.ResetListViewBody{ 292 Res: new(types.ResetListViewResponse), 293 } 294 295 v.View = nil 296 297 body.Res.Returnval = v.add(ctx, req.Obj) 298 299 v.update(ctx) 300 301 return body 302 }