Skip to content
This repository was archived by the owner on Oct 23, 2025. It is now read-only.

Commit ebfe3f0

Browse files
authored
Merge branch 'master' into extracting-predicates
2 parents 9c2a59b + c316d58 commit ebfe3f0

File tree

68 files changed

+1027
-197
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+1027
-197
lines changed

.github/workflows/maven-verify.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ on:
44
push:
55
branches: [ master ]
66
pull_request:
7-
branches: [ master ]
7+
merge_group:
88

99
jobs:
1010
build:

aws-rds-cfn-common/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@
3535
<artifactId>rds</artifactId>
3636
<version>2.25.56</version>
3737
</dependency>
38+
<dependency>
39+
<groupId>software.amazon.cloudformation</groupId>
40+
<artifactId>aws-cloudformation-resource-schema</artifactId>
41+
<version>[2.0.10,3.0.0)</version>
42+
</dependency>
3843
<dependency>
3944
<groupId>software.amazon.cloudformation</groupId>
4045
<artifactId>aws-cloudformation-rpdk-java-plugin</artifactId>

aws-rds-cfn-common/src/main/java/software/amazon/rds/common/handler/Commons.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.util.Map;
66
import java.util.function.Function;
77

8+
import com.google.common.collect.ImmutableMap;
89
import lombok.NonNull;
910
import org.apache.commons.lang3.exception.ExceptionUtils;
1011
import software.amazon.awssdk.core.exception.SdkClientException;
@@ -126,16 +127,16 @@ public static <M, C> ProgressEvent<M, C> reportResourceDrift(
126127
final M inputModel,
127128
final ProgressEvent<M, C> progress,
128129
final ResourceTypeSchema schema,
129-
final RequestLogger logger
130-
) {
130+
final RequestLogger requestLogger,
131+
final String handlerAction) {
131132
try {
132133
final DriftDetector driftDetector = new DriftDetector(schema);
133134
final Map<String, Mutation> mutations = driftDetector.detectDrift(inputModel, progress.getResourceModel());
134135
if (!mutations.isEmpty()) {
135-
logger.log("Resource drift detected", new DriftDetectorReport(mutations));
136+
requestLogger.log("Resource drift detected", ImmutableMap.of("HandlerAction", handlerAction, "Report", new DriftDetectorReport(mutations)));
136137
}
137138
} catch (Exception e) {
138-
logger.log("Drift detector internal error", e);
139+
requestLogger.log("Drift detector internal error", e);
139140
}
140141
return progress;
141142
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
package software.amazon.rds.common.status;
22

3+
/**
4+
* Represents a status that could be considered "terminal" for a resource.
5+
* Terminal states cause resource stabilization to fail immediately. If a
6+
* resource enters a terminal state following a mutation, the operation fails
7+
* with a {@link software.amazon.cloudformation.exceptions.CfnNotStabilizedException}.
8+
*/
39
public interface TerminableStatus extends Status {
10+
/**
11+
* Returns true if the status is terminal.
12+
*/
413
boolean isTerminal();
514
}

aws-rds-cfn-common/src/test/java/software/amazon/rds/common/handler/CommonsTest.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,10 +331,12 @@ void test_detectDrift_shouldLogDriftedModel() {
331331
final TestResourceModel output = new TestResourceModel();
332332
output.testProperty = "test-property-output";
333333

334+
final String handlerOperation = "test-property";
335+
334336
Logger logger = Mockito.mock(Logger.class);
335337
Mockito.doNothing().when(logger).log(any(String.class));
336338

337-
Commons.reportResourceDrift(input, ProgressEvent.<TestResourceModel, Void>progress(output, null), TEST_RESOURCE_TYPE_SCHEMA, new RequestLogger(logger, new ResourceHandlerRequest<>(), new FilteredJsonPrinter()));
339+
Commons.reportResourceDrift(input, ProgressEvent.<TestResourceModel, Void>progress(output, null), TEST_RESOURCE_TYPE_SCHEMA, new RequestLogger(logger, new ResourceHandlerRequest<>(), new FilteredJsonPrinter()), handlerOperation);
338340
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
339341
verify(logger).log(captor.capture());
340342

@@ -350,12 +352,32 @@ void test_detectDrift_shouldNotLogIfModelIsNotDrifted() {
350352
final TestResourceModel output = new TestResourceModel();
351353
output.testProperty = "test-property";
352354

355+
final String handlerOperation = "test-property";
356+
353357
Logger logger = Mockito.mock(Logger.class);
354358

355-
Commons.reportResourceDrift(input, ProgressEvent.<TestResourceModel, Void>progress(output, null), TEST_RESOURCE_TYPE_SCHEMA, new RequestLogger(logger, new ResourceHandlerRequest<>(), new FilteredJsonPrinter()));
359+
Commons.reportResourceDrift(input, ProgressEvent.<TestResourceModel, Void>progress(output, null), TEST_RESOURCE_TYPE_SCHEMA, new RequestLogger(logger, new ResourceHandlerRequest<>(), new FilteredJsonPrinter()), handlerOperation);
356360
verifyNoInteractions(logger);
357361
}
358362

363+
@Test
364+
void test_detectDrift_shouldFailIfSchemaIsNull(){
365+
366+
final TestResourceModel input = new TestResourceModel();
367+
input.testProperty = "test-property";
368+
369+
final TestResourceModel output = new TestResourceModel();
370+
output.testProperty = "test-property-1";
371+
372+
final String handlerOperation = null;
373+
374+
Commons.reportResourceDrift(input, ProgressEvent.<TestResourceModel, Void>progress(output, null), null, requestLogger, handlerOperation);
375+
376+
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
377+
ArgumentCaptor<Exception> exCaptor = ArgumentCaptor.forClass(Exception.class);
378+
verify(requestLogger).log(captor.capture(), exCaptor.capture());
379+
}
380+
359381
private AwsServiceException newAwsServiceException(final ErrorCode errorCode) {
360382
return AwsServiceException.builder()
361383
.awsErrorDetails(AwsErrorDetails.builder()

aws-rds-customdbengineversion/aws-rds-customdbengineversion.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,15 @@
33
"description": "The AWS::RDS::CustomDBEngineVersion resource creates an Amazon RDS custom DB engine version.",
44
"sourceUrl": "https://github.com/aws-cloudformation/aws-cloudformation-rpdk.git",
55
"tagging": {
6-
"taggable": true
6+
"taggable": true,
7+
"tagOnCreate": true,
8+
"tagUpdatable": true,
9+
"cloudFormationSystemTags": true,
10+
"tagProperty": "/properties/Tags",
11+
"permissions": [
12+
"rds:AddTagsToResource",
13+
"rds:RemoveTagsFromResource"
14+
]
715
},
816
"definitions": {
917
"Tag": {
@@ -112,7 +120,7 @@
112120
"propertyTransform": {
113121
"/properties/Engine": "$lowercase(Engine)",
114122
"/properties/EngineVersion": "$lowercase(EngineVersion)",
115-
"/properties/KMSKeyId": "$join([\"arn:(aws)[-]{0,1}[a-z]{0,2}[-]{0,1}[a-z]{0,3}:kms:[a-z]{2}[-]{1}[a-z]{3,10}[-]{0,1}[a-z]{0,10}[-]{1}[1-3]{1}:[0-9]{12}[:]{1}key\\/\", KMSKeyId])"
123+
"/properties/KMSKeyId": "$join([\"arn:.+?:kms:.+?:.+?:key\\/\", KMSKeyId])"
116124
},
117125
"required": [
118126
"Engine",

aws-rds-customdbengineversion/src/main/java/software/amazon/rds/customdbengineversion/BaseHandlerStd.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,9 @@ private void assertNoCustomDbEngineVersionTerminalStatus(final String source) th
156156
private void resourceStabilizationTime(final CallbackContext callbackContext) {
157157
callbackContext.timestampOnce(CUSTOM_DB_ENGINE_VERSION_REQUEST_STARTED_AT, Instant.now());
158158
callbackContext.timestamp(CUSTOM_DB_ENGINE_VERSION_REQUEST_IN_PROGRESS_AT, Instant.now());
159-
callbackContext.calculateTimeDeltaInMinutes(CUSTOM_DB_ENGINE_VERSION_RESOURCE_STABILIZATION_TIME, callbackContext.getTimestamp(CUSTOM_DB_ENGINE_VERSION_REQUEST_IN_PROGRESS_AT), callbackContext.getTimestamp(CUSTOM_DB_ENGINE_VERSION_REQUEST_STARTED_AT));
159+
callbackContext.calculateTimeDeltaInMinutes(CUSTOM_DB_ENGINE_VERSION_RESOURCE_STABILIZATION_TIME,
160+
callbackContext.getTimestamp(CUSTOM_DB_ENGINE_VERSION_REQUEST_IN_PROGRESS_AT),
161+
callbackContext.getTimestamp(CUSTOM_DB_ENGINE_VERSION_REQUEST_STARTED_AT));
160162
}
161163

162164
protected DBEngineVersion fetchDBEngineVersion(final ResourceModel model,

aws-rds-customdbengineversion/src/main/java/software/amazon/rds/customdbengineversion/CallbackContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public Instant getTimestamp(final String label) {
5959

6060
@Override
6161
public void calculateTimeDeltaInMinutes(final String label, final Instant currentTime, final Instant startTime){
62-
double delta = Duration.between(currentTime, startTime).toMinutes();
62+
double delta = Duration.between(startTime, currentTime).toMinutes();
6363
timeDelta.put(label, delta);
6464
}
6565
}

aws-rds-dbcluster/aws-rds-dbcluster.json

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
},
3636
"BacktrackWindow": {
3737
"description": "The target backtrack window, in seconds. To disable backtracking, set this value to 0.",
38-
"default": 0,
3938
"minimum": 0,
4039
"type": "integer"
4140
},
@@ -89,8 +88,7 @@
8988
},
9089
"DBClusterParameterGroupName": {
9190
"description": "The name of the DB cluster parameter group to associate with this DB cluster.",
92-
"type": "string",
93-
"default": "default.aurora5.6"
91+
"type": "string"
9492
},
9593
"DBSubnetGroupName": {
9694
"description": "A DB subnet group that you want to associate with this DB cluster.",
@@ -128,6 +126,10 @@
128126
"description": "A value that indicates whether to enable mapping of AWS Identity and Access Management (IAM) accounts to database accounts. By default, mapping is disabled.",
129127
"type": "boolean"
130128
},
129+
"EnableLocalWriteForwarding": {
130+
"description": "Specifies whether read replicas can forward write operations to the writer DB instance in the DB cluster. By default, write operations aren't allowed on reader DB instances.",
131+
"type": "boolean"
132+
},
131133
"Engine": {
132134
"description": "The name of the database engine to be used for this DB cluster. Valid Values: aurora (for MySQL 5.6-compatible Aurora), aurora-mysql (for MySQL 5.7-compatible Aurora), and aurora-postgresql",
133135
"type": "string"
@@ -171,9 +173,8 @@
171173
"description": "Contains the secret managed by RDS in AWS Secrets Manager for the master user password."
172174
},
173175
"MonitoringInterval": {
174-
"description": "The interval, in seconds, between points when Enhanced Monitoring metrics are collected for the DB cluster. To turn off collecting Enhanced Monitoring metrics, specify 0. The default is 0.",
175-
"type": "integer",
176-
"default": 0
176+
"description": "The interval, in seconds, between points when Enhanced Monitoring metrics are collected for the DB cluster. To turn off collecting Enhanced Monitoring metrics, specify 0. The default is not to enable Enhanced Monitoring.",
177+
"type": "integer"
177178
},
178179
"MonitoringRoleArn": {
179180
"description": "The Amazon Resource Name (ARN) for the IAM role that permits RDS to send Enhanced Monitoring metrics to Amazon CloudWatch Logs.",
@@ -221,8 +222,7 @@
221222
},
222223
"RestoreType": {
223224
"description": "The type of restore to be performed. You can specify one of the following values:\nfull-copy - The new DB cluster is restored as a full copy of the source DB cluster.\ncopy-on-write - The new DB cluster is restored as a clone of the source DB cluster.",
224-
"type": "string",
225-
"default": "full-copy"
225+
"type": "string"
226226
},
227227
"ServerlessV2ScalingConfiguration": {
228228
"description": "Contains the scaling configuration of an Aurora Serverless v2 DB cluster.",
@@ -410,13 +410,13 @@
410410
"/properties/DBClusterIdentifier": "$lowercase(DBClusterIdentifier)",
411411
"/properties/DBClusterParameterGroupName": "$lowercase(DBClusterParameterGroupName)",
412412
"/properties/DBSubnetGroupName": "$lowercase(DBSubnetGroupName)",
413-
"/properties/EnableHttpEndpoint": "$lowercase($string(EngineMode)) = 'serverless' ? EnableHttpEndpoint : ($lowercase($string(Engine)) = 'aurora-postgresql' ? EnableHttpEndpoint : false )",
413+
"/properties/EnableHttpEndpoint": "$lowercase($string(EngineMode)) = 'serverless' ? EnableHttpEndpoint : ($lowercase($string(Engine)) in ['aurora-postgresql', 'aurora-mysql'] ? EnableHttpEndpoint : false )",
414414
"/properties/Engine": "$lowercase(Engine)",
415415
"/properties/EngineVersion": "$join([$string(EngineVersion), \".*\"])",
416-
"/properties/KmsKeyId": "$join([\"arn:(aws)[-]{0,1}[a-z]{0,2}[-]{0,1}[a-z]{0,3}:kms:[a-z]{2}[-]{1}[a-z]{3,10}[-]{0,1}[a-z]{0,10}[-]{1}[1-3]{1}:[0-9]{12}[:]{1}key\\/\", KmsKeyId])",
417-
"/properties/MasterUserSecret/KmsKeyId": "$join([\"arn:(aws)[-]{0,1}[a-z]{0,2}[-]{0,1}[a-z]{0,3}:kms:[a-z]{2}[-]{1}[a-z]{3,10}[-]{0,1}[a-z]{0,10}[-]{1}[1-3]{1}:[0-9]{12}[:]{1}key\\/\", MasterUserSecret.KmsKeyId])",
416+
"/properties/KmsKeyId": "$join([\"arn:.+?:kms:.+?:.+?:key\\/\", KmsKeyId])",
417+
"/properties/MasterUserSecret/KmsKeyId": "$join([\"arn:.+?:kms:.+?:.+?:key\\/\", MasterUserSecret.KmsKeyId])",
418418
"/properties/NetworkType": "$lowercase(NetworkType)",
419-
"/properties/PerformanceInsightsKmsKeyId": "$join([\"arn:(aws)[-]{0,1}[a-z]{0,2}[-]{0,1}[a-z]{0,3}:kms:[a-z]{2}[-]{1}[a-z]{3,10}[-]{0,1}[a-z]{0,10}[-]{1}[1-3]{1}:[0-9]{12}[:]{1}key\\/\", PerformanceInsightsKmsKeyId])",
419+
"/properties/PerformanceInsightsKmsKeyId": "$join([\"arn:.+?:kms:.+?:.+?:key\\/\", PerformanceInsightsKmsKeyId])",
420420
"/properties/PreferredMaintenanceWindow": "$lowercase(PreferredMaintenanceWindow)",
421421
"/properties/SnapshotIdentifier": "$lowercase(SnapshotIdentifier)",
422422
"/properties/SourceDBClusterIdentifier": "$lowercase(SourceDBClusterIdentifier)",
@@ -428,7 +428,6 @@
428428
"/properties/Endpoint",
429429
"/properties/Endpoint/Address",
430430
"/properties/Endpoint/Port",
431-
"/properties/ReadEndpoint/Port",
432431
"/properties/ReadEndpoint/Address",
433432
"/properties/MasterUserSecret/SecretArn",
434433
"/properties/StorageThroughput"
@@ -517,6 +516,7 @@
517516
},
518517
"delete": {
519518
"permissions": [
519+
"rds:AddTagsToResource",
520520
"rds:CreateDBClusterSnapshot",
521521
"rds:DeleteDBCluster",
522522
"rds:DeleteDBInstance",
@@ -530,5 +530,16 @@
530530
"rds:DescribeDBClusters"
531531
]
532532
}
533+
},
534+
"tagging": {
535+
"taggable": true,
536+
"tagOnCreate": true,
537+
"tagUpdatable": true,
538+
"cloudFormationSystemTags": true,
539+
"tagProperty": "/properties/Tags",
540+
"permissions": [
541+
"rds:AddTagsToResource",
542+
"rds:RemoveTagsFromResource"
543+
]
533544
}
534545
}

aws-rds-dbcluster/docs/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ To declare this entity in your AWS CloudFormation template, use the following sy
3535
"<a href="#enableglobalwriteforwarding" title="EnableGlobalWriteForwarding">EnableGlobalWriteForwarding</a>" : <i>Boolean</i>,
3636
"<a href="#enablehttpendpoint" title="EnableHttpEndpoint">EnableHttpEndpoint</a>" : <i>Boolean</i>,
3737
"<a href="#enableiamdatabaseauthentication" title="EnableIAMDatabaseAuthentication">EnableIAMDatabaseAuthentication</a>" : <i>Boolean</i>,
38+
"<a href="#enablelocalwriteforwarding" title="EnableLocalWriteForwarding">EnableLocalWriteForwarding</a>" : <i>Boolean</i>,
3839
"<a href="#engine" title="Engine">Engine</a>" : <i>String</i>,
3940
"<a href="#enginelifecyclesupport" title="EngineLifecycleSupport">EngineLifecycleSupport</a>" : <i>String</i>,
4041
"<a href="#enginemode" title="EngineMode">EngineMode</a>" : <i>String</i>,
@@ -103,6 +104,7 @@ Properties:
103104
<a href="#enableglobalwriteforwarding" title="EnableGlobalWriteForwarding">EnableGlobalWriteForwarding</a>: <i>Boolean</i>
104105
<a href="#enablehttpendpoint" title="EnableHttpEndpoint">EnableHttpEndpoint</a>: <i>Boolean</i>
105106
<a href="#enableiamdatabaseauthentication" title="EnableIAMDatabaseAuthentication">EnableIAMDatabaseAuthentication</a>: <i>Boolean</i>
107+
<a href="#enablelocalwriteforwarding" title="EnableLocalWriteForwarding">EnableLocalWriteForwarding</a>: <i>Boolean</i>
106108
<a href="#engine" title="Engine">Engine</a>: <i>String</i>
107109
<a href="#enginelifecyclesupport" title="EngineLifecycleSupport">EngineLifecycleSupport</a>: <i>String</i>
108110
<a href="#enginemode" title="EngineMode">EngineMode</a>: <i>String</i>
@@ -382,6 +384,16 @@ _Type_: Boolean
382384

383385
_Update requires_: [No interruption](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-no-interrupt)
384386

387+
#### EnableLocalWriteForwarding
388+
389+
Specifies whether read replicas can forward write operations to the writer DB instance in the DB cluster. By default, write operations aren't allowed on reader DB instances.
390+
391+
_Required_: No
392+
393+
_Type_: Boolean
394+
395+
_Update requires_: [No interruption](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-no-interrupt)
396+
385397
#### Engine
386398

387399
The name of the database engine to be used for this DB cluster. Valid Values: aurora (for MySQL 5.6-compatible Aurora), aurora-mysql (for MySQL 5.7-compatible Aurora), and aurora-postgresql

0 commit comments

Comments
 (0)