Skip to content

Commit

Permalink
Use cdk-cli-lib to synthesize CDK application
Browse files Browse the repository at this point in the history
  • Loading branch information
corymhall committed Oct 7, 2024
1 parent 5bb37e9 commit b77236d
Show file tree
Hide file tree
Showing 10 changed files with 278 additions and 127 deletions.
3 changes: 3 additions & 0 deletions examples/lookups/Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: pulumi-lookups
runtime: nodejs
description: A minimal TypeScript Pulumi program
50 changes: 50 additions & 0 deletions examples/lookups/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import * as aws from '@pulumi/aws-native';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as pulumicdk from '@pulumi/cdk';
import { CfnOutput } from 'aws-cdk-lib';

export class Ec2CdkStack extends pulumicdk.Stack {
constructor(app: pulumicdk.App, id: string) {
super(app, id, {
props: {
env: { region: process.env.AWS_REGION, account: process.env.AWS_ACCOUNT },
},
});

// Create new VPC with 2 Subnets
const vpc = new ec2.Vpc(this, 'VPC', {
natGateways: 0,
subnetConfiguration: [
{
cidrMask: 24,
name: 'asterisk',
subnetType: ec2.SubnetType.PUBLIC,
},
],
});
const machineImage = new ec2.LookupMachineImage({
name: 'al2023-ami-2023.*.*.*.*-arm64',
});

const instance = new ec2.Instance(this, 'Instance', {
vpc,
instanceType: ec2.InstanceType.of(ec2.InstanceClass.T4G, ec2.InstanceSize.MICRO),
machineImage,
});

const param = new aws.ssm.Parameter('param', {
value: this.asOutput(instance.instanceId),
type: 'String',
});

new CfnOutput(this, 'instanceId', { value: instance.instanceId });
new CfnOutput(this, 'imageId', { value: machineImage.getImage(this).imageId });
}
}

const app = new pulumicdk.App('app', (scope: pulumicdk.App) => {
new Ec2CdkStack(scope, 'teststack');
});

