Beispiel #1
0
def list_change_sets(ctx, path):
    """
    List change sets for stack.

    :param path: Path to execute the command on.
    :type path: str
    """
    context = SceptreContext(
        command_path=path,
        project_path=ctx.obj.get("project_path"),
        user_variables=ctx.obj.get("user_variables"),
        output_format=ctx.obj.get("output_format"),
        options=ctx.obj.get("options"),
        ignore_dependencies=ctx.obj.get("ignore_dependencies"))

    plan = SceptrePlan(context)
    responses = [
        response for response in plan.list_change_sets().values() if response
    ]

    for response in responses:
        write(response, context.output_format)
Beispiel #2
0
def status_command(ctx, path):
    """
    Print status of stack or stack_group.

    Prints the stack status or the status of the stacks within a
    stack_group for a given config PATH.

    :param path: Path to execute the command on.
    :type path: str
    """
    context = SceptreContext(command_path=path,
                             project_path=ctx.obj.get("project_path"),
                             user_variables=ctx.obj.get("user_variables"),
                             options=ctx.obj.get("options"),
                             no_colour=ctx.obj.get("no_colour"),
                             output_format=ctx.obj.get("output_format"))

    plan = SceptrePlan(context)
    responses = plan.get_status()
    message = "\n".join("{}: {}".format(stack.name, status)
                        for stack, status in responses.items())
    write(message, no_colour=context.no_colour)
Beispiel #3
0
def list_resources(ctx, path):
    """
    List resources for stack or stack_group.
    \f

    :param path: Path to execute the command on.
    :type path: str
    """
    context = SceptreContext(
        command_path=path,
        project_path=ctx.obj.get("project_path"),
        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)

    responses = [
        response for response in plan.describe_resources().values() if response
    ]

    write(responses, context.output_format)
Beispiel #4
0
def describe_policy(ctx, path):
    """
    Displays the stack policy used.
    \f

    :param path: Path to execute the command on.
    :type path: str
    """
    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"),
        no_colour=ctx.obj.get("no_colour"),
        ignore_dependencies=ctx.obj.get("ignore_dependencies"))

    plan = SceptrePlan(context)
    responses = plan.get_policy()
    for response in responses.values():
        write(response, context.output_format, context.no_colour)
Beispiel #5
0
def launch_command(ctx, path, yes):
    """
    Launch a Stack or StackGroup for a given config PATH.
    \f

    :param path: The path to launch. Can be a Stack or StackGroup.
    :type path: str
    :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"),
        user_variables=ctx.obj.get("user_variables"),
        options=ctx.obj.get("options"),
        ignore_dependencies=ctx.obj.get("ignore_dependencies"))

    plan = SceptrePlan(context)

    confirmation(plan.launch.__name__, yes, command_path=path)
    responses = plan.launch()
    exit(stack_status_exit_code(responses.values()))
Beispiel #6
0
def validate_command(ctx, path):
    """
    Validates the template.

    Validates the template used for stack in PATH.
    """
    context = SceptreContext(
                command_path=path,
                project_path=ctx.obj.get("project_path"),
                user_variables=ctx.obj.get("user_variables"),
                options=ctx.obj.get("options"),
                output_format=ctx.obj.get("output_format")
            )

    stack, _ = get_stack_or_stack_group(context)
    action = 'validate'
    plan = SceptrePlan(context, action, stack.template)
    response = plan.execute()

    if response['ResponseMetadata']['HTTPStatusCode'] == 200:
        del response['ResponseMetadata']
        click.echo("Template is valid. Template details:\n")
    write(response, context.output_format)
Beispiel #7
0
def list_outputs(ctx, path, export):
    """
    List outputs for stack.

    """
    context = SceptreContext(command_path=path,
                             project_path=ctx.obj.get("project_path"),
                             user_variables=ctx.obj.get("user_variables"),
                             options=ctx.obj.get("options"))

    stack, _ = get_stack_or_stack_group(context)
    action = 'describe_outputs'
    plan = SceptrePlan(context, action, stack)
    response = plan.execute()

    if export == "envvar":
        write("\n".join([
            "export SCEPTRE_{0}={1}".format(output["OutputKey"],
                                            output["OutputValue"])
            for output in response
        ]))
    else:
        write(response, context.output_format)
Beispiel #8
0
def step_impl(context, stack_group_name):
    sceptre_context = SceptreContext(
        command_path=stack_group_name,
        project_path=context.sceptre_dir
    )

    sceptre_plan = SceptrePlan(sceptre_context)
    responses = sceptre_plan.describe()

    stack_names = get_full_stack_names(context, stack_group_name)
    cfn_stacks = {}

    for response in responses.values():
        if response is None:
            continue
        for stack in response['Stacks']:
            cfn_stacks[stack['StackName']] = stack['StackStatus']

    context.response = [
        {short_name: cfn_stacks[full_name]}
        for short_name, full_name in stack_names.items()
        if cfn_stacks.get(full_name)
    ]
Beispiel #9
0
def drift_detect(ctx: Context, path: str):
    """
    Detect stack drift and return stack drift status.

    In the event that the stack does not exist, we return
    a DetectionStatus and StackDriftStatus of STACK_DOES_NOT_EXIST.

    In the event that drift detection times out, we return
    a DetectionStatus and StackDriftStatus of TIMED_OUT.

    The timeout is set at 5 minutes, a value that cannot be configured.
    """
    context = SceptreContext(
        command_path=path,
        project_path=ctx.obj.get("project_path"),
        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)
    responses = plan.drift_detect()

    output_format = "json" if context.output_format == "json" else "yaml"

    exit_status = 0
    for stack, response in responses.items():
        status = response["DetectionStatus"]
        if status in BAD_STATUSES:
            exit_status += 1
        for key in ["Timestamp", "ResponseMetadata"]:
            response.pop(key, None)
        write({stack.external_name: deserialize_json_properties(response)},
              output_format)

    exit(exit_status)
Beispiel #10
0
def execute_command(ctx, path, change_set_name, yes):
    """
    Executes a Change Set.

    :param path: Path to execute the command on.
    :type path: str
    :param change_set_name: Change Set to use.
    :type change_set_name: str
    :param yes: A flag to answer 'yes' too all CLI 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"))

    plan = SceptrePlan(context)
    confirmation(plan.execute_change_set.__name__,
                 yes,
                 change_set=change_set_name,
                 command_path=path)
    plan.execute_change_set(change_set_name)
Beispiel #11
0
def validate_command(ctx, path):
    """
    Validates the template.

    Validates the template used for stack in PATH.

    :param path: Path to execute the command on.
    :type path: str
    """
    context = SceptreContext(command_path=path,
                             project_path=ctx.obj.get("project_path"),
                             user_variables=ctx.obj.get("user_variables"),
                             options=ctx.obj.get("options"),
                             output_format=ctx.obj.get("output_format"))

    plan = SceptrePlan(context)
    responses = plan.validate()

    for stack, response in responses.items():
        if response['ResponseMetadata']['HTTPStatusCode'] == 200:
            del response['ResponseMetadata']
            click.echo("Template {} is valid. Template details:\n".format(
                stack.name))
        write(response, context.output_format)
Beispiel #12
0
def describe_change_set(ctx, path, change_set_name, verbose):
    """
    Describes the change set.

    :param path: Path to execute the command on.
    :type path: str
    :param change_set_name: Name of the Change Set to use.
    :type change_set_name: str
    :param verbose: A flag to display verbose output.
    :type verbose: 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"))

    plan = SceptrePlan(context)

    responses = plan.describe_change_set(change_set_name)
    for response in responses.values():
        description = response
        if not verbose:
            description = simplify_change_set_description(description)
        write(description, context.output_format)
Beispiel #13
0
 def setup_method(self, test_method, mock_check_valid_project_path):
     self.runner = CliRunner()
     self.test_project_path = os.path.join(os.getcwd(), "tests", "fixtures")
     self.context = SceptreContext(project_path=self.test_project_path,
                                   command_path="A")
Beispiel #14
0
def step_impl(context, stack_name):
    sceptre_context = SceptreContext(command_path=stack_name + '.yaml',
                                     project_path=context.sceptre_dir)

    sceptre_plan = SceptrePlan(sceptre_context)
    context.output = list(sceptre_plan.describe_resources().values())
Beispiel #15
0
def sceptre_context():
    return SceptreContext("/var/data/config",
                          "another/stack_b.yaml",
                          ignore_dependencies=False)
Beispiel #16
0
def step_impl(context, stack_group_name):
    sceptre_context = SceptreContext(command_path=stack_group_name,
                                     project_path=context.sceptre_dir)

    sceptre_plan = SceptrePlan(sceptre_context)
    sceptre_plan.delete()
Beispiel #17
0
def step_impl(context, stack_group_name):
    sceptre_context = SceptreContext(command_path=stack_group_name,
                                     project_path=context.sceptre_dir)

    sceptre_plan = SceptrePlan(sceptre_context)
    context.response = sceptre_plan.describe_resources().values()
def step_impl(context: Context, group):
    sceptre_context = SceptreContext(command_path=group,
                                     project_path=context.sceptre_dir)
    plan = SceptrePlan(sceptre_context)
    result = plan.validate()
    context.response = result
Beispiel #19
0
class TestSceptreContext:
    def setup_method(self, test_method):
        self.context = SceptreContext(project_path="project_path/to/sceptre",
                                      command_path="command/path",
                                      user_variables={},
                                      options={},
                                      output_format="json",
                                      no_colour=True,
                                      ignore_dependencies=False)

    def test_context_with_path(self):
        context = SceptreContext(
            project_path="project_path/to/sceptre",
            command_path="command-path",
            user_variables=sentinel.user_variables,
            options=sentinel.options,
            output_format=sentinel.output_format,
            no_colour=sentinel.no_colour,
            ignore_dependencies=sentinel.ignore_dependencies)

        sentinel.project_path = "project_path/to/sceptre"
        assert context.project_path == sentinel.project_path

    def test_full_config_path_returns_correct_path(self):
        context = SceptreContext(
            project_path="project_path",
            command_path="command-path",
            user_variables=sentinel.user_variables,
            options=sentinel.options,
            output_format=sentinel.output_format,
            no_colour=sentinel.no_colour,
            ignore_dependencies=sentinel.ignore_dependencies)

        full_config_path = path.join("project_path", self.context.config_path)
        assert context.full_config_path == full_config_path

    def test_full_command_path_returns_correct_path(self):
        context = SceptreContext(
            project_path="project_path",
            command_path="command",
            user_variables=sentinel.user_variables,
            options=sentinel.options,
            output_format=sentinel.output_format,
            no_colour=sentinel.no_colour,
            ignore_dependencies=sentinel.ignore_dependencies)
        full_command_path = path.join("project_path", self.context.config_path,
                                      "command")

        assert context.full_command_path == full_command_path

    def test_full_templates_path_returns_correct_path(self):
        context = SceptreContext(
            project_path="project_path",
            command_path="command",
            user_variables=sentinel.user_variables,
            options=sentinel.options,
            output_format=sentinel.output_format,
            no_colour=sentinel.no_colour,
            ignore_dependencies=sentinel.ignore_dependencies)
        full_templates_path = path.join("project_path",
                                        self.context.templates_path)
        assert context.full_templates_path == full_templates_path

    def test_context_repr(self):
        assert self.context.__repr__() == \
            "sceptre.context.SceptreContext(" \
            "project_path='project_path/to/sceptre', " \
            "command_path='command/path', " \
            "user_variables={}, "\
            "options={}, " \
            "output_format='json', " \
            "no_colour=True, " \
            "ignore_dependencies=False" \
            ")"

    def test_repr_can_eval_correctly(self):
        sceptre = importlib.import_module('sceptre')
        mock = importlib.import_module('unittest.mock')
        evaluated_context = eval(repr(self.context), {
            'sceptre': sceptre,
            'sentinel': mock.sentinel
        })
        assert isinstance(evaluated_context, SceptreContext)
        assert evaluated_context.__eq__(self.context)

    def test_context_hash(self):
        assert hash(self.context) == self.context.__hash__()

    def test_command_path_is_stack_with_valid_stack(self):
        self.context.project_path = "tests/fixtures"
        self.context.command_path = "account/stack-group/region/vpc.yaml"
        assert self.context.command_path_is_stack()

    def test_command_path_is_stack_with_directory(self):
        self.context.project_path = "tests/fixtures"
        self.context.command_path = "account/stack-group/region"
        assert self.context.command_path_is_stack() is False
Beispiel #20
0
 def test_config_reader_with_invalid_path(self):
     with pytest.raises(InvalidSceptreDirectoryError):
         ConfigReader(SceptreContext("/path/does/not/exist", "example"))
Beispiel #21
0
import os

from sceptre.context import SceptreContext
from sceptre.plan.plan import SceptrePlan

context = SceptreContext(os.path.abspath('cloud_formation'), 'dev/lambda.yaml')
plan = SceptrePlan(context)
plan.launch()
Beispiel #22
0
def step_impl(context, stack_group_name):
    sceptre_context = SceptreContext(command_path=stack_group_name,
                                     project_path=context.sceptre_dir)
    sceptre_plan = SceptrePlan(sceptre_context)
    values = sceptre_plan.drift_detect().values()
    context.output = list(values)
Beispiel #23
0
def diff_command(ctx: Context, differ: str, show_no_echo: bool, no_placeholders: bool, path: str):
    """Indicates the difference between the currently DEPLOYED stacks in the command path and
    the stacks configured in Sceptre right now. This command will compare both the templates as well
    as the subset of stack configurations that can be compared.

    Some settings (such as sceptre_user_data) are not available in a CloudFormation stack
    description, so the diff will not be indicated. Currently compared stack configurations are:

    \b
      * parameters
      * notifications
      * role_arn
      * stack_tags

    Important: There are resolvers (notably !stack_output, among others) that rely on other stacks
    to be already deployed when they are resolved. When producing a diff on Stack Configs that have
    such resolvers that point to non-deployed stacks, this presents a challenge, since this means
    those resolvers cannot be resolved. This particularly applies to stack parameters and when a
    stack's template uses sceptre_user_data with resolvers in it. In order to continue to be useful
    when producing a diff in these conditions, this command will do the following:

    1. If the resolver CAN be resolved, it will be resolved and the resolved value will be in the
    diff results.
    2. If the resolver CANNOT be resolved, it will be replaced with a string that represents the
    resolver and its arguments. For example: !stack_output my_stack.yaml::MyOutput will resolve in
    the parameters to "{ !StackOutput(my_stack.yaml::MyOutput) }".

    Particularly in cases where the replaced value doesn't work in the template as the template logic
    requires and causes an error, there is nothing further Sceptre can do and diffing will fail.
    """
    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"),
        output_format=ctx.obj.get('output_format'),
        no_colour=ctx.obj.get('no_colour')
    )
    output_format = context.output_format
    plan = SceptrePlan(context)

    if differ == "deepdiff":
        stack_differ = DeepDiffStackDiffer(show_no_echo)
        writer_class = DeepDiffWriter
    elif differ == 'difflib':
        stack_differ = DifflibStackDiffer(show_no_echo)
        writer_class = DiffLibWriter
    else:
        raise ValueError(f"Unexpected differ type: {differ}")

    execution_context = null_context() if no_placeholders else use_resolver_placeholders_on_error()
    with execution_context:
        diffs: Dict[Stack, StackDiff] = plan.diff(stack_differ)

    num_stacks_with_diff = output_diffs(diffs.values(), writer_class, sys.stdout, output_format)

    if num_stacks_with_diff:
        logger.warning(
            f"{num_stacks_with_diff} stacks with differences detected."
        )