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.iam import models as iam_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 UnformattedGetAttTemplateException
from boto.cloudformation.stack import Output from boto.cloudformation.stack import Output
from boto.exception import BotoServerError from boto.exception import BotoServerError
@ -72,17 +73,22 @@ def clean_json(resource_json, resources_map):
return resource return resource
if 'Fn::GetAtt' in resource_json: if 'Fn::GetAtt' in resource_json:
resource = resources_map[resource_json['Fn::GetAtt'][0]] resource = resources_map[resource_json['Fn::GetAtt'][0]]
if resource is None:
return resource_json
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:
raise NotImplementedError(n.message.format(resource_json['Fn::GetAtt'][0])) logger.warning(n.message.format(resource_json['Fn::GetAtt'][0]))
except AttributeError: except UnformattedGetAttTemplateException:
raise BotoServerError( raise BotoServerError(
400, UnformattedGetAttTemplateException.status_code,
'Bad Request', 'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt'.format( UnformattedGetAttTemplateException.description.format(
resource_json['Fn::GetAtt'][0], resource_json['Fn::GetAtt'][1])) resource_json['Fn::GetAtt'][0], resource_json['Fn::GetAtt'][1]))
except Exception as e:
pass
cleaned_json = {} cleaned_json = {}
for key, value in resource_json.items(): 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.blockdevicemapping import BlockDeviceMapping, BlockDeviceType
from boto.ec2.spotinstancerequest import SpotInstanceRequest as BotoSpotRequest from boto.ec2.spotinstancerequest import SpotInstanceRequest as BotoSpotRequest
from boto.ec2.launchspecification import LaunchSpecification from boto.ec2.launchspecification import LaunchSpecification
from boto.exception import BotoServerError
from moto.core import BaseBackend from moto.core import BaseBackend
from moto.core.models import Model from moto.core.models import Model
@ -187,13 +186,12 @@ class NetworkInterface(object):
return self._group_set return self._group_set
def get_cfn_attribute(self, attribute_name): def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'PrimaryPrivateIpAddress': if attribute_name == 'PrimaryPrivateIpAddress':
return self.private_ip_address return self.private_ip_address
elif attribute_name == 'SecondaryPrivateIpAddresses': elif attribute_name == 'SecondaryPrivateIpAddresses':
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "SecondaryPrivateIpAddresses" ]"') raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "SecondaryPrivateIpAddresses" ]"')
raise BotoServerError(400, raise UnformattedGetAttTemplateException()
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
class NetworkInterfaceBackend(object): class NetworkInterfaceBackend(object):
@ -423,6 +421,7 @@ class Instance(BotoInstance, TaggedEC2Resource):
eni.device_index = None eni.device_index = None
def get_cfn_attribute(self, attribute_name): def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'AvailabilityZone': if attribute_name == 'AvailabilityZone':
return self.placement return self.placement
elif attribute_name == 'PrivateDnsName': elif attribute_name == 'PrivateDnsName':
@ -433,9 +432,7 @@ class Instance(BotoInstance, TaggedEC2Resource):
return self.private_ip_address return self.private_ip_address
elif attribute_name == 'PublicIp': elif attribute_name == 'PublicIp':
return self.ip_address return self.ip_address
raise BotoServerError(400, raise UnformattedGetAttTemplateException()
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
class InstanceBackend(object): class InstanceBackend(object):
@ -997,11 +994,10 @@ class SecurityGroup(object):
return True return True
def get_cfn_attribute(self, attribute_name): def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'GroupId': if attribute_name == 'GroupId':
return self.id return self.id
raise BotoServerError(400, raise UnformattedGetAttTemplateException()
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
class SecurityGroupBackend(object): class SecurityGroupBackend(object):
@ -1527,11 +1523,10 @@ class Subnet(TaggedEC2Resource):
return filter_value return filter_value
def get_cfn_attribute(self, attribute_name): def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'AvailabilityZone': if attribute_name == 'AvailabilityZone':
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "AvailabilityZone" ]"') raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "AvailabilityZone" ]"')
raise BotoServerError(400, raise UnformattedGetAttTemplateException()
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
class SubnetBackend(object): class SubnetBackend(object):
@ -1969,11 +1964,10 @@ class ElasticAddress(object):
return self.allocation_id return self.allocation_id
def get_cfn_attribute(self, attribute_name): def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'AllocationId': if attribute_name == 'AllocationId':
return self.allocation_id return self.allocation_id
raise BotoServerError(400, raise UnformattedGetAttTemplateException()
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
class ElasticAddressBackend(object): class ElasticAddressBackend(object):

View File

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

View File

@ -31,11 +31,10 @@ class Role(object):
return self.id return self.id
def get_cfn_attribute(self, attribute_name): def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'Arn': if attribute_name == 'Arn':
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "Arn" ]"') raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "Arn" ]"')
raise BotoServerError(400, raise UnformattedGetAttTemplateException()
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
class InstanceProfile(object): class InstanceProfile(object):
@ -61,11 +60,10 @@ class InstanceProfile(object):
return self.name return self.name
def get_cfn_attribute(self, attribute_name): def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'Arn': if attribute_name == 'Arn':
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "Arn" ]"') raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "Arn" ]"')
raise BotoServerError(400, raise UnformattedGetAttTemplateException()
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
class Certificate(object): class Certificate(object):
@ -93,11 +91,10 @@ class AccessKey(object):
) )
def get_cfn_attribute(self, attribute_name): def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'SecretAccessKey': if attribute_name == 'SecretAccessKey':
return self.secret_access_key return self.secret_access_key
raise BotoServerError(400, raise UnformattedGetAttTemplateException()
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
class Group(object): class Group(object):
@ -113,11 +110,10 @@ class Group(object):
self.users = [] self.users = []
def get_cfn_attribute(self, attribute_name): def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'Arn': if attribute_name == 'Arn':
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "Arn" ]"') raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "Arn" ]"')
raise BotoServerError(400, raise UnformattedGetAttTemplateException()
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
class User(object): class User(object):
@ -172,11 +168,10 @@ class User(object):
raise BotoServerError(404, 'Not Found') raise BotoServerError(404, 'Not Found')
def get_cfn_attribute(self, attribute_name): def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'Arn': if attribute_name == 'Arn':
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "Arn" ]"') raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "Arn" ]"')
raise BotoServerError(400, raise UnformattedGetAttTemplateException()
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
class IAMBackend(BaseBackend): 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 moto.core.utils import iso_8601_datetime, rfc_1123_datetime
from .exceptions import BucketAlreadyExists, MissingBucket from .exceptions import BucketAlreadyExists, MissingBucket
from .utils import clean_key_name, _VersionedKeyStore from .utils import clean_key_name, _VersionedKeyStore
from boto.exception import BotoServerError
UPLOAD_ID_BYTES = 43 UPLOAD_ID_BYTES = 43
UPLOAD_PART_MIN_SIZE = 5242880 UPLOAD_PART_MIN_SIZE = 5242880
@ -172,13 +171,12 @@ class FakeBucket(object):
return self.versioning_status == 'Enabled' return self.versioning_status == 'Enabled'
def get_cfn_attribute(self, attribute_name): def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == 'DomainName': if attribute_name == 'DomainName':
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "DomainName" ]"') raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "DomainName" ]"')
elif attribute_name == 'WebsiteURL': elif attribute_name == 'WebsiteURL':
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "WebsiteURL" ]"') raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "WebsiteURL" ]"')
raise BotoServerError(400, raise UnformattedGetAttTemplateException()
'Bad Request',
'Template error: resource {0} does not support attribute type {1} in Fn::GetAtt')
class S3Backend(BaseBackend): class S3Backend(BaseBackend):

View File

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

View File

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