def control(args): """Control the stack: update the AutoScaleGroup constraints.""" config, settings, sinfo = initialize_from_cli(args) stack = find_one_stack(args.stack_name, summary=False) yield format_stack_summary(stack) + '\n' asg = find_one_resource(stack, RES_TYPE_ASG) yield format_autoscale(asg) if args.min or args.max or args.desired: try: asg.min_size = int(args.min) asg.max_size = int(args.max) asg.desired_capacity = int(args.desired) except ValueError as error: raise CommandError("Invalid value for ASG: %s" % error) yield "Change to:" yield format_autoscale(asg) warn_for_live(sinfo) confirm_action(arg, default=True) asg.update() yield "Updated"
def batch_update(args): """Update a batch of stacks sequentially.""" args.template = None stacks = find_stacks(args.stack_name) yield format_stacks(stacks) confirm_action(arg, default=False) for stack in stacks: args.stack_name = stack.stack_name try: update(args) except CommandError as error: print error if not confirm('Continue anyway?', default=True): raise
def delete(args): """Delete a stack.""" config, settings, sinfo = initialize_from_cli(args) stack = find_one_stack(args.stack_name) yield format_stack_summary(stack) warn_for_live(sinfo) confirm_action(arg, default=True) try: res = boto.connect_cloudformation().delete_stack(stack.stack_name) except BotoServerError as error: if error: raise CommandError("BotoServerError: " + error.error_message) else: raise error print("Result %s" % res)
def stop(args): """Stop the stack: force the AutoScale to shut all instances down.""" config, settings, sinfo = initialize_from_cli(args) stack = find_one_stack(args.stack_name, summary=False) yield format_stack_summary(stack) asg = find_one_resource(stack, RES_TYPE_ASG) yield format_autoscale(asg) asg.min_size = 0 asg.max_size = 0 asg.desired_capacity = 0 yield "Change to:" yield format_autoscale(asg) warn_for_live(sinfo) confirm_action(arg, default=True) asg.update() yield "Updated"
def create(args): """Create a stack.""" config, settings, sinfo = initialize_from_cli(args) # Read template template_path = os.path.join( config.get("cfn", "templatedir"), args.template if args.template else sinfo['template']) template = cfntemplate.CfnTemplate(template_path) parameters = cfntemplate.CfnParameters(template, sinfo) tags = { 'Name': args.stack_name, 'Application': sinfo['Application'], 'Environment': sinfo['Environment'], 'Type': sinfo['Type'], } print("\nStack name: {args.stack_name}\n" "\nTemplate: {template!r}\n" "\nTags: {tags!r}\n" "\nParameters:\n{parameters!r}\n".format(args=args, template=template, parameters=parameters, tags=tags)) confirm_action(arg, default=True) try: stackid = boto.connect_cloudformation().create_stack( args.stack_name, template_body=template.body, parameters=parameters, tags=tags, capabilities=['CAPABILITY_IAM']) print("StackId %s" % stackid) except BotoServerError as error: if error.error_message: raise CommandError("BotoServerError: " + error.error_message) else: raise error
def start(args): """Start the stack: set AutoScale control to configured values.""" config, settings, sinfo = initialize_from_cli(args) stack = find_one_stack(args.stack_name, summary=False) print(format_stack_summary(stack)) asg = find_one_resource(stack, RES_TYPE_ASG) yield format_autoscale(asg) try: asg.min_size = int(sinfo['AutoScaleMinSize']) asg.max_size = int(sinfo['AutoScaleMaxSize']) asg.desired_capacity = int(sinfo['AutoScaleDesiredCapacity']) except ValueError as error: raise CommandError("Invalid values in stack definition: %s" % error) yield "Change to:" yield format_autoscale(asg) warn_for_live(sinfo) confirm_action(arg, default=True) asg.update() yield "Updated"
def update(args): """Update a stack.""" config, settings, sinfo = initialize_from_cli(args) # Read template template = cfntemplate.CfnTemplate( os.path.join( config.get("cfn", "templatedir"), args.template if args.template else sinfo['template'] ) ) parameters = cfntemplate.CfnParameters(template, sinfo) print("\nStack name: {args.stack_name}\n" "\nTemplate: {template!r}\n" "\nParameters:\n" "{parameters!r}\n".format(args=args, template=template, parameters=parameters)) warn_for_live(sinfo) confirm_action(arg, default=True) try: stackid = boto.connect_cloudformation().update_stack( args.stack_name, template_body=template.body, parameters=parameters, capabilities=['CAPABILITY_IAM']) print("StackId %s" % stackid) except BotoServerError as error: if error.error_message: raise CommandError("BotoServerError: " + error.error_message) else: raise error
def migrate_cfg(args): """Migrate the stack: re-instantiate all instances.""" config, settings, sinfo = initialize_from_cli(args) stack = find_one_stack(args.stack_name, summary=False) print(format_stack_summary(stack)) asg = find_one_resource(stack, RES_TYPE_ASG) yield format_autoscale(asg) orig_min = asg.min_size orig_max = asg.max_size orig_desired = asg.desired_capacity orig_term_pol = asg.termination_policies mig_min = orig_desired * 2 mig_max = orig_desired * 2 mig_desired = orig_desired * 2 mig_term_pol = [u'OldestLaunchConfiguration', u'OldestInstance'] if orig_desired != len(asg.instances): raise CommandError("The ASG is not stable (desired != instances)") for instance in asg.instances: if instance.health_status != 'Healthy': raise CommandError("The ASG is not stable (instance not healthy)") warn_for_live(sinfo) confirm_action(arg, default=True) yield "\n <> Setting termination policy to %s" % mig_term_pol asg.termination_policies = mig_term_pol asg.update() yield "\n <> Growing the desired capacity from %s to %s" % ( orig_desired, mig_desired) asg.min_size = mig_min asg.max_size = mig_max asg.desired_capacity = mig_desired asg.update() yield "\n <> Waiting instances to stabilize..." while True: sleep(30) asg = find_one_resource(stack, RES_TYPE_ASG) res_elb_id = find_one_resource(stack, RES_TYPE_ELB, only_id=True) elbinstances = boto.connect_elb().describe_instance_health(res_elb_id) if len(asg.instances) < mig_desired: yield " NOTYET: only %i instances created" % len(asg.instances) continue elif [i for i in asg.instances if i.health_status != 'Healthy']: yield " NOTYET: still unhealthy instances" continue elif len(elbinstances) < mig_desired: yield " NOTYET: only %i instances in ELB" % len(elbinstances) continue elif [i for i in elbinstances if i.state != 'InService']: yield " NOTYET: not all instances are ELB:InService" continue else: yield " OK: %s healthy instances in ELB" % len(asg.instances) break yield "\n <> Checking new ASG state..." asg = find_one_resource(stack, RES_TYPE_ASG) yield format_autoscale(asg) yield format_autoscale_instances(stack) yield "\n <> Restoring previous ASG control:" asg.termination_policies = orig_term_pol asg.min_size = orig_min asg.max_size = orig_max asg.desired_capacity = orig_desired yield format_autoscale(asg) if confirm('Restoring ASG config?', default=True): try: asg.update() except BotoServerError as error: yield "\n <> Restoration failed!" yield error else: yield "\n <> ASG control restored." else: yield "WARNING: The ASG desired capacity was doubled!"