Existe-t-il un moyen de forcer CloudFormation à supprimer un compartiment S3 non vide?
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",
}
}
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.
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
Vous devriez vider le seau:
$ aws s3 rm s3://bucket-name --recursive
Puis supprimez le seau
$ aws cloudformation delete-stack --stack-name mys3stack