Browse files

Moving autoscale as a seperate project

  • Loading branch information...
0 parents commit 81cffd03220bf03552215611850caa7db6b9dfa4 @prvn committed Jan 14, 2012
Showing with 282 additions and 0 deletions.
  1. +48 −0 README
  2. +234 −0 autoscale.py
48 README
@@ -0,0 +1,48 @@
+AutoScaling Setup
+-----------------
+
+This script helps to setup a autoscaling cluster without going through
+the pain of figuring out how a API works. The only reason behind
+writing this script is to make things easier and faster.
+
+This script is built on top of boto API for Python. You need to have
+Python boto 2.0 version pre installed on your machine to use this script.
+
+This script brings together all peices needed by for setting up auto scaling, like
+auto scaling configurations, load balancer configurations, cloud watch configuration,
+ec2 instances configuration etc and making this easier. You pass all the configurations
+or parameters to a single script which gets job done sooner.
+
+
+usage: autoscale.py [-h] --access-key <access key> --secret-key <secret key>
+ --ami-id <ami id> --key-name <key name> --region <region>
+ --launch-config <launch configuration> --instance-type
+ <t1.micro | m1.small | m1.large ..> --load-balancer
+ <load balancer> --min-size <minimum size> --max-size
+ <maximum size> --trigger <trigger name> --measure
+ <CPUUtilization> --lb-target <load balancer target path>
+ --lb-port <load balancer port> --instance-port <instance
+ port> --app-protocol <load balancer protocol>
+ --auto-scaling-group <auto scaling group name>
+ --auto-scaling-policy <auto scaling policy name>
+
+optional arguments:
+-h, --help show this help message and exit
+--access-key <access key> AWS access key
+--secret-key <secret key> AWS secret key
+--ami-id <ami id> EC2 AMI ID
+--key-name <key name> EC2 key name
+--region <region> Region to launch instances in
+--launch-config <launch configuration> Launch configuration name
+--instance-type <t1.micro | m1.small ..> Type of instance
+--load-balancer <load balancer> Load balancer name
+--min-size <minimum size> Minimum size of auto scale group
+--max-size <maximum size> Maximum size of auto scale group
+--trigger <trigger name> Trigger name
+--measure <CPUUtilization> Measure name to watch for
+--lb-target <load balancer target path> Load balancer target path to ping
+--lb-port <load balancer port> Load balancer port
+--instance-port <instance port> Instance port
+--app-protocol <load balancer protocol> Load balancer protocol
+--auto-scaling-group <auto scaling group name> Name of auto scaling group to create
+--auto-scaling-policy <auto scaling policy name> Name of auto scaling policy to create
234 autoscale.py
@@ -0,0 +1,234 @@
+'''
+Created on Dec 16, 2011
+
+@author: Prvn
+@version: 0.2
+
+This script basically wraps the Python boto API (2.0) and provides
+the whole auto scale functionality at one place, making it easy
+to setup a auto scaling cluster.
+
+TODO: Read configurations from both boto config file and user input
+
+'''
+
+import os
+import ConfigParser
+from argparse import ArgumentParser
+
+from boto.ec2.connection import EC2Connection
+from boto.ec2.autoscale import AutoScaleConnection
+from boto.ec2.autoscale import AutoScalingGroup
+from boto.ec2.autoscale import LaunchConfiguration
+from boto.ec2.autoscale import ScalingPolicy
+from boto.ec2.cloudwatch.metric import MetricAlarm
+from boto.ec2.cloudwatch import CloudWatchConnection
+from boto.ec2.elb import ELBConnection
+from boto.ec2.elb import HealthCheck
+
+class AutoScale:
+
+ def __init__(self, args):
+ """
+ Initializing basic variables needed for auto scaling
+ """
+ self.configs = ConfigParser.RawConfigParser()
+ self.args = args
+ self.test_props = {}
+ self.props = {}
+ self.ec2_connection = EC2Connection(self.args.access_key, self.args.secret_key)
+ self.autoscale_connection = AutoScaleConnection(self.args.access_key, self.args.secret_key)
+ self.elb_connection = ELBConnection(self.args.access_key, self.args.secret_key)
+ self.cw_connection = CloudWatchConnection(self.args.access_key, self.args.secret_key)
+ self.firstInstance = None
+ self.launchConfiguration = None
+ self.healthCheck = None
+
+ def loadConfigs(self):
+ """
+ FIX ME: Currently doesnt do anything
+ This method will load the configurations from boto config file if present else will
+ accept parameters passed by user.
+ """
+ if os.path.isfile("/etc/boto.cfg"):
+ self.configs.read("/etc/boto.cfg")
+ conf = self.configs.sections()
+ self.populateConfigs(conf)
+ if os.path.isfile("~/.boto"):
+ self.configs.read("~/.boto")
+ conf = self.configs.sections()
+ self.populateConfigs(conf)
+
+ print ">>> Loaded configs"
+
+ def populateConfigs(self, sections):
+ for section in sections:
+ self.boto_props[section] = self.configs.items(section)
+ for item in self.boto_props[section]:
+ key, value = item
+ if not self.props.has_key(key):
+ self.props[key] = value
+
+ def createLaunchConfiguration(self, lc_name, ami_id, key_name):
+ """
+ Creates launch configuration for the auto scaling cluster
+ """
+ self.launchConfiguration = LaunchConfiguration(name = lc_name,
+ image_id = ami_id,
+ key_name = key_name)
+ self.autoscale_connection.create_launch_configuration(self.launchConfiguration)
+ print ">>> Created launch configuration: " + lc_name
+
+ def createAutoScaleGroup(self, asg_name):
+ """
+ Create a Auto scaling group for the auto scaling cluster
+ """
+ autoScalingGroup = AutoScalingGroup(group_name = asg_name,
+ load_balancers = [self.args.lb_name],
+ launch_config = self.launchConfiguration,
+ min_size = self.args.min_size,
+ max_size = self.args.max_size,
+ availability_zones = ['us-east-1a'])
+ self.autoscale_connection.create_auto_scaling_group(autoScalingGroup)
+ print ">>> Created auto scaling group: " + asg_name
+
+ def createTrigger(self, trigger_name, measure, asg_name):
+ """
+ Trigger to spawn new instances as per specific metrics
+ """
+ alarm_actions = []
+ dimensions = {"AutoScalingGroupName" : asg_name}
+ policies = self.autoscale_connection.get_all_policies(as_group=self.args.asg_name, policy_names=[self.args.asp_name])
+ for policy in policies:
+ alarm_actions.append(policy.policy_arn)
+ alarm = MetricAlarm(name = trigger_name,
+ namespace = "AWS/EC2",
+ metric = measure,
+ statistic = "Average",
+ comparison = ">=",
+ threshold = 50,
+ period = 60,
+ unit = "Percent",
+ evaluation_periods = 2,
+ alarm_actions = alarm_actions,
+ dimensions = dimensions)
+
+ self.cw_connection.create_alarm(alarm)
+ print ">>> Created trigger: "+self.args.trigger
+
+ def createAutoScalePolicy(self, asp_name):
+ """
+ Creates a Auto scaling policy to Add/Remove a instance from auto scaling cluster
+ """
+ self.autoScalingUpPolicy = ScalingPolicy(name = asp_name+'-up',
+ adjustment_type = "ChangeInCapacity",
+ as_name = self.args.asg_name,
+ scaling_adjustment = 1,
+ cooldown = 180)
+ self.autoScalingDownPolicy = ScalingPolicy(name = asp_name+'-down',
+ adjustment_type = "ChangeInCapacity",
+ as_name = self.args.asg_name,
+ scaling_adjustment = -1,
+ cooldown = 180)
+
+ self.autoscale_connection.create_scaling_policy(self.autoScalingUpPolicy)
+ self.autoscale_connection.create_scaling_policy(self.autoScalingDownPolicy)
+
+ print ">>> Created auto scaling policy: " + asp_name
+
+ def configureHealthCheck(self, target):
+ """
+ Configures health check for the cluster
+ """
+ self.healthCheck = HealthCheck(target = target,
+ timeout = 5)
+ print ">>> Configured health check for: " + target
+
+ def createLoadBalancer(self, lb_name, region, lb_port, instance_port, protocol):
+ """
+ Creates a load balancer for cluster
+ """
+ listener = (int(lb_port), int(instance_port), protocol)
+ tuple_list =[]
+ tuple_list.append(listener)
+ lbs = self.elb_connection.get_all_load_balancers()
+ for lb in lbs:
+ if lb.name != lb_name:
+ self.elb_connection.create_load_balancer(lb_name, [region], tuple_list)
+ self.elb_connection.configure_health_check(name = lb_name,
+ health_check = self.healthCheck)
+ print ">>> Created load balancer: " + lb_name
+ else:
+ print "Load balancer with name '"+lb_name+"' already exists"
+
+ def startInstance(self, image_id, key_name, region, instance_type):
+ """
+ Starts the first instance which will be serving requests irrespective of auto scaling
+ instances.
+ """
+ reservation = self.ec2_connection.run_instances(image_id=image_id, min_count=1, max_count=1, placement=region, key_name=key_name, instance_type=instance_type)
+# for instance in reservation.instances:
+# instance.add_tag('node', '0')
+# break
+
+ self.firstInstance = reservation.instances[0].id.split('\'')[0]
+ print ">>> Started instance: ", self.firstInstance
+
+ def registerInstanceToELB(self, lb_name):
+ """
+ Register the first instance started to the Elastic Load Balancer.
+ """
+ self.elb_connection.register_instances(load_balancer_name = lb_name,
+ instances = [self.firstInstance])
+ print ">>> Registered instance '",self.firstInstance,"' to load balancer '"+lb_name+"'"
+
+ def setUp(self):
+ """
+ Set's up the auto scaling for the application
+ """
+ # STEP 1: Load the configurations
+ self.loadConfigs()
+ # STEP 2: Configure the health check for the instances
+ self.configureHealthCheck(self.args.lb_target)
+ # STEP 3: Create a load balancer
+ self.createLoadBalancer(self.args.lb_name, self.args.region, self.args.lb_port, self.args.instance_port, self.args.protocol)
+ # STEP 4: Start the first instance
+ self.startInstance(self.args.ami_id, self.args.key_name, self.args.region, self.args.instance_type)
+ # STEP 5: Register the instance to the load balancer created in STEP 4
+ self.registerInstanceToELB(self.args.lb_name)
+ # STEP 6: Create launch configuration to launch instances by auto scale
+ self.createLaunchConfiguration(self.args.lc_name, self.args.ami_id, self.args.key_name)
+ # STEP 7: Create a auto scale group which will manage the instances started by auto scaling
+ self.createAutoScaleGroup(self.args.asg_name)
+ # STEP 8: Create a auto scaling policy to say add/remove a node
+ self.createAutoScalePolicy(self.args.asp_name)
+ # STEP 9: Create a trigger, so that auto scaling can trigger it to start
+ # or remove a instance from auto scaling group
+ self.createTrigger(self.args.trigger, self.args.measure, self.args.asg_name)
+
+
+if __name__ == '__main__':
+ parser = ArgumentParser()
+ parser.add_argument('--access-key', metavar=('<access key>'), dest='access_key', required=True, help='AWS access key')
+ parser.add_argument('--secret-key', metavar=('<secret key>'), dest='secret_key', required=True, help='AWS secret key')
+ parser.add_argument('--ami-id', metavar=('<ami id>'), dest='ami_id', required=True, help='EC2 AMI ID')
+ parser.add_argument('--key-name', metavar=('<key name>'), dest='key_name', required=True, help='EC2 key name')
+ parser.add_argument('--region', metavar=('<region>'), dest='region', required=True, help='Region to launch instances in')
+ parser.add_argument('--launch-config', metavar=('<launch configuration>'), dest='lc_name', required=True, help='Launch configuration name')
+ parser.add_argument('--instance-type', metavar=('<t1.micro | m1.small | m1.large ..>'), dest='instance_type', required=True, help='Instance type')
+ parser.add_argument('--load-balancer', metavar=('<load balancer>'), dest='lb_name', required=True, help='Load balancer name')
+ parser.add_argument('--min-size', metavar=('<minimum size>'), dest='min_size', required=True, help='Minimum size of auto scale group')
+ parser.add_argument('--max-size', metavar=('<maximum size>'), dest='max_size', required=True, help='Maximum size of auto scale group')
+ parser.add_argument('--trigger', metavar=('<trigger name>'), dest='trigger', required=True, help='Trigger name')
+ parser.add_argument('--measure', metavar=('<CPUUtilization>'), dest='measure', required=True, help='Measure name to watch for')
+ parser.add_argument('--lb-target', metavar=('<load balancer target path>'), dest='lb_target', required=True, help='Load balancer target path to ping')
+ parser.add_argument('--lb-port', metavar=('<load balancer port>'), dest='lb_port', required=True, help='Load balancer port')
+ parser.add_argument('--instance-port', metavar=('<instance port>'), dest='instance_port', required=True, help='Instance port')
+ parser.add_argument('--app-protocol', metavar=('<load balancer protocol>'), dest='protocol', required=True, help='Load balancer protocol')
+ parser.add_argument('--auto-scaling-group', metavar=('<auto scaling group name>'), dest='asg_name', required=True, help='Name of auto scaling group to create')
+ parser.add_argument('--auto-scaling-policy', metavar=('<auto scaling policy name>'), dest='asp_name', required=True, help='Name of auto scaling policy to create')
+
+ args = parser.parse_args()
+
+ autoscale = AutoScale(args)
+ autoscale.setUp()

0 comments on commit 81cffd0

Please sign in to comment.