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  }