Ist es möglich, alle Dateien mit s3cmd von einem S3-Bucket in einen anderen zu kopieren?

77

Ich bin ziemlich zufrieden mit s3cmd, aber es gibt ein Problem: Wie kopiere ich alle Dateien von einem S3-Bucket in einen anderen? Ist es überhaupt möglich?

BEARBEITEN: Ich habe einen Weg gefunden, Dateien zwischen Buckets mit Python mit boto zu kopieren:

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

Die Synchronisierung ist fast so einfach wie das Kopieren. Für Schlüssel sind Felder für ETag, Größe und zuletzt geändert verfügbar.

Vielleicht hilft das auch anderen.

Jan Deinhard
quelle
3
Hey, könntest du deine Bearbeitung zu einer Antwort machen und akzeptieren? Dies ist ein wirklich nützlicher Tipp!
Hamish
1
Gibt es einen Grund, warum Sie 'get_all_keys' im Gegensatz zu 'list' verwenden?
Bill Rosmus

Antworten:

90

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

Für verfügbare Optionen verwenden Sie bitte: $s3cmd --help

amit_saxena
quelle
1
Super Vorschlag. Ich liebe dieses s3cmd. Nachgestellte Schrägstriche können wichtig sein, also s3cmd sync s3://sample_bucket/ s3://staging_bucket/hat es für mich gut funktioniert.
Charles Forcey
Ich mag dieses Verhalten auch nicht. Die Prüfer versuchen, den Zeitaufwand für eine Prüfung so gering wie möglich zu halten. Daher muss Ihre Änderung nicht nur in Ordnung sein, sondern auch so aussehen. Wenn Ihre Änderung abgelehnt wurde, Sie aber sehr, sehr sicher sind, dass sie wirklich benötigt wurde, halte ich schlechtes Verhalten nicht für möglich, wenn Sie es das nächste Mal versuchen - vielleicht haben Sie mit anderen Gutachtern mehr Glück.
Peter - Wiedereinsetzung Monica
12
Sie können dazu auch aws cli verwenden. aws s3 synchronisiere s3: // von / s3: // nach /
Bobo
2
Was ist, wenn jeder Bucket eine andere Zugriffsschlüssel-ID und ein anderes Geheimnis hat (unterschiedliche AWS-Konten)?
Brainstorming
@brainstorm Möglicherweise möchten Sie einen neuen AWS-Benutzer erstellen, der Zugriff auf beide Buckets hat, um s3cmd für den jeweiligen Anwendungsfall zu verwenden.
amit_saxena
46

AWS CLI scheint die Arbeit perfekt zu machen und hat den Vorteil, ein offiziell unterstütztes Tool zu sein.

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

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

python1981
quelle
Ja. Aber es gibt keinen Requester-Pays-Parameter und so weiter
Artem Ignatiev
29

Die Antwort mit den meisten positiven Stimmen, während ich dies schreibe, ist folgende:

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

Es ist eine nützliche Antwort. Aber manchmal ist die Synchronisierung nicht das, was Sie brauchen (sie löscht Dateien usw.). Es hat lange gedauert, bis ich diese Alternative ohne Skripte gefunden hatte, um einfach mehrere Dateien zwischen Buckets zu kopieren. (OK, in dem unten gezeigten Fall ist es nicht zwischen Buckets. Es ist zwischen Nicht-wirklich-Ordnern, aber es funktioniert zwischen Buckets gleich gut.)

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

Erläuterung des obigen Befehls:

  • –Rekursiv
    Meiner Meinung nach ist meine Anforderung nicht rekursiv. Ich möchte einfach mehrere Dateien. In diesem Zusammenhang weist rekursiv s3cmd cp jedoch nur an, mehrere Dateien zu verarbeiten. Großartig.
  • –Ausschließen
    Es ist eine seltsame Art, sich das Problem vorzustellen . Beginnen Sie mit der rekursiven Auswahl aller Dateien. Schließen Sie als Nächstes alle Dateien aus. Warte was?
  • -
    jetzt reden wir. Geben Sie das Dateipräfix (oder Suffix oder ein beliebiges Muster) an, das Sie einschließen möchten.
    s3://sourceBucket/ s3://targetBucket/
    Dieser Teil ist intuitiv genug. Obwohl es technisch gesehen gegen das dokumentierte Beispiel aus der s3cmd-Hilfe zu verstoßen scheint, das angibt, dass ein Quellobjekt angegeben werden muss:
    s3cmd cp s3://BUCKET1/OBJECT1 s3://BUCKET2[/OBJECT2]
