Example #1
0
def apply(ctx, profile, config_file, environment, region, change_set_name,
          change_set_id):
    """
    Apply a CloudFormation ChangeSet to create or update a CloudFormation stack.
    If using --change-set-name then --config --environment and --region are required.
    If using --change-set-id no other values are required (although --profile and --region may be needed).
    """
    if not change_set_name and not change_set_id:
        raise click.UsageError(
            "Option '--change-set-name' or '--change-set-id' required.")

    try:
        if change_set_id:
            runner = create_changeset_runner(profile, region, change_set_id)
            runner.apply_change_set()
        else:
            if not config_file:
                raise click.UsageError(
                    "Missing option '-c' / '--config-file'.")
            if not environment:
                raise click.UsageError(
                    "Missing option '-e' / '--environment'.")

            cfg = load_config(config_file,
                              ctx.obj.config,
                              environment,
                              False,
                              ChangeSetName=change_set_name)
            runner = create_runner(profile, cfg)
            runner.apply_change_set()
    except (ValidationError, StackError) as e:
        error(f'\nError: {e}')
        exit(1)
Example #2
0
def reject(ctx, profile, config_file, environment, region, change_set_name,
           change_set_id):
    """
    Reject a CloudFormation ChangeSet, deleting the stack if in REVIEW_IN_PROGRESS status and has no other ChangeSets.
    If using --change-set-name then --config --environment and --region are required.
    If using --change-set-id no other values are required (although --profile and --region may be needed).
    """
    if not change_set_name and not change_set_id:
        raise click.UsageError(
            "Option '--change-set-name' or '--change-set-id' required.")

    try:
        if change_set_id:
            runner = create_changeset_runner(profile, region, change_set_id)
            runner.reject_change_set()
        else:
            if not config_file:
                raise click.UsageError(
                    "Missing option '-c' / '--config-file'.")
            if not environment:
                raise click.UsageError(
                    "Missing option '-e' / '--environment'.")

            cfg = load_config(config_file,
                              ctx.obj.config,
                              environment,
                              False,
                              ChangeSetName=change_set_name)
            runner = create_runner(profile, cfg)
            runner.reject_change_set()
    except (ValidationError, StackError) as e:
        error(f'\nError: {e}')
        exit(1)
Example #3
0
def delete(ctx, profile, config, environment, region, retain_resources):
    try:
        cfg = load_config(config, environment, region, None, None)
        runner = create_runner(profile, cfg, None, False)
        runner.delete(retain_resources)
    except (ValidationError, StackError) as e:
        error(f'\nError: {e}')
Example #4
0
def apply(ctx, profile, config, environment, region, change_set_name):
    try:
        cfg = load_config(config, environment, region, None, None)
        runner = create_runner(profile, cfg, change_set_name, False)
        runner.execute_change_set()
    except (ValidationError, StackError) as e:
        error(f'\nError: {e}')
Example #5
0
    def delete(self, retain_resources=[]):
        """
        Delete a Stack, optionally retraining certain resources.
        Waits for Stack to delete and prints Events if deletion fails
        :param list retain_resources: List of LogicalIds to retain
        :raises StackError: if deletion fails
        """
        if not self.stack:
            raise ValidationError(f'Stack {self.config.stack_name} not found')
        if not StackStatus.is_deletable(self.stack):
            raise ValidationError(f'Stack {self.config.stack_name} is not in a deletable status: '
                                  f'{StackStatus.get_status(self.stack).name}')

        info(f'\nDeleting Stack {self.config.stack_name}')
        last_timestamp = self.get_last_timestamp()

        try:
            self.client.delete_stack(StackName=self.config.stack_name, RetainResources=retain_resources)

            self.client.get_waiter('stack_delete_complete').wait(
                StackName=self.config.stack_name,
                WaiterConfig={'Delay': 10, 'MaxAttempts': 360})

            info(f'\nDeletion of Stack {self.config.stack_name} successfully completed')
            self.stack = None
        except ClientError as ce:
            raise StackError(ce)
        except WaiterError as we:
            error(f'\nDeletion of Stack {self.config.stack_name} failed:\n')
            self.print_events(last_timestamp)
            raise StackError(we)
