350 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			350 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import boto3
 | 
						|
import json
 | 
						|
import sure  # noqa # pylint: disable=unused-import
 | 
						|
 | 
						|
from moto import mock_lambda, mock_cloudformation, mock_apigateway, mock_iam, mock_logs
 | 
						|
 | 
						|
template = """{
 | 
						|
  "AWSTemplateFormatVersion": "2010-09-09",
 | 
						|
  "Description": "The AWS CloudFormation template for this Serverless application",
 | 
						|
  "Resources": {
 | 
						|
    "ServerlessDeploymentBucket": {
 | 
						|
      "Type": "AWS::S3::Bucket"
 | 
						|
    },
 | 
						|
    "HelloLogGroup": {
 | 
						|
      "Type": "AWS::Logs::LogGroup",
 | 
						|
      "Properties": {
 | 
						|
        "LogGroupName": "/aws/lambda/timeseries-service-dev-hello"
 | 
						|
      }
 | 
						|
    },
 | 
						|
    "IamRoleLambdaExecution": {
 | 
						|
      "Type": "AWS::IAM::Role",
 | 
						|
      "Properties": {
 | 
						|
        "AssumeRolePolicyDocument": {
 | 
						|
          "Version": "2012-10-17",
 | 
						|
          "Statement": [
 | 
						|
            {
 | 
						|
              "Effect": "Allow",
 | 
						|
              "Principal": {
 | 
						|
                "Service": [
 | 
						|
                  "lambda.amazonaws.com"
 | 
						|
                ]
 | 
						|
              },
 | 
						|
              "Action": [
 | 
						|
                "sts:AssumeRole"
 | 
						|
              ]
 | 
						|
            }
 | 
						|
          ]
 | 
						|
        },
 | 
						|
        "Policies": [
 | 
						|
          {
 | 
						|
            "PolicyName": {
 | 
						|
              "Fn::Join": [
 | 
						|
                "-",
 | 
						|
                [
 | 
						|
                  "dev",
 | 
						|
                  "timeseries-service",
 | 
						|
                  "lambda"
 | 
						|
                ]
 | 
						|
              ]
 | 
						|
            },
 | 
						|
            "PolicyDocument": {
 | 
						|
              "Version": "2012-10-17",
 | 
						|
              "Statement": [
 | 
						|
                {
 | 
						|
                  "Effect": "Allow",
 | 
						|
                  "Action": [
 | 
						|
                    "logs:CreateLogStream"
 | 
						|
                  ],
 | 
						|
                  "Resource": [
 | 
						|
                    {
 | 
						|
                      "Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/timeseries-service-dev-hello:*"
 | 
						|
                    }
 | 
						|
                  ]
 | 
						|
                },
 | 
						|
                {
 | 
						|
                  "Effect": "Allow",
 | 
						|
                  "Action": [
 | 
						|
                    "logs:PutLogEvents"
 | 
						|
                  ],
 | 
						|
                  "Resource": [
 | 
						|
                    {
 | 
						|
                      "Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/timeseries-service-dev-hello:*:*"
 | 
						|
                    }
 | 
						|
                  ]
 | 
						|
                }
 | 
						|
              ]
 | 
						|
            }
 | 
						|
          }
 | 
						|
        ],
 | 
						|
        "Path": "/",
 | 
						|
        "RoleName": {
 | 
						|
          "Fn::Join": [
 | 
						|
            "-",
 | 
						|
            [
 | 
						|
              "timeseries-service",
 | 
						|
              "dev",
 | 
						|
              "us-east-1",
 | 
						|
              "lambdaRole"
 | 
						|
            ]
 | 
						|
          ]
 | 
						|
        }
 | 
						|
      }
 | 
						|
    },
 | 
						|
    "HelloLambdaFunction": {
 | 
						|
      "Type": "AWS::Lambda::Function",
 | 
						|
      "Properties": {
 | 
						|
        "Code": {
 | 
						|
          "S3Bucket": {
 | 
						|
            "Ref": "ServerlessDeploymentBucket"
 | 
						|
          },
 | 
						|
          "S3Key": "serverless/timeseries-service/dev/1542744572309-2018-11-20T20:09:32.309Z/timeseries-service.zip"
 | 
						|
        },
 | 
						|
        "FunctionName": "timeseries-service-dev-hello",
 | 
						|
        "Handler": "handler.hello",
 | 
						|
        "MemorySize": 1024,
 | 
						|
        "Role": {
 | 
						|
          "Fn::GetAtt": [
 | 
						|
            "IamRoleLambdaExecution",
 | 
						|
            "Arn"
 | 
						|
          ]
 | 
						|
        },
 | 
						|
        "Runtime": "python2.7",
 | 
						|
        "Timeout": 6
 | 
						|
      },
 | 
						|
      "DependsOn": [
 | 
						|
        "HelloLogGroup",
 | 
						|
        "IamRoleLambdaExecution"
 | 
						|
      ]
 | 
						|
    },
 | 
						|
    "HelloLambdaVersionU88Ag36tX5K6Yuze3R8jedH2g7q2TTGuafWQxEnUmo": {
 | 
						|
      "Type": "AWS::Lambda::Version",
 | 
						|
      "DeletionPolicy": "Retain",
 | 
						|
      "Properties": {
 | 
						|
        "FunctionName": {
 | 
						|
          "Ref": "HelloLambdaFunction"
 | 
						|
        },
 | 
						|
        "CodeSha256": "+pq+8RveA979z1DNF8UKnFGZfgE07blNyJGust5VJnU="
 | 
						|
      }
 | 
						|
    },
 | 
						|
    "ApiGatewayRestApi": {
 | 
						|
      "Type": "AWS::ApiGateway::RestApi",
 | 
						|
      "Properties": {
 | 
						|
        "Name": "dev-timeseries-service",
 | 
						|
        "EndpointConfiguration": {
 | 
						|
          "Types": [
 | 
						|
            "EDGE"
 | 
						|
          ]
 | 
						|
        }
 | 
						|
      }
 | 
						|
    },
 | 
						|
    "ApiGatewayResourceHello": {
 | 
						|
      "Type": "AWS::ApiGateway::Resource",
 | 
						|
      "Properties": {
 | 
						|
        "ParentId": {
 | 
						|
          "Fn::GetAtt": [
 | 
						|
            "ApiGatewayRestApi",
 | 
						|
            "RootResourceId"
 | 
						|
          ]
 | 
						|
        },
 | 
						|
        "PathPart": "hello",
 | 
						|
        "RestApiId": {
 | 
						|
          "Ref": "ApiGatewayRestApi"
 | 
						|
        }
 | 
						|
      }
 | 
						|
    },
 | 
						|
    "ApiGatewayMethodHelloGet": {
 | 
						|
      "Type": "AWS::ApiGateway::Method",
 | 
						|
      "Properties": {
 | 
						|
        "HttpMethod": "GET",
 | 
						|
        "RequestParameters": {},
 | 
						|
        "ResourceId": {
 | 
						|
          "Ref": "ApiGatewayResourceHello"
 | 
						|
        },
 | 
						|
        "RestApiId": {
 | 
						|
          "Ref": "ApiGatewayRestApi"
 | 
						|
        },
 | 
						|
        "ApiKeyRequired": false,
 | 
						|
        "AuthorizationType": "NONE",
 | 
						|
        "Integration": {
 | 
						|
          "IntegrationHttpMethod": "POST",
 | 
						|
          "Type": "AWS_PROXY",
 | 
						|
          "Uri": {
 | 
						|
            "Fn::Join": [
 | 
						|
              "",
 | 
						|
              [
 | 
						|
                "arn:",
 | 
						|
                {
 | 
						|
                  "Ref": "AWS::Partition"
 | 
						|
                },
 | 
						|
                ":apigateway:",
 | 
						|
                {
 | 
						|
                  "Ref": "AWS::Region"
 | 
						|
                },
 | 
						|
                ":lambda:path/2015-03-31/functions/",
 | 
						|
                {
 | 
						|
                  "Fn::GetAtt": [
 | 
						|
                    "HelloLambdaFunction",
 | 
						|
                    "Arn"
 | 
						|
                  ]
 | 
						|
                },
 | 
						|
                "/invocations"
 | 
						|
              ]
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        "MethodResponses": []
 | 
						|
      }
 | 
						|
    },
 | 
						|
    "ApiGatewayDeployment1542744572805": {
 | 
						|
      "Type": "AWS::ApiGateway::Deployment",
 | 
						|
      "Properties": {
 | 
						|
        "RestApiId": {
 | 
						|
          "Ref": "ApiGatewayRestApi"
 | 
						|
        },
 | 
						|
        "StageName": "dev"
 | 
						|
      },
 | 
						|
      "DependsOn": [
 | 
						|
        "ApiGatewayMethodHelloGet"
 | 
						|
      ]
 | 
						|
    },
 | 
						|
    "HelloLambdaPermissionApiGateway": {
 | 
						|
      "Type": "AWS::Lambda::Permission",
 | 
						|
      "Properties": {
 | 
						|
        "FunctionName": {
 | 
						|
          "Fn::GetAtt": [
 | 
						|
            "HelloLambdaFunction",
 | 
						|
            "Arn"
 | 
						|
          ]
 | 
						|
        },
 | 
						|
        "Action": "lambda:InvokeFunction",
 | 
						|
        "Principal": {
 | 
						|
          "Fn::Join": [
 | 
						|
            "",
 | 
						|
            [
 | 
						|
              "apigateway.",
 | 
						|
              {
 | 
						|
                "Ref": "AWS::URLSuffix"
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          ]
 | 
						|
        },
 | 
						|
        "SourceArn": {
 | 
						|
          "Fn::Join": [
 | 
						|
            "",
 | 
						|
            [
 | 
						|
              "arn:",
 | 
						|
              {
 | 
						|
                "Ref": "AWS::Partition"
 | 
						|
              },
 | 
						|
              ":execute-api:",
 | 
						|
              {
 | 
						|
                "Ref": "AWS::Region"
 | 
						|
              },
 | 
						|
              ":",
 | 
						|
              {
 | 
						|
                "Ref": "AWS::AccountId"
 | 
						|
              },
 | 
						|
              ":",
 | 
						|
              {
 | 
						|
                "Ref": "ApiGatewayRestApi"
 | 
						|
              },
 | 
						|
              "/*/*"
 | 
						|
            ]
 | 
						|
          ]
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  },
 | 
						|
  "Outputs": {
 | 
						|
    "ServerlessDeploymentBucketName": {
 | 
						|
      "Value": {
 | 
						|
        "Ref": "ServerlessDeploymentBucket"
 | 
						|
      }
 | 
						|
    },
 | 
						|
    "HelloLambdaFunctionQualifiedArn": {
 | 
						|
      "Description": "Current Lambda function version",
 | 
						|
      "Value": {
 | 
						|
        "Ref": "HelloLambdaVersionU88Ag36tX5K6Yuze3R8jedH2g7q2TTGuafWQxEnUmo"
 | 
						|
      }
 | 
						|
    },
 | 
						|
    "ServiceEndpoint": {
 | 
						|
      "Description": "URL of the service endpoint",
 | 
						|
      "Value": {
 | 
						|
        "Fn::Join": [
 | 
						|
          "",
 | 
						|
          [
 | 
						|
            "https://",
 | 
						|
            {
 | 
						|
              "Ref": "ApiGatewayRestApi"
 | 
						|
            },
 | 
						|
            ".execute-api.us-east-1.",
 | 
						|
            {
 | 
						|
              "Ref": "AWS::URLSuffix"
 | 
						|
            },
 | 
						|
            "/dev"
 | 
						|
          ]
 | 
						|
        ]
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}"""
 | 
						|
 | 
						|
 | 
						|
