github.com/openshift/installer@v1.4.17/pkg/destroy/powervs/publicgateway.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  	publicGatewayTypeName = "publicGateway"
    17  )
    18  
    19  // listAttachedSubnets lists subnets attached to the specified publicGateway.
    20  func (o *ClusterUninstaller) listAttachedSubnets(publicGatewayID string) (cloudResources, error) {
    21  	o.Logger.Debugf("Finding subnets attached to public gateway %s", publicGatewayID)
    22  
    23  	ctx, cancel := o.contextWithTimeout()
    24  	defer cancel()
    25  
    26  	options := o.vpcSvc.NewListSubnetsOptions()
    27  	resources, _, err := o.vpcSvc.ListSubnetsWithContext(ctx, options)
    28  	if err != nil {
    29  		return nil, fmt.Errorf("failed to list subnets: %w", err)
    30  	}
    31  
    32  	result := []cloudResource{}
    33  	for _, subnet := range resources.Subnets {
    34  		if subnet.PublicGateway != nil && *subnet.PublicGateway.ID == publicGatewayID {
    35  			result = append(result, cloudResource{
    36  				key:      *subnet.ID,
    37  				name:     *subnet.Name,
    38  				status:   *subnet.Status,
    39  				typeName: cloudSubnetTypeName,
    40  				id:       *subnet.ID,
    41  			})
    42  		}
    43  	}
    44  
    45  	return cloudResources{}.insert(result...), nil
    46  }
    47  
    48  // listPublicGateways lists publicGateways in the vpc.
    49  func (o *ClusterUninstaller) listPublicGateways() (cloudResources, error) {
    50  	var (
    51  		ctx context.Context
    52  		// https://raw.githubusercontent.com/IBM/vpc-go-sdk/master/vpcv1/vpc_v1.go
    53  		listPublicGatewaysOptions *vpcv1.ListPublicGatewaysOptions
    54  		publicGatewayCollection   *vpcv1.PublicGatewayCollection
    55  		detailedResponse          *core.DetailedResponse
    56  		err                       error
    57  		moreData                  bool  = true
    58  		foundOne                  bool  = false
    59  		perPage                   int64 = 20
    60  	)
    61  
    62  	o.Logger.Debugf("Listing publicGateways")
    63  
    64  	ctx, cancel := o.contextWithTimeout()
    65  	defer cancel()
    66  
    67  	select {
    68  	case <-ctx.Done():
    69  		o.Logger.Debugf("listPublicGateways: case <-ctx.Done()")
    70  		return nil, o.Context.Err() // we're cancelled, abort
    71  	default:
    72  	}
    73  
    74  	listPublicGatewaysOptions = o.vpcSvc.NewListPublicGatewaysOptions()
    75  
    76  	listPublicGatewaysOptions.SetLimit(perPage)
    77  
    78  	result := []cloudResource{}
    79  
    80  	for moreData {
    81  
    82  		publicGatewayCollection, detailedResponse, err = o.vpcSvc.ListPublicGatewaysWithContext(ctx, listPublicGatewaysOptions)
    83  		if err != nil {
    84  			return nil, fmt.Errorf("failed to list publicGateways and the response is: %s: %w", detailedResponse, err)
    85  		}
    86  
    87  		for _, publicGateway := range publicGatewayCollection.PublicGateways {
    88  			if strings.Contains(*publicGateway.Name, o.InfraID) {
    89  				foundOne = true
    90  				o.Logger.Debugf("listPublicGateways: FOUND: %s", *publicGateway.Name)
    91  				result = append(result, cloudResource{
    92  					key:      *publicGateway.Name,
    93  					name:     *publicGateway.Name,
    94  					status:   "",
    95  					typeName: publicGatewayTypeName,
    96  					id:       *publicGateway.ID,
    97  				})
    98  			}
    99  		}
   100  
   101  		if publicGatewayCollection.First != nil {
   102  			o.Logger.Debugf("listPublicGateways: First = %v", *publicGatewayCollection.First.Href)
   103  		}
   104  		if publicGatewayCollection.Limit != nil {
   105  			o.Logger.Debugf("listPublicGateways: Limit = %v", *publicGatewayCollection.Limit)
   106  		}
   107  		if publicGatewayCollection.Next != nil {
   108  			start, err := publicGatewayCollection.GetNextStart()
   109  			if err != nil {
   110  				o.Logger.Debugf("listPublicGateways: err = %v", err)
   111  				return nil, fmt.Errorf("listPublicGateways: failed to GetNextStart: %w", err)
   112  			}
   113  			if start != nil {
   114  				o.Logger.Debugf("listPublicGateways: start = %v", *start)
   115  				listPublicGatewaysOptions.SetStart(*start)
   116  			}
   117  		} else {
   118  			o.Logger.Debugf("listPublicGateways: Next = nil")
   119  			moreData = false
   120  		}
   121  	}
   122  	if !foundOne {
   123  		o.Logger.Debugf("listPublicGateways: NO matching publicGateway against: %s", o.InfraID)
   124  
   125  		listPublicGatewaysOptions = o.vpcSvc.NewListPublicGatewaysOptions()
   126  		listPublicGatewaysOptions.SetLimit(perPage)
   127  
   128  		for moreData {
   129  			publicGatewayCollection, detailedResponse, err = o.vpcSvc.ListPublicGatewaysWithContext(ctx, listPublicGatewaysOptions)
   130  			if err != nil {
   131  				return nil, fmt.Errorf("failed to list publicGateways and the response is: %s: %w", detailedResponse, err)
   132  			}
   133  
   134  			for _, publicGateway := range publicGatewayCollection.PublicGateways {
   135  				o.Logger.Debugf("listPublicGateways: FOUND: %s", *publicGateway.Name)
   136  			}
   137  			if publicGatewayCollection.First != nil {
   138  				o.Logger.Debugf("listPublicGateways: First = %v", *publicGatewayCollection.First.Href)
   139  			}
   140  			if publicGatewayCollection.Limit != nil {
   141  				o.Logger.Debugf("listPublicGateways: Limit = %v", *publicGatewayCollection.Limit)
   142  			}
   143  			if publicGatewayCollection.Next != nil {
   144  				start, err := publicGatewayCollection.GetNextStart()
   145  				if err != nil {
   146  					o.Logger.Debugf("listPublicGateways: err = %v", err)
   147  					return nil, fmt.Errorf("listPublicGateways: failed to GetNextStart: %w", err)
   148  				}
   149  				if start != nil {
   150  					o.Logger.Debugf("listPublicGateways: start = %v", *start)
   151  					listPublicGatewaysOptions.SetStart(*start)
   152  				}
   153  			} else {
   154  				o.Logger.Debugf("listPublicGateways: Next = nil")
   155  				moreData = false
   156  			}
   157  		}
   158  	}
   159  
   160  	return cloudResources{}.insert(result...), nil
   161  }
   162  
   163  func (o *ClusterUninstaller) deletePublicGateway(item cloudResource) error {
   164  	ctx, cancel := o.contextWithTimeout()
   165  	defer cancel()
   166  
   167  	select {
   168  	case <-ctx.Done():
   169  		o.Logger.Debugf("deletePublicGateway: case <-ctx.Done()")
   170  		return o.Context.Err() // we're cancelled, abort
   171  	default:
   172  	}
   173  
   174  	getPublicGatewayOptions := o.vpcSvc.NewGetPublicGatewayOptions(item.id)
   175  
   176  	_, _, err := o.vpcSvc.GetPublicGatewayWithContext(ctx, getPublicGatewayOptions)
   177  	if err != nil {
   178  		o.Logger.Debugf("deletePublicGateway: publicGateway %q no longer exists", item.name)
   179  		o.deletePendingItems(item.typeName, []cloudResource{item})
   180  		o.Logger.Infof("Deleted Public Gateway %q", item.name)
   181  		return nil
   182  	}
   183  
   184  	// Detach gateway from any subnets using it
   185  	subnets, err := o.listAttachedSubnets(item.id)
   186  	if err != nil {
   187  		return fmt.Errorf("failed to list subnets with gateway %s attached: %w", item.name, err)
   188  	}
   189  	for _, subnet := range subnets {
   190  		unsetSubnetPublicGatewayOptions := o.vpcSvc.NewUnsetSubnetPublicGatewayOptions(subnet.id)
   191  
   192  		_, err = o.vpcSvc.UnsetSubnetPublicGatewayWithContext(ctx, unsetSubnetPublicGatewayOptions)
   193  		if err != nil {
   194  			return fmt.Errorf("failed to detach publicGateway %s from subnet %s: %w", item.name, subnet.id, err)
   195  		}
   196  	}
   197  
   198  	deletePublicGatewayOptions := o.vpcSvc.NewDeletePublicGatewayOptions(item.id)
   199  
   200  	_, err = o.vpcSvc.DeletePublicGatewayWithContext(ctx, deletePublicGatewayOptions)
   201  	if err != nil {
   202  		return fmt.Errorf("failed to delete publicGateway %s: %w", item.name, err)
   203  	}
   204  
   205  	o.Logger.Infof("Deleted Public Gateway %q", item.name)
   206  	o.deletePendingItems(item.typeName, []cloudResource{item})
   207  
   208  	return nil
   209  }
   210  
   211  // destroyPublicGateways removes all publicGateway resources that have a name prefixed
   212  // with the cluster's infra ID.
   213  func (o *ClusterUninstaller) destroyPublicGateways() error {
   214  	firstPassList, err := o.listPublicGateways()
   215  	if err != nil {
   216  		return err
   217  	}
   218  
   219  	if len(firstPassList.list()) == 0 {
   220  		return nil
   221  	}
   222  
   223  	items := o.insertPendingItems(publicGatewayTypeName, firstPassList.list())
   224  
   225  	ctx, cancel := o.contextWithTimeout()
   226  	defer cancel()
   227  
   228  	for _, item := range items {
   229  		select {
   230  		case <-ctx.Done():
   231  			o.Logger.Debugf("destroyPublicGateways: case <-ctx.Done()")
   232  			return o.Context.Err() // we're cancelled, abort
   233  		default:
   234  		}
   235  
   236  		backoff := wait.Backoff{
   237  			Duration: 15 * time.Second,
   238  			Factor:   1.1,
   239  			Cap:      leftInContext(ctx),
   240  			Steps:    math.MaxInt32}
   241  		err = wait.ExponentialBackoffWithContext(ctx, backoff, func(context.Context) (bool, error) {
   242  			err2 := o.deletePublicGateway(item)
   243  			if err2 == nil {
   244  				return true, err2
   245  			}
   246  			o.errorTracker.suppressWarning(item.key, err2, o.Logger)
   247  			return false, err2
   248  		})
   249  		if err != nil {
   250  			o.Logger.Fatal("destroyPublicGateways: ExponentialBackoffWithContext (destroy) returns ", err)
   251  		}
   252  	}
   253  
   254  	if items = o.getPendingItems(publicGatewayTypeName); len(items) > 0 {
   255  		for _, item := range items {
   256  			o.Logger.Debugf("destroyPublicGateways: found %s in pending items", item.name)
   257  		}
   258  		return fmt.Errorf("destroyPublicGateways: %d undeleted items pending", len(items))
   259  	}
   260  
   261  	backoff := wait.Backoff{
   262  		Duration: 15 * time.Second,
   263  		Factor:   1.1,
   264  		Cap:      leftInContext(ctx),
   265  		Steps:    math.MaxInt32}
   266  	err = wait.ExponentialBackoffWithContext(ctx, backoff, func(context.Context) (bool, error) {
   267  		secondPassList, err2 := o.listPublicGateways()
   268  		if err2 != nil {
   269  			return false, err2
   270  		}
   271  		if len(secondPassList) == 0 {
   272  			// We finally don't see any remaining instances!
   273  			return true, nil
   274  		}
   275  		for _, item := range secondPassList {
   276  			o.Logger.Debugf("destroyPublicGateways: found %s in second pass", item.name)
   277  		}
   278  		return false, nil
   279  	})
   280  	if err != nil {
   281  		o.Logger.Fatal("destroyPublicGateways: ExponentialBackoffWithContext (list) returns ", err)
   282  	}
   283  
   284  	return nil
   285  }