github.com/openshift/installer@v1.4.17/pkg/destroy/powervs/cloud-instance.go (about)

     1  package powervs
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/IBM/go-sdk-core/v5/core"
    11  	"github.com/IBM/vpc-go-sdk/vpcv1"
    12  	"k8s.io/apimachinery/pkg/util/wait"
    13  )
    14  
    15  const (
    16  	cloudInstanceTypeName = "cloudInstance"
    17  )
    18  
    19  // listCloudInstances lists instances in the cloud server.
    20  func (o *ClusterUninstaller) listCloudInstances() (cloudResources, error) {
    21  	o.Logger.Debugf("Listing virtual Cloud service instances")
    22  
    23  	ctx, cancel := o.contextWithTimeout()
    24  	defer cancel()
    25  
    26  	options := o.vpcSvc.NewListInstancesOptions()
    27  
    28  	// https://raw.githubusercontent.com/IBM/vpc-go-sdk/master/vpcv1/vpc_v1.go
    29  	resources, _, err := o.vpcSvc.ListInstancesWithContext(ctx, options)
    30  	if err != nil {
    31  		o.Logger.Warnf("Error o.vpcSvc.ListInstancesWithContext: %v", err)
    32  		return nil, err
    33  	}
    34  
    35  	var foundOne = false
    36  
    37  	result := []cloudResource{}
    38  	for _, instance := range resources.Instances {
    39  		if strings.Contains(*instance.Name, o.InfraID) {
    40  			foundOne = true
    41  			o.Logger.Debugf("listCloudInstances: FOUND: %s, %s, %s", *instance.ID, *instance.Name, *instance.Status)
    42  			result = append(result, cloudResource{
    43  				key:      *instance.ID,
    44  				name:     *instance.Name,
    45  				status:   *instance.Status,
    46  				typeName: cloudInstanceTypeName,
    47  				id:       *instance.ID,
    48  			})
    49  		}
    50  	}
    51  	if !foundOne {
    52  		o.Logger.Debugf("listCloudInstances: NO matching virtual instance against: %s", o.InfraID)
    53  		for _, instance := range resources.Instances {
    54  			o.Logger.Debugf("listCloudInstances: only found virtual instance: %s", *instance.Name)
    55  		}
    56  	}
    57  
    58  	return cloudResources{}.insert(result...), nil
    59  }
    60  
    61  // destroyCloudInstance deletes a given instance.
    62  func (o *ClusterUninstaller) destroyCloudInstance(item cloudResource) error {
    63  	var (
    64  		ctx                   context.Context
    65  		err                   error
    66  		getInstanceOptions    *vpcv1.GetInstanceOptions
    67  		deleteInstanceOptions *vpcv1.DeleteInstanceOptions
    68  		response              *core.DetailedResponse
    69  	)
    70  
    71  	ctx, cancel := o.contextWithTimeout()
    72  	defer cancel()
    73  
    74  	getInstanceOptions = o.vpcSvc.NewGetInstanceOptions(item.id)
    75  
    76  	_, _, err = o.vpcSvc.GetInstanceWithContext(ctx, getInstanceOptions)
    77  	if err != nil {
    78  		o.deletePendingItems(item.typeName, []cloudResource{item})
    79  		o.Logger.Infof("Deleted Cloud Instance %q", item.name)
    80  		return nil
    81  	}
    82  
    83  	o.Logger.Debugf("Deleting Cloud instance %q", item.name)
    84  
    85  	deleteInstanceOptions = o.vpcSvc.NewDeleteInstanceOptions(item.id)
    86  
    87  	response, err = o.vpcSvc.DeleteInstanceWithContext(ctx, deleteInstanceOptions)
    88  	if err != nil {
    89  		o.Logger.Infof("Error: o.vpcSvc.DeleteInstanceWithContext: %q %q", err, response)
    90  		return err
    91  	}
    92  
    93  	o.deletePendingItems(item.typeName, []cloudResource{item})
    94  	o.Logger.Infof("Deleted Cloud Instance %q", item.name)
    95  
    96  	return nil
    97  }
    98  
    99  // destroyCloudInstances searches for Cloud instances that have a name that starts with
   100  // the cluster's infra ID.
   101  func (o *ClusterUninstaller) destroyCloudInstances() error {
   102  	firstPassList, err := o.listCloudInstances()
   103  	if err != nil {
   104  		return err
   105  	}
   106  
   107  	if len(firstPassList.list()) == 0 {
   108  		return nil
   109  	}
   110  
   111  	items := o.insertPendingItems(cloudInstanceTypeName, firstPassList.list())
   112  	ctx, cancel := o.contextWithTimeout()
   113  	defer cancel()
   114  	for _, item := range items {
   115  		select {
   116  		case <-ctx.Done():
   117  			o.Logger.Debugf("destroyCloudInstances: case <-ctx.Done()")
   118  			return o.Context.Err() // we're cancelled, abort
   119  		default:
   120  		}
   121  
   122  		backoff := wait.Backoff{
   123  			Duration: 15 * time.Second,
   124  			Factor:   1.1,
   125  			Cap:      leftInContext(ctx),
   126  			Steps:    math.MaxInt32}
   127  		err = wait.ExponentialBackoffWithContext(ctx, backoff, func(context.Context) (bool, error) {
   128  			err2 := o.destroyCloudInstance(item)
   129  			if err2 == nil {
   130  				return true, err2
   131  			}
   132  			o.errorTracker.suppressWarning(item.key, err2, o.Logger)
   133  			return false, err2
   134  		})
   135  		if err != nil {
   136  			o.Logger.Fatal("destroyCloudInstances: ExponentialBackoffWithContext (destroy) returns ", err)
   137  		}
   138  	}
   139  
   140  	if items = o.getPendingItems(cloudInstanceTypeName); len(items) > 0 {
   141  		for _, item := range items {
   142  			o.Logger.Debugf("destroyCloudInstances: found %s in pending items", item.name)
   143  		}
   144  		return fmt.Errorf("destroyCloudInstances: %d undeleted items pending", len(items))
   145  	}
   146  
   147  	backoff := wait.Backoff{
   148  		Duration: 15 * time.Second,
   149  		Factor:   1.1,
   150  		Cap:      leftInContext(ctx),
   151  		Steps:    math.MaxInt32}
   152  	err = wait.ExponentialBackoffWithContext(ctx, backoff, func(context.Context) (bool, error) {
   153  		secondPassList, err2 := o.listCloudInstances()
   154  		if err2 != nil {
   155  			return false, err2
   156  		}
   157  		if len(secondPassList) == 0 {
   158  			// We finally don't see any remaining instances!
   159  			return true, nil
   160  		}
   161  		for _, item := range secondPassList {
   162  			o.Logger.Debugf("destroyCloudInstances: found %s in second pass", item.name)
   163  		}
   164  		return false, nil
   165  	})
   166  	if err != nil {
   167  		o.Logger.Fatal("destroyCloudInstances: ExponentialBackoffWithContext (list) returns ", err)
   168  	}
   169  
   170  	return nil
   171  }