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