diff --git a/examples/s3-object-lambda/src/s3-object-lambda-stack.ts b/examples/s3-object-lambda/src/s3-object-lambda-stack.ts index 758ec23a..84398f3d 100644 --- a/examples/s3-object-lambda/src/s3-object-lambda-stack.ts +++ b/examples/s3-object-lambda/src/s3-object-lambda-stack.ts @@ -1,11 +1,11 @@ import * as pulumi from '@pulumi/pulumi'; +import * as aws from '@pulumi/aws-native'; import * as pulumicdk from '@pulumi/cdk'; import * as cdk from 'aws-cdk-lib'; import * as iam from 'aws-cdk-lib/aws-iam'; import * as lambda from 'aws-cdk-lib/aws-lambda'; import * as s3 from 'aws-cdk-lib/aws-s3'; import * as s3ObjectLambda from 'aws-cdk-lib/aws-s3objectlambda'; -import { Construct } from 'constructs'; // configurable variables const S3_ACCESS_POINT_NAME = 'example-test-ap'; @@ -74,23 +74,27 @@ export class S3ObjectLambdaStack extends pulumicdk.Stack { const policyStatement = new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: ['s3:GetObject'], - principals: [new iam.ArnPrincipal(retrieveTransformedObjectLambda.role?.roleArn)], - resources: [`${accessPoint}/object/*`], + principals: [ + new iam.ArnPrincipal(this.asOutput(retrieveTransformedObjectLambda.role?.roleArn) as unknown as string), + ], + resources: [this.asOutput(`${accessPoint}/object/*`) as unknown as string], }); policyStatement.sid = 'AllowLambdaToUseAccessPoint'; policyDoc.addStatements(policyStatement); - new s3.CfnAccessPoint(this, 'exampleBucketAP', { - bucket: bucket.bucketName, + const ap = new aws.s3.AccessPoint('exampleBucketAP', { + // CDK property can be passed to a Pulumi resource + bucket: this.asOutput(bucket.bucketName), name: S3_ACCESS_POINT_NAME, - policy: policyDoc, + policy: policyDoc.toJSON(), }); // Access point to receive GET request and use lambda to process objects const objectLambdaAP = new s3ObjectLambda.CfnAccessPoint(this, 's3ObjectLambdaAP', { name: OBJECT_LAMBDA_ACCESS_POINT_NAME, objectLambdaConfiguration: { - supportingAccessPoint: accessPoint, + // a pulumi resource property can be passed to a cdk resource + supportingAccessPoint: pulumicdk.asString(ap.arn), transformationConfigurations: [ { actions: ['GetObject'], diff --git a/src/assembly/manifest.ts b/src/assembly/manifest.ts index 00046f41..479ee2d3 100644 --- a/src/assembly/manifest.ts +++ b/src/assembly/manifest.ts @@ -62,7 +62,6 @@ export class AssemblyManifestReader { private renderStackManifests() { for (const [artifactId, artifact] of Object.entries(this.manifest.artifacts ?? {})) { if (artifact.type === ArtifactType.AWS_CLOUDFORMATION_STACK) { - const metadata: StackMetadata = {}; if (!artifact.properties || !('templateFile' in artifact.properties)) { throw new Error('Invalid CloudFormation artifact. Cannot find the template file'); } @@ -75,15 +74,8 @@ export class AssemblyManifestReader { throw new Error(`Failed to read CloudFormation template at path: ${templateFile}: ${e}`); } - for (const [metadataId, metadataEntry] of Object.entries(artifact.metadata ?? {})) { - metadataEntry.forEach((meta) => { - if (meta.type === ArtifactMetadataEntryType.LOGICAL_ID) { - // For some reason the metadata entry prefixes the path with a `/` - const path = metadataId.startsWith('/') ? metadataId.substring(1) : metadataId; - metadata[path] = meta.data as LogicalIdMetadataEntry; - } - }); - } + const metadata = this.getMetadata(artifact); + const assets = this.getAssetsForStack(artifactId); if (!this.tree.children) { throw new Error('Invalid tree.json found'); @@ -103,6 +95,26 @@ export class AssemblyManifestReader { } } + /** + * Creates a metadata map of constructPath to logicalId for all resources in the stack + * + * @param artifact - The manifest containing the stack metadata + * @returns The StackMetadata lookup table + */ + private getMetadata(artifact: ArtifactManifest): StackMetadata { + const metadata: StackMetadata = {}; + for (const [metadataId, metadataEntry] of Object.entries(artifact.metadata ?? {})) { + metadataEntry.forEach((meta) => { + if (meta.type === ArtifactMetadataEntryType.LOGICAL_ID) { + // For some reason the metadata entry prefixes the path with a `/` + const path = metadataId.startsWith('/') ? metadataId.substring(1) : metadataId; + metadata[path] = meta.data as LogicalIdMetadataEntry; + } + }); + } + return metadata; + } + /** * Get the stacks from the Cloud Assembly * diff --git a/src/assembly/types.ts b/src/assembly/types.ts index c9579830..f930422f 100644 --- a/src/assembly/types.ts +++ b/src/assembly/types.ts @@ -1,4 +1,5 @@ import { ConstructInfo } from 'aws-cdk-lib/core/lib/private/runtime-info'; +import { Node } from 'aws-cdk-lib/core/lib/private/tree-metadata'; import { DockerImageManifestEntry, FileManifestEntry } from 'cdk-assets'; export type StackAsset = FileManifestEntry | DockerImageManifestEntry; @@ -10,36 +11,5 @@ export type StackMetadata = { [path: string]: string }; /** * ConstructTree is a tree of the current CDK construct - * It represents the structure in the `tree.json` file and is based - * off the implementation here: - * https://github.com/aws/aws-cdk/blob/4bce941fc680ebd396569383f6cf07527541dcc2/packages/aws-cdk-lib/core/lib/private/tree-metadata.ts?plain=1#L177 */ -export interface ConstructTree { - /** - * The id of the construct - */ - readonly id: string; - - /** - * The path to the construct in the tree, i.e. `parentConstructId/constructId` - */ - readonly path: string; - - /** - * The parent construct in the tree. - * Will be undefined if this is the root construct - */ - readonly parent?: ConstructTree; - - /** - * Any children construct in the tree - */ - readonly children?: { [key: string]: ConstructTree }; - - /** - * Attributes of the construct - */ - readonly attributes?: { [key: string]: any }; - - readonly constructInfo?: ConstructInfo; -} +export type ConstructTree = Node; diff --git a/src/converters/app-converter.ts b/src/converters/app-converter.ts index 09659d11..f4b5a36c 100644 --- a/src/converters/app-converter.ts +++ b/src/converters/app-converter.ts @@ -69,7 +69,6 @@ export class StackConverter extends ArtifactConverter { readonly parameters = new Map(); readonly resources = new Map>(); readonly constructs = new Map(); - stackResource!: CdkConstruct; constructor(host: StackComponentResource, readonly stack: StackManifest) { super(host); @@ -85,7 +84,7 @@ export class StackConverter extends ArtifactConverter { for (const n of dependencyGraphNodes) { if (n.construct.id === this.stack.id) { - this.stackResource = new CdkConstruct( + const stackResource = new CdkConstruct( `${this.stackComponent.name}/${n.construct.path}`, n.construct.id, { @@ -97,7 +96,7 @@ export class StackConverter extends ArtifactConverter { dependsOn: this.stackDependsOn(dependencies), }, ); - this.constructs.set(n.construct, this.stackResource); + this.constructs.set(n.construct, stackResource); continue; } diff --git a/src/graph.ts b/src/graph.ts index 829abd6a..31b2a5e8 100644 --- a/src/graph.ts +++ b/src/graph.ts @@ -142,9 +142,9 @@ export class GraphBuilder { node.logicalId = logicalId; this.cfnElementNodes.set(logicalId, node); } else { - console.error('SOMETHING WENT WRONG: ', tree); - // TODO: - // Something went wrong... + throw new Error( + `Something went wrong: resourceType ${resource.Type} does not equal CfnType ${cfnType}`, + ); } } this.constructNodes.set(construct, node); diff --git a/src/index.ts b/src/index.ts index e5670ec1..2fa2557c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,4 +17,4 @@ export * from './output'; import * as interop from './interop'; export { interop }; -export * from './types'; +export { StackOptions } from './types';