web-dev-qa-db-fra.com

Comment supprimer un compartiment versionné dans AWS S3 à l'aide de la CLI?

J'ai essayé les deux s3cmd:

$ s3cmd -r -f -v del s3://my-versioned-bucket/

Et l'AWS CLI:

$ aws s3 rm s3://my-versioned-bucket/ --recursive

Mais ces deux commandes ajoutent simplement des marqueurs DELETE à S3. La commande de suppression d'un compartiment ne fonctionne pas non plus (à partir de l'AWS CLI):

$ aws s3 rb s3://my-versioned-bucket/ --force
Cleaning up. Please wait...
Completed 1 part(s) with ... file(s) remaining
remove_bucket failed: s3://my-versioned-bucket/ A client error (BucketNotEmpty) occurred when calling the DeleteBucket operation: The bucket you tried to delete is not empty. You must delete all versions in the bucket.

OK, comment? Il n'y a aucune information dans leur documentation pour cela. S3Cmd dit que c'est un outil de ligne de commande S3 "complet", mais il fait aucune référence aux versions autre que le sien. Existe-t-il un moyen de le faire sans utiliser l'interface Web, ce qui prendra une éternité et me demandera de garder mon ordinateur portable allumé?

35
NobleUplift

Une façon de le faire consiste à parcourir les versions et à les supprimer. Un peu délicat sur la CLI, mais comme vous l'avez mentionné Java, ce serait plus simple:

AmazonS3Client s3 = new AmazonS3Client();
String bucketName = "deleteversions-"+UUID.randomUUID();

//Creates Bucket
s3.createBucket(bucketName);

//Enable Versioning
BucketVersioningConfiguration configuration = new BucketVersioningConfiguration(ENABLED);
s3.setBucketVersioningConfiguration(new SetBucketVersioningConfigurationRequest(bucketName, configuration ));

//Puts versions
s3.putObject(bucketName, "some-key",new ByteArrayInputStream("some-bytes".getBytes()), null);
s3.putObject(bucketName, "some-key",new ByteArrayInputStream("other-bytes".getBytes()), null);

//Removes all versions
for ( S3VersionSummary version : S3Versions.inBucket(s3, bucketName) ) {
    String key = version.getKey();
    String versionId = version.getVersionId();          
    s3.deleteVersion(bucketName, key, versionId);
}

//Removes the bucket
s3.deleteBucket(bucketName);
System.out.println("Done!");

Vous pouvez également supprimer des appels par lots pour plus d'efficacité si nécessaire.

4
faermanj

J'ai rencontré la même limitation de l'AWS CLI. J'ai trouvé la solution la plus simple à utiliser Python et boto :

#!/usr/bin/env python

BUCKET = 'your-bucket-here'

import boto3

s3 = boto3.resource('s3')
bucket = s3.Bucket(BUCKET)
bucket.object_versions.delete()

# if you want to delete the now-empty bucket as well, uncomment this line:
#bucket.delete()

Une version précédente de cette réponse utilisait boto mais cette solution avait des problèmes de performances avec un grand nombre de clés comme l'a souligné Chuckles.

36
Abe Voelker

En utilisant boto3 c'est encore plus simple qu'avec la solution boto proposée pour supprimer toutes les versions d'objets dans un bucket S3:

#!/usr/bin/env python
import boto3

s3 = boto3.resource('s3')
bucket = s3.Bucket('your-bucket-name')
bucket.object_versions.all().delete()

Fonctionne également très bien pour de très grandes quantités de versions d'objet, bien que cela puisse prendre un certain temps dans ce cas.

17
Dunedan

Vous pouvez supprimer tous les objets du compartiment s3 versionné. Mais je ne sais pas comment supprimer des objets spécifiques.

$ aws s3api delete-objects \
      --bucket <value> \
      --delete "$(aws s3api list-object-versions \
      --bucket <value> | \
      jq '{Objects: [.Versions[] | {Key:.Key, VersionId : .VersionId}], Quiet: false}')"

Alternativement sans jq:

$ aws s3api delete-objects \
    --bucket ${bucket_name} \
    --delete "$(aws s3api list-object-versions \
    --bucket "${bucket_name}" \
    --output=json \
    --query='{Objects: Versions[].{Key:Key,VersionId:VersionId}}')"
11
Cheers

Voici une ligne que vous pouvez simplement couper et coller dans la ligne de commande pour supprimer toutes les versions et supprimer les marqueurs (cela nécessite des outils aws, remplacez votre sauvegarde de nom de bucket par votre nom de bucket)

echo '#!/bin/bash' > deleteBucketScript.sh \
&& aws --output text s3api list-object-versions --bucket $BUCKET_TO_PERGE \
| grep -E "^VERSIONS" |\
awk '{print "aws s3api delete-object --bucket $BUCKET_TO_PERGE --key "$4" --version-id "$8";"}' >> \
deleteBucketScript.sh && . deleteBucketScript.sh; rm -f deleteBucketScript.sh; echo '#!/bin/bash' > \
deleteBucketScript.sh && aws --output text s3api list-object-versions --bucket $BUCKET_TO_PERGE \
| grep -E "^DELETEMARKERS" | grep -v "null" \
| awk '{print "aws s3api delete-object --bucket $BUCKET_TO_PERGE --key "$3" --version-id "$5";"}' >> \
deleteBucketScript.sh && . deleteBucketScript.sh; rm -f deleteBucketScript.sh;

alors vous pouvez utiliser:

aws s3 rb s3://bucket-name --force

5
Nitin

J'ai rencontré des problèmes avec la solution d'Abe comme list_buckets le générateur est utilisé pour créer une liste massive appelée all_keys et j'ai passé une heure sans jamais terminer. Ce Tweak semble mieux fonctionner pour moi, j'avais près d'un million d'objets dans mon seau et ça compte!

import boto

s3 = boto.connect_s3()
bucket = s3.get_bucket("your-bucket-name-here")

chunk_counter = 0 #this is simply a Nice to have
keys = []
for key in bucket.list_versions():
    keys.append(key)
    if len(keys) > 1000:
        bucket.delete_keys(keys)
        chunk_counter += 1
        keys = []
        print("Another 1000 done.... {n} chunks so far".format(n=chunk_counter))

#bucket.delete() #as per usual uncomment if you're sure!

Espérons que cela aide quiconque à rencontrer ce cauchemar S3!

4
chuckwired
  1. Pour supprimer, spécifiez un ou des objets à l'aide du filtre jq.
  2. Vous devrez peut-être nettoyer les "DeleteMarkers" et pas seulement les "versions".
  3. Utilisation de $() au lieu de ``, vous pouvez incorporer des variables pour le nom de compartiment et la valeur-clé.
aws s3api delete-objects --bucket bucket-name --delete "$(aws s3api list-object-versions --bucket bucket-name | jq -M '{Objects: [.["Versions","DeleteMarkers"][]|select(.Key == "key-value")| {Key:.Key, VersionId : .VersionId}], Quiet: false}')"
4
Tiger peng

https://Gist.github.com/wknapik/191619bfa650b8572115cd07197f3baf

#!/usr/bin/env bash

set -eEo pipefail
shopt -s inherit_errexit >/dev/null 2>&1 || true

if [[ ! "$#" -eq 2 || "$1" != --bucket ]]; then
    echo -e "USAGE: $(basename "$0") --bucket <bucket>"
    exit 2
fi

# $@ := bucket_name
empty_bucket() {
    local -r bucket="${1:?}"
    for object_type in Versions DeleteMarkers; do
        local opt=() next_token=""
        while [[ "$next_token" != null ]]; do
            page="$(aws s3api list-object-versions --bucket "$bucket" --output json --max-items 1000 "${opt[@]}" \
                        --query="[{Objects: ${object_type}[].{Key:Key, VersionId:VersionId}}, NextToken]")"
            objects="$(jq -r '.[0]' <<<"$page")"
            next_token="$(jq -r '.[1]' <<<"$page")"
            case "$(jq -r .Objects <<<"$objects")" in
                '[]'|null) break;;
                *) opt=(--starting-token "$next_token")
                   aws s3api delete-objects --bucket "$bucket" --delete "$objects";;
            esac
        done
    done
}

empty_bucket "${2#s3://}"

Par exemple. empty_bucket.sh --bucket foo

Cela supprimera toutes les versions d'objet et supprimera les marqueurs dans un compartiment par lots de 1000. Ensuite, le compartiment peut être supprimé avec aws s3 rb s3://foo.

Nécessite bash, awscli et jq.

0
user2402169

De loin, la méthode la plus simple que j'ai trouvée consiste à utiliser cet outil CLI, s3wipe. Il est fourni sous forme de conteneur Docker afin que vous puissiez l'utiliser comme ceci:

$ docker run -it --rm slmingol/s3wipe --help
usage: s3wipe [-h] --path PATH [--id ID] [--key KEY] [--dryrun] [--quiet]
              [--batchsize BATCHSIZE] [--maxqueue MAXQUEUE]
              [--maxthreads MAXTHREADS] [--delbucket] [--region REGION]

Recursively delete all keys in an S3 path

optional arguments:
  -h, --help               show this help message and exit
  --path PATH              S3 path to delete (e.g. s3://bucket/path)
  --id ID                  Your AWS access key ID
  --key KEY                Your AWS secret access key
  --dryrun                 Don't delete. Print what we would have deleted
  --quiet                  Suprress all non-error output
  --batchsize BATCHSIZE    # of keys to batch delete (default 100)
  --maxqueue MAXQUEUE      Max size of deletion queue (default 10k)
  --maxthreads MAXTHREADS  Max number of threads (default 100)
  --delbucket              If S3 path is a bucket path, delete the bucket also
  --region REGION          Region of target S3 bucket. Default vaue `us-
                           east-1`

Exemple

Voici un exemple où je supprime tous les objets versionnés dans un compartiment, puis je supprime le compartiment:

$ docker run -it --rm slmingol/s3wipe \
   --id $(aws configure get default.aws_access_key_id) \
   --key $(aws configure get default.aws_secret_access_key) \
   --path s3://bw-tf-backends-aws-example-logs \
   --delbucket
[2019-02-20@03:39:16] INFO: Deleting from bucket: bw-tf-backends-aws-example-logs, path: None
[2019-02-20@03:39:16] INFO: Getting subdirs to feed to list threads
[2019-02-20@03:39:18] INFO: Done deleting keys
[2019-02-20@03:39:18] INFO: Bucket is empty.  Attempting to remove bucket

Comment ça fonctionne

Il y a un peu à déballer ici mais ce qui précède fait ce qui suit:

  • docker run -it --rm mikelorant/s3wipe - exécute s3wipe conteneur interactivement et le supprime après chaque exécution
  • --id & --key - transmission de notre clé d'accès et de notre identifiant d'accès
  • aws configure get default.aws_access_key_id - récupère notre identifiant de clé
  • aws configure get default.aws_secret_access_key - récupère notre clé secrète
  • --path s3://bw-tf-backends-aws-example-logs - compartiment que nous voulons supprimer
  • --delbucket - supprime le compartiment une fois vidé

Les références

0
slm

Ce script bash se trouve ici: https://Gist.github.com/weavenet/f40b09847ac17dd99d16

a fonctionné tel quel pour moi.

J'ai enregistré le script sous: delete_all_versions.sh, puis j'ai simplement exécuté:

./delete_all_versions.sh my_foobar_bucket

et cela a fonctionné sans faille.

N'a pas eu besoin de python ou boto ou quoi que ce soit.

0
Mamun