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

Add ability to specify resource options at the stack level #245

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
79 changes: 79 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,85 @@ const app = new pulumicdk.App('app', (scope: pulumicdk.App) => {
});
```

### Stack Level Providers

It is also possible to customize the Providers at the Stack level. This can be
useful in cases where you need to deploy resources to different AWS regions.

```ts
const awsProvider = new aws.Provider('aws-provider');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

examples are better with imports I think, if not too hard. To see where aws is coming from.

const awsCCAPIProvider = new ccapi.Provider('ccapi-provider', {
// enable autoNaming
autoNaming: {
autoTrim: true,
randomSuffixMinLength: 7,
}
});

const app = new pulumicdk.App('app', (scope: pulumicdk.App) => {
// inherits the provider from the app
const defaultProviderStack = new pulumicdk.Stack('default-provider-stack');
const bucket = new s3.Bucket(defaultProviderStack, 'Bucket');

// use a different provider for this stack
const east2Stack = new pulumicdk.Stack('east2-stack', {
providers: [
new aws.Provider('east2-provider', { region: 'us-east-2' }),
new ccapi.Provider('east2-ccapi-provider', {
region: 'us-east-2',
autoNaming: {
autoTrim: true,
randomSuffixMinLength: 7,
},
}),
],
});
const bucket2 = new s3.Bucket(east2Stack, 'Bucket');
}, {
providers: [
dockerBuildProvider,
awsProvider,
awsCCAPIProvider,
]
});
```

One thing to note is that when you pass different custom providers to a Stack,
by default the Stack becomes an [environment agnostic stack](https://docs.aws.amazon.com/cdk/v2/guide/configure-env.html#configure-env-examples).
If you want to have the environment specified at the CDK Stack level, then you
also need to provide the environment to the Stack Props.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stack Props, as follows:


```ts
const app = new pulumicdk.App('app', (scope: pulumicdk.App) => {
// inherits the provider from the app and has the CDK env auto populated
// based on the default provider
const defaultProviderStack = new pulumicdk.Stack('default-provider-stack');
const bucket = new s3.Bucket(defaultProviderStack, 'Bucket');

// use a different provider for this stack
const east2Stack = new pulumicdk.Stack('east2-stack', {
props: {
env: {
region: 'us-east-2',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I understand now the comment you had regarding not being able to pass a pulumi.Output region in here automatically.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was looking at IResolvable but it's unclear that that's allowed to return promises to CDK.

account: '12345678912',
},
},
providers: [
new aws.Provider('east2-provider', { region: 'us-east-2' }),
new ccapi.Provider('east2-ccapi-provider', {
region: 'us-east-2',
autoNaming: {
autoTrim: true,
randomSuffixMinLength: 7,
},
}),
],
});
const bucket2 = new s3.Bucket(east2Stack, 'Bucket');
});

