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