github.com/openshift/installer@v1.4.17/pkg/destroy/powervs/cloud-sshkey.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  	cloudSSHKeyTypeName = "cloudSshKey"
    17  )
    18  
    19  // listCloudSSHKeys lists images in the vpc.
    20  func (o *ClusterUninstaller) listCloudSSHKeys() (cloudResources, error) {
    21  	o.Logger.Debugf("Listing Cloud SSHKeys")
    22  
    23  	// https://raw.githubusercontent.com/IBM/vpc-go-sdk/master/vpcv1/vpc_v1.go
    24  	var (
    25  		ctx              context.Context
    26  		foundOne         bool  = false
    27  		perPage          int64 = 20
    28  		moreData         bool  = true
    29  		listKeysOptions  *vpcv1.ListKeysOptions
    30  		sshKeyCollection *vpcv1.KeyCollection
    31  		detailedResponse *core.DetailedResponse
    32  		err              error
    33  		sshKey           vpcv1.Key
    34  	)
    35  
    36  	ctx, cancel := o.contextWithTimeout()
    37  	defer cancel()
    38  
    39  	select {
    40  	case <-ctx.Done():
    41  		o.Logger.Debugf("listCloudSSHKeys: case <-ctx.Done()")
    42  		return nil, o.Context.Err() // we're cancelled, abort
    43  	default:
    44  	}
    45  
    46  	listKeysOptions = o.vpcSvc.NewListKeysOptions()
    47  	listKeysOptions.SetLimit(perPage)
    48  
    49  	result := []cloudResource{}
    50  
    51  	for moreData {
    52  		sshKeyCollection, detailedResponse, err = o.vpcSvc.ListKeysWithContext(ctx, listKeysOptions)
    53  		if err != nil {
    54  			return nil, fmt.Errorf("failed to list Cloud ssh keys: %w and the response is: %s", err, detailedResponse)
    55  		}
    56  
    57  		for _, sshKey = range sshKeyCollection.Keys {
    58  			if strings.Contains(*sshKey.Name, o.InfraID) {
    59  				foundOne = true
    60  				o.Logger.Debugf("listCloudSSHKeys: FOUND: %v", *sshKey.Name)
    61  				result = append(result, cloudResource{
    62  					key:      *sshKey.Name,
    63  					name:     *sshKey.Name,
    64  					status:   "",
    65  					typeName: cloudSSHKeyTypeName,
    66  					id:       *sshKey.ID,
    67  				})
    68  			}
    69  		}
    70  
    71  		if sshKeyCollection.First != nil {
    72  			o.Logger.Debugf("listCloudSSHKeys: First = %v", *sshKeyCollection.First.Href)
    73  		}
    74  		if sshKeyCollection.Limit != nil {
    75  			o.Logger.Debugf("listCloudSSHKeys: Limit = %v", *sshKeyCollection.Limit)
    76  		}
    77  		if sshKeyCollection.Next != nil {
    78  			start, err := sshKeyCollection.GetNextStart()
    79  			if err != nil {
    80  				o.Logger.Debugf("listCloudSSHKeys: err = %v", err)
    81  				return nil, fmt.Errorf("listCloudSSHKeys: failed to GetNextStart: %w", err)
    82  			}
    83  			if start != nil {
    84  				o.Logger.Debugf("listCloudSSHKeys: start = %v", *start)
    85  				listKeysOptions.SetStart(*start)
    86  			}
    87  		} else {
    88  			o.Logger.Debugf("listCloudSSHKeys: Next = nil")
    89  			moreData = false
    90  		}
    91  	}
    92  	if !foundOne {
    93  		o.Logger.Debugf("listCloudSSHKeys: NO matching sshKey against: %s", o.InfraID)
    94  
    95  		listKeysOptions = o.vpcSvc.NewListKeysOptions()
    96  		listKeysOptions.SetLimit(perPage)
    97  		moreData = true
    98  
    99  		for moreData {
   100  			sshKeyCollection, detailedResponse, err = o.vpcSvc.ListKeysWithContext(ctx, listKeysOptions)
   101  			if err != nil {
   102  				return nil, fmt.Errorf("failed to list Cloud ssh keys: %w and the response is: %s", err, detailedResponse)
   103  			}
   104  			for _, sshKey = range sshKeyCollection.Keys {
   105  				o.Logger.Debugf("listCloudSSHKeys: FOUND: %v", *sshKey.Name)
   106  			}
   107  			if sshKeyCollection.First != nil {
   108  				o.Logger.Debugf("listCloudSSHKeys: First = %v", *sshKeyCollection.First.Href)
   109  			}
   110  			if sshKeyCollection.Limit != nil {
   111  				o.Logger.Debugf("listCloudSSHKeys: Limit = %v", *sshKeyCollection.Limit)
   112  			}
   113  			if sshKeyCollection.Next != nil {
   114  				start, err := sshKeyCollection.GetNextStart()
   115  				if err != nil {
   116  					o.Logger.Debugf("listCloudSSHKeys: err = %v", err)
   117  					return nil, fmt.Errorf("listCloudSSHKeys: failed to GetNextStart: %w", err)
   118  				}
   119  				if start != nil {
   120  					o.Logger.Debugf("listCloudSSHKeys: start = %v", *start)
   121  					listKeysOptions.SetStart(*start)
   122  				}
   123  			} else {
   124  				o.Logger.Debugf("listCloudSSHKeys: Next = nil")
   125  				moreData = false
   126  			}
   127  		}
   128  	}
   129  
   130  	return cloudResources{}.insert(result...), nil
   131  }
   132  
   133  // deleteCloudSSHKey deletes a given ssh key.
   134  func (o *ClusterUninstaller) deleteCloudSSHKey(item cloudResource) error {
   135  	var (
   136  		ctx              context.Context
   137  		getKeyOptions    *vpcv1.GetKeyOptions
   138  		deleteKeyOptions *vpcv1.DeleteKeyOptions
   139  		err              error
   140  	)
   141  
   142  	ctx, cancel := o.contextWithTimeout()
   143  	defer cancel()
   144  
   145  	select {
   146  	case <-ctx.Done():
   147  		o.Logger.Debugf("deleteCloudSSHKey: case <-ctx.Done()")
   148  		return o.Context.Err() // we're cancelled, abort
   149  	default:
   150  	}
   151  
   152  	getKeyOptions = o.vpcSvc.NewGetKeyOptions(item.id)
   153  
   154  	_, _, err = o.vpcSvc.GetKey(getKeyOptions)
   155  	if err != nil {
   156  		o.deletePendingItems(item.typeName, []cloudResource{item})
   157  		o.Logger.Infof("Deleted Cloud SSHKey %q", item.name)
   158  		return nil
   159  	}
   160  
   161  	deleteKeyOptions = o.vpcSvc.NewDeleteKeyOptions(item.id)
   162  
   163  	_, err = o.vpcSvc.DeleteKeyWithContext(ctx, deleteKeyOptions)
   164  	if err != nil {
   165  		return fmt.Errorf("failed to delete sshKey %s: %w", item.name, err)
   166  	}
   167  
   168  	o.Logger.Infof("Deleted Cloud SSHKey %q", item.name)
   169  	o.deletePendingItems(item.typeName, []cloudResource{item})
   170  
   171  	return nil
   172  }
   173  
   174  // destroyCloudSSHKeys removes all key resources that have a name prefixed
   175  // with the cluster's infra ID.
   176  func (o *ClusterUninstaller) destroyCloudSSHKeys() error {
   177  	firstPassList, err := o.listCloudSSHKeys()
   178  	if err != nil {
   179  		return err
   180  	}
   181  
   182  	if len(firstPassList.list()) == 0 {
   183  		return nil
   184  	}
   185  
   186  	items := o.insertPendingItems(cloudSSHKeyTypeName, firstPassList.list())
   187  
   188  	ctx, cancel := o.contextWithTimeout()
   189  	defer cancel()
   190  
   191  	for _, item := range items {
   192  		select {
   193  		case <-ctx.Done():
   194  			o.Logger.Debugf("destroyCloudSSHKeys: case <-ctx.Done()")
   195  			return o.Context.Err() // we're cancelled, abort
   196  		default:
   197  		}
   198  
   199  		backoff := wait.Backoff{
   200  			Duration: 15 * time.Second,
   201  			Factor:   1.1,
   202  			Cap:      leftInContext(ctx),
   203  			Steps:    math.MaxInt32}
   204  		err = wait.ExponentialBackoffWithContext(ctx, backoff, func(context.Context) (bool, error) {
   205  			err2 := o.deleteCloudSSHKey(item)
   206  			if err2 == nil {
   207  				return true, err2
   208  			}
   209  			o.errorTracker.suppressWarning(item.key, err2, o.Logger)
   210  			return false, err2
   211  		})
   212  		if err != nil {
   213  			o.Logger.Fatal("destroyCloudSSHKeys: ExponentialBackoffWithContext (destroy) returns ", err)
   214  		}
   215  	}
   216  
   217  	if items = o.getPendingItems(cloudSSHKeyTypeName); len(items) > 0 {
   218  		for _, item := range items {
   219  			o.Logger.Debugf("destroyCloudSSHKeys: found %s in pending items", item.name)
   220  		}
   221  		return fmt.Errorf("destroyCloudSSHKeys: %d undeleted items pending", len(items))
   222  	}
   223  
   224  	backoff := wait.Backoff{
   225  		Duration: 15 * time.Second,
   226  		Factor:   1.1,
   227  		Cap:      leftInContext(ctx),
   228  		Steps:    math.MaxInt32}
   229  	err = wait.ExponentialBackoffWithContext(ctx, backoff, func(context.Context) (bool, error) {
   230  		secondPassList, err2 := o.listCloudSSHKeys()
   231  		if err2 != nil {
   232  			return false, err2
   233  		}
   234  		if len(secondPassList) == 0 {
   235  			// We finally don't see any remaining instances!
   236  			return true, nil
   237  		}
   238  		for _, item := range secondPassList {
   239  			o.Logger.Debugf("destroyCloudSSHKeys: found %s in second pass", item.name)
   240  		}
   241  		return false, nil
   242  	})
   243  	if err != nil {
   244  		o.Logger.Fatal("destroyCloudSSHKeys: ExponentialBackoffWithContext (list) returns ", err)
   245  	}
   246  
   247  	return nil
   248  }