Merge pull request #964 from whummer/feat/cloudformation-models
Add extended CloudFormation models for Lambda and DynamoDB
This commit is contained in:
		
						commit
						5684aa5922
					
				@ -4,6 +4,7 @@ import base64
 | 
				
			|||||||
import datetime
 | 
					import datetime
 | 
				
			||||||
import hashlib
 | 
					import hashlib
 | 
				
			||||||
import io
 | 
					import io
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
import zipfile
 | 
					import zipfile
 | 
				
			||||||
@ -16,12 +17,12 @@ except:
 | 
				
			|||||||
import boto.awslambda
 | 
					import boto.awslambda
 | 
				
			||||||
from moto.core import BaseBackend, BaseModel
 | 
					from moto.core import BaseBackend, BaseModel
 | 
				
			||||||
from moto.s3.models import s3_backend
 | 
					from moto.s3.models import s3_backend
 | 
				
			||||||
from moto.s3.exceptions import MissingBucket
 | 
					from moto.s3.exceptions import MissingBucket, MissingKey
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class LambdaFunction(BaseModel):
 | 
					class LambdaFunction(BaseModel):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, spec):
 | 
					    def __init__(self, spec, validate_s3=True):
 | 
				
			||||||
        # required
 | 
					        # required
 | 
				
			||||||
        self.code = spec['Code']
 | 
					        self.code = spec['Code']
 | 
				
			||||||
        self.function_name = spec['FunctionName']
 | 
					        self.function_name = spec['FunctionName']
 | 
				
			||||||
