Merge pull request #173 from hltbra/multi-region
Add multi-region support to EC2 Instances, Autoscaling Groups & LaunchConfigurations
This commit is contained in:
commit
5a20476e74
@ -1,2 +1,9 @@
|
|||||||
from .models import autoscaling_backend
|
from .models import autoscaling_backend, autoscaling_backends
|
||||||
mock_autoscaling = autoscaling_backend.decorator
|
from ..core.models import MockAWS
|
||||||
|
|
||||||
|
|
||||||
|
def mock_autoscaling(func=None):
|
||||||
|
if func:
|
||||||
|
return MockAWS(autoscaling_backends)(func)
|
||||||
|
else:
|
||||||
|
return MockAWS(autoscaling_backends)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from boto.ec2.blockdevicemapping import BlockDeviceType, BlockDeviceMapping
|
from boto.ec2.blockdevicemapping import BlockDeviceType, BlockDeviceMapping
|
||||||
from moto.core import BaseBackend
|
from moto.core import BaseBackend
|
||||||
from moto.ec2 import ec2_backend
|
from moto.ec2 import ec2_backends
|
||||||
|
|
||||||
# http://docs.aws.amazon.com/AutoScaling/latest/DeveloperGuide/AS_Concepts.html#Cooldown
|
# http://docs.aws.amazon.com/AutoScaling/latest/DeveloperGuide/AS_Concepts.html#Cooldown
|
||||||
DEFAULT_COOLDOWN = 300
|
DEFAULT_COOLDOWN = 300
|
||||||
@ -8,7 +8,7 @@ DEFAULT_COOLDOWN = 300
|
|||||||
|
|
||||||
class FakeScalingPolicy(object):
|
class FakeScalingPolicy(object):
|
||||||
def __init__(self, name, adjustment_type, as_name, scaling_adjustment,
|
def __init__(self, name, adjustment_type, as_name, scaling_adjustment,
|
||||||
cooldown):
|
cooldown, autoscaling_backend):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.adjustment_type = adjustment_type
|
self.adjustment_type = adjustment_type
|
||||||
self.as_name = as_name
|
self.as_name = as_name
|
||||||
@ -17,14 +17,15 @@ class FakeScalingPolicy(object):
|
|||||||
self.cooldown = cooldown
|
self.cooldown = cooldown
|
||||||
else:
|
else:
|
||||||
self.cooldown = DEFAULT_COOLDOWN
|
self.cooldown = DEFAULT_COOLDOWN
|
||||||
|
self.autoscaling_backend = autoscaling_backend
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
if self.adjustment_type == 'ExactCapacity':
|
if self.adjustment_type == 'ExactCapacity':
|
||||||
autoscaling_backend.set_desired_capacity(self.as_name, self.scaling_adjustment)
|
self.autoscaling_backend.set_desired_capacity(self.as_name, self.scaling_adjustment)
|
||||||
elif self.adjustment_type == 'ChangeInCapacity':
|
elif self.adjustment_type == 'ChangeInCapacity':
|
||||||
autoscaling_backend.change_capacity(self.as_name, self.scaling_adjustment)
|
self.autoscaling_backend.change_capacity(self.as_name, self.scaling_adjustment)
|
||||||
elif self.adjustment_type == 'PercentChangeInCapacity':
|
elif self.adjustment_type == 'PercentChangeInCapacity':
|
||||||
autoscaling_backend.change_capacity_percent(self.as_name, self.scaling_adjustment)
|
self.autoscaling_backend.change_capacity_percent(self.as_name, self.scaling_adjustment)
|
||||||
|
|
||||||
|
|
||||||
class FakeLaunchConfiguration(object):
|
class FakeLaunchConfiguration(object):
|
||||||
@ -104,7 +105,7 @@ class FakeAutoScalingGroup(object):
|
|||||||
def __init__(self, name, availability_zones, desired_capacity, max_size,
|
def __init__(self, name, availability_zones, desired_capacity, max_size,
|
||||||
min_size, launch_config_name, vpc_zone_identifier,
|
min_size, launch_config_name, vpc_zone_identifier,
|
||||||
default_cooldown, health_check_period, health_check_type,
|
default_cooldown, health_check_period, health_check_type,
|
||||||
load_balancers, placement_group, termination_policies):
|
load_balancers, placement_group, termination_policies, autoscaling_backend):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.availability_zones = availability_zones
|
self.availability_zones = availability_zones
|
||||||
self.max_size = max_size
|
self.max_size = max_size
|
||||||
@ -124,6 +125,8 @@ class FakeAutoScalingGroup(object):
|
|||||||
self.instances = []
|
self.instances = []
|
||||||
self.set_desired_capacity(desired_capacity)
|
self.set_desired_capacity(desired_capacity)
|
||||||
|
|
||||||
|
self.autoscaling_backend = autoscaling_backend
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_from_cloudformation_json(cls, resource_name, cloudformation_json):
|
def create_from_cloudformation_json(cls, resource_name, cloudformation_json):
|
||||||
properties = cloudformation_json['Properties']
|
properties = cloudformation_json['Properties']
|
||||||
@ -182,7 +185,7 @@ class FakeAutoScalingGroup(object):
|
|||||||
if self.desired_capacity > curr_instance_count:
|
if self.desired_capacity > curr_instance_count:
|
||||||
# Need more instances
|
# Need more instances
|
||||||
count_needed = self.desired_capacity - curr_instance_count
|
count_needed = self.desired_capacity - curr_instance_count
|
||||||
reservation = ec2_backend.add_instances(
|
reservation = autoscaling_backend.ec2_backend.add_instances(
|
||||||
self.launch_config.image_id,
|
self.launch_config.image_id,
|
||||||
count_needed,
|
count_needed,
|
||||||
self.launch_config.user_data,
|
self.launch_config.user_data,
|
||||||
@ -196,16 +199,22 @@ class FakeAutoScalingGroup(object):
|
|||||||
count_to_remove = curr_instance_count - self.desired_capacity
|
count_to_remove = curr_instance_count - self.desired_capacity
|
||||||
instances_to_remove = self.instances[:count_to_remove]
|
instances_to_remove = self.instances[:count_to_remove]
|
||||||
instance_ids_to_remove = [instance.id for instance in instances_to_remove]
|
instance_ids_to_remove = [instance.id for instance in instances_to_remove]
|
||||||
ec2_backend.terminate_instances(instance_ids_to_remove)
|
autoscaling_backend.ec2_backend.terminate_instances(instance_ids_to_remove)
|
||||||
self.instances = self.instances[count_to_remove:]
|
self.instances = self.instances[count_to_remove:]
|
||||||
|
|
||||||
|
|
||||||
class AutoScalingBackend(BaseBackend):
|
class AutoScalingBackend(BaseBackend):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, ec2_backend):
|
||||||
self.autoscaling_groups = {}
|
self.autoscaling_groups = {}
|
||||||
self.launch_configurations = {}
|
self.launch_configurations = {}
|
||||||
self.policies = {}
|
self.policies = {}
|
||||||
|
self.ec2_backend = ec2_backend
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
ec2_backend = self.ec2_backend
|
||||||
|
self.__dict__ = {}
|
||||||
|
self.__init__(ec2_backend)
|
||||||
|
|
||||||
def create_launch_configuration(self, name, image_id, key_name,
|
def create_launch_configuration(self, name, image_id, key_name,
|
||||||
security_groups, user_data, instance_type,
|
security_groups, user_data, instance_type,
|
||||||
@ -267,6 +276,7 @@ class AutoScalingBackend(BaseBackend):
|
|||||||
load_balancers=load_balancers,
|
load_balancers=load_balancers,
|
||||||
placement_group=placement_group,
|
placement_group=placement_group,
|
||||||
termination_policies=termination_policies,
|
termination_policies=termination_policies,
|
||||||
|
autoscaling_backend=self,
|
||||||
)
|
)
|
||||||
self.autoscaling_groups[name] = group
|
self.autoscaling_groups[name] = group
|
||||||
return group
|
return group
|
||||||
@ -328,7 +338,7 @@ class AutoScalingBackend(BaseBackend):
|
|||||||
def create_autoscaling_policy(self, name, adjustment_type, as_name,
|
def create_autoscaling_policy(self, name, adjustment_type, as_name,
|
||||||
scaling_adjustment, cooldown):
|
scaling_adjustment, cooldown):
|
||||||
policy = FakeScalingPolicy(name, adjustment_type, as_name,
|
policy = FakeScalingPolicy(name, adjustment_type, as_name,
|
||||||
scaling_adjustment, cooldown)
|
scaling_adjustment, cooldown, self)
|
||||||
|
|
||||||
self.policies[name] = policy
|
self.policies[name] = policy
|
||||||
return policy
|
return policy
|
||||||
@ -343,4 +353,9 @@ class AutoScalingBackend(BaseBackend):
|
|||||||
policy = self.policies[group_name]
|
policy = self.policies[group_name]
|
||||||
policy.execute()
|
policy.execute()
|
||||||
|
|
||||||
autoscaling_backend = AutoScalingBackend()
|
|
||||||
|
autoscaling_backends = {}
|
||||||
|
for region, ec2_backend in ec2_backends.items():
|
||||||
|
autoscaling_backends[region] = AutoScalingBackend(ec2_backend)
|
||||||
|
|
||||||
|
autoscaling_backend = autoscaling_backends['us-east-1']
|
||||||
|
@ -2,10 +2,15 @@ from jinja2 import Template
|
|||||||
|
|
||||||
from moto.core.responses import BaseResponse
|
from moto.core.responses import BaseResponse
|
||||||
from moto.core.utils import camelcase_to_underscores
|
from moto.core.utils import camelcase_to_underscores
|
||||||
from .models import autoscaling_backend
|
from .models import autoscaling_backends
|
||||||
|
|
||||||
|
|
||||||
class AutoScalingResponse(BaseResponse):
|
class AutoScalingResponse(BaseResponse):
|
||||||
|
|
||||||
|
@property
|
||||||
|
def autoscaling_backend(self):
|
||||||
|
return autoscaling_backends[self.region]
|
||||||
|
|
||||||
def _get_int_param(self, param_name):
|
def _get_int_param(self, param_name):
|
||||||
value = self._get_param(param_name)
|
value = self._get_param(param_name)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
@ -32,7 +37,7 @@ class AutoScalingResponse(BaseResponse):
|
|||||||
instance_monitoring = True
|
instance_monitoring = True
|
||||||
else:
|
else:
|
||||||
instance_monitoring = False
|
instance_monitoring = False
|
||||||
autoscaling_backend.create_launch_configuration(
|
self.autoscaling_backend.create_launch_configuration(
|
||||||
name=self._get_param('LaunchConfigurationName'),
|
name=self._get_param('LaunchConfigurationName'),
|
||||||
image_id=self._get_param('ImageId'),
|
image_id=self._get_param('ImageId'),
|
||||||
key_name=self._get_param('KeyName'),
|
key_name=self._get_param('KeyName'),
|
||||||
@ -51,18 +56,18 @@ class AutoScalingResponse(BaseResponse):
|
|||||||
|
|
||||||
def describe_launch_configurations(self):
|
def describe_launch_configurations(self):
|
||||||
names = self._get_multi_param('LaunchConfigurationNames')
|
names = self._get_multi_param('LaunchConfigurationNames')
|
||||||
launch_configurations = autoscaling_backend.describe_launch_configurations(names)
|
launch_configurations = self.autoscaling_backend.describe_launch_configurations(names)
|
||||||
template = Template(DESCRIBE_LAUNCH_CONFIGURATIONS_TEMPLATE)
|
template = Template(DESCRIBE_LAUNCH_CONFIGURATIONS_TEMPLATE)
|
||||||
return template.render(launch_configurations=launch_configurations)
|
return template.render(launch_configurations=launch_configurations)
|
||||||
|
|
||||||
def delete_launch_configuration(self):
|
def delete_launch_configuration(self):
|
||||||
launch_configurations_name = self.querystring.get('LaunchConfigurationName')[0]
|
launch_configurations_name = self.querystring.get('LaunchConfigurationName')[0]
|
||||||
autoscaling_backend.delete_launch_configuration(launch_configurations_name)
|
self.autoscaling_backend.delete_launch_configuration(launch_configurations_name)
|
||||||
template = Template(DELETE_LAUNCH_CONFIGURATION_TEMPLATE)
|
template = Template(DELETE_LAUNCH_CONFIGURATION_TEMPLATE)
|
||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
def create_auto_scaling_group(self):
|
def create_auto_scaling_group(self):
|
||||||
autoscaling_backend.create_autoscaling_group(
|
self.autoscaling_backend.create_autoscaling_group(
|
||||||
name=self._get_param('AutoScalingGroupName'),
|
name=self._get_param('AutoScalingGroupName'),
|
||||||
availability_zones=self._get_multi_param('AvailabilityZones.member'),
|
availability_zones=self._get_multi_param('AvailabilityZones.member'),
|
||||||
desired_capacity=self._get_int_param('DesiredCapacity'),
|
desired_capacity=self._get_int_param('DesiredCapacity'),
|
||||||
@ -82,12 +87,12 @@ class AutoScalingResponse(BaseResponse):
|
|||||||
|
|
||||||
def describe_auto_scaling_groups(self):
|
def describe_auto_scaling_groups(self):
|
||||||
names = self._get_multi_param("AutoScalingGroupNames")
|
names = self._get_multi_param("AutoScalingGroupNames")
|
||||||
groups = autoscaling_backend.describe_autoscaling_groups(names)
|
groups = self.autoscaling_backend.describe_autoscaling_groups(names)
|
||||||
template = Template(DESCRIBE_AUTOSCALING_GROUPS_TEMPLATE)
|
template = Template(DESCRIBE_AUTOSCALING_GROUPS_TEMPLATE)
|
||||||
return template.render(groups=groups)
|
return template.render(groups=groups)
|
||||||
|
|
||||||
def update_auto_scaling_group(self):
|
def update_auto_scaling_group(self):
|
||||||
autoscaling_backend.update_autoscaling_group(
|
self.autoscaling_backend.update_autoscaling_group(
|
||||||
name=self._get_param('AutoScalingGroupName'),
|
name=self._get_param('AutoScalingGroupName'),
|
||||||
availability_zones=self._get_multi_param('AvailabilityZones.member'),
|
availability_zones=self._get_multi_param('AvailabilityZones.member'),
|
||||||
desired_capacity=self._get_int_param('DesiredCapacity'),
|
desired_capacity=self._get_int_param('DesiredCapacity'),
|
||||||
@ -107,24 +112,24 @@ class AutoScalingResponse(BaseResponse):
|
|||||||
|
|
||||||
def delete_auto_scaling_group(self):
|
def delete_auto_scaling_group(self):
|
||||||
group_name = self._get_param('AutoScalingGroupName')
|
group_name = self._get_param('AutoScalingGroupName')
|
||||||
autoscaling_backend.delete_autoscaling_group(group_name)
|
self.autoscaling_backend.delete_autoscaling_group(group_name)
|
||||||
template = Template(DELETE_AUTOSCALING_GROUP_TEMPLATE)
|
template = Template(DELETE_AUTOSCALING_GROUP_TEMPLATE)
|
||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
def set_desired_capacity(self):
|
def set_desired_capacity(self):
|
||||||
group_name = self._get_param('AutoScalingGroupName')
|
group_name = self._get_param('AutoScalingGroupName')
|
||||||
desired_capacity = self._get_int_param('DesiredCapacity')
|
desired_capacity = self._get_int_param('DesiredCapacity')
|
||||||
autoscaling_backend.set_desired_capacity(group_name, desired_capacity)
|
self.autoscaling_backend.set_desired_capacity(group_name, desired_capacity)
|
||||||
template = Template(SET_DESIRED_CAPACITY_TEMPLATE)
|
template = Template(SET_DESIRED_CAPACITY_TEMPLATE)
|
||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
def describe_auto_scaling_instances(self):
|
def describe_auto_scaling_instances(self):
|
||||||
instances = autoscaling_backend.describe_autoscaling_instances()
|
instances = self.autoscaling_backend.describe_autoscaling_instances()
|
||||||
template = Template(DESCRIBE_AUTOSCALING_INSTANCES_TEMPLATE)
|
template = Template(DESCRIBE_AUTOSCALING_INSTANCES_TEMPLATE)
|
||||||
return template.render(instances=instances)
|
return template.render(instances=instances)
|
||||||
|
|
||||||
def put_scaling_policy(self):
|
def put_scaling_policy(self):
|
||||||
policy = autoscaling_backend.create_autoscaling_policy(
|
policy = self.autoscaling_backend.create_autoscaling_policy(
|
||||||
name=self._get_param('PolicyName'),
|
name=self._get_param('PolicyName'),
|
||||||
adjustment_type=self._get_param('AdjustmentType'),
|
adjustment_type=self._get_param('AdjustmentType'),
|
||||||
as_name=self._get_param('AutoScalingGroupName'),
|
as_name=self._get_param('AutoScalingGroupName'),
|
||||||
@ -135,19 +140,19 @@ class AutoScalingResponse(BaseResponse):
|
|||||||
return template.render(policy=policy)
|
return template.render(policy=policy)
|
||||||
|
|
||||||
def describe_policies(self):
|
def describe_policies(self):
|
||||||
policies = autoscaling_backend.describe_policies()
|
policies = self.autoscaling_backend.describe_policies()
|
||||||
template = Template(DESCRIBE_SCALING_POLICIES_TEMPLATE)
|
template = Template(DESCRIBE_SCALING_POLICIES_TEMPLATE)
|
||||||
return template.render(policies=policies)
|
return template.render(policies=policies)
|
||||||
|
|
||||||
def delete_policy(self):
|
def delete_policy(self):
|
||||||
group_name = self._get_param('PolicyName')
|
group_name = self._get_param('PolicyName')
|
||||||
autoscaling_backend.delete_policy(group_name)
|
self.autoscaling_backend.delete_policy(group_name)
|
||||||
template = Template(DELETE_POLICY_TEMPLATE)
|
template = Template(DELETE_POLICY_TEMPLATE)
|
||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
def execute_policy(self):
|
def execute_policy(self):
|
||||||
group_name = self._get_param('PolicyName')
|
group_name = self._get_param('PolicyName')
|
||||||
autoscaling_backend.execute_policy(group_name)
|
self.autoscaling_backend.execute_policy(group_name)
|
||||||
template = Template(EXECUTE_POLICY_TEMPLATE)
|
template = Template(EXECUTE_POLICY_TEMPLATE)
|
||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
|
@ -9,8 +9,8 @@ from .utils import convert_regex_to_flask_path
|
|||||||
class MockAWS(object):
|
class MockAWS(object):
|
||||||
nested_count = 0
|
nested_count = 0
|
||||||
|
|
||||||
def __init__(self, backend):
|
def __init__(self, backends):
|
||||||
self.backend = backend
|
self.backends = backends
|
||||||
|
|
||||||
if self.__class__.nested_count == 0:
|
if self.__class__.nested_count == 0:
|
||||||
HTTPretty.reset()
|
HTTPretty.reset()
|
||||||
@ -26,13 +26,15 @@ class MockAWS(object):
|
|||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
self.__class__.nested_count += 1
|
self.__class__.nested_count += 1
|
||||||
self.backend.reset()
|
for backend in self.backends.values():
|
||||||
|
backend.reset()
|
||||||
|
|
||||||
if not HTTPretty.is_enabled():
|
if not HTTPretty.is_enabled():
|
||||||
HTTPretty.enable()
|
HTTPretty.enable()
|
||||||
|
|
||||||
for method in HTTPretty.METHODS:
|
for method in HTTPretty.METHODS:
|
||||||
for key, value in self.backend.urls.iteritems():
|
backend = self.backends.values()[0]
|
||||||
|
for key, value in backend.urls.iteritems():
|
||||||
HTTPretty.register_uri(
|
HTTPretty.register_uri(
|
||||||
method=method,
|
method=method,
|
||||||
uri=re.compile(key),
|
uri=re.compile(key),
|
||||||
@ -151,6 +153,6 @@ class BaseBackend(object):
|
|||||||
|
|
||||||
def decorator(self, func=None):
|
def decorator(self, func=None):
|
||||||
if func:
|
if func:
|
||||||
return MockAWS(self)(func)
|
return MockAWS({'global': self})(func)
|
||||||
else:
|
else:
|
||||||
return MockAWS(self)
|
return MockAWS({'global': self})
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
|
import re
|
||||||
|
|
||||||
from urlparse import parse_qs, urlparse
|
from urlparse import parse_qs, urlparse
|
||||||
|
|
||||||
@ -9,6 +10,8 @@ from moto.core.utils import camelcase_to_underscores, method_names_from_class
|
|||||||
|
|
||||||
class BaseResponse(object):
|
class BaseResponse(object):
|
||||||
|
|
||||||
|
region = 'us-east-1'
|
||||||
|
|
||||||
def dispatch(self, request, full_url, headers):
|
def dispatch(self, request, full_url, headers):
|
||||||
querystring = {}
|
querystring = {}
|
||||||
|
|
||||||
@ -38,6 +41,9 @@ class BaseResponse(object):
|
|||||||
self.path = urlparse(full_url).path
|
self.path = urlparse(full_url).path
|
||||||
self.querystring = querystring
|
self.querystring = querystring
|
||||||
self.method = request.method
|
self.method = request.method
|
||||||
|
region = re.search(r'\.(.+?)\.amazonaws\.com', full_url)
|
||||||
|
if region:
|
||||||
|
self.region = region.group(1)
|
||||||
|
|
||||||
self.headers = dict(request.headers)
|
self.headers = dict(request.headers)
|
||||||
self.response_headers = headers
|
self.response_headers = headers
|
||||||
|
@ -1,2 +1,8 @@
|
|||||||
from .models import ec2_backend
|
from .models import ec2_backends, ec2_backend
|
||||||
mock_ec2 = ec2_backend.decorator
|
from ..core.models import MockAWS
|
||||||
|
|
||||||
|
def mock_ec2(func=None):
|
||||||
|
if func:
|
||||||
|
return MockAWS(ec2_backends)(func)
|
||||||
|
else:
|
||||||
|
return MockAWS(ec2_backends)
|
||||||
|
@ -2,6 +2,7 @@ import copy
|
|||||||
import itertools
|
import itertools
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
|
import boto
|
||||||
from boto.ec2.instance import Instance as BotoInstance, Reservation
|
from boto.ec2.instance import Instance as BotoInstance, Reservation
|
||||||
from boto.ec2.blockdevicemapping import BlockDeviceMapping, BlockDeviceType
|
from boto.ec2.blockdevicemapping import BlockDeviceMapping, BlockDeviceType
|
||||||
from boto.ec2.spotinstancerequest import SpotInstanceRequest as BotoSpotRequest
|
from boto.ec2.spotinstancerequest import SpotInstanceRequest as BotoSpotRequest
|
||||||
@ -1360,4 +1361,8 @@ class EC2Backend(BaseBackend, InstanceBackend, TagBackend, AmiBackend,
|
|||||||
raise EC2ClientError(code, message)
|
raise EC2ClientError(code, message)
|
||||||
|
|
||||||
|
|
||||||
ec2_backend = EC2Backend()
|
ec2_backends = {}
|
||||||
|
for region in boto.ec2.regions():
|
||||||
|
ec2_backends[region.name] = EC2Backend()
|
||||||
|
|
||||||
|
ec2_backend = ec2_backends['us-east-1']
|
||||||
|
@ -60,4 +60,7 @@ class EC2Response(
|
|||||||
VPNConnections,
|
VPNConnections,
|
||||||
Windows,
|
Windows,
|
||||||
):
|
):
|
||||||
pass
|
@property
|
||||||
|
def ec2_backend(self):
|
||||||
|
from moto.ec2.models import ec2_backends
|
||||||
|
return ec2_backends[self.region]
|
||||||
|
@ -2,7 +2,6 @@ from jinja2 import Template
|
|||||||
|
|
||||||
from moto.core.responses import BaseResponse
|
from moto.core.responses import BaseResponse
|
||||||
from moto.core.utils import camelcase_to_underscores
|
from moto.core.utils import camelcase_to_underscores
|
||||||
from moto.ec2.models import ec2_backend
|
|
||||||
from moto.ec2.utils import instance_ids_from_querystring, filters_from_querystring, filter_reservations
|
from moto.ec2.utils import instance_ids_from_querystring, filters_from_querystring, filter_reservations
|
||||||
|
|
||||||
|
|
||||||
@ -10,9 +9,9 @@ class InstanceResponse(BaseResponse):
|
|||||||
def describe_instances(self):
|
def describe_instances(self):
|
||||||
instance_ids = instance_ids_from_querystring(self.querystring)
|
instance_ids = instance_ids_from_querystring(self.querystring)
|
||||||
if instance_ids:
|
if instance_ids:
|
||||||
reservations = ec2_backend.get_reservations_by_instance_ids(instance_ids)
|
reservations = self.ec2_backend.get_reservations_by_instance_ids(instance_ids)
|
||||||
else:
|
else:
|
||||||
reservations = ec2_backend.all_reservations(make_copy=True)
|
reservations = self.ec2_backend.all_reservations(make_copy=True)
|
||||||
|
|
||||||
filter_dict = filters_from_querystring(self.querystring)
|
filter_dict = filters_from_querystring(self.querystring)
|
||||||
reservations = filter_reservations(reservations, filter_dict)
|
reservations = filter_reservations(reservations, filter_dict)
|
||||||
@ -29,7 +28,7 @@ class InstanceResponse(BaseResponse):
|
|||||||
instance_type = self.querystring.get("InstanceType", ["m1.small"])[0]
|
instance_type = self.querystring.get("InstanceType", ["m1.small"])[0]
|
||||||
subnet_id = self.querystring.get("SubnetId", [None])[0]
|
subnet_id = self.querystring.get("SubnetId", [None])[0]
|
||||||
key_name = self.querystring.get("KeyName", [None])[0]
|
key_name = self.querystring.get("KeyName", [None])[0]
|
||||||
new_reservation = ec2_backend.add_instances(
|
new_reservation = self.ec2_backend.add_instances(
|
||||||
image_id, min_count, user_data, security_group_names,
|
image_id, min_count, user_data, security_group_names,
|
||||||
instance_type=instance_type, subnet_id=subnet_id,
|
instance_type=instance_type, subnet_id=subnet_id,
|
||||||
key_name=key_name, security_group_ids=security_group_ids)
|
key_name=key_name, security_group_ids=security_group_ids)
|
||||||
@ -38,25 +37,25 @@ class InstanceResponse(BaseResponse):
|
|||||||
|
|
||||||
def terminate_instances(self):
|
def terminate_instances(self):
|
||||||
instance_ids = instance_ids_from_querystring(self.querystring)
|
instance_ids = instance_ids_from_querystring(self.querystring)
|
||||||
instances = ec2_backend.terminate_instances(instance_ids)
|
instances = self.ec2_backend.terminate_instances(instance_ids)
|
||||||
template = Template(EC2_TERMINATE_INSTANCES)
|
template = Template(EC2_TERMINATE_INSTANCES)
|
||||||
return template.render(instances=instances)
|
return template.render(instances=instances)
|
||||||
|
|
||||||
def reboot_instances(self):
|
def reboot_instances(self):
|
||||||
instance_ids = instance_ids_from_querystring(self.querystring)
|
instance_ids = instance_ids_from_querystring(self.querystring)
|
||||||
instances = ec2_backend.reboot_instances(instance_ids)
|
instances = self.ec2_backend.reboot_instances(instance_ids)
|
||||||
template = Template(EC2_REBOOT_INSTANCES)
|
template = Template(EC2_REBOOT_INSTANCES)
|
||||||
return template.render(instances=instances)
|
return template.render(instances=instances)
|
||||||
|
|
||||||
def stop_instances(self):
|
def stop_instances(self):
|
||||||
instance_ids = instance_ids_from_querystring(self.querystring)
|
instance_ids = instance_ids_from_querystring(self.querystring)
|
||||||
instances = ec2_backend.stop_instances(instance_ids)
|
instances = self.ec2_backend.stop_instances(instance_ids)
|
||||||
template = Template(EC2_STOP_INSTANCES)
|
template = Template(EC2_STOP_INSTANCES)
|
||||||
return template.render(instances=instances)
|
return template.render(instances=instances)
|
||||||
|
|
||||||
def start_instances(self):
|
def start_instances(self):
|
||||||
instance_ids = instance_ids_from_querystring(self.querystring)
|
instance_ids = instance_ids_from_querystring(self.querystring)
|
||||||
instances = ec2_backend.start_instances(instance_ids)
|
instances = self.ec2_backend.start_instances(instance_ids)
|
||||||
template = Template(EC2_START_INSTANCES)
|
template = Template(EC2_START_INSTANCES)
|
||||||
return template.render(instances=instances)
|
return template.render(instances=instances)
|
||||||
|
|
||||||
@ -64,9 +63,9 @@ class InstanceResponse(BaseResponse):
|
|||||||
instance_ids = instance_ids_from_querystring(self.querystring)
|
instance_ids = instance_ids_from_querystring(self.querystring)
|
||||||
|
|
||||||
if instance_ids:
|
if instance_ids:
|
||||||
instances = ec2_backend.get_multi_instances_by_id(instance_ids)
|
instances = self.ec2_backend.get_multi_instances_by_id(instance_ids)
|
||||||
else:
|
else:
|
||||||
instances = ec2_backend.all_instances()
|
instances = self.ec2_backend.all_instances()
|
||||||
|
|
||||||
template = Template(EC2_INSTANCE_STATUS)
|
template = Template(EC2_INSTANCE_STATUS)
|
||||||
return template.render(instances=instances)
|
return template.render(instances=instances)
|
||||||
@ -78,7 +77,7 @@ class InstanceResponse(BaseResponse):
|
|||||||
key = camelcase_to_underscores(attribute)
|
key = camelcase_to_underscores(attribute)
|
||||||
instance_ids = instance_ids_from_querystring(self.querystring)
|
instance_ids = instance_ids_from_querystring(self.querystring)
|
||||||
instance_id = instance_ids[0]
|
instance_id = instance_ids[0]
|
||||||
instance, value = ec2_backend.describe_instance_attribute(instance_id, key)
|
instance, value = self.ec2_backend.describe_instance_attribute(instance_id, key)
|
||||||
template = Template(EC2_DESCRIBE_INSTANCE_ATTRIBUTE)
|
template = Template(EC2_DESCRIBE_INSTANCE_ATTRIBUTE)
|
||||||
return template.render(instance=instance, attribute=attribute, value=value)
|
return template.render(instance=instance, attribute=attribute, value=value)
|
||||||
|
|
||||||
@ -126,7 +125,7 @@ class InstanceResponse(BaseResponse):
|
|||||||
|
|
||||||
instance_ids = instance_ids_from_querystring(self.querystring)
|
instance_ids = instance_ids_from_querystring(self.querystring)
|
||||||
instance_id = instance_ids[0]
|
instance_id = instance_ids[0]
|
||||||
instance = ec2_backend.get_instance(instance_id)
|
instance = self.ec2_backend.get_instance(instance_id)
|
||||||
|
|
||||||
block_device_type = instance.block_device_mapping[device_name_value]
|
block_device_type = instance.block_device_mapping[device_name_value]
|
||||||
block_device_type.delete_on_termination = del_on_term_value
|
block_device_type.delete_on_termination = del_on_term_value
|
||||||
@ -151,7 +150,7 @@ class InstanceResponse(BaseResponse):
|
|||||||
normalized_attribute = camelcase_to_underscores(attribute_key.split(".")[0])
|
normalized_attribute = camelcase_to_underscores(attribute_key.split(".")[0])
|
||||||
instance_ids = instance_ids_from_querystring(self.querystring)
|
instance_ids = instance_ids_from_querystring(self.querystring)
|
||||||
instance_id = instance_ids[0]
|
instance_id = instance_ids[0]
|
||||||
ec2_backend.modify_instance_attribute(instance_id, normalized_attribute, value)
|
self.ec2_backend.modify_instance_attribute(instance_id, normalized_attribute, value)
|
||||||
return EC2_MODIFY_INSTANCE_ATTRIBUTE
|
return EC2_MODIFY_INSTANCE_ATTRIBUTE
|
||||||
|
|
||||||
|
|
||||||
|
132
tests/test_ec2/test_regions.py
Normal file
132
tests/test_ec2/test_regions.py
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
import boto.ec2
|
||||||
|
import boto.ec2.autoscale
|
||||||
|
import sure
|
||||||
|
from moto import mock_ec2, mock_autoscaling
|
||||||
|
|
||||||
|
|
||||||
|
def add_servers_to_region(ami_id, count, region):
|
||||||
|
conn = boto.ec2.connect_to_region(region)
|
||||||
|
for index in range(count):
|
||||||
|
conn.run_instances(ami_id)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ec2
|
||||||
|
def test_add_servers_to_a_single_region():
|
||||||
|
region = 'ap-northeast-1'
|
||||||
|
add_servers_to_region('ami-1234abcd', 1, region)
|
||||||
|
add_servers_to_region('ami-5678efgh', 1, region)
|
||||||
|
|
||||||
|
conn = boto.ec2.connect_to_region(region)
|
||||||
|
reservations = conn.get_all_instances()
|
||||||
|
len(reservations).should.equal(2)
|
||||||
|
reservations.sort(key=lambda x: x.instances[0].image_id)
|
||||||
|
|
||||||
|
reservations[0].instances[0].image_id.should.equal('ami-1234abcd')
|
||||||
|
reservations[1].instances[0].image_id.should.equal('ami-5678efgh')
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ec2
|
||||||
|
def test_add_servers_to_multiple_regions():
|
||||||
|
region1 = 'us-east-1'
|
||||||
|
region2 = 'ap-northeast-1'
|
||||||
|
add_servers_to_region('ami-1234abcd', 1, region1)
|
||||||
|
add_servers_to_region('ami-5678efgh', 1, region2)
|
||||||
|
|
||||||
|
us_conn = boto.ec2.connect_to_region(region1)
|
||||||
|
ap_conn = boto.ec2.connect_to_region(region2)
|
||||||
|
us_reservations = us_conn.get_all_instances()
|
||||||
|
ap_reservations = ap_conn.get_all_instances()
|
||||||
|
|
||||||
|
len(us_reservations).should.equal(1)
|
||||||
|
len(ap_reservations).should.equal(1)
|
||||||
|
|
||||||
|
us_reservations[0].instances[0].image_id.should.equal('ami-1234abcd')
|
||||||
|
ap_reservations[0].instances[0].image_id.should.equal('ami-5678efgh')
|
||||||
|
|
||||||
|
|
||||||
|
@mock_autoscaling
|
||||||
|
def test_create_autoscaling_group():
|
||||||
|
us_conn = boto.ec2.autoscale.connect_to_region('us-east-1')
|
||||||
|
config = boto.ec2.autoscale.LaunchConfiguration(
|
||||||
|
name='us_tester',
|
||||||
|
image_id='ami-abcd1234',
|
||||||
|
instance_type='m1.small',
|
||||||
|
)
|
||||||
|
us_conn.create_launch_configuration(config)
|
||||||
|
|
||||||
|
group = boto.ec2.autoscale.AutoScalingGroup(
|
||||||
|
name='us_tester_group',
|
||||||
|
availability_zones=['us-east-1c'],
|
||||||
|
default_cooldown=60,
|
||||||
|
desired_capacity=2,
|
||||||
|
health_check_period=100,
|
||||||
|
health_check_type="EC2",
|
||||||
|
max_size=2,
|
||||||
|
min_size=2,
|
||||||
|
launch_config=config,
|
||||||
|
load_balancers=["us_test_lb"],
|
||||||
|
placement_group="us_test_placement",
|
||||||
|
vpc_zone_identifier='subnet-1234abcd',
|
||||||
|
termination_policies=["OldestInstance", "NewestInstance"],
|
||||||
|
)
|
||||||
|
us_conn.create_auto_scaling_group(group)
|
||||||
|
|
||||||
|
|
||||||
|
ap_conn = boto.ec2.autoscale.connect_to_region('ap-northeast-1')
|
||||||
|
config = boto.ec2.autoscale.LaunchConfiguration(
|
||||||
|
name='ap_tester',
|
||||||
|
image_id='ami-efgh5678',
|
||||||
|
instance_type='m1.small',
|
||||||
|
)
|
||||||
|
ap_conn.create_launch_configuration(config)
|
||||||
|
|
||||||
|
group = boto.ec2.autoscale.AutoScalingGroup(
|
||||||
|
name='ap_tester_group',
|
||||||
|
availability_zones=['ap-northeast-1a'],
|
||||||
|
default_cooldown=60,
|
||||||
|
desired_capacity=2,
|
||||||
|
health_check_period=100,
|
||||||
|
health_check_type="EC2",
|
||||||
|
max_size=2,
|
||||||
|
min_size=2,
|
||||||
|
launch_config=config,
|
||||||
|
load_balancers=["ap_test_lb"],
|
||||||
|
placement_group="ap_test_placement",
|
||||||
|
vpc_zone_identifier='subnet-5678efgh',
|
||||||
|
termination_policies=["OldestInstance", "NewestInstance"],
|
||||||
|
)
|
||||||
|
ap_conn.create_auto_scaling_group(group)
|
||||||
|
|
||||||
|
|
||||||
|
len(us_conn.get_all_groups()).should.equal(1)
|
||||||
|
len(ap_conn.get_all_groups()).should.equal(1)
|
||||||
|
|
||||||
|
us_group = us_conn.get_all_groups()[0]
|
||||||
|
us_group.name.should.equal('us_tester_group')
|
||||||
|
list(us_group.availability_zones).should.equal(['us-east-1c'])
|
||||||
|
us_group.desired_capacity.should.equal(2)
|
||||||
|
us_group.max_size.should.equal(2)
|
||||||
|
us_group.min_size.should.equal(2)
|
||||||
|
us_group.vpc_zone_identifier.should.equal('subnet-1234abcd')
|
||||||
|
us_group.launch_config_name.should.equal('us_tester')
|
||||||
|
us_group.default_cooldown.should.equal(60)
|
||||||
|
us_group.health_check_period.should.equal(100)
|
||||||
|
us_group.health_check_type.should.equal("EC2")
|
||||||
|
list(us_group.load_balancers).should.equal(["us_test_lb"])
|
||||||
|
us_group.placement_group.should.equal("us_test_placement")
|
||||||
|
list(us_group.termination_policies).should.equal(["OldestInstance", "NewestInstance"])
|
||||||
|
|
||||||
|
ap_group = ap_conn.get_all_groups()[0]
|
||||||
|
ap_group.name.should.equal('ap_tester_group')
|
||||||
|
list(ap_group.availability_zones).should.equal(['ap-northeast-1a'])
|
||||||
|
ap_group.desired_capacity.should.equal(2)
|
||||||
|
ap_group.max_size.should.equal(2)
|
||||||
|
ap_group.min_size.should.equal(2)
|
||||||
|
ap_group.vpc_zone_identifier.should.equal('subnet-5678efgh')
|
||||||
|
ap_group.launch_config_name.should.equal('ap_tester')
|
||||||
|
ap_group.default_cooldown.should.equal(60)
|
||||||
|
ap_group.health_check_period.should.equal(100)
|
||||||
|
ap_group.health_check_type.should.equal("EC2")
|
||||||
|
list(ap_group.load_balancers).should.equal(["ap_test_lb"])
|
||||||
|
ap_group.placement_group.should.equal("ap_test_placement")
|
||||||
|
list(ap_group.termination_policies).should.equal(["OldestInstance", "NewestInstance"])
|
@ -12,7 +12,10 @@ def test_ec2_server_get():
|
|||||||
backend = server.create_backend_app("ec2")
|
backend = server.create_backend_app("ec2")
|
||||||
test_client = backend.test_client()
|
test_client = backend.test_client()
|
||||||
|
|
||||||
res = test_client.get('/?Action=RunInstances&ImageId=ami-60a54009')
|
res = test_client.get(
|
||||||
|
'/?Action=RunInstances&ImageId=ami-60a54009',
|
||||||
|
headers={"Host": "ec2.us-east-1.amazonaws.com"}
|
||||||
|
)
|
||||||
|
|
||||||
groups = re.search("<instanceId>(.*)</instanceId>", res.data)
|
groups = re.search("<instanceId>(.*)</instanceId>", res.data)
|
||||||
instance_id = groups.groups()[0]
|
instance_id = groups.groups()[0]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user