Merge pull request #1150 from gvlproject/refactor_filtering

Refactored handling of unknown filter names
This commit is contained in:
Jack Danger 2017-09-16 12:07:13 -07:00 committed by GitHub
commit 35feb9feb7
2 changed files with 89 additions and 130 deletions

View File

@ -375,3 +375,20 @@ class RulesPerSecurityGroupLimitExceededError(EC2ClientError):
"RulesPerSecurityGroupLimitExceeded", "RulesPerSecurityGroupLimitExceeded",
'The maximum number of rules per security group ' 'The maximum number of rules per security group '
'has been reached.') 'has been reached.')
class MotoNotImplementedError(NotImplementedError):
def __init__(self, blurb):
super(MotoNotImplementedError, self).__init__(
"{0} has not been implemented in Moto yet."
" Feel free to open an issue at"
" https://github.com/spulec/moto/issues".format(blurb))
class FilterNotImplementedError(MotoNotImplementedError):
def __init__(self, filter_name, method_name):
super(FilterNotImplementedError, self).__init__(
"The filter '{0}' for {1}".format(
filter_name, method_name))

View File

@ -62,6 +62,8 @@ from .exceptions import (
InvalidVpnConnectionIdError, InvalidVpnConnectionIdError,
InvalidCustomerGatewayIdError, InvalidCustomerGatewayIdError,
RulesPerSecurityGroupLimitExceededError, RulesPerSecurityGroupLimitExceededError,
MotoNotImplementedError,
FilterNotImplementedError
) )
from .utils import ( from .utils import (
EC2_RESOURCE_TO_PREFIX, EC2_RESOURCE_TO_PREFIX,
@ -144,7 +146,7 @@ class TaggedEC2Resource(BaseModel):
for key, value in tag_map.items(): for key, value in tag_map.items():
self.ec2_backend.create_tags([self.id], {key: value}) self.ec2_backend.create_tags([self.id], {key: value})
def get_filter_value(self, filter_name): def get_filter_value(self, filter_name, method_name=None):
tags = self.get_tags() tags = self.get_tags()
if filter_name.startswith('tag:'): if filter_name.startswith('tag:'):
@ -154,12 +156,12 @@ class TaggedEC2Resource(BaseModel):
return tag['value'] return tag['value']
return '' return ''
elif filter_name == 'tag-key':
if filter_name == 'tag-key':
return [tag['key'] for tag in tags] return [tag['key'] for tag in tags]
elif filter_name == 'tag-value':
if filter_name == 'tag-value':
return [tag['value'] for tag in tags] return [tag['value'] for tag in tags]
else:
raise FilterNotImplementedError(filter_name, method_name)
class NetworkInterface(TaggedEC2Resource): class NetworkInterface(TaggedEC2Resource):
@ -261,17 +263,9 @@ class NetworkInterface(TaggedEC2Resource):
return [group.id for group in self._group_set] return [group.id for group in self._group_set]
elif filter_name == 'availability-zone': elif filter_name == 'availability-zone':
return self.subnet.availability_zone return self.subnet.availability_zone
else:
filter_value = super( return super(NetworkInterface, self).get_filter_value(
NetworkInterface, self).get_filter_value(filter_name) filter_name, 'DescribeNetworkInterfaces')
if filter_value is None:
self.ec2_backend.raise_not_implemented_error(
"The filter '{0}' for DescribeNetworkInterfaces".format(
filter_name)
)
return filter_value
class NetworkInterfaceBackend(object): class NetworkInterfaceBackend(object):
@ -802,6 +796,8 @@ class KeyPair(object):
return self.name return self.name
elif filter_name == 'fingerprint': elif filter_name == 'fingerprint':
return self.fingerprint return self.fingerprint
else:
raise FilterNotImplementedError(filter_name, 'DescribeKeyPairs')
class KeyPairBackend(object): class KeyPairBackend(object):
@ -1039,14 +1035,9 @@ class Ami(TaggedEC2Resource):
return self.state return self.state
elif filter_name == 'name': elif filter_name == 'name':
return self.name return self.name
else:
filter_value = super(Ami, self).get_filter_value(filter_name) return super(Ami, self).get_filter_value(
filter_name, 'DescribeImages')
if filter_value is None:
self.ec2_backend.raise_not_implemented_error(
"The filter '{0}' for DescribeImages".format(filter_name))
return filter_value
class AmiBackend(object): class AmiBackend(object):
@ -1703,43 +1694,31 @@ class Volume(TaggedEC2Resource):
return 'available' return 'available'
def get_filter_value(self, filter_name): def get_filter_value(self, filter_name):
if filter_name.startswith('attachment') and not self.attachment: if filter_name.startswith('attachment') and not self.attachment:
return None return None
if filter_name == 'attachment.attach-time': elif filter_name == 'attachment.attach-time':
return self.attachment.attach_time return self.attachment.attach_time
if filter_name == 'attachment.device': elif filter_name == 'attachment.device':
return self.attachment.device return self.attachment.device
if filter_name == 'attachment.instance-id': elif filter_name == 'attachment.instance-id':
return self.attachment.instance.id return self.attachment.instance.id
if filter_name == 'attachment.status': elif filter_name == 'attachment.status':
return self.attachment.status return self.attachment.status
elif filter_name == 'create-time':
if filter_name == 'create-time':
return self.create_time return self.create_time
elif filter_name == 'size':
if filter_name == 'size':
return self.size return self.size
elif filter_name == 'snapshot-id':
if filter_name == 'snapshot-id':
return self.snapshot_id return self.snapshot_id
elif filter_name == 'status':
if filter_name == 'status':
return self.status return self.status
elif filter_name == 'volume-id':
if filter_name == 'volume-id':
return self.id return self.id
elif filter_name == 'encrypted':
if filter_name == 'encrypted':
return str(self.encrypted).lower() return str(self.encrypted).lower()
else:
filter_value = super(Volume, self).get_filter_value(filter_name) return super(Volume, self).get_filter_value(
filter_name, 'DescribeVolumes')
if filter_value is None:
self.ec2_backend.raise_not_implemented_error(
"The filter '{0}' for DescribeVolumes".format(filter_name))
return filter_value
class Snapshot(TaggedEC2Resource): class Snapshot(TaggedEC2Resource):
@ -1754,35 +1733,23 @@ class Snapshot(TaggedEC2Resource):
self.encrypted = encrypted self.encrypted = encrypted
def get_filter_value(self, filter_name): def get_filter_value(self, filter_name):
if filter_name == 'description': if filter_name == 'description':
return self.description return self.description
elif filter_name == 'snapshot-id':
if filter_name == 'snapshot-id':
return self.id return self.id
elif filter_name == 'start-time':
if filter_name == 'start-time':
return self.start_time return self.start_time
elif filter_name == 'volume-id':
if filter_name == 'volume-id':
return self.volume.id return self.volume.id
elif filter_name == 'volume-size':
if filter_name == 'volume-size':
return self.volume.size return self.volume.size
elif filter_name == 'encrypted':
if filter_name == 'encrypted':
return str(self.encrypted).lower() return str(self.encrypted).lower()
elif filter_name == 'status':
if filter_name == 'status':
return self.status return self.status
else:
filter_value = super(Snapshot, self).get_filter_value(filter_name) return super(Snapshot, self).get_filter_value(
filter_name, 'DescribeSnapshots')
if filter_value is None:
self.ec2_backend.raise_not_implemented_error(
"The filter '{0}' for DescribeSnapshots".format(filter_name))
return filter_value
class EBSBackend(object): class EBSBackend(object):
@ -1944,16 +1911,10 @@ class VPC(TaggedEC2Resource):
elif filter_name in ('dhcp-options-id', 'dhcpOptionsId'): elif filter_name in ('dhcp-options-id', 'dhcpOptionsId'):
if not self.dhcp_options: if not self.dhcp_options:
return None return None
return self.dhcp_options.id return self.dhcp_options.id
else:
filter_value = super(VPC, self).get_filter_value(filter_name) return super(VPC, self).get_filter_value(
filter_name, 'DescribeVpcs')
if filter_value is None:
self.ec2_backend.raise_not_implemented_error(
"The filter '{0}' for DescribeVPCs".format(filter_name))
return filter_value
class VPCBackend(object): class VPCBackend(object):
@ -2187,14 +2148,9 @@ class Subnet(TaggedEC2Resource):
return self.availability_zone return self.availability_zone
elif filter_name in ('defaultForAz', 'default-for-az'): elif filter_name in ('defaultForAz', 'default-for-az'):
return self.default_for_az return self.default_for_az
else:
filter_value = super(Subnet, self).get_filter_value(filter_name) return super(Subnet, self).get_filter_value(
filter_name, 'DescribeSubnets')
if filter_value is None:
self.ec2_backend.raise_not_implemented_error(
"The filter '{0}' for DescribeSubnets".format(filter_name))
return filter_value
def get_cfn_attribute(self, attribute_name): def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
@ -2332,14 +2288,9 @@ class RouteTable(TaggedEC2Resource):
return self.associations.keys() return self.associations.keys()
elif filter_name == "association.subnet-id": elif filter_name == "association.subnet-id":
return self.associations.values() return self.associations.values()
else:
filter_value = super(RouteTable, self).get_filter_value(filter_name) return super(RouteTable, self).get_filter_value(
filter_name, 'DescribeRouteTables')
if filter_value is None:
self.ec2_backend.raise_not_implemented_error(
"The filter '{0}' for DescribeRouteTables".format(filter_name))
return filter_value
class RouteTableBackend(object): class RouteTableBackend(object):
@ -2686,16 +2637,11 @@ class SpotInstanceRequest(BotoSpotRequest, TaggedEC2Resource):
def get_filter_value(self, filter_name): def get_filter_value(self, filter_name):
if filter_name == 'state': if filter_name == 'state':
return self.state return self.state
if filter_name == 'spot-instance-request-id': elif filter_name == 'spot-instance-request-id':
return self.id return self.id
filter_value = super(SpotInstanceRequest, else:
self).get_filter_value(filter_name) return super(SpotInstanceRequest, self).get_filter_value(
filter_name, 'DescribeSpotInstanceRequests')
if filter_value is None:
self.ec2_backend.raise_not_implemented_error(
"The filter '{0}' for DescribeSpotInstanceRequests".format(filter_name))
return filter_value
def launch_instance(self): def launch_instance(self):
reservation = self.ec2_backend.add_instances( reservation = self.ec2_backend.add_instances(
@ -2966,15 +2912,13 @@ class ElasticAddress(object):
return self.instance.id return self.instance.id
elif filter_name == 'network-interface-id' and self.eni: elif filter_name == 'network-interface-id' and self.eni:
return self.eni.id return self.eni.id
elif filter_name == 'network-interface-owner-id':
msg = "The filter '{0}' for DescribeAddresses has not been" \
" implemented in Moto yet. Feel free to open an issue at" \
" https://github.com/spulec/moto/issues".format(filter_name)
raise NotImplementedError(msg)
elif filter_name == 'private-ip-address' and self.eni: elif filter_name == 'private-ip-address' and self.eni:
return self.eni.private_ip_address return self.eni.private_ip_address
elif filter_name == 'public-ip': elif filter_name == 'public-ip':
return self.public_ip return self.public_ip
else:
# TODO: implement network-interface-owner-id
raise FilterNotImplementedError(filter_name, 'DescribeAddresses')
class ElasticAddressBackend(object): class ElasticAddressBackend(object):
@ -3134,15 +3078,9 @@ class DHCPOptionsSet(TaggedEC2Resource):
elif filter_name == 'value': elif filter_name == 'value':
values = [item for item in list(self._options.values()) if item] values = [item for item in list(self._options.values()) if item]
return itertools.chain(*values) return itertools.chain(*values)
else:
filter_value = super( return super(DHCPOptionsSet, self).get_filter_value(
DHCPOptionsSet, self).get_filter_value(filter_name) filter_name, 'DescribeDhcpOptions')
if filter_value is None:
self.ec2_backend.raise_not_implemented_error(
"The filter '{0}' for DescribeDhcpOptions".format(filter_name))
return filter_value
@property @property
def options(self): def options(self):
@ -3229,6 +3167,10 @@ class VPNConnection(TaggedEC2Resource):
self.options = None self.options = None
self.static_routes = None self.static_routes = None
def get_filter_value(self, filter_name):
return super(VPNConnection, self).get_filter_value(
filter_name, 'DescribeVpnConnections')
class VPNConnectionBackend(object): class VPNConnectionBackend(object):
def __init__(self): def __init__(self):
@ -3408,14 +3350,9 @@ class NetworkAcl(TaggedEC2Resource):
return self.id return self.id
elif filter_name == "association.subnet-id": elif filter_name == "association.subnet-id":
return [assoc.subnet_id for assoc in self.associations.values()] return [assoc.subnet_id for assoc in self.associations.values()]
else:
filter_value = super(NetworkAcl, self).get_filter_value(filter_name) return super(NetworkAcl, self).get_filter_value(
filter_name, 'DescribeNetworkAcls')
if filter_value is None:
self.ec2_backend.raise_not_implemented_error(
"The filter '{0}' for DescribeNetworkAcls".format(filter_name))
return filter_value
class NetworkAclEntry(TaggedEC2Resource): class NetworkAclEntry(TaggedEC2Resource):
@ -3444,6 +3381,10 @@ class VpnGateway(TaggedEC2Resource):
self.attachments = {} self.attachments = {}
super(VpnGateway, self).__init__() super(VpnGateway, self).__init__()
def get_filter_value(self, filter_name):
return super(VpnGateway, self).get_filter_value(
filter_name, 'DescribeVpnGateways')
class VpnGatewayAttachment(object): class VpnGatewayAttachment(object):
def __init__(self, vpc_id, state): def __init__(self, vpc_id, state):
@ -3505,6 +3446,10 @@ class CustomerGateway(TaggedEC2Resource):
self.attachments = {} self.attachments = {}
super(CustomerGateway, self).__init__() super(CustomerGateway, self).__init__()
def get_filter_value(self, filter_name):
return super(CustomerGateway, self).get_filter_value(
filter_name, 'DescribeCustomerGateways')
class CustomerGatewayBackend(object): class CustomerGatewayBackend(object):
def __init__(self): def __init__(self):
@ -3648,10 +3593,7 @@ class EC2Backend(BaseBackend, InstanceBackend, TagBackend, AmiBackend,
raise EC2ClientError(code, message) raise EC2ClientError(code, message)
def raise_not_implemented_error(self, blurb): def raise_not_implemented_error(self, blurb):
msg = "{0} has not been implemented in Moto yet." \ raise MotoNotImplementedError(blurb)
" Feel free to open an issue at" \
" https://github.com/spulec/moto/issues".format(blurb)
raise NotImplementedError(msg)
def do_resources_exist(self, resource_ids): def do_resources_exist(self, resource_ids):
for resource_id in resource_ids: for resource_id in resource_ids: