Home > Software design >  python3(lambda function) failing to send response back to cloud formation template
python3(lambda function) failing to send response back to cloud formation template

Time:11-02

I have created a cloud formation template for cross s3-bucket object replication using lambda which is written in python, Below is the lambda code.

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)

the s3 objects are getting copied to the destination bucket successfully, but the lambda function is failing to send event responses back to cloud formation. below is the error Im getting.

[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 function getting failed with the above error, please help where it's going wrong.

CodePudding user response:

The error message is telling you what's wrong.

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

In your code, response_body is a str. You can convert it to bytes by doing response_body.encode('utf-8').

  • Related