export const imageId = app.outputs.then((output) => output['imageId']);
export const instanceId = app.outputs.then((output) => output['instanceId']);
14 changes: 14 additions & 0 deletions examples/lookups/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "pulumi-aws-cdk",
"devDependencies": {
"@types/node": "^10.0.0"
},
"dependencies": {
"@pulumi/aws": "^4.6.0",
"@pulumi/aws-native": "^1.0.2",
"@pulumi/cdk": "^0.5.0",
"@pulumi/pulumi": "^3.0.0",
"aws-cdk-lib": "2.149.0",
"constructs": "^10.0.111"
}
}
18 changes: 18 additions & 0 deletions examples/lookups/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"compilerOptions": {
"strict": true,
"outDir": "bin",
"target": "es2016",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"experimentalDecorators": true,
"pretty": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.ts"
]
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"constructs": "^10.0.111"
},
"dependencies": {
"@aws-cdk/cli-lib-alpha": "^2.161.1-alpha.0",
"@types/glob": "^8.1.0",
"archiver": "^7.0.1",
"cdk-assets": "^2.154.8",
Expand Down
53 changes: 23 additions & 30 deletions src/converters/app-converter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as pulumi from '@pulumi/pulumi';
import { AssemblyManifestReader, StackManifest } from '../assembly';
import { ConstructInfo, GraphBuilder } from '../graph';
import { StackComponentResource, lift, Mapping } from '../types';
import { lift, Mapping, AppComponent, PulumiStack } from '../types';
import { ArtifactConverter, FileAssetManifestConverter } from './artifact-converter';
import { CdkConstruct, ResourceMapping } from '../interop';
import { debug } from '@pulumi/pulumi/log';
Expand Down Expand Up @@ -30,7 +30,7 @@ export class AppConverter {

public readonly manifestReader: AssemblyManifestReader;

constructor(readonly host: StackComponentResource) {
constructor(readonly host: AppComponent) {
this.manifestReader = AssemblyManifestReader.fromDirectory(host.assemblyDir);
}

Expand Down Expand Up @@ -69,9 +69,11 @@ export class StackConverter extends ArtifactConverter {
readonly parameters = new Map<string, any>();
readonly resources = new Map<string, Mapping<pulumi.Resource>>();
readonly constructs = new Map<ConstructInfo, pulumi.Resource>();
private readonly cdkStack: PulumiStack;

constructor(host: StackComponentResource, readonly stack: StackManifest) {
constructor(host: AppComponent, readonly stack: StackManifest) {
super(host);
this.cdkStack = host.stacks[stack.id];
}

public convert(dependencies: Set<ArtifactConverter>) {
Expand All @@ -84,18 +86,14 @@ export class StackConverter extends ArtifactConverter {

for (const n of dependencyGraphNodes) {
if (n.construct.id === this.stack.id) {
const stackResource = new CdkConstruct(
`${this.stackComponent.name}/${n.construct.path}`,
n.construct.id,
{
parent: this.stackComponent,
// NOTE: Currently we make the stack depend on all the assets and then all resources
// have the parent as the stack. This means we deploy all assets before we deploy any resources
// we might be able better and have individual resources depend on individual assets, but CDK
// doesn't track asset dependencies at that level
dependsOn: this.stackDependsOn(dependencies),
},
);
const stackResource = new CdkConstruct(`${this.app.name}/${n.construct.path}`, n.construct.id, {
parent: this.app,
// NOTE: Currently we make the stack depend on all the assets and then all resources
// have the parent as the stack. This means we deploy all assets before we deploy any resources
// we might be able better and have individual resources depend on individual assets, but CDK
// doesn't track asset dependencies at that level
dependsOn: this.stackDependsOn(dependencies),
});
this.constructs.set(n.construct, stackResource);
continue;
}
Expand Down Expand Up @@ -123,18 +121,13 @@ export class StackConverter extends ArtifactConverter {
// // Do something with the condition
// }
} else {
const r = new CdkConstruct(`${this.stackComponent.name}/${n.construct.path}`, n.construct.type, {
const r = new CdkConstruct(`${this.app.name}/${n.construct.path}`, n.construct.type, {
parent,
});
this.constructs.set(n.construct, r);
}
}

// Register the outputs as outputs of the component resource.
for (const [outputId, args] of Object.entries(this.stack.outputs ?? {})) {
this.stackComponent.registerOutput(outputId, this.processIntrinsics(args.Value));
}

for (let i = dependencyGraphNodes.length - 1; i >= 0; i--) {
const n = dependencyGraphNodes[i];
if (!n.resource) {
Expand Down Expand Up @@ -178,7 +171,7 @@ export class StackConverter extends ArtifactConverter {
return key;
}

this.parameters.set(logicalId, parameterValue(this.stackComponent));
this.parameters.set(logicalId, parameterValue(this.app));
}

private mapResource(
Expand All @@ -187,8 +180,8 @@ export class StackConverter extends ArtifactConverter {
props: any,
options: pulumi.ResourceOptions,
): ResourceMapping {
if (this.stackComponent.options?.remapCloudControlResource !== undefined) {
const res = this.stackComponent.options.remapCloudControlResource(logicalId, typeName, props, options);
if (this.app.appOptions?.remapCloudControlResource !== undefined) {
const res = this.app.appOptions.remapCloudControlResource(logicalId, typeName, props, options);
if (res !== undefined) {
debug(`remapped ${logicalId}`);
return res;
Expand Down Expand Up @@ -216,11 +209,11 @@ export class StackConverter extends ArtifactConverter {

/** @internal */
asOutputValue<T>(v: T): T {
const value = this.stackComponent.stack.resolve(v);
const value = this.cdkStack.resolve(v);
return this.processIntrinsics(value) as T;
}

private processIntrinsics(obj: any): any {
public processIntrinsics(obj: any): any {
try {
debug(`Processing intrinsics for ${JSON.stringify(obj)}`);
} catch {
Expand Down Expand Up @@ -339,15 +332,15 @@ export class StackConverter extends ArtifactConverter {

switch (target) {
case 'AWS::AccountId':
return getAccountId({ parent: this.stackComponent }).then((r) => r.accountId);
return getAccountId({ parent: this.app }).then((r) => r.accountId);
case 'AWS::NoValue':
return undefined;
case 'AWS::Partition':
return getPartition({ parent: this.stackComponent }).then((p) => p.partition);
return getPartition({ parent: this.app }).then((p) => p.partition);
case 'AWS::Region':
return getRegion({ parent: this.stackComponent }).then((r) => r.region);
return getRegion({ parent: this.app }).then((r) => r.region);
case 'AWS::URLSuffix':
return getUrlSuffix({ parent: this.stackComponent }).then((r) => r.urlSuffix);
return getUrlSuffix({ parent: this.app }).then((r) => r.urlSuffix);
case 'AWS::NotificationARNs':
case 'AWS::StackId':
case 'AWS::StackName':
Expand Down
12 changes: 6 additions & 6 deletions src/converters/artifact-converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import { getAccountId, getPartition, getRegion } from '@pulumi/aws-native';
import { FileAssetManifest } from '../assembly';
import { FileAssetPackaging } from 'aws-cdk-lib/cloud-assembly-schema';
import { zipDirectory } from '../zip';
import { StackComponentResource } from '../types';
import { AppComponent } from '../types';

/**
* ArtifactConverter
*/
export abstract class ArtifactConverter {
constructor(protected readonly stackComponent: StackComponentResource) {}
constructor(protected readonly app: AppComponent) {}

/**
* Takes a string and resolves any CDK environment placeholders (e.g. accountId, region, partition)
Expand All @@ -19,7 +19,7 @@ export abstract class ArtifactConverter {
* @returns The string with the placeholders fully resolved
*/
protected resolvePlaceholders(s: string): Promise<string> {
const host = this.stackComponent;
const host = this.app;
return cx.EnvironmentPlaceholders.replaceAsync(s, {
async region(): Promise<string> {
return getRegion({ parent: host }).then((r) => r.region);
Expand All @@ -44,7 +44,7 @@ export class FileAssetManifestConverter extends ArtifactConverter {
public _id?: string;
public resourceType: string = 'aws:s3:BucketObjectv2';

constructor(host: StackComponentResource, readonly manifest: FileAssetManifest) {
constructor(host: AppComponent, readonly manifest: FileAssetManifest) {
super(host);
}

Expand All @@ -71,7 +71,7 @@ export class FileAssetManifestConverter extends ArtifactConverter {
public convert(): void {
const name = this.manifest.id.assetId;
const id = this.manifest.id.destinationId;
this._id = `${this.stackComponent.name}/${name}/${id}`;
this._id = `${this.app.name}/${name}/${id}`;

const outputPath =
this.manifest.packaging === FileAssetPackaging.FILE
Expand All @@ -85,7 +85,7 @@ export class FileAssetManifestConverter extends ArtifactConverter {
bucket: this.resolvePlaceholders(this.manifest.destination.bucketName),
key: this.resolvePlaceholders(this.manifest.destination.objectKey),
},
{ parent: this.stackComponent },
{ parent: this.app },
);
}
}
Loading

0 comments on commit b77236d

Please sign in to comment.