python3(лямбда-функция) не удается отправить ответ обратно в шаблон формирования облака

#amazon-web-services #aws-lambda #urllib2 #python-3.8 #aws-cloudformation-custom-resource

Вопрос:

Я создал шаблон формирования облака для перекрестной репликации объектов в сегменте s3 с использованием лямбда-кода, написанного на python, ниже приведен лямбда-код.

 import json
import logging
import signal
import boto3
from urllib.request import *
s3 = boto3.resource('s3')
s3client = boto3.client('s3')
LOGGER = logging.getLogger()
LOGGER.setLevel(logging.INFO)
def lambda_handler(event, context):
  sourcebucketname = event['ResourceProperties']['SourceBucketName']
  destinationbucketname = event['ResourceProperties']['DestinationBucketName']
 
  accountid = boto3.client('sts').get_caller_identity()['Account']
  try:
      LOGGER.info('REQUEST RECEIVED:n %s', event)
      LOGGER.info('REQUEST RECEIVED:n %s', context)
      if event['RequestType'] == 'Create':
          LOGGER.info('CREATE!')
          response = s3client.list_objects(Bucket=sourcebucketname)
          print(response)
          for record in response['Contents']:
              key = record['Key']
              dest_key = key
              copy_source = {'Bucket': sourcebucketname, 'Key': key}
              destbucket = s3.Bucket(destinationbucketname)
              response = destbucket.copy(copy_source, dest_key, ExtraArgs={'ACL':'bucket-owner-full-control'})
              print(response)
              print('{} transferred to destination bucket'.format(key))
          send_response(event, context, "SUCCESS",
                        {"Message": "Resource creation successful!"})
      elif event['RequestType'] == 'Update':
          LOGGER.info('UPDATE!')
         
          send_response(event, context, "SUCCESS",
                        {"Message": "Resource update successful!"})
      elif event['RequestType'] == 'Delete':
          LOGGER.info('DELETE!')
          send_response(event, context, "SUCCESS",
                        {"Message": "Resource deletion successful!"})
      else:
          LOGGER.info('FAILED!')
          send_response(event, context, "FAILED",
                        {"Message": "Unexpected event received from CloudFormation"})
  except: #pylint: disable=W0702
      LOGGER.info('FAILED!')
      send_response(event, context, "FAILED", {
          "Message": "Exception during processing"})
def send_response(event, context, response_status, response_data):
  '''Send a resource manipulation status response to CloudFormation'''
  response_body = json.dumps({
      "Status": response_status,
      "Reason": "See the details in CloudWatch Log Stream: "   context.log_stream_name,
      "PhysicalResourceId": context.log_stream_name,
      "StackId": event['StackId'],
      "RequestId": event['RequestId'],
      "LogicalResourceId": event['LogicalResourceId'],
      "Data": response_data
  })
  response_bdy=response_body.encode('utf-8')
  LOGGER.info('ResponseURL: %s', event['ResponseURL'])
  LOGGER.info('ResponseBody: %s', response_body)
  opener = build_opener(HTTPHandler)
  request = Request(event['ResponseURL'], data=response_bdy)
  request.add_header('Content-Type', '')
  request.add_header('Content-Length', len(response_body))
  request.get_method = lambda: 'PUT'
  response = opener.open(request)
  LOGGER.info("Status code: %s", response.getcode())
  LOGGER.info("Status message: %s", response.msg)
 

объекты s3 успешно копируются в корзину назначения, но функция lambda не может отправлять ответы на события обратно в облако. ниже приведена ошибка, которую я получаю.

 [ERROR] TypeError: POST data should be bytes, an iterable of bytes, or a file object. It cannot be of type str.
Traceback (most recent call last):
  File "/var/task/index.py", line 47, in lambda_handler
    send_response(event, context, "FAILED", {
  File "/var/task/index.py", line 69, in send_response
    response = opener.open(request)
  File "/var/lang/lib/python3.9/urllib/request.py", line 514, in open
    req = meth(req)
  File "/var/lang/lib/python3.9/urllib/request.py", line 1277, in do_request_
    raise TypeError(msg)
[ERROR] TypeError: POST data should be bytes, an iterable of bytes, or a file object. It cannot be of type str. Traceback (most recent call last):   File "/var/task/index.py", line 47, in lambda_handler     send_response(event, context, "FAILED", {   File "/var/task/index.py", line 69, in send_response     response = opener.open(request)   File "/var/lang/lib/python3.9/urllib/request.py", line 514, in open     req = meth(req)   File "/var/lang/lib/python3.9/urllib/request.py", line 1277, in do_request_     raise TypeError(msg)
 

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

Ответ №1:

Сообщение об ошибке говорит вам, что не так.

 [ERROR] TypeError: POST data should be bytes, an iterable of bytes, or a file object. It cannot be of type str.
 

В вашем коде response_body это a str . Вы можете преобразовать его в bytes , выполнив response_body.encode('utf-8') .

Комментарии:

1. Спасибо, @Noel Llevares, я закодировал тело ответа, как вы предложили, но теперь я получаю еще одну ошибку. [ERROR] TypeError: 'str' object is not callable Traceback (most recent call last):   File "/var/task/index.py", line 47, in lambda_handler     send_response(event, context, "FAILED", {   File "/var/task/index.py", line 69, in send_response     LOGGER.info("Status message: %s", response.msg()) Я отредактировал вопрос и добавил изменения.

2. Это не имеет отношения к моему предложению. Но постарайся response.msg не response.msg() в своей последней строчке.

3. @Neol Llevares, я собирался отредактировать это, да, я исправил ответ.msg. это сработало. Большое вам спасибо 🙂