Как восстановить папки (или целые корзины) в Amazon S3 из Glacier?

Я изменил жизненный цикл для множества своих корзин на Amazon S3, поэтому их класс хранения был установлен на Glacier. Я сделал это с помощью онлайн-консоли AWS. Теперь мне снова нужны эти файлы.

Я знаю, как восстановить их обратно до S3 на файл. Но мои ведра имеют тысячи файлов. Я хотел посмотреть, есть ли способ восстановить все ведро обратно на S3, точно так же, как был способ отправить все ведро на ледник?

Я предполагаю, что есть способ запрограммировать решение. Но я хотел посмотреть, есть ли способ сделать это в консоли. Или с другой программой? Или что-то еще, чего мне не хватает?

15 ответов

Решение

Для этого нет встроенного инструмента. "Папки" в S3 - это иллюзия для удобства человека, основанная на косых чертах в ключе объекта (путь / имя файла), и каждый объект, который мигрирует в ледник, должен быть восстановлен индивидуально, хотя...

Конечно, вы могли бы написать скрипт для итерации по иерархии и отправлять эти запросы на восстановление с помощью SDK или REST API на выбранном вами языке программирования.

Прежде чем продолжить, убедитесь, что вы понимаете, как происходит восстановление из ледника в S3. Это всегда только временное восстановление, и вы выбираете количество дней, в течение которых каждый объект будет сохраняться в S3, прежде чем вернуться к хранению только в леднике.

Кроме того, вы хотите быть уверены, что понимаете штрафные сборы за восстановление слишком большого количества данных о леднике за короткий промежуток времени, иначе вы можете столкнуться с непредвиденными расходами. В зависимости от срочности вы можете распространить операцию восстановления на несколько дней или недель.

Если вы используете s3cmd Вы можете использовать его для восстановления рекурсивно довольно легко:

s3cmd restore --recursive s3://mybucketname/ 

Я также использовал его, чтобы восстановить только папки:

s3cmd restore --recursive s3://mybucketname/folder/

Если вы используете инструмент AWS CLI (это хорошо, вам следует), вы можете сделать это следующим образом:

aws s3 ls s3://<bucket_name> | awk '{print $4}' | xargs -L 1 aws s3api restore-object --restore-request Days=<days> --bucket <bucket_name> --key

замещать <bucket_name> с именем ведра вы хотите.

замещать <days> с количеством дней, за которые вы хотите восстановить объект.

Приведенные выше ответы не помогли мне, потому что мое ведро было смешано с объектами на Леднике, а некоторые - нет. Самым простым для меня было создать список всех объектов GLACIER в корзине, а затем попытаться восстановить каждый из них в отдельности, игнорируя любые ошибки (например, уже в процессе, а не объект и т. Д.).

  1. Получить список всех файлов GLACIER (ключей) в корзине

    aws s3api list-objects-v2 --bucket <bucketName> --query "Contents[?StorageClass=='GLACIER']" --output text | awk '{print $2}' > glacier-restore.txt

  2. Создайте сценарий оболочки и запустите его, заменив "bucketName".

    #!/bin/sh
    
    for x in `cat glacier-restore.txt`
      do
        echo "Begin restoring $x"
        aws s3api restore-object --restore-request Days=7 --bucket <bucketName> <bucketName> --key "$x"
        echo "Done restoring $x"
      done
    

Благодарность достается Джошу по адресу http://capnjosh.com/blog/a-client-error-invalidobjectstate-occurred-when-calling-the-copyobject-operation-operation-is-not-valid-for-the-source-objects-storage-class/, ресурс, который я нашел после того, как попробовал некоторые из вышеуказанных решений.

Вот моя версия aws cli интерфейс и как восстановить данные с ледника. Я изменил некоторые из приведенных выше примеров, чтобы они работали, когда в ключе восстанавливаемых файлов содержатся пробелы.

# Parameters
BUCKET="my-bucket" # the bucket you want to restore, no s3:// no slashes
BPATH="path/in/bucket/" # the objects prefix you wish to restore (mind the `/`) 
DAYS=1 # For how many days you wish to restore the data.

# Restore the objects
aws s3 ls s3://{BUCKET}/${BPATH} --recursive | \
awk '{out=""; for(i=4;i<=NF;i++){out=out" "$i}; print out}'| \
xargs -I {} aws s3api restore-object --restore-request Days={DAYS} \
--bucket {BUCKET} --key "{}"

