1
+ import json
1
2
import typing as t
2
3
3
4
import attr
@@ -199,6 +200,28 @@ def database(self):
199
200
)
200
201
group .add (self ._db_security_group )
201
202
203
+ # aws rds describe-db-parameter-groups
204
+ # aws rds describe-db-parameters --db-parameter-group-name default.postgres15
205
+ db_parameter_group = rds .DBParameterGroup (
206
+ "RDSPostgreSQLParameterGroup" ,
207
+ rp_Family = "postgres15" ,
208
+ rp_Description = "DMS parameter group for postgres15" ,
209
+ p_DBParameterGroupName = "dms-postgres15" ,
210
+ # aws rds describe-db-parameters --db-parameter-group-name default.postgres15
211
+ p_Parameters = {
212
+ "log_connections" : True ,
213
+ # https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.pgaudit.html
214
+ "pgaudit.log" : "all" ,
215
+ "pgaudit.log_statement_once" : True ,
216
+ # `rds.logical_replication is a cluster level setting, not db instance setting?
217
+ # https://stackoverflow.com/a/66252465
218
+ "rds.logical_replication" : True ,
219
+ # TODO: wal2json?
220
+ "shared_preload_libraries" : "pgaudit,pglogical,pg_stat_statements" ,
221
+ },
222
+ )
223
+ group .add (db_parameter_group )
224
+
202
225
db = rds .DBInstance (
203
226
"RDSPostgreSQL" ,
204
227
p_DBInstanceClass = "db.t3.micro" ,
@@ -208,6 +231,7 @@ def database(self):
208
231
# The current default engine version for AWS DMS is 3.5.2.
209
232
# https://docs.aws.amazon.com/dms/latest/userguide/CHAP_ReleaseNotes.html
210
233
p_EngineVersion = "15" ,
234
+ p_DBParameterGroupName = "dms-postgres15" ,
211
235
# The parameter AllocatedStorage must be provided and must not be null.
212
236
# Invalid storage size for engine name postgres and storage type gp2: 1
213
237
p_AllocatedStorage = "5" ,
@@ -235,11 +259,17 @@ def database(self):
235
259
Name = cf .Sub .from_params (f"{ self .env_name } -db" ),
236
260
Description = cf .Sub .from_params (f"The DB instance for { self .env_name } " ),
237
261
),
238
- ra_DependsOn = [self ._db_security_group , self ._db_subnet_group ],
262
+ ra_DependsOn = [db_parameter_group , self ._db_security_group , self ._db_subnet_group ],
239
263
)
240
264
self ._db = db
241
265
group .add (db )
242
266
267
+ rds_arn = cf .Output (
268
+ "RDSInstanceArn" ,
269
+ Value = db .rv_DBInstanceArn ,
270
+ )
271
+ group .add (rds_arn )
272
+
243
273
public_endpoint = cf .Output (
244
274
"PublicDbEndpoint" ,
245
275
Value = db .rv_EndpointAddress ,
@@ -406,6 +436,9 @@ def dms(self):
406
436
)
407
437
group .add (vpc_endpoint_stream )
408
438
439
+ # https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.PostgreSQL.html#CHAP_Source.PostgreSQL.Advanced
440
+ # https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.PostgreSQL.html#CHAP_Source.PostgreSQL.RDSPostgreSQL
441
+ # https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.PostgreSQL.html#CHAP_Source.PostgreSQL.ConnectionAttrib
409
442
source_endpoint = dms .Endpoint ( # type: ignore[call-arg,misc]
410
443
"DMSSourceEndpoint" ,
411
444
rp_EndpointType = "source" ,
@@ -417,6 +450,12 @@ def dms(self):
417
450
p_Username = self .db_username ,
418
451
p_Password = self .db_password ,
419
452
p_DatabaseName = "postgres" ,
453
+ p_ExtraConnectionAttributes = json .dumps (
454
+ {
455
+ "CaptureDdls" : True ,
456
+ "PluginName" : "pglogical" ,
457
+ }
458
+ ),
420
459
p_EndpointIdentifier = f"{ self .env_name } -endpoint-source" ,
421
460
ra_DependsOn = [self ._db ],
422
461
)
@@ -427,6 +466,12 @@ def dms(self):
427
466
p_KinesisSettings = dms .PropEndpointKinesisSettings (
428
467
p_StreamArn = self ._stream .rv_Arn ,
429
468
p_MessageFormat = "json-unformatted" ,
469
+ p_IncludeControlDetails = True ,
470
+ p_IncludePartitionValue = True ,
471
+ p_IncludeTransactionDetails = True ,
472
+ p_IncludeNullAndEmpty = True ,
473
+ p_IncludeTableAlterOperations = True ,
474
+ p_PartitionIncludeSchemaTable = True ,
430
475
# The parameter ServiceAccessRoleArn must be provided and must not be blank.
431
476
p_ServiceAccessRoleArn = dms_target_access_role .rv_Arn ,
432
477
),
@@ -437,6 +482,7 @@ def dms(self):
437
482
group .add (target_endpoint )
438
483
439
484
# FIXME: Currently hard-coded to table `public.foo`.
485
+ # https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Kinesis.html
440
486
map_to_kinesis = {
441
487
"rules" : [
442
488
{
@@ -466,7 +512,7 @@ def dms(self):
466
512
"DMSReplicationConfig" ,
467
513
rp_ReplicationConfigIdentifier = f"{ self .env_name } -dms-serverless" ,
468
514
# p_ResourceIdentifier=f"{self.env_name}-dms-serverless-resource", # noqa: ERA001
469
- rp_ReplicationType = "full-load" ,
515
+ rp_ReplicationType = "full-load-and-cdc " ,
470
516
rp_SourceEndpointArn = source_endpoint .ref (),
471
517
rp_TargetEndpointArn = target_endpoint .ref (),
472
518
rp_ComputeConfig = dms .PropReplicationConfigComputeConfig (
@@ -478,6 +524,12 @@ def dms(self):
478
524
),
479
525
rp_TableMappings = map_to_kinesis ,
480
526
p_ReplicationSettings = {
527
+ # https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Tasks.CustomizingTasks.TaskSettings.BeforeImage.html
528
+ "BeforeImageSettings" : {
529
+ "EnableBeforeImage" : True ,
530
+ "FieldName" : "before-image" ,
531
+ "ColumnFilter" : "pk-only" ,
532
+ },
481
533
# https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Tasks.CustomizingTasks.TaskSettings.Logging.html
482
534
"Logging" : {
483
535
"EnableLogging" : True ,
@@ -507,7 +559,7 @@ def dms(self):
507
559
# {"Id": "VALIDATOR", "Severity": "LOGGER_SEVERITY_DETAILED_DEBUG"}, # noqa: ERA001
508
560
{"Id" : "VALIDATOR_EXT" , "Severity" : "LOGGER_SEVERITY_DETAILED_DEBUG" },
509
561
],
510
- }
562
+ },
511
563
},
512
564
ra_DependsOn = [
513
565
dms_replication_subnet_group ,
@@ -521,6 +573,12 @@ def dms(self):
521
573
)
522
574
group .add (serverless_replication )
523
575
576
+ replication_arn = cf .Output (
577
+ "ReplicationArn" ,
578
+ Value = serverless_replication .rv_ReplicationConfigArn ,
579
+ )
580
+ group .add (replication_arn )
581
+
524
582
return self .add (group )
525
583
526
584
@property
0 commit comments