def create_command(ctx, path, change_set_name, yes): """ Creates a stack or a change set. Creates a stack for a given config PATH. Or if CHANGE_SET_NAME is specified creates a change set for stack in PATH. :param path: Path to a Stack or StackGroup :type path: str :param change_set_name: A name of the Change Set - optional :type change_set_name: str :param yes: A flag to assume yes to all questions. :type yes: bool """ context = SceptreContext( command_path=path, project_path=ctx.obj.get("project_path"), user_variables=ctx.obj.get("user_variables"), options=ctx.obj.get("options"), ignore_dependencies=ctx.obj.get("ignore_dependencies")) action = "create" plan = SceptrePlan(context) if change_set_name: confirmation(action, yes, change_set=change_set_name, command_path=path) plan.create_change_set(change_set_name) else: confirmation(action, yes, command_path=path) responses = plan.create() exit(stack_status_exit_code(responses.values()))
def update_command(ctx, path, change_set, verbose, yes): """ Updates a stack for a given config PATH. Or perform an update via change-set when the change-set flag is set. \f :param path: Path to execute the command on. :type path: str :param change_set: Whether a change set should be created. :type change_set: bool :param verbose: A flag to print a verbose output. :type verbose: bool :param yes: A flag to answer 'yes' to all CLI questions. :type yes: bool """ context = SceptreContext( command_path=path, project_path=ctx.obj.get("project_path"), config_directory=ctx.obj.get("config_directory"), user_variables=ctx.obj.get("user_variables"), options=ctx.obj.get("options"), output_format=ctx.obj.get("output_format"), ignore_dependencies=ctx.obj.get("ignore_dependencies")) plan = SceptrePlan(context) if change_set: change_set_name = "-".join(["change-set", uuid1().hex]) plan.create_change_set(change_set_name) try: # Wait for change set to be created statuses = plan.wait_for_cs_completion(change_set_name) # Exit if change set fails to create for status in list(statuses.values()): if status != StackChangeSetStatus.READY: exit(1) # Describe changes descriptions = plan.describe_change_set(change_set_name) for description in list(descriptions.values()): if not verbose: description = simplify_change_set_description(description) write(description, context.output_format) # Execute change set if happy with changes if yes or click.confirm("Proceed with stack update?"): plan.execute_change_set(change_set_name) except Exception as e: raise e finally: # Clean up by deleting change set plan.delete_change_set(change_set_name) else: confirmation("update", yes, command_path=path) responses = plan.update() exit(stack_status_exit_code(responses.values()))
def step_impl(context, change_set_name, stack_name): sceptre_context = SceptreContext(command_path=stack_name + '.yaml', project_path=context.sceptre_dir) sceptre_plan = SceptrePlan(sceptre_context) allowed_errors = {'ValidationError', 'ChangeSetNotFound'} try: sceptre_plan.create_change_set(change_set_name) except ClientError as e: if e.response['Error']['Code'] in allowed_errors: context.error = e return else: raise e wait_for_final_state(context, stack_name, change_set_name)
class Sceptre(CloudFormation): def __init__(self, project, stack, *args, **kwargs): self.project = project self.stack = stack super(Sceptre, self).__init__(project, *args, **kwargs) self.stack_name = self.get_stack(stack)['StackName'] context = SceptreContext( self.resolve_sceptre_project_path().as_posix(), self.resolve_stack_file().as_posix(), ignore_dependencies=True ) self.plan = SceptrePlan(context) # import pdb; pdb.set_trace() @staticmethod def resolve_sceptre_project_path(): cwd = Path().cwd() for content in cwd.iterdir(): if 'infrastructure' in content.as_posix() and content.is_dir(): return content raise ClickException( 'We could not find an infrastructure folder. Make sure you are at ' 'the top-level directory of the project you are trying to deploy.' ) def resolve_stack_file(self): stack_file_path = self.stack if not self.stack.endswith('.yaml'): stack_file_path += '.yaml' if not self.stack.startswith('prod/'): stack_file_path = Path('prod') / stack_file_path return Path(stack_file_path) def create_change_set(self, change_set_name): os.environ['AWS_DEFAULT_PROFILE'] = self.aws_profile os.environ['AWS_DEFAULT_REGION'] = self.aws_region with click_spinner.spinner(): self.plan.create_change_set(change_set_name) self.plan.wait_for_cs_completion(change_set_name)