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 }