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

(cdk pipelines): primary output directory root/cdk.out generates errors since notices release #19234

Open
gbvanrenswoude opened this issue Mar 4, 2022 · 14 comments
Labels
@aws-cdk/pipelines CDK Pipelines library bug This issue is a bug. needs-reproduction This issue needs reproduction. p1 p2

Comments

@gbvanrenswoude
Copy link

What is the problem?

We observe in the default cdk pipeline:

Failed to load notices from cache: Error: ENOENT: no such file or directory, open '/root/.cdk/cache/notices.json'
Error on request: Error: read ETIMEDOUT
Notices refreshed
Error on request: Error: read ETIMEDOUT
Failed to get tree.json file: Error: cdk.out/tree.json: ENOTDIR: not a directory, open 'cdk.out/tree.json'

Note, we have the cdk root of our project in /infrastructure folder. That is specified in code:

primaryOutputDirectory: "infrastructure/cdk.out",

It does not result in error, just in a very long wait and then succesful exit.

Reproduction Steps

    const pipeline = new pipelines.CodePipeline(
      this,
      "niceName",
      {
        pipelineName: "niceName",
        crossAccountKeys: true,
        synth: new pipelines.CodeBuildStep("SynthStep", {
          input: remote,
          commands: [
            "cd infrastructure",
            "npm ci",
            "npm run test",
            "npm run build",
            "npx cdk synth",
          ],
          primaryOutputDirectory: "infrastructure/cdk.out",
        }),
        codeBuildDefaults: {
          vpc: <...>,
          subnetSelection: { subnets: <...> },
          partialBuildSpec: codebuild.BuildSpec.fromObject({
            phases: {
              install: {
                "runtime-versions": {
                  nodejs: "14.x",
                },
              },
              pre_build: {
                commands: ["n 16"],
              },
            },
          }),
          rolePolicy: [
            new iam.PolicyStatement({
              actions: ["<...>:<...>"],
              resources: ["<...>"],
            }),
          ],
        },
      }
    );

What did you expect to happen?

Pipeline result:

Time taken 30s blahblah :D

What actually happened?

Failed to load notices from cache: Error: ENOENT: no such file or directory, open '/root/.cdk/cache/notices.json'
Error on request: Error: read ETIMEDOUT
Notices refreshed
Error on request: Error: read ETIMEDOUT
Failed to get tree.json file: Error: cdk.out/tree.json: ENOTDIR: not a directory, open 'cdk.out/tree.json'

CDK CLI Version

2.13.0

Framework Version

No response

Node.js Version

17

OS

MacOs

Language

Typescript

Language Version

TS 4

Other information

No response

@gbvanrenswoude gbvanrenswoude added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Mar 4, 2022
@github-actions github-actions bot added the @aws-cdk/pipelines CDK Pipelines library label Mar 4, 2022
@NGL321 NGL321 added needs-reproduction This issue needs reproduction. p1 and removed needs-triage This issue or PR still needs to be triaged. labels Mar 4, 2022
@NGL321 NGL321 changed the title (cdk pipelines): short issue description (cdk pipelines): primary output directory root/cdk.out generates errors Mar 4, 2022
@NGL321
Copy link
Contributor

NGL321 commented Mar 4, 2022

Hey @gbvanrenswoude,

Just to confirm the nature of this report. You are getting error alerts in the output but the stack builds successfully, correct?
Considering that I was wondering if you observed this behavior just for root/cdk.out or if it persists with a different output directory?

@NGL321 NGL321 added the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Mar 4, 2022
@gbvanrenswoude
Copy link
Author

gbvanrenswoude commented Mar 4, 2022

Hey @gbvanrenswoude,

Just to confirm the nature of this report. You are getting error alerts in the output but the stack builds successfully, correct? Considering that I was wondering if you observed this behavior just for root/cdk.out or if it persists with a different output directory?

The stack indeeds builds correctly. We have done the cdk init in /infrastructure folder. cdk.out is located in <project root>/infrastructure/cdk.out. All of the CDK pipeline runs succesfully as well, it just waits very long in the UpdatePipeline step.

image

image

@github-actions github-actions bot removed the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Mar 5, 2022
@byongwu
Copy link

byongwu commented Mar 11, 2022

Hi. I would like to share how I resolved the problem similar to this.

I had a similar issue like this but in my case, it failed at "UpdatePipeline" stage.
This was my error log.

Toolkit stack: CDKToolkit
Setting "CDK_DEFAULT_REGION" environment variable to ap-northeast-2
Resolving default credentials
Looking up default account ID from STS
Failed to store notices in the cache: Error: ENOENT: no such file or directory, open '/root/.cdk/cache/notices.json'
Notices refreshed
Default account ID: 065121827172
Setting "CDK_DEFAULT_ACCOUNT" environment variable to 065121827172
context: {
  'aws:cdk:enable-path-metadata': true,
  'aws:cdk:enable-asset-metadata': true,
  'aws:cdk:version-reporting': true,
  'aws:cdk:bundling-stacks': [ '*' ]
}
--app points to a cloud assembly, so we bypass synth
Failed to get tree.json file: Error: cdk.out/tree.json: ENOTDIR: not a directory, open 'cdk.out/tree.json'

No stacks match the name(s) CdkStackPipeline-sf-common
Error: No stacks match the name(s) CdkStackPipeline-sf-common
    at CdkToolkit.validateStacksSelected (/usr/local/lib/node_modules/aws-cdk/lib/cdk-toolkit.ts:578:13)
    at CdkToolkit.selectStacksForDeploy (/usr/local/lib/node_modules/aws-cdk/lib/cdk-toolkit.ts:525:10)
    at CdkToolkit.deploy (/usr/local/lib/node_modules/aws-cdk/lib/cdk-toolkit.ts:130:20)
    at initCommandLine (/usr/local/lib/node_modules/aws-cdk/lib/cli.ts:310:12)

[Container] 2022/03/10 09:48:26 Command did not exit successfully cdk -a . deploy CdkStackPipeline-sf-common --require-approval=never --verbose exit status 1
[Container] 2022/03/10 09:48:26 Phase complete: BUILD State: FAILED
[Container] 2022/03/10 09:48:26 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: cdk -a . deploy CdkStackPipeline-sf-common --require-approval=never --verbose. Reason: exit status 1
[Container] 2022/03/10 09:48:26 Entering phase POST_BUILD
[Container] 2022/03/10 09:48:26 Phase complete: POST_BUILD State: SUCCEEDED
[Container] 2022/03/10 09:48:26 Phase context status code:  Message: 

I re-ran the CDK workshop (https://cdkworkshop.com/) from the start to end.
I compared my old CDK code with the new CDK code and found out there were quite much of difference.
I carefully merged the new code to my old code base and it worked like a charm. 😎

For your information, this is my code change.

diff --git a/packages/cdk-infra/src/pipeline-stack.ts b/packages/cdk-infra/src/pipeline-stack.ts
index 1d55346..62e3117 100644
--- a/packages/cdk-infra/src/pipeline-stack.ts
+++ b/packages/cdk-infra/src/pipeline-stack.ts
@@ -1,24 +1,25 @@
 
 import { Construct } from "constructs";
+import * as cdk from "aws-cdk-lib";
+import * as codecommit from "aws-cdk-lib/aws-codecommit";
 import {
-  Stack,
-  StackProps,
-  aws_codecommit as codecommit,
-  pipelines as pipelines,
-} from "aws-cdk-lib";
+  CodeBuildStep,
+  CodePipeline,
+  CodePipelineSource,
+} from "aws-cdk-lib/pipelines";
 import { SrvConfig } from "./srv-config";
 import { MainPipelineStage } from "./pipeline-stage";
 
 const repo_name = SrvConfig.CODE_COMMIT_REPO;
 
