Add multi-region support to Autoscaling

This commit is contained in:
Hugo Lopes Tavares 2014-08-26 17:45:19 -04:00
parent 82eef28937
commit 7e69c69ae0
4 changed files with 143 additions and 28 deletions

View File

@ -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)

View File

@ -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']

View File

@ -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()

View File

@ -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"])