Skip to content

Commit fc9259e

Browse files
committed
OCPBUGS-35323: aws: delete ignition bucket on bootstrap destroy
Leverage the post-destroy hook to delete the S3 ignition bucket after the cluster-api system has stopped running. Because of the `BestEffortDeleteIgnition` option, we need to save its value to the provider while the cluster-api system is still running during the bootstrap destroy process. While not ideal, this solution offers the least impact to consumers of the Installer code as opposed to saving that value into the metadata.
1 parent 36320f9 commit fc9259e

File tree

1 file changed

+62
-13
lines changed
  • pkg/infrastructure/aws/clusterapi

1 file changed

+62
-13
lines changed

pkg/infrastructure/aws/clusterapi/aws.go

Lines changed: 62 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/aws/aws-sdk-go/aws/session"
1313
"github.com/aws/aws-sdk-go/service/ec2"
1414
"github.com/aws/aws-sdk-go/service/elbv2"
15+
"github.com/aws/aws-sdk-go/service/s3"
1516
"github.com/sirupsen/logrus"
1617
"k8s.io/apimachinery/pkg/util/wait"
1718
"k8s.io/utils/ptr"
@@ -30,12 +31,15 @@ var (
3031
_ clusterapi.PreProvider = (*Provider)(nil)
3132
_ clusterapi.InfraReadyProvider = (*Provider)(nil)
3233
_ clusterapi.BootstrapDestroyer = (*Provider)(nil)
34+
_ clusterapi.PostDestroyer = (*Provider)(nil)
3335

3436
errNotFound = errors.New("not found")
3537
)
3638

3739
// Provider implements AWS CAPI installation.
38-
type Provider struct{}
40+
type Provider struct {
41+
bestEffortDeleteIgnition bool
42+
}
3943

4044
// Name gives the name of the provider, AWS.
4145
func (*Provider) Name() string { return awstypes.Name }
@@ -220,25 +224,28 @@ func getHostedZoneIDForNLB(ctx context.Context, awsSession *session.Session, reg
220224

221225
// DestroyBootstrap removes aws bootstrap resources not handled
222226
// by the deletion of the bootstrap machine by the capi controllers.
223-
func (*Provider) DestroyBootstrap(ctx context.Context, in clusterapi.BootstrapDestroyInput) error {
224-
if err := removeSSHRule(ctx, in.Client, in.Metadata.InfraID); err != nil {
225-
return fmt.Errorf("failed to remove bootstrap SSH rule: %w", err)
226-
}
227-
return nil
228-
}
229-
230-
// removeSSHRule removes the SSH rule for accessing the bootstrap node
231-
// by removing the rule from the cluster spec and updating the object.
232-
func removeSSHRule(ctx context.Context, cl k8sClient.Client, infraID string) error {
227+
func (p *Provider) DestroyBootstrap(ctx context.Context, in clusterapi.BootstrapDestroyInput) error {
233228
awsCluster := &capa.AWSCluster{}
234229
key := k8sClient.ObjectKey{
235-
Name: infraID,
230+
Name: in.Metadata.InfraID,
236231
Namespace: capiutils.Namespace,
237232
}
238-
if err := cl.Get(ctx, key, awsCluster); err != nil {
233+
if err := in.Client.Get(ctx, key, awsCluster); err != nil {
239234
return fmt.Errorf("failed to get AWSCluster: %w", err)
240235
}
241236

237+
// Save this value for use in the post-destroy hook since we don't have capi running anymore by that point.
238+
p.bestEffortDeleteIgnition = ptr.Deref(awsCluster.Spec.S3Bucket.BestEffortDeleteObjects, false)
239+
240+
if err := removeSSHRule(ctx, in.Client, in.Metadata.InfraID, awsCluster); err != nil {
241+
return fmt.Errorf("failed to remove bootstrap SSH rule: %w", err)
242+
}
243+
return nil
244+
}
245+
246+
// removeSSHRule removes the SSH rule for accessing the bootstrap node
247+
// by removing the rule from the cluster spec and updating the object.
248+
func removeSSHRule(ctx context.Context, cl k8sClient.Client, infraID string, awsCluster *capa.AWSCluster) error {
242249
postBootstrapRules := []capa.IngressRule{}
243250
for _, rule := range awsCluster.Spec.NetworkSpec.AdditionalControlPlaneIngressRules {
244251
if strings.EqualFold(rule.Description, awsmanifest.BootstrapSSHDescription) {
@@ -254,6 +261,10 @@ func removeSSHRule(ctx context.Context, cl k8sClient.Client, infraID string) err
254261
}
255262
logrus.Debug("Updated AWSCluster to remove bootstrap SSH rule")
256263

264+
key := k8sClient.ObjectKey{
265+
Name: infraID,
266+
Namespace: capiutils.Namespace,
267+
}
257268
timeout := 15 * time.Minute
258269
untilTime := time.Now().Add(timeout)
259270
warnTime := time.Now().Add(5 * time.Minute)
@@ -299,3 +310,41 @@ func removeSSHRule(ctx context.Context, cl k8sClient.Client, infraID string) err
299310

300311
return nil
301312
}
313+
314+
// PostDestroy deletes the ignition bucket after capi stopped running, so it won't try to reconcile the bucket.
315+
func (p *Provider) PostDestroy(ctx context.Context, in clusterapi.PostDestroyerInput) error {
316+
region := in.Metadata.AWS.Region
317+
session, err := awsconfig.GetSessionWithOptions(
318+
awsconfig.WithRegion(region),
319+
awsconfig.WithServiceEndpoints(region, in.Metadata.AWS.ServiceEndpoints),
320+
)
321+
if err != nil {
322+
return fmt.Errorf("failed to create aws session: %w", err)
323+
}
324+
325+
bucketName := fmt.Sprintf("openshift-bootstrap-data-%s", in.Metadata.InfraID)
326+
if err := removeS3Bucket(ctx, session, bucketName); err != nil {
327+
if p.bestEffortDeleteIgnition {
328+
logrus.Warnf("failed to delete ignition bucket %s: %v", bucketName, err)
329+
return nil
330+
}
331+
return fmt.Errorf("failed to delete ignition bucket %s: %w", bucketName, err)
332+
}
333+
334+
return nil
335+
}
336+
337+
// removeS3Bucket deletes an s3 bucket given its name.
338+
func removeS3Bucket(ctx context.Context, session *session.Session, bucketName string) error {
339+
client := s3.New(session)
340+
_, err := client.DeleteBucketWithContext(ctx, &s3.DeleteBucketInput{Bucket: aws.String(bucketName)})
341+
if err != nil {
342+
var awsErr awserr.Error
343+
if errors.As(err, &awsErr) && awsErr.Code() == s3.ErrCodeNoSuchBucket {
344+
logrus.Debugf("bucket %q already deleted", bucketName)
345+
return nil
346+
}
347+
return err
348+
}
349+
return nil
350+
}

0 commit comments

Comments
 (0)