Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Resolve #1318] Implement dump template and write output files #1325

Merged
merged 39 commits into from
May 14, 2023

Conversation

alex-harvey-z3q
Copy link
Contributor

@alex-harvey-z3q alex-harvey-z3q commented Apr 15, 2023

Description

Proposed implementation of #1318

This introduces a dump template command that behaves similarly to generate but also writes output docs to files.

The behaviour of dump config is changed here not to print multi-doc output to screen similar to dump config.

The write helper function is modified to optionally write to a file_path.

Writes files in a naming convention for dump config and dump template respectively:

f".dump/{stack_name}/config.yaml"
f".dump/{stack_name}/template.yaml"

Usage example

Dump config

% sceptre --merge-vars --dir=emr --var-file=/app/sceptre-environment/nonprod/datalake-nonprod/common-env.yaml --var-file=/app/sceptre-environment/common-env.yaml --var-file=/app/sceptre-environment/nonprod/datalake-nonprod/emr/streaming-nonprod-6100/cluster.yaml dump config emr.yaml > /dev/null

Dump template

% sceptre --merge-vars --dir=emr --var-file=/app/sceptre-environment/nonprod/datalake-nonprod/common-env.yaml --var-file=/app/sceptre-environment/common-env.yaml --var-file=/app/sceptre-environment/nonprod/datalake-nonprod/emr/streaming-nonprod-6100/cluster.yaml dump template emr.yaml > /dev/null

File structure created

% tree .dump/
.dump/
├── streaming-nonprod-6100-efs-pvt
│   ├── config.yaml
│   └── template.yaml
├── streaming-nonprod-6100-emr
│   ├── config.yaml
│   └── template.yaml
├── streaming-nonprod-6100-emr-profile
│   ├── config.yaml
│   └── template.yaml
└── streaming-nonprod-6100-emr-sg-pvt
    ├── config.yaml
    └── template.yaml

4 directories, 8 files

File content

% head .dump/streaming-nonprod-6100-emr/config.yaml 
---
dependencies:
- emr-profile.yaml
hooks:
  after_create:
  - !!python/object:hook.stack_termination_protection.StackTerminationProtection
    _argument: enabled
    _argument_is_resolved: false
    logger: &id001 !!python/object/apply:logging.getLogger
    - hook.stack_termination_protection
% head .dump/streaming-nonprod-6100-emr/template.yaml 
---
AWSTemplateFormatVersion: '2010-09-09'

Parameters:
  MasterInstanceType:
    Type: String
  CoreInstantType:
    Type: String
  CoreInstantCount:
    Type: String

