#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. это сработало. Большое вам спасибо 🙂