@fjall/components-infrastructure 2.16.0 → 2.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/resources/aws/compute/ec2GracefulTerminationHandler.js +13 -3
- package/dist/lib/resources/aws/compute/persistentDataVolume.js +5 -1
- package/dist/lib/resources/aws/messaging/sns.d.ts +5 -0
- package/dist/lib/resources/aws/messaging/sns.js +7 -1
- package/dist/lib/resources/aws/messaging/sqs.d.ts +6 -0
- package/dist/lib/resources/aws/messaging/sqs.js +10 -2
- package/package.json +4 -4
|
@@ -43,8 +43,13 @@ export class Ec2GracefulTerminationHandler extends Construct {
|
|
|
43
43
|
const dataVolumeOwnerLogicalId = resolveOptionalString(props.dataVolumeOwnerLogicalId);
|
|
44
44
|
this.queue = new SQSQueue(this, `${id}Queue`, {
|
|
45
45
|
visibilityTimeout: QUEUE_VISIBILITY_TIMEOUT_SECONDS,
|
|
46
|
-
deadLetterQueue: { enabled: true, maxReceiveCount: 5 }
|
|
46
|
+
deadLetterQueue: { enabled: true, maxReceiveCount: 5 },
|
|
47
|
+
// Transient instance-drain signals — no durable state. Pinned DESTROY
|
|
48
|
+
// (now also the SQSQueue wrapper default) so a replacing deploy of the
|
|
49
|
+
// parent Ec2Instance reclaims this queue + DLQ instead of orphaning them.
|
|
50
|
+
removalPolicy: "DESTROY"
|
|
47
51
|
});
|
|
52
|
+
const stack = Stack.of(this);
|
|
48
53
|
const ecsPolicies = ecsClusterArn !== undefined
|
|
49
54
|
? [
|
|
50
55
|
new PolicyStatement({
|
|
@@ -66,6 +71,9 @@ export class Ec2GracefulTerminationHandler extends Construct {
|
|
|
66
71
|
})
|
|
67
72
|
]
|
|
68
73
|
: [];
|
|
74
|
+
// EIP/ENI mutations cannot be ARN-scoped (the resources are not known at
|
|
75
|
+
// synth), but the Lambda only ever drains instances in its own region — a
|
|
76
|
+
// region clamp removes the cross-region blast radius a bare "*" would allow.
|
|
69
77
|
const ec2Policies = new PolicyStatement({
|
|
70
78
|
effect: Effect.ALLOW,
|
|
71
79
|
actions: [
|
|
@@ -74,7 +82,10 @@ export class Ec2GracefulTerminationHandler extends Construct {
|
|
|
74
82
|
"ec2:DescribeNetworkInterfaces",
|
|
75
83
|
"ec2:DetachNetworkInterface"
|
|
76
84
|
],
|
|
77
|
-
resources: ["*"]
|
|
85
|
+
resources: ["*"],
|
|
86
|
+
conditions: {
|
|
87
|
+
StringEquals: { "aws:RequestedRegion": stack.region }
|
|
88
|
+
}
|
|
78
89
|
});
|
|
79
90
|
const elbReadPolicy = new PolicyStatement({
|
|
80
91
|
effect: Effect.ALLOW,
|
|
@@ -94,7 +105,6 @@ export class Ec2GracefulTerminationHandler extends Construct {
|
|
|
94
105
|
}
|
|
95
106
|
}
|
|
96
107
|
});
|
|
97
|
-
const stack = Stack.of(this);
|
|
98
108
|
// Account/region-scoped wildcard rather than the specific ASG ARN —
|
|
99
109
|
// see PersistentDataVolume for the full deadlock writeup. Same gotcha:
|
|
100
110
|
// a specific ARN creates a CFN Ref to the ASG, the Lambda's IAM Policy
|
|
@@ -105,7 +105,11 @@ export class PersistentDataVolume extends Construct {
|
|
|
105
105
|
Tags.of(this.volume).add(PERSISTENT_DATA_VOLUME_TAG_STACK_ID, Aws.STACK_ID);
|
|
106
106
|
this.queue = new SQSQueue(this, `${id}Queue`, {
|
|
107
107
|
visibilityTimeout: QUEUE_VISIBILITY_TIMEOUT_SECONDS,
|
|
108
|
-
deadLetterQueue: { enabled: true, maxReceiveCount: 5 }
|
|
108
|
+
deadLetterQueue: { enabled: true, maxReceiveCount: 5 },
|
|
109
|
+
// Transient volume-attach signals — no durable state (the EBS volume
|
|
110
|
+
// itself is SNAPSHOT above). Pinned DESTROY (now also the SQSQueue wrapper
|
|
111
|
+
// default) so a replacing deploy reclaims this queue + DLQ, not orphans.
|
|
112
|
+
removalPolicy: "DESTROY"
|
|
109
113
|
});
|
|
110
114
|
const sourcePath = path.resolve(__dirname, LAUNCHING_LAMBDA_SOURCE_FILE);
|
|
111
115
|
const source = readFileSync(sourcePath, "utf-8");
|
|
@@ -7,6 +7,11 @@ export interface SNSTopicProps {
|
|
|
7
7
|
displayName?: string;
|
|
8
8
|
fifo?: boolean;
|
|
9
9
|
contentBasedDeduplication?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Removal policy for the topic. Defaults to DESTROY — a topic is a transient
|
|
12
|
+
* fan-out medium with no durable state (see the constructor). Pass "RETAIN"
|
|
13
|
+
* only for a topic that must survive stack deletion.
|
|
14
|
+
*/
|
|
10
15
|
removalPolicy?: RemovalPolicyString;
|
|
11
16
|
}
|
|
12
17
|
export declare class SNSTopic extends Construct {
|
|
@@ -22,7 +22,13 @@ export class SNSTopic extends Construct {
|
|
|
22
22
|
? (props.contentBasedDeduplication ?? true)
|
|
23
23
|
: undefined
|
|
24
24
|
});
|
|
25
|
-
|
|
25
|
+
// An SNS topic is a transient fan-out medium: it holds no durable state
|
|
26
|
+
// (subscriptions are re-created by the next deploy), so the wrapper defaults
|
|
27
|
+
// to DESTROY — deliberately NOT the env-aware production->RETAIN of
|
|
28
|
+
// data-bearing wrappers (S3, EventBus). RETAIN here buys no protection and
|
|
29
|
+
// orphans the topic on a parent construct's logical-ID churn (the same leak
|
|
30
|
+
// class fixed for SQS). Durable topics opt into RETAIN via props.removalPolicy.
|
|
31
|
+
this.topic.applyRemovalPolicy(toRemovalPolicy(props.removalPolicy ?? "DESTROY"));
|
|
26
32
|
new CfnOutput(this, `${id}TopicArn`, {
|
|
27
33
|
key: `${id}TopicArn`,
|
|
28
34
|
value: this.topic.topicArn,
|
|
@@ -60,6 +60,12 @@ export interface SQSQueueProps {
|
|
|
60
60
|
contentBasedDeduplication?: boolean;
|
|
61
61
|
fifoThroughputLimit?: "perQueue" | "perMessageGroupId";
|
|
62
62
|
deduplicationScope?: "queue" | "messageGroup";
|
|
63
|
+
/**
|
|
64
|
+
* Removal policy for the queue (and its auto-created DLQ, which tracks it).
|
|
65
|
+
* Defaults to DESTROY — a queue is a transient work medium (see the
|
|
66
|
+
* constructor). Pass "RETAIN" only for a queue whose contents are
|
|
67
|
+
* irreplaceable and must survive stack deletion.
|
|
68
|
+
*/
|
|
63
69
|
removalPolicy?: RemovalPolicyString;
|
|
64
70
|
}
|
|
65
71
|
export declare class SQSQueue extends Construct {
|
|
@@ -83,6 +83,14 @@ export class SQSQueue extends Construct {
|
|
|
83
83
|
this.id = id;
|
|
84
84
|
// Sanitise id for CloudFormation output keys (must be alphanumeric)
|
|
85
85
|
const outputName = toPascalCase(id);
|
|
86
|
+
// SQS queues are transient work mediums: their contents (job messages,
|
|
87
|
+
// failed-delivery copies) regenerate from a source of truth held elsewhere
|
|
88
|
+
// (Postgres, the producing schedule/rule), so the wrapper defaults to
|
|
89
|
+
// DESTROY — deliberately NOT the env-aware production->RETAIN of
|
|
90
|
+
// data-bearing wrappers (S3, EventBus). RETAIN here buys no protection and
|
|
91
|
+
// orphans the queue on a parent construct's logical-ID churn (the prod
|
|
92
|
+
// orphan leak). Durable queues opt into RETAIN via props.removalPolicy.
|
|
93
|
+
const resolvedRemovalPolicy = toRemovalPolicy(props.removalPolicy ?? "DESTROY");
|
|
86
94
|
const isFifo = props.queueType === "fifo";
|
|
87
95
|
const queueName = props.queueName
|
|
88
96
|
? isFifo
|
|
@@ -110,7 +118,7 @@ export class SQSQueue extends Construct {
|
|
|
110
118
|
fifo: isFifo,
|
|
111
119
|
encryption: toEncryption(props.encryption),
|
|
112
120
|
retentionPeriod: Duration.days(SQS_LIMITS.DEAD_LETTER_QUEUE.DEFAULT_RETENTION_DAYS),
|
|
113
|
-
removalPolicy:
|
|
121
|
+
removalPolicy: resolvedRemovalPolicy
|
|
114
122
|
});
|
|
115
123
|
deadLetterQueue = {
|
|
116
124
|
queue: this.dlq,
|
|
@@ -156,7 +164,7 @@ export class SQSQueue extends Construct {
|
|
|
156
164
|
deduplicationScope: isFifo
|
|
157
165
|
? toDeduplicationScope(props.deduplicationScope)
|
|
158
166
|
: undefined,
|
|
159
|
-
removalPolicy:
|
|
167
|
+
removalPolicy: resolvedRemovalPolicy
|
|
160
168
|
});
|
|
161
169
|
new CfnOutput(this, `${outputName}QueueUrl`, {
|
|
162
170
|
key: `${outputName}QueueUrl`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fjall/components-infrastructure",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.17.0",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -63,8 +63,8 @@
|
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
65
|
"@aws-sdk/client-organizations": "^3.1038.0",
|
|
66
|
-
"@fjall/generator": "^2.
|
|
67
|
-
"@fjall/util": "^2.
|
|
66
|
+
"@fjall/generator": "^2.17.0",
|
|
67
|
+
"@fjall/util": "^2.17.0",
|
|
68
68
|
"constructs": "^10.0.0",
|
|
69
69
|
"uuid": "^14.0.0"
|
|
70
70
|
},
|
|
@@ -79,5 +79,5 @@
|
|
|
79
79
|
"engines": {
|
|
80
80
|
"node": ">=18.0.0"
|
|
81
81
|
},
|
|
82
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "21cfe1aae339e12183af2813ec81f581b9b77d49"
|
|
83
83
|
}
|