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

[RFC] Deploy any CDK construct #183

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions src/constructs/aws/CustomCdk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { FromSchema } from "json-schema-to-ts";
import type { Construct as CdkConstruct } from "@aws-cdk/core";
import type { AwsProvider } from "@lift/providers";
import { AwsConstruct } from "@lift/constructs/abstracts";

const CUSTOM_CDK_DEFINITION = {
type: "object",
properties: {
type: { const: "customCdk" },
cdkConstructPath: { type: "string" },
},
additionalProperties: false,
required: ["cdkConstructPath"],
} as const;
type Configuration = FromSchema<typeof CUSTOM_CDK_DEFINITION>;

export class CustomCdk extends AwsConstruct {
public static type = "customCdk";
public static schema = CUSTOM_CDK_DEFINITION;

private customCdkConstruct: CdkConstruct;

constructor(
scope: CdkConstruct,
private readonly id: string,
private readonly configuration: Configuration,
private readonly provider: AwsProvider
) {
super(scope, id);

// dynamically import the file pointed by the path and compile it if it's a typescript file
const cdkConstructClass = importConstruct(this.configuration.cdkConstructPath);

// Imported file can contain anything. It should be validated
checkIsCdkConstruct(cdkConstructClass);

// The construct is only used to produce CloudFormation. It can't produce side effects such as artefacts upload.
checkConstructCanBeDeployed(cdkConstructClass);

this.customCdkConstruct = new cdkConstructClass(scope, "CdkConstruct");
}
variables(): Record<string, unknown> {
// Expose all the public attributes of the construct
return getAllPublicAttributes(this.customCdkConstruct);
}
}
65 changes: 65 additions & 0 deletions src/constructs/aws/CustomLift.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import type { FromSchema } from "json-schema-to-ts";
import type { Construct as CdkConstruct } from "@aws-cdk/core";
import type { AwsProvider } from "@lift/providers";
import { AwsConstruct } from "@lift/constructs/abstracts";
import type { ConstructInterface } from "@lift/constructs";
import type { PolicyStatement } from "../../CloudFormation";

const CUSTOM_LIFT_DEFINITION = {
type: "object",
properties: {
type: { const: "customLift" },
liftConstructPath: { type: "string" },
configuration: { type: "object" },
},
additionalProperties: false,
required: ["liftConstructPath"],
} as const;
type Configuration = FromSchema<typeof CUSTOM_LIFT_DEFINITION>;

export class CustomLift extends AwsConstruct {
public static type = "customLift";
public static schema = CUSTOM_LIFT_DEFINITION;

private customLiftConstruct: ConstructInterface;

constructor(
scope: CdkConstruct,
private readonly id: string,
private readonly configuration: Configuration,
private readonly provider: AwsProvider
) {
super(scope, id);

// dynamically import the file pointed by the path and compile it if it's a typescript file
const liftConstructClass = importConstruct(this.configuration.liftConstructPath);

// Imported file can contain anything. It should be validated
checkIsLiftConstruct(liftConstructClass);

// The construct is only used to produce CloudFormation. It can't produce side effects such as artefacts upload.
checkConstructCanBeDeployed(liftConstructClass);

this.customLiftConstruct = new liftConstructClass(
scope,
"CDKConstruct",
this.configuration.configuration ?? {},
provider
);
}
outputs(): Record<string, () => Promise<string | undefined>> {
return this.customLiftConstruct.outputs?.() ?? {};
}
variables(): Record<string, unknown> {
return this.customLiftConstruct.variables?.() ?? {};
}
postDeploy(): Promise<void> {
return this.customLiftConstruct.postDeploy?.() ?? Promise.resolve();
}
preRemove(): Promise<void> {
return this.customLiftConstruct.preRemove?.() ?? Promise.resolve();
}
permissions(): PolicyStatement[] {
return this.customLiftConstruct.permissions?.() ?? [];
}
}
2 changes: 2 additions & 0 deletions src/constructs/aws/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ export { Storage } from "./Storage";
export { Vpc } from "./Vpc";
export { Webhook } from "./Webhook";
export { ServerSideWebsite } from "./ServerSideWebsite";
export { CustomCdk } from "./CustomCdk";
export { CustomLift } from "./CustomLift";
6 changes: 5 additions & 1 deletion src/providers/AwsProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import type { AwsCfInstruction, AwsLambdaVpcConfig } from "@serverless/typescrip
import type { ProviderInterface } from "@lift/providers";
import type { ConstructInterface, StaticConstructInterface } from "@lift/constructs";
import {
CustomCdk,
CustomLift,
DatabaseDynamoDBSingleTable,
Queue,
ServerSideWebsite,
Expand Down Expand Up @@ -174,5 +176,7 @@ AwsProvider.registerConstructs(
StaticWebsite,
Vpc,
DatabaseDynamoDBSingleTable,
ServerSideWebsite
ServerSideWebsite,
CustomCdk,
CustomLift
);