Example #6
0
    def execute_change_set(self):
        """
        Execute a ChangeSet, waiting for execution to complete and printing the details of Stack Events
        caused by this ChangeSet
        :raises StackError: If there is an error executing the ChangeSet
        """
        last_timestamp = self.get_last_timestamp()

        try:
            info(f'\nExecuting ChangeSet {self.change_set_name} for {self.config.stack_name}')

            self.client.execute_change_set(ChangeSetName=self.change_set_name, StackName=self.config.stack_name)

            waiter_name = 'stack_create_complete' if StackStatus.is_creatable(self.stack) else 'stack_update_complete'
            self.client.get_waiter(waiter_name).wait(StackName=self.config.stack_name,
                                                     WaiterConfig={'Delay': 10, 'MaxAttempts': 360})

            info(f'\nChangeSet {self.change_set_name} for {self.config.stack_name} successfully completed:\n')
            self.print_events(last_timestamp)

        except ClientError as ce:
            raise StackError(ce)
        except WaiterError as we:
            error(f'\nChangeSet {self.change_set_name} for {self.config.stack_name} failed:\n')
            self.print_events(last_timestamp)
            raise StackError(we)
Example #7
0
def deploy(ctx, profile, config, environment, region, template, parameter,
           change_set_name, auto_approve):
    try:
        cfg = load_config(config, environment, region, template, parameter)
        runner = create_runner(profile, cfg, change_set_name, auto_approve)
        runner.deploy()
    except (ValidationError, StackError) as e:
        error(f'\nError: {e}')
Example #8
0
 def failed_change_set(self, last_timestamp):
     """
     Print Stack Events on failed change set.
     Subclasses can override this to output errors in a different format.
     """
     error(
         f'\nChangeSet {self.change_set_name} for {self.config.stack_name} failed:\n'
     )
     self.print_events(last_timestamp)
Example #9
0
def build_lambda(ctx, source_dir, output_dir, runtime, archive_name):
    """
    Build a Lambda function zip file.
    Can be chained into the upload command where it pre-populates the --filename option.
    """
    try:
        ctx.obj.zip_file = stackmanager.packager.build_lambda(
            source_dir, output_dir, runtime, archive_name)
    except (PackagingError, ValidationError) as e:
        error(f'\nError: {e}')
        exit(1)
Example #10
0
def delete(ctx, profile, config_file, environment, region, retain_resources):
    """
    Delete a CloudFormation stack.
    """
    try:
        cfg = load_config(config_file, ctx.obj.config, environment, False)
        runner = create_runner(profile, cfg)
        runner.delete(retain_resources)
    except (ValidationError, StackError) as e:
        error(f'\nError: {e}')
        exit(1)
Example #11
0
def get_output(ctx, profile, config_file, environment, region, output_key):
    """
    Returns matching Output value if it exists.
    """
    try:
        cfg = load_config(config_file, ctx.obj.config, environment, False)
        runner = create_runner(profile, cfg)
        output_value = runner.get_output(output_key)
        echo(output_value)
    except (ValidationError, StackError) as e:
        error(f'\nError: {e}')
        exit(1)
Example #12
0
def status(ctx, profile, config_file, environment, region, event_days):
    """
    Print current status of Stack.
    Includes pending ChangeSets and recent events.
    """
    try:
        cfg = load_config(config_file, ctx.obj.config, environment, False)
        runner = create_runner(profile, cfg)
        runner.status(event_days)
    except (ValidationError, StackError) as e:
        error(f'\nError: {e}')
        exit(1)
Example #13
0
def upload(ctx, profile, region, filename, bucket, key, bucket_parameter,
           key_parameter):
    """
    Uploads a File to S3.
    This might be a large CloudFormation template, or a Lambda zip file.
    Can be chained into the deploy command where it pre-populates parameters for the uploaded file.
    """
    if not filename and not ctx.obj.zip_file:
        raise click.UsageError("Missing option '-f' / '--filename'.")

    try:
        uploader = create_uploader(profile, region)
        uploader.upload(filename or ctx.obj.zip_file, bucket, key)
        ctx.obj.config.add_parameters({
            bucket_parameter: bucket,
            key_parameter: key
        })
    except (TransferError, ValidationError) as e:
        error(f'\nError: {e}')
        exit(1)
Example #14
0
def deploy(ctx, profile, config_file, environment, region, template, parameter,
           parameter_use_previous, change_set_name, existing_changes,
           auto_apply):
    """
    Create or update a CloudFormation stack using ChangeSets.
    """
    try:
        cfg = load_config(config_file,
                          ctx.obj.config,
                          environment,
                          Template=template,
                          Parameters=parameter,
                          PreviousParameters=parameter_use_previous,
                          ChangeSetName=change_set_name,
                          ExistingChanges=existing_changes,
                          AutoApply=auto_apply)
        runner = create_runner(profile, cfg)
        runner.deploy()
    except (ValidationError, StackError) as e:
        error(f'\nError: {e}')
        exit(1)