2011-03-04 7 views
67

Jestem całkiem zadowolony z s3cmd, ale jest jeden problem: jak skopiować wszystkie pliki z jednego wiadra S3 do drugiego? Czy to możliwe?Czy można kopiować wszystkie pliki z jednego zasobnika S3 na drugie z s3cmd?

EDIT: Znalazłem drogę do kopiowania plików między wiadrami wykorzystaniem Pythona w 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 

Synchronizacja jest prawie tak proste jak kopiowanie. Istnieją pola dla ETag, rozmiaru i ostatniej modyfikacji dostępne dla kluczy.

Może to również pomaga innym.

+3

Hej, czy mógłbyś dokonać edycji w odpowiedzi i zaakceptować? To naprawdę pożyteczna wskazówka! – Hamish

+1

jakiejkolwiek przyczyny używasz 'get_all_keys' zamiast "listy"? – BillR

Odpowiedz

82

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

Do dostępnych opcji, należy użyć: $s3cmd --help

+1

Niesamowita sugestia. Uwielbiam to s3cmd. Ukośne ukośniki mogą być ważne, więc 's3cmd sync s3: // sample_bucket/s3: // staging_bucket /' działało dobrze dla mnie. –

+0

Też nie lubię tego zachowania. Recenzenci starają się zminimalizować czas poświęcany na recenzję, dlatego Twoja zmiana nie musi być tylko w porządku, ale musi tak wyglądać. Jeśli twoja zmiana została odrzucona, ale jesteś bardzo, bardzo pewna, że ​​była naprawdę potrzebna, nie uważam złego zachowania, jeśli dasz sobie z nią kolejną próbę - może z innymi recenzentami będziesz miał więcej szczęścia. – peterh

+9

możesz także użyć aws cli, aby to zrobić. aws s3 sync s3: // od/s3: // do/ – Bobo

1

s3cmd nie będzie cp z tylko prefiksami lub znakami wieloznacznymi, ale można zakodować zachowanie za pomocą "s3cmd ls sourceBucket", awk, aby wyodrębnić nazwę obiektu. Następnie użyj "s3cmd cp sourceBucket/name destBucket", aby skopiować nazwę każdego obiektu na liście.

używam tych plików wsadowych w oknie DOS w systemie 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 
+0

Należy zauważyć, że ta metoda jest BARDZO powolna (podobnie jak inne rozwiązania, które wykonują jeden obiekt naraz) - ale działa, jeśli nie ma zbyt wielu elementów do skopiowania. –

+0

Ta odpowiedź oszukała mnie przez długi czas ... ale w rzeczywistości s3cmd CAN cp z symbolami wieloznacznymi, jeśli używasz poprawnego (nieco nieintuicyjnego) zestawu opcji. Wysłałem odpowiedź ze szczegółami. – mdahlman

2

Dzięki - używam wersji nieco zmodyfikowanej, gdzie Kopiuje tylko pliki, które nie istnieją lub mają inny rozmiar, i sprawdza miejsce docelowe, jeśli klucz istnieje w źródle. Znalazłem to nieco szybciej za gotowość środowiska testowego:

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

Napisałem skrypt, który tworzy kopie zapasowe jest wiadro 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 __name__ =='__main__':main() 

Używam tego w zadaniu natarcia (dla 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 
3

To rzeczywiście możliwe. Ten pracował dla mnie:

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) 
+0

Metoda kopiowania dotyczy obiektu 'boto.s3.key', [patrz tutaj] (http://boto.readthedocs.org/en/latest/ref/s3.html#module-boto.s3.key).Ale jest to dobry sposób na bezpośrednie kopiowanie/przenoszenie pliku bez martwienia się o szczegóły za pomocą * podfolderów *. – GeoSharp

28

odpowiedź z największą liczbą upvotes jak piszę to jest to jedno:

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

To przydatna odpowiedź. Ale czasami synchronizacja nie jest tym, czego potrzebujesz (usuwa pliki itp.). Dużo czasu zajęło mi zrozumienie tej niebankowej alternatywy po prostu kopiowanie wielu plików między zasobnikami. (OK, w przypadku pokazanym poniżej nie ma między zasobnikami.To między nie tak naprawdę foldery, ale działa równie dobrze między zasobnikami.)

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

Wyjaśnienie powyższego polecenia:

  • -recursive
    W moim umyśle, mój wymóg nie jest rekurencyjny. Po prostu chcę wielu plików. Ale rekurencyjne w tym kontekście po prostu mówi s3cmd cp do obsługi wielu plików. Wspaniały.
  • -exclude
    To dziwny sposób, aby pomyśleć o problemie. Rozpocznij od rekurencyjnego wybierania wszystkich plików. Następnie wykluczyć wszystkie pliki. Czekaj, co?
  • -włączenie
    Teraz rozmawiamy. Wskaż prefiks pliku (lub sufiks lub jakikolwiek wzorzec), który chcesz dołączyć.
    s3://sourceBucket/ s3://targetBucket/
    Ta część jest wystarczająco intuicyjna. Choć technicznie wydaje się naruszać udokumentowany przykład z s3cmd pomoc, która wskazuje, że obiekt źródłowy musi być określana:
    s3cmd cp s3://BUCKET1/OBJECT1 s3://BUCKET2[/OBJECT2]
+0

Aby ta dobra odpowiedź była wspaniała, skopiuj " Sekcja Enlightenment "[dogłębnego posta na blogu] (http://mdahlman.wordpress.com/2013/12/05/copy-files-between-s3-buckets/) na swoją odpowiedź tutaj. Świetna robota! –

+0

Nie można osiągnąć tego samego z: 's3cmd sync --max-delete = 0 s3: // od s3: // do'? – schmijos

+0

Hmm ... Nigdy nie znalazłem tej opcji. Nie mogę więc potwierdzić, że to działa. Ale nie rozumiem, dlaczego by tak nie było. W rzeczywistości, teraz widzę '--no-delete-removed', które wydaje się jeszcze bardziej na temat. – mdahlman

1

Można również użyć s3funnel który wykorzystuje wielowątkowości:

https://github.com/neelakanta/s3funnel

przykład (bez pokazanego klucza dostępu lub tajnych parametrów klucza):

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

2

kod mdahlman za nie działa dla mnie, ale to polecenie kopiuje wszystkie pliki w bucket1 do nowego folderu (polecenie tworzy również ten nowy folder) w segmencie 2.

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

można również używać interfejsu internetowego, aby to zrobić:

  1. Przejdź do wiadra źródłowego w interfejsie WWW mi.
  2. Zaznacz pliki, które chcesz skopiować (użyj przesunięcia i kliknięć myszy, aby zaznaczyć kilka).
  3. Naciśnij przyciski Akcje-> Kopiuj.
  4. Przejdź do pojemnika docelowego.
  5. Naciśnij przycisk Akcje-> Wklej.

To wszystko.

Powiązane problemy