123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- import os
- import boto3
- import mimetypes
- import json
- import requests
- import subprocess
- import tempfile
- import pathlib
- import shutil
- s3 = boto3.resource('s3')
- defaultContentType = 'application/octet-stream'
- def resource_handler(event, context):
- print(event)
- try:
- target_bucket = event['ResourceProperties']['TargetBucket']
- lambda_src = os.getcwd()
- acl = event['ResourceProperties']['Acl']
- cacheControl = 'max-age=' + \
- event['ResourceProperties']['CacheControlMaxAge']
- print(event['RequestType'])
- if event['RequestType'] == 'Create' or event['RequestType'] == 'Update':
-
- if 'Substitutions' in event['ResourceProperties'].keys():
- temp_dir = os.path.join(tempfile.mkdtemp(), context.aws_request_id)
- apply_substitutions(event['ResourceProperties']['Substitutions'], temp_dir)
- lambda_src = temp_dir
- print('uploading')
- upload(lambda_src, target_bucket, acl, cacheControl)
- elif event['RequestType'] == 'Delete':
- delete(lambda_src, target_bucket, s3)
- else:
- print('ignoring')
- if not lambda_src == os.getcwd():
- print('removing temporary', lambda_src)
- shutil.rmtree(lambda_src)
- send_result(event)
- except Exception as err:
- send_error(event, err)
- return event
- def upload(lambda_src, target_bucket, acl, cacheControl):
- for folder, subs, files in os.walk(lambda_src):
- for filename in files:
- source_file_path = os.path.join(folder, filename)
- destination_s3_key = os.path.relpath(source_file_path, lambda_src)
- contentType, encoding = mimetypes.guess_type(source_file_path)
- upload_file(source_file_path, target_bucket,
- destination_s3_key, s3, acl, cacheControl, contentType)
- def upload_file(source, bucket, key, s3lib, acl, cacheControl, contentType):
- print('uploading from {} {} {}'.format(source, bucket, key))
- contentType = contentType or defaultContentType
- s3lib.Object(bucket, key).put(ACL=acl, Body=open(source, 'rb'),
- CacheControl=cacheControl, ContentType=contentType)
- def delete(lambda_src, target_bucket, s3lib):
- for folder, subs, files in os.walk(lambda_src):
- for filename in files:
- source_file_path = os.path.join(folder, filename)
- destination_s3_key = os.path.relpath(source_file_path, lambda_src)
- print('deleting file {} from {}'.format(destination_s3_key, target_bucket))
- s3lib.Object(target_bucket, destination_s3_key).delete()
- def send_result(event):
- response_body = json.dumps({
- 'Status': 'SUCCESS',
- 'PhysicalResourceId': get_physical_resource_id(event),
- 'StackId': event['StackId'],
- 'RequestId': event['RequestId'],
- 'LogicalResourceId': event['LogicalResourceId']
- })
- print(response_body)
- requests.put(event['ResponseURL'], data=response_body)
- def send_error(event, error):
- response_body = json.dumps({
- 'Status': 'FAILED',
- 'Reason': str(error),
- 'PhysicalResourceId': get_physical_resource_id(event),
- 'StackId': event['StackId'],
- 'RequestId': event['RequestId'],
- 'LogicalResourceId': event['LogicalResourceId']
- })
- print(response_body)
- requests.put(event['ResponseURL'], data=response_body)
- def get_physical_resource_id(event):
- if 'PhysicalResourceId' in event.keys():
- return event['PhysicalResourceId']
- else:
- return event['RequestId']
- def apply_substitutions(substitutions, temp_dir):
- if not 'Values' in substitutions.keys():
- raise ValueError('Substitutions must contain Values')
- if not isinstance(substitutions['Values'], dict):
- raise ValueError('Substitutions.Values must be an Object')
- if len(substitutions['Values']) < 1:
- raise ValueError('Substitutions.Values must not be empty')
- if not 'FilePattern' in substitutions.keys():
- raise ValueError('Substitutions must contain FilePattern')
- if not isinstance(substitutions['FilePattern'], str):
- raise ValueError('Substitutions.FilePattern must be a String')
- if len(substitutions['FilePattern']) < 1:
- raise ValueError('Substitutions.FilePattern must not be empty')
- values = substitutions['Values']
- file_pattern = substitutions['FilePattern']
- subprocess.run(['cp', '-r', os.getcwd(), temp_dir])
- for full_path in pathlib.Path(temp_dir).glob(file_pattern):
- replace_with_command = lambda key: 's/\\${%s}/%s/g'% (sed_escape(key), sed_escape(values[key]))
- replacements = list(map(replace_with_command, values.keys()))
- sed_script = ';'.join(replacements)
- subprocess.run(['sed', sed_script, '-i', str(full_path)], cwd=tempfile.gettempdir(), check=True)
- def sed_escape(text):
- return text.replace('/', '\\/')
|