github.com/vmware/govmomi@v0.51.0/simulator/datacenter.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 "log" 9 "strings" 10 11 "github.com/vmware/govmomi/simulator/esx" 12 "github.com/vmware/govmomi/vim25/methods" 13 "github.com/vmware/govmomi/vim25/mo" 14 "github.com/vmware/govmomi/vim25/soap" 15 "github.com/vmware/govmomi/vim25/types" 16 ) 17 18 type Datacenter struct { 19 mo.Datacenter 20 21 isESX bool 22 } 23 24 // NewDatacenter creates a Datacenter and its child folders. 25 func NewDatacenter(ctx *Context, f *mo.Folder) *Datacenter { 26 dc := &Datacenter{ 27 isESX: f.Self == esx.RootFolder.Self, 28 } 29 30 if dc.isESX { 31 dc.Datacenter = esx.Datacenter 32 } 33 34 folderPutChild(ctx, f, dc) 35 36 dc.createFolders(ctx) 37 38 return dc 39 } 40 41 func (dc *Datacenter) RenameTask(ctx *Context, r *types.Rename_Task) soap.HasFault { 42 return RenameTask(ctx, dc, r) 43 } 44 45 // Create Datacenter Folders. 46 // Every Datacenter has 4 inventory Folders: Vm, Host, Datastore and Network. 47 // The ESX folder child types are limited to 1 type. 48 // The VC folders have additional child types, including nested folders. 49 func (dc *Datacenter) createFolders(ctx *Context) { 50 folders := []struct { 51 ref *types.ManagedObjectReference 52 name string 53 types []string 54 }{ 55 {&dc.VmFolder, "vm", []string{"VirtualMachine", "VirtualApp", "Folder"}}, 56 {&dc.HostFolder, "host", []string{"ComputeResource", "Folder"}}, 57 {&dc.DatastoreFolder, "datastore", []string{"Datastore", "StoragePod", "Folder"}}, 58 {&dc.NetworkFolder, "network", []string{"Network", "DistributedVirtualSwitch", "Folder"}}, 59 } 60 61 for _, f := range folders { 62 folder := &Folder{} 63 folder.Name = f.name 64 65 if dc.isESX { 66 folder.ChildType = f.types[:1] 67 folder.Self = *f.ref 68 ctx.Map.PutEntity(dc, folder) 69 } else { 70 folder.ChildType = f.types 71 e := ctx.Map.PutEntity(dc, folder) 72 73 // propagate the generated morefs to Datacenter 74 ref := e.Reference() 75 f.ref.Type = ref.Type 76 f.ref.Value = ref.Value 77 } 78 } 79 80 net := ctx.Map.Get(dc.NetworkFolder).(*Folder) 81 82 for _, ref := range esx.Datacenter.Network { 83 // Add VM Network by default to each Datacenter 84 network := &mo.Network{} 85 network.Self = ref 86 network.Name = strings.Split(ref.Value, "-")[1] 87 network.Entity().Name = network.Name 88 if !dc.isESX { 89 network.Self.Value = "" // we want a different moid per-DC 90 } 91 92 folderPutChild(ctx, &net.Folder, network) 93 } 94 } 95 96 func (dc *Datacenter) defaultNetwork() []types.ManagedObjectReference { 97 return dc.Network[:1] // VM Network 98 } 99 100 // folder returns the Datacenter folder that can contain the given object type 101 func (dc *Datacenter) folder(ctx *Context, obj mo.Entity) *mo.Folder { 102 folders := []types.ManagedObjectReference{ 103 dc.VmFolder, 104 dc.HostFolder, 105 dc.DatastoreFolder, 106 dc.NetworkFolder, 107 } 108 otype := getManagedObject(obj).Type() 109 rtype := obj.Reference().Type 110 111 for i := range folders { 112 folder, _ := asFolderMO(ctx.Map.Get(folders[i])) 113 for _, kind := range folder.ChildType { 114 if rtype == kind { 115 return folder 116 } 117 if f, ok := otype.FieldByName(kind); ok && f.Anonymous { 118 return folder 119 } 120 } 121 } 122 123 log.Panicf("failed to find folder for type=%s", rtype) 124 return nil 125 } 126 127 func datacenterEventArgument(ctx *Context, obj mo.Entity) *types.DatacenterEventArgument { 128 dc, ok := obj.(*Datacenter) 129 if !ok { 130 dc = ctx.Map.getEntityDatacenter(obj) 131 } 132 return &types.DatacenterEventArgument{ 133 Datacenter: dc.Self, 134 EntityEventArgument: types.EntityEventArgument{Name: dc.Name}, 135 } 136 } 137 138 func (dc *Datacenter) PowerOnMultiVMTask(ctx *Context, req *types.PowerOnMultiVM_Task) soap.HasFault { 139 task := CreateTask(dc, "powerOnMultiVM", func(_ *Task) (types.AnyType, types.BaseMethodFault) { 140 if dc.isESX { 141 return nil, new(types.NotImplemented) 142 } 143 144 // Return per-VM tasks, structured as: 145 // thisTask.result - DC level task 146 // +- []Attempted 147 // +- subTask.result - VM level powerOn task result 148 // +- ... 149 res := types.ClusterPowerOnVmResult{} 150 res.Attempted = []types.ClusterAttemptedVmInfo{} 151 152 for _, ref := range req.Vm { 153 vm, ok := ctx.Map.Get(ref).(*VirtualMachine) 154 if !ok { 155 continue 156 } 157 // This task creates multiple subtasks which violates the assumption 158 // of 1:1 Context:Task, which results in data races in objects 159 // like the Simulator.Event manager. This is the minimum context 160 // required for the PowerOnVMTask to complete. 161 taskCtx := &Context{ 162 Context: ctx.Context, 163 Session: ctx.Session, 164 Map: ctx.Map, 165 } 166 167 // NOTE: Simulator does not actually perform any specific host-level placement 168 // (equivalent to vSphere DRS). 169 taskCtx.WithLock(vm, func() { 170 vmTaskBody := vm.PowerOnVMTask(taskCtx, &types.PowerOnVM_Task{}).(*methods.PowerOnVM_TaskBody) 171 res.Attempted = append(res.Attempted, types.ClusterAttemptedVmInfo{Vm: ref, Task: &vmTaskBody.Res.Returnval}) 172 }) 173 } 174 175 return res, nil 176 }) 177 178 return &methods.PowerOnMultiVM_TaskBody{ 179 Res: &types.PowerOnMultiVM_TaskResponse{ 180 Returnval: task.Run(ctx), 181 }, 182 } 183 } 184 185 func (d *Datacenter) DestroyTask(ctx *Context, req *types.Destroy_Task) soap.HasFault { 186 task := CreateTask(d, "destroy", func(t *Task) (types.AnyType, types.BaseMethodFault) { 187 folders := []types.ManagedObjectReference{ 188 d.VmFolder, 189 d.HostFolder, 190 } 191 192 for _, ref := range folders { 193 f, _ := asFolderMO(ctx.Map.Get(ref)) 194 if len(f.ChildEntity) != 0 { 195 return nil, &types.ResourceInUse{} 196 } 197 } 198 199 p, _ := asFolderMO(ctx.Map.Get(*d.Parent)) 200 folderRemoveChild(ctx, p, d.Self) 201 202 return nil, nil 203 }) 204 205 return &methods.Destroy_TaskBody{ 206 Res: &types.Destroy_TaskResponse{ 207 Returnval: task.Run(ctx), 208 }, 209 } 210 }