@mock_cloudformation
 | 
						|
@mock_lambda
 | 
						|
@mock_iam
 | 
						|
@mock_logs
 | 
						|
@mock_apigateway
 | 
						|
def test_simple_apigateway_with_lambda_proxy():
 | 
						|
    region = "us-east-1"
 | 
						|
    apigw = boto3.client("apigateway", region_name=region)
 | 
						|
    cf = boto3.client("cloudformation", region_name=region)
 | 
						|
    awslambda = boto3.client("lambda", region_name=region)
 | 
						|
    cf.create_stack(StackName="teststack", TemplateBody=template)
 | 
						|
    #
 | 
						|
    cf.describe_stacks(StackName="teststack")["Stacks"]
 | 
						|
    resources = cf.describe_stack_resources(StackName="teststack")["StackResources"]
 | 
						|
    api_id = [
 | 
						|
        r["PhysicalResourceId"]
 | 
						|
        for r in resources
 | 
						|
        if r["ResourceType"] == "AWS::ApiGateway::RestApi"
 | 
						|
    ][0]
 | 
						|
    fn_name = [
 | 
						|
        r["PhysicalResourceId"]
 | 
						|
        for r in resources
 | 
						|
        if r["LogicalResourceId"] == "HelloLambdaFunction"
 | 
						|
    ][0]
 | 
						|
    #
 | 
						|
    # Verify Rest API was created
 | 
						|
    api = apigw.get_rest_apis()["items"][0]
 | 
						|
    api["id"].should.equal(api_id)
 | 
						|
    api["name"].should.equal("dev-timeseries-service")
 | 
						|
    #
 | 
						|
    # Verify Gateway Resource was created
 | 
						|
    paths = apigw.get_resources(restApiId=api_id)["items"]
 | 
						|
    root_path = [p for p in paths if p["path"] == "/"][0]
 | 
						|
    hello_path = [p for p in paths if p["path"] == "/hello"][0]
 | 
						|
    hello_path["parentId"].should.equal(root_path["id"])
 | 
						|
    #
 | 
						|
    # Verify Gateway Method was created
 | 
						|
    m = apigw.get_method(
 | 
						|
        restApiId=api_id, resourceId=hello_path["id"], httpMethod="GET"
 | 
						|
    )
 | 
						|
    m["httpMethod"].should.equal("GET")
 | 
						|
    #
 | 
						|
    # Verify a Gateway Deployment was created
 | 
						|
    d = apigw.get_deployments(restApiId=api_id)["items"]
 | 
						|
    d.should.have.length_of(1)
 | 
						|
    #
 | 
						|
    # Verify Lambda function was created
 | 
						|
    awslambda.get_function(FunctionName=fn_name)  # Will throw 404 if it doesn't exist
 | 
						|
    #
 | 
						|
    # Verify Lambda Permission was created
 | 
						|
    policy = json.loads(awslambda.get_policy(FunctionName=fn_name)["Policy"])
 | 
						|
    statement = policy["Statement"][0]
 | 
						|
    statement["FunctionName"].should.contain(fn_name)
 | 
						|
    statement["Condition"]["ArnLike"]["AWS:SourceArn"].should.equal(
 | 
						|
        "arn:aws:execute-api:us-east-1:123456789012:{}/*/*".format(api_id)
 | 
						|
    )
 |