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

chore(core): Stages #8423

Merged
merged 7 commits into from
Jun 8, 2020
Merged

chore(core): Stages #8423

merged 7 commits into from
Jun 8, 2020

Conversation

eladb
Copy link
Contributor

@eladb eladb commented Jun 7, 2020

Stages are self-contained application units that synthesize as a cloud assembly. This change centralizes prepare + synthesis logic into the stage level and changes App to extend Stage.

Once stage.synth() is called, the stage becomes (practically) immutable. This means that subsequent synths will return the same output.

The cloud assembly produced by stages is nested as an artifact inside another cloud assembly (either the App's top-level assembly) or a child.

Authors: @rix0rrr, @eladb


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

Stages synthesize to embedded Cloud Assemblies.

Ideally there should be CLI support for embedded Cloud Assemblies, but there isn't yet. It will be coming soon, I promise.

To implement this, had to grab the reins of synthesis back from the constructs library. I've taken the liberty to declare synthesis in constructs deprecated.

Took the opportunity where we're declaring a new type of construct in the construct hierarchy to clean up the default stack name generation (get rid of the hashes and add a prefix, which will make deploying multiple Stages in the same environment just naturally work out nicely in a non-ugly way).

Started to write a section in the README on Stacks and Stages, but I couldn't figure out how to write about the use for Stages without referencing unreleased things, so I gave up. For the same reason, made this a chore as there is no user value right now so why would this show up in
the CHANGELOG?

Also moved the "artifacts" classes in cx-api together to unclutter the file structure.

Primary author: @rix0rrr
@eladb eladb requested a review from rix0rrr June 7, 2020 18:04
@mergify mergify bot added the contribution/core This is a PR that came from AWS. label Jun 7, 2020
so we can now revert changes to test.stack.ts and stack.prepare
@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildProject6AEA49D1-qxepHUsryhcu
  • Commit ID: 4c70ed0
  • Result: FAILED
  • Build Logs (available for 30 days)

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

@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

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

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

Elad Ben-Israel added 3 commits June 7, 2020 21:53
The name is weak and it does not add additional value above the "Stage" concept.
It should not be possible to specify the output directory for a nested stage, only for apps.

Also, make assemblyBuilder internal. It is only needed from the private "synthesize.ts" module (and the reason it is a separate module is for backwards compat. in an ideal world synthesis will be implemented the same file).

There is no need for "addToParentAssembly" because we already do that when we create the nested assembly.
@eladb eladb changed the title chore(core): add Stage class chore(core): Stages Jun 7, 2020
@eladb eladb requested a review from iliapolo June 7, 2020 19:23
@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

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

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

@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

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

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

@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

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

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

@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildProject6AEA49D1-qxepHUsryhcu
  • Commit ID: 9e69886
  • 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 Jun 8, 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 f5ebacd into master Jun 8, 2020
@mergify mergify bot deleted the benisrae/stage-construct-2 branch June 8, 2020 08:53
mergify bot pushed a commit that referenced this pull request Aug 3, 2020
### Updated PR

Since we introduced [`stages`](#8423) which had the unintended side effect of the CDK not supporting adding an Aspect via another Aspect, we have not seen any issues reported beside #8536, that was resolved without requiring this capability.
Given that, and the fact this features has many sharp edges we decided to leave it unsupported, and add a warning in the meantime. 

-----------

Following up on #8536

If an aspect is added via another aspect, the inner aspect  will  not be invoked. Take for example this code:

```typescript
const app = new cdk.App();

app.node.applyAspect({
  visit(construct: cdk.IConstruct) {
    construct.node.applyAspect({
      visit(construct: cdk.IConstruct) {
        console.info("Invoking aspect on construct: " + construct.node.id);  // This will not be called
      }
    })
  }
});
```

Since aspects are added only on the top level node,  if an aspect is added while `InvokeAspects` is called on that node,  it will be ignored since it will not be added to list of aspects to invoke (`allAspectsHere` in the bellow code):
```typescript
function invokeAspects(root: IConstruct) {
  recurse(root, []);

  function recurse(construct: IConstruct, inheritedAspects: constructs.IAspect[]) {
    // hackery to be able to access some private members with strong types (yack!)
    const node: NodeWithAspectPrivatesHangingOut = construct.node._actualNode as any;

    const allAspectsHere = [...inheritedAspects ?? [], ...node._aspects];

    for (const aspect of allAspectsHere) {
      if (node.invokedAspects.includes(aspect)) { continue; }

      aspect.visit(construct); <-- an aspect that was added here will not be added to `allAspectsHere` and will be ignored

      node.invokedAspects.push(aspect);
    }

    for (const child of construct.node.children) {
      if (!Stage.isStage(child)) {
        recurse(child, allAspectsHere);
      }
    }
  }
}
 
```

Assuming this is not something we want to support**, we can detect it by comparing the size of `node._aspects` before and after the call to `aspect.visit`, and emit a warning if there has been a change. Note that while the aspect will not be invoked it will be added to every child construct during the recursive visit. Emitting a warning for each child construct will result in a noisy console, to prevent this I have added a flag that will only allow adding **one warning per application**, given this limitation I'm not sure  there is a lot of value in adding the warning, thoughts?
 
If we decide to add it I will add tests.



 (** theoretically we could support it by adding the aspects to `allAspectsHere`  during the loop, but this will require a non trivial implementation in order to avoid infinite recursion) 



----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
eladb pushed a commit that referenced this pull request Aug 10, 2020
### Updated PR

Since we introduced [`stages`](#8423) which had the unintended side effect of the CDK not supporting adding an Aspect via another Aspect, we have not seen any issues reported beside #8536, that was resolved without requiring this capability.
Given that, and the fact this features has many sharp edges we decided to leave it unsupported, and add a warning in the meantime. 

-----------

Following up on #8536

If an aspect is added via another aspect, the inner aspect  will  not be invoked. Take for example this code:

```typescript
const app = new cdk.App();

app.node.applyAspect({
  visit(construct: cdk.IConstruct) {
    construct.node.applyAspect({
      visit(construct: cdk.IConstruct) {
        console.info("Invoking aspect on construct: " + construct.node.id);  // This will not be called
      }
    })
  }
});
```

Since aspects are added only on the top level node,  if an aspect is added while `InvokeAspects` is called on that node,  it will be ignored since it will not be added to list of aspects to invoke (`allAspectsHere` in the bellow code):
```typescript
function invokeAspects(root: IConstruct) {
  recurse(root, []);

  function recurse(construct: IConstruct, inheritedAspects: constructs.IAspect[]) {
    // hackery to be able to access some private members with strong types (yack!)
    const node: NodeWithAspectPrivatesHangingOut = construct.node._actualNode as any;

    const allAspectsHere = [...inheritedAspects ?? [], ...node._aspects];

    for (const aspect of allAspectsHere) {
      if (node.invokedAspects.includes(aspect)) { continue; }

      aspect.visit(construct); <-- an aspect that was added here will not be added to `allAspectsHere` and will be ignored

      node.invokedAspects.push(aspect);
    }

    for (const child of construct.node.children) {
      if (!Stage.isStage(child)) {
        recurse(child, allAspectsHere);
      }
    }
  }
}
 
```

Assuming this is not something we want to support**, we can detect it by comparing the size of `node._aspects` before and after the call to `aspect.visit`, and emit a warning if there has been a change. Note that while the aspect will not be invoked it will be added to every child construct during the recursive visit. Emitting a warning for each child construct will result in a noisy console, to prevent this I have added a flag that will only allow adding **one warning per application**, given this limitation I'm not sure  there is a lot of value in adding the warning, thoughts?
 
If we decide to add it I will add tests.



 (** theoretically we could support it by adding the aspects to `allAspectsHere`  during the loop, but this will require a non trivial implementation in order to avoid infinite recursion) 



----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
curtiseppel pushed a commit to curtiseppel/aws-cdk that referenced this pull request Aug 11, 2020
### Updated PR

Since we introduced [`stages`](aws#8423) which had the unintended side effect of the CDK not supporting adding an Aspect via another Aspect, we have not seen any issues reported beside aws#8536, that was resolved without requiring this capability.
Given that, and the fact this features has many sharp edges we decided to leave it unsupported, and add a warning in the meantime. 

-----------

Following up on aws#8536

If an aspect is added via another aspect, the inner aspect  will  not be invoked. Take for example this code:

```typescript
const app = new cdk.App();

app.node.applyAspect({
  visit(construct: cdk.IConstruct) {
    construct.node.applyAspect({
      visit(construct: cdk.IConstruct) {
        console.info("Invoking aspect on construct: " + construct.node.id);  // This will not be called
      }
    })
  }
});
```

Since aspects are added only on the top level node,  if an aspect is added while `InvokeAspects` is called on that node,  it will be ignored since it will not be added to list of aspects to invoke (`allAspectsHere` in the bellow code):
```typescript
function invokeAspects(root: IConstruct) {
  recurse(root, []);

  function recurse(construct: IConstruct, inheritedAspects: constructs.IAspect[]) {
    // hackery to be able to access some private members with strong types (yack!)
    const node: NodeWithAspectPrivatesHangingOut = construct.node._actualNode as any;

    const allAspectsHere = [...inheritedAspects ?? [], ...node._aspects];

    for (const aspect of allAspectsHere) {
      if (node.invokedAspects.includes(aspect)) { continue; }

      aspect.visit(construct); <-- an aspect that was added here will not be added to `allAspectsHere` and will be ignored

      node.invokedAspects.push(aspect);
    }

    for (const child of construct.node.children) {
      if (!Stage.isStage(child)) {
        recurse(child, allAspectsHere);
      }
    }
  }
}
 
```

Assuming this is not something we want to support**, we can detect it by comparing the size of `node._aspects` before and after the call to `aspect.visit`, and emit a warning if there has been a change. Note that while the aspect will not be invoked it will be added to every child construct during the recursive visit. Emitting a warning for each child construct will result in a noisy console, to prevent this I have added a flag that will only allow adding **one warning per application**, given this limitation I'm not sure  there is a lot of value in adding the warning, thoughts?
 
If we decide to add it I will add tests.



 (** theoretically we could support it by adding the aspects to `allAspectsHere`  during the loop, but this will require a non trivial implementation in order to avoid infinite recursion) 



----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
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