@ -58,24 +59,25 @@ class LambdaFunction(BaseModel):
 | 
				
			|||||||
            self.code_size = len(to_unzip_code)
 | 
					            self.code_size = len(to_unzip_code)
 | 
				
			||||||
            self.code_sha_256 = hashlib.sha256(to_unzip_code).hexdigest()
 | 
					            self.code_sha_256 = hashlib.sha256(to_unzip_code).hexdigest()
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            # validate s3 bucket
 | 
					            # validate s3 bucket and key
 | 
				
			||||||
 | 
					            key = None
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                # FIXME: does not validate bucket region
 | 
					                # FIXME: does not validate bucket region
 | 
				
			||||||
                key = s3_backend.get_key(
 | 
					                key = s3_backend.get_key(
 | 
				
			||||||
                    self.code['S3Bucket'], self.code['S3Key'])
 | 
					                    self.code['S3Bucket'], self.code['S3Key'])
 | 
				
			||||||
            except MissingBucket:
 | 
					            except MissingBucket:
 | 
				
			||||||
                raise ValueError(
 | 
					                if do_validate_s3():
 | 
				
			||||||
                    "InvalidParameterValueException",
 | 
					                    raise ValueError(
 | 
				
			||||||
                    "Error occurred while GetObject. S3 Error Code: NoSuchBucket. S3 Error Message: The specified bucket does not exist")
 | 
					                        "InvalidParameterValueException",
 | 
				
			||||||
            else:
 | 
					                        "Error occurred while GetObject. S3 Error Code: NoSuchBucket. S3 Error Message: The specified bucket does not exist")
 | 
				
			||||||
                # validate s3 key
 | 
					            except MissingKey:
 | 
				
			||||||
                if key is None:
 | 
					                if do_validate_s3():
 | 
				
			||||||
                    raise ValueError(
 | 
					                    raise ValueError(
 | 
				
			||||||
                        "InvalidParameterValueException",
 | 
					                        "InvalidParameterValueException",
 | 
				
			||||||
                        "Error occurred while GetObject. S3 Error Code: NoSuchKey. S3 Error Message: The specified key does not exist.")
 | 
					                        "Error occurred while GetObject. S3 Error Code: NoSuchKey. S3 Error Message: The specified key does not exist.")
 | 
				
			||||||
                else:
 | 
					            if key:
 | 
				
			||||||
                    self.code_size = key.size
 | 
					                self.code_size = key.size
 | 
				
			||||||
                    self.code_sha_256 = hashlib.sha256(key.value).hexdigest()
 | 
					                self.code_sha_256 = hashlib.sha256(key.value).hexdigest()
 | 
				
			||||||
        self.function_arn = 'arn:aws:lambda:123456789012:function:{0}'.format(
 | 
					        self.function_arn = 'arn:aws:lambda:123456789012:function:{0}'.format(
 | 
				
			||||||
            self.function_name)
 | 
					            self.function_name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -209,6 +211,13 @@ class LambdaFunction(BaseModel):
 | 
				
			|||||||
        fn = backend.create_function(spec)
 | 
					        fn = backend.create_function(spec)
 | 
				
			||||||
        return fn
 | 
					        return fn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_cfn_attribute(self, attribute_name):
 | 
				
			||||||
 | 
					        from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
 | 
				
			||||||
 | 
					        if attribute_name == 'Arn':
 | 
				
			||||||
 | 
					            region = 'us-east-1'
 | 
				
			||||||
 | 
					            return 'arn:aws:lambda:{0}:123456789012:function:{1}'.format(region, self.function_name)
 | 
				
			||||||
 | 
					        raise UnformattedGetAttTemplateException()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def _create_zipfile_from_plaintext_code(code):
 | 
					    def _create_zipfile_from_plaintext_code(code):
 | 
				
			||||||
        zip_output = io.BytesIO()
 | 
					        zip_output = io.BytesIO()
 | 
				
			||||||
@ -219,6 +228,48 @@ class LambdaFunction(BaseModel):
 | 
				
			|||||||
        return zip_output.read()
 | 
					        return zip_output.read()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class EventSourceMapping(BaseModel):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, spec):
 | 
				
			||||||
 | 
					        # required
 | 
				
			||||||
 | 
					        self.function_name = spec['FunctionName']
 | 
				
			||||||
 | 
					        self.event_source_arn = spec['EventSourceArn']
 | 
				
			||||||
 | 
					        self.starting_position = spec['StartingPosition']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # optional
 | 
				
			||||||
 | 
					        self.batch_size = spec.get('BatchSize', 100)
 | 
				
			||||||
 | 
					        self.enabled = spec.get('Enabled', True)
 | 
				
			||||||
 | 
					        self.starting_position_timestamp = spec.get('StartingPositionTimestamp', None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):
 | 
				
			||||||
 | 
					        properties = cloudformation_json['Properties']
 | 
				
			||||||
 | 
					        spec = {
 | 
				
			||||||
 | 
					            'FunctionName': properties['FunctionName'],
 | 
				
			||||||
 | 
					            'EventSourceArn': properties['EventSourceArn'],
 | 
				
			||||||
 | 
					            'StartingPosition': properties['StartingPosition']
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        optional_properties = 'BatchSize Enabled StartingPositionTimestamp'.split()
 | 
				
			||||||
 | 
					        for prop in optional_properties:
 | 
				
			||||||
 | 
					            if prop in properties:
 | 
				
			||||||
 | 
					                spec[prop] = properties[prop]
 | 
				
			||||||
 | 
					        return EventSourceMapping(spec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LambdaVersion(BaseModel):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, spec):
 | 
				
			||||||
 | 
					        self.version = spec['Version']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):
 | 
				
			||||||
 | 
					        properties = cloudformation_json['Properties']
 | 
				
			||||||
 | 
					        spec = {
 | 
				
			||||||
 | 
					            'Version': properties.get('Version')
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return LambdaVersion(spec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class LambdaBackend(BaseBackend):
 | 
					class LambdaBackend(BaseBackend):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self):
 | 
					    def __init__(self):
 | 
				
			||||||
@ -242,6 +293,10 @@ class LambdaBackend(BaseBackend):
 | 
				
			|||||||
        return self._functions.values()
 | 
					        return self._functions.values()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def do_validate_s3():
 | 
				
			||||||
 | 
					    return os.environ.get('VALIDATE_LAMBDA_S3', '') in ['', '1', 'true']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
lambda_backends = {}
 | 
					lambda_backends = {}
 | 
				
			||||||
for region in boto.awslambda.regions():
 | 
					for region in boto.awslambda.regions():
 | 
				
			||||||
    lambda_backends[region.name] = LambdaBackend()
 | 
					    lambda_backends[region.name] = LambdaBackend()
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,9 @@ import warnings
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from moto.autoscaling import models as autoscaling_models
 | 
					from moto.autoscaling import models as autoscaling_models
 | 
				
			||||||
from moto.awslambda import models as lambda_models
 | 
					from moto.awslambda import models as lambda_models
 | 
				
			||||||
 | 
					from moto.cloudwatch import models as cloudwatch_models
 | 
				
			||||||
from moto.datapipeline import models as datapipeline_models
 | 
					from moto.datapipeline import models as datapipeline_models
 | 
				
			||||||
 | 
					from moto.dynamodb import models as dynamodb_models
 | 
				
			||||||
from moto.ec2 import models as ec2_models
 | 
					from moto.ec2 import models as ec2_models
 | 
				
			||||||
from moto.ecs import models as ecs_models
 | 
					from moto.ecs import models as ecs_models
 | 
				
			||||||
from moto.elb import models as elb_models
 | 
					from moto.elb import models as elb_models
 | 
				
			||||||
@ -27,7 +29,10 @@ from boto.cloudformation.stack import Output
 | 
				
			|||||||
MODEL_MAP = {
 | 
					MODEL_MAP = {
 | 
				
			||||||
    "AWS::AutoScaling::AutoScalingGroup": autoscaling_models.FakeAutoScalingGroup,
 | 
					    "AWS::AutoScaling::AutoScalingGroup": autoscaling_models.FakeAutoScalingGroup,
 | 
				
			||||||
    "AWS::AutoScaling::LaunchConfiguration": autoscaling_models.FakeLaunchConfiguration,
 | 
					    "AWS::AutoScaling::LaunchConfiguration": autoscaling_models.FakeLaunchConfiguration,
 | 
				
			||||||
 | 
					    "AWS::DynamoDB::Table": dynamodb_models.Table,
 | 
				
			||||||
 | 
					    "AWS::Lambda::EventSourceMapping": lambda_models.EventSourceMapping,
 | 
				
			||||||
    "AWS::Lambda::Function": lambda_models.LambdaFunction,
 | 
					    "AWS::Lambda::Function": lambda_models.LambdaFunction,
 | 
				
			||||||
 | 
					    "AWS::Lambda::Version": lambda_models.LambdaVersion,
 | 
				
			||||||
    "AWS::EC2::EIP": ec2_models.ElasticAddress,
 | 
					    "AWS::EC2::EIP": ec2_models.ElasticAddress,
 | 
				
			||||||
    "AWS::EC2::Instance": ec2_models.Instance,
 | 
					    "AWS::EC2::Instance": ec2_models.Instance,
 | 
				
			||||||
    "AWS::EC2::InternetGateway": ec2_models.InternetGateway,
 | 
					    "AWS::EC2::InternetGateway": ec2_models.InternetGateway,
 | 
				
			||||||
@ -53,6 +58,7 @@ MODEL_MAP = {
 | 
				
			|||||||
    "AWS::IAM::InstanceProfile": iam_models.InstanceProfile,
 | 
					    "AWS::IAM::InstanceProfile": iam_models.InstanceProfile,
 | 
				
			||||||
    "AWS::IAM::Role": iam_models.Role,
 | 
					    "AWS::IAM::Role": iam_models.Role,
 | 
				
			||||||
    "AWS::KMS::Key": kms_models.Key,
 | 
					    "AWS::KMS::Key": kms_models.Key,
 | 
				
			||||||
 | 
					    "AWS::Logs::LogGroup": cloudwatch_models.LogGroup,
 | 
				
			||||||
    "AWS::RDS::DBInstance": rds_models.Database,
 | 
					    "AWS::RDS::DBInstance": rds_models.Database,
 | 
				
			||||||
    "AWS::RDS::DBSecurityGroup": rds_models.SecurityGroup,
 | 
					    "AWS::RDS::DBSecurityGroup": rds_models.SecurityGroup,
 | 
				
			||||||
    "AWS::RDS::DBSubnetGroup": rds_models.SubnetGroup,
 | 
					    "AWS::RDS::DBSubnetGroup": rds_models.SubnetGroup,
 | 
				
			||||||
@ -133,7 +139,7 @@ def clean_json(resource_json, resources_map):
 | 
				
			|||||||
            try:
 | 
					            try:
 | 
				
			||||||
                return resource.get_cfn_attribute(resource_json['Fn::GetAtt'][1])
 | 
					                return resource.get_cfn_attribute(resource_json['Fn::GetAtt'][1])
 | 
				
			||||||
            except NotImplementedError as n:
 | 
					            except NotImplementedError as n:
 | 
				
			||||||
                logger.warning(n.message.format(
 | 
					                logger.warning(str(n).format(
 | 
				
			||||||
                    resource_json['Fn::GetAtt'][0]))
 | 
					                    resource_json['Fn::GetAtt'][0]))
 | 
				
			||||||
            except UnformattedGetAttTemplateException:
 | 
					            except UnformattedGetAttTemplateException:
 | 
				
			||||||
                raise ValidationError(
 | 
					                raise ValidationError(
 | 
				
			||||||
 | 
				
			|||||||
@ -111,6 +111,27 @@ class CloudWatchBackend(BaseBackend):
 | 
				
			|||||||
        return self.metric_data
 | 
					        return self.metric_data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LogGroup(BaseModel):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, spec):
 | 
				
			||||||
 | 
					        # required
 | 
				
			||||||
 | 
					        self.name = spec['LogGroupName']
 | 
				
			||||||
 | 
					        # optional
 | 
				
			||||||
 | 
					        self.tags = spec.get('Tags', [])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):
 | 
				
			||||||
 | 
					        properties = cloudformation_json['Properties']
 | 
				
			||||||
 | 
					        spec = {
 | 
				
			||||||
 | 
					            'LogGroupName': properties['LogGroupName']
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        optional_properties = 'Tags'.split()
 | 
				
			||||||
 | 
					        for prop in optional_properties:
 | 
				
			||||||
 | 
					            if prop in properties:
 | 
				
			||||||
 | 
					                spec[prop] = properties[prop]
 | 
				
			||||||
 | 
					        return LogGroup(spec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cloudwatch_backends = {}
 | 
					cloudwatch_backends = {}
 | 
				
			||||||
for region in boto.ec2.cloudwatch.regions():
 | 
					for region in boto.ec2.cloudwatch.regions():
 | 
				
			||||||
    cloudwatch_backends[region.name] = CloudWatchBackend()
 | 
					    cloudwatch_backends[region.name] = CloudWatchBackend()
 | 
				
			||||||
 | 
				
			|||||||
@ -137,6 +137,20 @@ class Table(BaseModel):
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        return results
 | 
					        return results
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):
 | 
				
			||||||
 | 
					        properties = cloudformation_json['Properties']
 | 
				
			||||||
 | 
					        key_attr = [i['AttributeName'] for i in properties['KeySchema'] if i['KeyType'] == 'HASH'][0]
 | 
				
			||||||
 | 
					        key_type = [i['AttributeType'] for i in properties['AttributeDefinitions'] if i['AttributeName'] == key_attr][0]
 | 
				
			||||||
 | 
					        spec = {
 | 
				
			||||||
 | 
					            'name': properties['TableName'],
 | 
				
			||||||
 | 
					            'hash_key_attr': key_attr,
 | 
				
			||||||
 | 
					            'hash_key_type': key_type
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        # TODO: optional properties still missing:
 | 
				
			||||||
 | 
					        # range_key_attr, range_key_type, read_capacity, write_capacity
 | 
				
			||||||
 | 
					        return Table(**spec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __len__(self):
 | 
					    def __len__(self):
 | 
				
			||||||
        count = 0
 | 
					        count = 0
 | 
				
			||||||
        for key, value in self.items.items():
 | 
					        for key, value in self.items.items():
 | 
				
			||||||
@ -245,6 +259,14 @@ class Table(BaseModel):
 | 
				
			|||||||
        except KeyError:
 | 
					        except KeyError:
 | 
				
			||||||
            return None
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_cfn_attribute(self, attribute_name):
 | 
				
			||||||
 | 
					        from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
 | 
				
			||||||
 | 
					        if attribute_name == 'StreamArn':
 | 
				
			||||||
 | 
					            region = 'us-east-1'
 | 
				
			||||||
 | 
					            time = '2000-01-01T00:00:00.000'
 | 
				
			||||||
 | 
					            return 'arn:aws:dynamodb:{0}:123456789012:table/{1}/stream/{2}'.format(region, self.name, time)
 | 
				
			||||||
 | 
					        raise UnformattedGetAttTemplateException()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DynamoDBBackend(BaseBackend):
 | 
					class DynamoDBBackend(BaseBackend):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
from __future__ import unicode_literals
 | 
					from __future__ import unicode_literals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import boto
 | 
					import boto
 | 
				
			||||||
@ -565,3 +566,80 @@ def test_describe_stack_events_shows_create_update_and_delete():
 | 
				
			|||||||
        assert False, "Too many stack events"
 | 
					        assert False, "Too many stack events"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    list(stack_events_to_look_for).should.be.empty
 | 
					    list(stack_events_to_look_for).should.be.empty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@mock_cloudformation_deprecated
 | 
				
			||||||
 | 
					@mock_route53_deprecated
 | 
				
			||||||
 | 
					def test_create_stack_lambda_and_dynamodb():
 | 
				
			||||||
 | 
					    conn = boto.connect_cloudformation()
 | 
				
			||||||
 | 
					    dummy_template = {
 | 
				
			||||||
 | 
					        "AWSTemplateFormatVersion": "2010-09-09",
 | 
				
			||||||
 | 
					        "Description": "Stack Lambda Test 1",
 | 
				
			||||||
 | 
					        "Parameters": {
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "Resources": {
 | 
				
			||||||
 | 
					            "func1": {
 | 
				
			||||||
 | 
					                "Type" : "AWS::Lambda::Function",
 | 
				
			||||||
 | 
					                "Properties" : {
 | 
				
			||||||
 | 
					                    "Code": {
 | 
				
			||||||
 | 
					                        "S3Bucket": "bucket_123",
 | 
				
			||||||
 | 
					                        "S3Key": "key_123"
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "FunctionName": "func1",
 | 
				
			||||||
 | 
					                    "Handler": "handler.handler",
 | 
				
			||||||
 | 
					                    "Role": "role1",
 | 
				
			||||||
 | 
					                    "Runtime": "python2.7",
 | 
				
			||||||
 | 
					                    "Description": "descr",
 | 
				
			||||||
 | 
					                    "MemorySize": 12345,
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "func1version": {
 | 
				
			||||||
 | 
					                "Type": "AWS::Lambda::LambdaVersion",
 | 
				
			||||||
 | 
					                "Properties" : {
 | 
				
			||||||
 | 
					                    "Version": "v1.2.3"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "tab1": {
 | 
				
			||||||
 | 
					                "Type" : "AWS::DynamoDB::Table",
 | 
				
			||||||
 | 
					                "Properties" : {
 | 
				
			||||||
 | 
					                    "TableName": "tab1",
 | 
				
			||||||
 | 
					                    "KeySchema": [{
 | 
				
			||||||
 | 
					                        "AttributeName": "attr1",
 | 
				
			||||||
 | 
					                        "KeyType": "HASH"
 | 
				
			||||||
 | 
					                    }],
 | 
				
			||||||
 | 
					                    "AttributeDefinitions": [{
 | 
				
			||||||
 | 
					                        "AttributeName": "attr1",
 | 
				
			||||||
 | 
					                        "AttributeType": "string"
 | 
				
			||||||
 | 
					                    }],
 | 
				
			||||||
 | 
					                    "ProvisionedThroughput": {
 | 
				
			||||||
 | 
					                        "ReadCapacityUnits": 10,
 | 
				
			||||||
 | 
					                        "WriteCapacityUnits": 10
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "func1mapping": {
 | 
				
			||||||
 | 
					                "Type": "AWS::Lambda::EventSourceMapping",
 | 
				
			||||||
 | 
					                "Properties" : {
 | 
				
			||||||
 | 
					                    "FunctionName": "v1.2.3",
 | 
				
			||||||
 | 
					                    "EventSourceArn": "arn:aws:dynamodb:region:XXXXXX:table/tab1/stream/2000T00:00:00.000",
 | 
				
			||||||
 | 
					                    "StartingPosition": "0",
 | 
				
			||||||
 | 
					                    "BatchSize": 100,
 | 
				
			||||||
 | 
					                    "Enabled": True
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    validate_s3_before = os.environ.get('VALIDATE_LAMBDA_S3', '')
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        os.environ['VALIDATE_LAMBDA_S3'] = 'false'
 | 
				
			||||||
 | 
					        conn.create_stack(
 | 
				
			||||||
 | 
					            "test_stack_lambda_1",
 | 
				
			||||||
 | 
					            template_body=json.dumps(dummy_template),
 | 
				
			||||||
 | 
					            parameters={}.items()
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    finally:
 | 
				
			||||||
 | 
					        os.environ['VALIDATE_LAMBDA_S3'] = validate_s3_before
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    stack = conn.describe_stacks()[0]
 | 
				
			||||||
 | 
					    resources = stack.list_resources()
 | 
				
			||||||
 | 
					    assert len(resources) == 4
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user