web-dev-qa-db-fra.com

Puis-je forcer CloudFormation à supprimer un compartiment S3 non vide?

Existe-t-il un moyen de forcer CloudFormation à supprimer un compartiment S3 non vide?

18
Jamie Czuy

Vous pouvez créer une fonction lambda pour nettoyer votre compartiment et appeler votre lambda à partir de votre pile CloudFormation à l'aide de CustomResource.

Ci-dessous un exemple de lambda nettoyant votre seau:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import json
import boto3
from botocore.vendored import requests


def lambda_handler(event, context):
    try:
        bucket = event['ResourceProperties']['BucketName']

        if event['RequestType'] == 'Delete':
            s3 = boto3.resource('s3')
            bucket = s3.Bucket(bucket)
            for obj in bucket.objects.filter():
                s3.Object(bucket.name, obj.key).delete()

        sendResponseCfn(event, context, "SUCCESS")
    except Exception as e:
        print(e)
        sendResponseCfn(event, context, "FAILED")


def sendResponseCfn(event, context, responseStatus):
    response_body = {'Status': responseStatus,
                     'Reason': 'Log stream name: ' + context.log_stream_name,
                     'PhysicalResourceId': context.log_stream_name,
                     'StackId': event['StackId'],
                     'RequestId': event['RequestId'],
                     'LogicalResourceId': event['LogicalResourceId'],
                     'Data': json.loads("{}")}

    requests.put(event['ResponseURL'], data=json.dumps(response_body))

Après avoir créé le lambda ci-dessus, il suffit de placer le CustomResource dans votre pile CloudFormation:

 ---
 AWSTemplateFormatVersion: '2010-09-09'

 Resources:

   myBucketResource:
     Type: AWS::S3::Bucket
     Properties:
       BucketName: my-test-bucket-cleaning-on-delete
     DependsOn: cleanupBucketOnDelete

   cleanupBucketOnDelete:
     Type: Custom::cleanupbucket
     Properties:
       ServiceToken: arn:aws:lambda:eu-west-1:123456789012:function:clean-bucket-lambda
       BucketName: my-test-bucket-cleaning-on-delete

N'oubliez pas d'attacher à votre lambda un rôle autorisé à supprimer des objets de votre compartiment.

De plus, gardez à l'esprit que vous pouvez créer une fonction lambda qui accepte la ligne de commande CLI à l'aide de la fonction lambda cli2cloudformation. Vous pouvez télécharger et installer à partir de ici . En utilisant cela, il vous suffit de créer un CustomResource comme ci-dessous:

"removeBucket": {
        "Type": "Custom::cli2cloudformation",
        "Properties": {
          "ServiceToken": "arn:aws:lambda:eu-west-1:123456789000:function:custom-lambda-name",
          "CliCommandDelete": "aws s3 rb s3://bucket-name --force",
        }
}
21

Je pense que votre DependsOn se trouve dans une mauvaise ressource. Au moins, cela ne fonctionnait pas correctement car, sur la pile deletion (via la console), la suppression du compartiment était forcée, ce qui échouait, puis la suppression de la ressource personnalisée , ce qui déclenche le lambda pour vider le seau. Cela videra le compartiment mais la suppression de la pile échouera car il a tenté de supprimer le compartiment avant qu'il ne soit vide. Nous souhaitons commencer par supprimer les ressources personnalisées, puis tenter de supprimer un compartiment après la suppression de la ressource personnalisée. Je l'ai donc fait comme ceci et cela fonctionne pour moi:

myBucketResource:
  Type: AWS::S3::Bucket
  Properties:
    BucketName: my-test-bucket-cleaning-on-delete

cleanupBucketOnDelete:
  Type: Custom::cleanupbucket
  Properties:
    ServiceToken: arn:aws:lambda:eu-west-1:123456789012:function:clean-bucket-lambda
    BucketName: my-test-bucket-cleaning-on-delete
  DependsOn: myBucketResource

Ainsi, vous vous assurez que la suppression du compartiment ne vient pas en premier car il existe une autre ressource qui en dépend, la ressource dépendante est donc supprimée en premier (ce qui déclenche le lambda pour vider le compartiment), puis le compartiment est supprimé. c'est utile.

1
OkayWhatever

Bien

que dis-tu de ça:

import boto3

s3 = boto3.client('s3')
res = boto3.resource('s3')

buckets = s3.list_buckets()

try:
    for bk in buckets['Buckets']:
            bucket = res.Bucket(bk['Name'])
            bucket.objects.all().delete()
            bucket.delete()

except Exception as e:
    print e
0
VFagundes

Vous devriez vider le seau:

$ aws s3 rm s3://bucket-name --recursive

Puis supprimez le seau

$ aws cloudformation delete-stack --stack-name mys3stack
0
Klykoo