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

     1  package powervs
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math"
     7  	"net/http"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/IBM/go-sdk-core/v5/core"
    12  	"github.com/IBM/vpc-go-sdk/vpcv1"
    13  	"k8s.io/apimachinery/pkg/util/wait"
    14  )
    15  
    16  const loadBalancerTypeName = "load balancer"
    17  
    18  // listLoadBalancers lists load balancers in the vpc.
    19  func (o *ClusterUninstaller) listLoadBalancers() (cloudResources, error) {
    20  	o.Logger.Debugf("Listing load balancers")
    21  
    22  	ctx, cancel := o.contextWithTimeout()
    23  	defer cancel()
    24  
    25  	select {
    26  	case <-ctx.Done():
    27  		o.Logger.Debugf("listLoadBalancers: case <-ctx.Done()")
    28  		return nil, o.Context.Err() // we're cancelled, abort
    29  	default:
    30  	}
    31  
    32  	options := o.vpcSvc.NewListLoadBalancersOptions()
    33  
    34  	resources, _, err := o.vpcSvc.ListLoadBalancersWithContext(ctx, options)
    35  	if err != nil {
    36  		return nil, fmt.Errorf("failed to list load balancers: %w", err)
    37  	}
    38  
    39  	var foundOne = false
    40  
    41  	result := []cloudResource{}
    42  	for _, loadbalancer := range resources.LoadBalancers {
    43  		if strings.Contains(*loadbalancer.Name, o.InfraID) {
    44  			foundOne = true
    45  			o.Logger.Debugf("listLoadBalancers: FOUND: %s, %s, %s", *loadbalancer.ID, *loadbalancer.Name, *loadbalancer.ProvisioningStatus)
    46  			result = append(result, cloudResource{
    47  				key:      *loadbalancer.ID,
    48  				name:     *loadbalancer.Name,
    49  				status:   *loadbalancer.ProvisioningStatus,
    50  				typeName: loadBalancerTypeName,
    51  				id:       *loadbalancer.ID,
    52  			})
    53  		}
    54  	}
    55  	if !foundOne {
    56  		o.Logger.Debugf("listLoadBalancers: NO matching loadbalancers against: %s", o.InfraID)
    57  		for _, loadbalancer := range resources.LoadBalancers {
    58  			o.Logger.Debugf("listLoadBalancers: loadbalancer: %s", *loadbalancer.Name)
    59  		}
    60  	}
    61  
    62  	return cloudResources{}.insert(result...), nil
    63  }
    64  
    65  func (o *ClusterUninstaller) deleteLoadBalancer(item cloudResource) error {
    66  	var getOptions *vpcv1.GetLoadBalancerOptions
    67  	var lb *vpcv1.LoadBalancer
    68  	var response *core.DetailedResponse
    69  	var err error
    70  
    71  	ctx, cancel := o.contextWithTimeout()
    72  	defer cancel()
    73  
    74  	select {
    75  	case <-ctx.Done():
    76  		o.Logger.Debugf("deleteLoadBalancer: case <-ctx.Done()")
    77  		return o.Context.Err() // we're cancelled, abort
    78  	default:
    79  	}
    80  
    81  	getOptions = o.vpcSvc.NewGetLoadBalancerOptions(item.id)
    82  	lb, response, err = o.vpcSvc.GetLoadBalancer(getOptions)
    83  
    84  	if err == nil && response.StatusCode == http.StatusNoContent {
    85  		return nil
    86  	}
    87  	if err != nil && response != nil && response.StatusCode == http.StatusNotFound {
    88  		// The resource is gone.
    89  		o.deletePendingItems(item.typeName, []cloudResource{item})
    90  		o.Logger.Infof("Deleted Load Balancer %q", item.name)
    91  		return nil
    92  	}
    93  	if err != nil && response != nil && response.StatusCode == http.StatusInternalServerError {
    94  		o.Logger.Infof("deleteLoadBalancer: internal server error")
    95  		return nil
    96  	}
    97  	if lb == nil {
    98  		o.Logger.Debugf("deleteLoadBalancer: lb = %v", lb)
    99  		o.Logger.Debugf("deleteLoadBalancer: response = %v", response)
   100  		o.Logger.Debugf("deleteLoadBalancer: err = %v", err)
   101  		o.Logger.Debugf("Rate and unhandled code, please investigate further")
   102  		return nil
   103  	}
   104  
   105  	if *lb.ProvisioningStatus == vpcv1.LoadBalancerProvisioningStatusDeletePendingConst {
   106  		o.Logger.Debugf("Waiting for load balancer %q to delete", item.name)
   107  		return nil
   108  	}
   109  
   110  	deleteOptions := o.vpcSvc.NewDeleteLoadBalancerOptions(item.id)
   111  
   112  	_, err = o.vpcSvc.DeleteLoadBalancerWithContext(ctx, deleteOptions)
   113  	if err != nil {
   114  		return fmt.Errorf("failed to delete load balancer %s: %w", item.name, err)
   115  	}
   116  
   117  	o.Logger.Infof("Deleted Load Balancer %q", item.name)
   118  	o.deletePendingItems(item.typeName, []cloudResource{item})
   119  
   120  	return nil
   121  }
   122  
   123  // destroyLoadBalancers removes all load balancer resources that have a name prefixed
   124  // with the cluster's infra ID.
   125  func (o *ClusterUninstaller) destroyLoadBalancers() error {
   126  	firstPassList, err := o.listLoadBalancers()
   127  	if err != nil {
   128  		return err
   129  	}
   130  
   131  	if len(firstPassList.list()) == 0 {
   132  		return nil
   133  	}
   134  
   135  	items := o.insertPendingItems(loadBalancerTypeName, firstPassList.list())
   136  
   137  	ctx, cancel := o.contextWithTimeout()
   138  	defer cancel()
   139  
   140  	for _, item := range items {
   141  		select {
   142  		case <-ctx.Done():
   143  			o.Logger.Debugf("destroyLoadBalancers: case <-ctx.Done()")
   144  			return o.Context.Err() // we're cancelled, abort
   145  		default:
   146  		}
   147  
   148  		backoff := wait.Backoff{
   149  			Duration: 15 * time.Second,
   150  			Factor:   1.1,
   151  			Cap:      leftInContext(ctx),
   152  			Steps:    math.MaxInt32}
   153  		err = wait.ExponentialBackoffWithContext(ctx, backoff, func(context.Context) (bool, error) {
   154  			err2 := o.deleteLoadBalancer(item)
   155  			if err2 == nil {
   156  				return true, err2
   157  			}
   158  			o.errorTracker.suppressWarning(item.key, err2, o.Logger)
   159  			return false, err2
   160  		})
   161  		if err != nil {
   162  			o.Logger.Fatal("destroyLoadBalancers: ExponentialBackoffWithContext (destroy) returns ", err)
   163  		}
   164  	}
   165  
   166  	if items = o.getPendingItems(loadBalancerTypeName); len(items) > 0 {
   167  		for _, item := range items {
   168  			o.Logger.Debugf("destroyLoadBalancers: found %s in pending items", item.name)
   169  		}
   170  		return fmt.Errorf("destroyLoadBalancers: %d undeleted items pending", len(items))
   171  	}
   172  
   173  	backoff := wait.Backoff{
   174  		Duration: 15 * time.Second,
   175  		Factor:   1.1,
   176  		Cap:      leftInContext(ctx),
   177  		Steps:    math.MaxInt32}
   178  	err = wait.ExponentialBackoffWithContext(ctx, backoff, func(context.Context) (bool, error) {
   179  		secondPassList, err2 := o.listLoadBalancers()
   180  		if err2 != nil {
   181  			return false, err2
   182  		}
   183  		if len(secondPassList) == 0 {
   184  			// We finally don't see any remaining instances!
   185  			return true, nil
   186  		}
   187  		for _, item := range secondPassList {
   188  			o.Logger.Debugf("destroyLoadBalancers: found %s in second pass", item.name)
   189  		}
   190  		return false, nil
   191  	})
   192  	if err != nil {
   193  		o.Logger.Fatal("destroyLoadBalancers: ExponentialBackoffWithContext (list) returns ", err)
   194  	}
   195  
   196  	return nil
   197  }