Fixed CF creation to trap imports of non-existent values
This commit is contained in:
parent
b6909ff64c
commit
da8bd545bf
@ -33,6 +33,18 @@ class MissingParameterError(BadRequest):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ExportNotFound(BadRequest):
|
||||||
|
"""Exception to raise if a template tries to import a non-existent export"""
|
||||||
|
|
||||||
|
def __init__(self, export_name):
|
||||||
|
template = Template(ERROR_RESPONSE)
|
||||||
|
super(ExportNotFound, self).__init__()
|
||||||
|
self.description = template.render(
|
||||||
|
code='ExportNotFound',
|
||||||
|
message="No export named {0} found.".format(export_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
ERROR_RESPONSE = """<ErrorResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
|
ERROR_RESPONSE = """<ErrorResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
|
||||||
<Error>
|
<Error>
|
||||||
<Type>Sender</Type>
|
<Type>Sender</Type>
|
||||||
|
@ -38,7 +38,7 @@ class FakeStack(BaseModel):
|
|||||||
resource_status_reason="User Initiated")
|
resource_status_reason="User Initiated")
|
||||||
|
|
||||||
self.description = self.template_dict.get('Description')
|
self.description = self.template_dict.get('Description')
|
||||||
self.cross_stack_resources = cross_stack_resources or []
|
self.cross_stack_resources = cross_stack_resources or {}
|
||||||
self.resource_map = self._create_resource_map()
|
self.resource_map = self._create_resource_map()
|
||||||
self.output_map = self._create_output_map()
|
self.output_map = self._create_output_map()
|
||||||
self._add_stack_event("CREATE_COMPLETE")
|
self._add_stack_event("CREATE_COMPLETE")
|
||||||
|
@ -28,7 +28,7 @@ from moto.s3 import models as s3_models
|
|||||||
from moto.sns import models as sns_models
|
from moto.sns import models as sns_models
|
||||||
from moto.sqs import models as sqs_models
|
from moto.sqs import models as sqs_models
|
||||||
from .utils import random_suffix
|
from .utils import random_suffix
|
||||||
from .exceptions import MissingParameterError, UnformattedGetAttTemplateException, ValidationError
|
from .exceptions import ExportNotFound, MissingParameterError, UnformattedGetAttTemplateException, ValidationError
|
||||||
from boto.cloudformation.stack import Output
|
from boto.cloudformation.stack import Output
|
||||||
|
|
||||||
MODEL_MAP = {
|
MODEL_MAP = {
|
||||||
@ -206,6 +206,8 @@ def clean_json(resource_json, resources_map):
|
|||||||
values = [x.value for x in resources_map.cross_stack_resources.values() if x.name == cleaned_val]
|
values = [x.value for x in resources_map.cross_stack_resources.values() if x.name == cleaned_val]
|
||||||
if any(values):
|
if any(values):
|
||||||
return values[0]
|
return values[0]
|
||||||
|
else:
|
||||||
|
raise ExportNotFound(cleaned_val)
|
||||||
|
|
||||||
if 'Fn::GetAZs' in resource_json:
|
if 'Fn::GetAZs' in resource_json:
|
||||||
region = resource_json.get('Fn::GetAZs') or DEFAULT_REGION
|
region = resource_json.get('Fn::GetAZs') or DEFAULT_REGION
|
||||||
|
85
tests/test_cloudformation/test_import_value.py
Normal file
85
tests/test_cloudformation/test_import_value.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||||
|
|
||||||
|
# Standard library modules
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
# Third-party modules
|
||||||
|
import boto3
|
||||||
|
from botocore.exceptions import ClientError
|
||||||
|
|
||||||
|
# Package modules
|
||||||
|
from moto import mock_cloudformation
|
||||||
|
|
||||||
|
SG_STACK_NAME = 'simple-sg-stack'
|
||||||
|
SG_TEMPLATE = """
|
||||||
|
AWSTemplateFormatVersion: 2010-09-09
|
||||||
|
Description: Simple test CF template for moto_cloudformation
|
||||||
|
|
||||||
|
|
||||||
|
Resources:
|
||||||
|
SimpleSecurityGroup:
|
||||||
|
Type: AWS::EC2::SecurityGroup
|
||||||
|
Description: "A simple security group"
|
||||||
|
Properties:
|
||||||
|
GroupName: simple-security-group
|
||||||
|
GroupDescription: "A simple security group"
|
||||||
|
SecurityGroupEgress:
|
||||||
|
-
|
||||||
|
Description: "Egress to remote HTTPS servers"
|
||||||
|
CidrIp: 0.0.0.0/0
|
||||||
|
IpProtocol: tcp
|
||||||
|
FromPort: 443
|
||||||
|
ToPort: 443
|
||||||
|
|
||||||
|
Outputs:
|
||||||
|
SimpleSecurityGroupName:
|
||||||
|
Value: !GetAtt SimpleSecurityGroup.GroupId
|
||||||
|
Export:
|
||||||
|
Name: "SimpleSecurityGroup"
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
EC2_STACK_NAME = 'simple-ec2-stack'
|
||||||
|
EC2_TEMPLATE = """
|
||||||
|
---
|
||||||
|
# The latest template format version is "2010-09-09" and as of 2018-04-09
|
||||||
|
# is currently the only valid value.
|
||||||
|
AWSTemplateFormatVersion: 2010-09-09
|
||||||
|
Description: Simple test CF template for moto_cloudformation
|
||||||
|
|
||||||
|
|
||||||
|
Resources:
|
||||||
|
SimpleInstance:
|
||||||
|
Type: AWS::EC2::Instance
|
||||||
|
Properties:
|
||||||
|
ImageId: ami-03cf127a
|
||||||
|
InstanceType: t2.micro
|
||||||
|
SecurityGroups: !Split [',', !ImportValue SimpleSecurityGroup]
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class TestSimpleInstance(unittest.TestCase):
|
||||||
|
def test_simple_instance(self):
|
||||||
|
"""Test that we can create a simple CloudFormation stack that imports values from an existing CloudFormation stack"""
|
||||||
|
with mock_cloudformation():
|
||||||
|
client = boto3.client('cloudformation')
|
||||||
|
client.create_stack(StackName=SG_STACK_NAME, TemplateBody=SG_TEMPLATE)
|
||||||
|
response = client.create_stack(StackName=EC2_STACK_NAME, TemplateBody=EC2_TEMPLATE)
|
||||||
|
self.assertIn('StackId', response)
|
||||||
|
response = client.describe_stacks(StackName=response['StackId'])
|
||||||
|
self.assertIn('Stacks', response)
|
||||||
|
stack_info = response['Stacks']
|
||||||
|
self.assertEqual(1, len(stack_info))
|
||||||
|
self.assertIn('StackName', stack_info[0])
|
||||||
|
self.assertEqual(EC2_STACK_NAME, stack_info[0]['StackName'])
|
||||||
|
|
||||||
|
def test_simple_instance_missing_export(self):
|
||||||
|
"""Test that we get an exception if a CloudFormation stack tries to imports a non-existent export value"""
|
||||||
|
with mock_cloudformation():
|
||||||
|
client = boto3.client('cloudformation')
|
||||||
|
with self.assertRaises(ClientError) as e:
|
||||||
|
client.create_stack(StackName=EC2_STACK_NAME, TemplateBody=EC2_TEMPLATE)
|
||||||
|
self.assertIn('Error', e.exception.response)
|
||||||
|
self.assertIn('Code', e.exception.response['Error'])
|
||||||
|
self.assertEqual('ExportNotFound', e.exception.response['Error']['Code'])
|
Loading…
Reference in New Issue
Block a user