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

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