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

Allow passing lambda alias or version to publish tool #297

Merged
merged 13 commits into from
Jan 15, 2023
14 changes: 12 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,17 @@ jobs:
echo "DEPLOYER_LAMBDA_NAME="$(aws cloudformation list-exports --query "Exports[?Name==\`${{ matrix.deployName }}-ghpublic-${NODE_ENV}${{ needs.build.outputs.prSuffix }}-deployer-func-name\`].Value" --no-paginate --output text) >> $GITHUB_ENV
echo "DEMO_APP_LAMBDA_NAME="$(aws cloudformation list-exports --query "Exports[?Name==\`${{ matrix.deployName }}-ghpublic-${NODE_ENV}${{ needs.build.outputs.prSuffix }}-demo-app-func-name\`].Value" --no-paginate --output text) >> $GITHUB_ENV
echo "NEXTJS_DEMO_APP_LAMBDA_NAME="$(aws cloudformation list-exports --query "Exports[?Name==\`${{ matrix.deployName }}-ghpublic-${NODE_ENV}${{ needs.build.outputs.prSuffix }}-nextjs-demo-app-func-name\`].Value" --no-paginate --output text) >> $GITHUB_ENV
echo "NEXTJS_DEMO_APP_LAMBDA_VERSION_ARN="$(aws cloudformation list-exports --query "Exports[?Name==\`${{ matrix.deployName }}-ghpublic-${NODE_ENV}${{ needs.build.outputs.prSuffix }}-nextjs-demo-app-vers-arn\`].Value" --no-paginate --output text) >> $GITHUB_ENV
echo "RELEASE_APP_LAMBDA_NAME="$(aws cloudformation list-exports --query "Exports[?Name==\`${{ matrix.deployName }}-ghpublic-${NODE_ENV}${{ needs.build.outputs.prSuffix }}-release-app-func-name\`].Value" --no-paginate --output text) >> $GITHUB_ENV
echo "RELEASE_APP_LAMBDA_VERSION_ARN="$(aws cloudformation list-exports --query "Exports[?Name==\`${{ matrix.deployName }}-ghpublic-${NODE_ENV}${{ needs.build.outputs.prSuffix }}-release-app-vers-arn\`].Value" --no-paginate --output text) >> $GITHUB_ENV

- name: Echo Exports
run: |
env | grep EDGE_DOMAIN
env | grep DEPLOYER_
env | grep DEMO_APP_
env | grep NEXTJS_DEMO_APP_
env | grep RELEASE_APP_

- name: Publish Demo App to MicroApps
run: |
Expand Down Expand Up @@ -327,7 +337,7 @@ jobs:
-a ${NEXTJS_DEMO_APP_NAME} \
-n ${{ needs.build.outputs.nextjsDemoAppPackageVersion }} \
-d ${DEPLOYER_LAMBDA_NAME} \
-l ${NEXTJS_DEMO_APP_LAMBDA_NAME} \
-l ${NEXTJS_DEMO_APP_LAMBDA_VERSION_ARN} \
-s packages/cdk/node_modules/@pwrdrvr/microapps-app-nextjs-demo-cdk/lib/microapps-app-nextjs-demo/.static_files/ \
--overwrite --noCache

Expand Down Expand Up @@ -358,7 +368,7 @@ jobs:
-a ${RELEASE_APP_NAME} \
-n ${{ needs.build.outputs.releaseAppPackageVersion }} \
-d ${DEPLOYER_LAMBDA_NAME} \
-l ${RELEASE_APP_LAMBDA_NAME} \
-l ${RELEASE_APP_LAMBDA_VERSION_ARN} \
-s packages/cdk/node_modules/@pwrdrvr/microapps-app-release-cdk/lib/microapps-app-release/.static_files/ \
--overwrite --noCache

Expand Down
16 changes: 15 additions & 1 deletion packages/cdk/lib/MicroApps.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Aws, CfnOutput, Duration, RemovalPolicy, Stack, StackProps } from 'aws-cdk-lib';
import { CfnOutput, RemovalPolicy, Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as acm from 'aws-cdk-lib/aws-certificatemanager';
import * as lambda from 'aws-cdk-lib/aws-lambda';
Expand Down Expand Up @@ -265,10 +265,17 @@ export class MicroAppsStack extends Stack {
removalPolicy,
});

const appVersion = (app.lambdaFunction as lambda.Function).currentVersion;