Недавно мне нужно было восстановить целое ведро и все его файлы и папки. Для этого вам потребуются инструменты s3cmd и aws cli, настроенные с вашими учетными данными.

Я нашел это довольно надежным для обработки ошибок с конкретными объектами в корзине, которые, возможно, уже имели запрос на восстановление.

#!/bin/sh

# This will give you a nice list of all objects in the bucket with the bucket name stripped out
s3cmd ls -r s3://<your-bucket-name> | awk '{print $4}' | sed 's#s3://<your-bucket-name>/##' > glacier-restore.txt

for x in `cat glacier-restore.txt`
do
    echo "restoring $x"
    aws s3api restore-object --restore-request Days=7 --bucket <your-bucket-name> --profile <your-aws-credentials-profile> --key "$x"
done

Похоже, что S3 Browser может "восстанавливать из Glacier" на уровне папок, но не на уровне корзины. Единственное, что вы должны купить Pro версию. Так что не лучшее решение.

Вариант ответа Дастина об использовании AWS CLI, но об использовании рекурсии и конвейера, чтобы пропустить ошибки (например, если некоторые объекты уже запросили восстановление...)

BUCKET=my-bucket
BPATH=/path/in/bucket
DAYS=1
aws s3 ls s3://$BUCKET$BPATH --recursive | awk '{print $4}' | xargs -L 1 \
 echo aws s3api restore-object --restore-request Days=$DAYS \
 --bucket $BUCKET --key | sh

Бит эха xargs генерирует список команд "aws s3api restore-object" и, отправив его в sh, вы можете продолжить в случае ошибки.

ПРИМЕЧАНИЕ: пакет Ubuntu 14.04 aws-cli устарел. Для того, чтобы использовать --recursive вам нужно будет установить через github.

POSTSCRIPT: Восстановление Glacier может стать неожиданно дорогим очень быстро. В зависимости от вашего варианта использования уровень "нечастый доступ" может оказаться более подходящим. У AWS есть хорошее объяснение различных уровней.

Если вы еще не верилиrcloneрешает все мировые проблемы (и вряд ли когда-либо будет причина использоватьawsCLI) см. rclone — серверная часть Amazon S3 — восстановление .

Вы захотите использовать это, чтобы избежать написания собственного сценария оболочки, как это делают многие другие ответы.

Пример:

      $ rclone backend restore s3:bucket/path/to/directory -o priority=Standard -o lifetime=90
[
        {
                "Status": "OK",
                "Remote": "needs-deglacierization.txt"
        },
        {
                "Status": "Not GLACIER or DEEP_ARCHIVE storage class",
                "Remote": "already-not-glacierized.txt"
        }
]

Я прошел через эту мельницу сегодня и придумал следующее, основываясь на ответах выше, а также попробовал s3cmd. s3cmd не работает для смешанных сегментов (Glacier и Standard). Это сделает то, что вам нужно, в два шага - сначала создайте список файлов ледника, а затем отключите запросы s3 cli (даже если они уже были). Он также будет отслеживать, какие из них уже были запрошены, чтобы вы могли перезапустить скрипт при необходимости. Следите за TAB (\t) в приведенной ниже команде вырезания:

#/bin/sh

bucket="$1"
glacier_file_list="glacier-restore-me-please.txt"
glacier_file_done="glacier-requested-restore-already.txt"

if [ "X${bucket}" = "X" ]
then
  echo "Please supply bucket name as first argument"
  exit 1
fi

aws s3api list-objects-v2 --bucket ${bucket} --query "Contents[?StorageClass=='GLACIER']" --output text |cut -d '\t' -f 2 > ${glacier_file_list}

if $? -ne 0
then
  echo "Failed to fetch list of objects from bucket ${bucket}"
  exit 1
fi

echo "Got list of glacier files from bucket ${bucket}"

while read x
do
  echo "Begin restoring $x"
  aws s3api restore-object --restore-request Days=7 --bucket ${bucket} --key "$x"

  if [ $? -ne 0 ]
  then
    echo "Failed to restore \"$x\""
  else
    echo "Done requested restore of \"$x\""
  fi

  # Log those done
  #
  echo "$x" >> ${glacier_file_done}

done < ${glacier_file_list}

Может быть, я опоздал всего на десятилетие, чтобы опубликовать ответ, но теперь у нас есть пакетные операции S3 для массового восстановления глубоко заархивированных объектов.Видеть это

Эта команда сработала для меня:

aws s3api list-objects-v2 \
--bucket BUCKET_NAME \
--query "Contents[?StorageClass=='GLACIER']" \
--output text | \
awk -F $'\t' '{print $2}' | \
tr '\n' '\0' | \
xargs -L 1 -0 \
aws s3api restore-object \
--restore-request Days=7 \
--bucket BUCKET_NAME \
--key

ProTip

  • Эта команда может занять некоторое время, если у вас много объектов.
  • Не нажимайте CTRL-C / прерывайте команду, иначе вам придется подождать, пока обработанные объекты выйдут из RestoreAlreadyInProgressсостояние, прежде чем вы сможете его повторно запустить. Переход состояния может занять несколько часов. Вы увидите это сообщение об ошибке, если вам нужно подождать:An error occurred (RestoreAlreadyInProgress) when calling the RestoreObject operation

Я написал программу на Python для рекурсивного восстановления папок. В s3cmd команда выше не сработала для меня, и awk команда.

Вы можете запустить это как python3 /home/ec2-user/recursive_restore.py -- restore и для отслеживания использования статуса восстановления python3 /home/ec2-user/recursive_restore.py -- status

      import argparse
import base64
import json
import os
import sys
from datetime import datetime
from pathlib import Path

import boto3
import pymysql.cursors
import yaml
from botocore.exceptions import ClientError

__author__ = "kyle.bridenstine"


def reportStatuses(
    operation,
    type,
    successOperation,
    folders,
    restoreFinished,
    restoreInProgress,
    restoreNotRequestedYet,
    restoreStatusUnknown,
    skippedFolders,
):
    """
    reportStatuses gives a generic, aggregated report for all operations (Restore, Status, Download)
    """

    report = 'Status Report For "{}" Operation. Of the {} total {}, {} are finished being {}, {} have a restore in progress, {} have not been requested to be restored yet, {} reported an unknown restore status, and {} were asked to be skipped.'.format(
        operation,
        str(len(folders)),
        type,
        str(len(restoreFinished)),
        successOperation,
        str(len(restoreInProgress)),
        str(len(restoreNotRequestedYet)),
        str(len(restoreStatusUnknown)),
        str(len(skippedFolders)),
    )

    if (len(folders) - len(skippedFolders)) == len(restoreFinished):
        print(report)
        print("Success: All {} operations are complete".format(operation))
    else:
        if (len(folders) - len(skippedFolders)) == len(restoreNotRequestedYet):
            print(report)
            print("Attention: No {} operations have been requested".format(operation))
        else:
            print(report)
            print("Attention: Not all {} operations are complete yet".format(operation))


def status(foldersToRestore, restoreTTL):

    s3 = boto3.resource("s3")

    folders = []
    skippedFolders = []

    # Read the list of folders to process
    with open(foldersToRestore, "r") as f:

        for rawS3Path in f.read().splitlines():

            folders.append(rawS3Path)

            s3Bucket = "put-your-bucket-name-here"
            maxKeys = 1000
            # Remove the S3 Bucket Prefix to get just the S3 Path i.e., the S3 Objects prefix and key name
            s3Path = removeS3BucketPrefixFromPath(rawS3Path, s3Bucket)

            # Construct an S3 Paginator that returns pages of S3 Object Keys with the defined prefix
            client = boto3.client("s3")
            paginator = client.get_paginator("list_objects")
            operation_parameters = {"Bucket": s3Bucket, "Prefix": s3Path, "MaxKeys": maxKeys}
            page_iterator = paginator.paginate(**operation_parameters)

            pageCount = 0

            totalS3ObjectKeys = []
            totalS3ObjKeysRestoreFinished = []
            totalS3ObjKeysRestoreInProgress = []
            totalS3ObjKeysRestoreNotRequestedYet = []
            totalS3ObjKeysRestoreStatusUnknown = []

            # Iterate through the pages of S3 Object Keys
            for page in page_iterator:

                for s3Content in page["Contents"]:

                    s3ObjectKey = s3Content["Key"]

                    # Folders show up as Keys but they cannot be restored or downloaded so we just ignore them
                    if s3ObjectKey.endswith("/"):
                        continue

                    totalS3ObjectKeys.append(s3ObjectKey)

                    s3Object = s3.Object(s3Bucket, s3ObjectKey)

                    if s3Object.restore is None:
                        totalS3ObjKeysRestoreNotRequestedYet.append(s3ObjectKey)
                    elif "true" in s3Object.restore:
                        totalS3ObjKeysRestoreInProgress.append(s3ObjectKey)
                    elif "false" in s3Object.restore:
                        totalS3ObjKeysRestoreFinished.append(s3ObjectKey)
                    else:
                        totalS3ObjKeysRestoreStatusUnknown.append(s3ObjectKey)

                pageCount = pageCount + 1

            # Report the total statuses for the folders
            reportStatuses(
                "restore folder " + rawS3Path,
                "files",
                "restored",
                totalS3ObjectKeys,
                totalS3ObjKeysRestoreFinished,
                totalS3ObjKeysRestoreInProgress,
                totalS3ObjKeysRestoreNotRequestedYet,
                totalS3ObjKeysRestoreStatusUnknown,
                [],
            )


def removeS3BucketPrefixFromPath(path, bucket):
    """
    removeS3BucketPrefixFromPath removes "s3a://<bucket name>" or "s3://<bucket name>" from the Path
    """

    s3BucketPrefix1 = "s3a://" + bucket + "/"
    s3BucketPrefix2 = "s3://" + bucket + "/"

    if path.startswith(s3BucketPrefix1):
        # remove one instance of prefix
        return path.replace(s3BucketPrefix1, "", 1)
    elif path.startswith(s3BucketPrefix2):
        # remove one instance of prefix
        return path.replace(s3BucketPrefix2, "", 1)
    else:
        return path


def restore(foldersToRestore, restoreTTL):
    """
    restore initiates a restore request on one or more folders
    """

    print("Restore Operation")

    s3 = boto3.resource("s3")
    bucket = s3.Bucket("put-your-bucket-name-here")

    folders = []
    skippedFolders = []

    # Read the list of folders to process
    with open(foldersToRestore, "r") as f:

        for rawS3Path in f.read().splitlines():

            folders.append(rawS3Path)

            # Skip folders that are commented out of the file
            if "#" in rawS3Path:
                print("Skipping this folder {} since it's commented out with #".format(rawS3Path))
                folders.append(rawS3Path)
                continue
            else:
                print("Restoring folder {}".format(rawS3Path))

            s3Bucket = "put-your-bucket-name-here"
            maxKeys = 1000
            # Remove the S3 Bucket Prefix to get just the S3 Path i.e., the S3 Objects prefix and key name
            s3Path = removeS3BucketPrefixFromPath(rawS3Path, s3Bucket)

            print("s3Bucket={}, s3Path={}, maxKeys={}".format(s3Bucket, s3Path, maxKeys))

            # Construct an S3 Paginator that returns pages of S3 Object Keys with the defined prefix
            client = boto3.client("s3")
            paginator = client.get_paginator("list_objects")
            operation_parameters = {"Bucket": s3Bucket, "Prefix": s3Path, "MaxKeys": maxKeys}
            page_iterator = paginator.paginate(**operation_parameters)

            pageCount = 0

            totalS3ObjectKeys = []
            totalS3ObjKeysRestoreFinished = []
            totalS3ObjKeysRestoreInProgress = []
            totalS3ObjKeysRestoreNotRequestedYet = []
            totalS3ObjKeysRestoreStatusUnknown = []

            # Iterate through the pages of S3 Object Keys
            for page in page_iterator:

                print("Processing S3 Key Page {}".format(str(pageCount)))

                s3ObjectKeys = []
                s3ObjKeysRestoreFinished = []
                s3ObjKeysRestoreInProgress = []
                s3ObjKeysRestoreNotRequestedYet = []
                s3ObjKeysRestoreStatusUnknown = []

                for s3Content in page["Contents"]:

                    print("Processing S3 Object Key {}".format(s3Content["Key"]))

                    s3ObjectKey = s3Content["Key"]

                    # Folders show up as Keys but they cannot be restored or downloaded so we just ignore them
                    if s3ObjectKey.endswith("/"):
                        print("Skipping this S3 Object Key because it's a folder {}".format(s3ObjectKey))
                        continue

                    s3ObjectKeys.append(s3ObjectKey)
                    totalS3ObjectKeys.append(s3ObjectKey)

                    s3Object = s3.Object(s3Bucket, s3ObjectKey)

                    print("{} - {} - {}".format(s3Object.key, s3Object.storage_class, s3Object.restore))

                    # Ensure this folder was not already processed for a restore
                    if s3Object.restore is None:

                        restore_response = bucket.meta.client.restore_object(
                            Bucket=s3Object.bucket_name, Key=s3Object.key, RestoreRequest={"Days": restoreTTL}
                        )

                        print("Restore Response: {}".format(str(restore_response)))

                        # Refresh object and check that the restore request was successfully processed
                        s3Object = s3.Object(s3Bucket, s3ObjectKey)

                        print("{} - {} - {}".format(s3Object.key, s3Object.storage_class, s3Object.restore))

                        if s3Object.restore is None:
                            s3ObjKeysRestoreNotRequestedYet.append(s3ObjectKey)
                            totalS3ObjKeysRestoreNotRequestedYet.append(s3ObjectKey)
                            print("%s restore request failed" % s3Object.key)
                            # Instead of failing the entire job continue restoring the rest of the log tree(s)
                            # raise Exception("%s restore request failed" % s3Object.key)
                        elif "true" in s3Object.restore:
                            print(
                                "The request to restore this file has been successfully received and is being processed: {}".format(
                                    s3Object.key
                                )
                            )
                            s3ObjKeysRestoreInProgress.append(s3ObjectKey)
                            totalS3ObjKeysRestoreInProgress.append(s3ObjectKey)
                        elif "false" in s3Object.restore:
                            print("This file has successfully been restored: {}".format(s3Object.key))
                            s3ObjKeysRestoreFinished.append(s3ObjectKey)
                            totalS3ObjKeysRestoreFinished.append(s3ObjectKey)
                        else:
                            print(
                                "Unknown restore status ({}) for file: {}".format(s3Object.restore, s3Object.key)
                            )
                            s3ObjKeysRestoreStatusUnknown.append(s3ObjectKey)
                            totalS3ObjKeysRestoreStatusUnknown.append(s3ObjectKey)

                    elif "true" in s3Object.restore:
                        print("Restore request already received for {}".format(s3Object.key))
                        s3ObjKeysRestoreInProgress.append(s3ObjectKey)
                        totalS3ObjKeysRestoreInProgress.append(s3ObjectKey)
                    elif "false" in s3Object.restore:
                        print("This file has successfully been restored: {}".format(s3Object.key))
                        s3ObjKeysRestoreFinished.append(s3ObjectKey)
                        totalS3ObjKeysRestoreFinished.append(s3ObjectKey)
                    else:
                        print(
                            "Unknown restore status ({}) for file: {}".format(s3Object.restore, s3Object.key)
                        )
                        s3ObjKeysRestoreStatusUnknown.append(s3ObjectKey)
                        totalS3ObjKeysRestoreStatusUnknown.append(s3ObjectKey)

                # Report the statuses per S3 Key Page
                reportStatuses(
                    "folder-" + rawS3Path + "-page-" + str(pageCount),
                    "files in this page",
                    "restored",
                    s3ObjectKeys,
                    s3ObjKeysRestoreFinished,
                    s3ObjKeysRestoreInProgress,
                    s3ObjKeysRestoreNotRequestedYet,
                    s3ObjKeysRestoreStatusUnknown,
                    [],
                )

                pageCount = pageCount + 1

            if pageCount > 1:
                # Report the total statuses for the files
                reportStatuses(
                    "restore-folder-" + rawS3Path,
                    "files",
                    "restored",
                    totalS3ObjectKeys,
                    totalS3ObjKeysRestoreFinished,
                    totalS3ObjKeysRestoreInProgress,
                    totalS3ObjKeysRestoreNotRequestedYet,
                    totalS3ObjKeysRestoreStatusUnknown,
                    [],
                )


def displayError(operation, exc):
    """
    displayError displays a generic error message for all failed operation's returned exceptions
    """

    print(
        'Error! Restore{} failed. Please ensure that you ran the following command "./tools/infra auth refresh" before executing this program. Error: {}'.format(
            operation, exc
        )
    )


def main(operation, foldersToRestore, restoreTTL):
    """
    main The starting point of the code that directs the operation to it's appropriate workflow
    """

    print(
        "{} Starting log_migration_restore.py with operation={} foldersToRestore={} restoreTTL={} Day(s)".format(
            str(datetime.now().strftime("%d/%m/%Y %H:%M:%S")), operation, foldersToRestore, str(restoreTTL)
        )
    )

    if operation == "restore":
        try:
            restore(foldersToRestore, restoreTTL)
        except Exception as exc:
            displayError("", exc)
    elif operation == "status":
        try:
            status(foldersToRestore, restoreTTL)
        except Exception as exc:
            displayError("-Status-Check", exc)
    else:
        raise Exception("%s is an invalid operation. Please choose either 'restore' or 'status'" % operation)


def check_operation(operation):
    """
    check_operation validates the runtime input arguments
    """

    if operation is None or (
        str(operation) != "restore" and str(operation) != "status" and str(operation) != "download"
    ):
        raise argparse.ArgumentTypeError(
            "%s is an invalid operation. Please choose either 'restore' or 'status' or 'download'" % operation
        )
    return str(operation)


# To run use sudo python3 /home/ec2-user/recursive_restore.py -- restore
# -l /home/ec2-user/folders_to_restore.csv
if __name__ == "__main__":

    # Form the argument parser.
    parser = argparse.ArgumentParser(
        description="Restore s3 folders from archival using 'restore' or check on the restore status using 'status'"
    )

    parser.add_argument(
        "operation",
        type=check_operation,
        help="Please choose either 'restore' to restore the list of s3 folders or 'status' to see the status of a restore on the list of s3 folders",
    )

    parser.add_argument(
        "-l",
        "--foldersToRestore",
        type=str,
        default="/home/ec2-user/folders_to_restore.csv",
        required=False,
        help="The location of the file containing the list of folders to restore. Put one folder on each line.",
    )

    parser.add_argument(
        "-t",
        "--restoreTTL",
        type=int,
        default=30,
        required=False,
        help="The number of days you want the filess to remain restored/unarchived. After this period the logs will automatically be rearchived.",
    )

    args = parser.parse_args()
    sys.exit(main(args.operation, args.foldersToRestore, args.restoreTTL))

Другой способ - это rclone. Этот инструмент может синхронизировать / копировать / Push-данные (как мы могли бы сделать с файлами). https://rclone.org/faq/#can-rclone-sync-directly-from-drive-to-s3 (пример ссылки для Google Drive, но это agnostique). Но, как сказал Майкл - sqlbot, сервер или контейнер должны где-то запустить операцию синхронизации / резервного копирования.

Проблема с этими ответами заключается в том, что они не работают в Windows, поскольку для них требуется awk или стороннее приложение. У меня есть метод, который работает очень хорошо и концептуально довольно просто.

  1. Используйте команду AWS Sync, чтобы получить список файлов, находящихся в хранилище ледника. Команда синхронизации вернет полезный список ошибок.aws s3 sync s3://bucketname/folderpath/ .(Примечание. Не используйте объекты списка aws s3api, как предлагает aws, поскольку команда list-objects ограничена максимум 1000 результатами). Возвращаемые ошибки выглядят следующим образом: предупреждение: пропуск файла s3://bucket/path/filename.txt. Объект имеет класс хранения GLACIER. Невозможно выполнить операции загрузки объектов GLACIER. Чтобы выполнить операцию, необходимо восстановить объект. См. справку по загрузке aws s3, чтобы узнать о дополнительных параметрах, позволяющих игнорировать или принудительно выполнять эти передачи.
  2. Используйте текстовый редактор, чтобы найти/заменить текст и закончить его списком команд восстановления. Оставьте «путь/имя файла», так как это параметр --key. Это займет всего 2 операции поиска/замены. В итоге вы получите список этих команд:aws s3api restore-object --bucket <bucketname> --restore-request Days=25,GlacierJobParameters={"Tier"="Bulk"} --key path/filename1.txt --output text
  3. Поместите это в командный файл и запустите! Подождите, пока AWS получит файлы (это займет несколько часов).
  4. Запустите команду синхронизации и добавьте параметр --force-glacier-transfer, напримерaws s3 sync s3://bucket/path/ . --force-glacier-transfer

Для справки, вот как AWS предлагает это сделать. Я не рекомендую вам следовать их советам: https://repost.aws/knowledge-center/s3-batch-operation-initiate-restore

Это более подробное описание предлагаемого метода: https://schwarzsoftware.com.au/blogentry.php?id=45 .

Другие вопросы по тегам