mdahlman
quelle
Um diese gute Antwort großartig zu machen, kopieren Sie bitte den Abschnitt "Aufklärung" Ihres ausführlichen Blog-Beitrags in Ihre Antwort hier. Gute Arbeit!
Iain Samuel McLean Elder
Könnten Sie nicht dasselbe erreichen mit : s3cmd sync --max-delete=0 s3://from s3://to?
schmijos
Hmm ... ich habe diese Option nie gefunden. Ich kann also nicht bestätigen, dass es funktioniert. Aber ich verstehe nicht, warum es nicht so wäre. In der Tat sehe ich jetzt, --no-delete-removedwas noch mehr auf den Punkt scheint.
Mdahlman
9

Sie können dazu auch die Weboberfläche verwenden:

  1. Wechseln Sie zum Quell-Bucket in der Weboberfläche.
  2. Markieren Sie die Dateien, die Sie kopieren möchten (markieren Sie mehrere mit Umschalt- und Mausklicks).
  3. Drücken Sie Aktionen-> Kopieren.
  4. Gehen Sie zum Ziel-Bucket.
  5. Drücken Sie Aktionen-> Einfügen.

Das ist es.

Moti Hamo
quelle
3

Es ist tatsächlich möglich. Das hat bei mir funktioniert:

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)
drekyn
quelle
Die Kopiermethode gilt für das boto.s3.keyObjekt, siehe hier . Dies ist jedoch eine gute Möglichkeit, eine Datei direkt zu kopieren / zu verschieben, ohne sich um Details mit Unterordnern kümmern zu müssen .
GeoSharp
2

Danke - Ich verwende eine leicht modifizierte Version, in der ich nur Dateien kopiere, die nicht existieren oder eine andere Größe haben, und am Ziel überprüfe, ob der Schlüssel in der Quelle vorhanden ist. Ich fand das etwas schneller, um die Testumgebung vorzubereiten:

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
Adam Morris
quelle
2

Ich habe ein Skript geschrieben, das einen S3-Bucket sichert: 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  __name__ =='__main__':main()

Ich benutze dies in einer Rechenaufgabe (für eine Rails-App):

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
Rose Perrone
quelle
2

Der Code von mdahlman hat bei mir nicht funktioniert, aber dieser Befehl kopiert alle Dateien in Bucket1 in einen neuen Ordner (Befehl erstellt auch diesen neuen Ordner) in Bucket 2.

cp --recursive --include=file_prefix* s3://bucket1/ s3://bucket2/new_folder_name/
ansonw
quelle
Dieser Befehl funktioniert nicht. Was sollte vor cp gehen? aw3 s3cmd oder irgendetwas anderes
NEOmen
1

s3cmd wird nicht nur mit Präfixen oder Platzhaltern cp, aber Sie können das Verhalten mit 's3cmd ls sourceBucket' und awk skripten, um den Objektnamen zu extrahieren. Verwenden Sie dann 's3cmd cp sourceBucket / name destBucket', um jeden Objektnamen in der Liste zu kopieren.

Ich verwende diese Batch-Dateien in einer DOS-Box unter 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
John Lemberger
quelle
Beachten Sie, dass diese Methode SEHR langsam ist (wie andere Lösungen, die jeweils ein Objekt ausführen) - sie funktioniert jedoch, wenn Sie nicht zu viele Elemente zum Kopieren haben.
Joshua Richardson
Diese Antwort hat mich lange getäuscht ... aber tatsächlich kann s3cmd mit Platzhaltern cp, wenn Sie die richtigen (etwas unintuitiven) Optionen verwenden. Ich habe eine Antwort mit Details gepostet.
Mdahlman
1

Sie können auch s3funnel verwenden, das Multithreading verwendet:

https://github.com/neelakanta/s3funnel

Beispiel (ohne die angezeigten Zugriffsschlüssel- oder Geheimschlüsselparameter):

s3funnel Quell-Bucket-Namensliste | s3funnel dest-Bucket-Name Kopie - Source-Bucket Source-Bucket-Name - Threads = 10

Mahesh Neelakanta
quelle