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 management 16 17import ( 18 "context" 19 "io/ioutil" 20 "net/url" 21 "os" 22 "path" 23 "testing" 24 25 log "github.com/sirupsen/logrus" 26 27 "github.com/vmware/govmomi/object" 28 "github.com/vmware/govmomi/simulator" 29 "github.com/vmware/govmomi/vim25/types" 30 "github.com/vmware/vic/lib/config" 31 "github.com/vmware/vic/lib/install/data" 32 "github.com/vmware/vic/lib/install/validate" 33 "github.com/vmware/vic/pkg/errors" 34 "github.com/vmware/vic/pkg/trace" 35 "github.com/vmware/vic/pkg/vsphere/session" 36) 37 38func TestDelete(t *testing.T) { 39 log.SetLevel(log.DebugLevel) 40 trace.Logger.Level = log.DebugLevel 41 ctx := context.Background() 42 op := trace.NewOperation(ctx, "TestDelete") 43 44 for i, model := range []*simulator.Model{simulator.ESX(), simulator.VPX()} { 45 t.Logf("%d", i) 46 defer model.Remove() 47 err := model.Create() 48 if err != nil { 49 t.Fatal(err) 50 } 51 52 s := model.Service.NewServer() 53 defer s.Close() 54 55 s.URL.User = url.UserPassword("user", "pass") 56 s.URL.Path = "" 57 t.Logf("server URL: %s", s.URL) 58 59 var input *data.Data 60 if i == 0 { 61 input = getESXData(s.URL) 62 } else { 63 input = getVPXData(s.URL) 64 } 65 if err != nil { 66 t.Fatal(err) 67 } 68 installSettings := &data.InstallerData{} 69 cpu := int64(1) 70 memory := int64(1024) 71 installSettings.ApplianceSize.CPU.Limit = &cpu 72 installSettings.ApplianceSize.Memory.Limit = &memory 73 installSettings.ResourcePoolPath = path.Join(input.ComputeResourcePath, input.DisplayName) 74 75 validator, err := validate.NewValidator(ctx, input) 76 if err != nil { 77 t.Errorf("Failed to validator: %s", err) 78 } 79 80 conf, err := validator.Validate(ctx, input, false) 81 if err != nil { 82 log.Errorf("Failed to validate conf: %s", err) 83 validator.ListIssues(op) 84 } 85 86 testCreateNetwork(op, validator.Session(), conf, t) 87 createAppliance(ctx, validator.Session(), conf, installSettings, false, t) 88 89 testNewVCHFromCompute(op, input.ComputeResourcePath, input.DisplayName, validator, t) 90 // testUpgrade(input.ComputeResourcePath, input.DisplayName, validator, installSettings, t) TODO: does not implement: CreateSnapshot_Task 91 testDeleteVCH(op, validator, conf, t) 92 93 testDeleteDatastoreFiles(op, validator, t) 94 } 95} 96 97func testUpgrade(op trace.Operation, computePath string, name string, v *validate.Validator, settings *data.InstallerData, t *testing.T) { 98 // TODO: add tests for rollback after snapshot func is added in vcsim 99 d := &Dispatcher{ 100 session: v.Session(), 101 op: op, 102 isVC: v.Session().IsVC(), 103 force: false, 104 } 105 vch, err := d.NewVCHFromComputePath(computePath, name, v) 106 if err != nil { 107 t.Errorf("Failed to get VCH: %s", err) 108 return 109 } 110 t.Logf("Got VCH %s, path %s", vch, path.Dir(vch.InventoryPath)) 111 conf, err := d.GetVCHConfig(vch) 112 if err != nil { 113 114 t.Errorf("Failed to get vch configuration: %s", err) 115 } 116 if err := d.Configure(conf, settings, true); err != nil { 117 t.Errorf("Failed to upgrade: %s", err) 118 } 119} 120 121func createAppliance(ctx context.Context, sess *session.Session, conf *config.VirtualContainerHostConfigSpec, vConf *data.InstallerData, hasErr bool, t *testing.T) { 122 var err error 123 124 d := &Dispatcher{ 125 session: sess, 126 op: trace.FromContext(ctx, "createAppliance"), 127 isVC: sess.IsVC(), 128 force: false, 129 } 130 131 err = d.createPool(conf, vConf) 132 if err != nil { 133 t.Fatal(err) 134 } 135 136 err = d.createAppliance(conf, vConf) 137 if err != nil { 138 t.Fatal(err) 139 } 140} 141 142func testNewVCHFromCompute(op trace.Operation, computePath string, name string, v *validate.Validator, t *testing.T) { 143 d := &Dispatcher{ 144 session: v.Session(), 145 op: op, 146 isVC: v.Session().IsVC(), 147 force: false, 148 } 149 vch, err := d.NewVCHFromComputePath(computePath, name, v) 150 if err != nil { 151 t.Errorf("Failed to get VCH: %s", err) 152 return 153 } 154 155 if d.session.Cluster == nil { 156 t.Errorf("Failed to set cluster: %s", err) 157 return 158 } 159 160 t.Logf("Got VCH %s, path %s", vch, path.Dir(vch.InventoryPath)) 161} 162 163func testDeleteVCH(op trace.Operation, v *validate.Validator, conf *config.VirtualContainerHostConfigSpec, t *testing.T) { 164 d := &Dispatcher{ 165 session: v.Session(), 166 op: op, 167 isVC: v.Session().IsVC(), 168 force: false, 169 } 170 // failed to get vm FolderName, that will eventually cause panic in simulator to delete empty datastore file 171 if err := d.DeleteVCH(conf, nil, nil); err != nil { 172 t.Errorf("Failed to get VCH: %s", err) 173 return 174 } 175 t.Logf("Successfully deleted VCH") 176 // check images directory is removed 177 dsPath := "[LocalDS_0] VIC" 178 _, err := d.lsFolder(v.Session().Datastore, dsPath) 179 if err != nil { 180 if !types.IsFileNotFound(err) { 181 t.Errorf("Failed to browse folder %s: %s", dsPath, errors.ErrorStack(err)) 182 } 183 t.Logf("Images Folder is not found") 184 } 185 186 // check appliance vm is deleted 187 vm, err := d.findApplianceByID(conf) 188 if vm != nil { 189 t.Errorf("Should not found vm %s", vm.Reference()) 190 } 191 if err != nil { 192 t.Errorf("Unexpected error to get appliance VM: %s", err) 193 } 194 195 // Verify that the VCH folder (if created on VC) is deleted after VCH delete. 196 folderPath := path.Join(d.session.VMFolder.InventoryPath, conf.Name) 197 vchFolder, err := d.session.Finder.Folder(d.op, folderPath) 198 if vchFolder != nil || err == nil { 199 t.Errorf("Should not have found VCH folder %q after VCH delete", folderPath) 200 } 201 202 // delete VM does not clean up resource pool after VM is removed, so resource pool could not be removed 203} 204 205func testDeleteDatastoreFiles(op trace.Operation, v *validate.Validator, t *testing.T) { 206 d := &Dispatcher{ 207 session: v.Session(), 208 op: op, 209 isVC: v.Session().IsVC(), 210 force: false, 211 } 212 213 ds := v.Session().Datastore 214 m := object.NewFileManager(ds.Client()) 215 err := m.MakeDirectory(op, ds.Path("Test/folder/data"), v.Session().Datacenter, true) 216 if err != nil { 217 t.Errorf("Failed to create datastore dir: %s", err) 218 return 219 } 220 err = m.MakeDirectory(op, ds.Path("Test/folder/metadata"), v.Session().Datacenter, true) 221 if err != nil { 222 t.Errorf("Failed to create datastore dir: %s", err) 223 return 224 } 225 err = m.MakeDirectory(op, ds.Path("Test/folder/file"), v.Session().Datacenter, true) 226 if err != nil { 227 t.Errorf("Failed to create datastore dir: %s", err) 228 return 229 } 230 231 isVSAN := d.isVSAN(ds) 232 t.Logf("datastore is vsan: %t", isVSAN) 233 234 if err = createDatastoreFiles(d, ds, t); err != nil { 235 t.Errorf("Failed to upload file: %s", err) 236 return 237 } 238 239 fm := ds.NewFileManager(d.session.Datacenter, true) 240 if err = d.deleteFilesIteratively(fm, ds, ds.Path("Test")); err != nil { 241 t.Errorf("Failed to delete recursively: %s", err) 242 } 243 244 err = m.MakeDirectory(op, ds.Path("Test/folder/data"), v.Session().Datacenter, true) 245 if err != nil { 246 t.Errorf("Failed to create datastore dir: %s", err) 247 return 248 } 249 250 if err = createDatastoreFiles(d, ds, t); err != nil { 251 t.Errorf("Failed to upload file: %s", err) 252 return 253 } 254 255 if _, err = d.deleteDatastoreFiles(ds, "Test", true); err != nil { 256 t.Errorf("Failed to delete recursively: %s", err) 257 } 258} 259 260func createDatastoreFiles(d *Dispatcher, ds *object.Datastore, t *testing.T) error { 261 tmpfile, err := ioutil.TempFile("", "tempDatastoreFile.vmdk") 262 if err != nil { 263 t.Errorf("Failed to create file: %s", err) 264 return err 265 } 266 267 defer os.Remove(tmpfile.Name()) // clean up 268 269 if err = ds.UploadFile(d.op, tmpfile.Name(), "Test/folder/data/temp.vmdk", nil); err != nil { 270 t.Errorf("Failed to upload file %q: %s", "Test/folder/data/temp.vmdk", err) 271 return err 272 } 273 if err = ds.UploadFile(d.op, tmpfile.Name(), "Test/folder/tempMetadata", nil); err != nil { 274 t.Errorf("Failed to upload file %q: %s", "Test/folder/tempMetadata", err) 275 return err 276 } 277 return nil 278} 279