def test_connection_draining_attribute(): conn = boto.connect_elb() ports = [(80, 8080, 'http'), (443, 8443, 'tcp')] lb = conn.create_load_balancer('my-lb', [], ports) connection_draining = ConnectionDrainingAttribute() connection_draining.enabled = True connection_draining.timeout = 60 conn.modify_lb_attribute( "my-lb", "ConnectionDraining", connection_draining) attributes = lb.get_attributes(force=True) attributes.connection_draining.enabled.should.be.true attributes.connection_draining.timeout.should.equal(60) connection_draining.timeout = 30 conn.modify_lb_attribute( "my-lb", "ConnectionDraining", connection_draining) attributes = lb.get_attributes(force=True) attributes.connection_draining.timeout.should.equal(30) connection_draining.enabled = False conn.modify_lb_attribute( "my-lb", "ConnectionDraining", connection_draining) attributes = lb.get_attributes(force=True) attributes.connection_draining.enabled.should.be.false
def get_default_attributes(cls): attributes = LbAttributes() cross_zone_load_balancing = CrossZoneLoadBalancingAttribute() cross_zone_load_balancing.enabled = False attributes.cross_zone_load_balancing = cross_zone_load_balancing connection_draining = ConnectionDrainingAttribute() connection_draining.enabled = False attributes.connection_draining = connection_draining access_log = AccessLogAttribute() access_log.enabled = False attributes.access_log = access_log connection_settings = ConnectionSettingAttribute() connection_settings.idle_timeout = 60 attributes.connecting_settings = connection_settings return attributes
def modify_load_balancer_attributes(self): load_balancer_name = self._get_param('LoadBalancerName') load_balancer = self.elb_backend.get_load_balancer(load_balancer_name) cross_zone = self._get_dict_param( "LoadBalancerAttributes.CrossZoneLoadBalancing.") if cross_zone: attribute = CrossZoneLoadBalancingAttribute() attribute.enabled = cross_zone["enabled"] == "true" self.elb_backend.set_cross_zone_load_balancing_attribute( load_balancer_name, attribute) access_log = self._get_dict_param("LoadBalancerAttributes.AccessLog.") if access_log: attribute = AccessLogAttribute() attribute.enabled = access_log["enabled"] == "true" attribute.s3_bucket_name = access_log['s3_bucket_name'] attribute.s3_bucket_prefix = access_log['s3_bucket_prefix'] attribute.emit_interval = access_log["emit_interval"] self.elb_backend.set_access_log_attribute(load_balancer_name, attribute) connection_draining = self._get_dict_param( "LoadBalancerAttributes.ConnectionDraining.") if connection_draining: attribute = ConnectionDrainingAttribute() attribute.enabled = connection_draining["enabled"] == "true" attribute.timeout = connection_draining["timeout"] self.elb_backend.set_connection_draining_attribute( load_balancer_name, attribute) connection_settings = self._get_dict_param( "LoadBalancerAttributes.ConnectionSettings.") if connection_settings: attribute = ConnectionSettingAttribute() attribute.idle_timeout = connection_settings["idle_timeout"] self.elb_backend.set_connection_settings_attribute( load_balancer_name, attribute) template = self.response_template(MODIFY_ATTRIBUTES_TEMPLATE) return template.render(attributes=load_balancer.attributes)
def test_connection_draining_attribute(): conn = boto.connect_elb() ports = [(80, 8080, 'http'), (443, 8443, 'tcp')] lb = conn.create_load_balancer('my-lb', [], ports) connection_draining = ConnectionDrainingAttribute() connection_draining.enabled = True connection_draining.timeout = 60 conn.modify_lb_attribute("my-lb", "ConnectionDraining", connection_draining) attributes = lb.get_attributes(force=True) attributes.connection_draining.enabled.should.be.true attributes.connection_draining.timeout.should.equal(60) connection_draining.timeout = 30 conn.modify_lb_attribute("my-lb", "ConnectionDraining", connection_draining) attributes = lb.get_attributes(force=True) attributes.connection_draining.timeout.should.equal(30) connection_draining.enabled = False conn.modify_lb_attribute("my-lb", "ConnectionDraining", connection_draining) attributes = lb.get_attributes(force=True) attributes.connection_draining.enabled.should.be.false
def set_attributes(name, attributes, region=None, key=None, keyid=None, profile=None): """ Set attributes on an ELB. name (string) Name of the ELB instance to set attributes for attributes A dict of attributes to set. Valid attributes are: access_log (dict) enabled (bool) Enable storage of access logs. s3_bucket_name (string) The name of the S3 bucket to place logs. s3_bucket_prefix (string) Prefix for the log file name. emit_interval (int) Interval for storing logs in S3 in minutes. Valid values are 5 and 60. connection_draining (dict) enabled (bool) Enable connection draining. timeout (int) Maximum allowed time in seconds for sending existing connections to an instance that is deregistering or unhealthy. Default is 300. cross_zone_load_balancing (dict) enabled (bool) Enable cross-zone load balancing. CLI example to set attributes on an ELB: .. code-block:: bash salt myminion boto_elb.set_attributes myelb '{"access_log": {"enabled": "true", "s3_bucket_name": "mybucket", "s3_bucket_prefix": "mylogs/", "emit_interval": "5"}}' region=us-east-1 """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) al = attributes.get("access_log", {}) czlb = attributes.get("cross_zone_load_balancing", {}) cd = attributes.get("connection_draining", {}) cs = attributes.get("connecting_settings", {}) if not al and not czlb and not cd and not cs: log.error("No supported attributes for ELB.") return False if al: _al = AccessLogAttribute() _al.enabled = al.get("enabled", False) if not _al.enabled: msg = "Access log attribute configured, but enabled config missing" log.error(msg) return False _al.s3_bucket_name = al.get("s3_bucket_name", None) _al.s3_bucket_prefix = al.get("s3_bucket_prefix", None) _al.emit_interval = al.get("emit_interval", None) added_attr = conn.modify_lb_attribute(name, "accessLog", _al) if added_attr: log.info("Added access_log attribute to %s elb.", name) else: log.error("Failed to add access_log attribute to %s elb.", name) return False if czlb: _czlb = CrossZoneLoadBalancingAttribute() _czlb.enabled = czlb["enabled"] added_attr = conn.modify_lb_attribute(name, "crossZoneLoadBalancing", _czlb.enabled) if added_attr: log.info("Added cross_zone_load_balancing attribute to %s elb.", name) else: log.error("Failed to add cross_zone_load_balancing attribute.") return False if cd: _cd = ConnectionDrainingAttribute() _cd.enabled = cd["enabled"] _cd.timeout = cd.get("timeout", 300) added_attr = conn.modify_lb_attribute(name, "connectionDraining", _cd) if added_attr: log.info("Added connection_draining attribute to %s elb.", name) else: log.error("Failed to add connection_draining attribute.") return False if cs: _cs = ConnectionSettingAttribute() _cs.idle_timeout = cs.get("idle_timeout", 60) added_attr = conn.modify_lb_attribute(name, "connectingSettings", _cs) if added_attr: log.info("Added connecting_settings attribute to %s elb.", name) else: log.error("Failed to add connecting_settings attribute.") return False return True
def set_attributes(name, attributes, region=None, key=None, keyid=None, profile=None): ''' Set attributes on an ELB. CLI example to set attributes on an ELB: .. code-block:: bash salt myminion boto_elb.set_attributes myelb '{"access_log": {"enabled": "true", "s3_bucket_name": "mybucket", "s3_bucket_prefix": "mylogs/", "emit_interval": "5"}}' region=us-east-1 ''' conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) al = attributes.get('access_log', {}) czlb = attributes.get('cross_zone_load_balancing', {}) cd = attributes.get('connection_draining', {}) cs = attributes.get('connecting_settings', {}) if not al and not czlb and not cd and not cs: log.error('No supported attributes for ELB.') return False if al: _al = AccessLogAttribute() _al.enabled = al.get('enabled', False) if not _al.enabled: msg = 'Access log attribute configured, but enabled config missing' log.error(msg) return False _al.s3_bucket_name = al.get('s3_bucket_name', None) _al.s3_bucket_prefix = al.get('s3_bucket_prefix', None) _al.emit_interval = al.get('emit_interval', None) added_attr = conn.modify_lb_attribute(name, 'accessLog', _al) if added_attr: log.info('Added access_log attribute to {0} elb.'.format(name)) else: msg = 'Failed to add access_log attribute to {0} elb.' log.error(msg.format(name)) return False if czlb: _czlb = CrossZoneLoadBalancingAttribute() _czlb.enabled = czlb['enabled'] added_attr = conn.modify_lb_attribute(name, 'crossZoneLoadBalancing', _czlb.enabled) if added_attr: msg = 'Added cross_zone_load_balancing attribute to {0} elb.' log.info(msg.format(name)) else: log.error('Failed to add cross_zone_load_balancing attribute.') return False if cd: _cd = ConnectionDrainingAttribute() _cd.enabled = cd['enabled'] _cd.timeout = cd.get('timeout', 300) added_attr = conn.modify_lb_attribute(name, 'connectionDraining', _cd) if added_attr: msg = 'Added connection_draining attribute to {0} elb.' log.info(msg.format(name)) else: log.error('Failed to add connection_draining attribute.') return False if cs: _cs = ConnectionSettingAttribute() _cs.idle_timeout = cs.get('idle_timeout', 60) added_attr = conn.modify_lb_attribute(name, 'connectingSettings', _cs) if added_attr: msg = 'Added connecting_settings attribute to {0} elb.' log.info(msg.format(name)) else: log.error('Failed to add connecting_settings attribute.') return False return True
def set_attributes(name, attributes, region=None, key=None, keyid=None, profile=None): """ Set attributes on an ELB. name (string) Name of the ELB instance to set attributes for attributes A dict of attributes to set. Valid attributes are: access_log (dict) enabled (bool) Enable storage of access logs. s3_bucket_name (string) The name of the S3 bucket to place logs. s3_bucket_prefix (string) Prefix for the log file name. emit_interval (int) Interval for storing logs in S3 in minutes. Valid values are 5 and 60. connection_draining (dict) enabled (bool) Enable connection draining. timeout (int) Maximum allowed time in seconds for sending existing connections to an instance that is deregistering or unhealthy. Default is 300. cross_zone_load_balancing (dict) enabled (bool) Enable cross-zone load balancing. CLI example to set attributes on an ELB: .. code-block:: bash salt myminion boto_elb.set_attributes myelb '{"access_log": {"enabled": "true", "s3_bucket_name": "mybucket", "s3_bucket_prefix": "mylogs/", "emit_interval": "5"}}' region=us-east-1 """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) al = attributes.get("access_log", {}) czlb = attributes.get("cross_zone_load_balancing", {}) cd = attributes.get("connection_draining", {}) cs = attributes.get("connecting_settings", {}) if not al and not czlb and not cd and not cs: log.error("No supported attributes for ELB.") return False if al: _al = AccessLogAttribute() _al.enabled = al.get("enabled", False) if not _al.enabled: msg = "Access log attribute configured, but enabled config missing" log.error(msg) return False _al.s3_bucket_name = al.get("s3_bucket_name", None) _al.s3_bucket_prefix = al.get("s3_bucket_prefix", None) _al.emit_interval = al.get("emit_interval", None) added_attr = conn.modify_lb_attribute(name, "accessLog", _al) if added_attr: log.info("Added access_log attribute to {0} elb.".format(name)) else: msg = "Failed to add access_log attribute to {0} elb." log.error(msg.format(name)) return False if czlb: _czlb = CrossZoneLoadBalancingAttribute() _czlb.enabled = czlb["enabled"] added_attr = conn.modify_lb_attribute(name, "crossZoneLoadBalancing", _czlb.enabled) if added_attr: msg = "Added cross_zone_load_balancing attribute to {0} elb." log.info(msg.format(name)) else: log.error("Failed to add cross_zone_load_balancing attribute.") return False if cd: _cd = ConnectionDrainingAttribute() _cd.enabled = cd["enabled"] _cd.timeout = cd.get("timeout", 300) added_attr = conn.modify_lb_attribute(name, "connectionDraining", _cd) if added_attr: msg = "Added connection_draining attribute to {0} elb." log.info(msg.format(name)) else: log.error("Failed to add connection_draining attribute.") return False if cs: _cs = ConnectionSettingAttribute() _cs.idle_timeout = cs.get("idle_timeout", 60) added_attr = conn.modify_lb_attribute(name, "connectingSettings", _cs) if added_attr: msg = "Added connecting_settings attribute to {0} elb." log.info(msg.format(name)) else: log.error("Failed to add connecting_settings attribute.") return False return True
def deploy_latest_app_ami(app_name, env_name): global aws aws = AWS.from_config(config) aws.connect() lb_group_ids=[aws.get_security_group_id('riker-load-balancer')] inst_group_ids=[aws.get_security_group_id('riker-instance')] app = App(env_name, app_name) health_check_target = app.config.get('health_check', 'TCP:80') name = re.sub('[^A-Za-z0-9\-]', '-', app.name) app_image = LatestAppImage(app).get() print '-----> Connecting to ELB' elb_conn = boto.connect_elb() log('info', 'Load balancer', show_header=True) load_balancer_name = name try: elb_result = elb_conn.get_all_load_balancers(load_balancer_names=[load_balancer_name]) lb = elb_result[0] log('info', 'Found {}'.format(load_balancer_name)) except boto.exception.BotoServerError: log('info', 'Not found, creating load balancer') listeners = [(80, 80, 'HTTP', 'HTTP')] lb = elb_conn.create_load_balancer(name=load_balancer_name, zones=None, complex_listeners=listeners, security_groups=lb_group_ids, subnets=[aws.subnet_id]) hc = HealthCheck(target=health_check_target) lb.configure_health_check(hc) cda = ConnectionDrainingAttribute() cda.enabled = True cda.timeout = 300 elb_conn.modify_lb_attribute(load_balancer_name=load_balancer_name, attribute='connectionDraining', value=cda) print '-----> Connecting to AutoScale' as_conn = boto.connect_autoscale() log('info', 'Launch configuration', show_header=True) launch_config_name = "{}-{}".format(name, app_image.tags['deploy-id']) lc_result = as_conn.get_all_launch_configurations(names=[launch_config_name]) if len(lc_result) == 0: log('info', 'Not found, creating LaunchConfiguration') lc = LaunchConfiguration(name=launch_config_name, image_id=app_image.id, key_name=aws.key_pair_name, security_groups=inst_group_ids, instance_type=aws.instance_type) as_conn.create_launch_configuration(lc) else: log('info', 'Found {}'.format(launch_config_name)) lc = lc_result[0] existing_group = None deploy_id = int(app_image.tags['deploy-id'] or 0) log('info', 'Getting previous auto-scaling group', show_header=True) for did in xrange(deploy_id-1, 0, -1): existing_group_name = "{}-{}".format(name, did) log('info', '{} ?'.format(existing_group_name)) ag_result = as_conn.get_all_groups(names=[existing_group_name]) if len(ag_result) > 0: existing_group = ag_result[0] log('info', 'Found {}'.format(existing_group.name)) break else: log('info', 'No') if existing_group is not None: existing_healthy_instances = [inst for inst in existing_group.instances if inst.lifecycle_state == 'InService' and inst.health_status == 'Healthy'] existing_healthy_instance_count = len(existing_healthy_instances) desired_capacity = existing_group.desired_capacity min_size = existing_group.min_size max_size = existing_group.max_size if existing_healthy_instance_count == 0 and desired_capacity == 0: print '-----> WARNING: existing auto-scaling group {} has no healthy instances and a desired capacity of 0. New auto-scaling group will launch 1 instance.'.format(existing_group) desired_capacity = 1 min_size = 1 max_size = max_size if max_size > 0 else 1 else: existing_healthy_instance_count = 0 desired_capacity = 1 min_size = 1 max_size = 1 log('info', '{} existing instance(s) found'.format(existing_healthy_instance_count), show_header=True) log('info', 'Existing auto-scale properties: desired_capacity={}, min_size={}, max_size={}'.format(desired_capacity, min_size, max_size)) log('info', 'Auto-scaling group', show_header=True) group_name = "{}-{}".format(name, app_image.tags['deploy-id']) ag_result = as_conn.get_all_groups(names=[group_name]) if len(ag_result) == 0: log('info', 'Not found, creating autoscale group') ag = AutoScalingGroup(name=group_name, load_balancers=[load_balancer_name], launch_config=lc, desired_capacity=desired_capacity, min_size=min_size, max_size=max_size, health_check_type='ELB', health_check_period='300', vpc_zone_identifier=aws.subnet_id) as_conn.create_auto_scaling_group(ag) else: log('info', 'Found {}'.format(group_name)) ag = ag_result[0] ag.desired_capacity = desired_capacity ag.max_size = max_size ag.min_size = min_size ag.launch_config_name = launch_config_name ag.update() log('info', 'Waiting for new instances to become healthy', show_header=True) all_healthy = False for i in xrange(60): if i > 0: print ' ---' time.sleep(10) elb_result = elb_conn.get_all_load_balancers(load_balancer_names=[load_balancer_name]) lb = elb_result[0] lb_insts = lb.get_instance_health() print ' Load-balancer instances: {}'.format(lb_insts) # NOTE: re-get auto-scaling group to get updated instance info. ag = as_conn.get_all_groups(names=[group_name])[0] ag_insts = [inst for inst in ag.instances] log('info', 'Auto-scaling group Instances: {}'.format(ag_insts)) if len(ag_insts) < desired_capacity: not_yet_launched_count = desired_capacity - len(ag_insts) log('info', '{} new instance(s) not yet launched'.format(not_yet_launched_count)) continue ag_inst_ids = set(inst.instance_id for inst in ag_insts) lb_inst_ids = set(inst.instance_id for inst in lb_insts) asg_insts_not_in_lb = ag_inst_ids.difference(lb_inst_ids) if len(asg_insts_not_in_lb) > 0: log('info', '{} new instance(s) not yet in load balancer'.format(len(asg_insts_not_in_lb))) continue new_lb_insts = [inst for inst in lb_insts if inst.instance_id in ag_inst_ids] healthy_new_lb_insts = [inst for inst in new_lb_insts if inst.state == 'InService'] all_healthy = len(healthy_new_lb_insts) == len(ag_insts) log('info', '{} new instance(s) are healthy'.format(len(healthy_new_lb_insts))) diff = existing_healthy_instance_count - len(healthy_new_lb_insts) if existing_group is not None and diff >= 0: change = False if existing_group.desired_capacity != diff: existing_group.desired_capacity = diff change = True if existing_group.max_size != diff: existing_group.max_size = diff change = True if diff < existing_group.min_size: existing_group.min_size = diff change = True if change: existing_group.update() log('info', 'Change previous auto-scale group {} properties: desired_capacity={}, min_size={}, max_size={}'.format(existing_group, existing_group.desired_capacity, existing_group.min_size, existing_group.max_size)) if all_healthy: log('info', 'All new instances healthy!', show_header=True) healthy_lb_inst_ids = [inst.instance_id for inst in lb_insts if inst.state == 'InService'] previous_healthy_inst_ids = [inst.instance_id for inst in existing_healthy_instances] if existing_group else [] not_yet_out_of_service = set(previous_healthy_inst_ids).intersection(healthy_lb_inst_ids) if len(not_yet_out_of_service) > 0: log('info', 'Waiting to remove previous instances ({}) from load balancer'.format(not_yet_out_of_service)) else: log('info', 'All previous instances ({}) have been removed from load balancer'.format(previous_healthy_inst_ids), show_header=True) if all_healthy and len(not_yet_out_of_service) == 0: break else: raise Exception("Timeout") elb_result = elb_conn.get_all_load_balancers(load_balancer_names=[load_balancer_name]) lb = elb_result[0] lb_insts = [inst for inst in lb.get_instance_health() if inst.state == 'InService'] print '-----> Deployed {} instance(s) of {} to {}'.format(lb_insts, app.name, lb.dns_name) print '-----> DONE!'
def deploy_latest_app_ami(app_name, env_name): global aws aws = AWS.from_config(config) aws.connect() lb_group_ids = [aws.get_security_group_id('riker-load-balancer')] inst_group_ids = [aws.get_security_group_id('riker-instance')] app = App(env_name, app_name) health_check_target = app.config.get('health_check', 'TCP:80') name = re.sub('[^A-Za-z0-9\-]', '-', app.name) app_image = LatestAppImage(app).get() print '-----> Connecting to ELB' elb_conn = boto.connect_elb() log('info', 'Load balancer', show_header=True) load_balancer_name = name try: elb_result = elb_conn.get_all_load_balancers( load_balancer_names=[load_balancer_name]) lb = elb_result[0] log('info', 'Found {}'.format(load_balancer_name)) except boto.exception.BotoServerError: log('info', 'Not found, creating load balancer') listeners = [(80, 80, 'HTTP', 'HTTP')] lb = elb_conn.create_load_balancer(name=load_balancer_name, zones=None, complex_listeners=listeners, security_groups=lb_group_ids, subnets=[aws.subnet_id]) hc = HealthCheck(target=health_check_target) lb.configure_health_check(hc) cda = ConnectionDrainingAttribute() cda.enabled = True cda.timeout = 300 elb_conn.modify_lb_attribute(load_balancer_name=load_balancer_name, attribute='connectionDraining', value=cda) print '-----> Connecting to AutoScale' as_conn = boto.connect_autoscale() log('info', 'Launch configuration', show_header=True) launch_config_name = "{}-{}".format(name, app_image.tags['deploy-id']) lc_result = as_conn.get_all_launch_configurations( names=[launch_config_name]) if len(lc_result) == 0: log('info', 'Not found, creating LaunchConfiguration') lc = LaunchConfiguration(name=launch_config_name, image_id=app_image.id, key_name=aws.key_pair_name, security_groups=inst_group_ids, instance_type=aws.instance_type) as_conn.create_launch_configuration(lc) else: log('info', 'Found {}'.format(launch_config_name)) lc = lc_result[0] existing_group = None deploy_id = int(app_image.tags['deploy-id'] or 0) log('info', 'Getting previous auto-scaling group', show_header=True) for did in xrange(deploy_id - 1, 0, -1): existing_group_name = "{}-{}".format(name, did) log('info', '{} ?'.format(existing_group_name)) ag_result = as_conn.get_all_groups(names=[existing_group_name]) if len(ag_result) > 0: existing_group = ag_result[0] log('info', 'Found {}'.format(existing_group.name)) break else: log('info', 'No') if existing_group is not None: existing_healthy_instances = [ inst for inst in existing_group.instances if inst.lifecycle_state == 'InService' and inst.health_status == 'Healthy' ] existing_healthy_instance_count = len(existing_healthy_instances) desired_capacity = existing_group.desired_capacity min_size = existing_group.min_size max_size = existing_group.max_size if existing_healthy_instance_count == 0 and desired_capacity == 0: print '-----> WARNING: existing auto-scaling group {} has no healthy instances and a desired capacity of 0. New auto-scaling group will launch 1 instance.'.format( existing_group) desired_capacity = 1 min_size = 1 max_size = max_size if max_size > 0 else 1 else: existing_healthy_instance_count = 0 desired_capacity = 1 min_size = 1 max_size = 1 log('info', '{} existing instance(s) found'.format( existing_healthy_instance_count), show_header=True) log( 'info', 'Existing auto-scale properties: desired_capacity={}, min_size={}, max_size={}' .format(desired_capacity, min_size, max_size)) log('info', 'Auto-scaling group', show_header=True) group_name = "{}-{}".format(name, app_image.tags['deploy-id']) ag_result = as_conn.get_all_groups(names=[group_name]) if len(ag_result) == 0: log('info', 'Not found, creating autoscale group') ag = AutoScalingGroup(name=group_name, load_balancers=[load_balancer_name], launch_config=lc, desired_capacity=desired_capacity, min_size=min_size, max_size=max_size, health_check_type='ELB', health_check_period='300', vpc_zone_identifier=aws.subnet_id) as_conn.create_auto_scaling_group(ag) else: log('info', 'Found {}'.format(group_name)) ag = ag_result[0] ag.desired_capacity = desired_capacity ag.max_size = max_size ag.min_size = min_size ag.launch_config_name = launch_config_name ag.update() log('info', 'Waiting for new instances to become healthy', show_header=True) all_healthy = False for i in xrange(60): if i > 0: print ' ---' time.sleep(10) elb_result = elb_conn.get_all_load_balancers( load_balancer_names=[load_balancer_name]) lb = elb_result[0] lb_insts = lb.get_instance_health() print ' Load-balancer instances: {}'.format(lb_insts) # NOTE: re-get auto-scaling group to get updated instance info. ag = as_conn.get_all_groups(names=[group_name])[0] ag_insts = [inst for inst in ag.instances] log('info', 'Auto-scaling group Instances: {}'.format(ag_insts)) if len(ag_insts) < desired_capacity: not_yet_launched_count = desired_capacity - len(ag_insts) log( 'info', '{} new instance(s) not yet launched'.format( not_yet_launched_count)) continue ag_inst_ids = set(inst.instance_id for inst in ag_insts) lb_inst_ids = set(inst.instance_id for inst in lb_insts) asg_insts_not_in_lb = ag_inst_ids.difference(lb_inst_ids) if len(asg_insts_not_in_lb) > 0: log( 'info', '{} new instance(s) not yet in load balancer'.format( len(asg_insts_not_in_lb))) continue new_lb_insts = [ inst for inst in lb_insts if inst.instance_id in ag_inst_ids ] healthy_new_lb_insts = [ inst for inst in new_lb_insts if inst.state == 'InService' ] all_healthy = len(healthy_new_lb_insts) == len(ag_insts) log('info', '{} new instance(s) are healthy'.format(len(healthy_new_lb_insts))) diff = existing_healthy_instance_count - len(healthy_new_lb_insts) if existing_group is not None and diff >= 0: change = False if existing_group.desired_capacity != diff: existing_group.desired_capacity = diff change = True if existing_group.max_size != diff: existing_group.max_size = diff change = True if diff < existing_group.min_size: existing_group.min_size = diff change = True if change: existing_group.update() log( 'info', 'Change previous auto-scale group {} properties: desired_capacity={}, min_size={}, max_size={}' .format(existing_group, existing_group.desired_capacity, existing_group.min_size, existing_group.max_size)) if all_healthy: log('info', 'All new instances healthy!', show_header=True) healthy_lb_inst_ids = [ inst.instance_id for inst in lb_insts if inst.state == 'InService' ] previous_healthy_inst_ids = [ inst.instance_id for inst in existing_healthy_instances ] if existing_group else [] not_yet_out_of_service = set( previous_healthy_inst_ids).intersection(healthy_lb_inst_ids) if len(not_yet_out_of_service) > 0: log( 'info', 'Waiting to remove previous instances ({}) from load balancer' .format(not_yet_out_of_service)) else: log('info', 'All previous instances ({}) have been removed from load balancer' .format(previous_healthy_inst_ids), show_header=True) if all_healthy and len(not_yet_out_of_service) == 0: break else: raise Exception("Timeout") elb_result = elb_conn.get_all_load_balancers( load_balancer_names=[load_balancer_name]) lb = elb_result[0] lb_insts = [ inst for inst in lb.get_instance_health() if inst.state == 'InService' ] print '-----> Deployed {} instance(s) of {} to {}'.format( lb_insts, app.name, lb.dns_name) print '-----> DONE!'