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')
.