Skip to content

Commit 0695c1e

Browse files
so0kclaude
andcommitted
fix(lib): restrict ephemeral resource lifecycle to pre/postconditions
Terraform ephemeral blocks support only precondition/postcondition in lifecycle — createBeforeDestroy, preventDestroy, ignoreChanges and replaceTriggeredBy are state-oriented concepts that do not apply to stateless ephemeral resources. New TerraformEphemeralResourceLifecycle replaces the full TerraformResourceLifecycle on the ephemeral API; narrowing later would be jsii-breaking, so it lands before first release. Found in draft-PR verification (#296 review notes). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 914f3c3 commit 0695c1e

2 files changed

Lines changed: 66 additions & 4 deletions

File tree

packages/cdktn/src/terraform-ephemeral-resource.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import { TerraformElement } from "./terraform-element";
66
import { TerraformProvider } from "./terraform-provider";
77
import {
88
TerraformProviderGeneratorMetadata,
9-
TerraformResourceLifecycle,
109
lifecycleToTerraform,
1110
} from "./terraform-resource";
11+
import { Precondition, Postcondition } from "./terraform-conditions";
1212
import {
1313
keysToSnakeCase,
1414
deepMerge,
@@ -40,6 +40,18 @@ const EPHEMERAL_RESOURCES_HINT = `Ephemeral resources are available in ${Object.
4040
.map(([product, range]) => `${product} ${range}`)
4141
.join(" and ")}.`;
4242

43+
/**
44+
* Lifecycle options supported by Terraform ephemeral blocks. Unlike managed
45+
* resources, ephemeral resources have no state, so Terraform only supports
46+
* `precondition`/`postcondition` here - `createBeforeDestroy`,
47+
* `preventDestroy`, `ignoreChanges`, and `replaceTriggeredBy` are all
48+
* state-oriented concepts that do not apply.
49+
*/
50+
export interface TerraformEphemeralResourceLifecycle {
51+
readonly precondition?: Precondition[];
52+
readonly postcondition?: Postcondition[];
53+
}
54+
4355
export interface ITerraformEphemeralResource {
4456
readonly terraformResourceType: string;
4557
readonly fqn: string;
@@ -48,7 +60,7 @@ export interface ITerraformEphemeralResource {
4860
dependsOn?: string[];
4961
count?: number | TerraformCount;
5062
provider?: TerraformProvider;
51-
lifecycle?: TerraformResourceLifecycle;
63+
lifecycle?: TerraformEphemeralResourceLifecycle;
5264
forEach?: ITerraformIterator;
5365

5466
interpolationForAttribute(terraformAttribute: string): IResolvable;
@@ -62,7 +74,7 @@ export interface TerraformEphemeralMetaArguments {
6274
readonly dependsOn?: ITerraformDependable[];
6375
readonly count?: number | TerraformCount;
6476
readonly provider?: TerraformProvider;
65-
readonly lifecycle?: TerraformResourceLifecycle;
77+
readonly lifecycle?: TerraformEphemeralResourceLifecycle;
6678
readonly forEach?: ITerraformIterator;
6779
}
6880

@@ -87,7 +99,7 @@ export class TerraformEphemeralResource
8799
public dependsOn?: string[];
88100
public count?: number | TerraformCount;
89101
public provider?: TerraformProvider;
90-
public lifecycle?: TerraformResourceLifecycle;
102+
public lifecycle?: TerraformEphemeralResourceLifecycle;
91103
public forEach?: ITerraformIterator;
92104

93105
constructor(

packages/cdktn/test/terraform-ephemeral-resource.test.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,56 @@ test("renders an ephemeral HCL block", () => {
9595
`);
9696
});
9797

98+
test("renders a precondition lifecycle block", () => {
99+
const app = Testing.app();
100+
const stack = new TerraformStack(app, "test");
101+
new TestProvider(stack, "provider", {});
102+
103+
new TestEphemeralResource(stack, "test", {
104+
name: "foo",
105+
lifecycle: {
106+
precondition: [
107+
{
108+
condition: '${var.foo != ""}',
109+
errorMessage: "foo must not be empty",
110+
},
111+
],
112+
},
113+
});
114+
115+
expect(Testing.synth(stack)).toMatchInlineSnapshot(`
116+
"{
117+
"ephemeral": {
118+
"test_ephemeral": {
119+
"test": {
120+
"lifecycle": {
121+
"precondition": [
122+
{
123+
"condition": "\${var.foo != \\"\\"}",
124+
"error_message": "foo must not be empty"
125+
}
126+
]
127+
},
128+
"name": "foo"
129+
}
130+
}
131+
},
132+
"provider": {
133+
"test": [
134+
{}
135+
]
136+
},
137+
"terraform": {
138+
"required_providers": {
139+
"test": {
140+
"version": "~> 2.0"
141+
}
142+
}
143+
}
144+
}"
145+
`);
146+
});
147+
98148
test("interpolationForAttribute produces ephemeral.-prefixed references", () => {
99149
const app = Testing.app();
100150
const stack = new TerraformStack(app, "test");

0 commit comments

Comments
 (0)