rds-database-auto-start-preventer 0.1.1

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.
@@ -0,0 +1,42 @@
1
+ import { Construct } from 'constructs';
2
+ /**
3
+ * Tag-based criteria to select which RDS instances or clusters are subject to auto-start prevention.
4
+ */
5
+ export interface TargetResource {
6
+ /** Tag key to match (e.g. "Environment", "AutoStartPrevent"). */
7
+ readonly tagKey: string;
8
+ /** Tag values that indicate the resource should be protected (e.g. ["production"]). */
9
+ readonly tagValues: string[];
10
+ }
11
+ /**
12
+ * External secrets required for notifications (e.g. Slack).
13
+ */
14
+ export interface Secrets {
15
+ /** Name of the Secrets Manager secret containing Slack token and channel. */
16
+ readonly slackSecretName: string;
17
+ }
18
+ /**
19
+ * Props for the RDS database auto-start preventer construct.
20
+ */
21
+ export interface RDSDatabaseAutoStartPreventerProps {
22
+ /** Tag-based target resource criteria for RDS instances/clusters to protect. */
23
+ readonly targetResource: TargetResource;
24
+ /** Whether the EventBridge rules are enabled. Defaults to true if omitted. */
25
+ readonly enableRule?: boolean;
26
+ /** Secrets used for notifications (e.g. Slack). */
27
+ readonly secrets: Secrets;
28
+ }
29
+ /**
30
+ * Construct that deploys EventBridge rules and a Durable Lambda to prevent RDS DB instances
31
+ * and clusters from staying running after an auto-start event (RDS-EVENT-0154 / RDS-EVENT-0153).
32
+ */
33
+ export declare class RDSDatabaseAutoStartPreventer extends Construct {
34
+ /**
35
+ * Creates the construct: Lambda (with Params and Secrets), EventBridge rules, and IAM.
36
+ *
37
+ * @param scope - Parent construct.
38
+ * @param id - Construct id.
39
+ * @param props - Target resource (tag key/values), enable rule flag, and secrets.
40
+ */
41
+ constructor(scope: Construct, id: string, props: RDSDatabaseAutoStartPreventerProps);
42
+ }
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ var _a;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.RDSDatabaseAutoStartPreventer = void 0;
5
+ const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
6
+ const aws_cdk_lib_1 = require("aws-cdk-lib");
7
+ const events = require("aws-cdk-lib/aws-events");
8
+ const targets = require("aws-cdk-lib/aws-events-targets");
9
+ const iam = require("aws-cdk-lib/aws-iam");
10
+ const lambda = require("aws-cdk-lib/aws-lambda");
11
+ const logs = require("aws-cdk-lib/aws-logs");
12
+ const aws_secretsmanager_1 = require("aws-cdk-lib/aws-secretsmanager");
13
+ const constructs_1 = require("constructs");
14
+ const auto_start_prevent_function_1 = require("../funcs/auto-start-prevent-function");
15
+ /**
16
+ * Construct that deploys EventBridge rules and a Durable Lambda to prevent RDS DB instances
17
+ * and clusters from staying running after an auto-start event (RDS-EVENT-0154 / RDS-EVENT-0153).
18
+ */
19
+ class RDSDatabaseAutoStartPreventer extends constructs_1.Construct {
20
+ /**
21
+ * Creates the construct: Lambda (with Params and Secrets), EventBridge rules, and IAM.
22
+ *
23
+ * @param scope - Parent construct.
24
+ * @param id - Construct id.
25
+ * @param props - Target resource (tag key/values), enable rule flag, and secrets.
26
+ */
27
+ constructor(scope, id, props) {
28
+ super(scope, id);
29
+ const slackSecret = aws_secretsmanager_1.Secret.fromSecretNameV2(this, 'SlackSecret', props.secrets.slackSecretName);
30
+ // Durable Functions-based Running Scheduler (previous Step Functions logic implemented in Lambda).
31
+ // Durable Execution requires Node.js 22+.
32
+ const autoStartPreventFunction = new auto_start_prevent_function_1.AutoStartPreventFunction(this, 'AutoStartPreventFunction', {
33
+ description: 'A function to prevent the RDS Database or Cluster from starting automatically.',
34
+ architecture: lambda.Architecture.ARM_64,
35
+ timeout: aws_cdk_lib_1.Duration.minutes(15),
36
+ memorySize: 512,
37
+ retryAttempts: 2,
38
+ durableConfig: {
39
+ executionTimeout: aws_cdk_lib_1.Duration.hours(2),
40
+ retentionPeriod: aws_cdk_lib_1.Duration.days(1),
41
+ },
42
+ environment: {
43
+ SLACK_SECRET_NAME: slackSecret.secretName,
44
+ },
45
+ paramsAndSecrets: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103, {
46
+ cacheSize: 500,
47
+ logLevel: lambda.ParamsAndSecretsLogLevel.INFO,
48
+ }),
49
+ role: new iam.Role(this, 'AutoStartPreventFunctionRole', {
50
+ description: 'A role to control the RDS Database or Cluster.',
51
+ assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
52
+ managedPolicies: [
53
+ iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'),
54
+ iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicDurableExecutionRolePolicy'),
55
+ ],
56
+ }),
57
+ logGroup: new logs.LogGroup(this, 'AutoStartPreventFunctionLogGroup', {
58
+ retention: logs.RetentionDays.THREE_MONTHS,
59
+ removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY,
60
+ }),
61
+ loggingFormat: lambda.LoggingFormat.JSON,
62
+ systemLogLevelV2: lambda.SystemLogLevel.INFO,
63
+ applicationLogLevelV2: lambda.ApplicationLogLevel.INFO,
64
+ });
65
+ autoStartPreventFunction.addToRolePolicy(new iam.PolicyStatement({
66
+ sid: 'GetResources',
67
+ effect: iam.Effect.ALLOW,
68
+ actions: [
69
+ 'tag:GetResources',
70
+ ],
71
+ resources: ['*'],
72
+ }));
73
+ // Grant read access to the RDS API
74
+ autoStartPreventFunction.addToRolePolicy(new iam.PolicyStatement({
75
+ sid: 'RdsAutoStartControl',
76
+ effect: iam.Effect.ALLOW,
77
+ actions: [
78
+ 'rds:DescribeDBInstances',
79
+ 'rds:DescribeDBClusters',
80
+ 'rds:StopDBInstance',
81
+ 'rds:StopDBCluster',
82
+ ],
83
+ resources: ['*'],
84
+ }));
85
+ // Grant read access to the Slack secret
86
+ slackSecret.grantRead(autoStartPreventFunction);
87
+ // See: https://docs.aws.amazon.com/lambda/latest/dg/durable-getting-started-iac.html
88
+ const autoStartPreventFunctionAlias = autoStartPreventFunction.addAlias('live');
89
+ const enableRule = (() => {
90
+ return props.enableRule === undefined || props.enableRule;
91
+ })();
92
+ // Convert the rule input to pass { event, params } to the Lambda (tag conditions are injected by the Rule).
93
+ const lambdaInput = events.RuleTargetInput.fromObject({
94
+ event: events.EventField.fromPath('$'),
95
+ params: {
96
+ tagKey: props.targetResource.tagKey,
97
+ tagValues: props.targetResource.tagValues,
98
+ },
99
+ });
100
+ // 👇 EventBridge by RDS DB Instance auto start event
101
+ new events.Rule(this, 'DBInstanceEvent', {
102
+ description: 'rds db instance auto start event catch rule.',
103
+ enabled: enableRule,
104
+ eventPattern: {
105
+ source: ['aws.rds'],
106
+ detailType: ['RDS DB Instance Event'],
107
+ detail: {
108
+ EventID: ['RDS-EVENT-0154'],
109
+ },
110
+ },
111
+ targets: [
112
+ new targets.LambdaFunction(autoStartPreventFunctionAlias, {
113
+ retryAttempts: 2,
114
+ event: lambdaInput,
115
+ }),
116
+ ],
117
+ });
118
+ // 👇 EventBridge by RDS DB Cluster auto start event
119
+ new events.Rule(this, 'DBClusterEvent', {
120
+ description: 'db cluster auto start event catch rule',
121
+ enabled: enableRule,
122
+ eventPattern: {
123
+ source: ['aws.rds'],
124
+ detailType: ['RDS DB Cluster Event'],
125
+ detail: {
126
+ EventID: ['RDS-EVENT-0153'],
127
+ },
128
+ },
129
+ targets: [
130
+ new targets.LambdaFunction(autoStartPreventFunctionAlias, {
131
+ retryAttempts: 2,
132
+ event: lambdaInput,
133
+ }),
134
+ ],
135
+ });
136
+ }
137
+ }
138
+ exports.RDSDatabaseAutoStartPreventer = RDSDatabaseAutoStartPreventer;
139
+ _a = JSII_RTTI_SYMBOL_1;
140
+ RDSDatabaseAutoStartPreventer[_a] = { fqn: "rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventer", version: "0.1.1" };
141
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmRzLWRhdGFiYXNlLWF1dG8tc3RhcnQtcHJldmVudGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbnN0cnVjdHMvcmRzLWRhdGFiYXNlLWF1dG8tc3RhcnQtcHJldmVudGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsNkNBQXNEO0FBQ3RELGlEQUFpRDtBQUNqRCwwREFBMEQ7QUFDMUQsMkNBQTJDO0FBQzNDLGlEQUFpRDtBQUNqRCw2Q0FBNkM7QUFDN0MsdUVBQXdEO0FBQ3hELDJDQUF1QztBQUN2QyxzRkFBZ0Y7QUFnQ2hGOzs7R0FHRztBQUNILE1BQWEsNkJBQThCLFNBQVEsc0JBQVM7SUFFMUQ7Ozs7OztPQU1HO0lBQ0gsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUF5QztRQUNqRixLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRWpCLE1BQU0sV0FBVyxHQUFHLDJCQUFNLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxFQUFFLGFBQWEsRUFBRSxLQUFLLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBRWhHLG1HQUFtRztRQUNuRywwQ0FBMEM7UUFDMUMsTUFBTSx3QkFBd0IsR0FBRyxJQUFJLHNEQUF3QixDQUFDLElBQUksRUFBRSwwQkFBMEIsRUFBRTtZQUM5RixXQUFXLEVBQUUsZ0ZBQWdGO1lBQzdGLFlBQVksRUFBRSxNQUFNLENBQUMsWUFBWSxDQUFDLE1BQU07WUFDeEMsT0FBTyxFQUFFLHNCQUFRLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUM3QixVQUFVLEVBQUUsR0FBRztZQUNmLGFBQWEsRUFBRSxDQUFDO1lBQ2hCLGFBQWEsRUFBRTtnQkFDYixnQkFBZ0IsRUFBRSxzQkFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7Z0JBQ25DLGVBQWUsRUFBRSxzQkFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7YUFDbEM7WUFDRCxXQUFXLEVBQUU7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WUFDM0QsT0FBTyxFQUFFLFVBQVU7WUFDbkIsWUFBWSxFQUFFO2dCQUNaLE1BQU0sRUFBRSxDQUFDLFNBQVMsQ0FBQztnQkFDbkIsVUFBVSxFQUFFLENBQUMsdUJBQXVCLENBQUM7Z0JBQ3JDLE1BQU0sRUFBRTtvQkFDTixPQUFPLEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQztpQkFDNUI7YUFDRjtZQUNELE9BQU8sRUFBRTtnQkFDUCxJQUFJLE9BQU8sQ0FBQyxjQUFjLENBQUMsNkJBQTZCLEVBQUU7b0JBQ3hELGFBQWEsRUFBRSxDQUFDO29CQUNoQixLQUFLLEVBQUUsV0FBVztpQkFDbkIsQ0FBQzthQUNIO1NBQ0YsQ0FBQyxDQUFDO1FBRUgsb0RBQW9EO1FBQ3BELElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsZ0JBQWdCLEVBQUU7WUFDdEMsV0FBVyxFQUFFLHdDQUF3QztZQUNyRCxPQUFPLEVBQUUsVUFBVTtZQUNuQixZQUFZLEVBQUU7Z0JBQ1osTUFBTSxFQUFFLENBQUMsU0FBUyxDQUFDO2dCQUNuQixVQUFVLEVBQUUsQ0FBQyxzQkFBc0IsQ0FBQztnQkFDcEMsTUFBTSxFQUFFO29CQUNOLE9BQU8sRUFBRSxDQUFDLGdCQUFnQixDQUFDO2lCQUM1QjthQUNGO1lBQ0QsT0FBTyxFQUFFO2dCQUNQLElBQUksT0FBTyxDQUFDLGNBQWMsQ0FBQyw2QkFBNkIsRUFBRTtvQkFDeEQsYUFBYSxFQUFFLENBQUM7b0JBQ2hCLEtBQUssRUFBRSxXQUFXO2lCQUNuQixDQUFDO2FBQ0g7U0FDRixDQUFDLENBQUM7SUFDTCxDQUFDOztBQTdISCxzRUE4SEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBEdXJhdGlvbiwgUmVtb3ZhbFBvbGljeSB9IGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCAqIGFzIGV2ZW50cyBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZXZlbnRzJztcbmltcG9ydCAqIGFzIHRhcmdldHMgZnJvbSAnYXdzLWNkay1saWIvYXdzLWV2ZW50cy10YXJnZXRzJztcbmltcG9ydCAqIGFzIGlhbSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtaWFtJztcbmltcG9ydCAqIGFzIGxhbWJkYSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbGFtYmRhJztcbmltcG9ydCAqIGFzIGxvZ3MgZnJvbSAnYXdzLWNkay1saWIvYXdzLWxvZ3MnO1xuaW1wb3J0IHsgU2VjcmV0IH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXNlY3JldHNtYW5hZ2VyJztcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuaW1wb3J0IHsgQXV0b1N0YXJ0UHJldmVudEZ1bmN0aW9uIH0gZnJvbSAnLi4vZnVuY3MvYXV0by1zdGFydC1wcmV2ZW50LWZ1bmN0aW9uJztcblxuLyoqXG4gKiBUYWctYmFzZWQgY3JpdGVyaWEgdG8gc2VsZWN0IHdoaWNoIFJEUyBpbnN0YW5jZXMgb3IgY2x1c3RlcnMgYXJlIHN1YmplY3QgdG8gYXV0by1zdGFydCBwcmV2ZW50aW9uLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFRhcmdldFJlc291cmNlIHtcbiAgLyoqIFRhZyBrZXkgdG8gbWF0Y2ggKGUuZy4gXCJFbnZpcm9ubWVudFwiLCBcIkF1dG9TdGFydFByZXZlbnRcIikuICovXG4gIHJlYWRvbmx5IHRhZ0tleTogc3RyaW5nO1xuICAvKiogVGFnIHZhbHVlcyB0aGF0IGluZGljYXRlIHRoZSByZXNvdXJjZSBzaG91bGQgYmUgcHJvdGVjdGVkIChlLmcuIFtcInByb2R1Y3Rpb25cIl0pLiAqL1xuICByZWFkb25seSB0YWdWYWx1ZXM6IHN0cmluZ1tdO1xufVxuXG4vKipcbiAqIEV4dGVybmFsIHNlY3JldHMgcmVxdWlyZWQgZm9yIG5vdGlmaWNhdGlvbnMgKGUuZy4gU2xhY2spLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFNlY3JldHMge1xuICAvKiogTmFtZSBvZiB0aGUgU2VjcmV0cyBNYW5hZ2VyIHNlY3JldCBjb250YWluaW5nIFNsYWNrIHRva2VuIGFuZCBjaGFubmVsLiAqL1xuICByZWFkb25seSBzbGFja1NlY3JldE5hbWU6IHN0cmluZztcbn1cblxuLyoqXG4gKiBQcm9wcyBmb3IgdGhlIFJEUyBkYXRhYmFzZSBhdXRvLXN0YXJ0IHByZXZlbnRlciBjb25zdHJ1Y3QuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUkRTRGF0YWJhc2VBdXRvU3RhcnRQcmV2ZW50ZXJQcm9wcyB7XG4gIC8qKiBUYWctYmFzZWQgdGFyZ2V0IHJlc291cmNlIGNyaXRlcmlhIGZvciBSRFMgaW5zdGFuY2VzL2NsdXN0ZXJzIHRvIHByb3RlY3QuICovXG4gIHJlYWRvbmx5IHRhcmdldFJlc291cmNlOiBUYXJnZXRSZXNvdXJjZTtcbiAgLyoqIFdoZXRoZXIgdGhlIEV2ZW50QnJpZGdlIHJ1bGVzIGFyZSBlbmFibGVkLiBEZWZhdWx0cyB0byB0cnVlIGlmIG9taXR0ZWQuICovXG4gIHJlYWRvbmx5IGVuYWJsZVJ1bGU/OiBib29sZWFuO1xuICAvKiogU2VjcmV0cyB1c2VkIGZvciBub3RpZmljYXRpb25zIChlLmcuIFNsYWNrKS4gKi9cbiAgcmVhZG9ubHkgc2VjcmV0czogU2VjcmV0cztcbn1cblxuLyoqXG4gKiBDb25zdHJ1Y3QgdGhhdCBkZXBsb3lzIEV2ZW50QnJpZGdlIHJ1bGVzIGFuZCBhIER1cmFibGUgTGFtYmRhIHRvIHByZXZlbnQgUkRTIERCIGluc3RhbmNlc1xuICogYW5kIGNsdXN0ZXJzIGZyb20gc3RheWluZyBydW5uaW5nIGFmdGVyIGFuIGF1dG8tc3RhcnQgZXZlbnQgKFJEUy1FVkVOVC0wMTU0IC8gUkRTLUVWRU5ULTAxNTMpLlxuICovXG5leHBvcnQgY2xhc3MgUkRTRGF0YWJhc2VBdXRvU3RhcnRQcmV2ZW50ZXIgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuXG4gIC8qKlxuICAgKiBDcmVhdGVzIHRoZSBjb25zdHJ1Y3Q6IExhbWJkYSAod2l0aCBQYXJhbXMgYW5kIFNlY3JldHMpLCBFdmVudEJyaWRnZSBydWxlcywgYW5kIElBTS5cbiAgICpcbiAgICogQHBhcmFtIHNjb3BlIC0gUGFyZW50IGNvbnN0cnVjdC5cbiAgICogQHBhcmFtIGlkIC0gQ29uc3RydWN0IGlkLlxuICAgKiBAcGFyYW0gcHJvcHMgLSBUYXJnZXQgcmVzb3VyY2UgKHRhZyBrZXkvdmFsdWVzKSwgZW5hYmxlIHJ1bGUgZmxhZywgYW5kIHNlY3JldHMuXG4gICAqL1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogUkRTRGF0YWJhc2VBdXRvU3RhcnRQcmV2ZW50ZXJQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICBjb25zdCBzbGFja1NlY3JldCA9IFNlY3JldC5mcm9tU2VjcmV0TmFtZVYyKHRoaXMsICdTbGFja1NlY3JldCcsIHByb3BzLnNlY3JldHMuc2xhY2tTZWNyZXROYW1lKTtcblxuICAgIC8vIER1cmFibGUgRnVuY3Rpb25zLWJhc2VkIFJ1bm5pbmcgU2NoZWR1bGVyIChwcmV2aW91cyBTdGVwIEZ1bmN0aW9ucyBsb2dpYyBpbXBsZW1lbnRlZCBpbiBMYW1iZGEpLlxuICAgIC8vIER1cmFibGUgRXhlY3V0aW9uIHJlcXVpcmVzIE5vZGUuanMgMjIrLlxuICAgIGNvbnN0IGF1dG9TdGFydFByZXZlbnRGdW5jdGlvbiA9IG5ldyBBdXRvU3RhcnRQcmV2ZW50RnVuY3Rpb24odGhpcywgJ0F1dG9TdGFydFByZXZlbnRGdW5jdGlvbicsIHtcbiAgICAgIGRlc2NyaXB0aW9uOiAnQSBmdW5jdGlvbiB0byBwcmV2ZW50IHRoZSBSRFMgRGF0YWJhc2Ugb3IgQ2x1c3RlciBmcm9tIHN0YXJ0aW5nIGF1dG9tYXRpY2FsbHkuJyxcbiAgICAgIGFyY2hpdGVjdHVyZTogbGFtYmRhLkFyY2hpdGVjdHVyZS5BUk1fNjQsXG4gICAgICB0aW1lb3V0OiBEdXJhdGlvbi5taW51dGVzKDE1KSxcbiAgICAgIG1lbW9yeVNpemU6IDUxMixcbiAgICAgIHJldHJ5QXR0ZW1wdHM6IDIsXG4gICAgICBkdXJhYmxlQ29uZmlnOiB7XG4gICAgICAgIGV4ZWN1dGlvblRpbWVvdXQ6IER1cmF0aW9uLmhvdXJzKDIpLFxuICAgICAgICByZXRlbnRpb25QZXJpb2Q6IER1cmF0aW9uLmRheXMoMSksXG4gICAgICB9LFxuICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgU0xBQ0tfU0VDUkVUX05BTUU6IHNsYWNrU2VjcmV0LnNlY3JldE5hbWUsXG4gICAgICB9LFxuICAgICAgcGFyYW1zQW5kU2VjcmV0czogbGFtYmRhLlBhcmFtc0FuZFNlY3JldHNMYXllclZlcnNpb24uZnJvbVZlcnNpb24obGFtYmRhLlBhcmFtc0FuZFNlY3JldHNWZXJzaW9ucy5WMV8wXzEwMywge1xuICAgICAgICBjYWNoZVNpemU6IDUwMCxcbiAgICAgICAgbG9nTGV2ZWw6IGxhbWJkYS5QYXJhbXNBbmRTZWNyZXRzTG9nTGV2ZWwuSU5GTyxcbiAgICAgIH0pLFxuICAgICAgcm9sZTogbmV3IGlhbS5Sb2xlKHRoaXMsICdBdXRvU3RhcnRQcmV2ZW50RnVuY3Rpb25Sb2xlJywge1xuICAgICAgICBkZXNjcmlwdGlvbjogJ0Egcm9sZSB0byBjb250cm9sIHRoZSBSRFMgRGF0YWJhc2Ugb3IgQ2x1c3Rlci4nLFxuICAgICAgICBhc3N1bWVkQnk6IG5ldyBpYW0uU2VydmljZVByaW5jaXBhbCgnbGFtYmRhLmFtYXpvbmF3cy5jb20nKSxcbiAgICAgICAgbWFuYWdlZFBvbGljaWVzOiBbXG4gICAgICAgICAgaWFtLk1hbmFnZWRQb2xpY3kuZnJvbUF3c01hbmFnZWRQb2xpY3lOYW1lKCdzZXJ2aWNlLXJvbGUvQVdTTGFtYmRhQmFzaWNFeGVjdXRpb25Sb2xlJyksXG4gICAgICAgICAgaWFtLk1hbmFnZWRQb2xpY3kuZnJvbUF3c01hbmFnZWRQb2xpY3lOYW1lKCdzZXJ2aWNlLXJvbGUvQVdTTGFtYmRhQmFzaWNEdXJhYmxlRXhlY3V0aW9uUm9sZVBvbGljeScpLFxuICAgICAgICBdLFxuICAgICAgfSksXG4gICAgICBsb2dHcm91cDogbmV3IGxvZ3MuTG9nR3JvdXAodGhpcywgJ0F1dG9TdGFydFByZXZlbnRGdW5jdGlvbkxvZ0dyb3VwJywge1xuICAgICAgICByZXRlbnRpb246IGxvZ3MuUmV0ZW50aW9uRGF5cy5USFJFRV9NT05USFMsXG4gICAgICAgIHJlbW92YWxQb2xpY3k6IFJlbW92YWxQb2xpY3kuREVTVFJPWSxcbiAgICAgIH0pLFxuICAgICAgbG9nZ2luZ0Zvcm1hdDogbGFtYmRhLkxvZ2dpbmdGb3JtYXQuSlNPTixcbiAgICAgIHN5c3RlbUxvZ0xldmVsVjI6IGxhbWJkYS5TeXN0ZW1Mb2dMZXZlbC5JTkZPLFxuICAgICAgYXBwbGljYXRpb25Mb2dMZXZlbFYyOiBsYW1iZGEuQXBwbGljYXRpb25Mb2dMZXZlbC5JTkZPLFxuICAgIH0pO1xuICAgIGF1dG9TdGFydFByZXZlbnRGdW5jdGlvbi5hZGRUb1JvbGVQb2xpY3kobmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgc2lkOiAnR2V0UmVzb3VyY2VzJyxcbiAgICAgIGVmZmVjdDogaWFtLkVmZmVjdC5BTExPVyxcbiAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgJ3RhZzpHZXRSZXNvdXJjZXMnLFxuICAgICAgXSxcbiAgICAgIHJlc291cmNlczogWycqJ10sXG4gICAgfSkpO1xuICAgIC8vIEdyYW50IHJlYWQgYWNjZXNzIHRvIHRoZSBSRFMgQVBJXG4gICAgYXV0b1N0YXJ0UHJldmVudEZ1bmN0aW9uLmFkZFRvUm9sZVBvbGljeShuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICBzaWQ6ICdSZHNBdXRvU3RhcnRDb250cm9sJyxcbiAgICAgIGVmZmVjdDogaWFtLkVmZmVjdC5BTExPVyxcbiAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgJ3JkczpEZXNjcmliZURCSW5zdGFuY2VzJyxcbiAgICAgICAgJ3JkczpEZXNjcmliZURCQ2x1c3RlcnMnLFxuICAgICAgICAncmRzOlN0b3BEQkluc3RhbmNlJyxcbiAgICAgICAgJ3JkczpTdG9wREJDbHVzdGVyJyxcbiAgICAgIF0sXG4gICAgICByZXNvdXJjZXM6IFsnKiddLFxuICAgIH0pKTtcbiAgICAvLyBHcmFudCByZWFkIGFjY2VzcyB0byB0aGUgU2xhY2sgc2VjcmV0XG4gICAgc2xhY2tTZWNyZXQuZ3JhbnRSZWFkKGF1dG9TdGFydFByZXZlbnRGdW5jdGlvbik7XG5cbiAgICAvLyBTZWU6IGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9sYW1iZGEvbGF0ZXN0L2RnL2R1cmFibGUtZ2V0dGluZy1zdGFydGVkLWlhYy5odG1sXG4gICAgY29uc3QgYXV0b1N0YXJ0UHJldmVudEZ1bmN0aW9uQWxpYXMgPSBhdXRvU3RhcnRQcmV2ZW50RnVuY3Rpb24uYWRkQWxpYXMoJ2xpdmUnKTtcblxuICAgIGNvbnN0IGVuYWJsZVJ1bGU6IGJvb2xlYW4gPSAoKCkgPT4ge1xuICAgICAgcmV0dXJuIHByb3BzLmVuYWJsZVJ1bGUgPT09IHVuZGVmaW5lZCB8fCBwcm9wcy5lbmFibGVSdWxlO1xuICAgIH0pKCk7XG5cbiAgICAvLyBDb252ZXJ0IHRoZSBydWxlIGlucHV0IHRvIHBhc3MgeyBldmVudCwgcGFyYW1zIH0gdG8gdGhlIExhbWJkYSAodGFnIGNvbmRpdGlvbnMgYXJlIGluamVjdGVkIGJ5IHRoZSBSdWxlKS5cbiAgICBjb25zdCBsYW1iZGFJbnB1dCA9IGV2ZW50cy5SdWxlVGFyZ2V0SW5wdXQuZnJvbU9iamVjdCh7XG4gICAgICBldmVudDogZXZlbnRzLkV2ZW50RmllbGQuZnJvbVBhdGgoJyQnKSxcbiAgICAgIHBhcmFtczoge1xuICAgICAgICB0YWdLZXk6IHByb3BzLnRhcmdldFJlc291cmNlLnRhZ0tleSxcbiAgICAgICAgdGFnVmFsdWVzOiBwcm9wcy50YXJnZXRSZXNvdXJjZS50YWdWYWx1ZXMsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgLy8g8J+RhyBFdmVudEJyaWRnZSBieSBSRFMgREIgSW5zdGFuY2UgYXV0byBzdGFydCBldmVudFxuICAgIG5ldyBldmVudHMuUnVsZSh0aGlzLCAnREJJbnN0YW5jZUV2ZW50Jywge1xuICAgICAgZGVzY3JpcHRpb246ICdyZHMgZGIgaW5zdGFuY2UgYXV0byBzdGFydCBldmVudCBjYXRjaCBydWxlLicsXG4gICAgICBlbmFibGVkOiBlbmFibGVSdWxlLFxuICAgICAgZXZlbnRQYXR0ZXJuOiB7XG4gICAgICAgIHNvdXJjZTogWydhd3MucmRzJ10sXG4gICAgICAgIGRldGFpbFR5cGU6IFsnUkRTIERCIEluc3RhbmNlIEV2ZW50J10sXG4gICAgICAgIGRldGFpbDoge1xuICAgICAgICAgIEV2ZW50SUQ6IFsnUkRTLUVWRU5ULTAxNTQnXSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgICB0YXJnZXRzOiBbXG4gICAgICAgIG5ldyB0YXJnZXRzLkxhbWJkYUZ1bmN0aW9uKGF1dG9TdGFydFByZXZlbnRGdW5jdGlvbkFsaWFzLCB7XG4gICAgICAgICAgcmV0cnlBdHRlbXB0czogMixcbiAgICAgICAgICBldmVudDogbGFtYmRhSW5wdXQsXG4gICAgICAgIH0pLFxuICAgICAgXSxcbiAgICB9KTtcblxuICAgIC8vIPCfkYcgRXZlbnRCcmlkZ2UgYnkgUkRTIERCIENsdXN0ZXIgYXV0byBzdGFydCBldmVudFxuICAgIG5ldyBldmVudHMuUnVsZSh0aGlzLCAnREJDbHVzdGVyRXZlbnQnLCB7XG4gICAgICBkZXNjcmlwdGlvbjogJ2RiIGNsdXN0ZXIgYXV0byBzdGFydCBldmVudCBjYXRjaCBydWxlJyxcbiAgICAgIGVuYWJsZWQ6IGVuYWJsZVJ1bGUsXG4gICAgICBldmVudFBhdHRlcm46IHtcbiAgICAgICAgc291cmNlOiBbJ2F3cy5yZHMnXSxcbiAgICAgICAgZGV0YWlsVHlwZTogWydSRFMgREIgQ2x1c3RlciBFdmVudCddLFxuICAgICAgICBkZXRhaWw6IHtcbiAgICAgICAgICBFdmVudElEOiBbJ1JEUy1FVkVOVC0wMTUzJ10sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgdGFyZ2V0czogW1xuICAgICAgICBuZXcgdGFyZ2V0cy5MYW1iZGFGdW5jdGlvbihhdXRvU3RhcnRQcmV2ZW50RnVuY3Rpb25BbGlhcywge1xuICAgICAgICAgIHJldHJ5QXR0ZW1wdHM6IDIsXG4gICAgICAgICAgZXZlbnQ6IGxhbWJkYUlucHV0LFxuICAgICAgICB9KSxcbiAgICAgIF0sXG4gICAgfSk7XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,13 @@
1
+ import * as lambda from 'aws-cdk-lib/aws-lambda';
2
+ import { Construct } from 'constructs';
3
+ /**
4
+ * Props for AutoStartPreventFunction
5
+ */
6
+ export interface AutoStartPreventFunctionProps extends lambda.FunctionOptions {
7
+ }
8
+ /**
9
+ * An AWS Lambda function which executes src/funcs/auto-start-prevent.
10
+ */
11
+ export declare class AutoStartPreventFunction extends lambda.Function {
12
+ constructor(scope: Construct, id: string, props?: AutoStartPreventFunctionProps);
13
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AutoStartPreventFunction = void 0;
4
+ // ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen".
5
+ const path = require("path");
6
+ const lambda = require("aws-cdk-lib/aws-lambda");
7
+ /**
8
+ * An AWS Lambda function which executes src/funcs/auto-start-prevent.
9
+ */
10
+ class AutoStartPreventFunction extends lambda.Function {
11
+ constructor(scope, id, props) {
12
+ super(scope, id, {
13
+ description: 'src/funcs/auto-start-prevent.lambda.ts',
14
+ ...props,
15
+ runtime: new lambda.Runtime('nodejs24.x', lambda.RuntimeFamily.NODEJS),
16
+ handler: 'index.handler',
17
+ code: lambda.Code.fromAsset(path.join(__dirname, '../../assets/funcs/auto-start-prevent.lambda')),
18
+ });
19
+ this.addEnvironment('AWS_NODEJS_CONNECTION_REUSE_ENABLED', '1', { removeInEdge: true });
20
+ }
21
+ }
22
+ exports.AutoStartPreventFunction = AutoStartPreventFunction;
23
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0by1zdGFydC1wcmV2ZW50LWZ1bmN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2Z1bmNzL2F1dG8tc3RhcnQtcHJldmVudC1mdW5jdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2RUFBNkU7QUFDN0UsNkJBQTZCO0FBQzdCLGlEQUFpRDtBQVNqRDs7R0FFRztBQUNILE1BQWEsd0JBQXlCLFNBQVEsTUFBTSxDQUFDLFFBQVE7SUFDM0QsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUFxQztRQUM3RSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRTtZQUNmLFdBQVcsRUFBRSx3Q0FBd0M7WUFDckQsR0FBRyxLQUFLO1lBQ1IsT0FBTyxFQUFFLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxZQUFZLEVBQUUsTUFBTSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUM7WUFDdEUsT0FBTyxFQUFFLGVBQWU7WUFDeEIsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLDhDQUE4QyxDQUFDLENBQUM7U0FDbEcsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLGNBQWMsQ0FBQyxxQ0FBcUMsRUFBRSxHQUFHLEVBQUUsRUFBRSxZQUFZLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUMxRixDQUFDO0NBQ0Y7QUFYRCw0REFXQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIH5+IEdlbmVyYXRlZCBieSBwcm9qZW4uIFRvIG1vZGlmeSwgZWRpdCAucHJvamVucmMudHMgYW5kIHJ1biBcIm5weCBwcm9qZW5cIi5cbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgKiBhcyBsYW1iZGEgZnJvbSAnYXdzLWNkay1saWIvYXdzLWxhbWJkYSc7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcblxuLyoqXG4gKiBQcm9wcyBmb3IgQXV0b1N0YXJ0UHJldmVudEZ1bmN0aW9uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQXV0b1N0YXJ0UHJldmVudEZ1bmN0aW9uUHJvcHMgZXh0ZW5kcyBsYW1iZGEuRnVuY3Rpb25PcHRpb25zIHtcbn1cblxuLyoqXG4gKiBBbiBBV1MgTGFtYmRhIGZ1bmN0aW9uIHdoaWNoIGV4ZWN1dGVzIHNyYy9mdW5jcy9hdXRvLXN0YXJ0LXByZXZlbnQuXG4gKi9cbmV4cG9ydCBjbGFzcyBBdXRvU3RhcnRQcmV2ZW50RnVuY3Rpb24gZXh0ZW5kcyBsYW1iZGEuRnVuY3Rpb24ge1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wcz86IEF1dG9TdGFydFByZXZlbnRGdW5jdGlvblByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkLCB7XG4gICAgICBkZXNjcmlwdGlvbjogJ3NyYy9mdW5jcy9hdXRvLXN0YXJ0LXByZXZlbnQubGFtYmRhLnRzJyxcbiAgICAgIC4uLnByb3BzLFxuICAgICAgcnVudGltZTogbmV3IGxhbWJkYS5SdW50aW1lKCdub2RlanMyNC54JywgbGFtYmRhLlJ1bnRpbWVGYW1pbHkuTk9ERUpTKSxcbiAgICAgIGhhbmRsZXI6ICdpbmRleC5oYW5kbGVyJyxcbiAgICAgIGNvZGU6IGxhbWJkYS5Db2RlLmZyb21Bc3NldChwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4vLi4vYXNzZXRzL2Z1bmNzL2F1dG8tc3RhcnQtcHJldmVudC5sYW1iZGEnKSksXG4gICAgfSk7XG4gICAgdGhpcy5hZGRFbnZpcm9ubWVudCgnQVdTX05PREVKU19DT05ORUNUSU9OX1JFVVNFX0VOQUJMRUQnLCAnMScsIHsgcmVtb3ZlSW5FZGdlOiB0cnVlIH0pO1xuICB9XG59Il19
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Durable Lambda handler: on RDS auto-start events, waits for the resource to become available
3
+ * (or already stopped), checks tag match, stops the instance/cluster if needed, then posts to Slack.
4
+ *
5
+ * @param input - EventBridge event plus params (tagKey, tagValues).
6
+ * @param context - Durable execution context for steps and waits.
7
+ * @returns Result with action ('stopped' | 'no-op'), finalStatus, account, region, identifier.
8
+ */
9
+ export declare const handler: import("@aws/durable-execution-sdk-js").DurableLambdaHandler;
@@ -0,0 +1,255 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handler = void 0;
4
+ const durable_execution_sdk_js_1 = require("@aws/durable-execution-sdk-js");
5
+ const client_rds_1 = require("@aws-sdk/client-rds");
6
+ const web_api_1 = require("@slack/web-api");
7
+ const aws_lambda_secret_fetcher_1 = require("aws-lambda-secret-fetcher");
8
+ /** Detect if the payload is the raw EventBridge event (has detail + detail-type). */
9
+ const isRawEvent = (input) => typeof input === 'object' &&
10
+ input != null &&
11
+ 'detail' in input &&
12
+ 'detail-type' in input;
13
+ /** Build params from environment (set by CDK from targetResource). */
14
+ const paramsFromEnv = () => {
15
+ const tagKey = process.env.TAG_KEY;
16
+ const tagValuesJson = process.env.TAG_VALUES;
17
+ if (!tagKey || !tagValuesJson) {
18
+ throw new Error('missing environment variables TAG_KEY or TAG_VALUES.');
19
+ }
20
+ let tagValues;
21
+ try {
22
+ tagValues = JSON.parse(tagValuesJson);
23
+ }
24
+ catch {
25
+ throw new Error('TAG_VALUES must be a JSON array of strings.');
26
+ }
27
+ if (!Array.isArray(tagValues)) {
28
+ throw new Error('TAG_VALUES must be a JSON array of strings.');
29
+ }
30
+ return { tagKey, tagValues };
31
+ };
32
+ /** Normalize invocation input to AutoStartPreventInput (event + params). */
33
+ const normalizeInput = (input) => {
34
+ if (isRawEvent(input)) {
35
+ return { event: input, params: paramsFromEnv() };
36
+ }
37
+ const candidate = input;
38
+ if (typeof candidate === 'object' &&
39
+ candidate != null &&
40
+ candidate.event != null &&
41
+ candidate.params != null) {
42
+ return candidate;
43
+ }
44
+ throw new Error('Invalid input: expected RDS event or { event, params }.');
45
+ };
46
+ const rdsClient = new client_rds_1.RDSClient({});
47
+ /** RDS statuses that indicate a transition in progress; we poll every 5 minutes while in these states. */
48
+ const TRANSITIONAL_STATUSES = new Set([
49
+ 'starting',
50
+ 'configuring-enhanced-monitoring',
51
+ 'backing-up',
52
+ 'modifying',
53
+ 'stopping',
54
+ ]);
55
+ /**
56
+ * Returns true if the resource has a tag with the given key and a value in the allowed list.
57
+ *
58
+ * @param params - Tag key and allowed values.
59
+ * @param tags - Resource tag list (e.g. from DescribeDBInstances / DescribeDBClusters).
60
+ * @returns Whether the tag matches.
61
+ */
62
+ const matchTag = (params, tags) => {
63
+ if (!tags || tags.length === 0) {
64
+ return false;
65
+ }
66
+ const value = tags.find(t => t.Key === params.tagKey)?.Value;
67
+ if (!value) {
68
+ return false;
69
+ }
70
+ return params.tagValues.includes(value);
71
+ };
72
+ /**
73
+ * Durable Lambda handler: on RDS auto-start events, waits for the resource to become available
74
+ * (or already stopped), checks tag match, stops the instance/cluster if needed, then posts to Slack.
75
+ *
76
+ * @param input - EventBridge event plus params (tagKey, tagValues).
77
+ * @param context - Durable execution context for steps and waits.
78
+ * @returns Result with action ('stopped' | 'no-op'), finalStatus, account, region, identifier.
79
+ */
80
+ exports.handler = (0, durable_execution_sdk_js_1.withDurableExecution)(async (input, context) => {
81
+ const { event, params } = normalizeInput(input);
82
+ const { detail, 'detail-type': detailType } = event;
83
+ const slackSecretName = process.env.SLACK_SECRET_NAME;
84
+ if (!slackSecretName) {
85
+ throw new Error('missing environment variable SLACK_SECRET_NAME.');
86
+ }
87
+ const slackSecretValue = await context.step('fetch-slack-secret', async () => {
88
+ return aws_lambda_secret_fetcher_1.secretFetcher.getSecretValue(slackSecretName);
89
+ });
90
+ if (!slackSecretValue?.token || !slackSecretValue?.channel) {
91
+ throw new Error('Slack secret must contain token and channel.');
92
+ }
93
+ const isInstance = detailType === 'RDS DB Instance Event' &&
94
+ detail.SourceType === 'DB_INSTANCE' &&
95
+ detail.EventID === 'RDS-EVENT-0154';
96
+ const isCluster = detailType === 'RDS DB Cluster Event' &&
97
+ detail.SourceType === 'CLUSTER' &&
98
+ detail.EventID === 'RDS-EVENT-0153';
99
+ if (!isInstance && !isCluster) {
100
+ throw new Error(`Unsupported event: detail-type=${detailType}, SourceType=${detail.SourceType}, EventID=${detail.EventID}`);
101
+ }
102
+ // Step Functions の StartingWait (1 分待つ) に相当
103
+ await context.wait({ minutes: 1 });
104
+ // Step Functions の DescribeTypeChoice + TagMatchChoice + StatusChoice の前半に相当
105
+ const firstDescribe = await context.waitForCondition(async (_state, _ctx) => {
106
+ if (isInstance) {
107
+ const res = await rdsClient.send(new client_rds_1.DescribeDBInstancesCommand({
108
+ DBInstanceIdentifier: detail.SourceIdentifier,
109
+ }));
110
+ const db = res.DBInstances?.[0];
111
+ return {
112
+ status: db?.DBInstanceStatus ?? 'unknown',
113
+ identifier: db?.DBInstanceIdentifier ?? detail.SourceIdentifier,
114
+ tags: (db?.TagList ?? []),
115
+ };
116
+ }
117
+ const res = await rdsClient.send(new client_rds_1.DescribeDBClustersCommand({
118
+ DBClusterIdentifier: detail.SourceIdentifier,
119
+ }));
120
+ const cluster = res.DBClusters?.[0];
121
+ return {
122
+ status: cluster?.Status ?? 'unknown',
123
+ identifier: cluster?.DBClusterIdentifier ?? detail.SourceIdentifier,
124
+ tags: (cluster?.TagList ?? []),
125
+ };
126
+ }, {
127
+ initialState: {
128
+ status: 'starting',
129
+ identifier: detail.SourceIdentifier,
130
+ },
131
+ waitStrategy: state => {
132
+ // ステータスが遷移中であれば 5 分おきにポーリング
133
+ if (TRANSITIONAL_STATUSES.has(state.status)) {
134
+ return { shouldContinue: true, delay: { minutes: 5 } };
135
+ }
136
+ // available / stopped / その他 → ここで一旦ループ終了し、後続ロジックへ
137
+ return { shouldContinue: false };
138
+ },
139
+ });
140
+ // タグが存在しない or マッチしない場合は何もせず終了
141
+ if (!matchTag(params, firstDescribe.tags)) {
142
+ return {
143
+ action: 'no-op',
144
+ reason: 'tag not matched or not found',
145
+ status: firstDescribe.status,
146
+ };
147
+ }
148
+ let finalStatus = firstDescribe.status;
149
+ // available の場合は stop API を呼び、その後 stopped になるまで待機
150
+ if (firstDescribe.status === 'available') {
151
+ if (isInstance) {
152
+ await context.step('stop-db-instance', async () => {
153
+ await rdsClient.send(new client_rds_1.StopDBInstanceCommand({
154
+ DBInstanceIdentifier: detail.SourceIdentifier,
155
+ }));
156
+ });
157
+ }
158
+ else {
159
+ await context.step('stop-db-cluster', async () => {
160
+ await rdsClient.send(new client_rds_1.StopDBClusterCommand({
161
+ DBClusterIdentifier: detail.SourceIdentifier,
162
+ }));
163
+ });
164
+ }
165
+ const stopped = await context.waitForCondition(async (_state, _ctx) => {
166
+ if (isInstance) {
167
+ const res = await rdsClient.send(new client_rds_1.DescribeDBInstancesCommand({
168
+ DBInstanceIdentifier: detail.SourceIdentifier,
169
+ }));
170
+ const db = res.DBInstances?.[0];
171
+ return {
172
+ status: db?.DBInstanceStatus ?? 'unknown',
173
+ identifier: db?.DBInstanceIdentifier ?? detail.SourceIdentifier,
174
+ };
175
+ }
176
+ const res = await rdsClient.send(new client_rds_1.DescribeDBClustersCommand({
177
+ DBClusterIdentifier: detail.SourceIdentifier,
178
+ }));
179
+ const cluster = res.DBClusters?.[0];
180
+ return {
181
+ status: cluster?.Status ?? 'unknown',
182
+ identifier: cluster?.DBClusterIdentifier ?? detail.SourceIdentifier,
183
+ };
184
+ }, {
185
+ initialState: {
186
+ status: firstDescribe.status,
187
+ identifier: firstDescribe.identifier,
188
+ },
189
+ waitStrategy: state => {
190
+ if (state.status === 'stopped') {
191
+ return { shouldContinue: false };
192
+ }
193
+ if (TRANSITIONAL_STATUSES.has(state.status)) {
194
+ return { shouldContinue: true, delay: { minutes: 5 } };
195
+ }
196
+ throw new Error(`Unexpected status while waiting for stop: ${state.status}`);
197
+ },
198
+ });
199
+ finalStatus = stopped.status;
200
+ }
201
+ // stopped になっていなければ通知は出さない(Step Functions の Fail 相当)
202
+ if (finalStatus !== 'stopped') {
203
+ throw new Error(`DB status is not stopped after processing: ${finalStatus}`);
204
+ }
205
+ // 通知用の account/region 取得(Slack 投稿用)
206
+ const sourceArnParts = detail.SourceArn.split(':');
207
+ const region = sourceArnParts[3];
208
+ const account = sourceArnParts[4];
209
+ // const sourceTypeHuman = humanReadableSourceType(detail.SourceType);
210
+ const client = new web_api_1.WebClient(slackSecretValue.token);
211
+ const channel = slackSecretValue.channel;
212
+ // send slack message
213
+ // const slackParentMessageResult =
214
+ await context.step('post-slack-messages', async () => {
215
+ return client.chat.postMessage({
216
+ channel,
217
+ attachments: [
218
+ {
219
+ color: '#36a64f',
220
+ pretext: `😴 Successfully stopped the automatically running RDS ${detail.SourceType} ${detail.SourceIdentifier}.`,
221
+ fields: [
222
+ {
223
+ title: 'Account',
224
+ value: account,
225
+ short: true,
226
+ },
227
+ {
228
+ title: 'Region',
229
+ value: region,
230
+ short: true,
231
+ },
232
+ {
233
+ title: 'Type',
234
+ value: detail.SourceType,
235
+ short: true,
236
+ },
237
+ {
238
+ title: 'Identifier',
239
+ value: detail.SourceIdentifier,
240
+ short: true,
241
+ },
242
+ ],
243
+ },
244
+ ],
245
+ });
246
+ });
247
+ return {
248
+ action: 'stopped',
249
+ finalStatus,
250
+ account,
251
+ region,
252
+ identifier: detail.SourceIdentifier,
253
+ };
254
+ });
255
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0by1zdGFydC1wcmV2ZW50LmxhbWJkYS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9mdW5jcy9hdXRvLXN0YXJ0LXByZXZlbnQubGFtYmRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDRFQUFxRjtBQUNyRixvREFNNkI7QUFDN0IsNENBQTJDO0FBQzNDLHlFQUEwRDtBQStDMUQscUZBQXFGO0FBQ3JGLE1BQU0sVUFBVSxHQUFHLENBQUMsS0FBYyxFQUE4QixFQUFFLENBQ2hFLE9BQU8sS0FBSyxLQUFLLFFBQVE7SUFDekIsS0FBSyxJQUFJLElBQUk7SUFDYixRQUFRLElBQUksS0FBSztJQUNqQixhQUFhLElBQUksS0FBSyxDQUFDO0FBRXpCLHNFQUFzRTtBQUN0RSxNQUFNLGFBQWEsR0FBRyxHQUFvQixFQUFFO0lBQzFDLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDO0lBQ25DLE1BQU0sYUFBYSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDO0lBQzdDLElBQUksQ0FBQyxNQUFNLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUM5QixNQUFNLElBQUksS0FBSyxDQUFDLHNEQUFzRCxDQUFDLENBQUM7SUFDMUUsQ0FBQztJQUNELElBQUksU0FBbUIsQ0FBQztJQUN4QixJQUFJLENBQUM7UUFDSCxTQUFTLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQWEsQ0FBQztJQUNwRCxDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsTUFBTSxJQUFJLEtBQUssQ0FBQyw2Q0FBNkMsQ0FBQyxDQUFDO0lBQ2pFLENBQUM7SUFDRCxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1FBQzlCLE1BQU0sSUFBSSxLQUFLLENBQUMsNkNBQTZDLENBQUMsQ0FBQztJQUNqRSxDQUFDO0lBQ0QsT0FBTyxFQUFFLE1BQU0sRUFBRSxT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TSxFQUFFLFNBQVM7UUFDakIsV0FBVztRQUNYLE9BQU87UUFDUCxNQUFNO1FBQ04sVUFBVSxFQUFFLE1BQU0sQ0FBQyxnQkFBZ0I7S0FDcEMsQ0FBQztBQUNKLENBQUMsQ0FDRixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgd2l0aER1cmFibGVFeGVjdXRpb24sIER1cmFibGVDb250ZXh0IH0gZnJvbSAnQGF3cy9kdXJhYmxlLWV4ZWN1dGlvbi1zZGstanMnO1xuaW1wb3J0IHtcbiAgUkRTQ2xpZW50LFxuICBEZXNjcmliZURCSW5zdGFuY2VzQ29tbWFuZCxcbiAgRGVzY3JpYmVEQkNsdXN0ZXJzQ29tbWFuZCxcbiAgU3RvcERCSW5zdGFuY2VDb21tYW5kLFxuICBTdG9wREJDbHVzdGVyQ29tbWFuZCxcbn0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LXJkcyc7XG5pbXBvcnQgeyBXZWJDbGllbnQgfSBmcm9tICdAc2xhY2svd2ViLWFwaSc7XG5pbXBvcnQgeyBzZWNyZXRGZXRjaGVyIH0gZnJvbSAnYXdzLWxhbWJkYS1zZWNyZXQtZmV0Y2hlcic7XG5cbi8qKlxuICogRGV0YWlsIHBheWxvYWQgb2YgYW4gUkRTIGF1dG8tc3RhcnQgZXZlbnQgZnJvbSBFdmVudEJyaWRnZSAoc3Vic2V0IHVzZWQgYnkgdGhpcyBoYW5kbGVyKS5cbiAqL1xuaW50ZXJmYWNlIFJkc0F1dG9TdGFydERldGFpbCB7XG4gIEV2ZW50SUQ6ICdSRFMtRVZFTlQtMDE1NCcgfCAnUkRTLUVWRU5ULTAxNTMnO1xuICBTb3VyY2VUeXBlOiAnREJfSU5TVEFOQ0UnIHwgJ0NMVVNURVInO1xuICBTb3VyY2VBcm46IHN0cmluZztcbiAgU291cmNlSWRlbnRpZmllcjogc3RyaW5nO1xufVxuXG4vKipcbiAqIFJEUyBhdXRvLXN0YXJ0IGV2ZW50IGFzIHJlY2VpdmVkIGZyb20gRXZlbnRCcmlkZ2UuXG4gKi9cbmludGVyZmFjZSBSZHNBdXRvU3RhcnRFdmVudCB7XG4gICdkZXRhaWwtdHlwZSc6ICdSRFMgREIgSW5zdGFuY2UgRXZlbnQnIHwgJ1JEUyBEQiBDbHVzdGVyIEV2ZW50JztcbiAgJ3NvdXJjZSc6ICdhd3MucmRzJztcbiAgJ2RldGFpbCc6IFJkc0F1dG9TdGFydERldGFpbDtcbn1cblxuLyoqXG4gKiBQYXJhbWV0ZXJzIGVxdWl2YWxlbnQgdG8gdGhvc2UgcHJldmlvdXNseSBwYXNzZWQgZnJvbSBTdGVwIEZ1bmN0aW9ucyAodGFnLWJhc2VkIGZpbHRlcmluZykuXG4gKi9cbmludGVyZmFjZSBBdXRvU3RhcnRQYXJhbXMge1xuICB0YWdLZXk6IHN0cmluZztcbiAgdGFnVmFsdWVzOiBzdHJpbmdbXTtcbn1cblxuLyoqXG4gKiBTbGFjayBzZWNyZXQgc2hhcGUgc3RvcmVkIGluIFNlY3JldHMgTWFuYWdlciAodG9rZW4gYW5kIGNoYW5uZWwpLlxuICovXG5pbnRlcmZhY2UgU2xhY2tTZWNyZXQge1xuICB0b2tlbjogc3RyaW5nO1xuICBjaGFubmVsOiBzdHJpbmc7XG59XG5cbi8qKlxuICogSW5wdXQgdG8gdGhlIExhbWJkYSBEdXJhYmxlIEZ1bmN0aW9uLiBFaXRoZXI6XG4gKiAtIEV2ZW50QnJpZGdlIHBhc3NlcyB0aGUgcmF3IFJEUyBldmVudDsgcGFyYW1zIGFyZSB0YWtlbiBmcm9tIGVudiAoVEFHX0tFWSwgVEFHX1ZBTFVFUykuXG4gKiAtIE9yIGNhbGxlciBjYW4gcGFzcyB7IGV2ZW50LCBwYXJhbXMgfSBkaXJlY3RseS5cbiAqL1xuaW50ZXJmYWNlIEF1dG9TdGFydFByZXZlbnRJbnB1dCB7XG4gIGV2ZW50OiBSZHNBdXRvU3RhcnRFdmVudDtcbiAgcGFyYW1zOiBBdXRvU3RhcnRQYXJhbXM7XG59XG5cbi8qKiBEZXRlY3QgaWYgdGhlIHBheWxvYWQgaXMgdGhlIHJhdyBFdmVudEJyaWRnZSBldmVudCAoaGFzIGRldGFpbCArIGRldGFpbC10eXBlKS4gKi9cbmNvbnN0IGlzUmF3RXZlbnQgPSAoaW5wdXQ6IHVua25vd24pOiBpbnB1dCBpcyBSZHNBdXRvU3RhcnRFdmVudCA9PlxuICB0eXBlb2YgaW5wdXQgPT09ICdvYmplY3QnICYmXG4gIGlucHV0ICE9IG51bGwgJiZcbiAgJ2RldGFpbCcgaW4gaW5wdXQgJiZcbiAgJ2RldGFpbC10eXBlJyBpbiBpbnB1dDtcblxuLyoqIEJ1aWxkIHBhcmFtcyBmcm9tIGVudmlyb25tZW50IChzZXQgYnkgQ0RLIGZyb20gdGFyZ2V0UmVzb3VyY2UpLiAqL1xuY29uc3QgcGFyYW1zRnJvbUVudiA9ICgpOiBBdXRvU3RhcnRQYXJhbXMgPT4ge1xuICBjb25zdCB0YWdLZXkgPSBwcm9jZXNzLmVudi5UQUdfS0VZO1xuICBjb25zdCB0YWdWYWx1ZXNKc29uID0gcHJvY2Vzcy5lbnYuVEFHX1ZBTFVFUztcbiAgaWYgKCF0YWdLZXkgfHwgIXRhZ1ZhbHVlc0pzb24pIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgZW52aXJvbm1lbnQgdmFyaWFibGVzIFRBR19LRVkgb3IgVEFHX1ZBTFVFUy4nKTtcbiAgfVxuICBsZXQgdGFnVmFsdWVzOiBzdHJpbmdbXTtcbiAgdHJ5IHtcbiAgICB0YWdWYWx1ZXMgPSBKU09OLnBhcnNlKHRhZ1ZhbHVlc0pzb24pIGFzIHN0cmluZ1tdO1xuICB9IGNhdGNoIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1RBR19WQUxVRVMgbXVzdCBiZSBhIEpTT04gYXJyYXkgb2Ygc3RyaW5ncy4nKTtcbiAgfVxuICBpZiAoIUFycmF5LmlzQXJyYXkodGFnVmFsdWVzKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignVEFHX1ZBTFVFUyBtdXN0IGJlIGEgSlNPTiBhcnJheSBvZiBzdHJpbmdzLicpO1xuICB9XG4gIHJldHVybiB7IHRhZ0tleSwgdGFnVmFsdWVzIH07XG59O1xuXG4vKiogTm9ybWFsaXplIGludm9jYXRpb24gaW5wdXQgdG8gQXV0b1N0YXJ0UHJldmVudElucHV0IChldmVudCArIHBhcmFtcykuICovXG5jb25zdCBub3JtYWxpemVJbnB1dCA9IChpbnB1dDogdW5rbm93bik6IEF1dG9TdGFydFByZXZlbnRJbnB1dCA9PiB7XG4gIGlmIChpc1Jhd0V2ZW50KGlucHV0KSkge1xuICAgIHJldHVybiB7IGV2ZW50OiBpbnB1dCwgcGFyYW1zOiBwYXJhbXNGcm9tRW52KCkgfTtcbiAgfVxuICBjb25zdCBjYW5kaWRhdGUgPSBpbnB1dCBhcyBBdXRvU3RhcnRQcmV2ZW50SW5wdXQ7XG4gIGlmIChcbiAgICB0eXBlb2YgY2FuZGlkYXRlID09PSAnb2JqZWN0JyAmJlxuICAgIGNhbmRpZGF0ZSAhPSBudWxsICYmXG4gICAgY2FuZGlkYXRlLmV2ZW50ICE9IG51bGwgJiZcbiAgICBjYW5kaWRhdGUucGFyYW1zICE9IG51bGxcbiAgKSB7XG4gICAgcmV0dXJuIGNhbmRpZGF0ZTtcbiAgfVxuICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgaW5wdXQ6IGV4cGVjdGVkIFJEUyBldmVudCBvciB7IGV2ZW50LCBwYXJhbXMgfS4nKTtcbn07XG5cbi8qKlxuICogQVdTLXN0eWxlIHRhZyAoS2V5L1ZhbHVlKS5cbiAqL1xuaW50ZXJmYWNlIFRhZyB7XG4gIEtleT86IHN0cmluZztcbiAgVmFsdWU/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogU3RhdGUgdXNlZCB3aGVuIHBvbGxpbmcgUkRTIGRlc2NyaWJlIHJlc3VsdHMgKHN0YXR1cywgaWRlbnRpZmllciwgb3B0aW9uYWwgdGFncykuXG4gKi9cbmludGVyZmFjZSBQb2xsU3RhdGUge1xuICBzdGF0dXM6IHN0cmluZztcbiAgaWRlbnRpZmllcjogc3RyaW5nO1xuICB0YWdzPzogVGFnW107XG59XG5cbmNvbnN0IHJkc0NsaWVudCA9IG5ldyBSRFNDbGllbnQoe30pO1xuXG4vKiogUkRTIHN0YXR1c2VzIHRoYXQgaW5kaWNhdGUgYSB0cmFuc2l0aW9uIGluIHByb2dyZXNzOyB3ZSBwb2xsIGV2ZXJ5IDUgbWludXRlcyB3aGlsZSBpbiB0aGVzZSBzdGF0ZXMuICovXG5jb25zdCBUUkFOU0lUSU9OQUxfU1RBVFVTRVMgPSBuZXcgU2V0KFtcbiAgJ3N0YXJ0aW5nJyxcbiAgJ2NvbmZpZ3VyaW5nLWVuaGFuY2VkLW1vbml0b3JpbmcnLFxuICAnYmFja2luZy11cCcsXG4gICdtb2RpZnlpbmcnLFxuICAnc3RvcHBpbmcnLFxuXSk7XG5cbi8qKlxuICogUmV0dXJucyB0cnVlIGlmIHRoZSByZXNvdXJjZSBoYXMgYSB0YWcgd2l0aCB0aGUgZ2l2ZW4ga2V5IGFuZCBhIHZhbHVlIGluIHRoZSBhbGxvd2VkIGxpc3QuXG4gKlxuICogQHBhcmFtIHBhcmFtcyAtIFRhZyBrZXkgYW5kIGFsbG93ZWQgdmFsdWVzLlxuICogQHBhcmFtIHRhZ3MgLSBSZXNvdXJjZSB0YWcgbGlzdCAoZS5nLiBmcm9tIERlc2NyaWJlREJJbnN0YW5jZXMgLyBEZXNjcmliZURCQ2x1c3RlcnMpLlxuICogQHJldHVybnMgV2hldGhlciB0aGUgdGFnIG1hdGNoZXMuXG4gKi9cbmNvbnN0IG1hdGNoVGFnID0gKHBhcmFtczogQXV0b1N0YXJ0UGFyYW1zLCB0YWdzPzogVGFnW10pOiBib29sZWFuID0+IHtcbiAgaWYgKCF0YWdzIHx8IHRhZ3MubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGNvbnN0IHZhbHVlID0gdGFncy5maW5kKHQgPT4gdC5LZXkgPT09IHBhcmFtcy50YWdLZXkpPy5WYWx1ZTtcbiAgaWYgKCF2YWx1ZSkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICByZXR1cm4gcGFyYW1zLnRhZ1ZhbHVlcy5pbmNsdWRlcyh2YWx1ZSk7XG59O1xuXG4vKipcbiAqIER1cmFibGUgTGFtYmRhIGhhbmRsZXI6IG9uIFJEUyBhdXRvLXN0YXJ0IGV2ZW50cywgd2FpdHMgZm9yIHRoZSByZXNvdXJjZSB0byBiZWNvbWUgYXZhaWxhYmxlXG4gKiAob3IgYWxyZWFkeSBzdG9wcGVkKSwgY2hlY2tzIHRhZyBtYXRjaCwgc3RvcHMgdGhlIGluc3RhbmNlL2NsdXN0ZXIgaWYgbmVlZGVkLCB0aGVuIHBvc3RzIHRvIFNsYWNrLlxuICpcbiAqIEBwYXJhbSBpbnB1dCAtIEV2ZW50QnJpZGdlIGV2ZW50IHBsdXMgcGFyYW1zICh0YWdLZXksIHRhZ1ZhbHVlcykuXG4gKiBAcGFyYW0gY29udGV4dCAtIER1cmFibGUgZXhlY3V0aW9uIGNvbnRleHQgZm9yIHN0ZXBzIGFuZCB3YWl0cy5cbiAqIEByZXR1cm5zIFJlc3VsdCB3aXRoIGFjdGlvbiAoJ3N0b3BwZWQnIHwgJ25vLW9wJyksIGZpbmFsU3RhdHVzLCBhY2NvdW50LCByZWdpb24sIGlkZW50aWZpZXIuXG4gKi9cbmV4cG9ydCBjb25zdCBoYW5kbGVyID0gd2l0aER1cmFibGVFeGVjdXRpb24oXG4gIGFzeW5jIChpbnB1dDogdW5rbm93biwgY29udGV4dDogRHVyYWJsZUNvbnRleHQpID0+IHtcbiAgICBjb25zdCB7IGV2ZW50LCBwYXJhbXMgfSA9IG5vcm1hbGl6ZUlucHV0KGlucHV0KTtcbiAgICBjb25zdCB7IGRldGFpbCwgJ2RldGFpbC10eXBlJzogZGV0YWlsVHlwZSB9ID0gZXZlbnQ7XG5cbiAgICBjb25zdCBzbGFja1NlY3JldE5hbWUgPSBwcm9jZXNzLmVudi5TTEFDS19TRUNSRVRfTkFNRTtcbiAgICBpZiAoIXNsYWNrU2VjcmV0TmFtZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIGVudmlyb25tZW50IHZhcmlhYmxlIFNMQUNLX1NFQ1JFVF9OQU1FLicpO1xuICAgIH1cbiAgICBjb25zdCBzbGFja1NlY3JldFZhbHVlID0gYXdhaXQgY29udGV4dC5zdGVwKCdmZXRjaC1zbGFjay1zZWNyZXQnLCBhc3luYyAoKSA9PiB7XG4gICAgICByZXR1cm4gc2VjcmV0RmV0Y2hlci5nZXRTZWNyZXRWYWx1ZTxTbGFja1NlY3JldD4oc2xhY2tTZWNyZXROYW1lKTtcbiAgICB9KTtcblxuICAgIGlmICghc2xhY2tTZWNyZXRWYWx1ZT8udG9rZW4gfHwgIXNsYWNrU2VjcmV0VmFsdWU/LmNoYW5uZWwpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignU2xhY2sgc2VjcmV0IG11c3QgY29udGFpbiB0b2tlbiBhbmQgY2hhbm5lbC4nKTtcbiAgICB9XG5cbiAgICBjb25zdCBpc0luc3RhbmNlID1cbiAgICAgIGRldGFpbFR5cGUgPT09ICdSRFMgREIgSW5zdGFuY2UgRXZlbnQnICYmXG4gICAgICBkZXRhaWwuU291cmNlVHlwZSA9PT0gJ0RCX0lOU1RBTkNFJyAmJlxuICAgICAgZGV0YWlsLkV2ZW50SUQgPT09ICdSRFMtRVZFTlQtMDE1NCc7XG5cbiAgICBjb25zdCBpc0NsdXN0ZXIgPVxuICAgICAgZGV0YWlsVHlwZSA9PT0gJ1JEUyBEQiBDbHVzdGVyIEV2ZW50JyAmJlxuICAgICAgZGV0YWlsLlNvdXJjZVR5cGUgPT09ICdDTFVTVEVSJyAmJlxuICAgICAgZGV0YWlsLkV2ZW50SUQgPT09ICdSRFMtRVZFTlQtMDE1Myc7XG5cbiAgICBpZiAoIWlzSW5zdGFuY2UgJiYgIWlzQ2x1c3Rlcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgVW5zdXBwb3J0ZWQgZXZlbnQ6IGRldGFpbC10eXBlPSR7ZGV0YWlsVHlwZX0sIFNvdXJjZVR5cGU9JHtkZXRhaWwuU291cmNlVHlwZX0sIEV2ZW50SUQ9JHtkZXRhaWwuRXZlbnRJRH1gLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBTdGVwIEZ1bmN0aW9ucyDjga4gU3RhcnRpbmdXYWl0ICgxIOWIhuW+heOBpCkg44Gr55u45b2TXG4gICAgYXdhaXQgY29udGV4dC53YWl0KHsgbWludXRlczogMSB9KTtcblxuICAgIC8vIFN0ZXAgRnVuY3Rpb25zIOOBriBEZXNjcmliZVR5cGVDaG9pY2UgKyBUYWdNYXRjaENob2ljZSArIFN0YXR1c0Nob2ljZSDjga7liY3ljYrjgavnm7jlvZNcbiAgICBjb25zdCBmaXJzdERlc2NyaWJlID0gYXdhaXQgY29udGV4dC53YWl0Rm9yQ29uZGl0aW9uPFBvbGxTdGF0ZT4oXG4gICAgICBhc3luYyAoX3N0YXRlLCBfY3R4KSA9PiB7XG4gICAgICAgIGlmIChpc0luc3RhbmNlKSB7XG4gICAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgcmRzQ2xpZW50LnNlbmQoXG4gICAgICAgICAgICBuZXcgRGVzY3JpYmVEQkluc3RhbmNlc0NvbW1hbmQoe1xuICAgICAgICAgICAgICBEQkluc3RhbmNlSWRlbnRpZmllcjogZGV0YWlsLlNvdXJjZUlkZW50aWZpZXIsXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICApO1xuICAgICAgICAgIGNvbnN0IGRiID0gcmVzLkRCSW5zdGFuY2VzPy5bMF07XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN0YXR1czogZGI/LkRCSW5zdGFuY2VTdGF0dXMgPz8gJ3Vua25vd24nLFxuICAgICAgICAgICAgaWRlbnRpZmllcjogZGI/LkRCSW5zdGFuY2VJZGVudGlmaWVyID8/IGRldGFpbC5Tb3VyY2VJZGVudGlmaWVyLFxuICAgICAgICAgICAgdGFnczogKGRiPy5UYWdMaXN0ID8/IFtdKSBhcyBUYWdbXSxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgcmRzQ2xpZW50LnNlbmQoXG4gICAgICAgICAgbmV3IERlc2NyaWJlREJDbHVzdGVyc0NvbW1hbmQoe1xuICAgICAgICAgICAgREJDbHVzdGVySWRlbnRpZmllcjogZGV0YWlsLlNvdXJjZUlkZW50aWZpZXIsXG4gICAgICAgICAgfSksXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IGNsdXN0ZXIgPSByZXMuREJDbHVzdGVycz8uWzBdO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHN0YXR1czogY2x1c3Rlcj8uU3RhdHVzID8/ICd1bmtub3duJyxcbiAgICAgICAgICBpZGVudGlmaWVyOiBjbHVzdGVyPy5EQkNsdXN0ZXJJZGVudGlmaWVyID8/IGRldGFpbC5Tb3VyY2VJZGVudGlmaWVyLFxuICAgICAgICAgIHRhZ3M6IChjbHVzdGVyPy5UYWdMaXN0ID8/IFtdKSBhcyBUYWdbXSxcbiAgICAgICAgfTtcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIGluaXRpYWxTdGF0ZToge1xuICAgICAgICAgIHN0YXR1czogJ3N0YXJ0aW5nJyxcbiAgICAgICAgICBpZGVudGlmaWVyOiBkZXRhaWwuU291cmNlSWRlbnRpZmllcixcbiAgICAgICAgfSxcbiAgICAgICAgd2FpdFN0cmF0ZWd5OiBzdGF0ZSA9PiB7XG4gICAgICAgICAgLy8g44K544OG44O844K/44K544GM6YG356e75Lit44Gn44GC44KM44GwIDUg5YiG44GK44GN44Gr44Od44O844Oq44Oz44KwXG4gICAgICAgICAgaWYgKFRSQU5TSVRJT05BTF9TVEFUVVNFUy5oYXMoc3RhdGUuc3RhdHVzKSkge1xuICAgICAgICAgICAgcmV0dXJuIHsgc2hvdWxkQ29udGludWU6IHRydWUsIGRlbGF5OiB7IG1pbnV0ZXM6IDUgfSB9O1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBhdmFpbGFibGUgLyBzdG9wcGVkIC8g44Gd44Gu5LuWIOKGkiDjgZPjgZPjgafkuIDml6bjg6vjg7zjg5fntYLkuobjgZfjgIHlvozntprjg63jgrjjg4Pjgq/jgbhcbiAgICAgICAgICByZXR1cm4geyBzaG91bGRDb250aW51ZTogZmFsc2UgfTtcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgKTtcblxuICAgIC8vIOOCv+OCsOOBjOWtmOWcqOOBl+OBquOBhCBvciDjg57jg4Pjg4HjgZfjgarjgYTloLTlkIjjga/kvZXjgoLjgZvjgZrntYLkuoZcbiAgICBpZiAoIW1hdGNoVGFnKHBhcmFtcywgZmlyc3REZXNjcmliZS50YWdzKSkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYWN0aW9uOiAnbm8tb3AnLFxuICAgICAgICByZWFzb246ICd0YWcgbm90IG1hdGNoZWQgb3Igbm90IGZvdW5kJyxcbiAgICAgICAgc3RhdHVzOiBmaXJzdERlc2NyaWJlLnN0YXR1cyxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgbGV0IGZpbmFsU3RhdHVzID0gZmlyc3REZXNjcmliZS5zdGF0dXM7XG5cbiAgICAvLyBhdmFpbGFibGUg44Gu5aC05ZCI44GvIHN0b3AgQVBJIOOCkuWRvOOBs+OAgeOBneOBruW+jCBzdG9wcGVkIOOBq+OBquOCi+OBvuOBp+W+heapn1xuICAgIGlmIChmaXJzdERlc2NyaWJlLnN0YXR1cyA9PT0gJ2F2YWlsYWJsZScpIHtcbiAgICAgIGlmIChpc0luc3RhbmNlKSB7XG4gICAgICAgIGF3YWl0IGNvbnRleHQuc3RlcCgnc3RvcC1kYi1pbnN0YW5jZScsIGFzeW5jICgpID0+IHtcbiAgICAgICAgICBhd2FpdCByZHNDbGllbnQuc2VuZChcbiAgICAgICAgICAgIG5ldyBTdG9wREJJbnN0YW5jZUNvbW1hbmQoe1xuICAgICAgICAgICAgICBEQkluc3RhbmNlSWRlbnRpZmllcjogZGV0YWlsLlNvdXJjZUlkZW50aWZpZXIsXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICApO1xuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGF3YWl0IGNvbnRleHQuc3RlcCgnc3RvcC1kYi1jbHVzdGVyJywgYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIGF3YWl0IHJkc0NsaWVudC5zZW5kKFxuICAgICAgICAgICAgbmV3IFN0b3BEQkNsdXN0ZXJDb21tYW5kKHtcbiAgICAgICAgICAgICAgREJDbHVzdGVySWRlbnRpZmllcjogZGV0YWlsLlNvdXJjZUlkZW50aWZpZXIsXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICApO1xuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc3RvcHBlZCA9IGF3YWl0IGNvbnRleHQud2FpdEZvckNvbmRpdGlvbjxQb2xsU3RhdGU+KFxuICAgICAgICBhc3luYyAoX3N0YXRlLCBfY3R4KSA9PiB7XG4gICAgICAgICAgaWYgKGlzSW5zdGFuY2UpIHtcbiAgICAgICAgICAgIGNvbnN0IHJlcyA9IGF3YWl0IHJkc0NsaWVudC5zZW5kKFxuICAgICAgICAgICAgICBuZXcgRGVzY3JpYmVEQkluc3RhbmNlc0NvbW1hbmQoe1xuICAgICAgICAgICAgICAgIERCSW5zdGFuY2VJZGVudGlmaWVyOiBkZXRhaWwuU291cmNlSWRlbnRpZmllcixcbiAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29uc3QgZGIgPSByZXMuREJJbnN0YW5jZXM/LlswXTtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN0YXR1czogZGI/LkRCSW5zdGFuY2VTdGF0dXMgPz8gJ3Vua25vd24nLFxuICAgICAgICAgICAgICBpZGVudGlmaWVyOiBkYj8uREJJbnN0YW5jZUlkZW50aWZpZXIgPz8gZGV0YWlsLlNvdXJjZUlkZW50aWZpZXIsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IHJlcyA9IGF3YWl0IHJkc0NsaWVudC5zZW5kKFxuICAgICAgICAgICAgbmV3IERlc2NyaWJlREJDbHVzdGVyc0NvbW1hbmQoe1xuICAgICAgICAgICAgICBEQkNsdXN0ZXJJZGVudGlmaWVyOiBkZXRhaWwuU291cmNlSWRlbnRpZmllcixcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICk7XG4gICAgICAgICAgY29uc3QgY2x1c3RlciA9IHJlcy5EQkNsdXN0ZXJzPy5bMF07XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN0YXR1czogY2x1c3Rlcj8uU3RhdHVzID8/ICd1bmtub3duJyxcbiAgICAgICAgICAgIGlkZW50aWZpZXI6IGNsdXN0ZXI/LkRCQ2x1c3RlcklkZW50aWZpZXIgPz8gZGV0YWlsLlNvdXJjZUlkZW50aWZpZXIsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIGluaXRpYWxTdGF0ZToge1xuICAgICAgICAgICAgc3RhdHVzOiBmaXJzdERlc2NyaWJlLnN0YXR1cyxcbiAgICAgICAgICAgIGlkZW50aWZpZXI6IGZpcnN0RGVzY3JpYmUuaWRlbnRpZmllcixcbiAgICAgICAgICB9LFxuICAgICAgICAgIHdhaXRTdHJhdGVneTogc3RhdGUgPT4ge1xuICAgICAgICAgICAgaWYgKHN0YXRlLnN0YXR1cyA9PT0gJ3N0b3BwZWQnKSB7XG4gICAgICAgICAgICAgIHJldHVybiB7IHNob3VsZENvbnRpbnVlOiBmYWxzZSB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKFRSQU5TSVRJT05BTF9TVEFUVVNFUy5oYXMoc3RhdGUuc3RhdHVzKSkge1xuICAgICAgICAgICAgICByZXR1cm4geyBzaG91bGRDb250aW51ZTogdHJ1ZSwgZGVsYXk6IHsgbWludXRlczogNSB9IH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuZXhwZWN0ZWQgc3RhdHVzIHdoaWxlIHdhaXRpbmcgZm9yIHN0b3A6ICR7c3RhdGUuc3RhdHVzfWApO1xuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICApO1xuXG4gICAgICBmaW5hbFN0YXR1cyA9IHN0b3BwZWQuc3RhdHVzO1xuICAgIH1cblxuICAgIC8vIHN0b3BwZWQg44Gr44Gq44Gj44Gm44GE44Gq44GR44KM44Gw6YCa55+l44Gv5Ye644GV44Gq44GE77yIU3RlcCBGdW5jdGlvbnMg44GuIEZhaWwg55u45b2T77yJXG4gICAgaWYgKGZpbmFsU3RhdHVzICE9PSAnc3RvcHBlZCcpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgREIgc3RhdHVzIGlzIG5vdCBzdG9wcGVkIGFmdGVyIHByb2Nlc3Npbmc6ICR7ZmluYWxTdGF0dXN9YCk7XG4gICAgfVxuXG4gICAgLy8g6YCa55+l55So44GuIGFjY291bnQvcmVnaW9uIOWPluW+l++8iFNsYWNrIOaKleeov+eUqO+8iVxuICAgIGNvbnN0IHNvdXJjZUFyblBhcnRzID0gZGV0YWlsLlNvdXJjZUFybi5zcGxpdCgnOicpO1xuICAgIGNvbnN0IHJlZ2lvbiA9IHNvdXJjZUFyblBhcnRzWzNdO1xuICAgIGNvbnN0IGFjY291bnQgPSBzb3VyY2VBcm5QYXJ0c1s0XTtcblxuICAgIC8vIGNvbnN0IHNvdXJjZVR5cGVIdW1hbiA9IGh1bWFuUmVhZGFibGVTb3VyY2VUeXBlKGRldGFpbC5Tb3VyY2VUeXBlKTtcblxuICAgIGNvbnN0IGNsaWVudCA9IG5ldyBXZWJDbGllbnQoc2xhY2tTZWNyZXRWYWx1ZS50b2tlbik7XG4gICAgY29uc3QgY2hhbm5lbCA9IHNsYWNrU2VjcmV0VmFsdWUuY2hhbm5lbDtcblxuICAgIC8vIHNlbmQgc2xhY2sgbWVzc2FnZVxuICAgIC8vIGNvbnN0IHNsYWNrUGFyZW50TWVzc2FnZVJlc3VsdCA9XG4gICAgYXdhaXQgY29udGV4dC5zdGVwKCdwb3N0LXNsYWNrLW1lc3NhZ2VzJywgYXN5bmMgKCkgPT4ge1xuICAgICAgcmV0dXJuIGNsaWVudC5jaGF0LnBvc3RNZXNzYWdlKHtcbiAgICAgICAgY2hhbm5lbCxcbiAgICAgICAgYXR0YWNobWVudHM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBjb2xvcjogJyMzNmE2NGYnLFxuICAgICAgICAgICAgcHJldGV4dDogYPCfmLQgU3VjY2Vzc2Z1bGx5IHN0b3BwZWQgdGhlIGF1dG9tYXRpY2FsbHkgcnVubmluZyBSRFMgJHtkZXRhaWwuU291cmNlVHlwZX0gJHtkZXRhaWwuU291cmNlSWRlbnRpZmllcn0uYCxcbiAgICAgICAgICAgIGZpZWxkczogW1xuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdGl0bGU6ICdBY2NvdW50JyxcbiAgICAgICAgICAgICAgICB2YWx1ZTogYWNjb3VudCxcbiAgICAgICAgICAgICAgICBzaG9ydDogdHJ1ZSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHRpdGxlOiAnUmVnaW9uJyxcbiAgICAgICAgICAgICAgICB2YWx1ZTogcmVnaW9uLFxuICAgICAgICAgICAgICAgIHNob3J0OiB0cnVlLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdGl0bGU6ICdUeXBlJyxcbiAgICAgICAgICAgICAgICB2YWx1ZTogZGV0YWlsLlNvdXJjZVR5cGUsXG4gICAgICAgICAgICAgICAgc2hvcnQ6IHRydWUsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB0aXRsZTogJ0lkZW50aWZpZXInLFxuICAgICAgICAgICAgICAgIHZhbHVlOiBkZXRhaWwuU291cmNlSWRlbnRpZmllcixcbiAgICAgICAgICAgICAgICBzaG9ydDogdHJ1ZSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGFjdGlvbjogJ3N0b3BwZWQnLFxuICAgICAgZmluYWxTdGF0dXMsXG4gICAgICBhY2NvdW50LFxuICAgICAgcmVnaW9uLFxuICAgICAgaWRlbnRpZmllcjogZGV0YWlsLlNvdXJjZUlkZW50aWZpZXIsXG4gICAgfTtcbiAgfSxcbik7XG5cbiJdfQ==
package/lib/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './constructs/rds-database-auto-start-preventer';
2
+ export * from './stacks/rds-database-auto-start-prevent-stack';
package/lib/index.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./constructs/rds-database-auto-start-preventer"), exports);
18
+ __exportStar(require("./stacks/rds-database-auto-start-prevent-stack"), exports);
19
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLGlGQUErRDtBQUMvRCxpRkFBK0QiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgKiBmcm9tICcuL2NvbnN0cnVjdHMvcmRzLWRhdGFiYXNlLWF1dG8tc3RhcnQtcHJldmVudGVyJztcbmV4cG9ydCAqIGZyb20gJy4vc3RhY2tzL3Jkcy1kYXRhYmFzZS1hdXRvLXN0YXJ0LXByZXZlbnQtc3RhY2snOyJdfQ==
@@ -0,0 +1,27 @@
1
+ import { Stack, StackProps } from 'aws-cdk-lib';
2
+ import { Construct } from 'constructs';
3
+ import { TargetResource, Secrets } from '../constructs/rds-database-auto-start-preventer';
4
+ /**
5
+ * Props for the RDS database auto start prevent CDK stack.
6
+ */
7
+ export interface RDSDatabaseAutoStartPreventStackProps extends StackProps {
8
+ /** Tag-based target resource criteria for RDS instances/clusters to protect. */
9
+ readonly targetResource: TargetResource;
10
+ /** Whether the EventBridge rules are enabled. Defaults to true if omitted. */
11
+ readonly enableRule?: boolean;
12
+ /** Secrets (e.g. Slack) for notifications. */
13
+ readonly secrets: Secrets;
14
+ }
15
+ /**
16
+ * CDK Stack that deploys the RDS database auto start prevent (EventBridge Rule + Durable Lambda).
17
+ */
18
+ export declare class RDSDatabaseAutoStartPreventStack extends Stack {
19
+ /**
20
+ * Creates the stack and the RDSDatabaseAutoStartPreventer construct.
21
+ *
22
+ * @param scope - Parent construct.
23
+ * @param id - Stack id.
24
+ * @param props - Stack props (target resource, enable rule, secrets).
25
+ */
26
+ constructor(scope: Construct, id: string, props: RDSDatabaseAutoStartPreventStackProps);
27
+ }