PR Checklist

  • Wrote a good commit message & description [see guide below].
  • Commit message starts with [Resolve #issue-number].
  • Added/Updated unit tests.
  • Added/Updated integration tests (if applicable).
  • All unit tests (make test) are passing.
  • Used the same coding conventions as the rest of the project.
  • The new code passes pre-commit validations (pre-commit run --all-files).
  • The PR relates to only one subject with a clear title.
    and description in grammatically correct, complete sentences.

Approver/Reviewer Checklist

  • Before merge squash related commits.

Other Information

Guide to writing a good commit

In the event that the reader class is unable to parse the rendered
config, this adds logic to write the rendered config to a file to assist
the caller in understand what went wrong.
This adds a sceptre dump template command and deprecates sceptre
generate.
This reverts commit 3005b14.
This reverts commit acb399b.
@alex-harvey-z3q alex-harvey-z3q changed the title Alexharvey/1318 part 1 [Resolves #1318] Part 1 Apr 15, 2023
@alex-harvey-z3q alex-harvey-z3q changed the title [Resolves #1318] Part 1 [Resolve #1318] Part 1 Apr 15, 2023
sceptre/cli/dump.py Outdated Show resolved Hide resolved
@jfalkenstein
Copy link
Contributor

I feel like there must be a better way. Is there a way we can fix the generate command?

CONTRIBUTING.md Outdated Show resolved Hide resolved
@dboitnot
Copy link
Contributor

I feel like there must be a better way. Is there a way we can fix the generate command?

Maybe a flag like --dump or something to the generate sub-command?

@alex-harvey-z3q
Copy link
Contributor Author

alex-harvey-z3q commented Apr 17, 2023

I feel like there must be a better way. Is there a way we can fix the generate command?

@jfalkenstein Well if we fixed the generate command (we could copy this functionality there instead), we are then left with:

  1. A breaking change
  2. A seriously ugly inconsistency in the naming and behaviour between dump config and generate.

I think this is actually quite clean and a big improvement myself. (Not that I really care either way.)

@alex-harvey-z3q
Copy link
Contributor Author

I feel like there must be a better way. Is there a way we can fix the generate command?

Maybe a flag like --dump or something to the generate sub-command?

Yes, I assume we will probably make this behaviour optional via some sort of flag in the final version.

sceptre/cli/dump.py Outdated Show resolved Hide resolved
if template is None:
logger.warning(f"{stack.external_name} does not exist")
else:
output.append({stack.external_name: template})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why a list of dicts and not just one big dict?

Copy link
Contributor Author

@alex-harvey-z3q alex-harvey-z3q Apr 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, for consistency with dump config. I can't remember to be honest why we did it this way.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That feels a bit odd to me

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it may be to work around or hack the limitations of the write helper. If we need to change dump config, perhaps this should be looked at in a separate issue/PR?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My only concern is this: Let's say I need to pipe a template over to a linter or awscli for some reason because it has jinja and other stuff in it. I want to do something like: sceptre dump template my/sceptre/config.yaml | cfn-lint -. When you're outputting the templates inside a larger data structure like this, that's not a valid template.

I understand your concern of wanting to be able to associate the template with a stack, so there are a few options I can think of:

Option 1: Rather than this, you could output the stack name via a logger rather than echoing it. That will result it going to stderr rather than stdout. That way, if you pipe output to another command or use >, it won't actually get included. So you could alternate by logging the stack name and then writing the output.

Option 2: Have a --stack-names flag that optionally makes it output this way but by default it does not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jfalkenstein you are misunderstanding the implementation and behaviour. Here's a demo, showing a yaml stream that can be parsed by external tools is always emitted, even in the case of multiple stacks:

Screen Shot 2023-04-21 at 8 20 03 pm

venv.sh Outdated Show resolved Hide resolved
Copy link
Contributor

@jfalkenstein jfalkenstein left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'm just very concerned about adding a completely new command that is ALMOST identical to the old command except it outputs in a slightly different format. I really don't think this is the right way to proceed.

@alex-harvey-z3q
Copy link
Contributor Author

I know you won't like this, but generate has integration tests and I believe that we should have integration tests on these dump commands as well.

I've refactored the generate test to instead call dump_template. As for the other dump commands, they are on a different branch so will have to go in different PRs and this one needs to be merged first.

@alex-harvey-z3q
Copy link
Contributor Author

@jfalkenstein have a look now. Here's what I changed:

  • implemented --to-file making the default behaviour not to create the dump files.
  • refactored the process files logic you didn't like moving it all back the dump commands.

@alex-harvey-z3q alex-harvey-z3q dismissed stale reviews from jfalkenstein and zaro0508 May 2, 2023 09:23

changes done

@@ -18,9 +22,12 @@ def dump_group():

@dump_group.command(name="config")
@click.argument("path")
@click.option(
"--to-file", is_flag=True, help="If True, also dump the template to a local file."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very minor thing, but this says "also", but it appears as if dumping is now either to file or to console, but not both.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind. I see what we're doing now.

@@ -93,6 +102,13 @@ def write(var, output_format="json", no_colour=True):

click.echo(output)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it odd that we still echo if a file_path is specified.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok how about now? (I'm not sure whether people want the text to go to both the screen and file if file_path is specified).

@jfalkenstein
Copy link
Contributor

Running integration tests now.

Copy link
Contributor

@zaro0508 zaro0508 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generate is found in a few locations in the docs. if we are deprecating that command in this same PR then could we also update to dump in the docs as well?

I think it might be cleaner to deprecate the generate command in a follow on PR.


@dump_group.command(name="all")
@click.argument("path")
@click.option(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is missing the --to-file option. is this intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not intentional, fixed.

@alex-harvey-z3q
Copy link
Contributor Author

generate is found in a few locations in the docs. if we are deprecating that command in this same PR then could we also update to dump in the docs as well?

I think it might be cleaner to deprecate the generate command in a follow on PR.

A few hits on the word when I grep -rw generate, however those are not hits on the subcommand. Are you sure?

@zaro0508
Copy link
Contributor

zaro0508 commented May 8, 2023

A few hits on the word when I grep -rw generate, however those are not hits on the subcommand. Are you sure?

This is what i see

docs/_source/docs/hooks.rst:``before_generate`` or ``after_generate`` - run hook before or after generating stack template.
docs/_source/docs/resolvers.rst:  ``!stack_output other_stack.yaml::OutputName`` and you run the ``dump template`` command, the generated
docs/_source/docs/templates.rst:to generate CloudFormation Template as a `json` string.
docs/_source/docs/templates.rst:  To generate templates using Troposphere you must install the
docs/_source/docs/templates.rst:AWS CDK can be used to programmatically generate templates for your stacks and then Sceptre can

I think those references should be changed to the dump command

Also didn't we decide to alias the generate to the dump command? if so, it looks like it wasn't done in template.py

sceptre/cli/template.py:@click.command(name="generate", short_help="Prints the template.")
sceptre/cli/template.py:def generate_command(ctx, no_placeholders, path):

@alex-harvey-z3q
Copy link
Contributor Author

This is what i see

docs/_source/docs/hooks.rst:``before_generate`` or ``after_generate`` - run hook before or after generating stack template.
docs/_source/docs/resolvers.rst:  ``!stack_output other_stack.yaml::OutputName`` and you run the ``dump template`` command, the generated
docs/_source/docs/templates.rst:to generate CloudFormation Template as a `json` string.
docs/_source/docs/templates.rst:  To generate templates using Troposphere you must install the
docs/_source/docs/templates.rst:AWS CDK can be used to programmatically generate templates for your stacks and then Sceptre can

I think those references should be changed to the dump command

@zaro0508 I didn't actually know about the before_generate and after_generate hooks but I don't see how those can be renamed. before_dump_template is both an ugly name and does not make sense in that context. It would have to stay as before_generate I think. Remember, it doesn't mean "before you run the generate command" ; it means "before Sceptre generates its template". Generating the template internally, and dumping it out for the caller to look at, are different things.

@alex-harvey-z3q
Copy link
Contributor Author

Also didn't we decide to alias the generate to the dump command? if so, it looks like it wasn't done in template.py

sceptre/cli/template.py:@click.command(name="generate", short_help="Prints the template.")
sceptre/cli/template.py:def generate_command(ctx, no_placeholders, path):

Yes but it was aliased not in the CLI but in the API which is I think the way it should be.

@zaro0508
Copy link
Contributor

zaro0508 commented May 9, 2023

Yes but it was aliased not in the CLI but in the API which is I think the way it should be.

What is your reasoning for not aliasing it in the CLI as well?

@alex-harvey-z3q
Copy link
Contributor Author

alex-harvey-z3q commented May 9, 2023

Yes but it was aliased not in the CLI but in the API which is I think the way it should be.

What is your reasoning for not aliasing it in the CLI as well?

Well, aliasing in both places will just result in unused code paths. If I point the generate CLI command at the dump_template API, why not just remove the generate API since it is no longer used?

In the end I don't really mind how it is done or necessarily see the point in aliasing in the first place. The implementation above does have the advantage that it seems to be the one that @jfalkenstein agreed to and not to mention that it's the one that I already implemented!

@zaro0508 zaro0508 merged commit dcae1a9 into Sceptre:master May 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants