github.com/vmware/govmomi@v0.37.1/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 // EventManager returns the EventManager singleton 520 func (r *Registry) EventManager() *EventManager { 521 return r.Get(r.content().EventManager.Reference()).(*EventManager) 522 } 523 524 // FileManager returns the FileManager singleton 525 func (r *Registry) FileManager() *FileManager { 526 return r.Get(r.content().FileManager.Reference()).(*FileManager) 527 } 528 529 type VirtualDiskManagerInterface interface { 530 mo.Reference 531 MO() mo.VirtualDiskManager 532 CreateVirtualDiskTask(*Context, *types.CreateVirtualDisk_Task) soap.HasFault 533 DeleteVirtualDiskTask(*Context, *types.DeleteVirtualDisk_Task) soap.HasFault 534 MoveVirtualDiskTask(*Context, *types.MoveVirtualDisk_Task) soap.HasFault 535 CopyVirtualDiskTask(*Context, *types.CopyVirtualDisk_Task) soap.HasFault 536 QueryVirtualDiskUuid(*Context, *types.QueryVirtualDiskUuid) soap.HasFault 537 SetVirtualDiskUuid(*Context, *types.SetVirtualDiskUuid) soap.HasFault 538 } 539 540 // VirtualDiskManager returns the VirtualDiskManager singleton 541 func (r *Registry) VirtualDiskManager() VirtualDiskManagerInterface { 542 return r.Get(r.content().VirtualDiskManager.Reference()).(VirtualDiskManagerInterface) 543 } 544 545 // ViewManager returns the ViewManager singleton 546 func (r *Registry) ViewManager() *ViewManager { 547 return r.Get(r.content().ViewManager.Reference()).(*ViewManager) 548 } 549 550 // UserDirectory returns the UserDirectory singleton 551 func (r *Registry) UserDirectory() *UserDirectory { 552 return r.Get(r.content().UserDirectory.Reference()).(*UserDirectory) 553 } 554 555 // SessionManager returns the SessionManager singleton 556 func (r *Registry) SessionManager() *SessionManager { 557 return r.Get(r.content().SessionManager.Reference()).(*SessionManager) 558 } 559 560 // OptionManager returns the OptionManager singleton 561 func (r *Registry) OptionManager() *OptionManager { 562 return r.Get(r.content().Setting.Reference()).(*OptionManager) 563 } 564 565 // CustomFieldsManager returns CustomFieldsManager singleton 566 func (r *Registry) CustomFieldsManager() *CustomFieldsManager { 567 return r.Get(r.content().CustomFieldsManager.Reference()).(*CustomFieldsManager) 568 } 569 570 // TenantManager returns TenantManager singleton 571 func (r *Registry) TenantManager() *TenantManager { 572 return r.Get(r.content().TenantManager.Reference()).(*TenantManager) 573 } 574 575 // ExtensionManager returns the ExtensionManager singleton 576 func (r *Registry) ExtensionManager() *ExtensionManager { 577 return r.Get(r.content().ExtensionManager.Reference()).(*ExtensionManager) 578 } 579 580 func (r *Registry) MarshalJSON() ([]byte, error) { 581 r.m.Lock() 582 defer r.m.Unlock() 583 584 vars := struct { 585 Objects int `json:"objects"` 586 Locks int `json:"locks"` 587 }{ 588 len(r.objects), 589 len(r.locks), 590 } 591 592 return json.Marshal(vars) 593 } 594 595 func (r *Registry) locker(obj mo.Reference) *internal.ObjectLock { 596 var ref types.ManagedObjectReference 597 598 switch x := obj.(type) { 599 case types.ManagedObjectReference: 600 ref = x 601 obj = r.Get(ref) // to check for sync.Locker 602 case *types.ManagedObjectReference: 603 ref = *x 604 obj = r.Get(ref) // to check for sync.Locker 605 default: 606 // Use of obj.Reference() may cause a read race, prefer the mo 'Self' field to avoid this 607 self := reflect.ValueOf(obj).Elem().FieldByName("Self") 608 if self.IsValid() { 609 ref = self.Interface().(types.ManagedObjectReference) 610 } else { 611 ref = obj.Reference() 612 } 613 } 614 615 if mu, ok := obj.(sync.Locker); ok { 616 // Objects that opt out of default locking are responsible for 617 // implementing their own lock sharing, if needed. Returning 618 // nil as heldBy means that WithLock will call Lock/Unlock 619 // every time. 620 return internal.NewObjectLock(mu) 621 } 622 623 r.m.Lock() 624 mu, ok := r.locks[ref] 625 if !ok { 626 mu = internal.NewObjectLock(new(sync.Mutex)) 627 r.locks[ref] = mu 628 } 629 r.m.Unlock() 630 631 return mu 632 } 633 634 var enableLocker = os.Getenv("VCSIM_LOCKER") != "false" 635 636 // WithLock holds a lock for the given object while then given function is run. 637 func (r *Registry) WithLock(onBehalfOf *Context, obj mo.Reference, f func()) { 638 unlock := r.AcquireLock(onBehalfOf, obj) 639 f() 640 unlock() 641 } 642 643 // AcquireLock acquires the lock for onBehalfOf then returns. The lock MUST be 644 // released by calling the returned function. WithLock should be preferred 645 // wherever possible. 646 func (r *Registry) AcquireLock(onBehalfOf *Context, obj mo.Reference) func() { 647 if onBehalfOf == nil { 648 panic(fmt.Sprintf("Attempt to lock %v with nil onBehalfOf", obj)) 649 } 650 651 if !enableLocker { 652 return func() {} 653 } 654 655 l := r.locker(obj) 656 l.Acquire(onBehalfOf) 657 return func() { 658 l.Release(onBehalfOf) 659 } 660 } 661 662 // nopLocker can be embedded to opt-out of auto-locking (see Registry.WithLock) 663 type nopLocker struct{} 664 665 func (*nopLocker) Lock() {} 666 func (*nopLocker) Unlock() {}