k8s.io/kubernetes@v1.29.3/test/e2e/storage/vsphere/vsphere.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 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 vsphere 18 19 import ( 20 "context" 21 "fmt" 22 "path/filepath" 23 "strconv" 24 "strings" 25 "time" 26 27 "github.com/vmware/govmomi" 28 "github.com/vmware/govmomi/find" 29 "github.com/vmware/govmomi/object" 30 "github.com/vmware/govmomi/vim25/mo" 31 "github.com/vmware/govmomi/vim25/soap" 32 "github.com/vmware/govmomi/vim25/types" 33 "k8s.io/kubernetes/test/e2e/framework" 34 ) 35 36 const ( 37 volDir = "kubevols" 38 defaultDiskCapacityKB = 2097152 39 defaultDiskFormat = "thin" 40 defaultSCSIControllerType = "lsiLogic" 41 virtualMachineType = "VirtualMachine" 42 ) 43 44 // VSphere represents a vSphere instance where one or more kubernetes nodes are running. 45 type VSphere struct { 46 Config *Config 47 Client *govmomi.Client 48 } 49 50 // VolumeOptions specifies various options for a volume. 51 type VolumeOptions struct { 52 Name string 53 CapacityKB int 54 DiskFormat string 55 SCSIControllerType string 56 Datastore string 57 } 58 59 // GetDatacenter returns the DataCenter Object for the given datacenterPath 60 func (vs *VSphere) GetDatacenter(ctx context.Context, datacenterPath string) (*object.Datacenter, error) { 61 Connect(ctx, vs) 62 finder := find.NewFinder(vs.Client.Client, false) 63 return finder.Datacenter(ctx, datacenterPath) 64 } 65 66 // GetDatacenterFromObjectReference returns the DataCenter Object for the given datacenter reference 67 func (vs *VSphere) GetDatacenterFromObjectReference(ctx context.Context, dc object.Reference) *object.Datacenter { 68 Connect(ctx, vs) 69 return object.NewDatacenter(vs.Client.Client, dc.Reference()) 70 } 71 72 // GetAllDatacenter returns all the DataCenter Objects 73 func (vs *VSphere) GetAllDatacenter(ctx context.Context) ([]*object.Datacenter, error) { 74 Connect(ctx, vs) 75 finder := find.NewFinder(vs.Client.Client, false) 76 return finder.DatacenterList(ctx, "*") 77 } 78 79 // GetVMByUUID returns the VM object Reference from the given vmUUID 80 func (vs *VSphere) GetVMByUUID(ctx context.Context, vmUUID string, dc object.Reference) (object.Reference, error) { 81 Connect(ctx, vs) 82 datacenter := vs.GetDatacenterFromObjectReference(ctx, dc) 83 s := object.NewSearchIndex(vs.Client.Client) 84 vmUUID = strings.ToLower(strings.TrimSpace(vmUUID)) 85 return s.FindByUuid(ctx, datacenter, vmUUID, true, nil) 86 } 87 88 // GetHostFromVMReference returns host object reference of the host on which the specified VM resides 89 func (vs *VSphere) GetHostFromVMReference(ctx context.Context, vm types.ManagedObjectReference) types.ManagedObjectReference { 90 Connect(ctx, vs) 91 var vmMo mo.VirtualMachine 92 vs.Client.RetrieveOne(ctx, vm, []string{"summary.runtime.host"}, &vmMo) 93 host := *vmMo.Summary.Runtime.Host 94 return host 95 } 96 97 // GetDatastoresMountedOnHost returns the datastore references of all the datastores mounted on the specified host 98 func (vs *VSphere) GetDatastoresMountedOnHost(ctx context.Context, host types.ManagedObjectReference) []types.ManagedObjectReference { 99 Connect(ctx, vs) 100 var hostMo mo.HostSystem 101 vs.Client.RetrieveOne(ctx, host, []string{"datastore"}, &hostMo) 102 return hostMo.Datastore 103 } 104 105 // GetDatastoreRefFromName returns the datastore reference of the specified datastore 106 func (vs *VSphere) GetDatastoreRefFromName(ctx context.Context, dc object.Reference, datastoreName string) (types.ManagedObjectReference, error) { 107 Connect(ctx, vs) 108 datacenter := object.NewDatacenter(vs.Client.Client, dc.Reference()) 109 finder := find.NewFinder(vs.Client.Client, false) 110 finder.SetDatacenter(datacenter) 111 datastore, err := finder.Datastore(ctx, datastoreName) 112 return datastore.Reference(), err 113 } 114 115 // GetFolderByPath gets the Folder Object Reference from the given folder path 116 // folderPath should be the full path to folder 117 func (vs *VSphere) GetFolderByPath(ctx context.Context, dc object.Reference, folderPath string) (vmFolderMor types.ManagedObjectReference, err error) { 118 Connect(ctx, vs) 119 datacenter := object.NewDatacenter(vs.Client.Client, dc.Reference()) 120 finder := find.NewFinder(datacenter.Client(), false) 121 finder.SetDatacenter(datacenter) 122 vmFolder, err := finder.Folder(ctx, folderPath) 123 if err != nil { 124 framework.Logf("Failed to get the folder reference for %s. err: %+v", folderPath, err) 125 return vmFolderMor, err 126 } 127 return vmFolder.Reference(), nil 128 } 129 130 // CreateVolume creates a vsphere volume using given volume parameters specified in VolumeOptions. 131 // If volume is created successfully the canonical disk path is returned else error is returned. 132 func (vs *VSphere) CreateVolume(volumeOptions *VolumeOptions, dataCenterRef types.ManagedObjectReference) (string, error) { 133 ctx, cancel := context.WithCancel(context.Background()) 134 defer cancel() 135 Connect(ctx, vs) 136 datacenter := object.NewDatacenter(vs.Client.Client, dataCenterRef) 137 var ( 138 err error 139 directoryAlreadyPresent = false 140 ) 141 if datacenter == nil { 142 return "", fmt.Errorf("datacenter is nil") 143 } 144 vs.initVolumeOptions(volumeOptions) 145 finder := find.NewFinder(datacenter.Client(), false) 146 finder.SetDatacenter(datacenter) 147 ds, err := finder.Datastore(ctx, volumeOptions.Datastore) 148 if err != nil { 149 return "", fmt.Errorf("Failed while searching for datastore: %s. err: %+v", volumeOptions.Datastore, err) 150 } 151 directoryPath := filepath.Clean(ds.Path(volDir)) + "/" 152 fileManager := object.NewFileManager(ds.Client()) 153 err = fileManager.MakeDirectory(ctx, directoryPath, datacenter, false) 154 if err != nil { 155 if soap.IsSoapFault(err) { 156 soapFault := soap.ToSoapFault(err) 157 if _, ok := soapFault.VimFault().(types.FileAlreadyExists); ok { 158 directoryAlreadyPresent = true 159 framework.Logf("Directory with the path %+q is already present", directoryPath) 160 } 161 } 162 if !directoryAlreadyPresent { 163 framework.Logf("Cannot create dir %#v. err %s", directoryPath, err) 164 return "", err 165 } 166 } 167 framework.Logf("Created dir with path as %+q", directoryPath) 168 vmdkPath := directoryPath + volumeOptions.Name + ".vmdk" 169 170 // Create a virtual disk manager 171 vdm := object.NewVirtualDiskManager(ds.Client()) 172 // Create specification for new virtual disk 173 vmDiskSpec := &types.FileBackedVirtualDiskSpec{ 174 VirtualDiskSpec: types.VirtualDiskSpec{ 175 AdapterType: volumeOptions.SCSIControllerType, 176 DiskType: volumeOptions.DiskFormat, 177 }, 178 CapacityKb: int64(volumeOptions.CapacityKB), 179 } 180 // Create virtual disk 181 task, err := vdm.CreateVirtualDisk(ctx, vmdkPath, datacenter, vmDiskSpec) 182 if err != nil { 183 framework.Logf("Failed to create virtual disk: %s. err: %+v", vmdkPath, err) 184 return "", err 185 } 186 taskInfo, err := task.WaitForResult(ctx, nil) 187 if err != nil { 188 framework.Logf("Failed to complete virtual disk creation: %s. err: %+v", vmdkPath, err) 189 return "", err 190 } 191 volumePath := taskInfo.Result.(string) 192 canonicalDiskPath, err := getCanonicalVolumePath(ctx, datacenter, volumePath) 193 if err != nil { 194 return "", err 195 } 196 return canonicalDiskPath, nil 197 } 198 199 // DeleteVolume deletes the vmdk file specified in the volumePath. 200 // if an error is encountered while deleting volume, error is returned. 201 func (vs *VSphere) DeleteVolume(volumePath string, dataCenterRef types.ManagedObjectReference) error { 202 ctx, cancel := context.WithCancel(context.Background()) 203 defer cancel() 204 Connect(ctx, vs) 205 206 datacenter := object.NewDatacenter(vs.Client.Client, dataCenterRef) 207 virtualDiskManager := object.NewVirtualDiskManager(datacenter.Client()) 208 diskPath := removeStorageClusterORFolderNameFromVDiskPath(volumePath) 209 // Delete virtual disk 210 task, err := virtualDiskManager.DeleteVirtualDisk(ctx, diskPath, datacenter) 211 if err != nil { 212 framework.Logf("Failed to delete virtual disk. err: %v", err) 213 return err 214 } 215 err = task.Wait(ctx) 216 if err != nil { 217 framework.Logf("Failed to delete virtual disk. err: %v", err) 218 return err 219 } 220 return nil 221 } 222 223 // IsVMPresent checks if VM with the name specified in the vmName argument, is present in the vCenter inventory. 224 // if VM is present, function returns true else false. 225 func (vs *VSphere) IsVMPresent(vmName string, dataCenterRef types.ManagedObjectReference) (isVMPresent bool, err error) { 226 ctx, cancel := context.WithCancel(context.Background()) 227 defer cancel() 228 Connect(ctx, vs) 229 folderMor, err := vs.GetFolderByPath(ctx, dataCenterRef, vs.Config.Folder) 230 if err != nil { 231 return 232 } 233 vmFolder := object.NewFolder(vs.Client.Client, folderMor) 234 vmFoldersChildren, err := vmFolder.Children(ctx) 235 if err != nil { 236 framework.Logf("Failed to get children from Folder: %s. err: %+v", vmFolder.InventoryPath, err) 237 return 238 } 239 for _, vmFoldersChild := range vmFoldersChildren { 240 if vmFoldersChild.Reference().Type == virtualMachineType { 241 if object.NewVirtualMachine(vs.Client.Client, vmFoldersChild.Reference()).Name() == vmName { 242 return true, nil 243 } 244 } 245 } 246 return 247 } 248 249 // initVolumeOptions function sets default values for volumeOptions parameters if not set 250 func (vs *VSphere) initVolumeOptions(volumeOptions *VolumeOptions) { 251 if volumeOptions == nil { 252 volumeOptions = &VolumeOptions{} 253 } 254 if volumeOptions.Datastore == "" { 255 volumeOptions.Datastore = vs.Config.DefaultDatastore 256 } 257 if volumeOptions.CapacityKB == 0 { 258 volumeOptions.CapacityKB = defaultDiskCapacityKB 259 } 260 if volumeOptions.Name == "" { 261 volumeOptions.Name = "e2e-vmdk-" + strconv.FormatInt(time.Now().UnixNano(), 10) 262 } 263 if volumeOptions.DiskFormat == "" { 264 volumeOptions.DiskFormat = defaultDiskFormat 265 } 266 if volumeOptions.SCSIControllerType == "" { 267 volumeOptions.SCSIControllerType = defaultSCSIControllerType 268 } 269 }