github.com/vmware/govmomi@v0.37.2/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  }