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 }