github.com/vmware/govmomi@v0.37.1/cns/client_test.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 cns 18 19 import ( 20 "context" 21 "fmt" 22 "os" 23 "strconv" 24 "strings" 25 "testing" 26 27 "github.com/dougm/pretty" 28 29 "github.com/vmware/govmomi/find" 30 "github.com/vmware/govmomi/object" 31 "github.com/vmware/govmomi/property" 32 "github.com/vmware/govmomi/vim25/debug" 33 "github.com/vmware/govmomi/vim25/mo" 34 "github.com/vmware/govmomi/vim25/soap" 35 36 "github.com/vmware/govmomi" 37 cnstypes "github.com/vmware/govmomi/cns/types" 38 vim25types "github.com/vmware/govmomi/vim25/types" 39 vsanfstypes "github.com/vmware/govmomi/vsan/vsanfs/types" 40 ) 41 42 const VSphere70u3VersionInt = 703 43 const VSphere80u3VersionInt = 803 44 45 func TestClient(t *testing.T) { 46 // set CNS_DEBUG to true if you need to emit soap traces from these tests 47 // soap traces will be emitted in the govmomi/cns/.soap directory 48 // example export CNS_DEBUG='true' 49 enableDebug := os.Getenv("CNS_DEBUG") 50 soapTraceDirectory := ".soap" 51 52 url := os.Getenv("CNS_VC_URL") // example: export CNS_VC_URL='https://username:password@vc-ip/sdk' 53 datacenter := os.Getenv("CNS_DATACENTER") 54 datastore := os.Getenv("CNS_DATASTORE") 55 56 // set CNS_RUN_FILESHARE_TESTS environment to true, if your setup has vsanfileshare enabled. 57 // when CNS_RUN_FILESHARE_TESTS is not set to true, vsan file share related tests are skipped. 58 // example: export CNS_RUN_FILESHARE_TESTS='true' 59 run_fileshare_tests := os.Getenv("CNS_RUN_FILESHARE_TESTS") 60 61 // if backingDiskURLPath is not set, test for Creating Volume with setting BackingDiskUrlPath in the BackingObjectDetails of 62 // CnsVolumeCreateSpec will be skipped. 63 // example: export BACKING_DISK_URL_PATH='https://vc-ip/folder/vmdkfilePath.vmdk?dcPath=DataCenterPath&dsName=DataStoreName' 64 backingDiskURLPath := os.Getenv("BACKING_DISK_URL_PATH") 65 66 // set REMOTE_VC_URL, REMOTE_DATACENTER only if you want to test cross-VC CNS operations. 67 // For instance, testing cross-VC volume migration. 68 remoteVcUrl := os.Getenv("REMOTE_VC_URL") 69 remoteDatacenter := os.Getenv("REMOTE_DATACENTER") 70 71 // if datastoreForMigration is not set, test for CNS Relocate API of a volume to another datastore is skipped. 72 // input format is same as CNS_DATASTORE. Format eg. "vSANDirect_10.92.217.162_mpx.vmhba0:C0:T2:L0"/ "vsandatastore" 73 datastoreForMigration := os.Getenv("CNS_MIGRATION_DATASTORE") 74 75 // if spbmPolicyId4Reconfig is not set, test for CnsReconfigVolumePolicy API will be skipped 76 // example: export CNS_SPBM_POLICY_ID_4_RECONFIG=6f64d90e-2ad5-4c4d-8cbc-a3330ebc496c 77 spbmPolicyId4Reconfig := os.Getenv("CNS_SPBM_POLICY_ID_4_RECONFIG") 78 79 if url == "" || datacenter == "" || datastore == "" { 80 t.Skip("CNS_VC_URL or CNS_DATACENTER or CNS_DATASTORE is not set") 81 } 82 resourcePoolPath := os.Getenv("CNS_RESOURCE_POOL_PATH") // example "/datacenter-name/host/host-ip/Resources" or /datacenter-name/host/cluster-name/Resources 83 u, err := soap.ParseURL(url) 84 if err != nil { 85 t.Fatal(err) 86 } 87 88 if enableDebug == "true" { 89 if _, err := os.Stat(soapTraceDirectory); os.IsNotExist(err) { 90 os.Mkdir(soapTraceDirectory, 0755) 91 } 92 p := debug.FileProvider{ 93 Path: soapTraceDirectory, 94 } 95 debug.SetProvider(&p) 96 } 97 98 ctx := context.Background() 99 c, err := govmomi.NewClient(ctx, u, true) 100 if err != nil { 101 t.Fatal(err) 102 } 103 cnsClient, err := NewClient(ctx, c.Client) 104 if err != nil { 105 t.Fatal(err) 106 } 107 finder := find.NewFinder(cnsClient.vim25Client, false) 108 dc, err := finder.Datacenter(ctx, datacenter) 109 if err != nil { 110 t.Fatal(err) 111 } 112 finder.SetDatacenter(dc) 113 ds, err := finder.Datastore(ctx, datastore) 114 if err != nil { 115 t.Fatal(err) 116 } 117 118 props := []string{"info", "summary"} 119 pc := property.DefaultCollector(c.Client) 120 var dsSummaries []mo.Datastore 121 err = pc.Retrieve(ctx, []vim25types.ManagedObjectReference{ds.Reference()}, props, &dsSummaries) 122 if err != nil { 123 t.Fatal(err) 124 } 125 dsUrl := dsSummaries[0].Summary.Url 126 127 var dsList []vim25types.ManagedObjectReference 128 dsList = append(dsList, ds.Reference()) 129 130 var containerClusterArray []cnstypes.CnsContainerCluster 131 containerCluster := cnstypes.CnsContainerCluster{ 132 ClusterType: string(cnstypes.CnsClusterTypeKubernetes), 133 ClusterId: "demo-cluster-id", 134 VSphereUser: "Administrator@vsphere.local", 135 ClusterFlavor: string(cnstypes.CnsClusterFlavorVanilla), 136 ClusterDistribution: "OpenShift", 137 } 138 containerClusterArray = append(containerClusterArray, containerCluster) 139 140 // Test CreateVolume API 141 var cnsVolumeCreateSpecList []cnstypes.CnsVolumeCreateSpec 142 cnsVolumeCreateSpec := cnstypes.CnsVolumeCreateSpec{ 143 Name: "pvc-901e87eb-c2bd-11e9-806f-005056a0c9a0", 144 VolumeType: string(cnstypes.CnsVolumeTypeBlock), 145 Datastores: dsList, 146 Metadata: cnstypes.CnsVolumeMetadata{ 147 ContainerCluster: containerCluster, 148 }, 149 BackingObjectDetails: &cnstypes.CnsBlockBackingDetails{ 150 CnsBackingObjectDetails: cnstypes.CnsBackingObjectDetails{ 151 CapacityInMb: 5120, 152 }, 153 }, 154 } 155 cnsVolumeCreateSpecList = append(cnsVolumeCreateSpecList, cnsVolumeCreateSpec) 156 t.Logf("Creating volume using the spec: %+v", pretty.Sprint(cnsVolumeCreateSpec)) 157 createTask, err := cnsClient.CreateVolume(ctx, cnsVolumeCreateSpecList) 158 if err != nil { 159 t.Errorf("Failed to create volume. Error: %+v \n", err) 160 t.Fatal(err) 161 } 162 createTaskInfo, err := GetTaskInfo(ctx, createTask) 163 if err != nil { 164 t.Errorf("Failed to create volume. Error: %+v \n", err) 165 t.Fatal(err) 166 } 167 createTaskResult, err := GetTaskResult(ctx, createTaskInfo) 168 if err != nil { 169 t.Errorf("Failed to create volume. Error: %+v \n", err) 170 t.Fatal(err) 171 } 172 if createTaskResult == nil { 173 t.Fatalf("Empty create task results") 174 t.FailNow() 175 } 176 createVolumeOperationRes := createTaskResult.GetCnsVolumeOperationResult() 177 if createVolumeOperationRes.Fault != nil { 178 t.Fatalf("Failed to create volume: fault=%+v", createVolumeOperationRes.Fault) 179 } 180 volumeId := createVolumeOperationRes.VolumeId.Id 181 volumeCreateResult := (createTaskResult).(*cnstypes.CnsVolumeCreateResult) 182 t.Logf("volumeCreateResult %+v", volumeCreateResult) 183 t.Logf("Volume created sucessfully. volumeId: %s", volumeId) 184 185 if cnsClient.Version != ReleaseVSAN67u3 { 186 // Test creating static volume using existing CNS volume should fail 187 var staticCnsVolumeCreateSpecList []cnstypes.CnsVolumeCreateSpec 188 staticCnsVolumeCreateSpec := cnstypes.CnsVolumeCreateSpec{ 189 Name: "pvc-901e87eb-c2bd-11e9-806f-005056a0c9a0", 190 VolumeType: string(cnstypes.CnsVolumeTypeBlock), 191 Metadata: cnstypes.CnsVolumeMetadata{ 192 ContainerCluster: containerCluster, 193 }, 194 BackingObjectDetails: &cnstypes.CnsBlockBackingDetails{ 195 CnsBackingObjectDetails: cnstypes.CnsBackingObjectDetails{ 196 CapacityInMb: 5120, 197 }, 198 BackingDiskId: volumeId, 199 }, 200 } 201 202 staticCnsVolumeCreateSpecList = append(staticCnsVolumeCreateSpecList, staticCnsVolumeCreateSpec) 203 t.Logf("Creating volume using the spec: %+v", pretty.Sprint(staticCnsVolumeCreateSpec)) 204 recreateTask, err := cnsClient.CreateVolume(ctx, staticCnsVolumeCreateSpecList) 205 if err != nil { 206 t.Errorf("Failed to create volume. Error: %+v \n", err) 207 t.Fatal(err) 208 } 209 reCreateTaskInfo, err := GetTaskInfo(ctx, recreateTask) 210 if err != nil { 211 t.Errorf("Failed to create volume. Error: %+v \n", err) 212 t.Fatal(err) 213 } 214 reCreateTaskResult, err := GetTaskResult(ctx, reCreateTaskInfo) 215 if err != nil { 216 t.Errorf("Failed to create volume. Error: %+v \n", err) 217 t.Fatal(err) 218 } 219 if reCreateTaskResult == nil { 220 t.Fatalf("Empty create task results") 221 t.FailNow() 222 } 223 reCreateVolumeOperationRes := reCreateTaskResult.GetCnsVolumeOperationResult() 224 t.Logf("reCreateVolumeOperationRes.: %+v", pretty.Sprint(reCreateVolumeOperationRes)) 225 if reCreateVolumeOperationRes.Fault != nil { 226 t.Logf("reCreateVolumeOperationRes.Fault: %+v", pretty.Sprint(reCreateVolumeOperationRes.Fault)) 227 _, ok := reCreateVolumeOperationRes.Fault.Fault.(cnstypes.CnsAlreadyRegisteredFault) 228 if !ok { 229 t.Fatalf("Fault is not a CnsAlreadyRegisteredFault") 230 } 231 } else { 232 t.Fatalf("re-create same volume should fail with CnsAlreadyRegisteredFault") 233 } 234 } 235 236 // Test QueryVolume API 237 var queryFilter cnstypes.CnsQueryFilter 238 var volumeIDList []cnstypes.CnsVolumeId 239 volumeIDList = append(volumeIDList, cnstypes.CnsVolumeId{Id: volumeId}) 240 queryFilter.VolumeIds = volumeIDList 241 t.Logf("Calling QueryVolume using queryFilter: %+v", pretty.Sprint(queryFilter)) 242 queryResult, err := cnsClient.QueryVolume(ctx, queryFilter) 243 if err != nil { 244 t.Errorf("Failed to query volume. Error: %+v \n", err) 245 t.Fatal(err) 246 } 247 t.Logf("Successfully Queried Volumes. queryResult: %+v", pretty.Sprint(queryResult)) 248 249 // Test QueryVolumeInfo API 250 // QueryVolumeInfo is not supported on ReleaseVSAN67u3 and ReleaseVSAN70 251 // This API is available on vSphere 7.0u1 onward 252 if cnsClient.Version != ReleaseVSAN67u3 && cnsClient.Version != ReleaseVSAN70 { 253 t.Logf("Calling QueryVolumeInfo using: %+v", pretty.Sprint(volumeIDList)) 254 queryVolumeInfoTask, err := cnsClient.QueryVolumeInfo(ctx, volumeIDList) 255 if err != nil { 256 t.Errorf("Failed to query volumes with QueryVolumeInfo. Error: %+v \n", err) 257 t.Fatal(err) 258 } 259 queryVolumeInfoTaskInfo, err := GetTaskInfo(ctx, queryVolumeInfoTask) 260 if err != nil { 261 t.Errorf("Failed to query volumes with QueryVolumeInfo. Error: %+v \n", err) 262 t.Fatal(err) 263 } 264 queryVolumeInfoTaskResults, err := GetTaskResultArray(ctx, queryVolumeInfoTaskInfo) 265 if err != nil { 266 t.Errorf("Failed to query volumes with QueryVolumeInfo. Error: %+v \n", err) 267 t.Fatal(err) 268 } 269 if queryVolumeInfoTaskResults == nil { 270 t.Fatalf("Empty queryVolumeInfoTaskResult") 271 t.FailNow() 272 } 273 for _, queryVolumeInfoTaskResult := range queryVolumeInfoTaskResults { 274 queryVolumeInfoOperationRes := queryVolumeInfoTaskResult.GetCnsVolumeOperationResult() 275 if queryVolumeInfoOperationRes.Fault != nil { 276 t.Fatalf("Failed to query volumes with QueryVolumeInfo. fault=%+v", queryVolumeInfoOperationRes.Fault) 277 } 278 t.Logf("Successfully Queried Volumes. queryVolumeInfoTaskResult: %+v", pretty.Sprint(queryVolumeInfoTaskResult)) 279 } 280 } 281 282 // Test BackingDiskObjectId field only for vVol or vSAN volume type 283 var queryFilterBackingDiskObjectIdTest cnstypes.CnsQueryFilter 284 var volumeIDListBackingDiskObjectIdTest []cnstypes.CnsVolumeId 285 volumeIDListBackingDiskObjectIdTest = append(volumeIDListBackingDiskObjectIdTest, cnstypes.CnsVolumeId{Id: volumeId}) 286 queryFilterBackingDiskObjectIdTest.VolumeIds = volumeIDListBackingDiskObjectIdTest 287 t.Logf("Calling QueryVolume using queryFilter: %+v", pretty.Sprint(queryFilterBackingDiskObjectIdTest)) 288 queryResultBackingDiskObjectIdTest, err := cnsClient.QueryVolume(ctx, queryFilterBackingDiskObjectIdTest) 289 if err != nil { 290 t.Errorf("Failed to query all volumes. Error: %+v \n", err) 291 t.Fatal(err) 292 } 293 t.Logf("Successfully Queried Volumes. queryResultBackingDiskObjectIdTest: %+v", pretty.Sprint(queryResultBackingDiskObjectIdTest)) 294 t.Log("Checking backingDiskObjectId retieved") 295 datastoreType, err := ds.Type(ctx) 296 if err != nil { 297 t.Errorf("Failed to get datastore type. Error: %+v \n", err) 298 t.Fatal(err) 299 } 300 for _, vol := range queryResultBackingDiskObjectIdTest.Volumes { 301 // BackingDiskObjectId is only for vsan/vvol, for other type this field is empty but test should not fail 302 backingDiskObjectId := vol.BackingObjectDetails.(*cnstypes.CnsBlockBackingDetails).BackingDiskObjectId 303 if backingDiskObjectId == "" { 304 if datastoreType == vim25types.HostFileSystemVolumeFileSystemTypeVsan || datastoreType == vim25types.HostFileSystemVolumeFileSystemTypeVVOL { 305 t.Errorf("Failed to get BackingDiskObjectId") 306 t.FailNow() 307 } 308 } 309 } 310 311 // Test QuerySnapshots API on 7.0 U3 or above 312 var snapshotQueryFilter cnstypes.CnsSnapshotQueryFilter 313 var querySnapshotsTaskResult *cnstypes.CnsSnapshotQueryResult 314 var QuerySnapshotsFunc func(snapshotQueryFilter cnstypes.CnsSnapshotQueryFilter) *cnstypes.CnsSnapshotQueryResult 315 316 if isvSphereVersion70U3orAbove(ctx, c.ServiceContent.About) { 317 // Construct the CNS SnapshotQueryFilter and the function handler of QuerySnapshots 318 QuerySnapshotsFunc = func(snapshotQueryFilter cnstypes.CnsSnapshotQueryFilter) *cnstypes.CnsSnapshotQueryResult { 319 querySnapshotsTask, err := cnsClient.QuerySnapshots(ctx, snapshotQueryFilter) 320 if err != nil { 321 t.Fatalf("Failed to get the task of QuerySnapshots. Error: %+v \n", err) 322 } 323 querySnapshotsTaskInfo, err := GetTaskInfo(ctx, querySnapshotsTask) 324 if err != nil { 325 t.Fatalf("Failed to get the task info of QuerySnapshots. Error: %+v \n", err) 326 } 327 querySnapshotsTaskResult, err := GetQuerySnapshotsTaskResult(ctx, querySnapshotsTaskInfo) 328 if err != nil { 329 t.Fatalf("Failed to get the task result of QuerySnapshots. Error: %+v \n", err) 330 } 331 return querySnapshotsTaskResult 332 } 333 334 // Calls QuerySnapshots before CreateSnapshots 335 snapshotQueryFilter = cnstypes.CnsSnapshotQueryFilter{ 336 SnapshotQuerySpecs: []cnstypes.CnsSnapshotQuerySpec{ 337 { 338 VolumeId: cnstypes.CnsVolumeId{Id: volumeId}, 339 }, 340 }, 341 } 342 t.Logf("QuerySnapshots before CreateSnapshots, snapshotQueryFilter %+v", snapshotQueryFilter) 343 querySnapshotsTaskResult = QuerySnapshotsFunc(snapshotQueryFilter) 344 t.Logf("snapshotQueryResult %+v", querySnapshotsTaskResult) 345 } 346 347 // Test CreateSnapshot API 348 // Construct the CNS SnapshotCreateSpec list 349 desc := "example-vanilla-block-snapshot" 350 var cnsSnapshotCreateSpecList []cnstypes.CnsSnapshotCreateSpec 351 cnsSnapshotCreateSpec := cnstypes.CnsSnapshotCreateSpec{ 352 VolumeId: cnstypes.CnsVolumeId{ 353 Id: volumeId, 354 }, 355 Description: desc, 356 } 357 cnsSnapshotCreateSpecList = append(cnsSnapshotCreateSpecList, cnsSnapshotCreateSpec) 358 t.Logf("Creating snapshot using the spec: %+v", pretty.Sprint(cnsSnapshotCreateSpecList)) 359 createSnapshotsTask, err := cnsClient.CreateSnapshots(ctx, cnsSnapshotCreateSpecList) 360 if err != nil { 361 t.Errorf("Failed to get the task of CreateSnapshots. Error: %+v \n", err) 362 t.Fatal(err) 363 } 364 createSnapshotsTaskInfo, err := GetTaskInfo(ctx, createSnapshotsTask) 365 if err != nil { 366 t.Errorf("Failed to get the task info of CreateSnapshots. Error: %+v \n", err) 367 t.Fatal(err) 368 } 369 createSnapshotsTaskResult, err := GetTaskResult(ctx, createSnapshotsTaskInfo) 370 if err != nil { 371 t.Errorf("Failed to get the task result of CreateSnapshots. Error: %+v \n", err) 372 t.Fatal(err) 373 } 374 createSnapshotsOperationRes := createSnapshotsTaskResult.GetCnsVolumeOperationResult() 375 if createSnapshotsOperationRes.Fault != nil { 376 t.Fatalf("Failed to create snapshots: fault=%+v", createSnapshotsOperationRes.Fault) 377 } 378 379 snapshotCreateResult := interface{}(createSnapshotsTaskResult).(*cnstypes.CnsSnapshotCreateResult) 380 snapshotId := snapshotCreateResult.Snapshot.SnapshotId.Id 381 snapshotCreateTime := snapshotCreateResult.Snapshot.CreateTime 382 t.Logf("snapshotCreateResult: %+v", pretty.Sprint(snapshotCreateResult)) 383 t.Logf("CreateSnapshots: Snapshot created successfully. volumeId: %q, snapshot id %q, time stamp %+v, opId: %q", volumeId, snapshotId, snapshotCreateTime, createSnapshotsTaskInfo.ActivationId) 384 385 // Test QuerySnapshots API on 7.0 U3 or above 386 if isvSphereVersion70U3orAbove(ctx, c.ServiceContent.About) { 387 // Calls QuerySnapshots after CreateSnapshots 388 snapshotQueryFilter = cnstypes.CnsSnapshotQueryFilter{ 389 SnapshotQuerySpecs: []cnstypes.CnsSnapshotQuerySpec{ 390 { 391 VolumeId: cnstypes.CnsVolumeId{Id: volumeId}, 392 SnapshotId: &cnstypes.CnsSnapshotId{Id: snapshotId}, 393 }, 394 }, 395 } 396 t.Logf("QuerySnapshots after CreateSnapshots, snapshotQueryFilter %+v", snapshotQueryFilter) 397 querySnapshotsTaskResult = QuerySnapshotsFunc(snapshotQueryFilter) 398 t.Logf("snapshotQueryResult %+v", querySnapshotsTaskResult) 399 } 400 401 // Test CreateVolumeFromSnapshot functionality by calling CreateVolume with VolumeSource set 402 // Query Volume for capacity 403 var queryVolumeIDList []cnstypes.CnsVolumeId 404 queryVolumeIDList = append(queryVolumeIDList, cnstypes.CnsVolumeId{Id: volumeId}) 405 queryFilter.VolumeIds = queryVolumeIDList 406 t.Logf("CreateVolumeFromSnapshot: calling QueryVolume using queryFilter: %+v", pretty.Sprint(queryFilter)) 407 queryResult, err = cnsClient.QueryVolume(ctx, queryFilter) 408 if err != nil { 409 t.Errorf("Failed to query volume. Error: %+v \n", err) 410 t.Fatal(err) 411 } 412 var snapshotSize int64 413 if len(queryResult.Volumes) > 0 { 414 snapshotSize = queryResult.Volumes[0].BackingObjectDetails.GetCnsBackingObjectDetails().CapacityInMb 415 } else { 416 msg := fmt.Sprintf("failed to get the snapshot size by querying volume: %q", volumeId) 417 t.Fatal(msg) 418 } 419 t.Logf("CreateVolumeFromSnapshot: Successfully Queried Volumes. queryResult: %+v", pretty.Sprint(queryResult)) 420 421 // Construct the CNS VolumeCreateSpec list 422 cnsCreateVolumeFromSnapshotCreateSpec := cnstypes.CnsVolumeCreateSpec{ 423 Name: "pvc-901e87eb-c2bd-11e9-806f-005056a0c9a0-create-from-snapshot", 424 VolumeType: string(cnstypes.CnsVolumeTypeBlock), 425 Datastores: dsList, 426 Metadata: cnstypes.CnsVolumeMetadata{ 427 ContainerCluster: containerCluster, 428 }, 429 BackingObjectDetails: &cnstypes.CnsBlockBackingDetails{ 430 CnsBackingObjectDetails: cnstypes.CnsBackingObjectDetails{ 431 CapacityInMb: snapshotSize, 432 }, 433 }, 434 VolumeSource: &cnstypes.CnsSnapshotVolumeSource{ 435 VolumeId: cnstypes.CnsVolumeId{ 436 Id: volumeId, 437 }, 438 SnapshotId: cnstypes.CnsSnapshotId{ 439 Id: snapshotId, 440 }, 441 }, 442 } 443 var cnsCreateVolumeFromSnapshotCreateSpecList []cnstypes.CnsVolumeCreateSpec 444 cnsCreateVolumeFromSnapshotCreateSpecList = append(cnsCreateVolumeFromSnapshotCreateSpecList, cnsCreateVolumeFromSnapshotCreateSpec) 445 t.Logf("Creating volume from snapshot using the spec: %+v", pretty.Sprint(cnsCreateVolumeFromSnapshotCreateSpec)) 446 createVolumeFromSnapshotTask, err := cnsClient.CreateVolume(ctx, cnsCreateVolumeFromSnapshotCreateSpecList) 447 if err != nil { 448 t.Errorf("Failed to create volume from snapshot. Error: %+v \n", err) 449 t.Fatal(err) 450 } 451 createVolumeFromSnapshotTaskInfo, err := GetTaskInfo(ctx, createVolumeFromSnapshotTask) 452 if err != nil { 453 t.Errorf("Failed to create volume from snapshot. Error: %+v \n", err) 454 t.Fatal(err) 455 } 456 createVolumeFromSnapshotTaskResult, err := GetTaskResult(ctx, createVolumeFromSnapshotTaskInfo) 457 if err != nil { 458 t.Errorf("Failed to create volume from snapshot. Error: %+v \n", err) 459 t.Fatal(err) 460 } 461 if createVolumeFromSnapshotTaskResult == nil { 462 t.Fatalf("Empty create task results") 463 t.FailNow() 464 } 465 createVolumeFromSnapshotOperationRes := createVolumeFromSnapshotTaskResult.GetCnsVolumeOperationResult() 466 if createVolumeFromSnapshotOperationRes.Fault != nil { 467 t.Fatalf("Failed to create volume from snapshot: fault=%+v", createVolumeFromSnapshotOperationRes.Fault) 468 } 469 createVolumeFromSnapshotVolumeId := createVolumeFromSnapshotOperationRes.VolumeId.Id 470 createVolumeFromSnapshotResult := (createVolumeFromSnapshotTaskResult).(*cnstypes.CnsVolumeCreateResult) 471 t.Logf("createVolumeFromSnapshotResult %+v", createVolumeFromSnapshotResult) 472 t.Logf("Volume created from snapshot %s sucessfully. volumeId: %s", snapshotId, createVolumeFromSnapshotVolumeId) 473 474 // Clean up volume created from snapshot above 475 var deleteVolumeFromSnapshotVolumeIDList []cnstypes.CnsVolumeId 476 deleteVolumeFromSnapshotVolumeIDList = append(deleteVolumeFromSnapshotVolumeIDList, cnstypes.CnsVolumeId{Id: createVolumeFromSnapshotVolumeId}) 477 t.Logf("Deleting volume: %+v", deleteVolumeFromSnapshotVolumeIDList) 478 deleteVolumeFromSnapshotTask, err := cnsClient.DeleteVolume(ctx, deleteVolumeFromSnapshotVolumeIDList, true) 479 if err != nil { 480 t.Errorf("Failed to delete volume. Error: %+v \n", err) 481 t.Fatal(err) 482 } 483 deleteVolumeFromSnapshotTaskInfo, err := GetTaskInfo(ctx, deleteVolumeFromSnapshotTask) 484 if err != nil { 485 t.Errorf("Failed to delete volume. Error: %+v \n", err) 486 t.Fatal(err) 487 } 488 deleteVolumeFromSnapshotTaskResult, err := GetTaskResult(ctx, deleteVolumeFromSnapshotTaskInfo) 489 if err != nil { 490 t.Errorf("Failed to delete volume. Error: %+v \n", err) 491 t.Fatal(err) 492 } 493 if deleteVolumeFromSnapshotTaskResult == nil { 494 t.Fatalf("Empty delete task results") 495 t.FailNow() 496 } 497 deleteVolumeFromSnapshotOperationRes := deleteVolumeFromSnapshotTaskResult.GetCnsVolumeOperationResult() 498 if deleteVolumeFromSnapshotOperationRes.Fault != nil { 499 t.Fatalf("Failed to delete volume: fault=%+v", deleteVolumeFromSnapshotOperationRes.Fault) 500 } 501 t.Logf("Volume: %q deleted sucessfully", createVolumeFromSnapshotVolumeId) 502 503 // Test DeleteSnapshot API 504 // Construct the CNS SnapshotDeleteSpec list 505 var cnsSnapshotDeleteSpecList []cnstypes.CnsSnapshotDeleteSpec 506 cnsSnapshotDeleteSpec := cnstypes.CnsSnapshotDeleteSpec{ 507 VolumeId: cnstypes.CnsVolumeId{ 508 Id: volumeId, 509 }, 510 SnapshotId: cnstypes.CnsSnapshotId{ 511 Id: snapshotId, 512 }, 513 } 514 cnsSnapshotDeleteSpecList = append(cnsSnapshotDeleteSpecList, cnsSnapshotDeleteSpec) 515 t.Logf("Deleting snapshot using the spec: %+v", pretty.Sprint(cnsSnapshotDeleteSpecList)) 516 deleteSnapshotsTask, err := cnsClient.DeleteSnapshots(ctx, cnsSnapshotDeleteSpecList) 517 if err != nil { 518 t.Errorf("Failed to get the task of DeleteSnapshots. Error: %+v \n", err) 519 t.Fatal(err) 520 } 521 deleteSnapshotsTaskInfo, err := GetTaskInfo(ctx, deleteSnapshotsTask) 522 if err != nil { 523 t.Errorf("Failed to get the task info of DeleteSnapshots. Error: %+v \n", err) 524 t.Fatal(err) 525 } 526 527 deleteSnapshotsTaskResult, err := GetTaskResult(ctx, deleteSnapshotsTaskInfo) 528 if err != nil { 529 t.Errorf("Failed to get the task result of DeleteSnapshots. Error: %+v \n", err) 530 t.Fatal(err) 531 } 532 533 deleteSnapshotsOperationRes := deleteSnapshotsTaskResult.GetCnsVolumeOperationResult() 534 if deleteSnapshotsOperationRes.Fault != nil { 535 t.Fatalf("Failed to delete snapshots: fault=%+v", deleteSnapshotsOperationRes.Fault) 536 } 537 538 snapshotDeleteResult := interface{}(deleteSnapshotsTaskResult).(*cnstypes.CnsSnapshotDeleteResult) 539 t.Logf("snapshotDeleteResult: %+v", pretty.Sprint(snapshotCreateResult)) 540 t.Logf("DeleteSnapshots: Snapshot deleted successfully. volumeId: %q, snapshot id %q, opId: %q", volumeId, snapshotDeleteResult.SnapshotId, deleteSnapshotsTaskInfo.ActivationId) 541 542 // Test Relocate API 543 // Relocate API is not supported on ReleaseVSAN67u3 and ReleaseVSAN70 544 // This API is available on vSphere 7.0u1 onward 545 if cnsClient.Version != ReleaseVSAN67u3 && cnsClient.Version != ReleaseVSAN70 && 546 datastoreForMigration != "" { 547 548 var migrationDS *object.Datastore 549 var serviceLocatorInstance *vim25types.ServiceLocator = nil 550 551 // Cross-VC migration. 552 // This is only supported on 8.0u3 onwards. 553 if remoteVcUrl != "" && isvSphereVersion80U3orAbove(ctx, c.ServiceContent.About) { 554 remoteUrl, err := soap.ParseURL(remoteVcUrl) 555 if err != nil { 556 t.Fatal(err) 557 } 558 remoteVcClient, err := govmomi.NewClient(ctx, remoteUrl, true) 559 if err != nil { 560 t.Fatal(err) 561 } 562 remoteCnsClient, err := NewClient(ctx, remoteVcClient.Client) 563 if err != nil { 564 t.Fatal(err) 565 } 566 remoteFinder := find.NewFinder(remoteCnsClient.vim25Client, false) 567 remoteDc, err := remoteFinder.Datacenter(ctx, remoteDatacenter) 568 if err != nil { 569 t.Fatal(err) 570 } 571 remoteFinder.SetDatacenter(remoteDc) 572 573 migrationDS, err = remoteFinder.Datastore(ctx, datastoreForMigration) 574 if err != nil { 575 t.Fatal(err) 576 } 577 578 // Get ServiceLocator instance for remote VC. 579 userName := remoteUrl.User.Username() 580 password, _ := remoteUrl.User.Password() 581 serviceLocatorInstance, err = GetServiceLocatorInstance(ctx, userName, password, remoteVcClient) 582 if err != nil { 583 t.Fatal(err) 584 } 585 586 } else { 587 // Same VC migration 588 migrationDS, err = finder.Datastore(ctx, datastoreForMigration) 589 if err != nil { 590 t.Fatal(err) 591 } 592 } 593 594 blockVolRelocateSpec := cnstypes.CnsBlockVolumeRelocateSpec{ 595 CnsVolumeRelocateSpec: cnstypes.CnsVolumeRelocateSpec{ 596 VolumeId: cnstypes.CnsVolumeId{ 597 Id: volumeId, 598 }, 599 Datastore: migrationDS.Reference(), 600 }, 601 } 602 if serviceLocatorInstance != nil { 603 blockVolRelocateSpec.ServiceLocator = serviceLocatorInstance 604 } 605 606 t.Logf("Relocating volume using the spec: %+v", pretty.Sprint(blockVolRelocateSpec)) 607 608 relocateTask, err := cnsClient.RelocateVolume(ctx, blockVolRelocateSpec) 609 if err != nil { 610 t.Errorf("Failed to migrate volume with Relocate API. Error: %+v \n", err) 611 t.Fatal(err) 612 } 613 relocateTaskInfo, err := GetTaskInfo(ctx, relocateTask) 614 if err != nil { 615 t.Errorf("Failed to get info of task returned by Relocate API. Error: %+v \n", err) 616 t.Fatal(err) 617 } 618 taskResults, err := GetTaskResultArray(ctx, relocateTaskInfo) 619 if err != nil { 620 t.Fatal(err) 621 } 622 for _, taskResult := range taskResults { 623 res := taskResult.GetCnsVolumeOperationResult() 624 if res.Fault != nil { 625 t.Fatalf("Relocation failed due to fault: %+v", res.Fault) 626 } 627 t.Logf("Successfully Relocated volume. Relocate task info result: %+v", pretty.Sprint(taskResult)) 628 } 629 } 630 631 // Test ExtendVolume API 632 var newCapacityInMb int64 = 10240 633 var cnsVolumeExtendSpecList []cnstypes.CnsVolumeExtendSpec 634 cnsVolumeExtendSpec := cnstypes.CnsVolumeExtendSpec{ 635 VolumeId: cnstypes.CnsVolumeId{ 636 Id: volumeId, 637 }, 638 CapacityInMb: newCapacityInMb, 639 } 640 cnsVolumeExtendSpecList = append(cnsVolumeExtendSpecList, cnsVolumeExtendSpec) 641 t.Logf("Extending volume using the spec: %+v", pretty.Sprint(cnsVolumeExtendSpecList)) 642 extendTask, err := cnsClient.ExtendVolume(ctx, cnsVolumeExtendSpecList) 643 if err != nil { 644 t.Errorf("Failed to extend volume. Error: %+v \n", err) 645 t.Fatal(err) 646 } 647 extendTaskInfo, err := GetTaskInfo(ctx, extendTask) 648 if err != nil { 649 t.Errorf("Failed to extend volume. Error: %+v \n", err) 650 t.Fatal(err) 651 } 652 extendTaskResult, err := GetTaskResult(ctx, extendTaskInfo) 653 if err != nil { 654 t.Errorf("Failed to extend volume. Error: %+v \n", err) 655 t.Fatal(err) 656 } 657 if extendTaskResult == nil { 658 t.Fatalf("Empty extend task results") 659 t.FailNow() 660 } 661 extendVolumeOperationRes := extendTaskResult.GetCnsVolumeOperationResult() 662 if extendVolumeOperationRes.Fault != nil { 663 t.Fatalf("Failed to extend volume: fault=%+v", extendVolumeOperationRes.Fault) 664 } 665 extendVolumeId := extendVolumeOperationRes.VolumeId.Id 666 t.Logf("Volume extended sucessfully. Volume ID: %s", extendVolumeId) 667 668 // Verify volume is extended to the specified size 669 t.Logf("Calling QueryVolume after ExtendVolume using queryFilter: %+v", queryFilter) 670 queryResult, err = cnsClient.QueryVolume(ctx, queryFilter) 671 if err != nil { 672 t.Errorf("Failed to query volume. Error: %+v \n", err) 673 t.Fatal(err) 674 } 675 t.Logf("Successfully Queried Volumes after ExtendVolume. queryResult: %+v", pretty.Sprint(queryResult)) 676 queryCapacity := queryResult.Volumes[0].BackingObjectDetails.(*cnstypes.CnsBlockBackingDetails).CapacityInMb 677 if newCapacityInMb != queryCapacity { 678 t.Errorf("After extend volume %s, expected new volume size is %d, but actual volume size is %d.", extendVolumeId, newCapacityInMb, queryCapacity) 679 } else { 680 t.Logf("Volume extended sucessfully to the new size. Volume ID: %s New Size: %d", extendVolumeId, newCapacityInMb) 681 } 682 683 // Test UpdateVolumeMetadata 684 var updateSpecList []cnstypes.CnsVolumeMetadataUpdateSpec 685 686 var metadataList []cnstypes.BaseCnsEntityMetadata 687 newLabels := []vim25types.KeyValue{ 688 { 689 Key: "testLabel", 690 Value: "testValue", 691 }, 692 } 693 pvmetadata := &cnstypes.CnsKubernetesEntityMetadata{ 694 CnsEntityMetadata: cnstypes.CnsEntityMetadata{ 695 DynamicData: vim25types.DynamicData{}, 696 EntityName: "pvc-53465372-5c12-4818-96f8-0ace4f4fd116", 697 Labels: newLabels, 698 Delete: false, 699 ClusterID: "demo-cluster-id", 700 }, 701 EntityType: string(cnstypes.CnsKubernetesEntityTypePV), 702 Namespace: "", 703 } 704 metadataList = append(metadataList, cnstypes.BaseCnsEntityMetadata(pvmetadata)) 705 706 pvcmetadata := &cnstypes.CnsKubernetesEntityMetadata{ 707 CnsEntityMetadata: cnstypes.CnsEntityMetadata{ 708 DynamicData: vim25types.DynamicData{}, 709 EntityName: "example-vanilla-block-pvc", 710 Labels: newLabels, 711 Delete: false, 712 ClusterID: "demo-cluster-id", 713 }, 714 EntityType: string(cnstypes.CnsKubernetesEntityTypePVC), 715 Namespace: "default", 716 ReferredEntity: []cnstypes.CnsKubernetesEntityReference{ 717 { 718 EntityType: string(cnstypes.CnsKubernetesEntityTypePV), 719 EntityName: "pvc-53465372-5c12-4818-96f8-0ace4f4fd116", 720 Namespace: "", 721 ClusterID: "demo-cluster-id", 722 }, 723 }, 724 } 725 metadataList = append(metadataList, cnstypes.BaseCnsEntityMetadata(pvcmetadata)) 726 727 podmetadata := &cnstypes.CnsKubernetesEntityMetadata{ 728 CnsEntityMetadata: cnstypes.CnsEntityMetadata{ 729 DynamicData: vim25types.DynamicData{}, 730 EntityName: "example-pod", 731 Delete: false, 732 ClusterID: "demo-cluster-id", 733 }, 734 EntityType: string(cnstypes.CnsKubernetesEntityTypePOD), 735 Namespace: "default", 736 ReferredEntity: []cnstypes.CnsKubernetesEntityReference{ 737 { 738 EntityType: string(cnstypes.CnsKubernetesEntityTypePVC), 739 EntityName: "example-vanilla-block-pvc", 740 Namespace: "default", 741 ClusterID: "demo-cluster-id", 742 }, 743 }, 744 } 745 metadataList = append(metadataList, cnstypes.BaseCnsEntityMetadata(podmetadata)) 746 747 cnsVolumeMetadataUpdateSpec := cnstypes.CnsVolumeMetadataUpdateSpec{ 748 VolumeId: cnstypes.CnsVolumeId{Id: volumeId}, 749 Metadata: cnstypes.CnsVolumeMetadata{ 750 DynamicData: vim25types.DynamicData{}, 751 ContainerCluster: containerCluster, 752 EntityMetadata: metadataList, 753 ContainerClusterArray: containerClusterArray, 754 }, 755 } 756 t.Logf("Updating volume using the spec: %+v", cnsVolumeMetadataUpdateSpec) 757 updateSpecList = append(updateSpecList, cnsVolumeMetadataUpdateSpec) 758 updateTask, err := cnsClient.UpdateVolumeMetadata(ctx, updateSpecList) 759 if err != nil { 760 t.Errorf("Failed to update volume metadata. Error: %+v \n", err) 761 t.Fatal(err) 762 } 763 updateTaskInfo, err := GetTaskInfo(ctx, updateTask) 764 if err != nil { 765 t.Errorf("Failed to update volume metadata. Error: %+v \n", err) 766 t.Fatal(err) 767 } 768 updateTaskResult, err := GetTaskResult(ctx, updateTaskInfo) 769 if err != nil { 770 t.Errorf("Failed to update volume metadata. Error: %+v \n", err) 771 t.Fatal(err) 772 } 773 if updateTaskResult == nil { 774 t.Fatalf("Empty update task results") 775 t.FailNow() 776 } 777 updateVolumeOperationRes := updateTaskResult.GetCnsVolumeOperationResult() 778 if updateVolumeOperationRes.Fault != nil { 779 t.Fatalf("Failed to update volume metadata: fault=%+v", updateVolumeOperationRes.Fault) 780 } else { 781 t.Logf("Successfully updated volume metadata") 782 } 783 784 t.Logf("Calling QueryVolume using queryFilter: %+v", pretty.Sprint(queryFilter)) 785 queryResult, err = cnsClient.QueryVolume(ctx, queryFilter) 786 if err != nil { 787 t.Errorf("Failed to query volume. Error: %+v \n", err) 788 t.Fatal(err) 789 } 790 t.Logf("Successfully Queried Volumes. queryResult: %+v", pretty.Sprint(queryResult)) 791 792 // Test QueryAll 793 querySelection := cnstypes.CnsQuerySelection{ 794 Names: []string{ 795 string(cnstypes.CnsQuerySelectionName_VOLUME_NAME), 796 string(cnstypes.CnsQuerySelectionName_VOLUME_TYPE), 797 string(cnstypes.CnsQuerySelectionName_DATASTORE_URL), 798 string(cnstypes.CnsQuerySelectionName_POLICY_ID), 799 string(cnstypes.CnsQuerySelectionName_HEALTH_STATUS), 800 string(cnstypes.CnsQuerySelectionName_BACKING_OBJECT_DETAILS), 801 string(cnstypes.CnsQuerySelectionName_COMPLIANCE_STATUS), 802 string(cnstypes.CnsQuerySelectionName_DATASTORE_ACCESSIBILITY_STATUS), 803 }, 804 } 805 queryResult, err = cnsClient.QueryAllVolume(ctx, cnstypes.CnsQueryFilter{}, querySelection) 806 if err != nil { 807 t.Errorf("Failed to query all volumes. Error: %+v \n", err) 808 t.Fatal(err) 809 } 810 t.Logf("Successfully Queried all Volumes. queryResult: %+v", pretty.Sprint(queryResult)) 811 812 // Create a VM to test Attach Volume API. 813 virtualMachineConfigSpec := vim25types.VirtualMachineConfigSpec{ 814 Name: "test-node-vm", 815 Files: &vim25types.VirtualMachineFileInfo{ 816 VmPathName: "[" + datastore + "]", 817 }, 818 NumCPUs: 1, 819 MemoryMB: 4, 820 DeviceChange: []vim25types.BaseVirtualDeviceConfigSpec{ 821 &vim25types.VirtualDeviceConfigSpec{ 822 Operation: vim25types.VirtualDeviceConfigSpecOperationAdd, 823 Device: &vim25types.ParaVirtualSCSIController{ 824 VirtualSCSIController: vim25types.VirtualSCSIController{ 825 SharedBus: vim25types.VirtualSCSISharingNoSharing, 826 VirtualController: vim25types.VirtualController{ 827 BusNumber: 0, 828 VirtualDevice: vim25types.VirtualDevice{ 829 Key: 1000, 830 }, 831 }, 832 }, 833 }, 834 }, 835 }, 836 } 837 defaultFolder, err := finder.DefaultFolder(ctx) 838 if err != nil { 839 t.Fatal(err) 840 } 841 var resourcePool *object.ResourcePool 842 if resourcePoolPath == "" { 843 resourcePool, err = finder.DefaultResourcePool(ctx) 844 } else { 845 resourcePool, err = finder.ResourcePool(ctx, resourcePoolPath) 846 } 847 if err != nil { 848 t.Errorf("Error occurred while getting DefaultResourcePool. err: %+v", err) 849 t.Fatal(err) 850 } 851 task, err := defaultFolder.CreateVM(ctx, virtualMachineConfigSpec, resourcePool, nil) 852 if err != nil { 853 t.Errorf("Failed to create VM. Error: %+v \n", err) 854 t.Fatal(err) 855 } 856 857 vmTaskInfo, err := task.WaitForResult(ctx, nil) 858 if err != nil { 859 t.Errorf("Error occurred while waiting for create VM task result. err: %+v", err) 860 t.Fatal(err) 861 } 862 863 vmRef := vmTaskInfo.Result.(object.Reference) 864 t.Logf("Node VM created sucessfully. vmRef: %+v", vmRef.Reference()) 865 866 nodeVM := object.NewVirtualMachine(cnsClient.vim25Client, vmRef.Reference()) 867 defer nodeVM.Destroy(ctx) 868 869 // Test AttachVolume API 870 var cnsVolumeAttachSpecList []cnstypes.CnsVolumeAttachDetachSpec 871 cnsVolumeAttachSpec := cnstypes.CnsVolumeAttachDetachSpec{ 872 VolumeId: cnstypes.CnsVolumeId{ 873 Id: volumeId, 874 }, 875 Vm: nodeVM.Reference(), 876 } 877 cnsVolumeAttachSpecList = append(cnsVolumeAttachSpecList, cnsVolumeAttachSpec) 878 t.Logf("Attaching volume using the spec: %+v", cnsVolumeAttachSpec) 879 attachTask, err := cnsClient.AttachVolume(ctx, cnsVolumeAttachSpecList) 880 if err != nil { 881 t.Errorf("Failed to attach volume. Error: %+v \n", err) 882 t.Fatal(err) 883 } 884 attachTaskInfo, err := GetTaskInfo(ctx, attachTask) 885 if err != nil { 886 t.Errorf("Failed to attach volume. Error: %+v \n", err) 887 t.Fatal(err) 888 } 889 attachTaskResult, err := GetTaskResult(ctx, attachTaskInfo) 890 if err != nil { 891 t.Errorf("Failed to attach volume. Error: %+v \n", err) 892 t.Fatal(err) 893 } 894 if attachTaskResult == nil { 895 t.Fatalf("Empty attach task results") 896 t.FailNow() 897 } 898 attachVolumeOperationRes := attachTaskResult.GetCnsVolumeOperationResult() 899 if attachVolumeOperationRes.Fault != nil { 900 t.Fatalf("Failed to attach volume: fault=%+v", attachVolumeOperationRes.Fault) 901 } 902 diskUUID := interface{}(attachTaskResult).(*cnstypes.CnsVolumeAttachResult).DiskUUID 903 t.Logf("Volume attached sucessfully. Disk UUID: %s", diskUUID) 904 905 // Re-Attach same volume to the same node and expect ResourceInUse fault 906 t.Logf("Re-Attaching volume using the spec: %+v", cnsVolumeAttachSpec) 907 attachTask, err = cnsClient.AttachVolume(ctx, cnsVolumeAttachSpecList) 908 if err != nil { 909 t.Errorf("Failed to attach volume. Error: %+v \n", err) 910 t.Fatal(err) 911 } 912 attachTaskInfo, err = GetTaskInfo(ctx, attachTask) 913 if err != nil { 914 t.Errorf("Failed to attach volume. Error: %+v \n", err) 915 t.Fatal(err) 916 } 917 attachTaskResult, err = GetTaskResult(ctx, attachTaskInfo) 918 if err != nil { 919 t.Errorf("Failed to attach volume. Error: %+v \n", err) 920 t.Fatal(err) 921 } 922 if attachTaskResult == nil { 923 t.Fatalf("Empty attach task results") 924 t.FailNow() 925 } 926 reAttachVolumeOperationRes := attachTaskResult.GetCnsVolumeOperationResult() 927 if reAttachVolumeOperationRes.Fault != nil { 928 t.Logf("reAttachVolumeOperationRes.Fault: %+v", pretty.Sprint(reAttachVolumeOperationRes.Fault)) 929 _, ok := reAttachVolumeOperationRes.Fault.Fault.(*vim25types.ResourceInUse) 930 if !ok { 931 t.Fatalf("Fault is not ResourceInUse") 932 } 933 } else { 934 t.Fatalf("re-attach same volume should fail with ResourceInUse fault") 935 } 936 937 // Test DetachVolume API 938 var cnsVolumeDetachSpecList []cnstypes.CnsVolumeAttachDetachSpec 939 cnsVolumeDetachSpec := cnstypes.CnsVolumeAttachDetachSpec{ 940 VolumeId: cnstypes.CnsVolumeId{ 941 Id: volumeId, 942 }, 943 Vm: nodeVM.Reference(), 944 } 945 cnsVolumeDetachSpecList = append(cnsVolumeDetachSpecList, cnsVolumeDetachSpec) 946 t.Logf("Detaching volume using the spec: %+v", cnsVolumeDetachSpec) 947 detachTask, err := cnsClient.DetachVolume(ctx, cnsVolumeDetachSpecList) 948 if err != nil { 949 t.Errorf("Failed to detach volume. Error: %+v \n", err) 950 t.Fatal(err) 951 } 952 detachTaskInfo, err := GetTaskInfo(ctx, detachTask) 953 if err != nil { 954 t.Errorf("Failed to detach volume. Error: %+v \n", err) 955 t.Fatal(err) 956 } 957 detachTaskResult, err := GetTaskResult(ctx, detachTaskInfo) 958 if err != nil { 959 t.Errorf("Failed to detach volume. Error: %+v \n", err) 960 t.Fatal(err) 961 } 962 if detachTaskResult == nil { 963 t.Fatalf("Empty detach task results") 964 t.FailNow() 965 } 966 detachVolumeOperationRes := detachTaskResult.GetCnsVolumeOperationResult() 967 if detachVolumeOperationRes.Fault != nil { 968 t.Fatalf("Failed to detach volume: fault=%+v", detachVolumeOperationRes.Fault) 969 } 970 t.Logf("Volume detached sucessfully") 971 972 // Test QueryVolumeAsync API only for vSphere version 7.0.3 onwards 973 if isvSphereVersion70U3orAbove(ctx, c.ServiceContent.About) { 974 queryVolumeAsyncTask, err := cnsClient.QueryVolumeAsync(ctx, queryFilter, nil) 975 if err != nil { 976 t.Errorf("Failed to query volumes with QueryVolumeAsync. Error: %+v \n", err) 977 } 978 queryVolumeAsyncTaskInfo, err := GetTaskInfo(ctx, queryVolumeAsyncTask) 979 if err != nil { 980 t.Errorf("Failed to query volumes with QueryVolumeAsync. Error: %+v \n", err) 981 } 982 queryVolumeAsyncTaskResults, err := GetTaskResultArray(ctx, queryVolumeAsyncTaskInfo) 983 if err != nil { 984 t.Errorf("Failed to query volumes with QueryVolumeAsync. Error: %+v \n", err) 985 } 986 for _, queryVolumeAsyncTaskResult := range queryVolumeAsyncTaskResults { 987 queryVolumeAsyncOperationRes := queryVolumeAsyncTaskResult.GetCnsVolumeOperationResult() 988 if queryVolumeAsyncOperationRes.Fault != nil { 989 t.Fatalf("Failed to query volumes with QueryVolumeAsync. fault=%+v", queryVolumeAsyncOperationRes.Fault) 990 } 991 t.Logf("Successfully queried Volume using queryAsync API. queryVolumeAsyncTaskResult: %+v", pretty.Sprint(queryVolumeAsyncTaskResult)) 992 } 993 } 994 995 // Test DeleteVolume API 996 t.Logf("Deleting volume: %+v", volumeIDList) 997 deleteTask, err := cnsClient.DeleteVolume(ctx, volumeIDList, true) 998 if err != nil { 999 t.Errorf("Failed to delete volume. Error: %+v \n", err) 1000 t.Fatal(err) 1001 } 1002 deleteTaskInfo, err := GetTaskInfo(ctx, deleteTask) 1003 if err != nil { 1004 t.Errorf("Failed to delete volume. Error: %+v \n", err) 1005 t.Fatal(err) 1006 } 1007 deleteTaskResult, err := GetTaskResult(ctx, deleteTaskInfo) 1008 if err != nil { 1009 t.Errorf("Failed to delete volume. Error: %+v \n", err) 1010 t.Fatal(err) 1011 } 1012 if deleteTaskResult == nil { 1013 t.Fatalf("Empty delete task results") 1014 t.FailNow() 1015 } 1016 deleteVolumeOperationRes := deleteTaskResult.GetCnsVolumeOperationResult() 1017 if deleteVolumeOperationRes.Fault != nil { 1018 t.Fatalf("Failed to delete volume: fault=%+v", deleteVolumeOperationRes.Fault) 1019 } 1020 t.Logf("Volume: %q deleted sucessfully", volumeId) 1021 1022 if run_fileshare_tests == "true" && cnsClient.Version != ReleaseVSAN67u3 { 1023 // Test creating vSAN file-share Volume 1024 var cnsFileVolumeCreateSpecList []cnstypes.CnsVolumeCreateSpec 1025 vSANFileCreateSpec := &cnstypes.CnsVSANFileCreateSpec{ 1026 SoftQuotaInMb: 5120, 1027 Permission: []vsanfstypes.VsanFileShareNetPermission{ 1028 { 1029 Ips: "*", 1030 Permissions: vsanfstypes.VsanFileShareAccessTypeREAD_WRITE, 1031 AllowRoot: true, 1032 }, 1033 }, 1034 } 1035 1036 cnsFileVolumeCreateSpec := cnstypes.CnsVolumeCreateSpec{ 1037 Name: "pvc-file-share-volume", 1038 VolumeType: string(cnstypes.CnsVolumeTypeFile), 1039 Datastores: dsList, 1040 Metadata: cnstypes.CnsVolumeMetadata{ 1041 ContainerCluster: containerCluster, 1042 ContainerClusterArray: containerClusterArray, 1043 }, 1044 BackingObjectDetails: &cnstypes.CnsVsanFileShareBackingDetails{ 1045 CnsFileBackingDetails: cnstypes.CnsFileBackingDetails{ 1046 CnsBackingObjectDetails: cnstypes.CnsBackingObjectDetails{ 1047 CapacityInMb: 5120, 1048 }, 1049 }, 1050 }, 1051 CreateSpec: vSANFileCreateSpec, 1052 } 1053 cnsFileVolumeCreateSpecList = append(cnsFileVolumeCreateSpecList, cnsFileVolumeCreateSpec) 1054 t.Logf("Creating CNS file volume using the spec: %+v", cnsFileVolumeCreateSpec) 1055 createTask, err = cnsClient.CreateVolume(ctx, cnsFileVolumeCreateSpecList) 1056 if err != nil { 1057 t.Errorf("Failed to create vsan fileshare volume. Error: %+v \n", err) 1058 t.Fatal(err) 1059 } 1060 createTaskInfo, err = GetTaskInfo(ctx, createTask) 1061 if err != nil { 1062 t.Errorf("Failed to create Fileshare volume. Error: %+v \n", err) 1063 t.Fatal(err) 1064 } 1065 createTaskResult, err = GetTaskResult(ctx, createTaskInfo) 1066 if err != nil { 1067 t.Errorf("Failed to create Fileshare volume. Error: %+v \n", err) 1068 t.Fatal(err) 1069 } 1070 if createTaskResult == nil { 1071 t.Fatalf("Empty create task results") 1072 t.FailNow() 1073 } 1074 createVolumeOperationRes = createTaskResult.GetCnsVolumeOperationResult() 1075 if createVolumeOperationRes.Fault != nil { 1076 t.Fatalf("Failed to create Fileshare volume: fault=%+v", createVolumeOperationRes.Fault) 1077 } 1078 filevolumeId := createVolumeOperationRes.VolumeId.Id 1079 t.Logf("Fileshare volume created sucessfully. filevolumeId: %s", filevolumeId) 1080 1081 // Test QueryVolume API 1082 volumeIDList = []cnstypes.CnsVolumeId{{Id: filevolumeId}} 1083 queryFilter.VolumeIds = volumeIDList 1084 t.Logf("Calling QueryVolume using queryFilter: %+v", queryFilter) 1085 queryResult, err = cnsClient.QueryVolume(ctx, queryFilter) 1086 if err != nil { 1087 t.Errorf("Failed to query volume. Error: %+v \n", err) 1088 t.Fatal(err) 1089 } 1090 t.Logf("Successfully Queried Volumes. queryResult: %+v", queryResult) 1091 fileBackingInfo := queryResult.Volumes[0].BackingObjectDetails.(*cnstypes.CnsVsanFileShareBackingDetails) 1092 t.Logf("File Share Name: %s with accessPoints: %+v", fileBackingInfo.Name, fileBackingInfo.AccessPoints) 1093 1094 // Test add read-only permissions using Configure ACLs 1095 netPerms := make([]vsanfstypes.VsanFileShareNetPermission, 0) 1096 netPerms = append(netPerms, vsanfstypes.VsanFileShareNetPermission{ 1097 Ips: "192.168.124.2", 1098 Permissions: "READ_ONLY", 1099 }) 1100 1101 vSanNFSACLEntry := make([]cnstypes.CnsNFSAccessControlSpec, 0) 1102 vSanNFSACLEntry = append(vSanNFSACLEntry, cnstypes.CnsNFSAccessControlSpec{ 1103 Permission: netPerms, 1104 }) 1105 1106 volumeID := cnstypes.CnsVolumeId{ 1107 Id: filevolumeId, 1108 } 1109 aclSpec := cnstypes.CnsVolumeACLConfigureSpec{ 1110 VolumeId: volumeID, 1111 AccessControlSpecList: vSanNFSACLEntry, 1112 } 1113 t.Logf("Invoking ConfigureVolumeACLs using the spec: %+v", pretty.Sprint(aclSpec)) 1114 aclTask, err := cnsClient.ConfigureVolumeACLs(ctx, aclSpec) 1115 if err != nil { 1116 t.Errorf("Failed to configure VolumeACLs. Error: %+v", err) 1117 t.Fatal(err) 1118 } 1119 aclTaskInfo, err := GetTaskInfo(ctx, aclTask) 1120 if err != nil { 1121 t.Errorf("Failed to configure VolumeACLs. Error: %+v", err) 1122 t.Fatal(err) 1123 } 1124 aclTaskResult, err := GetTaskResult(ctx, aclTaskInfo) 1125 if err != nil { 1126 t.Errorf("Failed to configure VolumeACLs. Error: %+v", err) 1127 t.Fatal(err) 1128 } 1129 if aclTaskResult == nil { 1130 t.Fatalf("Empty configure VolumeACLs task results") 1131 t.FailNow() 1132 } 1133 1134 // Test to revoke all permissions using Configure ACLs 1135 netPerms = make([]vsanfstypes.VsanFileShareNetPermission, 0) 1136 netPerms = append(netPerms, vsanfstypes.VsanFileShareNetPermission{ 1137 Ips: "192.168.124.2", 1138 Permissions: "READ_ONLY", 1139 }) 1140 1141 vSanNFSACLEntry = make([]cnstypes.CnsNFSAccessControlSpec, 0) 1142 vSanNFSACLEntry = append(vSanNFSACLEntry, cnstypes.CnsNFSAccessControlSpec{ 1143 Permission: netPerms, 1144 Delete: true, 1145 }) 1146 1147 aclSpec = cnstypes.CnsVolumeACLConfigureSpec{ 1148 VolumeId: volumeID, 1149 AccessControlSpecList: vSanNFSACLEntry, 1150 } 1151 t.Logf("Invoking ConfigureVolumeACLs using the spec: %+v", pretty.Sprint(aclSpec)) 1152 aclTask, err = cnsClient.ConfigureVolumeACLs(ctx, aclSpec) 1153 if err != nil { 1154 t.Errorf("Failed to configure VolumeACLs. Error: %+v", err) 1155 t.Fatal(err) 1156 } 1157 aclTaskInfo, err = GetTaskInfo(ctx, aclTask) 1158 if err != nil { 1159 t.Errorf("Failed to configure VolumeACLs. Error: %+v", err) 1160 t.Fatal(err) 1161 } 1162 aclTaskResult, err = GetTaskResult(ctx, aclTaskInfo) 1163 if err != nil { 1164 t.Errorf("Failed to configure VolumeACLs. Error: %+v", err) 1165 t.Fatal(err) 1166 } 1167 if aclTaskResult == nil { 1168 t.Fatalf("Empty configure VolumeACLs task results") 1169 t.FailNow() 1170 } 1171 1172 // Test Deleting vSAN file-share Volume 1173 var fileVolumeIDList []cnstypes.CnsVolumeId 1174 fileVolumeIDList = append(fileVolumeIDList, cnstypes.CnsVolumeId{Id: filevolumeId}) 1175 t.Logf("Deleting fileshare volume: %+v", fileVolumeIDList) 1176 deleteTask, err = cnsClient.DeleteVolume(ctx, fileVolumeIDList, true) 1177 if err != nil { 1178 t.Errorf("Failed to delete fileshare volume. Error: %+v \n", err) 1179 t.Fatal(err) 1180 } 1181 deleteTaskInfo, err = GetTaskInfo(ctx, deleteTask) 1182 if err != nil { 1183 t.Errorf("Failed to delete fileshare volume. Error: %+v \n", err) 1184 t.Fatal(err) 1185 } 1186 deleteTaskResult, err = GetTaskResult(ctx, deleteTaskInfo) 1187 if err != nil { 1188 t.Errorf("Failed to delete fileshare volume. Error: %+v \n", err) 1189 t.Fatal(err) 1190 } 1191 if deleteTaskResult == nil { 1192 t.Fatalf("Empty delete task results") 1193 t.FailNow() 1194 } 1195 deleteVolumeOperationRes = deleteTaskResult.GetCnsVolumeOperationResult() 1196 if deleteVolumeOperationRes.Fault != nil { 1197 t.Fatalf("Failed to delete fileshare volume: fault=%+v", deleteVolumeOperationRes.Fault) 1198 } 1199 t.Logf("fileshare volume:%q deleted sucessfully", filevolumeId) 1200 } 1201 if backingDiskURLPath != "" && cnsClient.Version != ReleaseVSAN67u3 && cnsClient.Version != ReleaseVSAN70 { 1202 // Test CreateVolume API with existing VMDK 1203 var cnsVolumeCreateSpecList []cnstypes.CnsVolumeCreateSpec 1204 cnsVolumeCreateSpec := cnstypes.CnsVolumeCreateSpec{ 1205 Name: "pvc-901e87eb-c2bd-11e9-806f-005056a0c9a0", 1206 VolumeType: string(cnstypes.CnsVolumeTypeBlock), 1207 Metadata: cnstypes.CnsVolumeMetadata{ 1208 ContainerCluster: containerCluster, 1209 }, 1210 BackingObjectDetails: &cnstypes.CnsBlockBackingDetails{ 1211 BackingDiskUrlPath: backingDiskURLPath, 1212 }, 1213 } 1214 cnsVolumeCreateSpecList = append(cnsVolumeCreateSpecList, cnsVolumeCreateSpec) 1215 t.Logf("Creating volume using the spec: %+v", pretty.Sprint(cnsVolumeCreateSpec)) 1216 createTask, err := cnsClient.CreateVolume(ctx, cnsVolumeCreateSpecList) 1217 if err != nil { 1218 t.Errorf("Failed to create volume. Error: %+v \n", err) 1219 t.Fatal(err) 1220 } 1221 createTaskInfo, err := GetTaskInfo(ctx, createTask) 1222 if err != nil { 1223 t.Errorf("Failed to create volume. Error: %+v \n", err) 1224 t.Fatal(err) 1225 } 1226 createTaskResult, err := GetTaskResult(ctx, createTaskInfo) 1227 if err != nil { 1228 t.Errorf("Failed to create volume. Error: %+v \n", err) 1229 t.Fatal(err) 1230 } 1231 if createTaskResult == nil { 1232 t.Fatalf("Empty create task results") 1233 t.FailNow() 1234 } 1235 createVolumeOperationRes := createTaskResult.GetCnsVolumeOperationResult() 1236 var volumeID string 1237 if createVolumeOperationRes.Fault != nil { 1238 t.Logf("Failed to create volume: fault=%+v", createVolumeOperationRes.Fault) 1239 fault, ok := createVolumeOperationRes.Fault.Fault.(cnstypes.CnsAlreadyRegisteredFault) 1240 if !ok { 1241 t.Fatalf("Fault is not CnsAlreadyRegisteredFault") 1242 } else { 1243 t.Logf("Fault is CnsAlreadyRegisteredFault. backingDiskURLPath: %s is already registered", backingDiskURLPath) 1244 volumeID = fault.VolumeId.Id 1245 } 1246 } else { 1247 volumeID = createVolumeOperationRes.VolumeId.Id 1248 t.Logf("Volume created sucessfully with backingDiskURLPath: %s. volumeId: %s", backingDiskURLPath, volumeID) 1249 1250 // Test re creating volume using BACKING_DISK_URL_PATH 1251 var reCreateCnsVolumeCreateSpecList []cnstypes.CnsVolumeCreateSpec 1252 reCreateCnsVolumeCreateSpec := cnstypes.CnsVolumeCreateSpec{ 1253 Name: "pvc-901e87eb-c2bd-11e9-806f-005056a0c9a0", 1254 VolumeType: string(cnstypes.CnsVolumeTypeBlock), 1255 Metadata: cnstypes.CnsVolumeMetadata{ 1256 ContainerCluster: containerCluster, 1257 }, 1258 BackingObjectDetails: &cnstypes.CnsBlockBackingDetails{ 1259 BackingDiskUrlPath: backingDiskURLPath, 1260 }, 1261 } 1262 1263 reCreateCnsVolumeCreateSpecList = append(reCreateCnsVolumeCreateSpecList, reCreateCnsVolumeCreateSpec) 1264 t.Logf("Creating volume using the spec: %+v", pretty.Sprint(reCreateCnsVolumeCreateSpec)) 1265 recreateTask, err := cnsClient.CreateVolume(ctx, reCreateCnsVolumeCreateSpecList) 1266 if err != nil { 1267 t.Errorf("Failed to create volume. Error: %+v \n", err) 1268 t.Fatal(err) 1269 } 1270 reCreateTaskInfo, err := GetTaskInfo(ctx, recreateTask) 1271 if err != nil { 1272 t.Errorf("Failed to create volume. Error: %+v \n", err) 1273 t.Fatal(err) 1274 } 1275 reCreateTaskResult, err := GetTaskResult(ctx, reCreateTaskInfo) 1276 if err != nil { 1277 t.Errorf("Failed to create volume. Error: %+v \n", err) 1278 t.Fatal(err) 1279 } 1280 if reCreateTaskResult == nil { 1281 t.Fatalf("Empty create task results") 1282 t.FailNow() 1283 } 1284 reCreateVolumeOperationRes := reCreateTaskResult.GetCnsVolumeOperationResult() 1285 t.Logf("reCreateVolumeOperationRes.: %+v", pretty.Sprint(reCreateVolumeOperationRes)) 1286 if reCreateVolumeOperationRes.Fault != nil { 1287 t.Logf("Failed to create volume: fault=%+v", reCreateVolumeOperationRes.Fault) 1288 _, ok := reCreateVolumeOperationRes.Fault.Fault.(cnstypes.CnsAlreadyRegisteredFault) 1289 if !ok { 1290 t.Fatalf("Fault is not CnsAlreadyRegisteredFault") 1291 } else { 1292 t.Logf("Fault is CnsAlreadyRegisteredFault. backingDiskURLPath: %q is already registered", backingDiskURLPath) 1293 } 1294 } 1295 } 1296 1297 // Test QueryVolume API 1298 var queryFilter cnstypes.CnsQueryFilter 1299 var volumeIDList []cnstypes.CnsVolumeId 1300 volumeIDList = append(volumeIDList, cnstypes.CnsVolumeId{Id: volumeID}) 1301 queryFilter.VolumeIds = volumeIDList 1302 t.Logf("Calling QueryVolume using queryFilter: %+v", pretty.Sprint(queryFilter)) 1303 queryResult, err := cnsClient.QueryVolume(ctx, queryFilter) 1304 if err != nil { 1305 t.Errorf("Failed to query volume. Error: %+v \n", err) 1306 t.Fatal(err) 1307 } 1308 t.Logf("Successfully Queried Volumes. queryResult: %+v", pretty.Sprint(queryResult)) 1309 1310 t.Logf("Deleting CNS volume created above using BACKING_DISK_URL_PATH: %s with volume: %+v", backingDiskURLPath, volumeIDList) 1311 deleteTask, err = cnsClient.DeleteVolume(ctx, volumeIDList, true) 1312 if err != nil { 1313 t.Errorf("Failed to delete volume. Error: %+v \n", err) 1314 t.Fatal(err) 1315 } 1316 deleteTaskInfo, err = GetTaskInfo(ctx, deleteTask) 1317 if err != nil { 1318 t.Errorf("Failed to delete volume. Error: %+v \n", err) 1319 t.Fatal(err) 1320 } 1321 deleteTaskResult, err = GetTaskResult(ctx, deleteTaskInfo) 1322 if err != nil { 1323 t.Errorf("Failed to delete volume. Error: %+v \n", err) 1324 t.Fatal(err) 1325 } 1326 if deleteTaskResult == nil { 1327 t.Fatalf("Empty delete task results") 1328 t.FailNow() 1329 } 1330 deleteVolumeOperationRes = deleteTaskResult.GetCnsVolumeOperationResult() 1331 if deleteVolumeOperationRes.Fault != nil { 1332 t.Fatalf("Failed to delete volume: fault=%+v", deleteVolumeOperationRes.Fault) 1333 } 1334 t.Logf("volume:%q deleted sucessfully", volumeID) 1335 } 1336 1337 // Test CnsReconfigVolumePolicy API 1338 if spbmPolicyId4Reconfig != "" { 1339 var cnsVolumeCreateSpecList []cnstypes.CnsVolumeCreateSpec 1340 cnsVolumeCreateSpec := cnstypes.CnsVolumeCreateSpec{ 1341 Name: "pvc-901e87eb-c2bd-11e9-806f-005056a0c9a0-1", 1342 VolumeType: string(cnstypes.CnsVolumeTypeBlock), 1343 Datastores: dsList, 1344 Metadata: cnstypes.CnsVolumeMetadata{ 1345 ContainerCluster: containerCluster, 1346 }, 1347 BackingObjectDetails: &cnstypes.CnsBlockBackingDetails{ 1348 CnsBackingObjectDetails: cnstypes.CnsBackingObjectDetails{ 1349 CapacityInMb: 5120, 1350 }, 1351 }, 1352 } 1353 cnsVolumeCreateSpecList = append(cnsVolumeCreateSpecList, cnsVolumeCreateSpec) 1354 t.Logf("Creating volume using the spec: %+v", pretty.Sprint(cnsVolumeCreateSpecList)) 1355 createTask, err = cnsClient.CreateVolume(ctx, cnsVolumeCreateSpecList) 1356 if err != nil { 1357 t.Errorf("Failed to create volume. Error: %+v \n", err) 1358 t.Fatal(err) 1359 } 1360 createTaskInfo, err = GetTaskInfo(ctx, createTask) 1361 if err != nil { 1362 t.Errorf("Failed to create volume. Error: %+v \n", err) 1363 t.Fatal(err) 1364 } 1365 createTaskResult, err = GetTaskResult(ctx, createTaskInfo) 1366 if err != nil { 1367 t.Errorf("Failed to create volume. Error: %+v \n", err) 1368 t.Fatal(err) 1369 } 1370 if createTaskResult == nil { 1371 t.Fatalf("Empty create task results") 1372 t.FailNow() 1373 } 1374 createVolumeOperationRes = createTaskResult.GetCnsVolumeOperationResult() 1375 if createVolumeOperationRes.Fault != nil { 1376 t.Fatalf("Failed to create volume: fault=%+v", createVolumeOperationRes.Fault) 1377 } 1378 volumeId = createVolumeOperationRes.VolumeId.Id 1379 volumeCreateResult = (createTaskResult).(*cnstypes.CnsVolumeCreateResult) 1380 t.Logf("volumeCreateResult %+v", volumeCreateResult) 1381 t.Logf("Volume created sucessfully. volumeId: %s", volumeId) 1382 1383 t.Logf("Calling reconfigpolicy on volume %v with policy %+v \n", volumeId, spbmPolicyId4Reconfig) 1384 reconfigSpecs := []cnstypes.CnsVolumePolicyReconfigSpec{ 1385 { 1386 VolumeId: createVolumeOperationRes.VolumeId, 1387 Profile: []vim25types.BaseVirtualMachineProfileSpec{ 1388 &vim25types.VirtualMachineDefinedProfileSpec{ 1389 ProfileId: spbmPolicyId4Reconfig, 1390 }, 1391 }, 1392 }, 1393 } 1394 reconfigTask, err := cnsClient.ReconfigVolumePolicy(ctx, reconfigSpecs) 1395 if err != nil { 1396 t.Errorf("Failed to reconfig policy %v on volume %v. Error: %+v \n", spbmPolicyId4Reconfig, volumeId, err) 1397 t.Fatal(err) 1398 } 1399 reconfigTaskInfo, err := GetTaskInfo(ctx, reconfigTask) 1400 if err != nil { 1401 t.Errorf("Failed to reconfig volume. Error: %+v \n", err) 1402 t.Fatal(err) 1403 } 1404 reconfigTaskResult, err := GetTaskResult(ctx, reconfigTaskInfo) 1405 if err != nil { 1406 t.Errorf("Failed to reconfig volume. Error: %+v \n", err) 1407 t.Fatal(err) 1408 } 1409 if reconfigTaskResult == nil { 1410 t.Fatalf("Empty reconfig task results") 1411 t.FailNow() 1412 } 1413 reconfigVolumeOperationRes := reconfigTaskResult.GetCnsVolumeOperationResult() 1414 if reconfigVolumeOperationRes.Fault != nil { 1415 t.Fatalf("Failed to reconfig volume %v with policy %v: fault=%+v", 1416 volumeId, spbmPolicyId4Reconfig, reconfigVolumeOperationRes.Fault) 1417 } 1418 t.Logf("reconfigpolicy on volume %v with policy %+v successful\n", volumeId, spbmPolicyId4Reconfig) 1419 } 1420 1421 // Test CnsSyncDatastore API 1422 t.Logf("Calling syncDatastore on %v ...\n", dsUrl) 1423 syncDatastoreTask, err := cnsClient.SyncDatastore(ctx, dsUrl, false) 1424 if err != nil { 1425 t.Errorf("Failed to sync datastore %v. Error: %+v \n", dsUrl, err) 1426 t.Fatal(err) 1427 } 1428 syncDatastoreTaskInfo, err := GetTaskInfo(ctx, syncDatastoreTask) 1429 if err != nil { 1430 t.Errorf("Failed to get sync datastore taskInfo. Error: %+v \n", err) 1431 t.Fatal(err) 1432 } 1433 if syncDatastoreTaskInfo.State != vim25types.TaskInfoStateSuccess { 1434 t.Errorf("Failed to sync datastore. Error: %+v \n", syncDatastoreTaskInfo.Error) 1435 t.Fatalf("%+v", syncDatastoreTaskInfo.Error) 1436 } 1437 t.Logf("syncDatastore on %v successful\n", dsUrl) 1438 1439 t.Logf("Calling syncDatastore on %v with fullsync...\n", dsUrl) 1440 syncDatastoreTask, err = cnsClient.SyncDatastore(ctx, dsUrl, true) 1441 if err != nil { 1442 t.Errorf("Failed to sync datastore %v with full sync. Error: %+v \n", dsUrl, err) 1443 t.Fatal(err) 1444 } 1445 syncDatastoreTaskInfo, err = GetTaskInfo(ctx, syncDatastoreTask) 1446 if err != nil { 1447 t.Errorf("Failed to get sync datastore taskInfo with full sync. Error: %+v \n", err) 1448 t.Fatal(err) 1449 } 1450 if syncDatastoreTaskInfo.State != vim25types.TaskInfoStateSuccess { 1451 t.Errorf("Failed to sync datastore with full sync. Error: %+v \n", syncDatastoreTaskInfo.Error) 1452 t.Fatalf("%+v", syncDatastoreTaskInfo.Error) 1453 } 1454 t.Logf("syncDatastore on %v with full sync successful\n", dsUrl) 1455 } 1456 1457 // isvSphereVersion70U3orAbove checks if specified version is 7.0 Update 3 or higher 1458 // The method takes aboutInfo{} as input which contains details about 1459 // VC version, build number and so on. 1460 // If the version is 7.0 Update 3 or higher, the method returns true, else returns false 1461 // along with appropriate errors during failure cases 1462 func isvSphereVersion70U3orAbove(ctx context.Context, aboutInfo vim25types.AboutInfo) bool { 1463 items := strings.Split(aboutInfo.Version, ".") 1464 version := strings.Join(items[:], "") 1465 // Convert version string to string, Ex: "7.0.3" becomes 703, "7.0.3.1" becomes 703 1466 if len(version) >= 3 { 1467 vSphereVersionInt, err := strconv.Atoi(version[0:3]) 1468 if err != nil { 1469 return false 1470 } 1471 // Check if the current vSphere version is 7.0.3 or higher 1472 if vSphereVersionInt >= VSphere70u3VersionInt { 1473 return true 1474 } 1475 } 1476 // For all other versions 1477 return false 1478 } 1479 1480 // isvSphereVersion80U3orAbove checks if specified version is 8.0 Update 3 or higher 1481 // The method takes aboutInfo{} as input which contains details about 1482 // VC version, build number and so on. 1483 // If the version is 8.0 Update 3 or higher, the method returns true, else returns false 1484 // along with appropriate errors during failure cases 1485 func isvSphereVersion80U3orAbove(ctx context.Context, aboutInfo vim25types.AboutInfo) bool { 1486 items := strings.Split(aboutInfo.Version, ".") 1487 version := strings.Join(items[:], "") 1488 // Convert version string to string, Ex: "8.0.3" becomes 803, "8.0.3.1" becomes 703 1489 if len(version) >= 3 { 1490 vSphereVersionInt, err := strconv.Atoi(version[0:3]) 1491 if err != nil { 1492 return false 1493 } 1494 // Check if the current vSphere version is 8.0.3 or higher 1495 if vSphereVersionInt >= VSphere80u3VersionInt { 1496 return true 1497 } 1498 } 1499 // For all other versions 1500 return false 1501 }