Example #1
0
def generate_command(ctx, no_placeholders, path):
    """
    Prints the template used for stack in PATH.
    \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)

    execution_context = null_context(
    ) if no_placeholders else use_resolver_placeholders_on_error()
    with execution_context:
        responses = plan.generate()

    output = [template for template in responses.values()]
    write(output, context.output_format)
Example #2
0
def validate_command(ctx, no_placeholders, path):
    """
    Validates the template used for stack in PATH.
    \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)

    execution_context = null_context(
    ) if no_placeholders else use_resolver_placeholders_on_error()
    with execution_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)
Example #3
0
    def test_get__resolver_raises_recursive_resolve__placeholders_allowed__raises_error(
            self):
        class RecursiveResolver(Resolver):
            def resolve(self):
                raise RecursiveResolve()

        resolver = RecursiveResolver()
        self.mock_object.resolvable_value_property = resolver
        with use_resolver_placeholders_on_error(), pytest.raises(
                RecursiveResolve):
            self.mock_object.resolvable_value_property
Example #4
0
    def test_create_placeholder_value(self, placeholder_type, argument,
                                      expected):
        class MyResolver(Resolver):
            def resolve(self):
                pass

        resolver = MyResolver(argument)

        with use_resolver_placeholders_on_error():
            result = create_placeholder_value(resolver, placeholder_type)

        assert result == expected
Example #5
0
    def test_get__resolver_raises_error__placeholders_allowed__alternate_placeholder_type__uses_alternate_type(
            self):
        class ErroringResolver(Resolver):
            def resolve(self):
                raise ValueError()

        resolver = ErroringResolver()
        self.mock_object.value_with_none_placeholder = resolver
        with use_resolver_placeholders_on_error():
            result = self.mock_object.value_with_none_placeholder

        assert result == create_placeholder_value(resolver,
                                                  PlaceholderType.none)
Example #6
0
    def test_get__resolver_raises_error__placeholders_allowed__returns_placeholder(
            self):
        class ErroringResolver(Resolver):
            def resolve(self):
                raise ValueError()

        resolver = ErroringResolver()
        self.mock_object.resolvable_value_property = resolver
        with use_resolver_placeholders_on_error():
            result = self.mock_object.resolvable_value_property

        assert result == create_placeholder_value(resolver,
                                                  PlaceholderType.explicit)
Example #7
0
    def test_get__resolver_raises_error__placeholders_allowed__alternate_placeholder_type__uses_alternate(
            self):
        class ErroringResolver(Resolver):
            def resolve(self):
                raise ValueError()

        resolver = ErroringResolver()
        self.mock_object.container_with_alphanum_placeholder = {
            'resolver': resolver
        }
        with use_resolver_placeholders_on_error():
            result = self.mock_object.container_with_alphanum_placeholder

        assert result == {
            'resolver':
            create_placeholder_value(resolver, PlaceholderType.alphanum)
        }
Example #8
0
    def test_are_placeholders_enabled__error_in_placeholder_context__returns_false(
            self):
        with pytest.raises(ValueError), use_resolver_placeholders_on_error():
            raise ValueError()

        assert are_placeholders_enabled() is False
Example #9
0
    def test_are_placeholders_enabled__out_of_placeholder_context__returns_false(
            self):
        with use_resolver_placeholders_on_error():
            pass

        assert are_placeholders_enabled() is False
Example #10
0
 def test_are_placeholders_enabled__in_placeholder_context__returns_true(
         self):
     with use_resolver_placeholders_on_error():
         assert are_placeholders_enabled() is True
Example #11
0
def step_impl(context: Context):
    placeholder_context = use_resolver_placeholders_on_error()
    placeholder_context.__enter__()
    context.add_cleanup(exit_placeholder_context, placeholder_context)
Example #12
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."
        )