Я видел несколько похожих постов, но, к сожалению, ни один мне не помог. У меня есть ведро s3 (на шкале масштабирования), и я пытаюсь просто перечислить все объекты, содержащиеся в этом ведре, используя клиент boto3 s3 следующим образом:

s3 = boto3.client('s3',
                  region_name=AWS_S3_REGION_NAME,
                  endpoint_url=AWS_S3_ENDPOINT_URL,
                  aws_access_key_id=AWS_ACCESS_KEY_ID,
                  aws_secret_access_key=AWS_SECRET_ACCESS_KEY
                  )

all_objects = s3.list_objects_v2(Bucket=AWS_STORAGE_BUCKET_NAME)

Этот простой фрагмент кода отвечает ошибкой:

botocore.errorfactory.NoSuchKey: An error occurred (NoSuchKey) when calling the ListObjects operation: The specified key does not exist.

Во-первых, ошибка мне кажется неуместной, поскольку я не указываю ключ для поиска. Я также попытался передать аргумент Prefix этому методу, чтобы сузить поиск до определенного подкаталога, та же ошибка. Во-вторых, я попытался добиться того же, используя boto3 Resource, а не Client, как показано ниже:

session = boto3.Session(
    region_name=AWS_S3_REGION_NAME,
    aws_access_key_id=AWS_ACCESS_KEY_ID,
    aws_secret_access_key=AWS_SECRET_ACCESS_KEY
)
resource = session.resource(
    's3',
    endpoint_url=AWS_S3_ENDPOINT_URL,
)

for bucket in resource.buckets.all():
    print(bucket.name)

Этот код абсолютно ничего не производит. Меня поражает одна странность: я нигде не передаю bucket_name, что, согласно документация по aws

Нет никаких шансов, что я неправильно сконфигурировал клиента, поскольку я могу идеально использовать метод put_object с тем же самым клиентом. Одна странность: когда я хочу поместить файл, я передаю весь путь к put_object как Key (как я обнаружил, это путь), но объект вставляется вместе с ведром имя добавляется к нему. Допустим, я вызываю put_object(Key='/path/to/myfile.ext'), объект будет /bucket-name/path/to/myfile.ext.

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

Спасибо

РЕДАКТИРОВАТЬ: Итак, после регистрации запроса, который отправляет клиент boto3, я заметил, что имя сегмента добавляется к URL-адресу, поэтому вместо запроса https://<bucket_name>.s3.<region>.<provider>/ он запрашивает https://<bucket_name>.s3.<region>.<provider>/<bucket-name>/, что является что приводит к ошибке NoSuchKey. Я заглянул в библиотеку botocore и обнаружил следующее:

url = _urljoin(endpoint_url, r['url_path'], host_prefix)

В botocore.awsrequest строке 252, где r['url_path'] содержит /skichic-bucket?list-type=2. Итак, отсюда я смогу легко исправить ядро ​​библиотеки, чтобы оно работало для меня.

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

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

Кто-нибудь может объяснить всю эту неразбериху? >. <

0
elachere 11 Ноя 2020 в 17:30

2 ответа

Лучший ответ

Присмотревшись к деталям, я обнаружил, что (многие) шаблоны конечных точек служб botocore начинаются с имени сегмента. Например, вот определение службы list_objects_v2:

"ListObjectsV2":{
      "name":"ListObjectsV2",
      "http":{
        "method":"GET",
        "requestUri":"/{Bucket}?list-type=2"
      },

Я предполагаю, что в стандартной реализации AWS S3 есть общий endpoint_url (который объясняет @jordanm комментарий ) и целевой сегмент достигается через конечную точку.

Теперь, в случае Scaleway, для каждого сегмента есть endpoint_url с именем сегмента, содержащимся в этом URL-адресе (например, https://<bucket_name>.s3.<region>.<provider>), и любая конечная точка должна напрямую начинаться с сегмента Key .

Я сделал вилку botocore, где я переписал каждую конечную точку, чтобы удалить имя корзины, если что может помочь кому-то в будущем.

Еще раз спасибо всем участникам!

0
elachere 16 Ноя 2020 в 10:40

Вы можете попробовать это. вам придется использовать свой ресурс вместо моего s3sr.

s3sr = resource('s3')
bucket = 'your-bucket'
prefix = 'your-prefix/' # if no prefix, pass ''

def get_keys_from_prefix(bucket, prefix):
    '''gets list of keys for given bucket and prefix'''
    keys_list = []
    paginator = s3sr.meta.client.get_paginator('list_objects_v2')
    # use Delimiter to limit search to that level of hierarchy
    for page in paginator.paginate(Bucket=bucket, Prefix=prefix, Delimiter='/'):
        keys = [content['Key'] for content in page.get('Contents')]
        print('keys in page: ', len(keys))
        keys_list.extend(keys)
    return keys_list

keys_list = get_keys_from_prefix(bucket, prefix)
0
Jonathan Leon 13 Ноя 2020 в 05:02