in _compile_cloudformation_template.py [0:0]
def main():
in_dir, out_dir, static_asset_s3_prefix = sys.argv[1:4]
static_asset_s3_prefix = static_asset_s3_prefix.strip('/')
# Unfortunately we've had to split our template into multiple configs with the API config at the top so that
# we could get past the 50kb limit of CloudFormation
with TemplateCompiler(
in_dir, out_dir,
'cognito.yml', 'lambda.yml', 'api_gateway.yml', 'api_gateway_lambda_roles.yml') as configs:
cognito_config, lambda_config, api_config, api_lambda_roles_config = configs
paths = {}
for func in base.route.registry.values():
lambda_name = snake_case_to_capitalized_words(func.__name__) + 'Lambda'
# Strip the parameter and return documentation out of the Lambda description as this confuses Lambda
lambda_description = ''
if func.__doc__:
for line in func.__doc__.splitlines():
line = line.strip()
if (':param' or ':return') in line:
break
if line:
lambda_description += f'{line} '
# Generate Lambda Resources
lambda_config['Resources'][lambda_name] = {
'Type': 'AWS::Lambda::Function',
'Properties': {
'Code': './build',
'Description': lambda_description,
'Environment': {
'Variables': {
'APP_CLIENT_ID': Ref('CognitoUserPoolClient'),
'USER_POOL_ID': Ref('CognitoUserPool'),
'PARTICIPANT_TABLE': Ref('participantDynamoDBTable'),
'WHEEL_TABLE': Ref('wheelDynamoDBTable'),
}
},
'Handler': f"{func.__module__}.{func.__name__}",
'MemorySize': 128,
'Role': GetAtt('AWSOpsWheelLambdaRole.Arn'),
'Runtime': 'python3.9',
'Timeout': 3
}
}
path = f'/api/{func.route.path.lstrip("/")}'
paths.setdefault(path, {})
for method in func.route.methods:
paths[path][method.lower()] = make_api_path_config(lambda_name, func.route.path)
stripped_path = path.lstrip('/')
api_lambda_roles_config['Resources'][f"{lambda_name}GatewayPermissions{method}"] = {
'Type': 'AWS::Lambda::Permission',
'Properties': {
'Action': 'lambda:invokeFunction',
'FunctionName': Ref(lambda_name),
'Principal': 'apigateway.amazonaws.com',
'SourceArn': {'Fn::Join': ['', [
'arn:aws:execute-api:',
Ref('AWS::Region'),
':',
Ref('AWS::AccountId'),
':',
Ref("AWSOpsWheelAPI"),
f"/*/{method.upper()}/{stripped_path}",
]]},
}
}
paths['/favicon.ico'] = {'get': {
'produces': [ 'image/x-icon' ],
'responses': {
'200': {
'description': '200 response',
'schema': {
'$ref': '#/definitions/Empty'
},
'headers': {
'Content-Length': {
'type': 'string'
},
'Content-Type': {
'type': 'string'
}
}
}
},
'x-amazon-apigateway-integration': {
'responses': {
'default': {
'statusCode': '200',
'responseParameters': {
'method.response.header.Content-Type': 'integration.response.header.Content-Type',
'method.response.header.Content-Length': 'integration.response.header.Content-Length'
},
'contentHandling': 'CONVERT_TO_BINARY'
}
},
'uri': f'{static_asset_s3_prefix}/favicon.ico',
'passthroughBehavior': 'when_no_match',
'httpMethod': 'GET',
'contentHandling': 'CONVERT_TO_BINARY',
'type': 'http'
}
}}
paths['/static/{proxy+}'] = {'x-amazon-apigateway-any-method': {
'parameters': [{'in': 'path', 'name': 'proxy', 'required': True, 'type': 'string'}],
'produces': ['application/json'],
'responses': {},
'x-amazon-apigateway-integration': {
'cacheKeyParameters': ['method.request.path.proxy'],
'cacheNamespace': 'static_assets',
'httpMethod': 'ANY',
'passthroughBehavior': 'when_no_match',
'requestParameters': {'integration.request.path.proxy': 'method.request.path.proxy'},
'responses': {'default': {'statusCode': '200'}},
'type': 'http_proxy',
'uri': f'{static_asset_s3_prefix}/{{proxy}}',
'contentHandling': 'CONVERT_TO_BINARY'}
}}
paths['/'] = {'x-amazon-apigateway-any-method': {
'parameters': [],
'produces': ['application/json'],
'responses': {},
'x-amazon-apigateway-integration': {
'httpMethod': 'ANY',
'passthroughBehavior': 'when_no_match',
'requestParameters': {},
'responses': {'default': {'statusCode': '200'}},
'type': 'http_proxy',
'uri': f'{static_asset_s3_prefix}/index.production.html'}
}}
paths['/{proxy+}'] = {'x-amazon-apigateway-any-method': {
'parameters': [{'in': 'path', 'name': 'proxy', 'required': False, 'type': 'string'}],
'produces': ['application/json'],
'responses': {},
'x-amazon-apigateway-integration': {
'cacheKeyParameters': ['method.request.path.proxy'],
'cacheNamespace': 'static_assets',
'httpMethod': 'ANY',
'passthroughBehavior': 'when_no_match',
'requestParameters': {'integration.request.path.proxy': 'method.request.path.proxy'},
'responses': {'default': {'statusCode': '200'}},
'type': 'http_proxy',
'uri': f'{static_asset_s3_prefix}/index.production.html'}
}}
api_config['Resources']['AWSOpsWheelAPI']['Properties']['Body'] = {
'schemes': ['https'],
'swagger': '2.0',
'info': {'title': 'AWSOpsWheel', 'version': '0.1'},
'definitions': {
'Empty': {'title': 'Empty Schema', 'type': 'object'}
},
'x-amazon-apigateway-binary-media-types': ['audio/mpeg', 'audio/*', 'image/x-icon', 'application/font*', 'font/*'],
'basePath': '/',
'paths': paths,
'securityDefinitions': {
'apiUsers': {
'type': 'apiKey',
'name': 'Authorization',
'in': 'header',
'x-amazon-apigateway-authtype': 'cognito_user_pools',
'x-amazon-apigateway-authorizer': {
'type': 'COGNITO_USER_POOLS',
'providerARNs': [Ref('CognitoUserPoolArn')]
}
}
}
}