1/* 2Copyright (c) 2017 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 simulator 18 19import ( 20 "fmt" 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 30type ResourcePool struct { 31 mo.ResourcePool 32} 33 34func NewResourcePool() *ResourcePool { 35 pool := &ResourcePool{ 36 ResourcePool: esx.ResourcePool, 37 } 38 39 if Map.IsVPX() { 40 pool.DisabledMethod = nil // Enable VApp methods for VC 41 } 42 43 return pool 44} 45 46func allResourceFieldsSet(info *types.ResourceAllocationInfo) bool { 47 return info.Reservation != nil && 48 info.Limit != nil && 49 info.ExpandableReservation != nil && 50 info.Shares != nil 51} 52 53func allResourceFieldsValid(info *types.ResourceAllocationInfo) bool { 54 if info.Reservation != nil { 55 if *info.Reservation < 0 { 56 return false 57 } 58 } 59 60 if info.Limit != nil { 61 if *info.Limit < -1 { 62 return false 63 } 64 } 65 66 if info.Shares != nil { 67 if info.Shares.Level == types.SharesLevelCustom { 68 if info.Shares.Shares < 0 { 69 return false 70 } 71 } 72 } 73 74 if info.OverheadLimit != nil { 75 return false 76 } 77 78 return true 79} 80 81func (p *ResourcePool) createChild(name string, spec types.ResourceConfigSpec) (*ResourcePool, *soap.Fault) { 82 if e := Map.FindByName(name, p.ResourcePool.ResourcePool); e != nil { 83 return nil, Fault("", &types.DuplicateName{ 84 Name: e.Entity().Name, 85 Object: e.Reference(), 86 }) 87 } 88 89 if !(allResourceFieldsSet(&spec.CpuAllocation) && allResourceFieldsValid(&spec.CpuAllocation)) { 90 return nil, Fault("", &types.InvalidArgument{ 91 InvalidProperty: "spec.cpuAllocation", 92 }) 93 } 94 95 if !(allResourceFieldsSet(&spec.MemoryAllocation) && allResourceFieldsValid(&spec.MemoryAllocation)) { 96 return nil, Fault("", &types.InvalidArgument{ 97 InvalidProperty: "spec.memoryAllocation", 98 }) 99 } 100 101 child := NewResourcePool() 102 103 child.Name = name 104 child.Owner = p.Owner 105 child.Summary.GetResourcePoolSummary().Name = name 106 child.Config.CpuAllocation = spec.CpuAllocation 107 child.Config.MemoryAllocation = spec.MemoryAllocation 108 child.Config.Entity = spec.Entity 109 110 return child, nil 111} 112 113func (p *ResourcePool) CreateResourcePool(c *types.CreateResourcePool) soap.HasFault { 114 body := &methods.CreateResourcePoolBody{} 115 116 child, err := p.createChild(c.Name, c.Spec) 117 if err != nil { 118 body.Fault_ = err 119 return body 120 } 121 122 Map.PutEntity(p, Map.NewEntity(child)) 123 124 p.ResourcePool.ResourcePool = append(p.ResourcePool.ResourcePool, child.Reference()) 125 126 body.Res = &types.CreateResourcePoolResponse{ 127 Returnval: child.Reference(), 128 } 129 130 return body 131} 132 133func updateResourceAllocation(kind string, src, dst *types.ResourceAllocationInfo) types.BaseMethodFault { 134 if !allResourceFieldsValid(src) { 135 return &types.InvalidArgument{ 136 InvalidProperty: fmt.Sprintf("spec.%sAllocation", kind), 137 } 138 } 139 140 if src.Reservation != nil { 141 dst.Reservation = src.Reservation 142 } 143 144 if src.Limit != nil { 145 dst.Limit = src.Limit 146 } 147 148 if src.Shares != nil { 149 dst.Shares = src.Shares 150 } 151 152 return nil 153} 154 155func (p *ResourcePool) UpdateConfig(c *types.UpdateConfig) soap.HasFault { 156 body := &methods.UpdateConfigBody{} 157 158 if c.Name != "" { 159 if e := Map.FindByName(c.Name, p.ResourcePool.ResourcePool); e != nil { 160 body.Fault_ = Fault("", &types.DuplicateName{ 161 Name: e.Entity().Name, 162 Object: e.Reference(), 163 }) 164 return body 165 } 166 167 p.Name = c.Name 168 } 169 170 spec := c.Config 171 172 if spec != nil { 173 if err := updateResourceAllocation("memory", &spec.MemoryAllocation, &p.Config.MemoryAllocation); err != nil { 174 body.Fault_ = Fault("", err) 175 return body 176 } 177 178 if err := updateResourceAllocation("cpu", &spec.CpuAllocation, &p.Config.CpuAllocation); err != nil { 179 body.Fault_ = Fault("", err) 180 return body 181 } 182 } 183 184 body.Res = &types.UpdateConfigResponse{} 185 186 return body 187} 188 189type VirtualApp struct { 190 mo.VirtualApp 191} 192 193func NewVAppConfigSpec() types.VAppConfigSpec { 194 spec := types.VAppConfigSpec{ 195 Annotation: "vcsim", 196 VmConfigSpec: types.VmConfigSpec{ 197 Product: []types.VAppProductSpec{ 198 { 199 Info: &types.VAppProductInfo{ 200 Name: "vcsim", 201 Vendor: "VMware", 202 VendorUrl: "http://www.vmware.com/", 203 Version: "0.1", 204 }, 205 ArrayUpdateSpec: types.ArrayUpdateSpec{ 206 Operation: types.ArrayUpdateOperationAdd, 207 }, 208 }, 209 }, 210 }, 211 } 212 213 return spec 214} 215 216func (p *ResourcePool) CreateVApp(req *types.CreateVApp) soap.HasFault { 217 body := &methods.CreateVAppBody{} 218 219 pool, err := p.createChild(req.Name, req.ResSpec) 220 if err != nil { 221 body.Fault_ = err 222 return body 223 } 224 225 child := &VirtualApp{} 226 child.ResourcePool = pool.ResourcePool 227 child.Self.Type = "VirtualApp" 228 child.ParentFolder = req.VmFolder 229 230 if child.ParentFolder == nil { 231 folder := Map.getEntityDatacenter(p).VmFolder 232 child.ParentFolder = &folder 233 } 234 235 child.VAppConfig = &types.VAppConfigInfo{ 236 VmConfigInfo: types.VmConfigInfo{}, 237 Annotation: req.ConfigSpec.Annotation, 238 } 239 240 for _, product := range req.ConfigSpec.Product { 241 child.VAppConfig.Product = append(child.VAppConfig.Product, *product.Info) 242 } 243 244 Map.PutEntity(p, Map.NewEntity(child)) 245 246 p.ResourcePool.ResourcePool = append(p.ResourcePool.ResourcePool, child.Reference()) 247 248 body.Res = &types.CreateVAppResponse{ 249 Returnval: child.Reference(), 250 } 251 252 return body 253} 254 255func (a *VirtualApp) CreateChildVMTask(ctx *Context, req *types.CreateChildVM_Task) soap.HasFault { 256 ctx.Caller = &a.Self 257 body := &methods.CreateChildVM_TaskBody{} 258 259 folder := Map.Get(*a.ParentFolder).(*Folder) 260 261 res := folder.CreateVMTask(ctx, &types.CreateVM_Task{ 262 This: folder.Self, 263 Config: req.Config, 264 Host: req.Host, 265 Pool: req.This, 266 }) 267 268 body.Res = &types.CreateChildVM_TaskResponse{ 269 Returnval: res.(*methods.CreateVM_TaskBody).Res.Returnval, 270 } 271 272 return body 273} 274 275func (a *VirtualApp) DestroyTask(req *types.Destroy_Task) soap.HasFault { 276 return (&ResourcePool{ResourcePool: a.ResourcePool}).DestroyTask(req) 277} 278 279func (p *ResourcePool) DestroyTask(req *types.Destroy_Task) soap.HasFault { 280 task := CreateTask(p, "destroy", func(t *Task) (types.AnyType, types.BaseMethodFault) { 281 if strings.HasSuffix(p.Parent.Type, "ComputeResource") { 282 // Can't destroy the root pool 283 return nil, &types.InvalidArgument{} 284 } 285 286 pp := Map.Get(*p.Parent).(*ResourcePool) 287 288 parent := &pp.ResourcePool 289 // Remove child reference from rp 290 Map.RemoveReference(parent, &parent.ResourcePool, req.This) 291 292 // The grandchildren become children of the parent (rp) 293 Map.AppendReference(parent, &parent.ResourcePool, p.ResourcePool.ResourcePool...) 294 295 // And VMs move to the parent 296 vms := p.ResourcePool.Vm 297 for _, ref := range vms { 298 vm := Map.Get(ref).(*VirtualMachine) 299 Map.WithLock(vm, func() { vm.ResourcePool = &parent.Self }) 300 } 301 302 Map.AppendReference(parent, &parent.Vm, vms...) 303 304 Map.Remove(req.This) 305 306 return nil, nil 307 }) 308 309 return &methods.Destroy_TaskBody{ 310 Res: &types.Destroy_TaskResponse{ 311 Returnval: task.Run(), 312 }, 313 } 314} 315