github.com/openshift/installer@v1.4.17/pkg/destroy/powervs/vpc.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 vpcTypeName = "vpc"
    17  
    18  // listVPCs lists VPCs in the cloud.
    19  func (o *ClusterUninstaller) listVPCs() (cloudResources, error) {
    20  	o.Logger.Debugf("Listing VPCs")
    21  
    22  	ctx, cancel := o.contextWithTimeout()
    23  	defer cancel()
    24  
    25  	select {
    26  	case <-ctx.Done():
    27  		o.Logger.Debugf("listVPCs: case <-ctx.Done()")
    28  		return nil, o.Context.Err() // we're cancelled, abort
    29  	default:
    30  	}
    31  
    32  	options := o.vpcSvc.NewListVpcsOptions()
    33  	vpcs, _, err := o.vpcSvc.ListVpcs(options)
    34  
    35  	if err != nil {
    36  		return nil, fmt.Errorf("failed to list vps: %w", err)
    37  	}
    38  
    39  	var foundOne = false
    40  
    41  	result := []cloudResource{}
    42  	for _, vpc := range vpcs.Vpcs {
    43  		if strings.Contains(*vpc.Name, o.InfraID) {
    44  			foundOne = true
    45  			o.Logger.Debugf("listVPCs: FOUND: %s, %s", *vpc.ID, *vpc.Name)
    46  			result = append(result, cloudResource{
    47  				key:      *vpc.ID,
    48  				name:     *vpc.Name,
    49  				status:   "",
    50  				typeName: vpcTypeName,
    51  				id:       *vpc.ID,
    52  			})
    53  		}
    54  	}
    55  	if !foundOne {
    56  		o.Logger.Debugf("listVPCs: NO matching vpc against: %s", o.InfraID)
    57  		for _, vpc := range vpcs.Vpcs {
    58  			o.Logger.Debugf("listVPCs: vpc: %s", *vpc.Name)
    59  		}
    60  	}
    61  
    62  	return cloudResources{}.insert(result...), nil
    63  }
    64  
    65  func (o *ClusterUninstaller) deleteVPC(item cloudResource) error {
    66  	var getOptions *vpcv1.GetVPCOptions
    67  	var getResponse *core.DetailedResponse
    68  	var deleteResponse *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("deleteVPC: case <-ctx.Done()")
    77  		return o.Context.Err() // we're cancelled, abort
    78  	default:
    79  	}
    80  
    81  	getOptions = o.vpcSvc.NewGetVPCOptions(item.id)
    82  	_, getResponse, err = o.vpcSvc.GetVPC(getOptions)
    83  
    84  	o.Logger.Debugf("deleteVPC: getResponse = %v", getResponse)
    85  	o.Logger.Debugf("deleteVPC: err = %v", err)
    86  
    87  	// Sadly, there is no way to get the status of this VPC to check on the results of the
    88  	// delete call.
    89  
    90  	if err == nil && getResponse.StatusCode == gohttp.StatusNoContent {
    91  		return nil
    92  	}
    93  	if err != nil && getResponse != nil && getResponse.StatusCode == gohttp.StatusNotFound {
    94  		// The resource is gone
    95  		o.deletePendingItems(item.typeName, []cloudResource{item})
    96  		o.Logger.Infof("Deleted VPC %q", item.name)
    97  		return nil
    98  	}
    99  	if err != nil && getResponse != nil && getResponse.StatusCode == gohttp.StatusInternalServerError {
   100  		o.Logger.Infof("deleteVPC: internal server error")
   101  		return nil
   102  	}
   103  
   104  	deleteOptions := o.vpcSvc.NewDeleteVPCOptions(item.id)
   105  	deleteResponse, err = o.vpcSvc.DeleteVPCWithContext(ctx, deleteOptions)
   106  	o.Logger.Debugf("deleteVPC: DeleteVPCWithContext returns %+v", deleteResponse)
   107  
   108  	if err != nil {
   109  		return fmt.Errorf("failed to delete vpc %s: %w", item.name, err)
   110  	}
   111  
   112  	o.Logger.Infof("Deleted VPC %q", item.name)
   113  	o.deletePendingItems(item.typeName, []cloudResource{item})
   114  
   115  	return nil
   116  }
   117  
   118  // destroyVPCs removes all vpc resources that have a name prefixed
   119  // with the cluster's infra ID.
   120  func (o *ClusterUninstaller) destroyVPCs() error {
   121  	firstPassList, err := o.listVPCs()
   122  	if err != nil {
   123  		return err
   124  	}
   125  
   126  	if len(firstPassList.list()) == 0 {
   127  		return nil
   128  	}
   129  
   130  	items := o.insertPendingItems(vpcTypeName, firstPassList.list())
   131  
   132  	ctx, cancel := o.contextWithTimeout()
   133  	defer cancel()
   134  
   135  	for _, item := range items {
   136  		select {
   137  		case <-ctx.Done():
   138  			o.Logger.Debugf("destroyVPCs: case <-ctx.Done()")
   139  			return o.Context.Err() // we're cancelled, abort
   140  		default:
   141  		}
   142  
   143  		backoff := wait.Backoff{
   144  			Duration: 15 * time.Second,
   145  			Factor:   1.1,
   146  			Cap:      leftInContext(ctx),
   147  			Steps:    math.MaxInt32}
   148  		err = wait.ExponentialBackoffWithContext(ctx, backoff, func(context.Context) (bool, error) {
   149  			err2 := o.deleteVPC(item)
   150  			if err2 == nil {
   151  				return true, err2
   152  			}
   153  			o.errorTracker.suppressWarning(item.key, err2, o.Logger)
   154  			return false, err2
   155  		})
   156  		if err != nil {
   157  			o.Logger.Fatal("destroyVPCs: ExponentialBackoffWithContext (destroy) returns ", err)
   158  		}
   159  	}
   160  
   161  	if items = o.getPendingItems(vpcTypeName); len(items) > 0 {
   162  		for _, item := range items {
   163  			o.Logger.Debugf("destroyVPCs: found %s in pending items", item.name)
   164  		}
   165  		return fmt.Errorf("destroyVPCs: %d undeleted items pending", len(items))
   166  	}
   167  
   168  	backoff := wait.Backoff{
   169  		Duration: 15 * time.Second,
   170  		Factor:   1.1,
   171  		Cap:      leftInContext(ctx),
   172  		Steps:    math.MaxInt32}
   173  	err = wait.ExponentialBackoffWithContext(ctx, backoff, func(context.Context) (bool, error) {
   174  		secondPassList, err2 := o.listVPCs()
   175  		if err2 != nil {
   176  			return false, err2
   177  		}
   178  		if len(secondPassList) == 0 {
   179  			// We finally don't see any remaining instances!
   180  			return true, nil
   181  		}
   182  		for _, item := range secondPassList {
   183  			o.Logger.Debugf("destroyVPCs: found %s in second pass", item.name)
   184  		}
   185  		return false, nil
   186  	})
   187  	if err != nil {
   188  		o.Logger.Fatal("destroyVPCs: ExponentialBackoffWithContext (list) returns ", err)
   189  	}
   190  
   191  	return nil
   192  }