github.com/vmware/govmomi@v0.37.1/cns/simulator/simulator.go (about) 1 /* 2 Copyright (c) 2019 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 "context" 21 "reflect" 22 "time" 23 24 "github.com/google/uuid" 25 26 "github.com/vmware/govmomi/cns" 27 "github.com/vmware/govmomi/cns/methods" 28 cnstypes "github.com/vmware/govmomi/cns/types" 29 pbmtypes "github.com/vmware/govmomi/pbm/types" 30 "github.com/vmware/govmomi/simulator" 31 "github.com/vmware/govmomi/vim25/soap" 32 vim25types "github.com/vmware/govmomi/vim25/types" 33 ) 34 35 func init() { 36 simulator.RegisterEndpoint(func(s *simulator.Service, r *simulator.Registry) { 37 if r.IsVPX() { 38 s.RegisterSDK(New()) 39 } 40 }) 41 } 42 43 func New() *simulator.Registry { 44 r := simulator.NewRegistry() 45 r.Namespace = cns.Namespace 46 r.Path = cns.Path 47 48 r.Put(&CnsVolumeManager{ 49 ManagedObjectReference: cns.CnsVolumeManagerInstance, 50 volumes: make(map[vim25types.ManagedObjectReference]map[cnstypes.CnsVolumeId]*cnstypes.CnsVolume), 51 attachments: make(map[cnstypes.CnsVolumeId]vim25types.ManagedObjectReference), 52 snapshots: make(map[cnstypes.CnsVolumeId]map[cnstypes.CnsSnapshotId]*cnstypes.CnsSnapshot), 53 }) 54 55 return r 56 } 57 58 type CnsVolumeManager struct { 59 vim25types.ManagedObjectReference 60 volumes map[vim25types.ManagedObjectReference]map[cnstypes.CnsVolumeId]*cnstypes.CnsVolume 61 attachments map[cnstypes.CnsVolumeId]vim25types.ManagedObjectReference 62 snapshots map[cnstypes.CnsVolumeId]map[cnstypes.CnsSnapshotId]*cnstypes.CnsSnapshot 63 } 64 65 const simulatorDiskUUID = "6000c298595bf4575739e9105b2c0c2d" 66 67 func (m *CnsVolumeManager) CnsCreateVolume(ctx *simulator.Context, req *cnstypes.CnsCreateVolume) soap.HasFault { 68 task := simulator.CreateTask(m, "CnsCreateVolume", func(*simulator.Task) (vim25types.AnyType, vim25types.BaseMethodFault) { 69 if len(req.CreateSpecs) == 0 { 70 return nil, &vim25types.InvalidArgument{InvalidProperty: "CnsVolumeCreateSpec"} 71 } 72 73 operationResult := []cnstypes.BaseCnsVolumeOperationResult{} 74 for _, createSpec := range req.CreateSpecs { 75 staticProvisionedSpec, ok := interface{}(createSpec.BackingObjectDetails).(*cnstypes.CnsBlockBackingDetails) 76 if ok && staticProvisionedSpec.BackingDiskId != "" { 77 datastore := simulator.Map.Any("Datastore").(*simulator.Datastore) 78 volumes, ok := m.volumes[datastore.Self] 79 if !ok { 80 volumes = make(map[cnstypes.CnsVolumeId]*cnstypes.CnsVolume) 81 m.volumes[datastore.Self] = volumes 82 } 83 newVolume := &cnstypes.CnsVolume{ 84 VolumeId: cnstypes.CnsVolumeId{ 85 Id: interface{}(createSpec.BackingObjectDetails).(*cnstypes.CnsBlockBackingDetails).BackingDiskId, 86 }, 87 Name: createSpec.Name, 88 VolumeType: createSpec.VolumeType, 89 DatastoreUrl: datastore.Info.GetDatastoreInfo().Url, 90 Metadata: createSpec.Metadata, 91 BackingObjectDetails: createSpec.BackingObjectDetails.(cnstypes.BaseCnsBackingObjectDetails).GetCnsBackingObjectDetails(), 92 ComplianceStatus: "Simulator Compliance Status", 93 DatastoreAccessibilityStatus: "Simulator Datastore Accessibility Status", 94 HealthStatus: string(pbmtypes.PbmHealthStatusForEntityGreen), 95 } 96 97 volumes[newVolume.VolumeId] = newVolume 98 placementResults := []cnstypes.CnsPlacementResult{} 99 placementResults = append(placementResults, cnstypes.CnsPlacementResult{ 100 Datastore: datastore.Reference(), 101 }) 102 operationResult = append(operationResult, &cnstypes.CnsVolumeCreateResult{ 103 CnsVolumeOperationResult: cnstypes.CnsVolumeOperationResult{ 104 VolumeId: newVolume.VolumeId, 105 }, 106 Name: createSpec.Name, 107 PlacementResults: placementResults, 108 }) 109 110 } else { 111 for _, datastoreRef := range createSpec.Datastores { 112 datastore := simulator.Map.Get(datastoreRef).(*simulator.Datastore) 113 114 volumes, ok := m.volumes[datastore.Self] 115 if !ok { 116 volumes = make(map[cnstypes.CnsVolumeId]*cnstypes.CnsVolume) 117 m.volumes[datastore.Self] = volumes 118 119 } 120 121 var policyId string 122 if createSpec.Profile != nil && createSpec.Profile[0] != nil && 123 reflect.TypeOf(createSpec.Profile[0]) == reflect.TypeOf(&vim25types.VirtualMachineDefinedProfileSpec{}) { 124 policyId = interface{}(createSpec.Profile[0]).(*vim25types.VirtualMachineDefinedProfileSpec).ProfileId 125 } 126 127 newVolume := &cnstypes.CnsVolume{ 128 VolumeId: cnstypes.CnsVolumeId{ 129 Id: uuid.New().String(), 130 }, 131 Name: createSpec.Name, 132 VolumeType: createSpec.VolumeType, 133 DatastoreUrl: datastore.Info.GetDatastoreInfo().Url, 134 Metadata: createSpec.Metadata, 135 BackingObjectDetails: createSpec.BackingObjectDetails.(cnstypes.BaseCnsBackingObjectDetails).GetCnsBackingObjectDetails(), 136 ComplianceStatus: "Simulator Compliance Status", 137 DatastoreAccessibilityStatus: "Simulator Datastore Accessibility Status", 138 HealthStatus: string(pbmtypes.PbmHealthStatusForEntityGreen), 139 StoragePolicyId: policyId, 140 } 141 142 volumes[newVolume.VolumeId] = newVolume 143 placementResults := []cnstypes.CnsPlacementResult{} 144 placementResults = append(placementResults, cnstypes.CnsPlacementResult{ 145 Datastore: datastore.Reference(), 146 }) 147 operationResult = append(operationResult, &cnstypes.CnsVolumeCreateResult{ 148 CnsVolumeOperationResult: cnstypes.CnsVolumeOperationResult{ 149 VolumeId: newVolume.VolumeId, 150 }, 151 Name: createSpec.Name, 152 PlacementResults: placementResults, 153 }) 154 } 155 } 156 } 157 158 return &cnstypes.CnsVolumeOperationBatchResult{ 159 VolumeResults: operationResult, 160 }, nil 161 }) 162 163 return &methods.CnsCreateVolumeBody{ 164 Res: &cnstypes.CnsCreateVolumeResponse{ 165 Returnval: task.Run(ctx), 166 }, 167 } 168 } 169 170 // CnsQueryVolume simulates the query volumes implementation for CNSQuery API 171 func (m *CnsVolumeManager) CnsQueryVolume(ctx context.Context, req *cnstypes.CnsQueryVolume) soap.HasFault { 172 retVolumes := []cnstypes.CnsVolume{} 173 reqVolumeIds := make(map[string]bool) 174 isQueryFilter := false 175 176 if req.Filter.VolumeIds != nil { 177 isQueryFilter = true 178 } 179 // Create map of requested volume Ids in query request 180 for _, volumeID := range req.Filter.VolumeIds { 181 reqVolumeIds[volumeID.Id] = true 182 } 183 184 for _, dsVolumes := range m.volumes { 185 for _, volume := range dsVolumes { 186 if isQueryFilter { 187 if _, ok := reqVolumeIds[volume.VolumeId.Id]; ok { 188 retVolumes = append(retVolumes, *volume) 189 } 190 } else { 191 retVolumes = append(retVolumes, *volume) 192 } 193 } 194 } 195 196 return &methods.CnsQueryVolumeBody{ 197 Res: &cnstypes.CnsQueryVolumeResponse{ 198 Returnval: cnstypes.CnsQueryResult{ 199 Volumes: retVolumes, 200 Cursor: cnstypes.CnsCursor{}, 201 }, 202 }, 203 } 204 } 205 206 // CnsQueryAllVolume simulates the query volumes implementation for CNSQueryAll API 207 func (m *CnsVolumeManager) CnsQueryAllVolume(ctx context.Context, req *cnstypes.CnsQueryAllVolume) soap.HasFault { 208 retVolumes := []cnstypes.CnsVolume{} 209 reqVolumeIds := make(map[string]bool) 210 isQueryFilter := false 211 212 if req.Filter.VolumeIds != nil { 213 isQueryFilter = true 214 } 215 // Create map of requested volume Ids in query request 216 for _, volumeID := range req.Filter.VolumeIds { 217 reqVolumeIds[volumeID.Id] = true 218 } 219 220 for _, dsVolumes := range m.volumes { 221 for _, volume := range dsVolumes { 222 if isQueryFilter { 223 if _, ok := reqVolumeIds[volume.VolumeId.Id]; ok { 224 retVolumes = append(retVolumes, *volume) 225 } 226 } else { 227 retVolumes = append(retVolumes, *volume) 228 } 229 } 230 } 231 232 return &methods.CnsQueryAllVolumeBody{ 233 Res: &cnstypes.CnsQueryAllVolumeResponse{ 234 Returnval: cnstypes.CnsQueryResult{ 235 Volumes: retVolumes, 236 Cursor: cnstypes.CnsCursor{}, 237 }, 238 }, 239 } 240 } 241 242 func (m *CnsVolumeManager) CnsDeleteVolume(ctx *simulator.Context, req *cnstypes.CnsDeleteVolume) soap.HasFault { 243 task := simulator.CreateTask(m, "CnsDeleteVolume", func(*simulator.Task) (vim25types.AnyType, vim25types.BaseMethodFault) { 244 operationResult := []cnstypes.BaseCnsVolumeOperationResult{} 245 for _, volumeId := range req.VolumeIds { 246 for ds, dsVolumes := range m.volumes { 247 volume := dsVolumes[volumeId] 248 if volume != nil { 249 delete(m.volumes[ds], volumeId) 250 operationResult = append(operationResult, &cnstypes.CnsVolumeOperationResult{ 251 VolumeId: volumeId, 252 }) 253 254 } 255 } 256 } 257 return &cnstypes.CnsVolumeOperationBatchResult{ 258 VolumeResults: operationResult, 259 }, nil 260 }) 261 262 return &methods.CnsDeleteVolumeBody{ 263 Res: &cnstypes.CnsDeleteVolumeResponse{ 264 Returnval: task.Run(ctx), 265 }, 266 } 267 } 268 269 // CnsUpdateVolumeMetadata simulates UpdateVolumeMetadata call for simulated vc 270 func (m *CnsVolumeManager) CnsUpdateVolumeMetadata(ctx *simulator.Context, req *cnstypes.CnsUpdateVolumeMetadata) soap.HasFault { 271 task := simulator.CreateTask(m, "CnsUpdateVolumeMetadata", func(*simulator.Task) (vim25types.AnyType, vim25types.BaseMethodFault) { 272 if len(req.UpdateSpecs) == 0 { 273 return nil, &vim25types.InvalidArgument{InvalidProperty: "CnsUpdateVolumeMetadataSpec"} 274 } 275 operationResult := []cnstypes.BaseCnsVolumeOperationResult{} 276 for _, updateSpecs := range req.UpdateSpecs { 277 for _, dsVolumes := range m.volumes { 278 for id, volume := range dsVolumes { 279 if id.Id == updateSpecs.VolumeId.Id { 280 volume.Metadata.EntityMetadata = updateSpecs.Metadata.EntityMetadata 281 operationResult = append(operationResult, &cnstypes.CnsVolumeOperationResult{ 282 VolumeId: volume.VolumeId, 283 }) 284 break 285 } 286 } 287 } 288 289 } 290 return &cnstypes.CnsVolumeOperationBatchResult{ 291 VolumeResults: operationResult, 292 }, nil 293 }) 294 return &methods.CnsUpdateVolumeBody{ 295 Res: &cnstypes.CnsUpdateVolumeMetadataResponse{ 296 Returnval: task.Run(ctx), 297 }, 298 } 299 } 300 301 // CnsAttachVolume simulates AttachVolume call for simulated vc 302 func (m *CnsVolumeManager) CnsAttachVolume(ctx *simulator.Context, req *cnstypes.CnsAttachVolume) soap.HasFault { 303 task := simulator.CreateTask(m, "CnsAttachVolume", func(task *simulator.Task) (vim25types.AnyType, vim25types.BaseMethodFault) { 304 if len(req.AttachSpecs) == 0 { 305 return nil, &vim25types.InvalidArgument{InvalidProperty: "CnsAttachVolumeSpec"} 306 } 307 operationResult := []cnstypes.BaseCnsVolumeOperationResult{} 308 for _, attachSpec := range req.AttachSpecs { 309 node := simulator.Map.Get(attachSpec.Vm).(*simulator.VirtualMachine) 310 if _, ok := m.attachments[attachSpec.VolumeId]; !ok { 311 m.attachments[attachSpec.VolumeId] = node.Self 312 } else { 313 return nil, &vim25types.ResourceInUse{ 314 Name: attachSpec.VolumeId.Id, 315 } 316 } 317 operationResult = append(operationResult, &cnstypes.CnsVolumeAttachResult{ 318 CnsVolumeOperationResult: cnstypes.CnsVolumeOperationResult{ 319 VolumeId: attachSpec.VolumeId, 320 }, 321 DiskUUID: simulatorDiskUUID, 322 }) 323 } 324 325 return &cnstypes.CnsVolumeOperationBatchResult{ 326 VolumeResults: operationResult, 327 }, nil 328 }) 329 330 return &methods.CnsAttachVolumeBody{ 331 Res: &cnstypes.CnsAttachVolumeResponse{ 332 Returnval: task.Run(ctx), 333 }, 334 } 335 } 336 337 // CnsDetachVolume simulates DetachVolume call for simulated vc 338 func (m *CnsVolumeManager) CnsDetachVolume(ctx *simulator.Context, req *cnstypes.CnsDetachVolume) soap.HasFault { 339 task := simulator.CreateTask(m, "CnsDetachVolume", func(*simulator.Task) (vim25types.AnyType, vim25types.BaseMethodFault) { 340 if len(req.DetachSpecs) == 0 { 341 return nil, &vim25types.InvalidArgument{InvalidProperty: "CnsDetachVolumeSpec"} 342 } 343 operationResult := []cnstypes.BaseCnsVolumeOperationResult{} 344 for _, detachSpec := range req.DetachSpecs { 345 if _, ok := m.attachments[detachSpec.VolumeId]; ok { 346 delete(m.attachments, detachSpec.VolumeId) 347 operationResult = append(operationResult, &cnstypes.CnsVolumeOperationResult{ 348 VolumeId: detachSpec.VolumeId, 349 }) 350 } else { 351 return nil, &vim25types.InvalidArgument{ 352 InvalidProperty: detachSpec.VolumeId.Id, 353 } 354 } 355 } 356 357 return &cnstypes.CnsVolumeOperationBatchResult{ 358 VolumeResults: operationResult, 359 }, nil 360 }) 361 return &methods.CnsDetachVolumeBody{ 362 Res: &cnstypes.CnsDetachVolumeResponse{ 363 Returnval: task.Run(ctx), 364 }, 365 } 366 } 367 368 // CnsExtendVolume simulates ExtendVolume call for simulated vc 369 func (m *CnsVolumeManager) CnsExtendVolume(ctx *simulator.Context, req *cnstypes.CnsExtendVolume) soap.HasFault { 370 task := simulator.CreateTask(m, "CnsExtendVolume", func(task *simulator.Task) (vim25types.AnyType, vim25types.BaseMethodFault) { 371 if len(req.ExtendSpecs) == 0 { 372 return nil, &vim25types.InvalidArgument{InvalidProperty: "CnsExtendVolumeSpec"} 373 } 374 operationResult := []cnstypes.BaseCnsVolumeOperationResult{} 375 376 for _, extendSpecs := range req.ExtendSpecs { 377 for _, dsVolumes := range m.volumes { 378 for id, volume := range dsVolumes { 379 if id.Id == extendSpecs.VolumeId.Id { 380 volume.BackingObjectDetails = &cnstypes.CnsBackingObjectDetails{ 381 CapacityInMb: extendSpecs.CapacityInMb, 382 } 383 operationResult = append(operationResult, &cnstypes.CnsVolumeOperationResult{ 384 VolumeId: volume.VolumeId, 385 }) 386 break 387 } 388 } 389 } 390 } 391 392 return &cnstypes.CnsVolumeOperationBatchResult{ 393 VolumeResults: operationResult, 394 }, nil 395 }) 396 397 return &methods.CnsExtendVolumeBody{ 398 Res: &cnstypes.CnsExtendVolumeResponse{ 399 Returnval: task.Run(ctx), 400 }, 401 } 402 } 403 404 func (m *CnsVolumeManager) CnsQueryVolumeInfo(ctx *simulator.Context, req *cnstypes.CnsQueryVolumeInfo) soap.HasFault { 405 task := simulator.CreateTask(m, "CnsQueryVolumeInfo", func(*simulator.Task) (vim25types.AnyType, vim25types.BaseMethodFault) { 406 operationResult := []cnstypes.BaseCnsVolumeOperationResult{} 407 for _, volumeId := range req.VolumeIds { 408 vstorageObject := vim25types.VStorageObject{ 409 Config: vim25types.VStorageObjectConfigInfo{ 410 BaseConfigInfo: vim25types.BaseConfigInfo{ 411 Id: vim25types.ID{ 412 Id: uuid.New().String(), 413 }, 414 Name: "name", 415 CreateTime: time.Now(), 416 KeepAfterDeleteVm: vim25types.NewBool(true), 417 RelocationDisabled: vim25types.NewBool(false), 418 NativeSnapshotSupported: vim25types.NewBool(false), 419 ChangedBlockTrackingEnabled: vim25types.NewBool(false), 420 Iofilter: nil, 421 }, 422 CapacityInMB: 1024, 423 ConsumptionType: []string{"disk"}, 424 ConsumerId: nil, 425 }, 426 } 427 vstorageObject.Config.Backing = &vim25types.BaseConfigInfoDiskFileBackingInfo{ 428 BaseConfigInfoFileBackingInfo: vim25types.BaseConfigInfoFileBackingInfo{ 429 BaseConfigInfoBackingInfo: vim25types.BaseConfigInfoBackingInfo{ 430 Datastore: simulator.Map.Any("Datastore").(*simulator.Datastore).Self, 431 }, 432 FilePath: "[vsanDatastore] 6785a85e-268e-6352-a2e8-02008b7afadd/kubernetes-dynamic-pvc-68734c9f-a679-42e6-a694-39632c51e31f.vmdk", 433 BackingObjectId: volumeId.Id, 434 Parent: nil, 435 DeltaSizeInMB: 0, 436 }, 437 } 438 439 operationResult = append(operationResult, &cnstypes.CnsQueryVolumeInfoResult{ 440 CnsVolumeOperationResult: cnstypes.CnsVolumeOperationResult{ 441 VolumeId: volumeId, 442 }, 443 VolumeInfo: &cnstypes.CnsBlockVolumeInfo{ 444 CnsVolumeInfo: cnstypes.CnsVolumeInfo{}, 445 VStorageObject: vstorageObject, 446 }, 447 }) 448 449 } 450 return &cnstypes.CnsVolumeOperationBatchResult{ 451 VolumeResults: operationResult, 452 }, nil 453 }) 454 455 return &methods.CnsQueryVolumeInfoBody{ 456 Res: &cnstypes.CnsQueryVolumeInfoResponse{ 457 Returnval: task.Run(ctx), 458 }, 459 } 460 } 461 462 func (m *CnsVolumeManager) CnsQueryAsync(ctx *simulator.Context, req *cnstypes.CnsQueryAsync) soap.HasFault { 463 task := simulator.CreateTask(m, "QueryVolumeAsync", func(*simulator.Task) (vim25types.AnyType, vim25types.BaseMethodFault) { 464 retVolumes := []cnstypes.CnsVolume{} 465 reqVolumeIds := make(map[string]bool) 466 isQueryFilter := false 467 468 if req.Filter.VolumeIds != nil { 469 isQueryFilter = true 470 } 471 // Create map of requested volume Ids in query request 472 for _, volumeID := range req.Filter.VolumeIds { 473 reqVolumeIds[volumeID.Id] = true 474 } 475 476 for _, dsVolumes := range m.volumes { 477 for _, volume := range dsVolumes { 478 if isQueryFilter { 479 if _, ok := reqVolumeIds[volume.VolumeId.Id]; ok { 480 retVolumes = append(retVolumes, *volume) 481 } 482 } else { 483 retVolumes = append(retVolumes, *volume) 484 } 485 } 486 } 487 operationResult := []cnstypes.BaseCnsVolumeOperationResult{} 488 operationResult = append(operationResult, &cnstypes.CnsAsyncQueryResult{ 489 QueryResult: cnstypes.CnsQueryResult{ 490 Volumes: retVolumes, 491 Cursor: cnstypes.CnsCursor{}, 492 }, 493 }) 494 495 return &cnstypes.CnsVolumeOperationBatchResult{ 496 VolumeResults: operationResult, 497 }, nil 498 }) 499 500 return &methods.CnsQueryAsyncBody{ 501 Res: &cnstypes.CnsQueryAsyncResponse{ 502 Returnval: task.Run(ctx), 503 }, 504 } 505 } 506 507 func (m *CnsVolumeManager) CnsCreateSnapshots(ctx *simulator.Context, req *cnstypes.CnsCreateSnapshots) soap.HasFault { 508 task := simulator.CreateTask(m, "CreateSnapshots", func(*simulator.Task) (vim25types.AnyType, vim25types.BaseMethodFault) { 509 if len(req.SnapshotSpecs) == 0 { 510 return nil, &vim25types.InvalidArgument{InvalidProperty: "CnsSnapshotCreateSpec"} 511 } 512 513 snapshotOperationResult := []cnstypes.BaseCnsVolumeOperationResult{} 514 for _, snapshotCreateSpec := range req.SnapshotSpecs { 515 for _, dsVolumes := range m.volumes { 516 for id, _ := range dsVolumes { 517 if id.Id != snapshotCreateSpec.VolumeId.Id { 518 continue 519 } 520 snapshots, ok := m.snapshots[snapshotCreateSpec.VolumeId] 521 if !ok { 522 snapshots = make(map[cnstypes.CnsSnapshotId]*cnstypes.CnsSnapshot) 523 m.snapshots[snapshotCreateSpec.VolumeId] = snapshots 524 } 525 526 newSnapshot := &cnstypes.CnsSnapshot{ 527 SnapshotId: cnstypes.CnsSnapshotId{ 528 Id: uuid.New().String(), 529 }, 530 VolumeId: snapshotCreateSpec.VolumeId, 531 Description: snapshotCreateSpec.Description, 532 CreateTime: time.Now(), 533 } 534 snapshots[newSnapshot.SnapshotId] = newSnapshot 535 snapshotOperationResult = append(snapshotOperationResult, &cnstypes.CnsSnapshotCreateResult{ 536 CnsSnapshotOperationResult: cnstypes.CnsSnapshotOperationResult{ 537 CnsVolumeOperationResult: cnstypes.CnsVolumeOperationResult{ 538 VolumeId: newSnapshot.VolumeId, 539 }, 540 }, 541 Snapshot: *newSnapshot, 542 }) 543 } 544 } 545 } 546 547 return &cnstypes.CnsVolumeOperationBatchResult{ 548 VolumeResults: snapshotOperationResult, 549 }, nil 550 }) 551 552 return &methods.CnsCreateSnapshotsBody{ 553 Res: &cnstypes.CnsCreateSnapshotsResponse{ 554 Returnval: task.Run(ctx), 555 }, 556 } 557 } 558 559 func (m *CnsVolumeManager) CnsDeleteSnapshots(ctx *simulator.Context, req *cnstypes.CnsDeleteSnapshots) soap.HasFault { 560 task := simulator.CreateTask(m, "DeleteSnapshots", func(*simulator.Task) (vim25types.AnyType, vim25types.BaseMethodFault) { 561 snapshotOperationResult := []cnstypes.BaseCnsVolumeOperationResult{} 562 for _, snapshotDeleteSpec := range req.SnapshotDeleteSpecs { 563 for _, dsVolumes := range m.volumes { 564 for id, _ := range dsVolumes { 565 if id.Id != snapshotDeleteSpec.VolumeId.Id { 566 continue 567 } 568 snapshots := m.snapshots[snapshotDeleteSpec.VolumeId] 569 snapshot, ok := snapshots[snapshotDeleteSpec.SnapshotId] 570 if ok { 571 delete(m.snapshots[snapshotDeleteSpec.VolumeId], snapshotDeleteSpec.SnapshotId) 572 snapshotOperationResult = append(snapshotOperationResult, &cnstypes.CnsSnapshotDeleteResult{ 573 CnsSnapshotOperationResult: cnstypes.CnsSnapshotOperationResult{ 574 CnsVolumeOperationResult: cnstypes.CnsVolumeOperationResult{ 575 VolumeId: snapshot.VolumeId, 576 }, 577 }, 578 SnapshotId: snapshot.SnapshotId, 579 }) 580 } 581 } 582 } 583 } 584 585 return &cnstypes.CnsVolumeOperationBatchResult{ 586 VolumeResults: snapshotOperationResult, 587 }, nil 588 }) 589 590 return &methods.CnsDeleteSnapshotBody{ 591 Res: &cnstypes.CnsDeleteSnapshotsResponse{ 592 Returnval: task.Run(ctx), 593 }, 594 } 595 } 596 597 func (m *CnsVolumeManager) CnsQuerySnapshots(ctx *simulator.Context, req *cnstypes.CnsQuerySnapshots) soap.HasFault { 598 task := simulator.CreateTask(m, "QuerySnapshots", func(*simulator.Task) (vim25types.AnyType, vim25types.BaseMethodFault) { 599 if len(req.SnapshotQueryFilter.SnapshotQuerySpecs) > 1 { 600 return nil, &vim25types.InvalidArgument{InvalidProperty: "CnsSnapshotQuerySpec"} 601 } 602 603 snapshotQueryResultEntries := []cnstypes.CnsSnapshotQueryResultEntry{} 604 checkVolumeExists := func(volumeId cnstypes.CnsVolumeId) bool { 605 for _, dsVolumes := range m.volumes { 606 for id, _ := range dsVolumes { 607 if id.Id == volumeId.Id { 608 return true 609 } 610 } 611 } 612 return false 613 } 614 615 if req.SnapshotQueryFilter.SnapshotQuerySpecs == nil && len(req.SnapshotQueryFilter.SnapshotQuerySpecs) == 0 { 616 // return all snapshots if snapshotQuerySpecs is empty 617 for _, volSnapshots := range m.snapshots { 618 for _, snapshot := range volSnapshots { 619 snapshotQueryResultEntries = append(snapshotQueryResultEntries, cnstypes.CnsSnapshotQueryResultEntry{Snapshot: *snapshot}) 620 } 621 } 622 } else { 623 // snapshotQuerySpecs is not empty 624 isSnapshotQueryFilter := false 625 snapshotQuerySpec := req.SnapshotQueryFilter.SnapshotQuerySpecs[0] 626 if snapshotQuerySpec.SnapshotId != nil && (*snapshotQuerySpec.SnapshotId != cnstypes.CnsSnapshotId{}) { 627 isSnapshotQueryFilter = true 628 } 629 630 if !checkVolumeExists(snapshotQuerySpec.VolumeId) { 631 // volumeId in snapshotQuerySpecs does not exist 632 snapshotQueryResultEntries = append(snapshotQueryResultEntries, cnstypes.CnsSnapshotQueryResultEntry{ 633 Error: &vim25types.LocalizedMethodFault{ 634 Fault: cnstypes.CnsVolumeNotFoundFault{ 635 VolumeId: snapshotQuerySpec.VolumeId, 636 }, 637 }, 638 }) 639 } else { 640 // volumeId in snapshotQuerySpecs exists 641 for _, snapshot := range m.snapshots[snapshotQuerySpec.VolumeId] { 642 if isSnapshotQueryFilter && snapshot.SnapshotId.Id != (*snapshotQuerySpec.SnapshotId).Id { 643 continue 644 } 645 646 snapshotQueryResultEntries = append(snapshotQueryResultEntries, cnstypes.CnsSnapshotQueryResultEntry{Snapshot: *snapshot}) 647 } 648 649 if isSnapshotQueryFilter && len(snapshotQueryResultEntries) == 0 { 650 snapshotQueryResultEntries = append(snapshotQueryResultEntries, cnstypes.CnsSnapshotQueryResultEntry{ 651 Error: &vim25types.LocalizedMethodFault{ 652 Fault: cnstypes.CnsSnapshotNotFoundFault{ 653 VolumeId: snapshotQuerySpec.VolumeId, 654 SnapshotId: *snapshotQuerySpec.SnapshotId, 655 }, 656 }, 657 }) 658 } 659 } 660 } 661 662 return &cnstypes.CnsSnapshotQueryResult{ 663 Entries: snapshotQueryResultEntries, 664 }, nil 665 }) 666 667 return &methods.CnsQuerySnapshotsBody{ 668 Res: &cnstypes.CnsQuerySnapshotsResponse{ 669 Returnval: task.Run(ctx), 670 }, 671 } 672 }