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

fix(core): write Metadata resource in core framework #10306

Merged
merged 18 commits into from
Sep 28, 2020

Conversation

rix0rrr
Copy link
Contributor

@rix0rrr rix0rrr commented Sep 11, 2020

The Metadata resource used to be added by the CLI, which led to a bug. The better, less error-prone way to do it is to have the framework add the metadata resource to the stack template upon synthesis.

The resources need to be added just-in-time (before synthesis), because if we do it in the constructor node.setContext() will stop working (for the Stack already having children).

We only add the Metadata resource if we're running via the CLI. If we did not do this, all unit tests everywhere that use toMatchTemplate()/toExactlyMatchTemplate()/toMatch() will break. There are hundreds alone in our codebase, nevermind however many other ones are out there. The consequences of this are that we [still] will not record users who are doing in-memory synthesis.

The CLI only does the work when the runtimeInfo field of the assembly is filled, which we just never do anymore. However, the code cannot be removed from the CLI because old versions of the framework might still set that field and expect the resource to be added to the template.


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

The CDK Metadata Resource is added by the CLI, and only added
to the in-memory representation of the template.

This in-memory representation is only used in the `CreateChangeSet`
call if the full template body is <=50kB.

If the template is larger than this size, the template file that's on
disk will be uploaded to the bootstrap S3 bucket and referenced.
However, that template will not have had the metadata resource
injected and so the stack will not be registered.

This PR:

- Provisionally fixes this issue by flushing the in-memory modifications
  back out to disk.
- Also adds the metadata resources to stacks found in nested Cloud
  Assemblies, such as the stacks deployed via CDK Pipelines.

There is some jank around new-style synthesis stacks: the protocol
specifies that those stacks have synthesized their templates as assets,
and those will not (necessarily) be processed by the CLI, although
it might coincidentally work if the files are the same.

The proper fix to this whole mess is to have the framework inject the
metadata resource at synthesis time. That fix is forthcoming, but this
current one is a good stopgap until that time.
@rix0rrr rix0rrr requested review from njlynch, nija-at and a team September 11, 2020 07:56
@rix0rrr rix0rrr self-assigned this Sep 11, 2020
@mergify mergify bot added the contribution/core This is a PR that came from AWS. label Sep 11, 2020
Copy link
Contributor

@njlynch njlynch left a comment

Choose a reason for hiding this comment

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

Should we update this comment to point to this new code?

// @deprecated(v2): remove this 'if' block and all code referenced by it.
// This should honestly not be done here. The framework
// should (and will, shortly) synthesize this information directly into
// the template. However, in order to support old framework versions
// that don't synthesize this info yet, we can only remove this code
// once we break backwards compatibility.

