tweak Fn::GetAtt to return resource_json if resource is not implemented. DRY

This is better than failing out with a misleading Boto 400 error which should only happen when get_cfn_attribute is called but fails.
This commit is contained in:
Joseph Lawson 2014-10-21 14:51:26 -04:00
parent 83f187fa7e
commit 20a69255c3
8 changed files with 46 additions and 52 deletions

View File

@ -0,0 +1,6 @@
from __future__ import unicode_literals
class UnformattedGetAttTemplateException(Exception):
description = 'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt'
status_code = 400

View File

@ -8,6 +8,7 @@ from moto.elb import models as elb_models
from moto.iam import models as iam_models
from moto.sqs import models as sqs_models
from .utils import random_suffix
from .exceptions import UnformattedGetAttTemplateException
from boto.cloudformation.stack import Output
from boto.exception import BotoServerError
@ -72,17 +73,22 @@ def clean_json(resource_json, resources_map):
return resource
if 'Fn::GetAtt' in resource_json:
resource = resources_map[resource_json['Fn::GetAtt'][0]]
if resource is None:
return resource_json
try:
return resource.get_cfn_attribute(resource_json['Fn::GetAtt'][1])
except NotImplementedError as n:
raise NotImplementedError(n.message.format(resource_json['Fn::GetAtt'][0]))
except AttributeError:
logger.warning(n.message.format(resource_json['Fn::GetAtt'][0]))
except UnformattedGetAttTemplateException:
raise BotoServerError(
400,
UnformattedGetAttTemplateException.status_code,
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt'.format(
resource_json['Fn::GetAtt'][0], resource_json['Fn::GetAtt'][1]))
UnformattedGetAttTemplateException.description.format(
resource_json['Fn::GetAtt'][0], resource_json['Fn::GetAtt'][1]))
except Exception as e:
pass
cleaned_json = {}
for key, value in resource_json.items():

View File

