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

     1  package powervs
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math"
     7  	gohttp "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 cloudSubnetTypeName = "cloudSubnet"
    17  
    18  // listCloudSubnets lists subnets in the VPC cloud.
    19  func (o *ClusterUninstaller) listCloudSubnets() (cloudResources, error) {
    20  	o.Logger.Debugf("Listing virtual Cloud Subnets")
    21  
    22  	ctx, cancel := o.contextWithTimeout()
    23  	defer cancel()
    24  
    25  	select {
    26  	case <-ctx.Done():
    27  		o.Logger.Debugf("listCloudSubnets: case <-ctx.Done()")
    28  		return nil, o.Context.Err() // we're cancelled, abort
    29  	default:
    30  	}
    31  
    32  	options := o.vpcSvc.NewListSubnetsOptions()
    33  	subnets, detailedResponse, err := o.vpcSvc.ListSubnets(options)
    34  
    35  	if err != nil {
    36  		return nil, fmt.Errorf("failed to list subnets and the response is: %s: %w", detailedResponse, err)
    37  	}
    38  
    39  	var foundOne = false
    40  
    41  	result := []cloudResource{}
    42  	for _, subnet := range subnets.Subnets {
    43  		if strings.Contains(*subnet.Name, o.InfraID) {
    44  			foundOne = true
    45  			o.Logger.Debugf("listCloudSubnets: FOUND: %s, %s", *subnet.ID, *subnet.Name)
    46  			result = append(result, cloudResource{
    47  				key:      *subnet.ID,
    48  				name:     *subnet.Name,
    49  				status:   "",
    50  				typeName: cloudSubnetTypeName,
    51  				id:       *subnet.ID,
    52  			})
    53  		}
    54  	}
    55  	if !foundOne {
    56  		o.Logger.Debugf("listCloudSubnets: NO matching subnet against: %s", o.InfraID)
    57  		for _, subnet := range subnets.Subnets {
    58  			o.Logger.Debugf("listCloudSubnets: subnet: %s", *subnet.Name)
    59  		}
    60  	}
    61  
    62  	return cloudResources{}.insert(result...), nil
    63  }
    64  
    65  func (o *ClusterUninstaller) deleteCloudSubnet(item cloudResource) error {
    66  	var getOptions *vpcv1.GetSubnetOptions
    67  	var response *core.DetailedResponse
    68  	var err error
    69  
    70  	ctx, cancel := o.contextWithTimeout()
    71  	defer cancel()
    72  
    73  	select {
    74  	case <-ctx.Done():
    75  		o.Logger.Debugf("deleteCloudSubnet: case <-ctx.Done()")
    76  		return o.Context.Err() // we're cancelled, abort
    77  	default:
    78  	}
    79  
    80  	getOptions = o.vpcSvc.NewGetSubnetOptions(item.id)
    81  	_, response, err = o.vpcSvc.GetSubnet(getOptions)
    82  
    83  	if err != nil && response != nil && response.StatusCode == gohttp.StatusNotFound {
    84  		// The resource is gone
    85  		o.deletePendingItems(item.typeName, []cloudResource{item})
    86  		o.Logger.Infof("Deleted Subnet %q", item.name)
    87  		return nil
    88  	}
    89  	if err != nil && response != nil && response.StatusCode == gohttp.StatusInternalServerError {
    90  		o.Logger.Infof("deleteCloudSubnet: internal server error")
    91  		return nil
    92  	}
    93  
    94  	deleteOptions := o.vpcSvc.NewDeleteSubnetOptions(item.id)
    95  	_, err = o.vpcSvc.DeleteSubnetWithContext(ctx, deleteOptions)
    96  	if err != nil {
    97  		return fmt.Errorf("failed to delete subnet %s: %w", item.name, err)
    98  	}
    99  
   100  	o.Logger.Infof("Deleted Subnet %q", item.name)
   101  	o.deletePendingItems(item.typeName, []cloudResource{item})
   102  
   103  	return nil
   104  }
   105  
   106  // destroyCloudSubnets removes all subnet resources that have a name prefixed
   107  // with the cluster's infra ID.
   108  func (o *ClusterUninstaller) destroyCloudSubnets() error {
   109  	firstPassList, err := o.listCloudSubnets()
   110  	if err != nil {
   111  		return err
   112  	}
   113  
   114  	if len(firstPassList.list()) == 0 {
   115  		return nil
   116  	}
   117  
   118  	items := o.insertPendingItems(cloudSubnetTypeName, firstPassList.list())
   119  
   120  	ctx, cancel := o.contextWithTimeout()
   121  	defer cancel()
   122  
   123  	for _, item := range items {
   124  		select {
   125  		case <-ctx.Done():
   126  			o.Logger.Debugf("destroyCloudSubnets: case <-ctx.Done()")
   127  			return o.Context.Err() // we're cancelled, abort
   128  		default:
   129  		}
   130  
   131  		backoff := wait.Backoff{
   132  			Duration: 15 * time.Second,
   133  			Factor:   1.1,
   134  			Cap:      leftInContext(ctx),
   135  			Steps:    math.MaxInt32}
   136  		err = wait.ExponentialBackoffWithContext(ctx, backoff, func(context.Context) (bool, error) {
   137  			err2 := o.deleteCloudSubnet(item)
   138  			if err2 == nil {
   139  				return true, err2
   140  			}
   141  			o.errorTracker.suppressWarning(item.key, err2, o.Logger)
   142  			return false, err2
   143  		})
   144  		if err != nil {
   145  			o.Logger.Fatal("destroyCloudSubnets: ExponentialBackoffWithContext (destroy) returns ", err)
   146  		}
   147  	}
   148  
   149  	if items = o.getPendingItems(cloudSubnetTypeName); len(items) > 0 {
   150  		for _, item := range items {
   151  			o.Logger.Debugf("destroyCloudSubnets: found %s in pending items", item.name)
   152  		}
   153  		return fmt.Errorf("destroyCloudSubnets: %d undeleted items pending", len(items))
   154  	}
   155  
   156  	backoff := wait.Backoff{
   157  		Duration: 15 * time.Second,
   158  		Factor:   1.1,
   159  		Cap:      leftInContext(ctx),
   160  		Steps:    math.MaxInt32}
   161  	err = wait.ExponentialBackoffWithContext(ctx, backoff, func(context.Context) (bool, error) {
   162  		secondPassList, err2 := o.listCloudSubnets()
   163  		if err2 != nil {
   164  			return false, err2
   165  		}
   166  		if len(secondPassList) == 0 {
   167  			// We finally don't see any remaining instances!
   168  			return true, nil
   169  		}
   170  		for _, item := range secondPassList {
   171  			o.Logger.Debugf("destroyCloudSubnets: found %s in second pass", item.name)
   172  		}
   173  		return false, nil
   174  	})
   175  	if err != nil {
   176  		o.Logger.Fatal("destroyCloudSubnets: ExponentialBackoffWithContext (list) returns ", err)
   177  	}
   178  
   179  	return nil
   180  }