Невозможно скачать_файл из S3 в лямбду после уведомления о создании объекта S3 - PullRequest
0 голосов
/ 30 декабря 2018

Я настроил SES, чтобы поместить несколько писем в корзину S3 и установить триггер S3 для запуска лямбда-функции на созданном объекте.В лямбде мне нужно разобрать и обработать письмо.Вот моя лямбда (соответствующая часть):

s3client = boto3.client('s3')
def lambda_handler(event, context):
    my_bucket = s3.Bucket(‘xxxxxxxx')
    my_key = event['Records'][0]['s3']['object']['key']
    filename = '/tmp/'+ my_key
    logger.info('Target file: ' + filename)
    s3client.download_file(my_bucket, my_key, filename)
#   Process email file

download_file выдает исключение:

expected string or bytes-like object: TypeError


Traceback (most recent call last):
File "/var/task/lambda_function.py", line 22, in lambda_handler
s3client.download_file(my_bucket, my_key, filename)

...

File "/var/runtime/botocore/handlers.py", line 217, in validate_bucket_name
if VALID_BUCKET.search(bucket) is None:
TypeError: expected string or bytes-like object

Есть идеи, что не так?Ведро в порядке, объект существует в ведре.

Ответы [ 2 ]

0 голосов
/ 31 декабря 2018

Ошибка связана с именем корзины (и в вашем коде есть странная фигурная кавычка).

рекомендуемый рекомендуемый способ получения сведений об объекте:

for record in event['Records']:
    bucket = record['s3']['bucket']['name']
    key = record['s3']['object']['key']
    ...
    s3_client.download_file(bucket, key, download_path)
0 голосов
/ 30 декабря 2018

Редактировать: мой первый ответ был, вероятно, неправильным, вот еще одна попытка

Функцию проверки, которая вызывает исключение, можно найти здесь

# From the S3 docs:
# The rules for bucket names in the US Standard region allow bucket names
# to be as long as 255 characters, and bucket names can contain any
# combination of uppercase letters, lowercase letters, numbers, periods
# (.), hyphens (-), and underscores (_).
VALID_BUCKET = re.compile(r'^[a-zA-Z0-9.\-_]{1,255}$')

# [I excluded unrelated code here]

def validate_bucket_name(params, **kwargs):
    if 'Bucket' not in params:
        return
    bucket = params['Bucket']
    if VALID_BUCKET.search(bucket) is None:
        error_msg = (
            'Invalid bucket name "%s": Bucket name must match '
            'the regex "%s"' % (bucket, VALID_BUCKET.pattern))
        raise ParamValidationError(report=error_msg)

boto3 использует S3Transfer Download Manager, который затем использует метод download, который определяется как следует :

def download(self, bucket, key, fileobj, extra_args=None,
             subscribers=None):
    """Downloads a file from S3
    :type bucket: str
    :param bucket: The name of the bucket to download from
...

Он ожидает, что параметр bucketбыть строкой, и вы передаете объект s3.Bucket(‘xxxxxxxx'), который, вероятно, не является строкой.

Я бы попытался передать имя сегмента download_file в виде строки.


Старый и, скорее всего, неправильный ответ, как указано в комментариях

Пример кода в документации Boto показывает нам, какзагрузка с S3 может быть выполнена:

import boto3
import botocore

BUCKET_NAME = 'my-bucket' # replace with your bucket name
KEY = 'my_image_in_s3.jpg' # replace with your object key

s3 = boto3.resource('s3')

try:
    s3.Bucket(BUCKET_NAME).download_file(KEY, 'my_local_image.jpg')
except botocore.exceptions.ClientError as e:
    if e.response['Error']['Code'] == "404":
        print("The object does not exist.")
    else:
        raise

Глядя на ваш код, кажется, что вы вызываете метод download_file неправильно, он должен выглядеть следующим образом - вам нужно вызвать методна объекте-ковше:

s3client = boto3.client('s3')
def lambda_handler(event, context):
    my_bucket = s3.Bucket(‘xxxxxxxx')
    my_key = event['Records'][0]['s3']['object']['key']
    filename = '/tmp/'+ my_key
    logger.info('Target file: ' + filename)
    my_bucket.download_file(my_key, filename)
#   Process email file

Важная часть my_bucket.download_file(my_key, filename)

...