moto/moto/ec2/utils.py

511 lines
16 KiB
Python
Raw Normal View History

from __future__ import unicode_literals
2013-02-18 16:09:40 -05:00
import random
2013-07-08 21:18:05 -04:00
import re
2014-08-26 13:25:50 -04:00
import six
2013-02-18 16:09:40 -05:00
2014-10-05 21:55:23 -04:00
EC2_RESOURCE_TO_PREFIX = {
'customer-gateway': 'cgw',
'dhcp-options': 'dopt',
'image': 'ami',
'instance': 'i',
'internet-gateway': 'igw',
'network-acl': 'acl',
'network-acl-subnet-assoc': 'aclassoc',
2014-10-05 21:55:23 -04:00
'network-interface': 'eni',
'network-interface-attachment': 'eni-attach',
'reserved-instance': 'uuid4',
'route-table': 'rtb',
'route-table-association': 'rtbassoc',
2014-10-05 21:55:23 -04:00
'security-group': 'sg',
'snapshot': 'snap',
'spot-instance-request': 'sir',
'subnet': 'subnet',
'reservation': 'r',
'volume': 'vol',
'vpc': 'vpc',
'vpc-elastic-ip': 'eipalloc',
'vpc-elastic-ip-association': 'eipassoc',
'vpc-peering-connection': 'pcx',
'vpn-connection': 'vpn',
'vpn-gateway': 'vgw'}
EC2_PREFIX_TO_RESOURCE = dict((v, k) for (k, v) in EC2_RESOURCE_TO_PREFIX.items())
2013-02-18 16:09:40 -05:00
def random_id(prefix=''):
size = 8
2014-08-26 13:25:50 -04:00
chars = list(range(10)) + ['a', 'b', 'c', 'd', 'e', 'f']
2013-02-18 16:09:40 -05:00
2014-10-05 21:55:23 -04:00
resource_id = ''.join(six.text_type(random.choice(chars)) for x in range(size))
return '{0}-{1}'.format(prefix, resource_id)
2013-02-18 16:09:40 -05:00
2013-02-18 23:06:23 -05:00
2013-08-17 18:11:29 -04:00
def random_ami_id():
2014-10-05 21:55:23 -04:00
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['image'])
2013-08-17 18:11:29 -04:00
2013-02-18 16:09:40 -05:00
def random_instance_id():
2014-10-05 21:55:23 -04:00
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['instance'])
2013-02-18 16:09:40 -05:00
2013-02-18 23:06:23 -05:00
2013-02-18 16:09:40 -05:00
def random_reservation_id():
2014-10-05 21:55:23 -04:00
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['reservation'])
2013-02-18 23:06:23 -05:00
2013-02-23 15:26:54 -05:00
def random_security_group_id():
2014-10-05 21:55:23 -04:00
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['security-group'])
2013-02-23 15:26:54 -05:00
2013-08-17 18:11:29 -04:00
def random_snapshot_id():
2014-10-05 21:55:23 -04:00
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['snapshot'])
2013-02-23 17:37:55 -05:00
2013-08-17 18:11:29 -04:00
def random_spot_request_id():
2014-10-05 21:55:23 -04:00
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['spot-instance-request'])
2013-03-05 22:33:41 -05:00
2013-03-05 22:53:53 -05:00
def random_subnet_id():
2014-10-05 21:55:23 -04:00
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['subnet'])
2013-03-05 22:53:53 -05:00
def random_subnet_association_id():
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['route-table-association'])
def random_network_acl_id():
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['network-acl'])
def random_network_acl_subnet_association_id():
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['network-acl-subnet-assoc'])
2014-12-02 10:28:09 -06:00
def random_vpn_gateway_id():
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['vpn-gateway'])
def random_vpn_connection_id():
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['vpn-connection'])
def random_customer_gateway_id():
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['customer-gateway'])
2013-08-17 18:11:29 -04:00
def random_volume_id():
2014-10-05 21:55:23 -04:00
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['volume'])
2013-08-17 18:11:29 -04:00
def random_vpc_id():
2014-10-05 21:55:23 -04:00
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['vpc'])
2014-07-31 14:41:30 -07:00
def random_vpc_peering_connection_id():
2014-10-05 21:55:23 -04:00
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['vpc-peering-connection'])
2014-07-31 14:41:30 -07:00
2013-09-03 21:47:16 -04:00
def random_eip_association_id():
2014-10-05 21:55:23 -04:00
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['vpc-elastic-ip-association'])
2013-09-03 21:47:16 -04:00
2014-06-05 00:12:22 -04:00
def random_internet_gateway_id():
2014-10-05 21:55:23 -04:00
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['internet-gateway'])
def random_route_table_id():
2014-10-05 21:55:23 -04:00
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['route-table'])
2013-09-03 21:47:16 -04:00
def random_eip_allocation_id():
2014-10-05 21:55:23 -04:00
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['vpc-elastic-ip'])
2013-09-03 21:47:16 -04:00
2014-04-15 19:02:26 -04:00
def random_dhcp_option_id():
2014-10-05 21:55:23 -04:00
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['dhcp-options'])
2014-04-15 19:02:26 -04:00
def random_eni_id():
2014-10-05 21:55:23 -04:00
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['network-interface'])
def random_eni_attach_id():
2014-10-05 21:55:23 -04:00
return random_id(prefix=EC2_RESOURCE_TO_PREFIX['network-interface-attachment'])
def random_public_ip():
return '54.214.{0}.{1}'.format(random.choice(range(255)),
random.choice(range(255)))
2014-09-30 17:07:09 +03:00
def random_private_ip():
return '10.{0}.{1}.{2}'.format(random.choice(range(255)),
random.choice(range(255)),
random.choice(range(255)))
2013-09-03 21:47:16 -04:00
def random_ip():
return "127.{0}.{1}.{2}".format(
random.randint(0, 255),
random.randint(0, 255),
random.randint(0, 255)
)
def generate_route_id(route_table_id, cidr_block):
return "%s~%s" % (route_table_id, cidr_block)
def split_route_id(route_id):
2014-11-15 09:35:52 -05:00
values = route_id.split('~')
return values[0], values[1]
2013-02-18 23:06:23 -05:00
def instance_ids_from_querystring(querystring_dict):
instance_ids = []
2014-08-26 13:25:50 -04:00
for key, value in querystring_dict.items():
2013-02-18 23:06:23 -05:00
if 'InstanceId' in key:
instance_ids.append(value[0])
return instance_ids
def image_ids_from_querystring(querystring_dict):
image_ids = []
2014-08-26 13:25:50 -04:00
for key, value in querystring_dict.items():
if 'ImageId' in key:
image_ids.append(value[0])
return image_ids
def route_table_ids_from_querystring(querystring_dict):
route_table_ids = []
for key, value in querystring_dict.items():
if 'RouteTableId' in key:
route_table_ids.append(value[0])
return route_table_ids
def network_acl_ids_from_querystring(querystring_dict):
network_acl_ids = []
for key, value in querystring_dict.items():
if 'NetworkAclId' in key:
network_acl_ids.append(value[0])
return network_acl_ids
2014-09-30 17:07:09 +03:00
def vpc_ids_from_querystring(querystring_dict):
vpc_ids = []
for key, value in querystring_dict.items():
if 'VpcId' in key:
vpc_ids.append(value[0])
return vpc_ids
2013-09-03 21:47:16 -04:00
def sequence_from_querystring(parameter, querystring_dict):
parameter_values = []
2014-08-26 13:25:50 -04:00
for key, value in querystring_dict.items():
2013-09-03 21:47:16 -04:00
if parameter in key:
parameter_values.append(value[0])
return parameter_values
2014-10-05 21:55:23 -04:00
def tags_from_query_string(querystring_dict):
prefix = 'Tag'
suffix = 'Key'
2013-02-20 23:19:43 -05:00
response_values = {}
2014-08-26 13:25:50 -04:00
for key, value in querystring_dict.items():
2014-10-05 21:55:23 -04:00
if key.startswith(prefix) and key.endswith(suffix):
tag_index = key.replace(prefix + ".", "").replace("." + suffix, "")
tag_key = querystring_dict.get("Tag.{0}.Key".format(tag_index))[0]
tag_value_key = "Tag.{0}.Value".format(tag_index)
2013-02-25 23:37:01 -05:00
if tag_value_key in querystring_dict:
2014-10-05 21:55:23 -04:00
response_values[tag_key] = querystring_dict.get(tag_value_key)[0]
2013-02-25 23:37:01 -05:00
else:
2014-10-05 21:55:23 -04:00
response_values[tag_key] = None
2013-02-20 23:19:43 -05:00
return response_values
2013-07-08 21:18:05 -04:00
2014-04-15 19:02:26 -04:00
def dhcp_configuration_from_querystring(querystring, option=u'DhcpConfiguration'):
"""
turn:
{u'AWSAccessKeyId': [u'the_key'],
u'Action': [u'CreateDhcpOptions'],
u'DhcpConfiguration.1.Key': [u'domain-name'],
u'DhcpConfiguration.1.Value.1': [u'example.com'],
u'DhcpConfiguration.2.Key': [u'domain-name-servers'],
u'DhcpConfiguration.2.Value.1': [u'10.0.0.6'],
u'DhcpConfiguration.2.Value.2': [u'10.0.0.7'],
u'Signature': [u'uUMHYOoLM6r+sT4fhYjdNT6MHw22Wj1mafUpe0P0bY4='],
u'SignatureMethod': [u'HmacSHA256'],
u'SignatureVersion': [u'2'],
u'Timestamp': [u'2014-03-18T21:54:01Z'],
u'Version': [u'2013-10-15']}
into:
{u'domain-name': [u'example.com'], u'domain-name-servers': [u'10.0.0.6', u'10.0.0.7']}
"""
key_needle = re.compile(u'{0}.[0-9]+.Key'.format(option), re.UNICODE)
response_values = {}
2014-08-26 13:25:50 -04:00
for key, value in querystring.items():
2014-04-15 19:02:26 -04:00
if key_needle.match(key):
values = []
key_index = key.split(".")[1]
value_index = 1
while True:
value_key = u'{0}.{1}.Value.{2}'.format(option, key_index, value_index)
if value_key in querystring:
values.extend(querystring[value_key])
else:
break
value_index += 1
response_values[value[0]] = values
return response_values
def optional_from_querystring(parameter, querystring):
parameter_array = querystring.get(parameter)
return parameter_array[0] if parameter_array else None
2013-07-08 21:18:05 -04:00
def filters_from_querystring(querystring_dict):
response_values = {}
2014-08-26 13:25:50 -04:00
for key, value in querystring_dict.items():
2014-06-05 00:12:22 -04:00
match = re.search(r"Filter.(\d).Name", key)
2013-07-08 21:18:05 -04:00
if match:
filter_index = match.groups()[0]
2013-10-03 20:34:13 -04:00
value_prefix = "Filter.{0}.Value".format(filter_index)
2014-09-30 17:07:09 +03:00
filter_values = [filter_value[0] for filter_key, filter_value in querystring_dict.items() if
filter_key.startswith(value_prefix)]
2013-07-08 21:18:05 -04:00
response_values[value[0]] = filter_values
return response_values
def dict_from_querystring(parameter, querystring_dict):
2014-09-30 17:07:09 +03:00
use_dict = {}
for key, value in querystring_dict.items():
match = re.search(r"{0}.(\d).(\w+)".format(parameter), key)
if match:
use_dict_index = match.groups()[0]
use_dict_element_property = match.groups()[1]
if not use_dict.get(use_dict_index):
use_dict[use_dict_index] = {}
2014-09-30 17:07:09 +03:00
use_dict[use_dict_index][use_dict_element_property] = value[0]
return use_dict
2014-02-24 15:22:08 +02:00
def keypair_names_from_querystring(querystring_dict):
keypair_names = []
2014-08-26 13:25:50 -04:00
for key, value in querystring_dict.items():
2014-02-24 15:22:08 +02:00
if 'KeyName' in key:
keypair_names.append(value[0])
return keypair_names
2014-04-15 19:02:26 -04:00
def get_object_value(obj, attr):
keys = attr.split('.')
val = obj
for key in keys:
if hasattr(val, key):
val = getattr(val, key)
elif isinstance(val, dict):
val = val[key]
else:
return None
return val
2013-07-08 21:18:05 -04:00
def is_tag_filter(filter_name):
return (filter_name.startswith('tag:') or
2015-02-23 10:45:16 -06:00
filter_name.startswith('tag-value') or
filter_name.startswith('tag-key'))
def get_obj_tag(obj, filter_name):
tag_name = filter_name.replace('tag:', '', 1)
tags = dict((tag['key'], tag['value']) for tag in obj.get_tags())
return tags.get(tag_name)
2015-02-23 10:45:16 -06:00
def get_obj_tag_names(obj):
tags = set((tag['key'] for tag in obj.get_tags()))
return tags
def get_obj_tag_values(obj):
tags = set((tag['value'] for tag in obj.get_tags()))
return tags
def tag_filter_matches(obj, filter_name, filter_values):
2015-02-23 10:45:16 -06:00
if filter_name == 'tag-key':
tag_names = get_obj_tag_names(obj)
return len(set(filter_values).intersection(tag_names)) > 0
elif filter_name == 'tag-value':
tag_values = get_obj_tag_values(obj)
return len(set(filter_values).intersection(tag_values)) > 0
else:
tag_value = get_obj_tag(obj, filter_name)
return tag_value in filter_values
filter_dict_attribute_mapping = {
'instance-state-name': 'state',
'instance-id': 'id',
'state-reason-code': '_state_reason.code',
'source-dest-check': 'source_dest_check',
'vpc-id': 'vpc_id',
'group-id': 'security_groups',
2015-02-23 10:45:16 -06:00
'instance.group-id': 'security_groups',
2015-02-23 11:03:59 -06:00
'instance-type': 'instance_type'
}
2013-07-08 21:18:05 -04:00
def passes_filter_dict(instance, filter_dict):
2014-08-26 13:25:50 -04:00
for filter_name, filter_values in filter_dict.items():
2013-07-08 21:18:05 -04:00
if filter_name in filter_dict_attribute_mapping:
instance_attr = filter_dict_attribute_mapping[filter_name]
instance_value = get_object_value(instance, instance_attr)
if not instance_value_in_filter_values(instance_value, filter_values):
2014-09-03 16:14:21 -07:00
return False
elif is_tag_filter(filter_name):
if not tag_filter_matches(instance, filter_name, filter_values):
2014-09-03 16:14:21 -07:00
return False
2013-07-08 21:18:05 -04:00
else:
2014-09-30 17:07:09 +03:00
raise NotImplementedError(
"Filter dicts have not been implemented in Moto for '%s' yet. Feel free to open an issue at https://github.com/spulec/moto/issues",
filter_name)
2013-07-08 21:18:05 -04:00
return True
def instance_value_in_filter_values(instance_value, filter_values):
if isinstance(instance_value, list):
if not set(filter_values).intersection(set(instance_value)):
return False
elif instance_value not in filter_values:
return False
return True
2013-07-08 21:18:05 -04:00
2013-07-08 21:18:05 -04:00
def filter_reservations(reservations, filter_dict):
result = []
2013-07-08 21:18:05 -04:00
for reservation in reservations:
new_instances = []
for instance in reservation.instances:
if passes_filter_dict(instance, filter_dict):
new_instances.append(instance)
if new_instances:
reservation.instances = new_instances
result.append(reservation)
return result
2014-02-24 13:03:26 +02:00
filter_dict_igw_mapping = {
"attachment.vpc-id": "vpc.id",
"attachment.state": "attachment_state",
"internet-gateway-id": "id",
}
def passes_igw_filter_dict(igw, filter_dict):
for filter_name, filter_values in filter_dict.items():
if filter_name in filter_dict_igw_mapping:
igw_attr = filter_dict_igw_mapping[filter_name]
if get_object_value(igw, igw_attr) not in filter_values:
return False
elif is_tag_filter(filter_name):
if not tag_filter_matches(igw, filter_name, filter_values):
return False
else:
raise NotImplementedError(
"Internet Gateway filter dicts have not been implemented in Moto for '%s' yet. Feel free to open an issue at https://github.com/spulec/moto/issues",
filter_name)
return True
def filter_internet_gateways(igws, filter_dict):
result = []
for igw in igws:
if passes_igw_filter_dict(igw, filter_dict):
result.append(igw)
return result
def is_filter_matching(obj, filter, filter_value):
value = obj.get_filter_value(filter)
if isinstance(value, six.string_types):
return value in filter_value
try:
value = set(value)
return (value and value.issubset(filter_value)) or value.issuperset(filter_value)
except TypeError:
return value in filter_value
def generic_filter(filters, objects):
if filters:
for (_filter, _filter_value) in filters.items():
objects = [obj for obj in objects if is_filter_matching(obj, _filter, _filter_value)]
return objects
2014-10-05 21:55:23 -04:00
def simple_aws_filter_to_re(filter_string):
import fnmatch
2014-11-15 09:53:45 -05:00
tmp_filter = filter_string.replace('\?', '[?]')
tmp_filter = tmp_filter.replace('\*', '[*]')
2014-10-05 21:55:23 -04:00
tmp_filter = fnmatch.translate(tmp_filter)
return tmp_filter
2014-02-24 13:03:26 +02:00
def random_key_pair():
def random_hex():
return chr(random.choice(list(range(48, 58)) + list(range(97, 102))))
def random_fingerprint():
return ':'.join([random_hex()+random_hex() for i in range(20)])
def random_material():
return ''.join([
chr(random.choice(list(range(65, 91)) + list(range(48, 58)) +
list(range(97, 102))))
for i in range(1000)
])
material = "---- BEGIN RSA PRIVATE KEY ----" + random_material() + \
"-----END RSA PRIVATE KEY-----"
2014-02-24 13:03:26 +02:00
return {
'fingerprint': random_fingerprint(),
'material': material
2014-02-24 13:03:26 +02:00
}
2014-10-05 21:55:23 -04:00
def get_prefix(resource_id):
resource_id_prefix, separator, after = resource_id.partition('-')
if resource_id_prefix == EC2_RESOURCE_TO_PREFIX['network-interface']:
if after.startswith('attach'):
resource_id_prefix = EC2_RESOURCE_TO_PREFIX['network-interface-attachment']
2014-11-15 09:53:45 -05:00
if resource_id_prefix not in EC2_RESOURCE_TO_PREFIX.values():
2014-10-05 21:55:23 -04:00
uuid4hex = re.compile('[0-9a-f]{12}4[0-9a-f]{3}[89ab][0-9a-f]{15}\Z', re.I)
if uuid4hex.match(resource_id) is not None:
resource_id_prefix = EC2_RESOURCE_TO_PREFIX['reserved-instance']
else:
return None
return resource_id_prefix
def is_valid_resource_id(resource_id):
valid_prefixes = EC2_RESOURCE_TO_PREFIX.values()
resource_id_prefix = get_prefix(resource_id)
2014-11-15 09:53:45 -05:00
if resource_id_prefix not in valid_prefixes:
2014-10-05 21:55:23 -04:00
return False
resource_id_pattern = resource_id_prefix + '-[0-9a-f]{8}'
resource_pattern_re = re.compile(resource_id_pattern)
return resource_pattern_re.match(resource_id) is not None
def is_valid_cidr(cird):
cidr_pattern = '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(\d|[1-2]\d|3[0-2]))$'
cidr_pattern_re = re.compile(cidr_pattern)
return cidr_pattern_re.match(cird) is not None