Чи можна скопіювати всі файли з одного сегмента S3 в інший за допомогою s3cmd?


77

Я дуже задоволений s3cmd, але є одне питання: як скопіювати всі файли з одного сегмента S3 в інший? Це взагалі можливо?

EDIT: Я знайшов спосіб копіювати файли між сегментами за допомогою Python з 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

Синхронізація майже така ж пряма, як і копіювання. Для ключів є поля для ETag, розміру та останньої модифікації.

Можливо, це допомагає і іншим.


3
Гей, не могли б ви зробити свою редакцію відповіддю та прийняти? Це дійсно корисна порада!
Хаміш

1
з якоїсь причини ви використовуєте 'get_all_keys' на відміну від 'list'?
Білл Росмус,

Відповіді:


90

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

Для доступних варіантів використовуйте: $s3cmd --help


1
Чудова пропозиція. Люблю цей s3cmd. Кінцеві скісні риски можуть бути важливими, тому s3cmd sync s3://sample_bucket/ s3://staging_bucket/добре працювали для мене.
Чарльз Форсі

Мені також не подобається така поведінка. Рецензенти намагаються мінімізувати час, витрачений на огляд, отже, ваша зміна повинна бути не тільки нормальною, але вона повинна виглядати так. Якщо вашу зміну було відхилено, але ви дуже, дуже впевнені, що вона дійсно потрібна, я не вважаю поганою поведінкою, якщо ви спробуєте наступну спробу - можливо, з іншими рецензентами вам пощастить більше.
Петер

12
Ви також можете використовувати aws cli для цього. aws s3 sync s3: // from / s3: // to /
Бобо

2
Що робити, якщо кожен сегмент має різний набір ідентифікатора ключа доступу та секретний (різні облікові записи AWS)?
мозковий штурм

@brainstorm, можливо, ви захочете створити нового користувача AWS, який має доступ до обох сегментів, для використання s3cmd для конкретного випадку використання.
amit_saxena


29

Відповідь із найбільшою кількістю голосів, коли я пишу це, така:

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

Це корисна відповідь. Але іноді синхронізація - це не те, що вам потрібно (вона видаляє файли тощо). Мені знадобилося багато часу, щоб зрозуміти цю альтернативу сценарію, щоб просто скопіювати кілька файлів між сегментами. (Добре, у наведеному нижче випадку справа не між сегментами. Це між не-справді папками, але вона працює однаково добре між сегментами.)

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

Пояснення наведеної команди:

  • –Рекурсивно
    На мою думку, моя вимога не є рекурсивною. Я просто хочу кілька файлів. Але рекурсивний у цьому контексті просто говорить s3cmd cp обробляти кілька файлів. Чудово.
  • –Exclude
    Це дивний спосіб думати про проблему. Почніть з рекурсивного виділення всіх файлів. Далі виключіть усі файли. Чекати, що?
  • –Включити
    Зараз ми говоримо. Вкажіть префікс файлу (або суфікс або будь-який інший шаблон), який ви хочете включити.
    s3://sourceBucket/ s3://targetBucket/
    Ця частина досить інтуїтивна. Хоча технічно це, здається, порушує задокументований приклад з довідки s3cmd, який вказує на те, що потрібно вказати вихідний об'єкт:
    s3cmd cp s3://BUCKET1/OBJECT1 s3://BUCKET2[/OBJECT2]

Щоб зробити цю хорошу відповідь чудовою, скопіюйте розділ «Просвіта» свого поглибленого допису в блозі у свою відповідь тут. Чудова робота!
Iain Samuel McLean Elder

Не могли б ви досягти того ж за допомогою s3cmd sync --max-delete=0 s3://from s3://to:?
schmijos

Хм ... я ніколи не знайшов такого варіанту. Тому я не можу підтвердити, що це працює. Але я не розумію, чому б цього не сталося. Насправді, зараз я бачу, --no-delete-removedщо здається ще більш важливим.
mdahlman

9

Ви також можете використовувати веб-інтерфейс:

  1. Перейдіть до вихідного сегмента у веб-інтерфейсі.
  2. Позначте файли, які потрібно скопіювати (використовуйте клавіші Shift та клацання миші, щоб позначити кілька).
  3. Натисніть Дії-> Копіювати.
  4. Перейдіть до відра призначення.
  5. Натисніть Дії-> Вставити.

Це воно.



3

Це насправді можливо. Це спрацювало для мене:

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)

Метод копіювання призначений для boto.s3.keyоб'єкта, дивіться тут . Але це хороший спосіб безпосереднього копіювання / переміщення файлу, не турбуючись про деталі з "підпапками" .
GeoSharp

2

Дякую - я використовую дещо змінену версію, де копіюю лише ті файли, які не існують або мають інший розмір, і перевіряю місце призначення, чи існує ключ у джерелі. Я знайшов це трохи швидше для підготовки тестового середовища:

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

Я написав сценарій, який створює резервну копію сегмента 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()

Я використовую це в завданні граблі (для програми 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

Код mdahlman у мене не спрацював, але ця команда копіює всі файли в bucket1 в нову папку (команда також створює цю нову папку) у відрі 2.

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

ця команда не працює, що має йти перед cp? aw3 s3cmd або що-небудь ще
NEOmen

1

s3cmd не буде cp лише з префіксами або символами підстановки, але ви можете сценарій поведінки за допомогою 's3cmd ls sourceBucket' і awk для вилучення імені об'єкта. Потім використовуйте 's3cmd cp sourceBucket / name destBucket', щоб скопіювати кожне ім'я об'єкта у списку.

Я використовую ці командні файли у вікні DOS у 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

Зауважте, що цей метод ДУЖЕ повільний (як і інші рішення, які роблять по одному об’єкту за раз), але він працює, якщо у вас не надто багато елементів для копіювання.
Джошуа Річардсон

Ця відповідь мене довго обдурювала ... але насправді s3cmd МОЖЕ cp з узагальнюючими знаками, якщо ви використовуєте правильний (дещо не інтуїтивний) набір параметрів. Я розмістив відповідь із деталями.
mdahlman

1

Ви також можете використовувати s3funnel, який використовує багатопоточність:

https://github.com/neelakanta/s3funnel

приклад (без показаних параметрів ключа доступу або секретного ключа):

s3funnel список-джерело-ім'я | s3funnel dest-bucket-name copy --source-bucket source-bucket-name --threads = 10

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.