github.com/openshift/installer@v1.4.17/pkg/destroy/vsphere/client.go (about) 1 package vsphere 2 3 import ( 4 "context" 5 "net/http" 6 "strings" 7 "time" 8 9 "github.com/pkg/errors" 10 "github.com/vmware/govmomi/object" 11 "github.com/vmware/govmomi/pbm" 12 pbmtypes "github.com/vmware/govmomi/pbm/types" 13 "github.com/vmware/govmomi/property" 14 "github.com/vmware/govmomi/vapi/rest" 15 "github.com/vmware/govmomi/vapi/tags" 16 "github.com/vmware/govmomi/vim25" 17 "github.com/vmware/govmomi/vim25/mo" 18 "github.com/vmware/govmomi/vim25/types" 19 utilerrors "k8s.io/apimachinery/pkg/util/errors" 20 21 "github.com/openshift/installer/pkg/asset/installconfig/vsphere" 22 ) 23 24 //go:generate mockgen -source=./client.go -destination=mock/vsphereclient_generated.go -package=mock 25 26 // API represents the calls made to the API. 27 type API interface { 28 Logout() 29 ListFolders(ctx context.Context, tagID string) ([]mo.Folder, error) 30 ListVirtualMachines(ctx context.Context, tagID string) ([]mo.VirtualMachine, error) 31 StopVirtualMachine(ctx context.Context, vmMO mo.VirtualMachine) error 32 DeleteFolder(ctx context.Context, f mo.Folder) error 33 DeleteVirtualMachine(ctx context.Context, vmMO mo.VirtualMachine) error 34 DeleteStoragePolicy(ctx context.Context, policyName string) error 35 DeleteTag(ctx context.Context, id string) error 36 DeleteTagCategory(ctx context.Context, id string) error 37 } 38 39 // Client makes calls to the Azure API. 40 type Client struct { 41 client *vim25.Client 42 restClient *rest.Client 43 cleanup vsphere.ClientLogout 44 } 45 46 const defaultTimeout = time.Minute * 5 47 48 // NewClient initializes a client. 49 // Logout() must be called when you are done with the client. 50 func NewClient(vCenter, username, password string) (*Client, error) { 51 vim25Client, restClient, cleanup, err := vsphere.CreateVSphereClients( 52 context.TODO(), 53 vCenter, 54 username, 55 password) 56 if err != nil { 57 return nil, err 58 } 59 60 return &Client{ 61 client: vim25Client, 62 restClient: restClient, 63 cleanup: cleanup, 64 }, nil 65 } 66 67 // Logout logs out from the clients used. 68 func (c *Client) Logout() { 69 c.cleanup() 70 } 71 72 func isNotFound(err error) bool { 73 return err != nil && strings.HasSuffix(err.Error(), http.StatusText(http.StatusNotFound)) 74 } 75 76 func (c *Client) getAttachedObjectsOnTag(ctx context.Context, tag, objType string) ([]types.ManagedObjectReference, error) { 77 ctx, cancel := context.WithTimeout(ctx, defaultTimeout) 78 defer cancel() 79 80 tagManager := tags.NewManager(c.restClient) 81 attached, err := tagManager.GetAttachedObjectsOnTags(ctx, []string{tag}) 82 if err != nil && !isNotFound(err) { 83 return nil, err 84 } 85 86 // Separate the objects attached to the tag based on type 87 var objectList []types.ManagedObjectReference 88 for _, attachedObject := range attached { 89 for _, ref := range attachedObject.ObjectIDs { 90 if ref.Reference().Type == objType { 91 objectList = append(objectList, ref.Reference()) 92 } 93 } 94 } 95 96 return objectList, nil 97 } 98 99 func (c *Client) getVirtualMachineManagedObjects(ctx context.Context, moRef []types.ManagedObjectReference) ([]mo.VirtualMachine, error) { 100 ctx, cancel := context.WithTimeout(ctx, defaultTimeout) 101 defer cancel() 102 103 var virtualMachineMoList []mo.VirtualMachine 104 if len(moRef) > 0 { 105 pc := property.DefaultCollector(c.client) 106 err := pc.Retrieve(ctx, moRef, nil, &virtualMachineMoList) 107 if err != nil { 108 return nil, err 109 } 110 } 111 return virtualMachineMoList, nil 112 } 113 114 func (c *Client) getFolderManagedObjects(ctx context.Context, moRef []types.ManagedObjectReference) ([]mo.Folder, error) { 115 ctx, cancel := context.WithTimeout(ctx, defaultTimeout) 116 defer cancel() 117 118 var folderMoList []mo.Folder 119 if len(moRef) > 0 { 120 pc := property.DefaultCollector(c.client) 121 err := pc.Retrieve(ctx, moRef, nil, &folderMoList) 122 if err != nil { 123 return nil, err 124 } 125 } 126 return folderMoList, nil 127 } 128 129 // ListFolders returns all ManagedObjects of type "Folder". 130 func (c *Client) ListFolders(ctx context.Context, tagID string) ([]mo.Folder, error) { 131 folderList, err := c.getAttachedObjectsOnTag(ctx, tagID, "Folder") 132 if err != nil { 133 return nil, err 134 } 135 136 return c.getFolderManagedObjects(ctx, folderList) 137 } 138 139 // ListVirtualMachines returns ManagedObjects of type "VirtualMachine". 140 func (c *Client) ListVirtualMachines(ctx context.Context, tagID string) ([]mo.VirtualMachine, error) { 141 virtualMachineList, err := c.getAttachedObjectsOnTag(ctx, tagID, "VirtualMachine") 142 if err != nil { 143 return nil, err 144 } 145 146 return c.getVirtualMachineManagedObjects(ctx, virtualMachineList) 147 } 148 149 func isPoweredOff(vmMO mo.VirtualMachine) bool { 150 return vmMO.Summary.Runtime.PowerState == "poweredOff" 151 } 152 153 // StopVirtualMachine stops a VM if it's not already powered off. 154 func (c *Client) StopVirtualMachine(ctx context.Context, vmMO mo.VirtualMachine) error { 155 ctx, cancel := context.WithTimeout(ctx, time.Minute*30) 156 defer cancel() 157 158 if !isPoweredOff(vmMO) { 159 vm := object.NewVirtualMachine(c.client, vmMO.Reference()) 160 task, err := vm.PowerOff(ctx) 161 if err == nil { 162 err = task.Wait(ctx) 163 } 164 return err 165 } 166 return nil 167 } 168 169 // DeleteVirtualMachine deletes a VirtualMachine. 170 func (c *Client) DeleteVirtualMachine(ctx context.Context, vmMO mo.VirtualMachine) error { 171 ctx, cancel := context.WithTimeout(ctx, time.Minute*30) 172 defer cancel() 173 174 vm := object.NewVirtualMachine(c.client, vmMO.Reference()) 175 task, err := vm.Destroy(ctx) 176 if err == nil { 177 err = task.Wait(ctx) 178 } 179 return err 180 } 181 182 // DeleteFolder deletes a Folder. 183 func (c *Client) DeleteFolder(ctx context.Context, f mo.Folder) error { 184 ctx, cancel := context.WithTimeout(ctx, defaultTimeout) 185 defer cancel() 186 187 folder := object.NewFolder(c.client, f.Reference()) 188 189 task, err := folder.Destroy(ctx) 190 if err == nil { 191 err = task.Wait(ctx) 192 } 193 return err 194 } 195 196 // DeleteStoragePolicy deletes a Storage Policy named `policyName`. 197 func (c *Client) DeleteStoragePolicy(ctx context.Context, policyName string) error { 198 ctx, cancel := context.WithTimeout(ctx, time.Minute*30) 199 defer cancel() 200 201 rtype := pbmtypes.PbmProfileResourceType{ 202 ResourceType: string(pbmtypes.PbmProfileResourceTypeEnumSTORAGE), 203 } 204 205 category := pbmtypes.PbmProfileCategoryEnumREQUIREMENT 206 207 pbmClient, err := pbm.NewClient(ctx, c.client) 208 if err != nil { 209 return err 210 } 211 212 ids, err := pbmClient.QueryProfile(ctx, rtype, string(category)) 213 if err != nil { 214 return err 215 } 216 217 profiles, err := pbmClient.RetrieveContent(ctx, ids) 218 if err != nil { 219 return err 220 } 221 222 matchingProfileIds := []pbmtypes.PbmProfileId{} 223 for _, p := range profiles { 224 if p.GetPbmProfile().Name == policyName { 225 profileID := p.GetPbmProfile().ProfileId 226 matchingProfileIds = append(matchingProfileIds, profileID) 227 } 228 } 229 if len(matchingProfileIds) > 0 { 230 _, err = pbmClient.DeleteProfile(ctx, matchingProfileIds) 231 if err != nil { 232 return err 233 } 234 } 235 return nil 236 } 237 238 // DeleteTag deletes a Tag named `id`. 239 func (c *Client) DeleteTag(ctx context.Context, id string) error { 240 ctx, cancel := context.WithTimeout(ctx, defaultTimeout) 241 defer cancel() 242 243 tagManager := tags.NewManager(c.restClient) 244 tag, err := tagManager.GetTag(ctx, id) 245 if isNotFound(err) { 246 return nil 247 } 248 if err == nil { 249 err = tagManager.DeleteTag(ctx, tag) 250 } 251 return err 252 } 253 254 // DeleteTagCategory deletes a Tag Category named `categoryName`. 255 func (c *Client) DeleteTagCategory(ctx context.Context, categoryName string) error { 256 ctx, cancel := context.WithTimeout(ctx, defaultTimeout) 257 defer cancel() 258 259 tagManager := tags.NewManager(c.restClient) 260 ids, err := tagManager.ListCategories(ctx) 261 if err != nil { 262 return err 263 } 264 265 var errs []error 266 for _, id := range ids { 267 category, err := tagManager.GetCategory(ctx, id) 268 if err != nil { 269 if !isNotFound(err) { 270 errs = append(errs, errors.Wrapf(err, "could not get category %q", id)) 271 } 272 continue 273 } 274 if category.Name == categoryName { 275 if err = tagManager.DeleteCategory(ctx, category); err != nil { 276 return err 277 } 278 return nil 279 } 280 } 281 282 return utilerrors.NewAggregate(errs) 283 }