packages/@aws-cdk/core/lib/private/metadata-resource.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/core/test/test.app.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/core/test/util.ts Outdated Show resolved Hide resolved
if (!Stack.isStack(construct)
|| construct.parentStack
// Unless disabled
|| construct.node.tryGetContext(cxapi.DISABLE_VERSION_REPORTING)
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be a property of Stack such as stack.versionReportingEnabled which will take into account context and the nested stack posture instead of leaking the fact that this can he set through context?

Copy link
Contributor

Choose a reason for hiding this comment

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

I was also thinking that this should be an opt-in switch ("enable") and not opt-out ("disable"). This way, we (and our users) won't need to fix all their unit tests because the metadata resource will only be attached if the CLI sets that context flag.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We could do that, but since we already have an existing opt-out flag: DISABLE_VERSION_REPORTING (which we need to support for backwards compatibility anyway) I didn't really want to add another ENABLE_VERSION_REPORTING flag as well.

The Stack property probably makes sense although it would need to be exposed as a public property or a (ew!) public @internal one so that this function external to the class can use it.

It fights with the App's { runtimeInfo?: @default true } property as well...

Copy link
Contributor

Choose a reason for hiding this comment

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

DISABLE_VERSION_REPORTING is not really public API, so I would recommend removing it in favor of ENABLE_VERSION_REPORTING and deprecate runtimeInfo in favor of versionReporting (in props and at the Stack level as public API.

// Unless disabled
|| construct.node.tryGetContext(cxapi.DISABLE_VERSION_REPORTING)
// While running via CLI
|| !process.env[cxapi.CLI_VERSION_ENV]) { return; }
Copy link
Contributor

Choose a reason for hiding this comment

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

Why?

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 believe I described that twice.

Copy link
Contributor

Choose a reason for hiding this comment

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

Won't it make sense to just not include the CLI version in case this environment variable in not defined?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's not actually about the CLI_VERSION_ENV itself. I'm using CLI_VERSION_ENV as a trigger to determine whether we're running under the CLI (and hence emitting the metadata)

// Because of https://github.com/aws/aws-cdk/blob/master/packages/@aws-cdk/assert/lib/synth-utils.ts#L74
// synthesize() may be called more than once on a stack in unit tests, and the below would break
// if we execute it a second time. Guard against the constructs already existing.
if (construct.node.tryFindChild('CDKMetadata')) { return; }
Copy link
Contributor

Choose a reason for hiding this comment

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

Make 'CDKMetadata' a const

@@ -369,6 +369,8 @@ export interface AssemblyBuildOptions {
/**
* Include the specified runtime information (module versions) in manifest.
* @default - if this option is not specified, runtime info will not be included
* @deprecated All template modifications that should result from this should
* have already been inserted into the template.
*/
readonly runtimeInfo?: RuntimeInfo;
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we really want to continue to emit this info into the assembly? I think this should now be always undefined

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. But I don't think we can remove it from this API due to backwards compatibility guarantees.

Copy link
Contributor

@eladb eladb left a comment

Choose a reason for hiding this comment

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

Let's try to clean up all the flags and switches and stuff. I don't think that's going to be a major breaking change

@rix0rrr
Copy link
Contributor Author

rix0rrr commented Sep 22, 2020

Let's try to clean up all the flags and switches and stuff. I don't think that's going to be a major breaking change

Nevertheless, we're going to have to break the cx-api protocol version for this, because we're flipping a default.

If we don't break the protocol version, people will be free to use an old CLI with the new framework. The old CLI won't emit DISABLE_VERSION_REPORTING (because the default is true), and the framework won't see ENABLE_VERSION_REPORTING (because the default is false) and not do anything.

@rix0rrr rix0rrr requested review from eladb, njlynch and a team September 22, 2020 09:14
Copy link
Contributor

@njlynch njlynch left a comment

Choose a reason for hiding this comment

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

Looks good to me, minus some docstring changes.

packages/@aws-cdk/core/lib/app.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/core/lib/stack.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/cx-api/lib/app.ts Outdated Show resolved Hide resolved
rix0rrr and others added 3 commits September 22, 2020 12:58
Co-authored-by: Nick Lynch <nlynch@amazon.com>
Co-authored-by: Nick Lynch <nlynch@amazon.com>
Co-authored-by: Nick Lynch <nlynch@amazon.com>
@rix0rrr
Copy link
Contributor Author

rix0rrr commented Sep 22, 2020

Thanks @njlynch. Waiting for @eladb to weigh in on the protocol change as well

Copy link
Contributor

@eladb eladb left a comment

Choose a reason for hiding this comment

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

Looks good. See a few questions/clarifications

*
* @default Value of 'aws:cdk:version-reporting' context key
*/
readonly versionReporting?: boolean;
Copy link
Contributor

Choose a reason for hiding this comment

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

I am wondering if the correct terminology should be analytics: boolean--broaden the scope a little bit.

const CDKMetadata = 'CDKMetadata';
if (construct.node.tryFindChild(CDKMetadata)) { return; }

new MetadataResource(construct, CDKMetadata);
Copy link
Contributor

Choose a reason for hiding this comment

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

Remind me what's the rationale for not just adding this in the Stack's constructor based on the prop?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can't set context anymore

Copy link
Contributor

Choose a reason for hiding this comment

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

And why do we need to set context? My view is that the context is just used to determine the default for analyticsReporting when new stacks are created. From that point forward we shouldn't care about the context key, no?

}
if (versionReporting) { context[cxapi.VERSION_REPORTING_ENABLED_CONTEXT] = true; }
// We need to keep on doing this for framework version from before this flag was deprecated.
if (!versionReporting) { context[cxapi.DISABLE_VERSION_REPORTING] = true; }
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if we can remove this constant from cxapi and just plug the explicit value here for backwards compat

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh please yes

@eladb eladb added the pr/do-not-merge This PR should not be merged at this time. label Sep 28, 2020
@eladb
Copy link
Contributor

eladb commented Sep 28, 2020

Added do not merge

@rix0rrr rix0rrr removed the pr/do-not-merge This PR should not be merged at this time. label Sep 28, 2020
@rix0rrr rix0rrr changed the title fix(core): add Metadata resource in core framework fix(core): write Metadata resource in core framework Sep 28, 2020
@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildProject6AEA49D1-qxepHUsryhcu
  • Commit ID: a3fc956
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@mergify
Copy link
Contributor

mergify bot commented Sep 28, 2020

Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

@mergify mergify bot merged commit fb39803 into master Sep 28, 2020
@mergify mergify bot deleted the huijbers/metadata-in-framework2 branch September 28, 2020 16:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contribution/core This is a PR that came from AWS.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants