web-dev-qa-db-fra.com

Est-il possible de copier tous les fichiers d'un bucket S3 vers un autre avec s3cmd?

Je suis assez satisfait de s3cmd, mais il y a un problème: comment copier tous les fichiers d'un compartiment S3 vers un autre? Est-ce même possible?

EDIT: J'ai trouvé un moyen de copier des fichiers entre des compartiments en utilisant Python avec boto:

from boto.s3.connection import S3Connection

def copyBucket(srcBucketName, dstBucketName, maxKeys = 100):
  conn = S3Connection(awsAccessKey, awsSecretKey)

  srcBucket = conn.get_bucket(srcBucketName);
  dstBucket = conn.get_bucket(dstBucketName);

  resultMarker = ''
  while True:
    keys = srcBucket.get_all_keys(max_keys = maxKeys, marker = resultMarker)

    for k in keys:
      print 'Copying ' + k.key + ' from ' + srcBucketName + ' to ' + dstBucketName

      t0 = time.clock()
      dstBucket.copy_key(k.key, srcBucketName, k.key)
      print time.clock() - t0, ' seconds'

    if len(keys) < maxKeys:
      print 'Done'
      break

    resultMarker = keys[maxKeys - 1].key

La synchronisation est presque aussi simple que la copie. Il existe des champs pour ETag, la taille et la dernière modification disponibles pour les clés.

Peut-être que cela aide aussi les autres.

74
Jan Deinhard

s3cmd sync s3://from/this/bucket/ s3://to/this/bucket/

Pour les options disponibles, veuillez utiliser: $s3cmd --help

88
amit_saxena

L'AWS CLI semble parfaitement faire le travail et a l'avantage d'être un outil officiellement pris en charge.

aws s3 sync s3://mybucket s3://backup-mybucket

http://docs.aws.Amazon.com/cli/latest/reference/s3/sync.html

42
python1981

La réponse avec le plus de votes au moment où j'écris ceci est celle-ci:

s3cmd sync s3://from/this/bucket s3://to/this/bucket

C'est une réponse utile. Mais parfois, la synchronisation n'est pas ce dont vous avez besoin (elle supprime les fichiers, etc.). Il m'a fallu beaucoup de temps pour trouver cette alternative sans script pour copier simplement plusieurs fichiers entre des compartiments. (OK, dans le cas ci-dessous, ce n'est pas entre des compartiments. C'est entre des dossiers pas vraiment, mais cela fonctionne aussi bien entre des compartiments.)

# Slightly verbose, slightly unintuitive, very useful:
s3cmd cp --recursive --exclude=* --include=file_prefix* s3://semarchy-inc/source1/ s3://semarchy-inc/target/

Explication de la commande ci-dessus:

  • –Récursif
    Dans mon esprit, mon exigence n'est pas récursive. Je veux simplement plusieurs fichiers. Mais récursif dans ce contexte indique simplement à s3cmd cp de gérer plusieurs fichiers. Génial.
  • -exclure
    C'est une façon étrange de penser au problème. Commencez par sélectionner récursivement tous les fichiers. Ensuite, excluez tous les fichiers. Attends quoi?
  • -comprendre
    Nous parlons maintenant. Indiquez le préfixe de fichier (ou suffixe ou tout autre motif) que vous souhaitez inclure.
    s3://sourceBucket/ s3://targetBucket/
    Cette partie est suffisamment intuitive. Bien que techniquement, il semble violer l'exemple documenté de l'aide de s3cmd qui indique qu'un objet source doit être spécifié:
    s3cmd cp s3://BUCKET1/OBJECT1 s3://BUCKET2[/OBJECT2]
29
mdahlman

Vous pouvez également utiliser l'interface Web pour ce faire:

  1. Accédez au compartiment source dans l'interface Web.
  2. Marquez les fichiers que vous souhaitez copier (utilisez Maj et les clics de souris pour en marquer plusieurs).
  3. Appuyez sur Actions-> Copier.
  4. Accédez au compartiment de destination.
  5. Appuyez sur Actions-> Coller.

C'est ça.

8
Moti Hamo

J'avais besoin de copier un très grand compartiment, j'ai donc adapté le code de la question dans une version multithread et l'ai mis sur GitHub.

https://github.com/paultuckey/s3-bucket-to-bucket-copy-py

8
Paul

C'est en fait possible. Cela a fonctionné pour moi:

import boto


AWS_ACCESS_KEY = 'Your access key'
AWS_SECRET_KEY = 'Your secret key'

conn = boto.s3.connection.S3Connection(AWS_ACCESS_KEY, AWS_SECRET_KEY)
bucket = boto.s3.bucket.Bucket(conn, SRC_BUCKET_NAME)

for item in bucket:
    # Note: here you can put also a path inside the DEST_BUCKET_NAME,
    # if you want your item to be stored inside a folder, like this:
    # bucket.copy(DEST_BUCKET_NAME, '%s/%s' % (folder_name, item.key))
    bucket.copy(DEST_BUCKET_NAME, item.key)
3
drekyn

le code de mdahlman n'a pas fonctionné pour moi, mais cette commande copie tous les fichiers du bucket1 dans un nouveau dossier (la commande crée également ce nouveau dossier) dans le bucket 2.

cp --recursive --include=file_prefix* s3://bucket1/ s3://bucket2/new_folder_name/
3
ansonw

Merci - J'utilise une version légèrement modifiée, où je copie uniquement les fichiers qui n'existent pas ou qui sont d'une taille différente, et vérifie la destination si la clé existe dans la source. J'ai trouvé cela un peu plus rapide pour préparer l'environnement de test:

def botoSyncPath(path):
    """
       Sync keys in specified path from source bucket to target bucket.
    """
    try:
        conn = S3Connection(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
        srcBucket = conn.get_bucket(AWS_SRC_BUCKET)
        destBucket = conn.get_bucket(AWS_DEST_BUCKET)
        for key in srcBucket.list(path):
            destKey = destBucket.get_key(key.name)
            if not destKey or destKey.size != key.size:
                key.copy(AWS_DEST_BUCKET, key.name)

        for key in destBucket.list(path):
            srcKey = srcBucket.get_key(key.name)
            if not srcKey:
                key.delete()
    except:
        return False
    return True
2
Adam Morris

J'ai écrit un script qui sauvegarde un compartiment S3: https://github.com/roseperrone/aws-backup-rake-task

#!/usr/bin/env python
from boto.s3.connection import S3Connection
import re
import datetime
import sys
import time

def main():
    s3_ID = sys.argv[1]
    s3_key = sys.argv[2]
    src_bucket_name = sys.argv[3]
    num_backup_buckets = sys.argv[4]
    connection = S3Connection(s3_ID, s3_key)
    delete_oldest_backup_buckets(connection, num_backup_buckets)
    backup(connection, src_bucket_name)

def delete_oldest_backup_buckets(connection, num_backup_buckets):
    """Deletes the oldest backup buckets such that only the newest NUM_BACKUP_BUCKETS - 1 buckets remain."""
    buckets = connection.get_all_buckets() # returns a list of bucket objects
    num_buckets = len(buckets)

    backup_bucket_names = []
    for bucket in buckets:
        if (re.search('backup-' + r'\d{4}-\d{2}-\d{2}' , bucket.name)):
            backup_bucket_names.append(bucket.name)

    backup_bucket_names.sort(key=lambda x: datetime.datetime.strptime(x[len('backup-'):17], '%Y-%m-%d').date())

    # The buckets are sorted latest to earliest, so we want to keep the last NUM_BACKUP_BUCKETS - 1
    delete = len(backup_bucket_names) - (int(num_backup_buckets) - 1)
    if delete <= 0:
        return

    for i in range(0, delete):
        print 'Deleting the backup bucket, ' + backup_bucket_names[i]
        connection.delete_bucket(backup_bucket_names[i])

def backup(connection, src_bucket_name):
    now = datetime.datetime.now()
    # the month and day must be zero-filled
    new_backup_bucket_name = 'backup-' + str('%02d' % now.year) + '-' + str('%02d' % now.month) + '-' + str(now.day);
    print "Creating new bucket " + new_backup_bucket_name
    new_backup_bucket = connection.create_bucket(new_backup_bucket_name)
    copy_bucket(src_bucket_name, new_backup_bucket_name, connection)


def copy_bucket(src_bucket_name, dst_bucket_name, connection, maximum_keys = 100):
    src_bucket = connection.get_bucket(src_bucket_name);
    dst_bucket = connection.get_bucket(dst_bucket_name);

    result_marker = ''
    while True:
        keys = src_bucket.get_all_keys(max_keys = maximum_keys, marker = result_marker)

        for k in keys:
            print 'Copying ' + k.key + ' from ' + src_bucket_name + ' to ' + dst_bucket_name

            t0 = time.clock()
            dst_bucket.copy_key(k.key, src_bucket_name, k.key)
            print time.clock() - t0, ' seconds'

        if len(keys) < maximum_keys:
            print 'Done backing up.'
            break

        result_marker = keys[maximum_keys - 1].key

if  __=='__main__':main()

J'utilise ceci dans une tâche de râteau (pour une application Rails):

desc "Back up a file onto S3"
task :backup do
     S3ID = "*****"
     S3KEY = "*****"
     SRCBUCKET = "primary-mzgd"
     NUM_BACKUP_BUCKETS = 2

     Dir.chdir("#{Rails.root}/lib/tasks")
     system "./do_backup.py #{S3ID} #{S3KEY} #{SRCBUCKET} #{NUM_BACKUP_BUCKETS}"
end
2
Rose Perrone

Vous pouvez également utiliser s3funnel qui utilise le multithread:

https://github.com/neelakanta/s3funnel

exemple (sans les paramètres de clé d'accès ou de clé secrète affichés):

s3funnel source-bucket-name list | s3funnel dest-bucket-name copy --source-bucket source-bucket-name --threads = 10

1

s3cmd ne sera pas cp avec seulement des préfixes ou des caractères génériques mais vous pouvez scripter le comportement avec 's3cmd ls sourceBucket', et awk pour extraire le nom de l'objet. Utilisez ensuite 's3cmd cp sourceBucket/name destBucket' pour copier chaque nom d'objet dans la liste.

J'utilise ces fichiers batch dans une boîte DOS sous Windows:

s3list.bat

s3cmd ls %1 | gawk "/s3/{ print \"\\"\"\"substr($0,index($0,\"s3://\"))\"\\"\"\"; }"

s3copy.bat

@for /F "delims=" %%s in ('s3list %1') do @s3cmd cp %%s %2
1
John Lemberger