github.com/vmware/govmomi@v0.43.0/simulator/registry.go (about) 1 /* 2 Copyright (c) 2017-2024 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 "encoding/json" 21 "fmt" 22 "log" 23 "os" 24 "reflect" 25 "strings" 26 "sync" 27 "sync/atomic" 28 29 "github.com/vmware/govmomi/simulator/internal" 30 "github.com/vmware/govmomi/vim25" 31 "github.com/vmware/govmomi/vim25/mo" 32 "github.com/vmware/govmomi/vim25/soap" 33 "github.com/vmware/govmomi/vim25/types" 34 ) 35 36 // This is a map from a reference type name to a reference value name prefix. 37 // It's a convention that VirtualCenter follows. The map is not complete, but 38 // it should cover the most popular objects. 39 var refValueMap = map[string]string{ 40 "DistributedVirtualPortgroup": "dvportgroup", 41 "EnvironmentBrowser": "envbrowser", 42 "HostSystem": "host", 43 "ResourcePool": "resgroup", 44 "VirtualMachine": "vm", 45 "VirtualMachineSnapshot": "snapshot", 46 "VmwareDistributedVirtualSwitch": "dvs", 47 "DistributedVirtualSwitch": "dvs", 48 "ClusterComputeResource": "domain-c", 49 "Folder": "group", 50 "StoragePod": "group-p", 51 } 52 53 // Map is the default Registry instance. 54 // 55 // TODO/WIP: To support the eventual removal of this unsyncronized global 56 // variable, the Map should be accessed through any Context.Map that is passed 57 // in to functions that may need it. 58 var Map = NewRegistry() 59 60 // RegisterObject interface supports callbacks when objects are created, updated and deleted from the Registry 61 type RegisterObject interface { 62 mo.Reference 63 PutObject(mo.Reference) 64 UpdateObject(mo.Reference, []types.PropertyChange) 65 RemoveObject(*Context, types.ManagedObjectReference) 66 } 67 68 // Registry manages a map of mo.Reference objects 69 type Registry struct { 70 counter int64 // Keep first to ensure 64-bit alignment 71 m sync.Mutex 72 objects map[types.ManagedObjectReference]mo.Reference 73 handlers map[types.ManagedObjectReference]RegisterObject 74 locks map[types.ManagedObjectReference]*internal.ObjectLock 75 76 Namespace string 77 Path string 78 Handler func(*Context, *Method) (mo.Reference, types.BaseMethodFault) 79 80 tagManager tagManager 81 } 82 83 // tagManager is an interface to simplify internal interaction with the vapi tag manager simulator. 84 type tagManager interface { 85 AttachedObjects(types.VslmTagEntry) ([]types.ManagedObjectReference, types.BaseMethodFault) 86 AttachedTags(id types.ManagedObjectReference) ([]types.VslmTagEntry, types.BaseMethodFault) 87 AttachTag(types.ManagedObjectReference, types.VslmTagEntry) types.BaseMethodFault 88 DetachTag(types.ManagedObjectReference, types.VslmTagEntry) types.BaseMethodFault 89 } 90 91 // NewRegistry creates a new instances of Registry 92 func NewRegistry() *Registry { 93 r := &Registry{ 94 objects: make(map[types.ManagedObjectReference]mo.Reference), 95 handlers: make(map[types.ManagedObjectReference]RegisterObject), 96 locks: make(map[types.ManagedObjectReference]*internal.ObjectLock), 97 98 Namespace: vim25.Namespace, 99 Path: vim25.Path, 100 } 101 102 return r 103 } 104 105 func (r *Registry) typeFunc(name string) (reflect.Type, bool) { 106 if r.Namespace != "" && r.Namespace != vim25.Namespace { 107 if kind, ok := defaultMapType(r.Namespace + ":" + name); ok { 108 return kind, ok 109 } 110 } 111 return defaultMapType(name) 112 } 113 114 // typeName returns the type of the given object. 115 func typeName(item mo.Reference) string { 116 return reflect.TypeOf(item).Elem().Name() 117 } 118 119 // valuePrefix returns the value name prefix of a given object 120 func valuePrefix(typeName string) string { 121 v, ok := refValueMap[typeName] 122 if ok { 123 if strings.Contains(v, "-") { 124 return v 125 } 126 } else { 127 v = strings.ToLower(typeName) 128 } 129 130 return v + "-" 131 } 132 133 // newReference returns a new MOR, where Type defaults to type of the given item 134 // and Value defaults to a unique id for the given type. 135 func (r *Registry) newReference(item mo.Reference) types.ManagedObjectReference { 136 ref := item.Reference() 137 138 if ref.Type == "" { 139 ref.Type = typeName(item) 140 } 141 142 if ref.Value == "" { 143 n := atomic.AddInt64(&r.counter, 1) 144 ref.Value = fmt.Sprintf("%s%d", valuePrefix(ref.Type), n) 145 } 146 147 return ref 148 } 149 150 func (r *Registry) setReference(item mo.Reference, ref types.ManagedObjectReference) { 151 // mo.Reference() returns a value, not a pointer so use reflect to set the Self field 152 reflect.ValueOf(item).Elem().FieldByName("Self").Set(reflect.ValueOf(ref)) 153 } 154 155 // AddHandler adds a RegisterObject handler to the Registry. 156 func (r *Registry) AddHandler(h RegisterObject) { 157 r.m.Lock() 158 r.handlers[h.Reference()] = h 159 r.m.Unlock() 160 } 161 162 // RemoveHandler removes a RegisterObject handler from the Registry. 163 func (r *Registry) RemoveHandler(h RegisterObject) { 164 r.m.Lock() 165 delete(r.handlers, h.Reference()) 166 r.m.Unlock() 167 } 168 169 // NewEntity sets Entity().Self with a new, unique Value. 170 // Useful for creating object instances from templates. 171 func (r *Registry) NewEntity(item mo.Entity) mo.Entity { 172 e := item.Entity() 173 e.Self.Value = "" 174 e.Self = r.newReference(item) 175 return item 176 } 177 178 // PutEntity sets item.Parent to that of parent.Self before adding item to the Registry. 179 func (r *Registry) PutEntity(parent mo.Entity, item mo.Entity) mo.Entity { 180 e := item.Entity() 181 182 if parent != nil { 183 e.Parent = &parent.Entity().Self 184 } 185 186 r.Put(item) 187 188 return item 189 } 190 191 // Get returns the object for the given reference. 192 func (r *Registry) Get(ref types.ManagedObjectReference) mo.Reference { 193 r.m.Lock() 194 defer r.m.Unlock() 195 196 return r.objects[ref] 197 } 198 199 // Any returns the first instance of entity type specified by kind. 200 func (r *Registry) Any(kind string) mo.Entity { 201 r.m.Lock() 202 defer r.m.Unlock() 203 204 for ref, val := range r.objects { 205 if ref.Type == kind { 206 return val.(mo.Entity) 207 } 208 } 209 210 return nil 211 } 212 213 // All returns all entities of type specified by kind. 214 // If kind is empty - all entities will be returned. 215 func (r *Registry) All(kind string) []mo.Entity { 216 r.m.Lock() 217 defer r.m.Unlock() 218 219 var entities []mo.Entity 220 for ref, val := range r.objects { 221 if kind == "" || ref.Type == kind { 222 if e, ok := val.(mo.Entity); ok { 223 entities = append(entities, e) 224 } 225 } 226 } 227 228 return entities 229 } 230 231 // AllReference returns all mo.Reference objects of type specified by kind. 232 // If kind is empty - all objects will be returned. 233 func (r *Registry) AllReference(kind string) []mo.Reference { 234 r.m.Lock() 235 defer r.m.Unlock() 236 237 var objs []mo.Reference 238 for ref, val := range r.objects { 239 if kind == "" || ref.Type == kind { 240 objs = append(objs, val) 241 } 242 } 243 244 return objs 245 } 246 247 // applyHandlers calls the given func for each r.handlers 248 func (r *Registry) applyHandlers(f func(o RegisterObject)) { 249 r.m.Lock() 250 handlers := make([]RegisterObject, 0, len(r.handlers)) 251 for _, handler := range r.handlers { 252 handlers = append(handlers, handler) 253 } 254 r.m.Unlock() 255 256 for i := range handlers { 257 f(handlers[i]) 258 } 259 } 260 261 func (r *Registry) reference(item mo.Reference) types.ManagedObjectReference { 262 ref := item.Reference() 263 if ref.Type == "" || ref.Value == "" { 264 ref = r.newReference(item) 265 r.setReference(item, ref) 266 } 267 return ref 268 } 269 270 // Put adds a new object to Registry, generating a ManagedObjectReference if not already set. 271 func (r *Registry) Put(item mo.Reference) mo.Reference { 272 r.m.Lock() 273 274 if me, ok := item.(mo.Entity); ok { 275 me.Entity().ConfigStatus = types.ManagedEntityStatusGreen 276 me.Entity().OverallStatus = types.ManagedEntityStatusGreen 277 me.Entity().EffectiveRole = []int32{-1} // Admin 278 } 279 280 r.objects[r.reference(item)] = item 281 282 r.m.Unlock() 283 284 r.applyHandlers(func(o RegisterObject) { 285 o.PutObject(item) 286 }) 287 288 return item 289 } 290 291 // Remove removes an object from the Registry. 292 func (r *Registry) Remove(ctx *Context, item types.ManagedObjectReference) { 293 r.applyHandlers(func(o RegisterObject) { 294 o.RemoveObject(ctx, item) 295 }) 296 297 r.m.Lock() 298 delete(r.objects, item) 299 delete(r.handlers, item) 300 delete(r.locks, item) 301 r.m.Unlock() 302 } 303 304 // Update dispatches object property changes to RegisterObject handlers, 305 // such as any PropertyCollector instances with in-progress WaitForUpdates calls. 306 // The changes are also applied to the given object via mo.ApplyPropertyChange, 307 // so there is no need to set object fields directly. 308 func (r *Registry) Update(obj mo.Reference, changes []types.PropertyChange) { 309 for i := range changes { 310 if changes[i].Op == "" { 311 changes[i].Op = types.PropertyChangeOpAssign 312 } 313 if changes[i].Val != nil { 314 rval := reflect.ValueOf(changes[i].Val) 315 changes[i].Val = wrapValue(rval, rval.Type()) 316 } 317 } 318 319 val := getManagedObject(obj).Addr().Interface().(mo.Reference) 320 321 mo.ApplyPropertyChange(val, changes) 322 323 r.applyHandlers(func(o RegisterObject) { 324 o.UpdateObject(val, changes) 325 }) 326 } 327 328 func (r *Registry) AtomicUpdate(ctx *Context, obj mo.Reference, changes []types.PropertyChange) { 329 r.WithLock(ctx, obj, func() { 330 r.Update(obj, changes) 331 }) 332 } 333 334 // getEntityParent traverses up the inventory and returns the first object of type kind. 335 // If no object of type kind is found, the method will panic when it reaches the 336 // inventory root Folder where the Parent field is nil. 337 func (r *Registry) getEntityParent(item mo.Entity, kind string) mo.Entity { 338 var ok bool 339 for { 340 parent := item.Entity().Parent 341 342 item, ok = r.Get(*parent).(mo.Entity) 343 if !ok { 344 return nil 345 } 346 if item.Reference().Type == kind { 347 return item 348 } 349 } 350 } 351 352 // getEntityDatacenter returns the Datacenter containing the given item 353 func (r *Registry) getEntityDatacenter(item mo.Entity) *Datacenter { 354 dc, ok := r.getEntityParent(item, "Datacenter").(*Datacenter) 355 if ok { 356 return dc 357 } 358 return nil 359 } 360 361 func (r *Registry) getEntityFolder(item mo.Entity, kind string) *mo.Folder { 362 dc := r.getEntityDatacenter(item) 363 364 var ref types.ManagedObjectReference 365 366 switch kind { 367 case "datastore": 368 ref = dc.DatastoreFolder 369 } 370 371 folder, _ := asFolderMO(r.Get(ref)) 372 373 // If Model was created with Folder option, use that Folder; else use top-level folder 374 for _, child := range folder.ChildEntity { 375 if child.Type == "Folder" { 376 folder, _ = asFolderMO(r.Get(child)) 377 break 378 } 379 } 380 381 return folder 382 } 383 384 // getEntityComputeResource returns the ComputeResource parent for the given item. 385 // A ResourcePool for example may have N Parents of type ResourcePool, but the top 386 // most Parent pool is always a ComputeResource child. 387 func (r *Registry) getEntityComputeResource(item mo.Entity) mo.Entity { 388 for { 389 parent := item.Entity().Parent 390 391 item = r.Get(*parent).(mo.Entity) 392 393 switch item.Reference().Type { 394 case "ComputeResource": 395 return item 396 case "ClusterComputeResource": 397 return item 398 } 399 } 400 } 401 402 func entityName(e mo.Entity) string { 403 name := e.Entity().Name 404 if name != "" { 405 return name 406 } 407 408 obj := getManagedObject(e).Addr().Interface() 409 410 // The types below have their own 'Name' field, so ManagedEntity.Name (me.Name) is empty. 411 // See also mo.Ancestors 412 switch x := obj.(type) { 413 case *mo.Network: 414 return x.Name 415 case *mo.DistributedVirtualSwitch: 416 return x.Name 417 case *mo.DistributedVirtualPortgroup: 418 return x.Name 419 case *mo.OpaqueNetwork: 420 return x.Name 421 } 422 423 log.Panicf("%T object %s does not have a Name", obj, e.Reference()) 424 return name 425 } 426 427 // FindByName returns the first mo.Entity of the given refs whose Name field is equal to the given name. 428 // If there is no match, nil is returned. 429 // This method is useful for cases where objects are required to have a unique name, such as Datastore with 430 // a HostStorageSystem or HostSystem within a ClusterComputeResource. 431 func (r *Registry) FindByName(name string, refs []types.ManagedObjectReference) mo.Entity { 432 for _, ref := range refs { 433 if e, ok := r.Get(ref).(mo.Entity); ok { 434 if name == entityName(e) { 435 return e 436 } 437 } 438 } 439 440 return nil 441 } 442 443 // FindReference returns the 1st match found in refs, or nil if not found. 444 func FindReference(refs []types.ManagedObjectReference, match ...types.ManagedObjectReference) *types.ManagedObjectReference { 445 for _, ref := range refs { 446 for _, m := range match { 447 if ref == m { 448 return &ref 449 } 450 } 451 } 452 453 return nil 454 } 455 456 // AppendReference appends the given refs to field. 457 func (r *Registry) AppendReference(ctx *Context, obj mo.Reference, field *[]types.ManagedObjectReference, ref ...types.ManagedObjectReference) { 458 r.WithLock(ctx, obj, func() { 459 *field = append(*field, ref...) 460 }) 461 } 462 463 // AddReference appends ref to field if not already in the given field. 464 func (r *Registry) AddReference(ctx *Context, obj mo.Reference, field *[]types.ManagedObjectReference, ref types.ManagedObjectReference) { 465 r.WithLock(ctx, obj, func() { 466 if FindReference(*field, ref) == nil { 467 *field = append(*field, ref) 468 } 469 }) 470 } 471 472 // RemoveReference removes ref from the given field. 473 func RemoveReference(field *[]types.ManagedObjectReference, ref types.ManagedObjectReference) { 474 for i, r := range *field { 475 if r == ref { 476 *field = append((*field)[:i], (*field)[i+1:]...) 477 break 478 } 479 } 480 } 481 482 // RemoveReference removes ref from the given field. 483 func (r *Registry) RemoveReference(ctx *Context, obj mo.Reference, field *[]types.ManagedObjectReference, ref types.ManagedObjectReference) { 484 r.WithLock(ctx, obj, func() { 485 RemoveReference(field, ref) 486 }) 487 } 488 489 func (r *Registry) removeString(ctx *Context, obj mo.Reference, field *[]string, val string) { 490 r.WithLock(ctx, obj, func() { 491 for i, name := range *field { 492 if name == val { 493 *field = append((*field)[:i], (*field)[i+1:]...) 494 break 495 } 496 } 497 }) 498 } 499 500 func (r *Registry) content() types.ServiceContent { 501 return r.Get(vim25.ServiceInstance).(*ServiceInstance).Content 502 } 503 504 // IsESX returns true if this Registry maps an ESX model 505 func (r *Registry) IsESX() bool { 506 return r.content().About.ApiType == "HostAgent" 507 } 508 509 // IsVPX returns true if this Registry maps a VPX model 510 func (r *Registry) IsVPX() bool { 511 return !r.IsESX() 512 } 513 514 // SearchIndex returns the SearchIndex singleton 515 func (r *Registry) SearchIndex() *SearchIndex { 516 return r.Get(r.content().SearchIndex.Reference()).(*SearchIndex) 517 } 518 519 // AlarmManager returns the AlarmManager singleton 520 func (r *Registry) AlarmManager() *AlarmManager { 521 ref := r.content().AlarmManager 522 if ref == nil { 523 return nil // ESX 524 } 525 return r.Get(*ref).(*AlarmManager) 526 } 527 528 // EventManager returns the EventManager singleton 529 func (r *Registry) EventManager() *EventManager { 530 return r.Get(r.content().EventManager.Reference()).(*EventManager) 531 } 532 533 // FileManager returns the FileManager singleton 534 func (r *Registry) FileManager() *FileManager { 535 return r.Get(r.content().FileManager.Reference()).(*FileManager) 536 } 537 538 type VirtualDiskManagerInterface interface { 539 mo.Reference 540 MO() mo.VirtualDiskManager 541 CreateVirtualDiskTask(*Context, *types.CreateVirtualDisk_Task) soap.HasFault 542 DeleteVirtualDiskTask(*Context, *types.DeleteVirtualDisk_Task) soap.HasFault 543 MoveVirtualDiskTask(*Context, *types.MoveVirtualDisk_Task) soap.HasFault 544 CopyVirtualDiskTask(*Context, *types.CopyVirtualDisk_Task) soap.HasFault 545 QueryVirtualDiskUuid(*Context, *types.QueryVirtualDiskUuid) soap.HasFault 546 SetVirtualDiskUuid(*Context, *types.SetVirtualDiskUuid) soap.HasFault 547 } 548 549 // VirtualDiskManager returns the VirtualDiskManager singleton 550 func (r *Registry) VirtualDiskManager() VirtualDiskManagerInterface { 551 return r.Get(r.content().VirtualDiskManager.Reference()).(VirtualDiskManagerInterface) 552 } 553 554 // ViewManager returns the ViewManager singleton 555 func (r *Registry) ViewManager() *ViewManager { 556 return r.Get(r.content().ViewManager.Reference()).(*ViewManager) 557 } 558 559 // UserDirectory returns the UserDirectory singleton 560 func (r *Registry) UserDirectory() *UserDirectory { 561 return r.Get(r.content().UserDirectory.Reference()).(*UserDirectory) 562 } 563 564 // SessionManager returns the SessionManager singleton 565 func (r *Registry) SessionManager() *SessionManager { 566 return r.Get(r.content().SessionManager.Reference()).(*SessionManager) 567 } 568 569 // OptionManager returns the OptionManager singleton 570 func (r *Registry) OptionManager() *OptionManager { 571 return r.Get(r.content().Setting.Reference()).(*OptionManager) 572 } 573 574 // CustomFieldsManager returns CustomFieldsManager singleton 575 func (r *Registry) CustomFieldsManager() *CustomFieldsManager { 576 return r.Get(r.content().CustomFieldsManager.Reference()).(*CustomFieldsManager) 577 } 578 579 // TenantManager returns TenantManager singleton 580 func (r *Registry) TenantManager() *TenantManager { 581 return r.Get(r.content().TenantManager.Reference()).(*TenantManager) 582 } 583 584 // VmCompatibilityChecker returns VmCompatibilityChecker singleton 585 func (r *Registry) VmCompatibilityChecker() *VmCompatibilityChecker { 586 return r.Get(r.content().VmCompatibilityChecker.Reference()).(*VmCompatibilityChecker) 587 } 588 589 // VmProvisioningChecker returns VmProvisioningChecker singleton 590 func (r *Registry) VmProvisioningChecker() *VmProvisioningChecker { 591 return r.Get(r.content().VmProvisioningChecker.Reference()).(*VmProvisioningChecker) 592 } 593 594 // ExtensionManager returns the ExtensionManager singleton 595 func (r *Registry) ExtensionManager() *ExtensionManager { 596 return r.Get(r.content().ExtensionManager.Reference()).(*ExtensionManager) 597 } 598 599 func (r *Registry) MarshalJSON() ([]byte, error) { 600 r.m.Lock() 601 defer r.m.Unlock() 602 603 vars := struct { 604 Objects int `json:"objects"` 605 Locks int `json:"locks"` 606 }{ 607 len(r.objects), 608 len(r.locks), 609 } 610 611 return json.Marshal(vars) 612 } 613 614 func (r *Registry) locker(obj mo.Reference) *internal.ObjectLock { 615 var ref types.ManagedObjectReference 616 617 switch x := obj.(type) { 618 case types.ManagedObjectReference: 619 ref = x 620 obj = r.Get(ref) // to check for sync.Locker 621 case *types.ManagedObjectReference: 622 ref = *x 623 obj = r.Get(ref) // to check for sync.Locker 624 default: 625 // Use of obj.Reference() may cause a read race, prefer the mo 'Self' field to avoid this 626 self := reflect.ValueOf(obj).Elem().FieldByName("Self") 627 if self.IsValid() { 628 ref = self.Interface().(types.ManagedObjectReference) 629 } else { 630 ref = obj.Reference() 631 } 632 } 633 634 if mu, ok := obj.(sync.Locker); ok { 635 // Objects that opt out of default locking are responsible for 636 // implementing their own lock sharing, if needed. Returning 637 // nil as heldBy means that WithLock will call Lock/Unlock 638 // every time. 639 return internal.NewObjectLock(mu) 640 } 641 642 r.m.Lock() 643 mu, ok := r.locks[ref] 644 if !ok { 645 mu = internal.NewObjectLock(new(sync.Mutex)) 646 r.locks[ref] = mu 647 } 648 r.m.Unlock() 649 650 return mu 651 } 652 653 var enableLocker = os.Getenv("VCSIM_LOCKER") != "false" 654 655 // WithLock holds a lock for the given object while then given function is run. 656 func (r *Registry) WithLock(onBehalfOf *Context, obj mo.Reference, f func()) { 657 unlock := r.AcquireLock(onBehalfOf, obj) 658 f() 659 unlock() 660 } 661 662 // AcquireLock acquires the lock for onBehalfOf then returns. The lock MUST be 663 // released by calling the returned function. WithLock should be preferred 664 // wherever possible. 665 func (r *Registry) AcquireLock(onBehalfOf *Context, obj mo.Reference) func() { 666 if onBehalfOf == nil { 667 panic(fmt.Sprintf("Attempt to lock %v with nil onBehalfOf", obj)) 668 } 669 670 if !enableLocker { 671 return func() {} 672 } 673 674 l := r.locker(obj) 675 l.Acquire(onBehalfOf) 676 return func() { 677 l.Release(onBehalfOf) 678 } 679 } 680 681 // nopLocker can be embedded to opt-out of auto-locking (see Registry.WithLock) 682 type nopLocker struct{} 683 684 func (*nopLocker) Lock() {} 685 func (*nopLocker) Unlock() {}