def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) api_log_group = cwlogs.LogGroup(self, "HelloWorldAPILogs") # Create the api gateway for this lambda set self.target_api = apigw.RestApi( self, 'HelloWorldAPI', rest_api_name='HelloWorld', endpoint_types=[apigw.EndpointType.REGIONAL], deploy_options={ "access_log_destination": apigw.LogGroupLogDestination(api_log_group), "access_log_format": apigw.AccessLogFormat.clf(), "method_options": { "/*/*": { # This special path applies to all resource paths and all HTTP methods "throttling_rate_limit": 100, "throttling_burst_limit": 200 } } }) hello_world = py_lambda.PythonFunction( self, "HelloWorld", entry='thewafapigateway/lambda_fns', index='helloworld.py', handler='lambda_handler', description='Helloworld', timeout=core.Duration.seconds(60)) entity = self.target_api.root.add_resource('helloworld') this_lambda_integration = apigw.LambdaIntegration( hello_world, proxy=False, integration_responses=[{ 'statusCode': '200', 'responseParameters': { 'method.response.header.Access-Control-Allow-Origin': "'*'", } }]) method = entity.add_method( 'GET', this_lambda_integration, method_responses=[{ 'statusCode': '200', 'responseParameters': { 'method.response.header.Access-Control-Allow-Origin': True, } }]) self.resource_arn = f"arn:aws:apigateway:ap-southeast-2::/restapis/{self.target_api.rest_api_id}/stages/{self.target_api.deployment_stage.stage_name}"
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) api_log_group = cw_logs.LogGroup(self, "HelloWorldAPILogs") # Create the api gateway for this lambda set self.target_api = api_gw.RestApi( self, 'HelloWorldAPI', rest_api_name='HelloWorld', endpoint_types=[api_gw.EndpointType.REGIONAL], deploy_options=api_gw.StageOptions( access_log_destination=api_gw.LogGroupLogDestination( api_log_group), access_log_format=api_gw.AccessLogFormat.clf(), method_options={ # This special path applies to all resource paths and all HTTP methods "/*/*": api_gw.MethodDeploymentOptions(throttling_rate_limit=100, throttling_burst_limit=200) })) hello_world = _lambda.Function( self, "HelloWorld", runtime=_lambda.Runtime.PYTHON_3_8, handler='helloworld.lambda_handler', code=_lambda.Code.from_asset("lambda_fns"), timeout=core.Duration.seconds(60)) entity = self.target_api.root.add_resource('helloworld') this_lambda_integration = api_gw.LambdaIntegration( hello_world, proxy=False, integration_responses=[ api_gw.IntegrationResponse( status_code='200', response_parameters={ 'method.response.header.Access-Control-Allow-Origin': "'*'" }) ]) entity.add_method( 'GET', this_lambda_integration, method_responses=[ api_gw.MethodResponse( status_code='200', response_parameters={ 'method.response.header.Access-Control-Allow-Origin': True }) ]) self.resource_arn = f"arn:aws:apigateway:{core.Stack.of(self).region}::/restapis/{self.target_api.rest_api_id}/stages/{self.target_api.deployment_stage.stage_name}"
def __init__(self, scope: cdk.Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) # Lambda function hello_function = lambda_.Function( self, "hello-function", code=lambda_.Code.from_asset("src/hello/"), handler="main.handler", runtime=lambda_.Runtime.PYTHON_3_8, tracing=lambda_.Tracing.ACTIVE) logs.LogGroup( self, "hello-logs", log_group_name=f"/aws/lambda/{hello_function.function_name}", retention=logs.RetentionDays.ONE_WEEK) # API Gateway api_logs = logs.LogGroup(self, "hello-api-logs", retention=logs.RetentionDays.ONE_WEEK) api = apigw.RestApi( self, "hello-api", deploy_options=apigw.StageOptions( access_log_destination=apigw.LogGroupLogDestination(api_logs), access_log_format=apigw.AccessLogFormat. json_with_standard_fields(caller=True, http_method=True, ip=True, protocol=True, request_time=True, resource_path=True, response_length=True, status=True, user=True), throttling_burst_limit=1000, throttling_rate_limit=10, tracing_enabled=True)) hello_integration = apigw.LambdaIntegration(hello_function, proxy=True) api.root.add_method("GET", hello_integration)
def __init__( self, scope: core.Construct, id: str, webhook_function, on_demand_function, schedule_update_function, status_query_function, slack_function, ingest_allowed_ips, ): super().__init__(scope, id) stack_name = core.Stack.of(self).stack_name policy = iam.PolicyDocument( statements=[ iam.PolicyStatement( effect=iam.Effect.ALLOW, actions=["execute-api:Invoke"], principals=[iam.AnyPrincipal()], # note that the policy is a prop of the api which cannot # reference itself, see the Cloudformation documentation # for api gateway policy attribute resources=[core.Fn.join("", ["execute-api:/", "*"])], ), iam.PolicyStatement( effect=iam.Effect.DENY, actions=["execute-api:Invoke"], principals=[iam.AnyPrincipal()], resources=[ core.Fn.join("", ["execute-api:/", "*/POST/ingest"]), core.Fn.join("", ["execute-api:/", "*/GET/status"]), ], conditions={ "NotIpAddress": {"aws:SourceIp": ingest_allowed_ips} }, ), ] ) self.rest_api_name = f"{stack_name}-{names.REST_API}" log_group = logs.LogGroup( self, "apilogs", log_group_name=f"/aws/apigateway/{self.rest_api_name}/access_logs", removal_policy=core.RemovalPolicy.DESTROY, retention=logs.RetentionDays.SIX_MONTHS, ) self.api = apigw.LambdaRestApi( self, "api", handler=webhook_function, # default handler rest_api_name=self.rest_api_name, proxy=False, deploy=True, policy=policy, deploy_options=apigw.StageOptions( access_log_destination=apigw.LogGroupLogDestination(log_group), access_log_format=apigw.AccessLogFormat.clf(), data_trace_enabled=True, metrics_enabled=True, logging_level=apigw.MethodLoggingLevel.INFO, stage_name=names.API_STAGE, ), ) self.api.add_api_key("ZoomIngesterApiKey") self.new_recording_resource = self.create_resource( "new_recording", webhook_function, "POST", ) self.ingest_resource = self.create_resource( "ingest", on_demand_function, "POST", cors_options=apigw.CorsOptions( allow_origins=apigw.Cors.ALL_ORIGINS, allow_methods=["POST", "OPTIONS"], allow_headers=apigw.Cors.DEFAULT_HEADERS + ["Accept-Language", "X-Requested-With"], ), ) self.schedule_update_resource = self.create_resource( "schedule_update", schedule_update_function, "POST", ) self.status_query_resource = self.create_resource( "status", status_query_function, "GET", ) self.slack_resource = self.create_resource( "slack", slack_function, "POST", ) def endpoint_url(resource_name): return ( f"https://{self.api.rest_api_id}.execute-api." f"{core.Stack.of(self).region}.amazonaws.com/" f"{names.API_STAGE}/{resource_name}" ) on_demand_function.add_environment( "WEBHOOK_ENDPOINT_URL", endpoint_url("new_recording"), ) core.CfnOutput( self, "WebhookEndpoint", export_name=f"{stack_name}-{names.WEBHOOK_ENDPOINT}-url", value=endpoint_url("new_recording"), ) core.CfnOutput( self, "OnDemandEndpoint", export_name=f"{stack_name}-{names.ON_DEMAND_ENDPOINT}-url", value=endpoint_url("ingest"), ) core.CfnOutput( self, "ScheduleUpdateEndpoint", export_name=f"{stack_name}-{names.SCHEDULE_UPDATE_ENDPOINT}-url", value=endpoint_url("schedule_update"), ) core.CfnOutput( self, "StatusQueryEndpoint", export_name=f"{stack_name}-{names.STATUS_ENDPOINT}-url", value=endpoint_url("status"), ) core.CfnOutput( self, "SlackEndpoint", export_name=f"{stack_name}-{names.SLACK_ENDPOINT}-url", value=endpoint_url("slack"), ) core.CfnOutput( self, "WebhookResourceId", export_name=f"{stack_name}-{names.WEBHOOK_ENDPOINT}-resource-id", value=self.new_recording_resource.resource_id, ) core.CfnOutput( self, "OnDemandResourceId", export_name=f"{stack_name}-{names.ON_DEMAND_ENDPOINT}-resource-id", value=self.ingest_resource.resource_id, ) core.CfnOutput( self, "ScheduleUpdateResourceId", export_name=f"{stack_name}-{names.SCHEDULE_UPDATE_ENDPOINT}-resource-id", value=self.schedule_update_resource.resource_id, ) core.CfnOutput( self, "StatusQueryResourceId", export_name=f"{stack_name}-{names.STATUS_ENDPOINT}-resource-id", value=self.status_query_resource.resource_id, ) core.CfnOutput( self, "SlackResourceId", export_name=f"{stack_name}-{names.SLACK_ENDPOINT}-resource-id", value=self.slack_resource.resource_id, ) core.CfnOutput( self, "RestApiId", export_name=f"{stack_name}-{names.REST_API}-id", value=self.api.rest_api_id, )
def __init__(self, scope: core.Construct, id: str, webhook_function, on_demand_function, ingest_allowed_ips): super().__init__(scope, id) stack_name = core.Stack.of(self).stack_name policy = iam.PolicyDocument(statements=[ iam.PolicyStatement( effect=iam.Effect.ALLOW, actions=["execute-api:Invoke"], principals=[iam.AnyPrincipal()], # note that the policy is a prop of the api which cannot reference itself # see the Cloudformation documentation for api gateway policy attribute resources=[core.Fn.join('', ['execute-api:/', '*'])]), iam.PolicyStatement(effect=iam.Effect.DENY, actions=["execute-api:Invoke"], principals=[iam.AnyPrincipal()], resources=[ core.Fn.join( '', ['execute-api:/', '*/POST/ingest']) ], conditions={ "NotIpAddress": { "aws:SourceIp": ingest_allowed_ips } }) ]) self.rest_api_name = f"{stack_name}-{names.REST_API}" log_group = logs.LogGroup( self, "apilogs", log_group_name=f"/aws/apigateway/{self.rest_api_name}/access_logs", removal_policy=core.RemovalPolicy.DESTROY, retention=logs.RetentionDays.SIX_MONTHS) self.api = apigw.LambdaRestApi( self, "api", handler=webhook_function, # default handler rest_api_name=self.rest_api_name, proxy=False, deploy=True, policy=policy, deploy_options=apigw.StageOptions( access_log_destination=apigw.LogGroupLogDestination(log_group), access_log_format=apigw.AccessLogFormat.clf(), data_trace_enabled=True, metrics_enabled=True, logging_level=apigw.MethodLoggingLevel.INFO, stage_name=names.API_STAGE)) self.api.add_api_key("ZoomIngesterApiKey") self.new_recording_resource = self.api.root.add_resource( "new_recording") self.new_recording_method = self.new_recording_resource.add_method( "POST", method_responses=[ apigw.MethodResponse(status_code="200", response_models={ "application/json": apigw.Model.EMPTY_MODEL }) ]) self.ingest_resource = self.api.root.add_resource("ingest", default_cors_preflight_options=apigw.CorsOptions( allow_origins=apigw.Cors.ALL_ORIGINS, allow_methods=["POST", "OPTIONS"], allow_headers=apigw.Cors.DEFAULT_HEADERS \ + ["Accept-Language","X-Requested-With"] ) ) on_demand_integration = apigw.LambdaIntegration(on_demand_function) self.ingest_method = self.ingest_resource.add_method( "POST", on_demand_integration, method_responses=[ apigw.MethodResponse(status_code="200", response_models={ "application/json": apigw.Model.EMPTY_MODEL }) ]) def endpoint_url(resource_name): return (f"https://{self.api.rest_api_id}.execute-api." f"{core.Stack.of(self).region}.amazonaws.com/" f"{names.API_STAGE}/{resource_name}") on_demand_function.add_environment("WEBHOOK_ENDPOINT_URL", endpoint_url("new_recording")) core.CfnOutput( self, "WebhookEndpoint", export_name=f"{stack_name}-{names.WEBHOOK_ENDPOINT}-url", value=endpoint_url("new_recording")) core.CfnOutput( self, "OnDemandEndpoint", export_name=f"{stack_name}-{names.ON_DEMAND_ENDPOINT}-url", value=endpoint_url("ingest")) core.CfnOutput( self, "WebhookResourceId", export_name=f"{stack_name}-{names.WEBHOOK_ENDPOINT}-resource-id", value=self.new_recording_resource.resource_id) core.CfnOutput( self, "OnDemandResourceId", export_name=f"{stack_name}-{names.ON_DEMAND_ENDPOINT}-resource-id", value=self.ingest_resource.resource_id) core.CfnOutput(self, "RestApiId", export_name=f"{stack_name}-{names.REST_API}-id", value=self.api.rest_api_id)
def __init__(self, scope: core.Construct, id: str, stack_log_level: str, back_end_api_name: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) # Create Serverless Event Processor using Lambda): # Read Lambda Code): try: with open( "api_with_stage_variables/stacks/back_end/lambda_src/serverless_greeter.py", mode="r") as f: greeter_fn_code = f.read() except OSError as e: print("Unable to read Lambda Function Code") raise e greeter_fn = _lambda.Function( self, "secureGreeterFn", function_name=f"greeter_fn_{id}", runtime=_lambda.Runtime.PYTHON_3_7, handler="index.lambda_handler", code=_lambda.InlineCode(greeter_fn_code), timeout=core.Duration.seconds(15), reserved_concurrent_executions=20, environment={ "LOG_LEVEL": f"{stack_log_level}", "Environment": "Production", "ANDON_CORD_PULLED": "False", "RANDOM_SLEEP_ENABLED": "False" }, description= "A simple greeter function, which responds with a timestamp") greeter_fn_version = greeter_fn.latest_version greeter_fn_version_alias = _lambda.Alias( self, "greeterFnMystiqueAutomationAlias", alias_name="MystiqueAutomation", version=greeter_fn_version) greeter_fn_dev_alias = _lambda.Alias(self, "greeterFnDevAlias", alias_name="dev", version=greeter_fn_version) greeter_fn_test_alias = _lambda.Alias(self, "greeterFnTestAlias", alias_name="test", version=greeter_fn_version) greeter_fn_prod_alias = _lambda.Alias(self, "greeterFnProdAlias", alias_name="prod", version=greeter_fn_version) # Create Custom Loggroup # /aws/lambda/function-name greeter_fn_lg = _logs.LogGroup( self, "greeterFnLoggroup", log_group_name=f"/aws/lambda/{greeter_fn.function_name}", retention=_logs.RetentionDays.ONE_WEEK, removal_policy=core.RemovalPolicy.DESTROY) # %% # Create API Gateway wa_api = _apigw.RestApi( self, "backEnd01Api", rest_api_name=f"{back_end_api_name}", # deploy_options=wa_api_dev_stage_options, retain_deployments=False, deploy=False, endpoint_types=[_apigw.EndpointType.EDGE], description= f"{GlobalArgs.OWNER}: API Best Practices. Stage Variables for APIs. This stack deploys an API and integrates with Lambda using Stage Variables." ) wa_api_logs = _logs.LogGroup( self, "waApiLogs", log_group_name=f"/aws/apigateway/{back_end_api_name}/access_logs", removal_policy=core.RemovalPolicy.DESTROY, retention=_logs.RetentionDays.ONE_DAY) ###################################### ## CONFIG FOR API STAGE : DEV ## ###################################### dev_wa_api_deploy = _apigw.Deployment( self, "devDeploy", api=wa_api, description=f"{GlobalArgs.OWNER}: Deployment of 'dev' Api Stage", retain_deployments=False) dev_api_stage = _apigw.Stage( self, "devStage", deployment=dev_wa_api_deploy, stage_name="miztiik-dev", throttling_rate_limit=10, throttling_burst_limit=100, # Log full requests/responses data data_trace_enabled=True, # Enable Detailed CloudWatch Metrics metrics_enabled=True, logging_level=_apigw.MethodLoggingLevel.INFO, access_log_destination=_apigw.LogGroupLogDestination(wa_api_logs), variables={"lambdaAlias": "dev"}) # wa_api.deployment_stage = dev_api_stage test_wa_api_deploy = _apigw.Deployment( self, "testDeploy", api=wa_api, description=f"{GlobalArgs.OWNER}: Deployment of 'test' Api Stage", retain_deployments=False) test_api_stage = _apigw.Stage( self, "testStage", deployment=test_wa_api_deploy, stage_name="miztiik-test", throttling_rate_limit=10, throttling_burst_limit=100, # Log full requests/responses data data_trace_enabled=True, # Enable Detailed CloudWatch Metrics metrics_enabled=True, logging_level=_apigw.MethodLoggingLevel.INFO, access_log_destination=_apigw.LogGroupLogDestination(wa_api_logs), variables={"lambdaAlias": "test"}) wa_api.deployment_stage = test_api_stage prod_wa_api_deploy = _apigw.Deployment( self, "prodDeploy", api=wa_api, description=f"{GlobalArgs.OWNER}: Deployment of 'prod' Api Stage", retain_deployments=False) prod_api_stage = _apigw.Stage( self, "prodStage", deployment=prod_wa_api_deploy, stage_name="miztiik-prod", throttling_rate_limit=10, throttling_burst_limit=100, # Log full requests/responses data data_trace_enabled=True, # Enable Detailed CloudWatch Metrics metrics_enabled=True, logging_level=_apigw.MethodLoggingLevel.INFO, access_log_destination=_apigw.LogGroupLogDestination(wa_api_logs), variables={"lambdaAlias": "prod"}) prod_api_stage.node.add_dependency(test_api_stage) wa_api.deployment_stage = prod_api_stage wa_api_res = wa_api.root.add_resource("wa-api") greeter = wa_api_res.add_resource("greeter") backend_stage_uri = (f"arn:aws:apigateway:" f"{core.Aws.REGION}" f":lambda:path/2015-03-31/functions/" f"{greeter_fn.function_arn}" f":" f"${{stageVariables.lambdaAlias}}" f"/invocations") greeter_method_get = greeter.add_method( http_method="GET", request_parameters={ "method.request.header.InvocationType": True, "method.request.path.mystique": True }, # integration=_apigw.LambdaIntegration( # # handler=greeter_fn, # handler=backend_stage_uri, # proxy=True # ) integration=_apigw.Integration( type=_apigw.IntegrationType.AWS_PROXY, integration_http_method="GET", uri=backend_stage_uri)) # "arn:aws:apigateway:eu-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:eu-west-2:614517326458:function:${stageVariables.preflightFunction}/invocations", # https://lambda.us-east-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-east-1:230023004178:function:greeter_fn_well-architected-api:${stageVariable.lambdaAlias}/invocations # We need to manually add permissions for the stages to invoke # CDK By default adds permission only for the last .deployment_stage ##################################################################### ## CDK BUG: CONDITIONS DOES NOT TAKE EFFECT IN SERVICE PRINCIPAL ## ##################################################################### """ greeter_fn.grant_invoke( _iam.ServicePrincipal( service="apigateway.amazonaws.com", conditions={ "ArnLike": {"aws:SourceArn": "this-does-not-work"} } ) ) """ greeter_fn.add_permission( "allowStageInvocation", principal=_iam.ServicePrincipal("apigateway.amazonaws.com"), # source_arn=f"arn:aws:execute-api:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:{wa_api.rest_api_id}/{dev_api_stage.stage_name}/{greeter_method_get.resource.path}" source_arn=greeter_method_get.method_arn.replace( wa_api.deployment_stage.stage_name, "*"), action="lambda:InvokeFunction", ) greeter_fn_dev_alias.add_permission( "greeter_fn_devAliasApiPerms", principal=_iam.ServicePrincipal("apigateway.amazonaws.com"), action="lambda:InvokeFunction", source_arn=greeter_method_get.method_arn.replace( wa_api.deployment_stage.stage_name, "*"), ) greeter_fn_test_alias.add_permission( "greeter_fn_testAliasApiPerms", principal=_iam.ServicePrincipal("apigateway.amazonaws.com"), action="lambda:InvokeFunction", source_arn=greeter_method_get.method_arn.replace( wa_api.deployment_stage.stage_name, "*"), ) greeter_fn_prod_alias.add_permission( "greeter_fn_prodAliasApiPerms", principal=_iam.ServicePrincipal("apigateway.amazonaws.com"), action="lambda:InvokeFunction", source_arn=greeter_method_get.method_arn.replace( wa_api.deployment_stage.stage_name, "*"), ) # Outputs output_0 = core.CfnOutput( self, "AutomationFrom", value=f"{GlobalArgs.SOURCE_INFO}", description= "To know more about this automation stack, check out our github page." ) output_1 = core.CfnOutput( self, "WaApiUrl", value=f"{greeter.url}", description= "Use an utility like curl from the same VPC as the API to invoke it." )
def __init__( self, scope: core.Construct, id: str, stack_log_level: str, back_end_api_name: str, **kwargs ) -> None: super().__init__(scope, id, **kwargs) # Read Lambda Code): try: with open("api_request_validation/stacks/back_end/lambda_src/serverless_greeter.py", mode="r") as f: greeter_fn_code = f.read() except OSError as e: print("Unable to read Lambda Function Code") raise e greeter_fn = _lambda.Function( self, "secureGreeterFn", function_name=f"greeter_fn_{id}", runtime=_lambda.Runtime.PYTHON_3_7, handler="index.lambda_handler", code=_lambda.InlineCode(greeter_fn_code), current_version_options={ "removal_policy": core.RemovalPolicy.DESTROY, # Remove old versions "retry_attempts": 1, "description": "Mystique Factory Build Version" }, timeout=core.Duration.seconds(5), reserved_concurrent_executions=10, environment={ "LOG_LEVEL": f"{stack_log_level}", "Environment": "Production", "ANDON_CORD_PULLED": "False", "RANDOM_SLEEP_ENABLED": "False", "RANDOM_SLEEP_SECS": "2", }, description="A simple greeter function, which responds with a timestamp" ) greeter_fn_version_alias = greeter_fn.current_version.add_alias( "MystiqueAutomation") greeter_fn_prod_alias = greeter_fn.current_version.add_alias("prod") # Create Custom Loggroup greeter_fn_lg = _logs.LogGroup( self, "squareFnLoggroup", log_group_name=f"/aws/lambda/{greeter_fn.function_name}", retention=_logs.RetentionDays.ONE_WEEK, removal_policy=core.RemovalPolicy.DESTROY ) # %% ####################################### ## CONFIG FOR API STAGE : PROD ## ####################################### wa_api_logs = _logs.LogGroup( self, "waApiLogs", log_group_name=f"/aws/apigateway/{back_end_api_name}/access_logs", removal_policy=core.RemovalPolicy.DESTROY, retention=_logs.RetentionDays.ONE_DAY ) # Add API GW front end for the Lambda prod_api_stage_options = _apigw.StageOptions( stage_name="miztiik", throttling_rate_limit=10, throttling_burst_limit=100, # Log full requests/responses data data_trace_enabled=True, # Enable Detailed CloudWatch Metrics metrics_enabled=True, logging_level=_apigw.MethodLoggingLevel.INFO, access_log_destination=_apigw.LogGroupLogDestination(wa_api_logs), variables={ "lambdaAlias": "prod", "appOwner": "Mystique" } ) # Create API Gateway wa_api = _apigw.RestApi( self, "backEnd01Api", rest_api_name=f"{back_end_api_name}", deploy_options=prod_api_stage_options, minimum_compression_size=0, endpoint_types=[ _apigw.EndpointType.EDGE ], description=f"{GlobalArgs.OWNER}: API Best Practice Demonstration. Validate HTTP Requests at API Gateway" ) wa_api_res = wa_api.root.add_resource("well-architected-api") stationary_by_category = wa_api_res.add_resource("get-stationary") # Because this is NOT a proxy integration, we need to define our response model response_model = wa_api.add_model( "ResponseModel", content_type="application/json", model_name="MiztiikResponseModel", schema=_apigw.JsonSchema( schema=_apigw.JsonSchemaVersion.DRAFT4, title="updateResponse", type=_apigw.JsonSchemaType.OBJECT, properties={ "message": _apigw.JsonSchema(type=_apigw.JsonSchemaType.STRING) } ) ) # "pencil": [{"id": 1, "type": "microtip", "status": "unavailable", "price": 19}] req_model_stationary = wa_api.add_model( "RequestModel", content_type="application/json", model_name="RequestModelForStationary", schema=_apigw.JsonSchema( schema=_apigw.JsonSchemaVersion.DRAFT4, title="RequestValidation", type=_apigw.JsonSchemaType.OBJECT, properties={ "category": { "type": _apigw.JsonSchemaType.STRING, "enum": ["pens", "pencil", "eraser"] } }, required=["category"] ) ) stationary_by_category_req_validator = wa_api.add_request_validator( "apiReqValidator", validate_request_parameters=True, validate_request_body=True ) req_template = """$input.json('$')""" # resp_template = """$input.path('$.body.message')""" resp_template = """$input.path('$.body')""" stationary_by_category_method_get = stationary_by_category.add_method( http_method="POST", request_parameters={ "method.request.header.InvocationType": False, "method.request.path.category": False }, request_models={ "application/json": req_model_stationary }, request_validator=stationary_by_category_req_validator, integration=_apigw.LambdaIntegration( handler=greeter_fn, proxy=False, request_parameters={ "integration.request.path.category": "method.request.path.category" }, cache_key_parameters=[ "method.request.path.category" ], request_templates={ "application/json": req_template }, passthrough_behavior=_apigw.PassthroughBehavior.NEVER, integration_responses=[ _apigw.IntegrationResponse( status_code="200", # selection_pattern="2\d{2}", # Use for mapping Lambda Errors response_parameters={ "method.response.header.Access-Control-Allow-Headers": "'cache-control,Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'", "method.response.header.Content-Type": "'application/json'", }, response_templates={ "application/json": f"{resp_template}" } ) ] ), method_responses=[ _apigw.MethodResponse( status_code="200", response_parameters={ "method.response.header.Content-Type": True, "method.response.header.Access-Control-Allow-Headers": True, }, response_models={ "application/json": response_model } ), _apigw.MethodResponse( status_code="400", response_parameters={ "method.response.header.Content-Length": True, }, response_models={ "application/json": _apigw.EmptyModel() } ) ] ) # Outputs output_0 = core.CfnOutput( self, "AutomationFrom", value=f"{GlobalArgs.SOURCE_INFO}", description="To know more about this automation stack, check out our github page." ) output_1 = core.CfnOutput( self, "WellArchitectedApiUrl", value=f"{stationary_by_category.url}", description="Use an utility like curl from the same VPC as the API to invoke it." )
def __init__(self, scope: core.Construct, id: str, vpc, efs_sg, efs_share, efs_ap_nginx, stack_log_level: str, back_end_api_name: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) # Create Serverless Event Processor using Lambda): # Read Lambda Code): try: with open( "fargate_with_efs/stacks/back_end/lambda_src/serverless_greeter.py", mode="r") as f: greeter_fn_code = f.read() except OSError as e: print("Unable to read Lambda Function Code") raise e efs_mnt_path = "/mnt/html" greeter_fn = _lambda.Function( self, "secureGreeterFn", function_name=f"greeter_fn_{id}", runtime=_lambda.Runtime.PYTHON_3_7, handler="index.lambda_handler", code=_lambda.InlineCode(greeter_fn_code), current_version_options={ "removal_policy": core.RemovalPolicy.DESTROY, # retain old versions "retry_attempts": 1, "description": "Mystique Factory Build Version" }, timeout=core.Duration.seconds(15), reserved_concurrent_executions=20, retry_attempts=1, environment={ "LOG_LEVEL": f"{stack_log_level}", "Environment": "Production", "ANDON_CORD_PULLED": "False", "RANDOM_SLEEP_ENABLED": "False", "EFS_MNT_PATH": efs_mnt_path }, description= "A simple greeter function, which responds with a timestamp", vpc=vpc, vpc_subnets=_ec2.SubnetType.PRIVATE, security_groups=[efs_sg], filesystem=_lambda.FileSystem.from_efs_access_point( efs_ap_nginx, efs_mnt_path)) greeter_fn_version = greeter_fn.latest_version greeter_fn_dev_alias = _lambda.Alias( self, "greeterFnMystiqueAutomationAlias", alias_name="MystiqueAutomation", version=greeter_fn_version, description= "Mystique Factory Build Version to ingest content from API GW to EFS", retry_attempts=1) # Create Custom Loggroup greeter_fn_lg = _logs.LogGroup( self, "greeterFnLoggroup", log_group_name=f"/aws/lambda/{greeter_fn.function_name}", retention=_logs.RetentionDays.ONE_WEEK, removal_policy=core.RemovalPolicy.DESTROY) # %% wa_api_logs = _logs.LogGroup( self, "waApiLogs", log_group_name=f"/aws/apigateway/{back_end_api_name}/access_logs", removal_policy=core.RemovalPolicy.DESTROY, retention=_logs.RetentionDays.ONE_DAY) ####################################### ## CONFIG FOR API STAGE : PROD ## ####################################### # Add API GW front end for the Lambda prod_api_stage_options = _apigw.StageOptions( stage_name="prod", throttling_rate_limit=10, throttling_burst_limit=100, # Log full requests/responses data data_trace_enabled=True, # Enable Detailed CloudWatch Metrics metrics_enabled=True, logging_level=_apigw.MethodLoggingLevel.INFO, access_log_destination=_apigw.LogGroupLogDestination(wa_api_logs), variables={ "lambdaAlias": "prod", "appOwner": "Mystique" }) # Create API Gateway wa_api = _apigw.RestApi( self, "backEnd01Api", rest_api_name=f"{back_end_api_name}", deploy_options=prod_api_stage_options, endpoint_types=[_apigw.EndpointType.EDGE], description= f"{GlobalArgs.OWNER}: API Best Practices. This stack deploys an API and integrates with Lambda $LATEST alias." ) wa_api_res = wa_api.root.add_resource("well-architected-api") create_content = wa_api_res.add_resource("create-content") # Add POST method to API create_content_get = create_content.add_method( http_method="POST", request_parameters={ "method.request.header.InvocationType": True, "method.request.path.mystique": True }, integration=_apigw.LambdaIntegration(handler=greeter_fn, proxy=True)) # Outputs output_0 = core.CfnOutput( self, "AutomationFrom", value=f"{GlobalArgs.SOURCE_INFO}", description= "To know more about this automation stack, check out our github page." ) output_1 = core.CfnOutput( self, "ContentCreatorApiUrl", value= f"curl -X POST -H 'Content-Type: text/plain' -d 'Hello again :)' {create_content.url}", description= 'Use an utility like curl to add content to EFS. For ex: curl -X POST -H "Content-Type: text/plain" -d "Hello again :)" ${API_URL}' )
def __init__(self, scope: core.Construct, id: str, vpc, efs_sg, efs_share, efs_ap, stack_log_level: str, back_end_api_name: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) # Create Serverless Event Processor using Lambda): # Read Lambda Code): try: with open( "lambda_with_efs/stacks/back_end/lambda_src/serverless_greeter.py", mode="r") as f: greeter_fn_code = f.read() except OSError as e: print("Unable to read Lambda Function Code") raise e greeter_fn = _lambda.Function( self, "secureGreeterFn", function_name=f"greeter_fn_{id}", runtime=_lambda.Runtime.PYTHON_3_7, handler="index.lambda_handler", code=_lambda.InlineCode(greeter_fn_code), current_version_options={ "removal_policy": core.RemovalPolicy.DESTROY, # retain old versions "retry_attempts": 1, "description": "Mystique Factory Build Version" }, timeout=core.Duration.seconds(15), reserved_concurrent_executions=20, retry_attempts=1, environment={ "LOG_LEVEL": f"{stack_log_level}", "Environment": "Production", "ANDON_CORD_PULLED": "False", "RANDOM_SLEEP_ENABLED": "False" }, description= "A simple greeter function, which responds with a timestamp", vpc=vpc, vpc_subnets=_ec2.SubnetType.PRIVATE, security_groups=[efs_sg], filesystem=_lambda.FileSystem.from_efs_access_point( efs_ap, '/mnt/efs')) greeter_fn_version = greeter_fn.latest_version greeter_fn_dev_alias = _lambda.Alias( self, "greeterFnMystiqueAutomationAlias", alias_name="MystiqueAutomation", version=greeter_fn_version) # greeter_fn_version_alias = greeter_fn.current_version.add_alias("dev") # greeter_fn_prod_alias = greeter_fn.current_version.add_alias("prod") # Create Custom Loggroup # /aws/lambda/function-name greeter_fn_lg = _logs.LogGroup( self, "greeterFnLoggroup", log_group_name=f"/aws/lambda/{greeter_fn.function_name}", retention=_logs.RetentionDays.ONE_WEEK, removal_policy=core.RemovalPolicy.DESTROY) # Permissions to mount EFS (CDK May add them automatically) # roleStmt1 = _iam.PolicyStatement( # effect=_iam.Effect.ALLOW, # resources=[ # f"arn:aws:elasticfilesystem:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:file-system/{efs_share.file_system_id}" # ], # actions=["elasticfilesystem:*"] # ) # roleStmt1.sid = "AllowLambdaToReadWriteToEfs" # greeter_fn.add_to_role_policy(roleStmt1) # %% wa_api_logs = _logs.LogGroup( self, "waApiLogs", log_group_name=f"/aws/apigateway/{back_end_api_name}/access_logs", removal_policy=core.RemovalPolicy.DESTROY, retention=_logs.RetentionDays.ONE_DAY) ####################################### ## CONFIG FOR API STAGE : PROD ## ####################################### # Add API GW front end for the Lambda prod_api_stage_options = _apigw.StageOptions( stage_name="prod", throttling_rate_limit=10, throttling_burst_limit=100, # Log full requests/responses data data_trace_enabled=True, # Enable Detailed CloudWatch Metrics metrics_enabled=True, logging_level=_apigw.MethodLoggingLevel.INFO, access_log_destination=_apigw.LogGroupLogDestination(wa_api_logs), variables={ "lambdaAlias": "prod", "appOwner": "Mystique" }) # Create API Gateway wa_api = _apigw.RestApi( self, "backEnd01Api", rest_api_name=f"{back_end_api_name}", deploy_options=prod_api_stage_options, endpoint_types=[_apigw.EndpointType.EDGE], description= f"{GlobalArgs.OWNER}: API Best Practices. This stack deploys an API and integrates with Lambda $LATEST alias." ) wa_api_res = wa_api.root.add_resource("well-architected-api") greetings_wall = wa_api_res.add_resource("message-wall") # Add GET method to API greetings_wall_get = greetings_wall.add_method( http_method="GET", request_parameters={ "method.request.header.InvocationType": True, "method.request.path.mystique": True }, integration=_apigw.LambdaIntegration(handler=greeter_fn, proxy=True)) # Add POST method to API greeter_method_get = greetings_wall.add_method( http_method="POST", request_parameters={ "method.request.header.InvocationType": True, "method.request.path.mystique": True }, integration=_apigw.LambdaIntegration(handler=greeter_fn, proxy=True)) # Add DELETE method to API greeter_method_get = greetings_wall.add_method( http_method="DELETE", request_parameters={ "method.request.header.InvocationType": True, "method.request.path.mystique": True }, integration=_apigw.LambdaIntegration(handler=greeter_fn, proxy=True)) # Outputs output_0 = core.CfnOutput( self, "AutomationFrom", value=f"{GlobalArgs.SOURCE_INFO}", description= "To know more about this automation stack, check out our github page." ) output_1 = core.CfnOutput( self, "GreetingsWallApiUrl", value=f"{greetings_wall.url}", description= "Use an utility like curl from the same VPC as the API to invoke it." )