github.com/vmware/govmomi@v0.51.0/vslm/simulator/simulator.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 "cmp" 9 "fmt" 10 "slices" 11 "strconv" 12 "strings" 13 "time" 14 15 "github.com/vmware/govmomi/simulator" 16 "github.com/vmware/govmomi/vim25" 17 vimx "github.com/vmware/govmomi/vim25/methods" 18 "github.com/vmware/govmomi/vim25/soap" 19 vim "github.com/vmware/govmomi/vim25/types" 20 "github.com/vmware/govmomi/vslm" 21 "github.com/vmware/govmomi/vslm/methods" 22 "github.com/vmware/govmomi/vslm/types" 23 ) 24 25 var content = types.VslmServiceInstanceContent{ 26 AboutInfo: types.VslmAboutInfo{ 27 Name: "VMware Virtual Storage Lifecycle Manager Service", 28 FullName: "VMware Virtual Storage Lifecycle Manager Service 1.0.0", 29 Vendor: "VMware, Inc.", 30 ApiVersion: "1.0.0", 31 InstanceUuid: "31c68687-4f1e-4247-8158-f31d1ce95bbe", 32 }, 33 SessionManager: vim.ManagedObjectReference{Type: "VslmSessionManager", Value: "SessionManager"}, 34 VStorageObjectManager: vim.ManagedObjectReference{Type: "VslmVStorageObjectManager", Value: "VStorageObjectManager"}, 35 StorageLifecycleManager: vim.ManagedObjectReference{Type: "VslmStorageLifecycleManager", Value: "StorageLifecycleManager"}, 36 } 37 38 func init() { 39 simulator.RegisterEndpoint(func(s *simulator.Service, r *simulator.Registry) { 40 if r.IsVPX() { 41 s.RegisterSDK(New()) 42 } 43 }) 44 } 45 46 func New() *simulator.Registry { 47 r := simulator.NewRegistry() 48 r.Namespace = vslm.Namespace 49 r.Path = vslm.Path 50 r.Cookie = simulator.SOAPCookie 51 52 r.Put(&ServiceInstance{ 53 ManagedObjectReference: vslm.ServiceInstance, 54 Content: content, 55 }) 56 57 r.Put(&VStorageObjectManager{ 58 ManagedObjectReference: content.VStorageObjectManager, 59 }) 60 61 return r 62 } 63 64 type ServiceInstance struct { 65 vim.ManagedObjectReference 66 67 Content types.VslmServiceInstanceContent 68 } 69 70 func (s *ServiceInstance) RetrieveContent(_ *types.RetrieveContent) soap.HasFault { 71 return &methods.RetrieveContentBody{ 72 Res: &types.RetrieveContentResponse{ 73 Returnval: s.Content, 74 }, 75 } 76 } 77 78 // VStorageObjectManager APIs manage First Class Disks (FCDs) using the "Global Catalog". 79 // The majority of methods in this API simulator dispatch to VcenterVStorageObjectManager methods, 80 // after looking up a disk's Datastore. Along with 'VslmTask', who's methods proxy to a vim25 'Task'. 81 type VStorageObjectManager struct { 82 vim.ManagedObjectReference 83 } 84 85 func matchesTime(q types.VslmVsoVStorageObjectQuerySpec, val time.Time) (bool, error) { 86 src, err := time.Parse(time.RFC3339Nano, q.QueryValue[0]) 87 if err != nil { 88 return false, err 89 } 90 91 switch types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnum(q.QueryOperator) { 92 case types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnumEquals: 93 return src == val, nil 94 case types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnumLessThan: 95 return val.Before(src), nil 96 case types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnumGreaterThan: 97 return val.After(src), nil 98 default: 99 return false, fmt.Errorf("invalid queryOperator %s for time", q.QueryOperator) 100 } 101 } 102 103 var longOps = map[types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnum]func(int64, int64) bool{ 104 types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnumEquals: func(a, b int64) bool { return a == b }, 105 types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnumNotEquals: func(a, b int64) bool { return a != b }, 106 types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnumLessThan: func(a, b int64) bool { return a < b }, 107 types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnumGreaterThan: func(a, b int64) bool { return a > b }, 108 types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnumLessThanOrEqual: func(a, b int64) bool { return a < b || a == b }, 109 types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnumGreaterThanOrEqual: func(a, b int64) bool { return a > b || a == b }, 110 } 111 112 func matchesLong(q types.VslmVsoVStorageObjectQuerySpec, field int64) (bool, error) { 113 num, err := strconv.ParseInt(q.QueryValue[0], 10, 64) 114 if err != nil { 115 return false, err 116 } 117 118 op, ok := longOps[types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnum(q.QueryOperator)] 119 if !ok { 120 return false, fmt.Errorf("invalid QueryOperator: %s", q.QueryOperator) 121 } 122 123 return op(field, int64(num)), nil 124 } 125 126 var stringOps = map[types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnum]func(string, string) bool{ 127 types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnumEquals: func(a, b string) bool { return a == b }, 128 types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnumNotEquals: func(a, b string) bool { return a != b }, 129 types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnumLessThan: func(a, b string) bool { return a < b }, 130 types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnumGreaterThan: func(a, b string) bool { return a > b }, 131 types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnumLessThanOrEqual: func(a, b string) bool { return a < b || a == b }, 132 types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnumGreaterThanOrEqual: func(a, b string) bool { return a > b || a == b }, 133 types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnumContains: strings.Contains, 134 types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnumStartsWith: strings.HasPrefix, 135 types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnumEndsWith: strings.HasSuffix, 136 } 137 138 func matches(obj *simulator.VStorageObject, q types.VslmVsoVStorageObjectQuerySpec) (bool, error) { 139 var field []string 140 141 switch types.VslmVsoVStorageObjectQuerySpecQueryFieldEnum(q.QueryField) { 142 case types.VslmVsoVStorageObjectQuerySpecQueryFieldEnumCapacity: 143 return matchesLong(q, obj.Config.CapacityInMB) 144 case types.VslmVsoVStorageObjectQuerySpecQueryFieldEnumCreateTime: 145 return matchesTime(q, obj.Config.CreateTime) 146 case types.VslmVsoVStorageObjectQuerySpecQueryFieldEnumBackingObjectId: 147 return false, fmt.Errorf("Query field %s is not supported", q.QueryField) // Same as real VC currently 148 case types.VslmVsoVStorageObjectQuerySpecQueryFieldEnumDatastoreMoId: 149 return true, nil // Already filtered datastores 150 case types.VslmVsoVStorageObjectQuerySpecQueryFieldEnumId: 151 field = append(field, obj.Config.Id.Id) 152 case types.VslmVsoVStorageObjectQuerySpecQueryFieldEnumName: 153 field = append(field, obj.Config.Name) 154 case types.VslmVsoVStorageObjectQuerySpecQueryFieldEnumMetadataKey: 155 field = make([]string, len(obj.Metadata)) 156 for i := range obj.Metadata { 157 field[i] = obj.Metadata[i].Key 158 } 159 case types.VslmVsoVStorageObjectQuerySpecQueryFieldEnumMetadataValue: 160 field = make([]string, len(obj.Metadata)) 161 for i := range obj.Metadata { 162 field[i] = obj.Metadata[i].Value 163 } 164 default: 165 return false, fmt.Errorf("invalid QueryField: %s", q.QueryField) 166 } 167 168 op, ok := stringOps[types.VslmVsoVStorageObjectQuerySpecQueryOperatorEnum(q.QueryOperator)] 169 if !ok { 170 return false, fmt.Errorf("invalid QueryOperator: %s", q.QueryOperator) 171 } 172 173 for _, f := range field { 174 if op(f, q.QueryValue[0]) { 175 return true, nil 176 } 177 } 178 179 return false, nil 180 } 181 182 var ( 183 invalidValues = &vim.InvalidArgument{InvalidProperty: "values"} 184 185 invalidQuery = &vim.SystemError{ 186 RuntimeFault: vim.RuntimeFault{ 187 MethodFault: vim.MethodFault{ 188 FaultCause: &vim.LocalizedMethodFault{ 189 Fault: &types.VslmFault{ 190 Msg: "Unexpected exception", 191 }, 192 }, 193 }, 194 }, 195 Reason: "Undeclared fault", 196 } 197 ) 198 199 func matchesSpec(obj *simulator.VStorageObject, query []types.VslmVsoVStorageObjectQuerySpec) (bool, *soap.Fault) { 200 for _, q := range query { 201 if len(q.QueryValue) != 1 { // Only 1 value is currently supported by vCenter 202 return false, simulator.Fault("", invalidValues) 203 } 204 match, err := matches(obj, q) 205 if err != nil { 206 return false, simulator.Fault(err.Error(), invalidQuery) 207 } 208 if !match { 209 return false, nil 210 } 211 } 212 return true, nil 213 } 214 215 func (m *VStorageObjectManager) VslmListVStorageObjectForSpec(ctx *simulator.Context, req *types.VslmListVStorageObjectForSpec) soap.HasFault { 216 body := new(methods.VslmListVStorageObjectForSpecBody) 217 vctx := ctx.For(vim25.Path) 218 vsom := vctx.Map.VStorageObjectManager() 219 220 datastores := map[vim.ManagedObjectReference]bool{} 221 for _, q := range req.Query { 222 if q.QueryField == string(types.VslmVsoVStorageObjectQuerySpecQueryFieldEnumDatastoreMoId) { 223 for _, id := range q.QueryValue { 224 datastores[vim.ManagedObjectReference{ 225 Type: "Datastore", 226 Value: "datastore-" + id, 227 }] = true 228 } 229 } 230 } 231 232 var catalog []vim.VStorageObject 233 234 for ds, objs := range vsom.Catalog() { 235 if len(datastores) != 0 && !datastores[ds] { 236 continue 237 } 238 239 for _, obj := range objs { 240 matches, err := matchesSpec(obj, req.Query) 241 if err != nil { 242 body.Fault_ = err 243 return body 244 } 245 if !matches { 246 continue 247 } 248 249 catalog = append(catalog, obj.VStorageObject) 250 } 251 } 252 253 // Sort as real VC does, required to support pagination 254 slices.SortFunc(catalog, func(a, b vim.VStorageObject) int { 255 return cmp.Compare(a.Config.Id.Id, b.Config.Id.Id) 256 }) 257 258 res := &types.VslmVsoVStorageObjectQueryResult{ 259 AllRecordsReturned: true, 260 } 261 262 for _, obj := range catalog { 263 res.Id = append(res.Id, obj.Config.Id) 264 265 vso := types.VslmVsoVStorageObjectResult{ 266 Id: obj.Config.Id, 267 Name: obj.Config.Name, 268 CapacityInMB: obj.Config.CapacityInMB, 269 CreateTime: &obj.Config.CreateTime, 270 } 271 272 res.QueryResults = append(res.QueryResults, vso) 273 274 if len(res.QueryResults) >= int(req.MaxResult) { 275 res.AllRecordsReturned = false 276 break 277 } 278 } 279 280 body.Res = &types.VslmListVStorageObjectForSpecResponse{ 281 Returnval: res, 282 } 283 284 return body 285 } 286 287 func (m *VStorageObjectManager) VslmRetrieveVStorageObject(ctx *simulator.Context, req *types.VslmRetrieveVStorageObject) soap.HasFault { 288 body := new(methods.VslmRetrieveVStorageObjectBody) 289 290 vctx := ctx.For(vim25.Path) 291 vsom := vctx.Map.VStorageObjectManager() 292 293 for _, objs := range vsom.Catalog() { 294 for id, obj := range objs { 295 if id == req.Id { 296 body.Res = &types.VslmRetrieveVStorageObjectResponse{ 297 Returnval: obj.VStorageObject, 298 } 299 return body 300 } 301 } 302 } 303 304 body.Fault_ = simulator.Fault("", &vim.InvalidArgument{InvalidProperty: "VolumeId"}) 305 306 return body 307 } 308 309 func (m *VStorageObjectManager) VslmReconcileDatastoreInventoryTask(ctx *simulator.Context, req *types.VslmReconcileDatastoreInventory_Task) soap.HasFault { 310 body := new(methods.VslmReconcileDatastoreInventory_TaskBody) 311 312 vctx := ctx.For(vim25.Path) 313 vsom := vctx.Map.VStorageObjectManager() 314 315 val := vsom.ReconcileDatastoreInventoryTask(vctx, &vim.ReconcileDatastoreInventory_Task{ 316 This: vsom.Self, 317 Datastore: req.Datastore, 318 }) 319 320 if val.Fault() != nil { 321 body.Fault_ = val.Fault() 322 } else { 323 ref := val.(*vimx.ReconcileDatastoreInventory_TaskBody).Res.Returnval 324 325 body.Res = &types.VslmReconcileDatastoreInventory_TaskResponse{ 326 Returnval: newVslmTask(ctx, ref), 327 } 328 } 329 330 return body 331 } 332 333 func (m *VStorageObjectManager) VslmRegisterDisk(ctx *simulator.Context, req *types.VslmRegisterDisk) soap.HasFault { 334 body := new(methods.VslmRegisterDiskBody) 335 336 vctx := ctx.For(vim25.Path) 337 vsom := vctx.Map.VStorageObjectManager() 338 339 val := vsom.RegisterDisk(vctx, &vim.RegisterDisk{ 340 This: vsom.Self, 341 Path: req.Path, 342 Name: req.Name, 343 }) 344 345 if val.Fault() != nil { 346 body.Fault_ = val.Fault() 347 } else { 348 body.Res = &types.VslmRegisterDiskResponse{ 349 Returnval: val.(*vimx.RegisterDiskBody).Res.Returnval, 350 } 351 } 352 353 return body 354 } 355 356 func (m *VStorageObjectManager) VslmCreateDiskTask(ctx *simulator.Context, req *types.VslmCreateDisk_Task) soap.HasFault { 357 body := new(methods.VslmCreateDisk_TaskBody) 358 359 vctx := ctx.For(vim25.Path) 360 vsom := vctx.Map.VStorageObjectManager() 361 362 val := vsom.CreateDiskTask(vctx, &vim.CreateDisk_Task{ 363 This: vsom.Self, 364 Spec: req.Spec, 365 }) 366 367 if val.Fault() != nil { 368 body.Fault_ = val.Fault() 369 } else { 370 ref := val.(*vimx.CreateDisk_TaskBody).Res.Returnval 371 372 body.Res = &types.VslmCreateDisk_TaskResponse{ 373 Returnval: newVslmTask(ctx, ref), 374 } 375 } 376 377 return body 378 } 379 380 func (m *VStorageObjectManager) VslmDeleteVStorageObjectTask(ctx *simulator.Context, req *types.VslmDeleteVStorageObject_Task) soap.HasFault { 381 body := new(methods.VslmDeleteVStorageObject_TaskBody) 382 383 vctx := ctx.For(vim25.Path) 384 vsom := vctx.Map.VStorageObjectManager() 385 386 val := vsom.DeleteVStorageObjectTask(vctx, &vim.DeleteVStorageObject_Task{ 387 This: vsom.Self, 388 Id: req.Id, 389 Datastore: m.ds(vsom, req.Id), 390 }) 391 392 if val.Fault() != nil { 393 body.Fault_ = val.Fault() 394 return body 395 } else { 396 ref := val.(*vimx.DeleteVStorageObject_TaskBody).Res.Returnval 397 398 body.Res = &types.VslmDeleteVStorageObject_TaskResponse{ 399 Returnval: newVslmTask(ctx, ref), 400 } 401 } 402 403 return body 404 } 405 406 func (m *VStorageObjectManager) VslmRetrieveSnapshotInfo(ctx *simulator.Context, req *types.VslmRetrieveSnapshotInfo) soap.HasFault { 407 body := new(methods.VslmRetrieveSnapshotInfoBody) 408 409 vctx := ctx.For(vim25.Path) 410 vsom := vctx.Map.VStorageObjectManager() 411 412 var vso *simulator.VStorageObject 413 for _, objs := range vsom.Catalog() { 414 for id, obj := range objs { 415 if id == req.Id { 416 vso = obj 417 break 418 } 419 } 420 } 421 422 if vso == nil { 423 body.Fault_ = simulator.Fault("", &vim.InvalidArgument{InvalidProperty: "VolumeId"}) 424 } else { 425 body.Res = &types.VslmRetrieveSnapshotInfoResponse{ 426 Returnval: vso.VStorageObjectSnapshotInfo, 427 } 428 } 429 430 return body 431 } 432 433 func (m *VStorageObjectManager) VslmCreateSnapshotTask(ctx *simulator.Context, req *types.VslmCreateSnapshot_Task) soap.HasFault { 434 body := new(methods.VslmCreateSnapshot_TaskBody) 435 436 vctx := ctx.For(vim25.Path) 437 vsom := vctx.Map.VStorageObjectManager() 438 439 val := vsom.VStorageObjectCreateSnapshotTask(vctx, &vim.VStorageObjectCreateSnapshot_Task{ 440 This: vsom.Self, 441 Id: req.Id, 442 Description: req.Description, 443 Datastore: m.ds(vsom, req.Id), 444 }) 445 446 if val.Fault() != nil { 447 body.Fault_ = val.Fault() 448 } else { 449 ref := val.(*vimx.VStorageObjectCreateSnapshot_TaskBody).Res.Returnval 450 451 body.Res = &types.VslmCreateSnapshot_TaskResponse{ 452 Returnval: newVslmTask(ctx, ref), 453 } 454 } 455 456 return body 457 } 458 459 func (m *VStorageObjectManager) VslmDeleteSnapshotTask(ctx *simulator.Context, req *types.VslmDeleteSnapshot_Task) soap.HasFault { 460 body := new(methods.VslmDeleteSnapshot_TaskBody) 461 462 vctx := ctx.For(vim25.Path) 463 vsom := vctx.Map.VStorageObjectManager() 464 465 val := vsom.DeleteSnapshotTask(vctx, &vim.DeleteSnapshot_Task{ 466 This: vsom.Self, 467 Id: req.Id, 468 SnapshotId: req.SnapshotId, 469 Datastore: m.ds(vsom, req.Id), 470 }) 471 472 if val.Fault() != nil { 473 body.Fault_ = val.Fault() 474 } else { 475 ref := val.(*vimx.DeleteSnapshot_TaskBody).Res.Returnval 476 477 body.Res = &types.VslmDeleteSnapshot_TaskResponse{ 478 Returnval: newVslmTask(ctx, ref), 479 } 480 } 481 482 return body 483 } 484 485 func (m *VStorageObjectManager) VslmAttachTagToVStorageObject(ctx *simulator.Context, req *types.VslmAttachTagToVStorageObject) soap.HasFault { 486 body := new(methods.VslmAttachTagToVStorageObjectBody) 487 488 vctx := ctx.For(vim25.Path) 489 vsom := vctx.Map.VStorageObjectManager() 490 491 val := vsom.AttachTagToVStorageObject(vctx, &vim.AttachTagToVStorageObject{ 492 This: vsom.Self, 493 Id: req.Id, 494 Category: req.Category, 495 Tag: req.Tag, 496 }) 497 498 if val.Fault() != nil { 499 body.Fault_ = val.Fault() 500 } else { 501 body.Res = new(types.VslmAttachTagToVStorageObjectResponse) 502 } 503 504 return body 505 } 506 507 func (m *VStorageObjectManager) VslmDetachTagFromVStorageObject(ctx *simulator.Context, req *types.VslmDetachTagFromVStorageObject) soap.HasFault { 508 body := new(methods.VslmDetachTagFromVStorageObjectBody) 509 510 vctx := ctx.For(vim25.Path) 511 vsom := vctx.Map.VStorageObjectManager() 512 513 val := vsom.DetachTagFromVStorageObject(vctx, &vim.DetachTagFromVStorageObject{ 514 This: vsom.Self, 515 Id: req.Id, 516 Category: req.Category, 517 Tag: req.Tag, 518 }) 519 520 if val.Fault() != nil { 521 body.Fault_ = val.Fault() 522 } else { 523 body.Res = new(types.VslmDetachTagFromVStorageObjectResponse) 524 } 525 526 return body 527 } 528 529 func (m *VStorageObjectManager) VslmListVStorageObjectsAttachedToTag(ctx *simulator.Context, req *types.VslmListVStorageObjectsAttachedToTag) soap.HasFault { 530 body := new(methods.VslmListVStorageObjectsAttachedToTagBody) 531 532 vctx := ctx.For(vim25.Path) 533 vsom := vctx.Map.VStorageObjectManager() 534 535 val := vsom.ListVStorageObjectsAttachedToTag(vctx, &vim.ListVStorageObjectsAttachedToTag{ 536 This: vsom.Self, 537 Category: req.Category, 538 Tag: req.Tag, 539 }) 540 541 if val.Fault() != nil { 542 body.Fault_ = val.Fault() 543 } else { 544 body.Res = &types.VslmListVStorageObjectsAttachedToTagResponse{ 545 Returnval: val.(*vimx.ListVStorageObjectBody).Res.Returnval, 546 } 547 } 548 549 return body 550 } 551 552 func (m *VStorageObjectManager) VslmListTagsAttachedToVStorageObject(ctx *simulator.Context, req *types.VslmListTagsAttachedToVStorageObject) soap.HasFault { 553 body := new(methods.VslmListTagsAttachedToVStorageObjectBody) 554 555 vctx := ctx.For(vim25.Path) 556 vsom := vctx.Map.VStorageObjectManager() 557 558 val := vsom.ListTagsAttachedToVStorageObject(vctx, &vim.ListTagsAttachedToVStorageObject{ 559 This: vsom.Self, 560 Id: req.Id, 561 }) 562 563 if val.Fault() != nil { 564 body.Fault_ = val.Fault() 565 } else { 566 body.Res = &types.VslmListTagsAttachedToVStorageObjectResponse{ 567 Returnval: val.(*vimx.ListTagsAttachedToVStorageObjectBody).Res.Returnval, 568 } 569 } 570 571 return body 572 } 573 574 func (m *VStorageObjectManager) VslmAttachDiskTask(ctx *simulator.Context, req *types.VslmAttachDisk_Task) soap.HasFault { 575 body := new(methods.VslmAttachDisk_TaskBody) 576 577 vctx := ctx.For(vim25.Path) 578 vsom := vctx.Map.VStorageObjectManager() 579 580 vm, ok := vctx.Map.Get(req.Vm).(*simulator.VirtualMachine) 581 if !ok { 582 body.Fault_ = simulator.Fault("", &vim.ManagedObjectNotFound{Obj: req.Vm}) 583 return body 584 } 585 586 var val soap.HasFault 587 588 vctx.WithLock(vm, func() { 589 val = vm.AttachDiskTask(vctx, &vim.AttachDisk_Task{ 590 This: vm.Self, 591 Datastore: m.ds(vsom, req.Id), 592 DiskId: req.Id, 593 ControllerKey: req.ControllerKey, 594 UnitNumber: req.UnitNumber, 595 }) 596 }) 597 598 if val.Fault() != nil { 599 body.Fault_ = val.Fault() 600 } else { 601 ref := val.(*vimx.AttachDisk_TaskBody).Res.Returnval 602 603 body.Res = &types.VslmAttachDisk_TaskResponse{ 604 Returnval: newVslmTask(ctx, ref), 605 } 606 } 607 608 return body 609 } 610 611 func (m *VStorageObjectManager) VslmUpdateVStorageObjectMetadataTask(ctx *simulator.Context, req *types.VslmUpdateVStorageObjectMetadata_Task) soap.HasFault { 612 body := new(methods.VslmUpdateVStorageObjectMetadata_TaskBody) 613 614 vctx := ctx.For(vim25.Path) 615 vsom := vctx.Map.VStorageObjectManager() 616 617 val := vsom.VCenterUpdateVStorageObjectMetadataExTask(vctx, &vim.VCenterUpdateVStorageObjectMetadataEx_Task{ 618 This: vsom.Self, 619 Id: req.Id, 620 Metadata: req.Metadata, 621 DeleteKeys: req.DeleteKeys, 622 Datastore: m.ds(vsom, req.Id), 623 }) 624 625 if val.Fault() != nil { 626 body.Fault_ = val.Fault() 627 } else { 628 ref := val.(*vimx.VCenterUpdateVStorageObjectMetadataEx_TaskBody).Res.Returnval 629 630 body.Res = &types.VslmUpdateVStorageObjectMetadata_TaskResponse{ 631 Returnval: newVslmTask(ctx, ref), 632 } 633 } 634 635 return body 636 } 637 638 func (m *VStorageObjectManager) VslmRetrieveVStorageObjectMetadata(ctx *simulator.Context, req *types.VslmRetrieveVStorageObjectMetadata) soap.HasFault { 639 body := new(methods.VslmRetrieveVStorageObjectMetadataBody) 640 641 vctx := ctx.For(vim25.Path) 642 vsom := vctx.Map.VStorageObjectManager() 643 644 obj := m.object(vsom, req.Id) 645 if obj == nil { 646 body.Fault_ = simulator.Fault("", &vim.InvalidArgument{InvalidProperty: "VolumeId"}) 647 } else { 648 body.Res = new(types.VslmRetrieveVStorageObjectMetadataResponse) 649 650 for _, kv := range obj.Metadata { 651 if req.Prefix == "" || strings.HasPrefix(kv.Key, req.Prefix) { 652 body.Res.Returnval = append(body.Res.Returnval, kv) 653 } 654 } 655 } 656 657 return body 658 } 659 660 func (m *VStorageObjectManager) VslmRetrieveVStorageObjectMetadataValue(ctx *simulator.Context, req *types.VslmRetrieveVStorageObjectMetadataValue) soap.HasFault { 661 body := new(methods.VslmRetrieveVStorageObjectMetadataValueBody) 662 663 vctx := ctx.For(vim25.Path) 664 vsom := vctx.Map.VStorageObjectManager() 665 666 obj := m.object(vsom, req.Id) 667 if obj == nil { 668 body.Fault_ = simulator.Fault("", &vim.InvalidArgument{InvalidProperty: "VolumeId"}) 669 } else { 670 val, ok := func() (string, bool) { 671 for _, data := range obj.Metadata { 672 if data.Key == req.Key { 673 return data.Value, true 674 } 675 } 676 return "", false 677 }() 678 679 if ok { 680 body.Res = &types.VslmRetrieveVStorageObjectMetadataValueResponse{Returnval: val} 681 } else { 682 body.Fault_ = simulator.Fault("", &vim.KeyNotFound{Key: req.Key}) 683 } 684 } 685 686 return body 687 } 688 689 // VslmTask methods are just a proxy to vim25 Task methods 690 type VslmTask struct { 691 vim.ManagedObjectReference 692 } 693 694 func newVslmTask(ctx *simulator.Context, ref vim.ManagedObjectReference) vim.ManagedObjectReference { 695 task := &VslmTask{ 696 ManagedObjectReference: vim.ManagedObjectReference{ 697 Type: "VslmTask", 698 Value: ref.Value, 699 }, 700 } 701 702 return ctx.Map.Put(task).Reference() 703 } 704 705 func (p *VslmTask) VslmQueryInfo(ctx *simulator.Context, req *types.VslmQueryInfo) soap.HasFault { 706 body := new(methods.VslmQueryInfoBody) 707 708 task, fault := p.task(ctx, req.This) 709 if fault != nil { 710 body.Fault_ = fault 711 } else { 712 info := types.VslmTaskInfo{ 713 Key: p.Value, 714 Task: p.ManagedObjectReference, 715 DescriptionId: "com.vmware.cns.vslm.tasks.createDisk", 716 State: types.VslmTaskInfoState(task.State), 717 Error: task.Error, 718 Result: task.Result, 719 QueueTime: task.QueueTime, 720 StartTime: task.StartTime, 721 CompleteTime: task.CompleteTime, 722 } 723 724 body.Res = &types.VslmQueryInfoResponse{Returnval: info} 725 } 726 727 return body 728 } 729 730 func (p *VslmTask) VslmQueryTaskResult(ctx *simulator.Context, req *types.VslmQueryTaskResult) soap.HasFault { 731 body := new(methods.VslmQueryTaskResultBody) 732 733 task, fault := p.task(ctx, req.This) 734 if fault != nil { 735 body.Fault_ = fault 736 } else { 737 body.Res = &types.VslmQueryTaskResultResponse{Returnval: task.Result} 738 } 739 740 return body 741 } 742 743 func (*VslmTask) task(ctx *simulator.Context, ref vim.ManagedObjectReference) (vim.TaskInfo, *soap.Fault) { 744 ctx = ctx.For(vim25.Path) 745 746 ref.Type = "Task" 747 748 if task, ok := ctx.Map.Get(ref).(*simulator.Task); ok { 749 unlock := ctx.Map.AcquireLock(ctx, ref) 750 defer unlock() 751 return task.Info, nil 752 } 753 754 return vim.TaskInfo{}, simulator.Fault("", &vim.ManagedObjectNotFound{Obj: ref}) 755 } 756 757 func (*VStorageObjectManager) ds(vsom *simulator.VcenterVStorageObjectManager, reqID vim.ID) vim.ManagedObjectReference { 758 for ds, objs := range vsom.Catalog() { 759 for id := range objs { 760 if id == reqID { 761 return ds 762 } 763 } 764 } 765 766 // vsom calls will fault as they would when ID is NotFound 767 return vim.ManagedObjectReference{Type: "Datastore"} 768 } 769 770 func (*VStorageObjectManager) object(vsom *simulator.VcenterVStorageObjectManager, reqID vim.ID) *simulator.VStorageObject { 771 for _, objs := range vsom.Catalog() { 772 for id, obj := range objs { 773 if id == reqID { 774 return obj 775 } 776 } 777 } 778 return nil 779 }