moto/moto/ec2/models.py

455 lines
14 KiB
Python
Raw Normal View History

2013-02-21 04:19:43 +00:00
from collections import defaultdict
2013-02-28 05:08:35 +00:00
from boto.ec2.instance import Instance as BotoInstance, Reservation
2013-02-18 21:09:40 +00:00
from moto.core import BaseBackend
from .utils import (
random_ami_id,
random_instance_id,
random_reservation_id,
random_security_group_id,
random_snapshot_id,
2013-03-06 03:53:53 +00:00
random_subnet_id,
random_volume_id,
2013-03-06 03:33:41 +00:00
random_vpc_id,
)
2013-02-18 21:09:40 +00:00
2013-02-28 05:08:35 +00:00
class Instance(BotoInstance):
def __init__(self):
self._state_name = None
self._state_code = None
super(Instance, self).__init__()
2013-02-21 04:19:43 +00:00
class InstanceBackend(object):
2013-02-18 21:09:40 +00:00
def __init__(self):
self.reservations = {}
2013-02-21 04:19:43 +00:00
super(InstanceBackend, self).__init__()
2013-02-18 21:09:40 +00:00
2013-02-19 04:06:23 +00:00
def get_instance(self, instance_id):
for instance in self.all_instances():
if instance.id == instance_id:
return instance
2013-02-18 21:09:40 +00:00
2013-03-05 13:14:43 +00:00
def add_instances(self, image_id, count):
2013-02-18 21:09:40 +00:00
new_reservation = Reservation()
new_reservation.id = random_reservation_id()
2013-02-19 04:06:23 +00:00
for index in range(count):
new_instance = Instance()
new_instance.id = random_instance_id()
2013-03-05 13:14:43 +00:00
new_instance.image_id = image_id
2013-02-28 05:08:35 +00:00
new_instance._state_name = "pending"
new_instance._state_code = 0
2013-02-19 04:06:23 +00:00
new_reservation.instances.append(new_instance)
2013-02-18 21:09:40 +00:00
self.reservations[new_reservation.id] = new_reservation
return new_reservation
2013-02-19 02:56:22 +00:00
def start_instances(self, instance_ids):
started_instances = []
for instance in self.all_instances():
if instance.id in instance_ids:
2013-02-28 05:08:35 +00:00
instance._state_name = "pending"
instance._state_code = 0
2013-02-19 02:56:22 +00:00
started_instances.append(instance)
return started_instances
def stop_instances(self, instance_ids):
stopped_instances = []
for instance in self.all_instances():
if instance.id in instance_ids:
2013-02-28 05:08:35 +00:00
instance._state_name = "stopping"
instance._state_code = 64
2013-02-19 02:56:22 +00:00
stopped_instances.append(instance)
return stopped_instances
2013-02-18 21:09:40 +00:00
def terminate_instances(self, instance_ids):
terminated_instances = []
for instance in self.all_instances():
if instance.id in instance_ids:
2013-02-28 05:08:35 +00:00
instance._state_name = "shutting-down"
instance._state_code = 32
2013-02-18 21:09:40 +00:00
terminated_instances.append(instance)
return terminated_instances
2013-02-20 04:55:01 +00:00
def reboot_instances(self, instance_ids):
rebooted_instances = []
for instance in self.all_instances():
if instance.id in instance_ids:
# TODO double check instances go to pending when reboot
2013-02-28 05:08:35 +00:00
instance._state_name = "pending"
instance._state_code = 0
2013-02-20 04:55:01 +00:00
rebooted_instances.append(instance)
return rebooted_instances
def modify_instance_attribute(self, instance_id, key, value):
instance = self.get_instance(instance_id)
setattr(instance, key, value)
return instance
def describe_instance_attribute(self, instance_id, key):
instance = self.get_instance(instance_id)
value = getattr(instance, key)
return instance, value
2013-02-18 21:09:40 +00:00
def all_instances(self):
instances = []
for reservation in self.all_reservations():
for instance in reservation.instances:
instances.append(instance)
return instances
def all_reservations(self):
return self.reservations.values()
2013-02-21 04:19:43 +00:00
class TagBackend(object):
def __init__(self):
self.tags = defaultdict(dict)
super(TagBackend, self).__init__()
def create_tag(self, resource_id, key, value):
self.tags[resource_id][key] = value
return value
def delete_tag(self, resource_id, key):
return self.tags[resource_id].pop(key)
def describe_tags(self):
results = []
for resource_id, tags in self.tags.iteritems():
ami = 'ami' in resource_id
for key, value in tags.iteritems():
result = {
'resource_id': resource_id,
'key': key,
'value': value,
'resource_type': 'image' if ami else 'instance',
}
results.append(result)
return results
class Ami(object):
def __init__(self, ami_id, instance, name, description):
self.id = ami_id
self.instance = instance
self.instance_id = instance.id
self.name = name
self.description = description
self.virtualization_type = instance.virtualization_type
self.kernel_id = instance.kernel
2013-02-26 05:31:01 +00:00
class AmiBackend(object):
def __init__(self):
self.amis = {}
super(AmiBackend, self).__init__()
def create_image(self, instance_id, name, description):
# TODO: check that instance exists and pull info from it.
ami_id = random_ami_id()
2013-02-23 20:26:54 +00:00
instance = self.get_instance(instance_id)
if not instance:
return None
2013-02-26 05:31:01 +00:00
ami = Ami(ami_id, instance, name, description)
self.amis[ami_id] = ami
return ami
def describe_images(self):
return self.amis.values()
def deregister_image(self, ami_id):
if ami_id in self.amis:
self.amis.pop(ami_id)
return True
return False
2013-02-23 19:51:19 +00:00
class Region(object):
def __init__(self, name, endpoint):
self.name = name
self.endpoint = endpoint
class Zone(object):
def __init__(self, name, region_name):
self.name = name
self.region_name = region_name
class RegionsAndZonesBackend(object):
regions = [
Region("eu-west-1", "ec2.eu-west-1.amazonaws.com"),
Region("sa-east-1", "ec2.sa-east-1.amazonaws.com"),
Region("us-east-1", "ec2.us-east-1.amazonaws.com"),
Region("ap-northeast-1", "ec2.ap-northeast-1.amazonaws.com"),
Region("us-west-2", "ec2.us-west-2.amazonaws.com"),
Region("us-west-1", "ec2.us-west-1.amazonaws.com"),
Region("ap-southeast-1", "ec2.ap-southeast-1.amazonaws.com"),
Region("ap-southeast-2", "ec2.ap-southeast-2.amazonaws.com"),
]
# TODO: cleanup. For now, pretend everything is us-east-1. 'merica.
zones = [
Zone("us-east-1a", "us-east-1"),
Zone("us-east-1b", "us-east-1"),
Zone("us-east-1c", "us-east-1"),
Zone("us-east-1d", "us-east-1"),
Zone("us-east-1e", "us-east-1"),
]
def describe_regions(self):
return self.regions
def describe_availability_zones(self):
return self.zones
2013-02-23 22:37:55 +00:00
def get_zone_by_name(self, name):
for zone in self.zones:
if zone.name == name:
return zone
2013-02-23 19:51:19 +00:00
2013-02-23 21:27:43 +00:00
class SecurityRule(object):
def __init__(self, ip_protocol, from_port, to_port, ip_ranges, source_groups):
self.ip_protocol = ip_protocol
self.from_port = from_port
self.to_port = to_port
self.ip_ranges = ip_ranges or []
self.source_groups = source_groups
@property
def unique_representation(self):
return "{}-{}-{}-{}-{}".format(
2013-03-05 13:14:43 +00:00
self.ip_protocol,
self.from_port,
self.to_port,
self.ip_ranges,
self.source_groups
2013-02-26 05:31:01 +00:00
)
2013-02-23 21:27:43 +00:00
def __eq__(self, other):
return self.unique_representation == other.unique_representation
2013-02-23 20:26:54 +00:00
class SecurityGroup(object):
def __init__(self, group_id, name, description):
self.id = group_id
self.name = name
self.description = description
2013-02-23 21:27:43 +00:00
self.ingress_rules = []
self.egress_rules = []
2013-02-23 20:26:54 +00:00
class SecurityGroupBackend(object):
def __init__(self):
self.groups = {}
2013-02-23 22:37:55 +00:00
super(SecurityGroupBackend, self).__init__()
2013-02-23 20:26:54 +00:00
def create_security_group(self, name, description):
group_id = random_security_group_id()
existing_group = self.get_security_group_from_name(name)
if existing_group:
return None
2013-02-26 05:31:01 +00:00
group = SecurityGroup(group_id, name, description)
2013-02-23 20:26:54 +00:00
self.groups[group_id] = group
return group
def describe_security_groups(self):
return self.groups.values()
def delete_security_group(self, name_or_group_id):
if name_or_group_id in self.groups:
# Group Id
return self.groups.pop(name_or_group_id)
else:
# Group Name
group = self.get_security_group_from_name(name_or_group_id)
if group:
return self.groups.pop(group.id)
def get_security_group_from_name(self, name):
for group_id, group in self.groups.iteritems():
if group.name == name:
return group
2013-02-23 21:27:43 +00:00
def authorize_security_group_ingress(self, group_name, ip_protocol, from_port, to_port, ip_ranges=None, source_group_names=None):
group = self.get_security_group_from_name(group_name)
source_groups = []
for source_group_name in source_group_names:
source_groups.append(self.get_security_group_from_name(source_group_name))
security_rule = SecurityRule(ip_protocol, from_port, to_port, ip_ranges, source_groups)
group.ingress_rules.append(security_rule)
def revoke_security_group_ingress(self, group_name, ip_protocol, from_port, to_port, ip_ranges=None, source_group_names=None):
group = self.get_security_group_from_name(group_name)
source_groups = []
for source_group_name in source_group_names:
source_groups.append(self.get_security_group_from_name(source_group_name))
security_rule = SecurityRule(ip_protocol, from_port, to_port, ip_ranges, source_groups)
if security_rule in group.ingress_rules:
group.ingress_rules.remove(security_rule)
return security_rule
return False
2013-02-23 22:37:55 +00:00
class VolumeAttachment(object):
def __init__(self, volume, instance, device):
self.volume = volume
self.instance = instance
self.device = device
class Volume(object):
def __init__(self, volume_id, size, zone):
self.id = volume_id
self.size = size
self.zone = zone
self.attachment = None
@property
def status(self):
if self.attachment:
return 'in-use'
else:
return 'available'
class Snapshot(object):
def __init__(self, snapshot_id, volume, description):
self.id = snapshot_id
self.volume = volume
self.description = description
2013-02-23 22:37:55 +00:00
class EBSBackend(object):
def __init__(self):
self.volumes = {}
self.attachments = {}
self.snapshots = {}
2013-02-23 22:37:55 +00:00
super(EBSBackend, self).__init__()
def create_volume(self, size, zone_name):
volume_id = random_volume_id()
zone = self.get_zone_by_name(zone_name)
volume = Volume(volume_id, size, zone)
self.volumes[volume_id] = volume
return volume
def describe_volumes(self):
return self.volumes.values()
def delete_volume(self, volume_id):
if volume_id in self.volumes:
return self.volumes.pop(volume_id)
return False
def attach_volume(self, volume_id, instance_id, device_path):
volume = self.volumes.get(volume_id)
instance = self.get_instance(instance_id)
if not volume or not instance:
return False
volume.attachment = VolumeAttachment(volume, instance, device_path)
return volume.attachment
def detach_volume(self, volume_id, instance_id, device_path):
volume = self.volumes.get(volume_id)
instance = self.get_instance(instance_id)
if not volume or not instance:
return False
old_attachment = volume.attachment
volume.attachment = None
return old_attachment
def create_snapshot(self, volume_id, description):
snapshot_id = random_snapshot_id()
volume = self.volumes.get(volume_id)
snapshot = Snapshot(snapshot_id, volume, description)
self.snapshots[snapshot_id] = snapshot
return snapshot
def describe_snapshots(self):
return self.snapshots.values()
def delete_snapshot(self, snapshot_id):
if snapshot_id in self.snapshots:
return self.snapshots.pop(snapshot_id)
return False
2013-02-23 22:37:55 +00:00
2013-03-06 03:33:41 +00:00
class VPC(object):
def __init__(self, vpc_id, cidr_block):
self.id = vpc_id
self.cidr_block = cidr_block
class VPCBackend(object):
def __init__(self):
self.vpcs = {}
super(VPCBackend, self).__init__()
def create_vpc(self, cidr_block):
vpc_id = random_vpc_id()
vpc = VPC(vpc_id, cidr_block)
self.vpcs[vpc_id] = vpc
return vpc
2013-03-06 03:53:53 +00:00
def get_vpc(self, vpc_id):
return self.vpcs.get(vpc_id)
2013-03-06 03:33:41 +00:00
def get_all_vpcs(self):
return self.vpcs.values()
def delete_vpc(self, vpc_id):
return self.vpcs.pop(vpc_id, None)
2013-03-06 03:53:53 +00:00
class Subnet(object):
def __init__(self, subnet_id, vpc, cidr_block):
self.id = subnet_id
self.vpc = vpc
self.cidr_block = cidr_block
class SubnetBackend(object):
def __init__(self):
self.subnets = {}
super(SubnetBackend, self).__init__()
def create_subnet(self, vpc_id, cidr_block):
subnet_id = random_subnet_id()
vpc = self.get_vpc(vpc_id)
subnet = Subnet(subnet_id, vpc, cidr_block)
self.subnets[subnet_id] = subnet
return subnet
def get_all_subnets(self):
return self.subnets.values()
def delete_subnet(self, subnet_id):
return self.subnets.pop(subnet_id, None)
2013-03-06 03:33:41 +00:00
class EC2Backend(BaseBackend, InstanceBackend, TagBackend, AmiBackend,
RegionsAndZonesBackend, SecurityGroupBackend, EBSBackend,
2013-03-06 03:53:53 +00:00
VPCBackend, SubnetBackend):
2013-02-21 04:19:43 +00:00
pass
ec2_backend = EC2Backend()