I'm trying to create a reusable library to handle ECR image scan results. The code is available at https://github.com/markusl/cdk-ecr-image-scan-handler
After publishing the generated library (using projen & JSII tools) to NPM and using it from another AWS CDK project I get the following, not very useful error message:
$ npm run build && cdk synth
> [email protected] build aws-cdk-pipelines-test
> tsc
Cannot find entry file.
Subprocess exited with error 1
The directory structure of the imported NPM package under node_modules looks ok to me:
cdk-ecr-image-scan-handler/lib/index.js
cdk-ecr-image-scan-handler/lib/index.d.ts
cdk-ecr-image-scan-handler/lib/index.handler.js
cdk-ecr-image-scan-handler/lib/index.handler.d.ts
@jogold already provided some input for the source module setup which apparently is supposed to work like this:
new lambda_nodejs.NodejsFunction(this, 'handler', {
runtime: lambda.Runtime.NODEJS_12_X,
minify: true,
role: lambdaRole,
functionName: componentName,
description: 'Handler for ECR Image Scan results',
environment: {
FROM_ADDRESS: props.fromAddress,
TO_ADDRESS: props.toAddress,
},
});
Please let me know if there are any configuration errors in the project. I was looking for a reference setup but did not find one yet.
I would expect the Lambda function to be packaged correctly.
I received the error.
This is :bug: Bug Report
@jogold any ideas?
The construct is looking for the file at cdk-ecr-image-scan-handler/src/index.handler.js but it's published at cdk-ecr-image-scan-handler/lib/index.handler.js (src vs lib).
I think that this has something to do with this (extracting from stack trace):
https://github.com/aws/aws-cdk/blob/bb90fbe36a7935a43397f94dfcd0008b0a0bb806/packages/%40aws-cdk/aws-lambda-nodejs/lib/function.ts#L133-L135
and the source map generated for the file.
The solution would be to specify the entry relatively (using __dirname) = not use automatic entry finding here (I know I said earlier that it's easier to use it). Or preserve the same directory structure in your repo and on npm.
Also looking at your construct, it seems that your Lambda code is "self contained": you are not using node modules or requiring/importing other files. This means that you don't really need bundling. Are using the NodejsFunction for the defaults it provides?
@eladb maybe we should add something like a noBundling prop to the NodejsFunction.
@jogold we are also considering creating some internal libraries/tooling which require the bunding functionality. If we get this working :) I'd like to start with a simple example first to get the baseline configuration working.
Would you be able to provide a complete JSII module with an example setup using NodejsFunction bundling? That would be a good starting point for us and others as well.
Or preserve the same directory structure in your repo and on npm.
Is this an option for you? This means outputting compiled files next to .ts files. This is how it is done in this repo.
@jogold I don't mind about the directory layout published to NPM. Would you be able to provide a reference setup that would include a JSII construct that has a NodejsFunction that bundles an AWS Lambda from multiple source files?
@eladb @jogold do you have any ideas on how to make this work? I'm a little bit confused right now because this issue means NodejsFunction cannot be used in modules because they result in compilation errors in the AWS CDK infrastructure project when imported.
I still do get the Cannot find entry file. error with CDK 1.60.0. Please let me know if there is another way to build reusable constructs or if there are any problems in the configuration.
@markusl switching to local bundling in your repo (https://github.com/markusl/cdk-ecr-image-scan-handler/pull/28, https://github.com/markusl/cdk-ecr-image-scan-handler/pull/29) made it work in your GitHub action.
It looks like Docker-in-Docker with volume mounts inside a GitHub action is problematic but we now have local bundling.
Regarding the Cannot find entry file I think we can improve the automatic entry finding in the CDK. There's something to do with the source map.
@jogold I also tried to change the configuration to multi-file bundling as discussed earlier but now it seems to be failing with a yet another error message: https://github.com/markusl/cdk-ecr-image-scan-handler/runs/1007797552
$ yarn test && yarn compile && yarn run package
$ yarn eslint && rm -fr lib/ && jest --passWithNoTests --updateSnapshot
$ eslint . --ext .ts
Bundling asset testing-stack/ecr-scan-result-handler/handler/Code/Stage...
error: unknown option `--no-autoinstall'
FAIL test/index.test.ts (8.74 s)
✕ Create EcrImageScanResultHandler (1039 ms)
● Create EcrImageScanResultHandler
Failed to bundle asset testing-stack/ecr-scan-result-handler/handler/Code/Stage: Error: bash exited with status 1
I may have been unclear before, but I would highly appreciate a complete, working example of how to create a reusable JSII module that bundles a Lambda function with NodejsFunction that consists of multiple TypeScript source files which may or may not include third party NPM libraries. This would enable our organization to effectively concentrate our AWS development efforts on AWS CDK technology so that teams could easily include required company internal libraries for reporting and security purposes. Please let me know if you need more details about this use case.
Can you fix the version of parcel to 2.0.0-beta.1 (no caret ^)?
I may have been unclear before, but I would highly appreciate a complete, working example of how to create a reusable JSII module that bundles a Lambda function with
NodejsFunctionthat consists of multiple TypeScript source files which may or may not include third party NPM libraries. This would enable our organization to effectively concentrate our AWS development efforts on AWS CDK technology so that teams could easily include required company internal libraries for reporting and security purposes. Please let me know if you need more details about this use case.
I understand but I don't have time to do this right now. Your repo (which I fixed) is now a good example. Will definitely let you know if I get a chance to do this.
Can you fix the version of
parcelto2.0.0-beta.1(no caret^)?
This seems to solve the build! Thanks.
However, consuming the package does not work with an empty app:
cdk init app --language typescript
npm i --save cdk-ecr-image-scan-handler
export class TestStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
new EcrImageScanResultHandler(this, 'ecr-scan-result-handler', {
fromAddress: '[email protected]', // Use SES for validating the addresses
toAddress: '[email protected]',
notificationTopicArn: 'arn:aws:sns:eu-central-1:112233445566:ecr-repository-scan-completed-topic',
});
}
}
The error message when building the code is Assets must be defined indirectly within a "Stage" or an "App" scope which seems to be a similar problem a lot of people are having at https://github.com/aws/aws-cdk/issues/9546
Again, I would like to know if what we are trying to do something that you plan to support, or is this approach somehow incorrect? :)
The error message when building the code is
Assets must be defined indirectly within a "Stage" or an "App" scopewhich seems to be a similar problem a lot of people are having at #9546
This error doesn't seem to be related to the NodejsFunction construct. Is it possible that you are consuming your module with a different version of @aws-cdk/core or constructs than the one in your module? @eladb, any idea?
The error message when building the code is
Assets must be defined indirectly within a "Stage" or an "App" scopewhich seems to be a similar problem a lot of people are having at #9546This error doesn't seem to be related to the
NodejsFunctionconstruct. Is it possible that you are consuming your module with a different version of@aws-cdk/coreorconstructsthan the one in your module? @eladb, any idea?
Yeah, that was weird. After I nuked everything, the problem went away.
Now that I have been experimenting with this, I still don't understand what causes the bundling to happen within Docker and what locally.
Project created from scratch (works as expected):
$ npm run build && cdk synth
> [email protected] build test
> tsc
Bundling asset TestStack/ecr-scan-result-handler/handler/Code/Stage...
Bundling...
✨ Built in 1.63s
../../../../asset-output/index.handler.js 2.59 KB 510ms
npm WARN asset-output No description
npm WARN asset-output No repository field.
npm WARN asset-output No license field.
added 14 packages from 66 contributors and audited 14 packages in 10.664s
found 0 vulnerabilities
Existing AWS CDK Pipelines project:
$ npm run build && cdk synth
> [email protected] build aws-cdk-pipelines-test
> tsc
Bundling asset CdkpipelinesDemoPipelineStack/Devops/EcrStackDevops/ecr-scan-result-handler/handler/Code/Stage...
The weird thing here is that the bundling seems to be stuck forever. I even left the bundling running for the night and it was just stuck there. Any ideas?
I still don't understand what causes the bundling to happen within Docker and what locally.
Bundling happens locally if the correct version of Parcel is available (2.0.0-beta.1). This is checked by running parcel --version.
Ok, now after CDK 1.61.0 this moved slightly forward again. Bundling & building & publishing almost work 👍
Two issues at the moment:
It seems new format generated by projen does not pass the anti-tamper check in Github Workflows https://github.com/markusl/cdk-ecr-image-scan-handler/runs/1036304012
It seems that when including the JSII library as part of a CDK Pipelines project fails building it:
[Container] 2020/08/27 12:00:45 Running command npx cdk synth
Cannot find project root. Please specify it with `projectRoot`.
Subprocess exited with error 1
@jogold do you have any recommendations on the latter?
The configuration improvements for the NodejsFunction in #10174 will solve the projectRoot issue. I'll close this now as a duplicate.
I've just experienced a similar issue when running my code in ~VS~ Github Codespaces:
Cannot find entry file.
> 16 | const handler = new lambdaNode.NodejsFunction(this, "Handler", {
This is using "aws-cdk": "1.74.0" and "parcel": "2.0.0-beta.1".
I could fix it by manually adding the entry: option:
export class Stack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const handler = new lambdaNode.NodejsFunction(this, "Handler", {
entry: path.join(__dirname, ".", "stack.handler.ts"),
I didn't need to add the projectRoot option.
Is this a different bug? Should I open a new issue?
@hughevans if you don't specify entry the construct looks for a file named after the construct's id, in your case it looks for a file named stack.Handler.ts or stack.Handler.js (note the capital H).
@jogold Brilliant, thanks. It worked on MacOS because of its case insensitive filesystem.