чтение файлов, вызванное событием s3

Вот что я хочу сделать:

  1. Пользователь загружает CSV-файл в корзину AWS S3.
  2. После загрузки файла ведро S3 вызывает созданную мной лямбда-функцию.
  3. Моя лямбда-функция считывает содержимое файла csv, а затем отправляет электронное письмо с содержимым файла и информацией

Местная среда

Бессерверный фреймворк версии 1.22.0

Python 2.7

Вот мой файл serverless.yml

service: aws-python # NOTE: update this with your service name

provider:
  name: aws
  runtime: python2.7
  stage: dev
  region: us-east-1
  iamRoleStatements:
        - Effect: "Allow"
          Action:
              - s3:*
              - "ses:SendEmail"
              - "ses:SendRawEmail"
              - "s3:PutBucketNotification"
          Resource: "*"

functions:
  csvfile:
    handler: handler.csvfile
    description: send mail whenever a csv file is uploaded on S3 
    events:
      - s3:
          bucket: mine2
          event: s3:ObjectCreated:*
          rules:
            - suffix: .csv

и вот моя лямбда-функция:

import json
import boto3
import botocore
import logging
import sys
import traceback
import csv

from botocore.exceptions import ClientError
from pprint import pprint
from time import strftime, gmtime
from json import dumps, loads, JSONEncoder, JSONDecoder


#setup simple logging for INFO
logger = logging.getLogger()
logger.setLevel(logging.INFO)

from botocore.exceptions import ClientError

def csvfile(event, context):
    """Send email whenever a csvfile is uploaded to S3 """
    body = {}
    emailcontent = ''
    status_code = 200
    #set email information
    email_from = '****@*****.com'
    email_to = '****@****.com'
    email_subject = 'new file is uploaded'
    try:
        s3 = boto3.resource(u's3')
        s3 = boto3.client('s3')
        for record in event['Records']:
            filename = record['s3']['object']['key']
            filesize = record['s3']['object']['size']
            source = record['requestParameters']['sourceIPAddress']
            eventTime = record['eventTime']
        # get a handle on the bucket that holds your file
        bucket = s3.Bucket(u'mine2')
        # get a handle on the object you want (i.e. your file)
        obj = bucket.Object(key= event[u'Records'][0][u's3'][u'object'][u'key'])
        # get the object
        response = obj.get()
        # read the contents of the file and split it into a list of lines
        lines = response[u'Body'].read().split()
        # now iterate over those lines
        for row in csv.DictReader(lines):    
            print(row)
            emailcontent = emailcontent + '\n' + row 
    except Exception as e:
        print(traceback.format_exc())
        status_code = 500
        body["message"] = json.dumps(e)

    email_body = "File Name: " + filename + "\n" + "File Size: " + str(filesize) + "\n" +  "Upload Time: " + eventTime + "\n" + "User Details: " + source + "\n" + "content of the csv file :" + emailcontent
    ses = boto3.client('ses')
    ses.send_email(Source = email_from,
        Destination = {'ToAddresses': [email_to,],}, 
            Message = {'Subject': {'Data': email_subject}, 'Body':{'Text' : {'Data': email_body}}}
            )
    print('Function execution Completed')

Я не знаю, что я сделал не так, потому что часть, когда я просто получаю информацию о файле, работает нормально, когда я добавляю часть чтения, лямбда-функция ничего не возвращает


person ner    schedule 25.10.2017    source источник


Ответы (1)


Предлагаю добавить в вашу политику IAM еще и доступ к Cloudwatch. На самом деле ваша лямбда-функция ничего не возвращает, но вы можете увидеть вывод журнала в Cloudwatch. Я действительно рекомендую использовать logger.info(message) вместо print при настройке logger.

Я надеюсь, что это поможет отладить вашу функцию.

За исключением части отправки, я ее перепишу следующим образом (только что протестировал в консоли AWS):

import logging
import boto3

logger = logging.getLogger()
logger.setLevel(logging.INFO)

s3 = boto3.client('s3')

def lambda_handler(event, context):
    email_content = ''

    # retrieve bucket name and file_key from the S3 event
    bucket_name = event['Records'][0]['s3']['bucket']['name']
    file_key = event['Records'][0]['s3']['object']['key']
    logger.info('Reading {} from {}'.format(file_key, bucket_name))
    # get the object
    obj = s3.get_object(Bucket=bucket_name, Key=file_key)
    # get lines inside the csv
    lines = obj['Body'].read().split(b'\n')
    for r in lines:
       logger.info(r.decode())
       email_content = email_content + '\n' + r.decode()
    logger.info(email_content)
person nicor88    schedule 25.10.2017
comment
эй, братан, это действительно помогло, большое спасибо, я получил ответ, на самом деле в моем коде я написал два s3 ​​= boto3.resource (u's3 ') s3 = boto3.client (' s3 ') это был ошибка. - person ner; 25.10.2017
comment
Небольшое улучшение - лучше инициализировать соединения с базой данных, SDK и т. Д. Вне функции обработчика (на глобальном уровне). Служба Lambda сохраняет контекст функции, поэтому последующие вызовы выполняются намного быстрее - подробнее на: docs.aws.amazon.com/lambda/latest/dg/best-practices.html - person jpact; 26.03.2018
comment
Хороший момент, я перенес инициализацию клиента s3 за пределы обработчика лямбда - person nicor88; 06.04.2018