1// Copyright 2016-2018 VMware, Inc. All Rights Reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package vsphere 16 17import ( 18 "context" 19 "fmt" 20 "sync" 21 "testing" 22 23 "github.com/stretchr/testify/assert" 24 25 "github.com/vmware/govmomi/object" 26 "github.com/vmware/vic/lib/portlayer/storage/volume" 27 "github.com/vmware/vic/lib/portlayer/storage/volume/cache" 28 "github.com/vmware/vic/pkg/trace" 29 "github.com/vmware/vic/pkg/vsphere/datastore" 30 "github.com/vmware/vic/pkg/vsphere/datastore/test" 31 "github.com/vmware/vic/pkg/vsphere/tasks" 32) 33 34func TestVolumeCreateListAndRestart(t *testing.T) { 35 client := test.Session(context.TODO(), t) 36 if client == nil { 37 return 38 } 39 40 op := trace.NewOperation(context.Background(), "test") 41 42 // Root our datastore 43 testStorePath := datastore.TestName("voltest") 44 ds, err := datastore.NewHelper(op, client, client.Datastore, testStorePath) 45 if !assert.NoError(t, err) || !assert.NotNil(t, ds) { 46 return 47 } 48 49 // Create the backing store on vsphere 50 DetachAll = false 51 vsVolumeStore, err := NewVolumeStore(op, "testStoreName", client, ds) 52 if !assert.NoError(t, err) || !assert.NotNil(t, vsVolumeStore) { 53 return 54 } 55 56 // Clean up the mess 57 defer func() { 58 fm := object.NewFileManager(client.Vim25()) 59 tasks.WaitForResult(context.TODO(), func(ctx context.Context) (tasks.Task, error) { 60 return fm.DeleteDatastoreFile(ctx, client.Datastore.Path(testStorePath), client.Datacenter) 61 }) 62 }() 63 64 // Create the cache 65 firstCache := cache.NewVolumeLookupCache(op) 66 if !assert.NotNil(t, firstCache) { 67 return 68 } 69 70 // add the vs to the cache and assert the url matches 71 storeURL, err := firstCache.AddStore(op, "testStoreName", vsVolumeStore) 72 if !assert.NoError(t, err) || !assert.Equal(t, vsVolumeStore.SelfLink, storeURL) { 73 return 74 } 75 76 // test we can list it 77 m, err := firstCache.VolumeStoresList(op) 78 if !assert.NoError(t, err) || !assert.Len(t, m, 1) || !assert.Equal(t, m[0], "testStoreName") { 79 return 80 } 81 82 // Create the volumes (in parallel) 83 numVols := 5 84 wg := &sync.WaitGroup{} 85 wg.Add(numVols) 86 volumes := make(map[string]*volume.Volume) 87 for i := 0; i < numVols; i++ { 88 go func(idx int) { 89 defer wg.Done() 90 ID := fmt.Sprintf("testvolume-%d", idx) 91 92 // add some metadata if i is even 93 var info map[string][]byte 94 95 if idx%2 == 0 { 96 info = make(map[string][]byte) 97 info[ID] = []byte(ID) 98 } 99 100 outVol, err := firstCache.VolumeCreate(op, ID, storeURL, 10240, info) 101 if !assert.NoError(t, err) || !assert.NotNil(t, outVol) { 102 return 103 } 104 105 volumes[ID] = outVol 106 }(i) 107 } 108 109 wg.Wait() 110 111 // list using the datastore (skipping the cache) 112 outVols, err := vsVolumeStore.VolumesList(op) 113 if !assert.NoError(t, err) || !assert.NotNil(t, outVols) || !assert.Equal(t, numVols, len(outVols)) { 114 return 115 } 116 117 for _, outVol := range outVols { 118 if !assert.Equal(t, volumes[outVol.ID], outVol) { 119 return 120 } 121 } 122 123 // Test restart 124 125 // Create a new vs and cache to the same datastore (simulating restart) and compare 126 secondVStore, err := NewVolumeStore(op, "testStoreName", client, ds) 127 if !assert.NoError(t, err) || !assert.NotNil(t, vsVolumeStore) { 128 return 129 } 130 131 secondCache := cache.NewVolumeLookupCache(op) 132 if !assert.NotNil(t, secondCache) { 133 return 134 } 135 136 _, err = secondCache.AddStore(op, "testStore", secondVStore) 137 if !assert.NoError(t, err) { 138 return 139 } 140 141 secondOutVols, err := secondCache.VolumesList(op) 142 if !assert.NoError(t, err) || !assert.NotNil(t, secondOutVols) || !assert.Equal(t, numVols, len(secondOutVols)) { 143 return 144 } 145 146 for _, outVol := range secondOutVols { 147 // XXX we could compare the Volumes, but the paths are different the 148 // second time around on vsan since the vsan UUID is not included. 149 if !assert.NotEmpty(t, volumes[outVol.ID].Device.DiskPath()) { 150 return 151 } 152 } 153} 154