github.com/openshift/installer@v1.4.17/pkg/destroy/vsphere/vsphere.go (about) 1 package vsphere 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 "time" 8 9 "github.com/pkg/errors" 10 "github.com/sirupsen/logrus" 11 "github.com/vmware/govmomi/vim25/mo" 12 utilerrors "k8s.io/apimachinery/pkg/util/errors" 13 "k8s.io/apimachinery/pkg/util/wait" 14 15 "github.com/openshift/installer/pkg/destroy/providers" 16 installertypes "github.com/openshift/installer/pkg/types" 17 ) 18 19 // ClusterUninstaller holds the various options for the cluster we want to delete. 20 type ClusterUninstaller struct { 21 ClusterID string 22 InfraID string 23 terraformPlatform string 24 25 Logger logrus.FieldLogger 26 clients []API 27 } 28 29 // New returns an VSphere destroyer from ClusterMetadata. 30 func New(logger logrus.FieldLogger, metadata *installertypes.ClusterMetadata) (providers.Destroyer, error) { 31 var clients []API 32 33 // We have two ways of processing metadata. Older metadata has only 1 vcenter but configured at root level. New 34 // way is for all vcenter data to be part of the vcenters array. 35 if len(metadata.VSphere.VCenters) > 0 { 36 for _, vsphere := range metadata.VSphere.VCenters { 37 client, err := NewClient(vsphere.VCenter, vsphere.Username, vsphere.Password) 38 if err != nil { 39 return nil, err 40 } 41 clients = append(clients, client) 42 } 43 } else { 44 client, err := NewClient(metadata.VSphere.VCenter, metadata.VSphere.Username, metadata.VSphere.Password) 45 if err != nil { 46 return nil, err 47 } 48 clients = append(clients, client) 49 } 50 return newWithClient(logger, metadata, clients), nil 51 } 52 53 func newWithClient(logger logrus.FieldLogger, metadata *installertypes.ClusterMetadata, clients []API) *ClusterUninstaller { 54 return &ClusterUninstaller{ 55 ClusterID: metadata.ClusterID, 56 InfraID: metadata.InfraID, 57 terraformPlatform: metadata.VSphere.TerraformPlatform, 58 59 Logger: logger, 60 clients: clients, 61 } 62 } 63 64 func (o *ClusterUninstaller) deleteFolder(ctx context.Context) error { 65 ctx, cancel := context.WithTimeout(ctx, defaultTimeout) 66 defer cancel() 67 68 o.Logger.Debug("Delete Folder") 69 70 for _, client := range o.clients { 71 folderMoList, err := client.ListFolders(ctx, o.InfraID) 72 if err != nil { 73 return err 74 } 75 76 if len(folderMoList) == 0 { 77 o.Logger.Debug("All folders deleted") 78 return nil 79 } 80 81 // If there are no children in the folder, go ahead and remove it 82 83 for _, f := range folderMoList { 84 folderLogger := o.Logger.WithField("Folder", f.Name) 85 if numChildren := len(f.ChildEntity); numChildren > 0 { 86 entities := make([]string, 0, numChildren) 87 for _, child := range f.ChildEntity { 88 entities = append(entities, fmt.Sprintf("%s:%s", child.Type, child.Value)) 89 } 90 folderLogger.Errorf("Folder should be empty but contains %d objects: %s. The installer will retry removing \"virtualmachine\" objects, but any other type will need to be removed manually before the deprovision can proceed", numChildren, strings.Join(entities, ", ")) 91 return errors.Errorf("Expected Folder %s to be empty", f.Name) 92 } 93 err = client.DeleteFolder(ctx, f) 94 if err != nil { 95 folderLogger.Debug(err) 96 return err 97 } 98 folderLogger.Info("Destroyed") 99 } 100 } 101 102 return nil 103 } 104 105 func (o *ClusterUninstaller) deleteStoragePolicy(ctx context.Context) error { 106 ctx, cancel := context.WithTimeout(ctx, time.Minute*30) 107 defer cancel() 108 109 policyName := fmt.Sprintf("openshift-storage-policy-%s", o.InfraID) 110 policyLogger := o.Logger.WithField("StoragePolicy", policyName) 111 policyLogger.Debug("Delete") 112 for _, client := range o.clients { 113 err := client.DeleteStoragePolicy(ctx, policyName) 114 if err != nil { 115 policyLogger.Debug(err) 116 return err 117 } 118 policyLogger.Info("Destroyed") 119 } 120 121 return nil 122 } 123 124 func (o *ClusterUninstaller) deleteTag(ctx context.Context) error { 125 ctx, cancel := context.WithTimeout(ctx, time.Minute*30) 126 defer cancel() 127 128 tagLogger := o.Logger.WithField("Tag", o.InfraID) 129 tagLogger.Debug("Delete") 130 for _, client := range o.clients { 131 err := client.DeleteTag(ctx, o.InfraID) 132 if err != nil { 133 tagLogger.Debug(err) 134 return err 135 } 136 tagLogger.Info("Deleted") 137 } 138 139 return nil 140 } 141 142 func (o *ClusterUninstaller) deleteTagCategory(ctx context.Context) error { 143 ctx, cancel := context.WithTimeout(ctx, defaultTimeout) 144 defer cancel() 145 146 categoryID := "openshift-" + o.InfraID 147 tcLogger := o.Logger.WithField("TagCategory", categoryID) 148 tcLogger.Debug("Delete") 149 for _, client := range o.clients { 150 err := client.DeleteTagCategory(ctx, categoryID) 151 if err != nil { 152 tcLogger.Errorln(err) 153 return err 154 } 155 tcLogger.Info("Deleted") 156 } 157 158 return nil 159 } 160 161 func (o *ClusterUninstaller) stopVirtualMachine(ctx context.Context, vmMO mo.VirtualMachine, client API) error { 162 virtualMachineLogger := o.Logger.WithField("VirtualMachine", vmMO.Name) 163 err := client.StopVirtualMachine(ctx, vmMO) 164 if err != nil { 165 virtualMachineLogger.Debug(err) 166 return err 167 } 168 virtualMachineLogger.Debug("Powered off") 169 170 return nil 171 } 172 173 func (o *ClusterUninstaller) stopVirtualMachines(ctx context.Context) error { 174 ctx, cancel := context.WithTimeout(ctx, time.Minute*30) 175 defer cancel() 176 177 o.Logger.Debug("Power Off Virtual Machines") 178 var errs []error 179 for _, client := range o.clients { 180 found, err := client.ListVirtualMachines(ctx, o.InfraID) 181 if err != nil { 182 o.Logger.Debug(err) 183 return err 184 } 185 186 for _, vmMO := range found { 187 if !isPoweredOff(vmMO) { 188 if err := o.stopVirtualMachine(ctx, vmMO, client); err != nil { 189 errs = append(errs, err) 190 } 191 } 192 } 193 } 194 195 return utilerrors.NewAggregate(errs) 196 } 197 198 func (o *ClusterUninstaller) deleteVirtualMachine(ctx context.Context, vmMO mo.VirtualMachine, client API) error { 199 virtualMachineLogger := o.Logger.WithField("VirtualMachine", vmMO.Name) 200 err := client.DeleteVirtualMachine(ctx, vmMO) 201 if err != nil { 202 virtualMachineLogger.Debug(err) 203 return err 204 } 205 virtualMachineLogger.Info("Destroyed") 206 207 return nil 208 } 209 210 func (o *ClusterUninstaller) deleteVirtualMachines(ctx context.Context) error { 211 ctx, cancel := context.WithTimeout(ctx, time.Minute*30) 212 defer cancel() 213 214 o.Logger.Debug("Delete Virtual Machines") 215 var errs []error 216 for _, client := range o.clients { 217 found, err := client.ListVirtualMachines(ctx, o.InfraID) 218 if err != nil { 219 o.Logger.Debug(err) 220 return err 221 } 222 223 for _, vmMO := range found { 224 if err := o.deleteVirtualMachine(ctx, vmMO, client); err != nil { 225 errs = append(errs, err) 226 } 227 } 228 } 229 230 return utilerrors.NewAggregate(errs) 231 } 232 233 func (o *ClusterUninstaller) destroyCluster(ctx context.Context) (bool, error) { 234 stagedFuncs := [][]struct { 235 name string 236 execute func(context.Context) error 237 }{{ 238 {name: "Stop virtual machines", execute: o.stopVirtualMachines}, 239 }, { 240 {name: "Virtual Machines", execute: o.deleteVirtualMachines}, 241 }, { 242 {name: "Folder", execute: o.deleteFolder}, 243 }, { 244 {name: "Storage Policy", execute: o.deleteStoragePolicy}, 245 {name: "Tag", execute: o.deleteTag}, 246 {name: "Tag Category", execute: o.deleteTagCategory}, 247 }} 248 249 stageFailed := false 250 for _, stage := range stagedFuncs { 251 if stageFailed { 252 break 253 } 254 for _, f := range stage { 255 err := f.execute(ctx) 256 if err != nil { 257 o.Logger.Debugf("%s: %v", f.name, err) 258 stageFailed = true 259 } 260 } 261 } 262 263 return !stageFailed, nil 264 } 265 266 // Run is the entrypoint to start the uninstall process. 267 func (o *ClusterUninstaller) Run() (*installertypes.ClusterQuota, error) { 268 for _, client := range o.clients { 269 defer client.Logout() 270 } 271 272 err := wait.PollUntilContextCancel( 273 context.Background(), 274 time.Second*10, 275 true, 276 o.destroyCluster, 277 ) 278 if err != nil { 279 return nil, errors.Wrap(err, "failed to destroy cluster") 280 } 281 282 return nil, nil 283 }