Reputation: 11831
I have an app that has two stacks, both within the same region/account. One of those stacks requires the ARN of a lambda that exists in the other stack. How do I reference this?
// within stackA constructor
public StackA(Construct scope, String id, StackProps props) {
SingletonFunction myLambda = SingletonFunction.Builder.create(this, "myLambda")
// some code here
.build()
CfnOutput myLambdaArn = CfnOutput.Builder.create(this, "myLambdaArn")
.exportName("myLambdaArn")
.description("ARN of the lambda that I want to use in StackB")
.value(myLambda.getFunctionArn())
.build();
}
App app = new App();
Stack stackA = new StackA(app, "stackA", someAProps);
Stack stackB = new StackB(app, "stackB", someBProps);
stackB.dependsOn(stackA);
How do pass the ARN into StackB?
Upvotes: 35
Views: 55680
Reputation: 1212
CDK's official documentation has a complete example for sharing a S3 bucket between stacks. I copied it below for quicker reference.
/**
* Stack that defines the bucket
*/
class Producer extends cdk.Stack {
public readonly myBucket: s3.Bucket;
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const bucket = new s3.Bucket(this, 'MyBucket', {
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
this.myBucket = bucket;
}
}
interface ConsumerProps extends cdk.StackProps {
userBucket: s3.IBucket;
}
/**
* Stack that consumes the bucket
*/
class Consumer extends cdk.Stack {
constructor(scope: cdk.App, id: string, props: ConsumerProps) {
super(scope, id, props);
const user = new iam.User(this, 'MyUser');
props.userBucket.grantReadWrite(user);
}
}
const producer = new Producer(app, 'ProducerStack');
new Consumer(app, 'ConsumerStack', { userBucket: producer.myBucket });
Upvotes: 38
Reputation: 11
On Alien Attack https://github.com/aws-samples/aws-alien-attack I created a class named ResourceAwareStack that extends Stack, and implements methods to add/get resources that can be shared between stacks. Take a look at it.
Upvotes: 1
Reputation: 1079
You can access resources in a different stack, as long as they are in the same account and AWS Region. The following example defines the stack stack1, which defines an Amazon S3 bucket. Then it defines a second stack, stack2, which takes the bucket from stack1 as a constructor property.
// Helper method to build an environment
static Environment makeEnv(String account, String region) {
return Environment.builder().account(account).region(region)
.build();
}
App app = new App();
Environment prod = makeEnv("123456789012", "us-east-1");
StackThatProvidesABucket stack1 = new StackThatProvidesABucket(app, "Stack1",
StackProps.builder().env(prod).build());
// stack2 will take an argument "bucket"
StackThatExpectsABucket stack2 = new StackThatExpectsABucket(app, "Stack,",
StackProps.builder().env(prod).build(), stack1.getBucket());
Upvotes: 20
Reputation: 1637
I found all of the answers to be on the right path, but none explained it fully and/or well. In this example, I'm passing a VPC from a VPC stack to an ECS cluster.
First, add a property to the originating stack. This property is set whenever the asset is created:
export class VpcStack extends cdk.Stack {
readonly vpc: Vpc;
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Here
this.vpc = new Vpc(this, 'vpc', {
maxAzs: 3,
cidr: '10.0.0.0/16',
});
});
}
Next, require this property as a parameter to the consuming stack:
// Create an interface that extends cdk.StackProps
// The VPC property is added here
interface EcsClusterStackProps extends cdk.StackProps {
vpc: Vpc,
}
export class EcsClusterStack extends cdk.Stack {
// Use your interface instead of the regular cdk.StackProps
constructor(scope: cdk.Construct, id: string, props: EcsClusterStackProps) {
super(scope, id, props);
// Use the passed-in VPC where you need it
new Cluster(this, "myCluster", {
capacity: {
instanceType: InstanceType.of(InstanceClass.M6I, InstanceSize.LARGE)
},
clusterName: "myCluster",
vpc: props.vpc, // Here
});
}
}
Third, pass the reference in your app file:
const app = new cdk.App();
// Create the VPC stack
const vpcStack = new VpcStack(app, 'vpc-stack', {
env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
});
// Pass the VPC directly to the consuming stack's constructor
const ecsClusterStack = new EcsClusterStack(app, 'ecs-cluster-stack', {
vpc: vpcStack.vpc, // Here
});
Hopefully this helps clarify some of the ambiguous areas.
Upvotes: 8
Reputation: 8122
Option 1:
pass the data from Stack A to Stack B using the constructor :
You can extend cdk.stack
and create a new class that will contain stackA.
In that stack, expose the relevant data you want by using public XXX: string\number (etc)
( See line 2 in the example).
Later, just pass this data into StackB constructor ( you can pass it using props as well).
Working code snippet:
Stack A:
export class StackA extends cdk.Stack {
public YourKey: KEY_TYPE;
constructor(scope: cdk.Construct, id: string, props: cdk.StackProps ) {
super(scope, id, props);
Code goes here...
// Output the key
new cdk.CfnOutput(this, 'KEY', { value: this.YourKey });
}
}
Stack B:
export class StackB extends cdk.Stack {
constructor(scope: cdk.Construct, id: string,importedKey: KEY_TYPE, props: cdk.props) {
super(scope, id, props)
Code goes here...
console.log(importedKey)
}
}
bin ts:
const importedKey = new StackA(app, 'id',props).YourKey;
new StackB(app, 'id',importedKey,props);
Option 2:
Sometimes it's just better to save this kind of stuff in the parameter store and read it from there.
More info here.
Upvotes: 8