@ -9,7 +9,6 @@ from boto.ec2.instance import Instance as BotoInstance, Reservation
from boto.ec2.blockdevicemapping import BlockDeviceMapping, BlockDeviceType
from boto.ec2.spotinstancerequest import SpotInstanceRequest as BotoSpotRequest
from boto.ec2.launchspecification import LaunchSpecification
from boto.exception import BotoServerError
from moto.core import BaseBackend
from moto.core.models import Model
@ -187,13 +186,12 @@ class NetworkInterface(object):
return self._group_set
def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'PrimaryPrivateIpAddress':
return self.private_ip_address
elif attribute_name == 'SecondaryPrivateIpAddresses':
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "SecondaryPrivateIpAddresses" ]"')
raise BotoServerError(400,
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
raise UnformattedGetAttTemplateException()
class NetworkInterfaceBackend(object):
@ -423,6 +421,7 @@ class Instance(BotoInstance, TaggedEC2Resource):
eni.device_index = None
def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'AvailabilityZone':
return self.placement
elif attribute_name == 'PrivateDnsName':
@ -433,9 +432,7 @@ class Instance(BotoInstance, TaggedEC2Resource):
return self.private_ip_address
elif attribute_name == 'PublicIp':
return self.ip_address
raise BotoServerError(400,
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
raise UnformattedGetAttTemplateException()
class InstanceBackend(object):
@ -997,11 +994,10 @@ class SecurityGroup(object):
return True
def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'GroupId':
return self.id
raise BotoServerError(400,
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
raise UnformattedGetAttTemplateException()
class SecurityGroupBackend(object):
@ -1527,11 +1523,10 @@ class Subnet(TaggedEC2Resource):
return filter_value
def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'AvailabilityZone':
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "AvailabilityZone" ]"')
raise BotoServerError(400,
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
raise UnformattedGetAttTemplateException()
class SubnetBackend(object):
@ -1969,11 +1964,10 @@ class ElasticAddress(object):
return self.allocation_id
def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'AllocationId':
return self.allocation_id
raise BotoServerError(400,
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
raise UnformattedGetAttTemplateException()
class ElasticAddressBackend(object):

View File

@ -1,6 +1,5 @@
from __future__ import unicode_literals
from moto.core import BaseBackend
from boto.exception import BotoServerError
class FakeHealthCheck(object):
@ -58,6 +57,7 @@ class FakeLoadBalancer(object):
return self.name
def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'CanonicalHostedZoneName':
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "CanonicalHostedZoneName" ]"')
elif attribute_name == 'CanonicalHostedZoneNameID':
@ -68,9 +68,7 @@ class FakeLoadBalancer(object):
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "SourceSecurityGroup.GroupName" ]"')
elif attribute_name == 'SourceSecurityGroup.OwnerAlias':
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "SourceSecurityGroup.OwnerAlias" ]"')
raise BotoServerError(400,
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
raise UnformattedGetAttTemplateException()
class ELBBackend(BaseBackend):

View File

@ -31,11 +31,10 @@ class Role(object):
return self.id
def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'Arn':
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "Arn" ]"')
raise BotoServerError(400,
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
raise UnformattedGetAttTemplateException()
class InstanceProfile(object):
@ -61,11 +60,10 @@ class InstanceProfile(object):
return self.name
def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'Arn':
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "Arn" ]"')
raise BotoServerError(400,
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
raise UnformattedGetAttTemplateException()
class Certificate(object):
@ -93,11 +91,10 @@ class AccessKey(object):
)
def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'SecretAccessKey':
return self.secret_access_key
raise BotoServerError(400,
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
raise UnformattedGetAttTemplateException()
class Group(object):
@ -113,11 +110,10 @@ class Group(object):
self.users = []
def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'Arn':
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "Arn" ]"')
raise BotoServerError(400,
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
raise UnformattedGetAttTemplateException()
class User(object):
@ -172,11 +168,10 @@ class User(object):
raise BotoServerError(404, 'Not Found')
def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'Arn':
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "Arn" ]"')
raise BotoServerError(400,
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
raise UnformattedGetAttTemplateException()
class IAMBackend(BaseBackend):

View File

@ -12,7 +12,6 @@ from moto.core import BaseBackend
from moto.core.utils import iso_8601_datetime, rfc_1123_datetime
from .exceptions import BucketAlreadyExists, MissingBucket
from .utils import clean_key_name, _VersionedKeyStore
from boto.exception import BotoServerError
UPLOAD_ID_BYTES = 43
UPLOAD_PART_MIN_SIZE = 5242880
@ -172,13 +171,12 @@ class FakeBucket(object):
return self.versioning_status == 'Enabled'
def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'DomainName':
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "DomainName" ]"')
elif attribute_name == 'WebsiteURL':
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "WebsiteURL" ]"')
raise BotoServerError(400,
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
raise UnformattedGetAttTemplateException()
class S3Backend(BaseBackend):

View File

@ -8,7 +8,6 @@ from moto.core import BaseBackend
from moto.core.utils import iso_8601_datetime
from moto.sqs.models import sqs_backend
from .utils import make_arn_for_topic, make_arn_for_subscription
from boto.exception import BotoServerError
DEFAULT_ACCOUNT_ID = 123456789012
@ -35,11 +34,10 @@ class Topic(object):
return message_id
def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'TopicName':
return self.name
raise BotoServerError(400,
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
raise UnformattedGetAttTemplateException()
class Subscription(object):

View File

@ -4,7 +4,7 @@ import hashlib
import time
import re
from boto.exception import BotoServerError
from moto.core import BaseBackend
from moto.core.utils import camelcase_to_underscores, get_random_message_id
from .utils import generate_receipt_handle, unix_time_millis
@ -154,13 +154,12 @@ class Queue(object):
self._messages.append(message)
def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'Arn':
return self.queue_arn
elif attribute_name == 'QueueName':
return self.name
raise BotoServerError(400,
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
raise UnformattedGetAttTemplateException()
class SQSBackend(BaseBackend):