From 20a69255c30f5d327052ba732f262a29c2af883a Mon Sep 17 00:00:00 2001 From: Joseph Lawson Date: Tue, 21 Oct 2014 14:51:26 -0400 Subject: [PATCH] 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. --- moto/cloudformation/exceptions.py | 6 ++++++ moto/cloudformation/parsing.py | 16 +++++++++++----- moto/ec2/models.py | 26 ++++++++++---------------- moto/elb/models.py | 6 ++---- moto/iam/models.py | 25 ++++++++++--------------- moto/s3/models.py | 6 ++---- moto/sns/models.py | 6 ++---- moto/sqs/models.py | 7 +++---- 8 files changed, 46 insertions(+), 52 deletions(-) create mode 100644 moto/cloudformation/exceptions.py diff --git a/moto/cloudformation/exceptions.py b/moto/cloudformation/exceptions.py new file mode 100644 index 000000000..a0a4eb63c --- /dev/null +++ b/moto/cloudformation/exceptions.py @@ -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 diff --git a/moto/cloudformation/parsing.py b/moto/cloudformation/parsing.py index 4dbe687d9..b0f29fc21 100644 --- a/moto/cloudformation/parsing.py +++ b/moto/cloudformation/parsing.py @@ -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(): diff --git a/moto/ec2/models.py b/moto/ec2/models.py index b75be944f..77f489eb3 100644 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -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): diff --git a/moto/elb/models.py b/moto/elb/models.py index 026a3e4f4..c0eb4e686 100644 --- a/moto/elb/models.py +++ b/moto/elb/models.py @@ -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): diff --git a/moto/iam/models.py b/moto/iam/models.py index 477192dfa..304a3ee16 100644 --- a/moto/iam/models.py +++ b/moto/iam/models.py @@ -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): diff --git a/moto/s3/models.py b/moto/s3/models.py index 2a342fd81..6e003edda 100644 --- a/moto/s3/models.py +++ b/moto/s3/models.py @@ -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): diff --git a/moto/sns/models.py b/moto/sns/models.py index 765295dc7..9b11d9530 100644 --- a/moto/sns/models.py +++ b/moto/sns/models.py @@ -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): diff --git a/moto/sqs/models.py b/moto/sqs/models.py index 3a6746697..f50806e8a 100644 --- a/moto/sqs/models.py +++ b/moto/sqs/models.py @@ -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):