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:
parent
83f187fa7e
commit
20a69255c3
6
moto/cloudformation/exceptions.py
Normal file
6
moto/cloudformation/exceptions.py
Normal 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
|
@ -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(
|
||||
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():
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
Loading…
Reference in New Issue
Block a user