From 82eef2893753124de6daa27aae77e889d8daa843 Mon Sep 17 00:00:00 2001 From: Hugo Lopes Tavares Date: Tue, 26 Aug 2014 16:42:08 -0400 Subject: [PATCH 1/4] Add multi-region support to EC2 Instances --- moto/core/models.py | 14 ++++++----- moto/core/responses.py | 6 +++++ moto/ec2/__init__.py | 10 ++++++-- moto/ec2/models.py | 7 +++++- moto/ec2/responses/__init__.py | 5 +++- moto/ec2/responses/instances.py | 25 +++++++++---------- tests/test_ec2/test_regions.py | 44 +++++++++++++++++++++++++++++++++ tests/test_ec2/test_server.py | 5 +++- 8 files changed, 92 insertions(+), 24 deletions(-) create mode 100644 tests/test_ec2/test_regions.py diff --git a/moto/core/models.py b/moto/core/models.py index fe0161f8d..7460d2d93 100644 --- a/moto/core/models.py +++ b/moto/core/models.py @@ -9,8 +9,8 @@ from .utils import convert_regex_to_flask_path class MockAWS(object): nested_count = 0 - def __init__(self, backend): - self.backend = backend + def __init__(self, backends): + self.backends = backends if self.__class__.nested_count == 0: HTTPretty.reset() @@ -26,13 +26,15 @@ class MockAWS(object): def start(self): self.__class__.nested_count += 1 - self.backend.reset() + for backend in self.backends.values(): + backend.reset() if not HTTPretty.is_enabled(): HTTPretty.enable() 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( method=method, uri=re.compile(key), @@ -151,6 +153,6 @@ class BaseBackend(object): def decorator(self, func=None): if func: - return MockAWS(self)(func) + return MockAWS({'global': self})(func) else: - return MockAWS(self) + return MockAWS({'global': self}) diff --git a/moto/core/responses.py b/moto/core/responses.py index fee641843..4c346b173 100644 --- a/moto/core/responses.py +++ b/moto/core/responses.py @@ -1,5 +1,6 @@ import datetime import json +import re 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): + region = 'us-east-1' + def dispatch(self, request, full_url, headers): querystring = {} @@ -38,6 +41,9 @@ class BaseResponse(object): self.path = urlparse(full_url).path self.querystring = querystring 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.response_headers = headers diff --git a/moto/ec2/__init__.py b/moto/ec2/__init__.py index 089c79df1..dc34e5f69 100644 --- a/moto/ec2/__init__.py +++ b/moto/ec2/__init__.py @@ -1,2 +1,8 @@ -from .models import ec2_backend -mock_ec2 = ec2_backend.decorator +from .models import ec2_backends, ec2_backend +from ..core.models import MockAWS + +def mock_ec2(func=None): + if func: + return MockAWS(ec2_backends)(func) + else: + return MockAWS(ec2_backends) diff --git a/moto/ec2/models.py b/moto/ec2/models.py index 2aebc463f..bdeaa53f1 100644 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -2,6 +2,7 @@ import copy import itertools from collections import defaultdict +import boto from boto.ec2.instance import Instance as BotoInstance, Reservation from boto.ec2.blockdevicemapping import BlockDeviceMapping, BlockDeviceType from boto.ec2.spotinstancerequest import SpotInstanceRequest as BotoSpotRequest @@ -1360,4 +1361,8 @@ class EC2Backend(BaseBackend, InstanceBackend, TagBackend, AmiBackend, raise EC2ClientError(code, message) -ec2_backend = EC2Backend() +ec2_backends = {} +for region_name in boto.regioninfo.load_regions()['ec2'].keys(): + ec2_backends[region_name] = EC2Backend() + +ec2_backend = ec2_backends['us-east-1'] diff --git a/moto/ec2/responses/__init__.py b/moto/ec2/responses/__init__.py index fa487293f..13b6ce017 100644 --- a/moto/ec2/responses/__init__.py +++ b/moto/ec2/responses/__init__.py @@ -60,4 +60,7 @@ class EC2Response( VPNConnections, Windows, ): - pass + @property + def ec2_backend(self): + from moto.ec2.models import ec2_backends + return ec2_backends[self.region] diff --git a/moto/ec2/responses/instances.py b/moto/ec2/responses/instances.py index 8d0c8fc2f..b4b3bedb7 100644 --- a/moto/ec2/responses/instances.py +++ b/moto/ec2/responses/instances.py @@ -2,7 +2,6 @@ from jinja2 import Template from moto.core.responses import BaseResponse 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 @@ -10,9 +9,9 @@ class InstanceResponse(BaseResponse): def describe_instances(self): instance_ids = instance_ids_from_querystring(self.querystring) 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: - reservations = ec2_backend.all_reservations(make_copy=True) + reservations = self.ec2_backend.all_reservations(make_copy=True) filter_dict = filters_from_querystring(self.querystring) reservations = filter_reservations(reservations, filter_dict) @@ -29,7 +28,7 @@ class InstanceResponse(BaseResponse): instance_type = self.querystring.get("InstanceType", ["m1.small"])[0] subnet_id = self.querystring.get("SubnetId", [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, instance_type=instance_type, subnet_id=subnet_id, key_name=key_name, security_group_ids=security_group_ids) @@ -38,25 +37,25 @@ class InstanceResponse(BaseResponse): def terminate_instances(self): 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) return template.render(instances=instances) def reboot_instances(self): 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) return template.render(instances=instances) def stop_instances(self): 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) return template.render(instances=instances) def start_instances(self): 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) return template.render(instances=instances) @@ -64,9 +63,9 @@ class InstanceResponse(BaseResponse): instance_ids = instance_ids_from_querystring(self.querystring) 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: - instances = ec2_backend.all_instances() + instances = self.ec2_backend.all_instances() template = Template(EC2_INSTANCE_STATUS) return template.render(instances=instances) @@ -78,7 +77,7 @@ class InstanceResponse(BaseResponse): key = camelcase_to_underscores(attribute) instance_ids = instance_ids_from_querystring(self.querystring) 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) 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_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.delete_on_termination = del_on_term_value @@ -151,7 +150,7 @@ class InstanceResponse(BaseResponse): normalized_attribute = camelcase_to_underscores(attribute_key.split(".")[0]) instance_ids = instance_ids_from_querystring(self.querystring) 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 diff --git a/tests/test_ec2/test_regions.py b/tests/test_ec2/test_regions.py new file mode 100644 index 000000000..3bbb9c84a --- /dev/null +++ b/tests/test_ec2/test_regions.py @@ -0,0 +1,44 @@ +import boto.ec2 +import sure +from moto import mock_ec2 + + +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) + instances = conn.get_only_instances() + len(instances).should.equal(2) + instances.sort(key=lambda x: x.image_id) + + instances[0].image_id.should.equal('ami-1234abcd') + instances[1].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_instances = us_conn.get_only_instances() + ap_instances = ap_conn.get_only_instances() + + len(us_instances).should.equal(1) + len(ap_instances).should.equal(1) + + us_instances[0].image_id.should.equal('ami-1234abcd') + ap_instances[0].image_id.should.equal('ami-5678efgh') + diff --git a/tests/test_ec2/test_server.py b/tests/test_ec2/test_server.py index ea6b9b380..8e630f7e2 100644 --- a/tests/test_ec2/test_server.py +++ b/tests/test_ec2/test_server.py @@ -12,7 +12,10 @@ def test_ec2_server_get(): backend = server.create_backend_app("ec2") 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("(.*)", res.data) instance_id = groups.groups()[0] From 7e69c69ae0f6b9e7102f14e3272a7baaac3a64c1 Mon Sep 17 00:00:00 2001 From: Hugo Lopes Tavares Date: Tue, 26 Aug 2014 17:45:19 -0400 Subject: [PATCH 2/4] Add multi-region support to Autoscaling --- moto/autoscaling/__init__.py | 11 ++++- moto/autoscaling/models.py | 37 +++++++++----- moto/autoscaling/responses.py | 33 +++++++------ tests/test_ec2/test_regions.py | 90 +++++++++++++++++++++++++++++++++- 4 files changed, 143 insertions(+), 28 deletions(-) diff --git a/moto/autoscaling/__init__.py b/moto/autoscaling/__init__.py index 2c25ca388..b1df21694 100644 --- a/moto/autoscaling/__init__.py +++ b/moto/autoscaling/__init__.py @@ -1,2 +1,9 @@ -from .models import autoscaling_backend -mock_autoscaling = autoscaling_backend.decorator +from .models import autoscaling_backend, autoscaling_backends +from ..core.models import MockAWS + + +def mock_autoscaling(func=None): + if func: + return MockAWS(autoscaling_backends)(func) + else: + return MockAWS(autoscaling_backends) diff --git a/moto/autoscaling/models.py b/moto/autoscaling/models.py index fc7c82ccd..6571c97db 100644 --- a/moto/autoscaling/models.py +++ b/moto/autoscaling/models.py @@ -1,6 +1,6 @@ from boto.ec2.blockdevicemapping import BlockDeviceType, BlockDeviceMapping 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 DEFAULT_COOLDOWN = 300 @@ -8,7 +8,7 @@ DEFAULT_COOLDOWN = 300 class FakeScalingPolicy(object): def __init__(self, name, adjustment_type, as_name, scaling_adjustment, - cooldown): + cooldown, autoscaling_backend): self.name = name self.adjustment_type = adjustment_type self.as_name = as_name @@ -17,14 +17,15 @@ class FakeScalingPolicy(object): self.cooldown = cooldown else: self.cooldown = DEFAULT_COOLDOWN + self.autoscaling_backend = autoscaling_backend def execute(self): 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': - 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': - 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): @@ -104,7 +105,7 @@ class FakeAutoScalingGroup(object): def __init__(self, name, availability_zones, desired_capacity, max_size, min_size, launch_config_name, vpc_zone_identifier, 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.availability_zones = availability_zones self.max_size = max_size @@ -124,6 +125,8 @@ class FakeAutoScalingGroup(object): self.instances = [] self.set_desired_capacity(desired_capacity) + self.autoscaling_backend = autoscaling_backend + @classmethod def create_from_cloudformation_json(cls, resource_name, cloudformation_json): properties = cloudformation_json['Properties'] @@ -182,7 +185,7 @@ class FakeAutoScalingGroup(object): if self.desired_capacity > curr_instance_count: # Need more instances 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, count_needed, self.launch_config.user_data, @@ -196,16 +199,22 @@ class FakeAutoScalingGroup(object): count_to_remove = curr_instance_count - self.desired_capacity instances_to_remove = self.instances[:count_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:] class AutoScalingBackend(BaseBackend): - def __init__(self): + def __init__(self, ec2_backend): self.autoscaling_groups = {} self.launch_configurations = {} 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, security_groups, user_data, instance_type, @@ -267,6 +276,7 @@ class AutoScalingBackend(BaseBackend): load_balancers=load_balancers, placement_group=placement_group, termination_policies=termination_policies, + autoscaling_backend=self, ) self.autoscaling_groups[name] = group return group @@ -328,7 +338,7 @@ class AutoScalingBackend(BaseBackend): def create_autoscaling_policy(self, name, adjustment_type, as_name, scaling_adjustment, cooldown): policy = FakeScalingPolicy(name, adjustment_type, as_name, - scaling_adjustment, cooldown) + scaling_adjustment, cooldown, self) self.policies[name] = policy return policy @@ -343,4 +353,9 @@ class AutoScalingBackend(BaseBackend): policy = self.policies[group_name] 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'] diff --git a/moto/autoscaling/responses.py b/moto/autoscaling/responses.py index 890317ee5..1b893e424 100644 --- a/moto/autoscaling/responses.py +++ b/moto/autoscaling/responses.py @@ -2,10 +2,15 @@ from jinja2 import Template from moto.core.responses import BaseResponse from moto.core.utils import camelcase_to_underscores -from .models import autoscaling_backend +from .models import autoscaling_backends class AutoScalingResponse(BaseResponse): + + @property + def autoscaling_backend(self): + return autoscaling_backends[self.region] + def _get_int_param(self, param_name): value = self._get_param(param_name) if value is not None: @@ -32,7 +37,7 @@ class AutoScalingResponse(BaseResponse): instance_monitoring = True else: instance_monitoring = False - autoscaling_backend.create_launch_configuration( + self.autoscaling_backend.create_launch_configuration( name=self._get_param('LaunchConfigurationName'), image_id=self._get_param('ImageId'), key_name=self._get_param('KeyName'), @@ -51,18 +56,18 @@ class AutoScalingResponse(BaseResponse): def describe_launch_configurations(self): 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) return template.render(launch_configurations=launch_configurations) def delete_launch_configuration(self): 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) return template.render() def create_auto_scaling_group(self): - autoscaling_backend.create_autoscaling_group( + self.autoscaling_backend.create_autoscaling_group( name=self._get_param('AutoScalingGroupName'), availability_zones=self._get_multi_param('AvailabilityZones.member'), desired_capacity=self._get_int_param('DesiredCapacity'), @@ -82,12 +87,12 @@ class AutoScalingResponse(BaseResponse): def describe_auto_scaling_groups(self): 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) return template.render(groups=groups) def update_auto_scaling_group(self): - autoscaling_backend.update_autoscaling_group( + self.autoscaling_backend.update_autoscaling_group( name=self._get_param('AutoScalingGroupName'), availability_zones=self._get_multi_param('AvailabilityZones.member'), desired_capacity=self._get_int_param('DesiredCapacity'), @@ -107,24 +112,24 @@ class AutoScalingResponse(BaseResponse): def delete_auto_scaling_group(self): 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) return template.render() def set_desired_capacity(self): group_name = self._get_param('AutoScalingGroupName') 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) return template.render() 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) return template.render(instances=instances) def put_scaling_policy(self): - policy = autoscaling_backend.create_autoscaling_policy( + policy = self.autoscaling_backend.create_autoscaling_policy( name=self._get_param('PolicyName'), adjustment_type=self._get_param('AdjustmentType'), as_name=self._get_param('AutoScalingGroupName'), @@ -135,19 +140,19 @@ class AutoScalingResponse(BaseResponse): return template.render(policy=policy) def describe_policies(self): - policies = autoscaling_backend.describe_policies() + policies = self.autoscaling_backend.describe_policies() template = Template(DESCRIBE_SCALING_POLICIES_TEMPLATE) return template.render(policies=policies) def delete_policy(self): group_name = self._get_param('PolicyName') - autoscaling_backend.delete_policy(group_name) + self.autoscaling_backend.delete_policy(group_name) template = Template(DELETE_POLICY_TEMPLATE) return template.render() def execute_policy(self): group_name = self._get_param('PolicyName') - autoscaling_backend.execute_policy(group_name) + self.autoscaling_backend.execute_policy(group_name) template = Template(EXECUTE_POLICY_TEMPLATE) return template.render() diff --git a/tests/test_ec2/test_regions.py b/tests/test_ec2/test_regions.py index 3bbb9c84a..3643745e4 100644 --- a/tests/test_ec2/test_regions.py +++ b/tests/test_ec2/test_regions.py @@ -1,6 +1,7 @@ import boto.ec2 +import boto.ec2.autoscale import sure -from moto import mock_ec2 +from moto import mock_ec2, mock_autoscaling def add_servers_to_region(ami_id, count, region): @@ -42,3 +43,90 @@ def test_add_servers_to_multiple_regions(): us_instances[0].image_id.should.equal('ami-1234abcd') ap_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"]) \ No newline at end of file From bce64599f7fb96962d139a16616ca8163a6fced3 Mon Sep 17 00:00:00 2001 From: Hugo Lopes Tavares Date: Tue, 26 Aug 2014 18:21:26 -0400 Subject: [PATCH 3/4] Get region names in a backward compatible way --- moto/ec2/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/moto/ec2/models.py b/moto/ec2/models.py index bdeaa53f1..1e903bcb9 100644 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -1362,7 +1362,7 @@ class EC2Backend(BaseBackend, InstanceBackend, TagBackend, AmiBackend, ec2_backends = {} -for region_name in boto.regioninfo.load_regions()['ec2'].keys(): - ec2_backends[region_name] = EC2Backend() +for region in boto.ec2.regions(): + ec2_backends[region.name] = EC2Backend() ec2_backend = ec2_backends['us-east-1'] From 55400038a8f3536c9b8356d3d6f1e09cfd0aa50a Mon Sep 17 00:00:00 2001 From: Hugo Lopes Tavares Date: Tue, 26 Aug 2014 18:38:08 -0400 Subject: [PATCH 4/4] Change test_regions.py to work with old boto versions --- tests/test_ec2/test_regions.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/test_ec2/test_regions.py b/tests/test_ec2/test_regions.py index 3643745e4..a72412f0e 100644 --- a/tests/test_ec2/test_regions.py +++ b/tests/test_ec2/test_regions.py @@ -17,12 +17,12 @@ def test_add_servers_to_a_single_region(): add_servers_to_region('ami-5678efgh', 1, region) conn = boto.ec2.connect_to_region(region) - instances = conn.get_only_instances() - len(instances).should.equal(2) - instances.sort(key=lambda x: x.image_id) + reservations = conn.get_all_instances() + len(reservations).should.equal(2) + reservations.sort(key=lambda x: x.instances[0].image_id) - instances[0].image_id.should.equal('ami-1234abcd') - instances[1].image_id.should.equal('ami-5678efgh') + reservations[0].instances[0].image_id.should.equal('ami-1234abcd') + reservations[1].instances[0].image_id.should.equal('ami-5678efgh') @mock_ec2 @@ -34,14 +34,14 @@ def test_add_servers_to_multiple_regions(): us_conn = boto.ec2.connect_to_region(region1) ap_conn = boto.ec2.connect_to_region(region2) - us_instances = us_conn.get_only_instances() - ap_instances = ap_conn.get_only_instances() + us_reservations = us_conn.get_all_instances() + ap_reservations = ap_conn.get_all_instances() - len(us_instances).should.equal(1) - len(ap_instances).should.equal(1) + len(us_reservations).should.equal(1) + len(ap_reservations).should.equal(1) - us_instances[0].image_id.should.equal('ami-1234abcd') - ap_instances[0].image_id.should.equal('ami-5678efgh') + us_reservations[0].instances[0].image_id.should.equal('ami-1234abcd') + ap_reservations[0].instances[0].image_id.should.equal('ami-5678efgh') @mock_autoscaling