import boto.ec2.elb
import boto.ec2.autoscale
from boto.ec2.autoscale import AutoScalingGroup
from boto.ec2.autoscale import LaunchConfiguration
from boto.ec2.autoscale import ScalingPolicy
import boto.ec2.cloudwatch
from boto.ec2.cloudwatch import MetricAlarm
import sys
from boto.ec2.autoscale.tag import Tag
from cloudscale.deployment_scripts.config import AWSConfig
from cloudscale.deployment_scripts.scripts import check_args, get_cfg_logger
class Autoscalability(AWSConfig):
def __init__(self, config, logger):
AWSConfig.__init__(self, config, logger)
self.as_ami_id = self.cfg.get('infrastructure', 'ami_id')
def create(self):
self.conn = boto.ec2.autoscale.connect_to_region(
self.region,
aws_access_key_id=self.access_key,
aws_secret_access_key=self.secret_key
)
lb = self.create_load_balancer()
self.create_security_group('http', 'Security group for HTTP', '0.0.0.0/0', '80')
self.create_security_group('ssh', 'Security group for SSH', '0.0.0.0/0', '22')
lc = self.create_launch_configuration()
self.create_autoscalability_group(lb.name, lc)
scale_up_policy_arn, scale_down_policy_arn = self.create_scaling_policy()
self.create_cloudwatch_alarms(scale_up_policy_arn, scale_down_policy_arn)
return lb.dns_name
def create_cloudwatch_alarms(self, scale_up_policy_arn, scale_down_policy_arn):
self.logger.log("Creating CloudWatch alarms ...")
conn = boto.ec2.cloudwatch.connect_to_region(
self.region,
aws_access_key_id=self.access_key,
aws_secret_access_key=self.secret_key
)
alarm_dimensions = {'AutoScalingGroupName' : 'cloudscale-as'}
scale_up_alarm = MetricAlarm(
name='scale_up_on_cpu', namespace='AWS/EC2',
metric='CPUUtilization', statistic='Average',
comparison='>', threshold='70',
period='60', evaluation_periods=1,
alarm_actions=[scale_up_policy_arn],
dimensions=alarm_dimensions)
scale_down_alarm = MetricAlarm(
name='scale_down_on_cpu', namespace='AWS/EC2',
metric='CPUUtilization', statistic='Average',
comparison='<', threshold='20',
period='60', evaluation_periods=1,
alarm_actions=[scale_down_policy_arn],
dimensions=alarm_dimensions)
conn.create_alarm(scale_up_alarm)
conn.create_alarm(scale_down_alarm)
def create_scaling_policy(self):
self.logger.log("Creating scaling policy ...")
scale_up_policy = ScalingPolicy(name='scale_up',
adjustment_type='ChangeInCapacity',
as_name='cloudscale-as',
scaling_adjustment=1,
cooldown=self.cooldown
)
scale_down_policy = ScalingPolicy(name='scale_down',
adjustment_type='ChangeInCapacity',
as_name='cloudscale-as',
scaling_adjustment=-1,
cooldown=self.cooldown
)
self.conn.create_scaling_policy(scale_up_policy)
self.conn.create_scaling_policy(scale_down_policy)
scale_up_policy = self.conn.get_all_policies(
as_group='cloudscale-as', policy_names=['scale_up'])[0]
scale_down_policy = self.conn.get_all_policies(
as_group='cloudscale-as', policy_names=['scale_down'])[0]
return scale_up_policy.policy_arn, scale_down_policy.policy_arn
def create_launch_configuration(self):
self.logger.log("Creating launch configuration ...")
try:
lc = LaunchConfiguration(self.conn,
"cloudscale-lc",
self.as_ami_id,
self.key_name,
['http'],
None,
self.instance_type,
instance_monitoring=True
)
self.conn.create_launch_configuration(lc)
return lc
except boto.exception.BotoServerError as e:
if e.error_code == 'AlreadyExists':
return self.conn.get_all_launch_configurations(names=['cloudscale-lc'])
else:
raise
def create_autoscalability_group(self, lb_name, lc):
self.logger.log("Creating autoscalability group ...")
try:
tag = Tag(
key='Name',
value = self.instance_identifier,
propagate_at_launch=True,
resource_id='cloudscale-as'
)
ag = AutoScalingGroup(group_name='cloudscale-as',
load_balancers=[lb_name],
availability_zones=[self.availability_zone],
launch_config=lc,
min_size=1,
max_size=10,
connection=self.conn,
tags=[tag])
self.conn.create_auto_scaling_group(ag)
except boto.exception.BotoServerError as e:
if e.error_code != 'AlreadyExists':
raise # self.conn.get_all_groups(names=['cloudscale-as'])[0]
def create_security_group(self, name, description, cidr, port):
try:
conn = boto.ec2.connect_to_region(self.region,
aws_access_key_id=self.access_key,
aws_secret_access_key=self.secret_key
)
conn.create_security_group(name, description)
conn.authorize_security_group(group_name=name, ip_protocol='tcp', from_port=port, to_port=port, cidr_ip=cidr)
conn.create_dbsecurity_group(name, description)
conn.authorize_dbsecurity_group(name, cidr, name)
except boto.exception.EC2ResponseError as e:
if str(e.error_code) != 'InvalidGroup.Duplicate':
raise
def create_load_balancer(self):
self.logger.log("Creating load balancer ...")
conn = boto.ec2.elb.connect_to_region(
self.region,
aws_access_key_id=self.access_key,
aws_secret_access_key=self.secret_key
)
ports = [(80, 80, 'http')]
lb = conn.create_load_balancer('cloudscale-lb', self.availability_zone, ports)
return lb
if __name__ == "__main__":
check_args(2, "<config_path>")
user_path, cfg, logger = get_cfg_logger(sys.argv[1], sys.argv[2])
Autoscalability(cfg, logger)