```

## CDK Lookups

CDK [lookups](https://docs.aws.amazon.com/cdk/v2/guide/context.html#context_methods) are currently disabled by default.
Expand Down
70 changes: 63 additions & 7 deletions api-docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,45 @@ export const bucket = app.outputs['bucket'];

###### Defined in

[stack.ts:96](https://github.com/pulumi/pulumi-cdk/blob/main/src/stack.ts#L96)
[stack.ts:105](https://github.com/pulumi/pulumi-cdk/blob/main/src/stack.ts#L105)

#### Properties

| Property | Modifier | Type | Default value | Description | Defined in |
| ------ | ------ | ------ | ------ | ------ | ------ |
| `name` | `readonly` | `string` | `undefined` | The name of the component | [stack.ts:55](https://github.com/pulumi/pulumi-cdk/blob/main/src/stack.ts#L55) |
| `outputs` | `public` | `object` | `{}` | The collection of outputs from the AWS CDK Stack represented as Pulumi Outputs. Each CfnOutput defined in the AWS CDK Stack will populate a value in the outputs. | [stack.ts:61](https://github.com/pulumi/pulumi-cdk/blob/main/src/stack.ts#L61) |
| `name` | `readonly` | `string` | `undefined` | The name of the component | [stack.ts:57](https://github.com/pulumi/pulumi-cdk/blob/main/src/stack.ts#L57) |
| `outputs` | `public` | `object` | `{}` | The collection of outputs from the AWS CDK Stack represented as Pulumi Outputs. Each CfnOutput defined in the AWS CDK Stack will populate a value in the outputs. | [stack.ts:63](https://github.com/pulumi/pulumi-cdk/blob/main/src/stack.ts#L63) |

#### Accessors

##### env

###### Get Signature

> **get** **env**(): `Environment`

This can be used to get the CDK Environment based on the Pulumi Provider used for the App.
You can then use this to configure an explicit environment on Stacks.

###### Example

```ts
const app = new pulumicdk.App('app', (scope: pulumicdk.App) => {
const stack = new pulumicdk.Stack(scope, 'pulumi-stack', {
props: { env: app.env },
});
});
```

###### Returns

`Environment`

the CDK Environment configured for the App

###### Defined in

[stack.ts:155](https://github.com/pulumi/pulumi-cdk/blob/main/src/stack.ts#L155)

***

Expand Down Expand Up @@ -121,7 +152,7 @@ Create and register an AWS CDK stack deployed with Pulumi.

###### Defined in

[stack.ts:264](https://github.com/pulumi/pulumi-cdk/blob/main/src/stack.ts#L264)
[stack.ts:336](https://github.com/pulumi/pulumi-cdk/blob/main/src/stack.ts#L336)

#### Methods

Expand Down Expand Up @@ -151,7 +182,7 @@ A Pulumi Output value.

###### Defined in

[stack.ts:277](https://github.com/pulumi/pulumi-cdk/blob/main/src/stack.ts#L277)
[stack.ts:418](https://github.com/pulumi/pulumi-cdk/blob/main/src/stack.ts#L418)

## Interfaces

Expand Down Expand Up @@ -233,6 +264,31 @@ Options specific to the Pulumi CDK App component.

Options for creating a Pulumi CDK Stack

Any Pulumi resource options provided at the Stack level will override those configured
at the App level

#### Example

```ts
new App('testapp', (scope: App) => {
// This stack will inherit the options from the App
new Stack(scope, 'teststack1');

// Override the options for this stack
new Stack(scope, 'teststack', {
providers: [
new native.Provider('custom-provider', { region: 'us-east-1' }),
],
props: { env: { region: 'us-east-1' } },
})
}, {
providers: [
new native.Provider('app-provider', { region: 'us-west-2' }),
]

})
```

#### Extends

- `ComponentResourceOptions`
Expand All @@ -241,7 +297,7 @@ Options for creating a Pulumi CDK Stack

| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `props?` | `StackProps` | The CDK Stack props | [stack.ts:230](https://github.com/pulumi/pulumi-cdk/blob/main/src/stack.ts#L230) |
| `props?` | `StackProps` | The CDK Stack props | [stack.ts:295](https://github.com/pulumi/pulumi-cdk/blob/main/src/stack.ts#L295) |

## Type Aliases

Expand All @@ -255,7 +311,7 @@ Options for creating a Pulumi CDK Stack

#### Defined in

[stack.ts:24](https://github.com/pulumi/pulumi-cdk/blob/main/src/stack.ts#L24)
[stack.ts:26](https://github.com/pulumi/pulumi-cdk/blob/main/src/stack.ts#L26)

## Functions

Expand Down
65 changes: 65 additions & 0 deletions examples/examples_nodejs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,71 @@ func TestScalableWebhook(t *testing.T) {
integration.ProgramTest(t, &test)
}

func TestStackProvider(t *testing.T) {
// App will use default provider and one stack will use explicit provider
// with region=us-east-1
t.Run("With default env", func(t *testing.T) {
test := getJSBaseOptions(t).
With(integration.ProgramTestOptions{
Dir: filepath.Join(getCwd(t), "stack-provider"),
ExtraRuntimeValidation: func(t *testing.T, stack integration.RuntimeValidationStackInfo) {
east1LogsRegion := stack.Outputs["east1LogsRegion"].(string)
defaultLogsRegion := stack.Outputs["defaultLogsRegion"].(string)
east1StackRegion := stack.Outputs["east1StackRegion"].(string)
defaultStackRegion := stack.Outputs["defaultStackRegion"].(string)
assert.Equalf(t, "us-east-1", east1LogsRegion, "Expected east1LogsRegion to be us-east-1, got %s", east1LogsRegion)
assert.Equalf(t, "us-east-2", defaultLogsRegion, "Expected defaultLogsRegion to be us-east-2, got %s", defaultLogsRegion)
assert.Equalf(t, "us-east-1", east1StackRegion, "Expected east1StackRegion to be us-east-1, got %s", east1StackRegion)
assert.Equalf(t, "us-east-2", defaultStackRegion, "Expected defaultStackRegion to be us-east-2, got %s", defaultStackRegion)
},
})

integration.ProgramTest(t, &test)
})

// App will use a custom explicit provider and one stack will use explicit provider
// with region=us-east-1
t.Run("With different env", func(t *testing.T) {
test := getJSBaseOptions(t).
With(integration.ProgramTestOptions{
Dir: filepath.Join(getCwd(t), "stack-provider"),
Config: map[string]string{
"default-region": "us-west-2",
},
ExtraRuntimeValidation: func(t *testing.T, stack integration.RuntimeValidationStackInfo) {
east1LogsRegion := stack.Outputs["east1LogsRegion"].(string)
defaultLogsRegion := stack.Outputs["defaultLogsRegion"].(string)
east1StackRegion := stack.Outputs["east1StackRegion"].(string)
defaultStackRegion := stack.Outputs["defaultStackRegion"].(string)
assert.Equalf(t, "us-east-1", east1LogsRegion, "Expected east1LogsRegion to be us-east-1, got %s", east1LogsRegion)
assert.Equalf(t, "us-west-2", defaultLogsRegion, "Expected defaultLogsRegion to be us-west-2, got %s", defaultLogsRegion)
assert.Equalf(t, "us-east-1", east1StackRegion, "Expected east1StackRegion to be us-east-1, got %s", east1StackRegion)
assert.Equalf(t, "us-west-2", defaultStackRegion, "Expected defaultStackRegion to be us-west-2, got %s", defaultStackRegion)
},
})

integration.ProgramTest(t, &test)
})

t.Run("Fails with different cdk env", func(t *testing.T) {
var output bytes.Buffer
test := getJSBaseOptions(t).
With(integration.ProgramTestOptions{
Dir: filepath.Join(getCwd(t), "stack-provider"),
Stderr: &output,
ExpectFailure: true,
Config: map[string]string{
"cdk-region": "us-east-2",
},
ExtraRuntimeValidation: func(t *testing.T, stack integration.RuntimeValidationStackInfo) {
assert.Contains(t, output.String(), "The stack 'teststack' has conflicting regions between the native provider (us-east-1) and the stack environment (us-east-2)")
},
})

integration.ProgramTest(t, &test)
})
}

func TestTheBigFan(t *testing.T) {
test := getJSBaseOptions(t).
With(integration.ProgramTestOptions{
Expand Down
5 changes: 1 addition & 4 deletions examples/lookups-enabled/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as aws from '@pulumi/aws';
import * as pulumi from '@pulumi/pulumi';
import * as pulumicdk from '@pulumi/cdk';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
Expand All @@ -12,14 +11,12 @@ import {

const config = new pulumi.Config();
const zoneName = config.require('zoneName');
const accountId = config.require('accountId');
const region = aws.config.requireRegion();

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

Expand Down
3 changes: 3 additions & 0 deletions examples/stack-provider/Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: pulumi-stack-provider
runtime: nodejs
description: A minimal TypeScript Pulumi program
70 changes: 70 additions & 0 deletions examples/stack-provider/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import * as logs from 'aws-cdk-lib/aws-logs';
import * as pulumi from '@pulumi/pulumi';
import * as pulumicdk from '@pulumi/cdk';
import * as native from '@pulumi/aws-native';
import { RemovalPolicy } from 'aws-cdk-lib';

const config = new pulumi.Config();
const cdkRegion = config.get('cdk-region');
const cdkAccount = config.get('cdk-account');
const defaultRegion = config.get('default-region');

export class StackProviderStack extends pulumicdk.Stack {
public readonly logsRegion: pulumi.Output<string>;
constructor(app: pulumicdk.App, id: string, providers?: pulumi.ProviderResource[]) {
super(app, id, {
providers,
props:
cdkRegion || cdkAccount
? {
env: {
region: cdkRegion,
account: cdkAccount,
},
}
: undefined,
});

const group = new logs.LogGroup(this, 'group', {
retention: logs.RetentionDays.ONE_DAY,
removalPolicy: RemovalPolicy.DESTROY,
});

this.logsRegion = this.asOutput(group.logGroupArn).apply((arn) => arn.split(':')[3]);
}
}

const app = new pulumicdk.App(
'app',
(scope: pulumicdk.App) => {
const stack = new StackProviderStack(scope, 'teststack', [
new native.Provider('ccapi-provider', {
region: 'us-east-1', // a different region from the app provider
}),
]);
const defaultStack = new StackProviderStack(scope, 'default-stack');
return {
east1LogsRegion: stack.logsRegion,
east1StackRegion: stack.asOutput(stack.region),
defaultLogsRegion: defaultStack.logsRegion,
defaultStackRegion: defaultStack.asOutput(defaultStack.region),
};
},
{
providers: defaultRegion
? [
new native.Provider('app-provider', {
region: defaultRegion as native.Region, // a different region from the default env
}),
]
: undefined,
},
);

// You can (we check for this though) configure a different region on the provider
// that the stack uses vs the region in the CDK StackProps. This tests checks that both the
// stack region and the region the resources are deployed to are the same.
export const east1LogsRegion = app.outputs['east1LogsRegion'];
export const defaultLogsRegion = app.outputs['defaultLogsRegion'];
export const east1StackRegion = app.outputs['east1StackRegion'];
export const defaultStackRegion = app.outputs['defaultStackRegion'];
13 changes: 13 additions & 0 deletions examples/stack-provider/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "pulumi-aws-cdk",
"devDependencies": {
"@types/node": "^10.0.0"
},
"dependencies": {
"@pulumi/aws": "^6.0.0",
"@pulumi/aws-native": "^1.9.0",
"@pulumi/cdk": "^0.5.0",
"aws-cdk-lib": "2.156.0",
"constructs": "10.3.0"
}
}
Loading