new CfnOutput(this, 'release-app-func-name', {
value: `${app.lambdaFunction.functionName}`,
exportName: `${this.stackName}-release-app-func-name`,
});

new CfnOutput(this, 'release-app-vers-arn', {
value: `${appVersion.functionArn}`,
exportName: `${this.stackName}-release-app-vers-arn`,
});
}

if (deployNextjsDemoApp) {
Expand All @@ -280,10 +287,17 @@ export class MicroAppsStack extends Stack {
removalPolicy,
});

const appVersion = (app.lambdaFunction as lambda.Function).currentVersion;

new CfnOutput(this, 'nextjs-demo-app-func-name', {
value: `${app.lambdaFunction.functionName}`,
exportName: `${this.stackName}-nextjs-demo-app-func-name`,
});

new CfnOutput(this, 'nextjs-demo-app-vers-arn', {
value: `${appVersion.functionArn}`,
exportName: `${this.stackName}-nextjs-demo-app-vers-arn`,
});
}

// Exports
Expand Down
4 changes: 2 additions & 2 deletions packages/cdk/test/MicroApps.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe('MicroAppsStack', () => {

expect(stack).toBeDefined();
Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', {});
Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 4);
Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 3);
Template.fromStack(stack).hasOutput('edgedomainname', {
Value: { 'Fn::GetAtt': ['microappscft5FDF8AB8', 'DomainName'] },
Export: { Name: `${stackName}-edge-domain-name` },
Expand Down Expand Up @@ -46,7 +46,7 @@ describe('MicroAppsStack', () => {

expect(stack).toBeDefined();
Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', {});
Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 4);
Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 3);
Template.fromStack(stack).hasOutput('edgedomainname', {
Value: 'appz.pwrdrvr.com',
Export: { Name: `${stackName}-edge-domain-name` },
Expand Down
150 changes: 75 additions & 75 deletions packages/microapps-cdk/src/MicroAppsSvcs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ export interface IMicroAppsSvcs {
/**
* Lambda function for the Router
*/
readonly routerFunc: lambda.IFunction;
readonly routerFunc?: lambda.IFunction;
}

/**
Expand All @@ -207,8 +207,8 @@ export class MicroAppsSvcs extends Construct implements IMicroAppsSvcs {
return this._deployerFunc;
}

private _routerFunc: lambda.Function;
public get routerFunc(): lambda.IFunction {
private _routerFunc?: lambda.Function;
public get routerFunc(): lambda.IFunction | undefined {
return this._routerFunc;
}

Expand Down Expand Up @@ -268,78 +268,6 @@ export class MicroAppsSvcs extends Construct implements IMicroAppsSvcs {
this._table = props.table;
}

//
// Router Lambda Function
//

// Create Router Lambda Function
const routerFuncProps: Omit<lambda.FunctionProps, 'handler' | 'code'> = {
functionName: assetNameRoot ? `${assetNameRoot}-router${assetNameSuffix}` : undefined,
memorySize: 1769,
logRetention: logs.RetentionDays.ONE_MONTH,
runtime: lambda.Runtime.NODEJS_16_X,
timeout: Duration.seconds(15),
environment: {
NODE_ENV: appEnv,
DATABASE_TABLE_NAME: this._table.tableName,
AWS_NODEJS_CONNECTION_REUSE_ENABLED: '1',
ROOT_PATH_PREFIX: rootPathPrefix,
},
};
if (
process.env.NODE_ENV === 'test' &&
existsSync(path.join(__dirname, '..', '..', 'microapps-router', 'dist', 'index.js'))
) {
// This is for local dev
this._routerFunc = new lambda.Function(this, 'router-func', {
code: lambda.Code.fromAsset(path.join(__dirname, '..', '..', 'microapps-router', 'dist')),
handler: 'index.handler',
...routerFuncProps,
});
} else if (existsSync(path.join(__dirname, 'microapps-router', 'index.js'))) {
// This is for built apps packaged with the CDK construct
this._routerFunc = new lambda.Function(this, 'router-func', {
code: lambda.Code.fromAsset(path.join(__dirname, 'microapps-router')),
handler: 'index.handler',
...routerFuncProps,
});
} else {
// Create Router Lambda Layer
const routerDataFiles = new lambda.LayerVersion(this, 'router-templates', {
code: lambda.Code.fromAsset(
path.join(__dirname, '..', '..', 'microapps-router', 'templates'),
),
removalPolicy,
});

this._routerFunc = new lambdaNodejs.NodejsFunction(this, 'router-func', {
entry: path.join(__dirname, '..', '..', 'microapps-router', 'src', 'index.ts'),
handler: 'handler',
bundling: {
minify: true,
sourceMap: true,
},
layers: [routerDataFiles],
...routerFuncProps,
});
}
if (removalPolicy !== undefined) {
this._routerFunc.applyRemovalPolicy(removalPolicy);
}
const policyReadTarget = new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['s3:GetObject'],
resources: [`${bucketApps.bucketArn}/*`],
});
for (const router of [this._routerFunc]) {
router.addToRolePolicy(policyReadTarget);
// Give the Router access to DynamoDB table
this._table.grantReadData(router);
this._table.grant(router, 'dynamodb:DescribeTable');
}
// Create alias for Router
const routerAlias = this._routerFunc.addAlias('CurrentVersion');

//
// Deployer Lambda Function
//
Expand Down Expand Up @@ -630,6 +558,78 @@ export class MicroAppsSvcs extends Construct implements IMicroAppsSvcs {
this._deployerFunc.addToRolePolicy(policyAPIManageLambdas);

if (httpApi) {
//
// Router Lambda Function
//

// Create Router Lambda Function
const routerFuncProps: Omit<lambda.FunctionProps, 'handler' | 'code'> = {
functionName: assetNameRoot ? `${assetNameRoot}-router${assetNameSuffix}` : undefined,
memorySize: 1769,
logRetention: logs.RetentionDays.ONE_MONTH,
runtime: lambda.Runtime.NODEJS_16_X,
timeout: Duration.seconds(15),
environment: {
NODE_ENV: appEnv,
DATABASE_TABLE_NAME: this._table.tableName,
AWS_NODEJS_CONNECTION_REUSE_ENABLED: '1',
ROOT_PATH_PREFIX: rootPathPrefix,
},
};
if (
process.env.NODE_ENV === 'test' &&
existsSync(path.join(__dirname, '..', '..', 'microapps-router', 'dist', 'index.js'))
) {
// This is for local dev
this._routerFunc = new lambda.Function(this, 'router-func', {
code: lambda.Code.fromAsset(path.join(__dirname, '..', '..', 'microapps-router', 'dist')),
handler: 'index.handler',
...routerFuncProps,
});
} else if (existsSync(path.join(__dirname, 'microapps-router', 'index.js'))) {
// This is for built apps packaged with the CDK construct
this._routerFunc = new lambda.Function(this, 'router-func', {
code: lambda.Code.fromAsset(path.join(__dirname, 'microapps-router')),
handler: 'index.handler',
...routerFuncProps,
});
} else {
// Create Router Lambda Layer
const routerDataFiles = new lambda.LayerVersion(this, 'router-templates', {
code: lambda.Code.fromAsset(
path.join(__dirname, '..', '..', 'microapps-router', 'templates'),
),
removalPolicy,
});

this._routerFunc = new lambdaNodejs.NodejsFunction(this, 'router-func', {
entry: path.join(__dirname, '..', '..', 'microapps-router', 'src', 'index.ts'),
handler: 'handler',
bundling: {
minify: true,
sourceMap: true,
},
layers: [routerDataFiles],
...routerFuncProps,
});
}
if (removalPolicy !== undefined) {
this._routerFunc.applyRemovalPolicy(removalPolicy);
}
const policyReadTarget = new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['s3:GetObject'],
resources: [`${bucketApps.bucketArn}/*`],
});
for (const router of [this._routerFunc]) {
router.addToRolePolicy(policyReadTarget);
// Give the Router access to DynamoDB table
this._table.grantReadData(router);
this._table.grant(router, 'dynamodb:DescribeTable');
}
// Create alias for Router
const routerAlias = this._routerFunc.addAlias('CurrentVersion');

// This creates an integration and a router
const route = new apigwy.HttpRoute(this, 'route-default', {
httpApi,
Expand Down
49 changes: 23 additions & 26 deletions packages/microapps-cdk/test/MicroApps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe('MicroApps', () => {
expect(construct.node).toBeDefined();
Template.fromStack(stack).resourceCountIs('AWS::DynamoDB::Table', 1);
Template.fromStack(stack).resourceCountIs('AWS::CloudFront::Distribution', 1);
Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 4);
Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 3);

// Confirm that logical IDs have not changed accidentally (causes delete/create)
Template.fromStack(stack).templateMatches({
Expand All @@ -42,9 +42,9 @@ describe('MicroApps', () => {
// constructedgeToOriginedgetoapigwyfuncFn10C0FCC9: {
// Type: 'AWS::Lambda::Function',
// },
constructsvcsrouterfunc73102284: {
Type: 'AWS::Lambda::Function',
},
// constructsvcsrouterfunc73102284: {
// Type: 'AWS::Lambda::Function',
// },
constructs3apps91016270: {
Type: 'AWS::S3::Bucket',
},
Expand Down Expand Up @@ -90,7 +90,7 @@ describe('MicroApps', () => {
expect(construct.node).toBeDefined();
Template.fromStack(stack).resourceCountIs('AWS::DynamoDB::Table', 1);
Template.fromStack(stack).resourceCountIs('AWS::CloudFront::Distribution', 1);
Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 4);
Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 3);

// Confirm that logical IDs have not changed accidentally (causes delete/create)
Template.fromStack(stack).templateMatches({
Expand All @@ -104,9 +104,9 @@ describe('MicroApps', () => {
// constructedgeToOriginedgetoapigwyfuncFn10C0FCC9: {
// Type: 'AWS::Lambda::Function',
// },
constructsvcsrouterfunc73102284: {
Type: 'AWS::Lambda::Function',
},
// constructsvcsrouterfunc73102284: {
// Type: 'AWS::Lambda::Function',
// },
constructs3apps91016270: {
Type: 'AWS::S3::Bucket',
},
Expand Down Expand Up @@ -153,10 +153,10 @@ describe('MicroApps', () => {
expect(construct.node).toBeDefined();
Template.fromStack(stack).resourceCountIs('AWS::DynamoDB::Table', 1);
Template.fromStack(stack).resourceCountIs('AWS::CloudFront::Distribution', 1);
Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 4);
Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', {
FunctionName: 'my-asset-root-name-router-some-suffix',
});
Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 3);
// Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', {
// FunctionName: 'my-asset-root-name-router-some-suffix',
// });
Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', {
FunctionName: 'my-asset-root-name-deployer-some-suffix',
});
Expand All @@ -173,9 +173,9 @@ describe('MicroApps', () => {
// constructedgeToOriginedgetoapigwyfuncFn10C0FCC9: {
// Type: 'AWS::Lambda::Function',
// },
constructsvcsrouterfunc73102284: {
Type: 'AWS::Lambda::Function',
},
// constructsvcsrouterfunc73102284: {
// Type: 'AWS::Lambda::Function',
// },
constructs3apps91016270: {
Type: 'AWS::S3::Bucket',
},
Expand Down Expand Up @@ -223,10 +223,10 @@ describe('MicroApps', () => {
expect(construct.node).toBeDefined();
Template.fromStack(stack).resourceCountIs('AWS::DynamoDB::Table', 1);
Template.fromStack(stack).resourceCountIs('AWS::CloudFront::Distribution', 1);
Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 4);
Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', {
FunctionName: 'my-asset-root-name-router-some-suffix',
});
Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 3);
// Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', {
// FunctionName: 'my-asset-root-name-router-some-suffix',
// });
Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', {
FunctionName: 'my-asset-root-name-deployer-some-suffix',
});
Expand Down Expand Up @@ -257,9 +257,9 @@ describe('MicroApps', () => {
constructsvcsdeployerfunc88CC1526: {
Type: 'AWS::Lambda::Function',
},
constructsvcsrouterfunc73102284: {
Type: 'AWS::Lambda::Function',
},
// constructsvcsrouterfunc73102284: {
// Type: 'AWS::Lambda::Function',
// },
constructs3apps91016270: {
Type: 'AWS::S3::Bucket',
},
Expand Down Expand Up @@ -311,7 +311,7 @@ describe('MicroApps', () => {
expect(construct.node).toBeDefined();
Template.fromStack(stack).resourceCountIs('AWS::DynamoDB::Table', 1);
Template.fromStack(stack).resourceCountIs('AWS::CloudFront::Distribution', 1);
Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 3);
Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 2);

// Confirm that logical IDs have not changed accidentally (causes delete/create)
Template.fromStack(stack).templateMatches({
Expand All @@ -322,9 +322,6 @@ describe('MicroApps', () => {
constructsvcstable0311CF05: {
Type: 'AWS::DynamoDB::Table',
},
constructsvcsrouterfunc73102284: {
Type: 'AWS::Lambda::Function',
},
constructs3apps91016270: {
Type: 'AWS::S3::Bucket',
},
Expand Down
Loading