-export class MainPipelineStack extends Stack {
-  constructor(scope: Construct, id: string, props?: StackProps) {
+export class MainPipelineStack extends cdk.Stack {
+  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
     super(scope, id, props);
 
     // Creates a CodeCommit repository called ${repo_name}.
@@ -30,8 +31,9 @@ export class MainPipelineStack extends Stack {
     // of our pipeline
     const cdk_infra_path = "packages/cdk-infra";
     const cdk_out_path = "cdk.out";
-    const steps = new pipelines.ShellStep("Synth", {
-      input: pipelines.CodePipelineSource.codeCommit(repo, "master"),
+    const steps = new CodeBuildStep("SynthStep", {
+      input: CodePipelineSource.codeCommit(repo, "master"),
+      installCommands: ["npm install -g aws-cdk"],
       commands: [
         "cd " + cdk_infra_path,
         "npx lerna bootstrap --ci",
@@ -41,13 +43,15 @@ export class MainPipelineStack extends Stack {
       primaryOutputDirectory: cdk_infra_path + "/" + cdk_out_path,
     });
 
-    const pipeline = new pipelines.CodePipeline(this, "Pipeline", {
+    const pipeline = new CodePipeline(this, "Pipeline", {
       pipelineName: SrvConfig.PIPELINE_NAME,
       synth: steps,
     });
 
-    pipeline.addStage(
-      new MainPipelineStage(this, "Stack-" + SrvConfig.SYSTEM_NAME)
+    const deploy = new MainPipelineStage(
+      this,
+      "Stack-" + SrvConfig.SYSTEM_NAME
     );
+    const deployStage = pipeline.addStage(deploy);
   }
 }
diff --git a/packages/cdk-infra/cdk.json b/packages/cdk-infra/cdk.json
index 7cce01c..afb6215 100644
--- a/packages/cdk-infra/cdk.json
+++ b/packages/cdk-infra/cdk.json
@@ -1,5 +1,32 @@
 {
   "app": "npx ts-node --prefer-ts-exts src/cdk-main.ts",
+  "watch": {
+    "include": [
+      "**"
+    ],
+    "exclude": [
+      "README.md",
+      "cdk*.json",
+      "**/*.d.ts",
+      "**/*.js",
+      "tsconfig.json",
+      "package*.json",
+      "yarn.lock",
+      "node_modules",
+      "test"
+    ]
+  },
   "context": {
+    "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true,
+    "@aws-cdk/core:stackRelativeExports": true,
+    "@aws-cdk/aws-rds:lowercaseDbIdentifier": true,
+    "@aws-cdk/aws-lambda:recognizeVersionProps": true,
+    "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true,
+    "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
+    "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
+    "@aws-cdk/core:target-partitions": [
+      "aws",
+      "aws-cn"
+    ]
   }
 }
diff --git a/packages/cdk-infra/package.json b/packages/cdk-infra/package.json
index 0e2c8f1..482af25 100644
--- a/packages/cdk-infra/package.json
+++ b/packages/cdk-infra/package.json
@@ -1,53 +1,32 @@
 {
   "name": "@dev/cdk-infra",
   "version": "0.2.1",
   "description": "The CDK infrastructure",
   "author": "John Doe",
   "homepage": "",
   "private": true,
-  "main": "src/cdk-main.js",
-  "types": "src/cdk-main.d.ts",
   "bin": {
     "cdk-main": "src/cdk-main.js"
   },
-  "directories": {
-    "lib": "lib",
-    "test": "__tests__"
-  },
-  "files": [
-    "lib"
-  ],
   "scripts": {
     "build": "tsc",
     "watch": "tsc -w",
     "tsc": "tsc",
     "clean:tsc": "tsc --build --clean",
     "cdk": "cdk",
-    "test": "echo \"Error: run tests from root\" && exit 1"
+    "test": "jest"
   },
   "devDependencies": {
-    "@types/aws-serverless-express": "^3.3.5",
-    "@types/busboy": "^0.2.4",
-    "@types/jest": "^26.0.23",
-    "@types/node": "^15.12.4",
-    "aws-cdk-lib": "^2.15.0",
-    "constructs": "^10.0.0",
-    "ts-node": "^10.2.0",
-    "typescript": "^4.3.4"
+    "@types/jest": "^26.0.10",
+    "@types/node": "10.17.27",
+    "aws-cdk": "2.15.0",
+    "jest": "^26.4.2",
+    "ts-jest": "^26.2.0",
+    "ts-node": "^9.0.0",
+    "typescript": "~3.9.7"
   },
   "dependencies": {
-    "archiver": "^5.3.0",
-    "aws-cdk-lib": "^2.15.0",
-    "aws-sdk": "^2.931.0",
-    "cdk-assets": "^1.124.0",
-    "cdk-dynamo-table-viewer": "^3.1.2",
-    "constructs": "^10.0.0",
-    "fs-extra": "^10.0.0",
-    "jest": "^26.6.3",
-    "json-diff": "^0.5.4",
-    "lambda-facade": "../lambda-facade",
-    "promptly": "^3.2.0",
-    "proxy-agent": "^4.0.1",
-    "unique-string": "^3.0.0"
+    "aws-cdk-lib": "2.15.0",
+    "constructs": "^10.0.0"
   }
 }
diff --git a/packages/cdk-infra/.gitignore b/packages/cdk-infra/.gitignore
index 0d9935a..408f5b4 100644
--- a/packages/cdk-infra/.gitignore
+++ b/packages/cdk-infra/.gitignore
@@ -1,11 +1,3 @@
-*.d.ts
-*.js
-/node_modules
-
-/build/
-
-!/jest.config.js
-
-# CDK asset staging directory
-.cdk.staging
-cdk.out
+node_modules
+!lambda/*.js
+cdk.out/

I am not completely sure which of this code change did the trick but my hunch tells me maybe it's related with changing from ShellStep to CodeBuildStep.

I hope it helps.

@byongwu
Copy link

byongwu commented Mar 11, 2022

And the whole pipeline didn't take long time. Mine had quite many resources and took the reasonable time it usually took: 10 minutes 29 seconds.

@gbvanrenswoude
Copy link
Author

gbvanrenswoude commented Mar 14, 2022

@byongwu based on your remarks, I made some runs with ShellStep instead of CodeBuildStep, and also without the primaryOutputDirectory specified. Unfortunately no difference in runtimes, all still throw: Failed to get tree.json file: Error: cdk.out/tree.json: ENOTDIR: not a directory, open 'cdk.out/tree.json'
Since the pipeline is still functional, just slow, I'll leave this issue up to either revisit it once my current assignment is done or for the cdk team for review.

Seems related to: #19201 and possibly caused by: #18936

@byongwu
Copy link

byongwu commented Mar 15, 2022

@gbvanrenswoude Thanks for sharing. Then it must have been some other problem. Since the CDK workshop is an open source, let me share the typescript + CodePipeline working code (cdk-workshop-v2.16.0.tar.gz) based on the latest CDK (v2.16.0). I checked it with my AWS account and CodePipeline deployed fine.

But, as a side note, I would like to a comment that since CDK is so rapidly upgrading, it is forcing the production & previously-stable users to upgrade to the latest CDK. I mean there shouldn't be deployment problem if the user didn't touch anything except their code.

@gbvanrenswoude gbvanrenswoude changed the title (cdk pipelines): primary output directory root/cdk.out generates errors (cdk pipelines): primary output directory root/cdk.out generates errors since notices release Mar 15, 2022
@gbisaga
Copy link

gbisaga commented Mar 15, 2022

I am actually having my Update stage failing with:

Failed to get tree.json file: Error: cdk.out/tree.json: ENOTDIR: not a directory, open 'cdk.out/tree.json'

My CDK is in the components/cdk subdirectory of the root. In my cdk.Pipeline I specify the synth as follows:

      synth: new cp.ShellStep('Synth', {
        input: cp.CodePipelineSource.codeCommit(sourceRepo, 'main'),
        commands: [
... other commands here ...
          'cd components/cdk && npx cdk synth'
        ],
        primaryOutputDirectory: 'components/cdk/cdk.out'
      }),

I looked at the S3 artifact zip file being generated and it looks pretty much like I would expect it to:

image

I do have cdk --version 2.16.0 (build 4c77925), but I will say, I did have an older version installed when I did the cdk init originally (2.10?) Also, when I originally ran cdk init it was NOT in this subdirectory, it was in the root dir - we moved it to the subdir later. I will try re-running cdk init and compare what's generated.

@Chriscbr
Copy link
Contributor

Hi there - I've also noticed this error on some CodeBuild jobs, but I believe this error message "Failed to get tree.json file" is actually just intended to be an debug message as part of the CDK notices mechanism. When it gets printed, we actually catch the error so that it does not cause the CDK command to fail. This is based on what I found from digging into our source code here:

function loadTree(outdir: string) {
try {
return fs.readJSONSync(path.join(outdir, 'tree.json'));
} catch (e) {
debug(`Failed to get tree.json file: ${e}`);
return {};
}
}

I think it's possible that in these scenarios, the cause of build failures may be something different in the build logs. Here's an example from our build, showing that the actual error is located nearby:
Screen Shot 2022-04-12 at 4 06 33 PM

I'm not totally sure why this is printed red in codebuild when other "debug" lines aren't printed red, but I've submitted a PR that should try and improve the wording (#19887).

cc @otaviomacedo

mergify bot pushed a commit that referenced this issue Apr 12, 2022
Related to #19234. This improves the log wording so it's more clear this is not a "hard stop" error, and switch the log level to "trace" so it won't be shown in as many ordinary logs as a false positive error.

----

### All Submissions:

* [ ] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md)

### Adding new Unconventional Dependencies:

* [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md/#adding-new-unconventional-dependencies)

### New Features

* [ ] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/master/INTEGRATION_TESTS.md)?
	* [ ] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)?

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
StevePotter pushed a commit to StevePotter/aws-cdk that referenced this issue Apr 27, 2022
Related to aws#19234. This improves the log wording so it's more clear this is not a "hard stop" error, and switch the log level to "trace" so it won't be shown in as many ordinary logs as a false positive error.

----

### All Submissions:

* [ ] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md)

### Adding new Unconventional Dependencies:

* [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md/#adding-new-unconventional-dependencies)

### New Features

* [ ] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/master/INTEGRATION_TESTS.md)?
	* [ ] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)?

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
@55Cancri
Copy link

55Cancri commented May 26, 2022

It's been three months since this issue was opened, has anyone been able to solve this and get a pipeline to successfully pass through the UpdatePipeline - SelfMutate step?

The error I receive is Failed to store notices in the cache: Error: ENOENT: no such file or directory, open '/root/.cdk/cache/notices.json' and then a few lines later ENOENT: no such file or directory, open 'manifest.json'.

My pipeline exists in a monorepo setup like:

packages/
    client/
    server/
        ...cdk stuff
    shared/

where the cdk is in the server folder. The error seems to be searching for the cdk output after synth in the root of this monorepo instead of packages/server, despite setting the primaryOutputDirectory to "packages/server". Here is how my cdk stack looks:

   const pipeline = new cdk.pipelines.CodePipeline(this, "Pipeline", {
            pipelineName: app_name + "pipeline",
            // stop $1/month kms key charge
            crossAccountKeys: false,
            // the purpose of this step is to create a cdk.out folder via cdk synth command
            synth: new cdk.pipelines.ShellStep("Synth", {
                input: cdk.pipelines.CodePipelineSource.gitHub(
                    props!.repo_name,
                    props!.branch_name,
                    { authentication: github_token }
                ),
                commands: [
                    "yarn install",
                    // go into server folder first
                    "cd packages/server",
                    // then install and synth the cdk there
                    "yarn install",
                    "yarn build",
                    "npx cdk synth --all -c stage=" + env_name,
                    // then move the folder back up to the root so the build step can pass and hopefully the next step
                    "mv cdk.out ../..",
                ],
                primaryOutputDirectory: "packages/server",
            }),
        })
       // ...
       pipeline.addStage(server_stage)
       pipeline.addStage(client_stage)

You can see the primaryOutputDirectory is set to "packages/server", and also the last step of the commands array is "mv cdk.out ../..", which moves the generated cdk/ folder up two directories to the root.
That step is necessary for the build step to pass, but it looks like this is not persisted to the UpdatePipeline - SelfMutate step because the error doesn't seem to find the folder anymore (its searching in root/.cdk).

Any help or work arounds on this would be great. My understanding is that this is an issue in the current cdk versions, which don't seem to work well with monorepos.

@volkanunsal
Copy link

Also running into this issue. Has anyone made it work with a monorepo?

@volkanunsal
Copy link

It turns out Failed to store notices in the cache: Error: ENOENT: no such file or directory, open '/root/.cdk/cache/notices.json' was a red herring. If anyone else is having this issue, the real problem is...

... is not authorized to perform: cloudformation:GetTemplate on resource ...

This was happening because I didn't have "@aws-cdk/core:newStyleStackSynthesis": true, in cdk.json. When I changed that, the error went away and self update succeeded.

More about this issue:

#9606 (comment)

@froilan
Copy link

froilan commented Oct 31, 2022

@55Cancri
I was encountering the same issue as yours and managed to make it work.
The primaryOutputDirectory was set without */cdk.out.

Reason for the issue:
The generated codebuild relies on the artifact typed CODEPIPELINE (docs). Meaning it will come from the build output of the CodePipeline. And not adding the cdk.out in the output directory means the build output of CodePipeline is empty. Resulting the self mutate step to have no inputs, thus the error.

Hope that helps.

@maslick
Copy link

maslick commented Nov 8, 2022

@froilan so what is the workaround exactly? thnx

@T0MM0R
Copy link

T0MM0R commented Nov 25, 2022

I was running into a similar issue. I needed to specify the primaryOutputDirectory property on the ShellStep object.

import { Construct } from 'constructs';
import { Stack, StackProps } from 'aws-cdk-lib';
import { CodePipeline, CodePipelineSource, ShellStep, FileSet } from 'aws-cdk-lib/pipelines';
import { LinuxBuildImage, BuildSpec } from 'aws-cdk-lib/aws-codebuild';

export class PipelineStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);
    const pipeline = new CodePipeline(this, 'Pipeline', {
      pipelineName: 'CdkPipeline',
      synth: new ShellStep('Synth', {
        input: CodePipelineSource.connection('-----/------', 'main', {
          connectionArn: 'arn'
          }),
        commands: [
          'cd ${CODEBUILD_SRC_DIR}/cdk',
          'npm ci',
          'npx lerna bootstrap',
          'npx lerna run build',
          'cd ${CODEBUILD_SRC_DIR}/cdk/packages/infrastructure',
          'npx cdk synth',
        ],
        primaryOutputDirectory: '${CODEBUILD_SRC_DIR}/cdk/packages/infrastructure/cdk.out'
      }),
      codeBuildDefaults: {
        buildEnvironment: {
          buildImage: LinuxBuildImage.AMAZON_LINUX_2_4,
        },
      },
    });
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/pipelines CDK Pipelines library bug This issue is a bug. needs-reproduction This issue needs reproduction. p1 p2
Projects
None yet
Development

No branches or pull requests