cdk-factory 0.15.12__tar.gz → 0.15.14__tar.gz

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.

Potentially problematic release.


This version of cdk-factory might be problematic. Click here for more details.

Files changed (159) hide show
  1. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/PKG-INFO +1 -1
  2. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/pyproject.toml +1 -1
  3. cdk_factory-0.15.14/src/cdk_factory/configurations/resources/rds.py +411 -0
  4. cdk_factory-0.15.14/src/cdk_factory/version.py +1 -0
  5. cdk_factory-0.15.12/src/cdk_factory/configurations/resources/rds.py +0 -240
  6. cdk_factory-0.15.12/src/cdk_factory/version.py +0 -1
  7. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/.gitignore +0 -0
  8. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/.windsurfrules +0 -0
  9. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/LICENSE +0 -0
  10. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/README.md +0 -0
  11. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/archive/README.md +0 -0
  12. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/archive/migrate_to_enhanced_ssm.py +0 -0
  13. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/examples/json-imports/README.md +0 -0
  14. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/examples/separate-api-gateway/README.md +0 -0
  15. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/examples/separate-api-gateway/api-gateway-stack.json +0 -0
  16. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/examples/separate-api-gateway/config.json +0 -0
  17. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/examples/separate-api-gateway/lambda-stack.json +0 -0
  18. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/mypy.ini +0 -0
  19. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/publish_to_pypi.py +0 -0
  20. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/publish_to_pypi.sh +0 -0
  21. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/pysetup.py +0 -0
  22. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/pysetup.sh +0 -0
  23. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/requirements.dev.txt +0 -0
  24. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/requirements.tests.txt +0 -0
  25. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/requirements.txt +0 -0
  26. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/run-checks.sh +0 -0
  27. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/run-tests-clean-venv.sh +0 -0
  28. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/run-tests.sh +0 -0
  29. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/scripts/cloudfront-cleanup.sh +0 -0
  30. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/__init__.py +0 -0
  31. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/app.py +0 -0
  32. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/builds/README.md +0 -0
  33. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/cdk.json +0 -0
  34. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/cli.py +0 -0
  35. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/commands/command_loader.py +0 -0
  36. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/base_config.py +0 -0
  37. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/cdk_config.py +0 -0
  38. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/deployment.py +0 -0
  39. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/deployment_wave.py +0 -0
  40. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/devops.py +0 -0
  41. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/enhanced_base_config.py +0 -0
  42. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/enhanced_ssm_config.py +0 -0
  43. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/management.py +0 -0
  44. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/pipeline.py +0 -0
  45. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/pipeline_stage.py +0 -0
  46. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/_resources.py +0 -0
  47. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/api_gateway.py +0 -0
  48. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/apigateway_route_config.py +0 -0
  49. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/auto_scaling.py +0 -0
  50. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/cloudfront.py +0 -0
  51. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/cloudwatch_widget.py +0 -0
  52. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/code_artifact.py +0 -0
  53. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/code_artifact_login.py +0 -0
  54. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/code_repository.py +0 -0
  55. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/cognito.py +0 -0
  56. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/docker.py +0 -0
  57. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/dynamodb.py +0 -0
  58. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/ecr.py +0 -0
  59. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/ecs_service.py +0 -0
  60. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/exisiting.py +0 -0
  61. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/lambda_edge.py +0 -0
  62. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/lambda_function.py +0 -0
  63. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/lambda_layers.py +0 -0
  64. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/lambda_triggers.py +0 -0
  65. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/load_balancer.py +0 -0
  66. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/monitoring.py +0 -0
  67. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/resource_mapping.py +0 -0
  68. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/resource_naming.py +0 -0
  69. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/resource_types.py +0 -0
  70. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/route53.py +0 -0
  71. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/route53_hosted_zone.py +0 -0
  72. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/rum.py +0 -0
  73. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/s3.py +0 -0
  74. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/security_group.py +0 -0
  75. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/security_group_full_stack.py +0 -0
  76. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/sqs.py +0 -0
  77. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/resources/vpc.py +0 -0
  78. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/stack.py +0 -0
  79. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/configurations/workload.py +0 -0
  80. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/constructs/cloudfront/cloudfront_distribution_construct.py +0 -0
  81. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/constructs/ecr/ecr_construct.py +0 -0
  82. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/constructs/lambdas/lambda_function_construct.py +0 -0
  83. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/constructs/lambdas/lambda_function_docker_construct.py +0 -0
  84. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/constructs/lambdas/lambda_function_role_construct.py +0 -0
  85. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/constructs/lambdas/policies/policy_docs.py +0 -0
  86. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/constructs/lambdas/policies/policy_statements.py +0 -0
  87. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/constructs/s3_buckets/s3_bucket_construct.py +0 -0
  88. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/constructs/s3_buckets/s3_bucket_replication_destination_construct.py +0 -0
  89. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/constructs/s3_buckets/s3_bucket_replication_source_construct.py +0 -0
  90. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/constructs/sqs/policies/sqs_policies.py +0 -0
  91. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/interfaces/enhanced_ssm_parameter_mixin.py +0 -0
  92. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/interfaces/istack.py +0 -0
  93. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/interfaces/live_ssm_resolver.py +0 -0
  94. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/interfaces/ssm_parameter_mixin.py +0 -0
  95. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/lambdas/edge/ip_gate/handler.py +0 -0
  96. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/lambdas/health_handler.py +0 -0
  97. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/pipeline/path_utils.py +0 -0
  98. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/pipeline/pipeline_factory.py +0 -0
  99. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/pipeline/security/policies.py +0 -0
  100. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/pipeline/security/roles.py +0 -0
  101. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/pipeline/stage.py +0 -0
  102. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack/istack.py +0 -0
  103. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack/stack_factory.py +0 -0
  104. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack/stack_module_loader.py +0 -0
  105. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack/stack_module_registry.py +0 -0
  106. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack/stack_modules.py +0 -0
  107. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/__init__.py +0 -0
  108. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/api_gateway/api_gateway_stack.py +0 -0
  109. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/auto_scaling/__init__.py +0 -0
  110. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/auto_scaling/auto_scaling_stack.py +0 -0
  111. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/aws_lambdas/lambda_stack.py +0 -0
  112. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/buckets/README.md +0 -0
  113. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/buckets/bucket_stack.py +0 -0
  114. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/cloudfront/__init__.py +0 -0
  115. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/cloudfront/cloudfront_stack.py +0 -0
  116. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/code_artifact/code_artifact_stack.py +0 -0
  117. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/cognito/cognito_stack.py +0 -0
  118. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/dynamodb/dynamodb_stack.py +0 -0
  119. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/ecr/README.md +0 -0
  120. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/ecr/ecr_stack.py +0 -0
  121. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/ecs/__init__.py +0 -0
  122. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/ecs/ecs_service_stack.py +0 -0
  123. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/lambda_edge/__init__.py +0 -0
  124. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/lambda_edge/lambda_edge_stack.py +0 -0
  125. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/load_balancer/__init__.py +0 -0
  126. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/load_balancer/load_balancer_stack.py +0 -0
  127. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/monitoring/__init__.py +0 -0
  128. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/monitoring/monitoring_stack.py +0 -0
  129. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/rds/__init__.py +0 -0
  130. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/rds/rds_stack.py +0 -0
  131. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/route53/__init__.py +0 -0
  132. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/route53/route53_stack.py +0 -0
  133. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/rum/__init__.py +0 -0
  134. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/rum/rum_stack.py +0 -0
  135. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/security_group/__init__.py +0 -0
  136. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/security_group/security_group_full_stack.py +0 -0
  137. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/security_group/security_group_stack.py +0 -0
  138. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/simple_queue_service/sqs_stack.py +0 -0
  139. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/stack_base.py +0 -0
  140. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/vpc/__init__.py +0 -0
  141. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/vpc/vpc_stack.py +0 -0
  142. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stack_library/websites/static_website_stack.py +0 -0
  143. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/stages/websites/static_website_stage.py +0 -0
  144. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/templates/README.md +0 -0
  145. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/templates/app.py.template +0 -0
  146. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/templates/cdk.json.template +0 -0
  147. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/utilities/api_gateway_integration_utility.py +0 -0
  148. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/utilities/commandline_args.py +0 -0
  149. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/utilities/configuration_loader.py +0 -0
  150. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/utilities/docker_utilities.py +0 -0
  151. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/utilities/environment_services.py +0 -0
  152. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/utilities/file_operations.py +0 -0
  153. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/utilities/git_utilities.py +0 -0
  154. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/utilities/json_loading_utility.py +0 -0
  155. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/utilities/lambda_function_utilities.py +0 -0
  156. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/utilities/os_execute.py +0 -0
  157. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/utils/api_gateway_utilities.py +0 -0
  158. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/cdk_factory/workload/workload_factory.py +0 -0
  159. {cdk_factory-0.15.12 → cdk_factory-0.15.14}/src/handlers/test/handler.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cdk_factory
3
- Version: 0.15.12
3
+ Version: 0.15.14
4
4
  Summary: CDK Factory. A QuickStarter and best practices setup for CDK projects
5
5
  Author-email: Eric Wilson <eric.wilson@geekcafe.com>
6
6
  License: MIT License
@@ -33,7 +33,7 @@ markers = [
33
33
  [project]
34
34
 
35
35
  name = "cdk_factory"
36
- version = "0.15.12"
36
+ version = "0.15.14"
37
37
  authors = [
38
38
  { name="Eric Wilson", email="eric.wilson@geekcafe.com" }
39
39
  ]
@@ -0,0 +1,411 @@
1
+ """
2
+ RdsConfig - supports RDS database settings for AWS CDK.
3
+ Maintainers: Eric Wilson
4
+ MIT License. See Project Root for license information.
5
+ """
6
+
7
+ import re
8
+ from typing import Any, Dict, List, Optional, Tuple, Literal
9
+ from aws_lambda_powertools import Logger
10
+ from cdk_factory.configurations.enhanced_base_config import EnhancedBaseConfig
11
+
12
+ logger = Logger(service="RdsConfig")
13
+
14
+ # Supported RDS engines
15
+ Engine = Literal["mysql", "mariadb", "postgres", "aurora-mysql", "aurora-postgres", "sqlserver", "oracle"]
16
+
17
+
18
+ class RdsConfig(EnhancedBaseConfig):
19
+ """
20
+ RDS Configuration - supports RDS database settings.
21
+ Each property reads from the config dict and provides a sensible default if not set.
22
+ """
23
+
24
+ def __init__(self, config: dict, deployment) -> None:
25
+ super().__init__(config or {}, resource_type="rds", resource_name=config.get("name", "rds") if config else "rds")
26
+ self.__config = config or {}
27
+ self.__deployment = deployment
28
+
29
+ @property
30
+ def name(self) -> str:
31
+ """RDS instance name"""
32
+ return self.__config.get("name", "database")
33
+
34
+ @property
35
+ def identifier(self) -> str:
36
+ """RDS DB instance identifier (sanitized)"""
37
+ raw_id = self.__config.get("identifier", self.name)
38
+ return self._sanitize_instance_identifier(raw_id)
39
+
40
+ def _sanitize_instance_identifier(self, identifier: str) -> str:
41
+ """
42
+ Sanitize DB instance identifier to meet RDS requirements:
43
+ - 1-63 chars, lowercase letters/digits/hyphen
44
+ - Must start with letter, can't end with hyphen, no consecutive hyphens
45
+ """
46
+ if not identifier:
47
+ raise ValueError("Instance identifier cannot be empty")
48
+
49
+ sanitized, notes = self._sanitize_instance_identifier_impl(identifier)
50
+
51
+ if notes:
52
+ logger.info(f"Sanitized instance identifier from '{identifier}' to '{sanitized}': {', '.join(notes)}")
53
+
54
+ return sanitized
55
+
56
+ def _sanitize_instance_identifier_impl(self, identifier: str) -> Tuple[str, List[str]]:
57
+ """
58
+ DB instance identifier rules (all engines):
59
+ - 1-63 chars, lowercase letters/digits/hyphen
60
+ - Must start with letter
61
+ - Can't end with hyphen
62
+ - No consecutive hyphens (--)
63
+ """
64
+ notes: List[str] = []
65
+ s = identifier.lower()
66
+
67
+ # Keep only lowercase letters, digits, hyphen
68
+ s_clean = re.sub(r"[^a-z0-9-]", "", s)
69
+ if s_clean != s:
70
+ notes.append("removed invalid characters (only a-z, 0-9, '-' allowed)")
71
+ s = s_clean
72
+
73
+ if not s:
74
+ raise ValueError(f"Instance identifier '{identifier}' contains no valid characters")
75
+
76
+ # Must start with letter
77
+ if not re.match(r"^[a-z]", s):
78
+ s = f"db{s}"
79
+ notes.append("prefixed with 'db' to start with a letter")
80
+
81
+ # Collapse consecutive hyphens
82
+ s_collapsed = re.sub(r"-{2,}", "-", s)
83
+ if s_collapsed != s:
84
+ s = s_collapsed
85
+ notes.append("collapsed consecutive hyphens")
86
+
87
+ # Can't end with hyphen
88
+ if s.endswith("-"):
89
+ s = s.rstrip("-")
90
+ notes.append("removed trailing hyphen")
91
+
92
+ # Truncate to 63 characters
93
+ if len(s) > 63:
94
+ s = s[:63]
95
+ # Make sure we didn't truncate to a trailing hyphen
96
+ if s.endswith("-"):
97
+ s = s.rstrip("-")
98
+ notes.append("truncated to 63 characters")
99
+
100
+ return s, notes
101
+
102
+ @property
103
+ def engine(self) -> str:
104
+ """Database engine"""
105
+ return self.__config.get("engine", "postgres")
106
+
107
+ @property
108
+ def engine_version(self) -> str:
109
+ """Database engine version"""
110
+ engine_version = self.__config.get("engine_version")
111
+ if not engine_version:
112
+ raise ValueError("No engine version found")
113
+ return engine_version
114
+
115
+ @property
116
+ def instance_class(self) -> str:
117
+ """Database instance class"""
118
+ return self.__config.get("instance_class", "t3.micro")
119
+
120
+ @property
121
+ def database_name(self) -> str:
122
+ """Name of the database to create (sanitized for RDS requirements)"""
123
+ raw_name = self.__config.get("database_name", "appdb")
124
+ return self._sanitize_database_name(raw_name)
125
+
126
+ @property
127
+ def username(self) -> str:
128
+ """Master username for the database (sanitized for RDS requirements)"""
129
+ raw_username = self.__config.get("username", "appuser")
130
+ return self._sanitize_username(raw_username)
131
+
132
+ @property
133
+ def secret_name(self) -> str:
134
+ """Name of the secret to store credentials"""
135
+ env_name = self.__deployment.environment if self.__deployment else None
136
+ if not env_name:
137
+ raise ValueError("No environment found for RDS secret name. Please add an environment to the deployment.")
138
+ return self.__config.get("secret_name", f"/{env_name}/db/creds")
139
+
140
+ @property
141
+ def allocated_storage(self) -> int:
142
+ """Allocated storage in GB"""
143
+ # Ensure we return an integer
144
+ return int(self.__config.get("allocated_storage", 20))
145
+
146
+ @property
147
+ def storage_encrypted(self) -> bool:
148
+ """Whether storage is encrypted"""
149
+ return self.__config.get("storage_encrypted", True)
150
+
151
+ @property
152
+ def multi_az(self) -> bool:
153
+ """Whether to enable Multi-AZ deployment"""
154
+ return self.__config.get("multi_az", False)
155
+
156
+ @property
157
+ def backup_retention(self) -> int:
158
+ """Backup retention period in days"""
159
+ return self.__config.get("backup_retention", 7)
160
+
161
+ @property
162
+ def deletion_protection(self) -> bool:
163
+ """Whether deletion protection is enabled"""
164
+ return self.__config.get("deletion_protection", False)
165
+
166
+ @property
167
+ def enable_performance_insights(self) -> bool:
168
+ """Whether to enable Performance Insights"""
169
+ return self.__config.get("enable_performance_insights", True)
170
+
171
+ @property
172
+ def subnet_group_name(self) -> str:
173
+ """Subnet group name for database placement"""
174
+ return self.__config.get("subnet_group_name", "db")
175
+
176
+ @property
177
+ def security_group_ids(self) -> List[str]:
178
+ """Security group IDs for the database"""
179
+ return self.__config.get("security_group_ids", [])
180
+
181
+ @property
182
+ def cloudwatch_logs_exports(self) -> List[str]:
183
+ """
184
+ Log types to export to CloudWatch (engine-specific).
185
+ Returns configured log types or engine-specific defaults.
186
+ """
187
+ # If explicitly configured, use that
188
+ if "cloudwatch_logs_exports" in self.__config:
189
+ return self.__config["cloudwatch_logs_exports"]
190
+
191
+ # Otherwise, return engine-specific defaults
192
+ engine = self.engine.lower()
193
+
194
+ # MySQL / MariaDB
195
+ if engine in ("mysql", "mariadb", "aurora-mysql"):
196
+ return ["error", "general", "slowquery"]
197
+
198
+ # PostgreSQL
199
+ elif engine in ("postgres", "postgresql", "aurora-postgres", "aurora-postgresql"):
200
+ return ["postgresql"]
201
+
202
+ # SQL Server
203
+ elif engine in ("sqlserver", "sqlserver-ee", "sqlserver-se", "sqlserver-ex", "sqlserver-web"):
204
+ return ["error", "agent"]
205
+
206
+ # Oracle
207
+ elif engine in ("oracle", "oracle-ee", "oracle-se2", "oracle-se1"):
208
+ return ["alert", "audit", "trace"]
209
+
210
+ # Default to empty list for unknown engines (safer than guessing)
211
+ else:
212
+ logger.warning(f"Unknown engine '{engine}', disabling CloudWatch logs exports by default")
213
+ return []
214
+
215
+ @property
216
+ def removal_policy(self) -> str:
217
+ """Removal policy for the database"""
218
+ return self.__config.get("removal_policy", "retain")
219
+
220
+ @property
221
+ def existing_instance_id(self) -> Optional[str]:
222
+ """Existing RDS instance ID to import (if using existing)"""
223
+ return self.__config.get("existing_instance_id")
224
+
225
+ @property
226
+ def tags(self) -> Dict[str, str]:
227
+ """Tags to apply to the RDS instance"""
228
+ return self.__config.get("tags", {})
229
+
230
+ @property
231
+ def vpc_id(self) -> str | None:
232
+ """Returns the VPC ID for the Security Group"""
233
+ return self.__config.get("vpc_id")
234
+
235
+ @vpc_id.setter
236
+ def vpc_id(self, value: str):
237
+ """Sets the VPC ID for the Security Group"""
238
+ self.__config["vpc_id"] = value
239
+
240
+ @property
241
+ def ssm_imports(self) -> Dict[str, str]:
242
+ """SSM parameter imports for the RDS instance"""
243
+ # Check both nested and flat structures for backwards compatibility
244
+ if "ssm" in self.__config and "imports" in self.__config["ssm"]:
245
+ return self.__config["ssm"]["imports"]
246
+ return self.__config.get("ssm_imports", {})
247
+
248
+ @property
249
+ def ssm_exports(self) -> Dict[str, str]:
250
+ """SSM parameter exports for the RDS instance"""
251
+ # Check both nested and flat structures for backwards compatibility
252
+ if "ssm" in self.__config and "exports" in self.__config["ssm"]:
253
+ return self.__config["ssm"]["exports"]
254
+ return self.__config.get("ssm_exports", {})
255
+
256
+ def _sanitize_database_name(self, name: str) -> str:
257
+ """
258
+ Sanitize database name to meet RDS requirements (engine-specific).
259
+ Implements rules from RDS documentation for each engine type.
260
+
261
+ Args:
262
+ name: Raw database name from config
263
+
264
+ Returns:
265
+ Sanitized database name
266
+
267
+ Raises:
268
+ ValueError: If name cannot be sanitized to meet requirements
269
+ """
270
+ if not name:
271
+ raise ValueError("Database name cannot be empty")
272
+
273
+ engine = self.engine.lower()
274
+ sanitized, notes = self._sanitize_db_name_impl(engine, name)
275
+
276
+ if notes:
277
+ logger.info(f"Sanitized database name from '{name}' to '{sanitized}': {', '.join(notes)}")
278
+
279
+ return sanitized
280
+
281
+ def _sanitize_db_name_impl(self, engine: str, name: str) -> Tuple[str, List[str]]:
282
+ """
283
+ Engine-specific database name sanitization.
284
+ Based on AWS RDS naming requirements:
285
+ - MySQL/MariaDB: 1-64 chars, start with letter, letters/digits/underscore
286
+ - PostgreSQL: 1-63 chars, start with letter, letters/digits/underscore
287
+ - SQL Server: 1-128 chars, start with letter, letters/digits/underscore
288
+ - Oracle: 1-8 chars (SID), alphanumeric only, start with letter
289
+ """
290
+ notes: List[str] = []
291
+
292
+ # Determine engine-specific limits
293
+ if engine in ("mysql", "mariadb", "aurora-mysql"):
294
+ allowed_chars = r"A-Za-z0-9_"
295
+ max_len = 64
296
+ elif engine in ("postgres", "postgresql", "aurora-postgres", "aurora-postgresql"):
297
+ allowed_chars = r"A-Za-z0-9_"
298
+ max_len = 63
299
+ elif engine in ("sqlserver", "sqlserver-ee", "sqlserver-se", "sqlserver-ex", "sqlserver-web"):
300
+ allowed_chars = r"A-Za-z0-9_"
301
+ max_len = 128
302
+ elif engine in ("oracle", "oracle-ee", "oracle-se2", "oracle-se1"):
303
+ allowed_chars = r"A-Za-z0-9" # No underscore for Oracle SID
304
+ max_len = 8
305
+ else:
306
+ # Default to conservative rules
307
+ allowed_chars = r"A-Za-z0-9_"
308
+ max_len = 64
309
+ notes.append(f"unknown engine '{engine}', using default MySQL rules")
310
+
311
+ # Replace hyphens with underscores (except Oracle which doesn't allow underscores)
312
+ s = name
313
+ if "oracle" not in engine:
314
+ s = s.replace("-", "_")
315
+ if "_" in name and "-" in name:
316
+ notes.append("replaced hyphens with underscores")
317
+
318
+ # Strip disallowed characters
319
+ s_clean = re.sub(f"[^{allowed_chars}]", "", s)
320
+ if s_clean != s:
321
+ notes.append("removed invalid characters")
322
+ s = s_clean
323
+
324
+ if not s:
325
+ raise ValueError(f"Database name '{name}' contains no valid characters after sanitization")
326
+
327
+ # Must start with a letter
328
+ if not re.match(r"^[A-Za-z]", s):
329
+ s = f"db{s}"
330
+ notes.append("prefixed with 'db' to start with a letter")
331
+
332
+ # Truncate to max length
333
+ if len(s) > max_len:
334
+ s = s[:max_len]
335
+ notes.append(f"truncated to {max_len} characters")
336
+
337
+ # SQL Server: can't start with 'rdsadmin'
338
+ if "sqlserver" in engine and s.lower().startswith("rdsadmin"):
339
+ s = f"db_{s}"
340
+ notes.append("prefixed to avoid 'rdsadmin' (SQL Server restriction)")
341
+
342
+ return s, notes
343
+
344
+ def _sanitize_username(self, username: str) -> str:
345
+ """
346
+ Sanitize master username to meet RDS requirements:
347
+ - Must begin with a letter (a-z, A-Z)
348
+ - Can contain alphanumeric characters and underscores
349
+ - Max 16 characters (AWS RDS master username limit)
350
+ - Cannot be a reserved word
351
+
352
+ Args:
353
+ username: Raw username from config
354
+
355
+ Returns:
356
+ Sanitized username
357
+
358
+ Raises:
359
+ ValueError: If username is invalid
360
+ """
361
+ if not username:
362
+ raise ValueError("Username cannot be empty")
363
+
364
+ sanitized, notes = self._sanitize_master_username_impl(username)
365
+
366
+ if notes:
367
+ logger.info(f"Sanitized username from '{username}' to '{sanitized}': {', '.join(notes)}")
368
+
369
+ return sanitized
370
+
371
+ def _sanitize_master_username_impl(self, username: str) -> Tuple[str, List[str]]:
372
+ """
373
+ Sanitize master username according to AWS RDS rules:
374
+ - 1-16 characters
375
+ - Start with a letter
376
+ - Letters, digits, underscore only
377
+ - Not a reserved word
378
+ """
379
+ notes: List[str] = []
380
+ s = username
381
+
382
+ # Replace hyphens with underscores, remove other invalid chars
383
+ s = s.replace("-", "_")
384
+ s_clean = re.sub(r"[^A-Za-z0-9_]", "", s)
385
+ if s_clean != s:
386
+ notes.append("removed invalid characters")
387
+ s = s_clean
388
+
389
+ if not s:
390
+ raise ValueError(f"Username '{username}' contains no valid characters after sanitization")
391
+
392
+ # Must start with a letter
393
+ if not re.match(r"^[A-Za-z]", s):
394
+ s = f"user{s}"
395
+ notes.append("prefixed with 'user' to start with a letter")
396
+
397
+ # Truncate to 16 characters
398
+ if len(s) > 16:
399
+ s = s[:16]
400
+ notes.append("truncated to 16 characters")
401
+
402
+ # Check against common reserved words
403
+ reserved = {"postgres", "mysql", "root", "admin", "rdsadmin", "system", "sa", "user"}
404
+ if s.lower() in reserved:
405
+ s = f"{s}_usr"
406
+ # Re-truncate if needed after adding suffix
407
+ if len(s) > 16:
408
+ s = s[:16]
409
+ notes.append("appended '_usr' to avoid reserved username")
410
+
411
+ return s, notes
@@ -0,0 +1 @@
1
+ __version__ = "0.15.14"
@@ -1,240 +0,0 @@
1
- """
2
- RdsConfig - supports RDS database settings for AWS CDK.
3
- Maintainers: Eric Wilson
4
- MIT License. See Project Root for license information.
5
- """
6
-
7
- import re
8
- from typing import Any, Dict, List, Optional
9
- from aws_lambda_powertools import Logger
10
- from cdk_factory.configurations.enhanced_base_config import EnhancedBaseConfig
11
-
12
- logger = Logger(service="RdsConfig")
13
-
14
-
15
- class RdsConfig(EnhancedBaseConfig):
16
- """
17
- RDS Configuration - supports RDS database settings.
18
- Each property reads from the config dict and provides a sensible default if not set.
19
- """
20
-
21
- def __init__(self, config: dict, deployment) -> None:
22
- super().__init__(config or {}, resource_type="rds", resource_name=config.get("name", "rds") if config else "rds")
23
- self.__config = config or {}
24
- self.__deployment = deployment
25
-
26
- @property
27
- def name(self) -> str:
28
- """RDS instance name"""
29
- return self.__config.get("name", "database")
30
-
31
- @property
32
- def engine(self) -> str:
33
- """Database engine"""
34
- return self.__config.get("engine", "postgres")
35
-
36
- @property
37
- def engine_version(self) -> str:
38
- """Database engine version"""
39
- engine_version = self.__config.get("engine_version")
40
- if not engine_version:
41
- raise ValueError("No engine version found")
42
- return engine_version
43
-
44
- @property
45
- def instance_class(self) -> str:
46
- """Database instance class"""
47
- return self.__config.get("instance_class", "t3.micro")
48
-
49
- @property
50
- def database_name(self) -> str:
51
- """Name of the database to create (sanitized for RDS requirements)"""
52
- raw_name = self.__config.get("database_name", "appdb")
53
- return self._sanitize_database_name(raw_name)
54
-
55
- @property
56
- def username(self) -> str:
57
- """Master username for the database (sanitized for RDS requirements)"""
58
- raw_username = self.__config.get("username", "appuser")
59
- return self._sanitize_username(raw_username)
60
-
61
- @property
62
- def secret_name(self) -> str:
63
- """Name of the secret to store credentials"""
64
- env_name = self.__deployment.environment if self.__deployment else None
65
- if not env_name:
66
- raise ValueError("No environment found for RDS secret name. Please add an environment to the deployment.")
67
- return self.__config.get("secret_name", f"/{env_name}/db/creds")
68
-
69
- @property
70
- def allocated_storage(self) -> int:
71
- """Allocated storage in GB"""
72
- # Ensure we return an integer
73
- return int(self.__config.get("allocated_storage", 20))
74
-
75
- @property
76
- def storage_encrypted(self) -> bool:
77
- """Whether storage is encrypted"""
78
- return self.__config.get("storage_encrypted", True)
79
-
80
- @property
81
- def multi_az(self) -> bool:
82
- """Whether to enable Multi-AZ deployment"""
83
- return self.__config.get("multi_az", False)
84
-
85
- @property
86
- def backup_retention(self) -> int:
87
- """Backup retention period in days"""
88
- return self.__config.get("backup_retention", 7)
89
-
90
- @property
91
- def deletion_protection(self) -> bool:
92
- """Whether deletion protection is enabled"""
93
- return self.__config.get("deletion_protection", False)
94
-
95
- @property
96
- def enable_performance_insights(self) -> bool:
97
- """Whether to enable Performance Insights"""
98
- return self.__config.get("enable_performance_insights", True)
99
-
100
- @property
101
- def subnet_group_name(self) -> str:
102
- """Subnet group name for database placement"""
103
- return self.__config.get("subnet_group_name", "db")
104
-
105
- @property
106
- def security_group_ids(self) -> List[str]:
107
- """Security group IDs for the database"""
108
- return self.__config.get("security_group_ids", [])
109
-
110
- @property
111
- def cloudwatch_logs_exports(self) -> List[str]:
112
- """Log types to export to CloudWatch"""
113
- return self.__config.get("cloudwatch_logs_exports", ["postgresql"])
114
-
115
- @property
116
- def removal_policy(self) -> str:
117
- """Removal policy for the database"""
118
- return self.__config.get("removal_policy", "retain")
119
-
120
- @property
121
- def existing_instance_id(self) -> Optional[str]:
122
- """Existing RDS instance ID to import (if using existing)"""
123
- return self.__config.get("existing_instance_id")
124
-
125
- @property
126
- def tags(self) -> Dict[str, str]:
127
- """Tags to apply to the RDS instance"""
128
- return self.__config.get("tags", {})
129
-
130
- @property
131
- def vpc_id(self) -> str | None:
132
- """Returns the VPC ID for the Security Group"""
133
- return self.__config.get("vpc_id")
134
-
135
- @vpc_id.setter
136
- def vpc_id(self, value: str):
137
- """Sets the VPC ID for the Security Group"""
138
- self.__config["vpc_id"] = value
139
-
140
- @property
141
- def ssm_imports(self) -> Dict[str, str]:
142
- """SSM parameter imports for the RDS instance"""
143
- # Check both nested and flat structures for backwards compatibility
144
- if "ssm" in self.__config and "imports" in self.__config["ssm"]:
145
- return self.__config["ssm"]["imports"]
146
- return self.__config.get("ssm_imports", {})
147
-
148
- @property
149
- def ssm_exports(self) -> Dict[str, str]:
150
- """SSM parameter exports for the RDS instance"""
151
- # Check both nested and flat structures for backwards compatibility
152
- if "ssm" in self.__config and "exports" in self.__config["ssm"]:
153
- return self.__config["ssm"]["exports"]
154
- return self.__config.get("ssm_exports", {})
155
-
156
- def _sanitize_database_name(self, name: str) -> str:
157
- """
158
- Sanitize database name to meet RDS requirements:
159
- - Must begin with a letter (a-z, A-Z)
160
- - Can contain alphanumeric characters and underscores
161
- - Max 64 characters
162
-
163
- Args:
164
- name: Raw database name from config
165
-
166
- Returns:
167
- Sanitized database name
168
-
169
- Raises:
170
- ValueError: If name starts with a number or is empty after sanitization
171
- """
172
- if not name:
173
- raise ValueError("Database name cannot be empty")
174
-
175
- # Replace hyphens with underscores, remove other invalid chars
176
- sanitized = name.replace('-', '_')
177
- sanitized = re.sub(r'[^a-zA-Z0-9_]', '', sanitized)
178
-
179
- if not sanitized:
180
- raise ValueError(f"Database name '{name}' contains no valid characters")
181
-
182
- # Check if it starts with a number
183
- if sanitized[0].isdigit():
184
- raise ValueError(
185
- f"Database name '{name}' (sanitized to '{sanitized}') cannot start with a number. "
186
- f"Please ensure the database name begins with a letter."
187
- )
188
-
189
- # Truncate to 64 characters if needed
190
- if len(sanitized) > 64:
191
- sanitized = sanitized[:64]
192
-
193
- # Log if sanitization changed the name
194
- if sanitized != name:
195
- logger.info(f"Sanitized database name from '{name}' to '{sanitized}'")
196
-
197
- return sanitized
198
-
199
- def _sanitize_username(self, username: str) -> str:
200
- """
201
- Sanitize username to meet RDS requirements:
202
- - Must begin with a letter (a-z, A-Z)
203
- - Can contain alphanumeric characters and underscores
204
- - Max 16 characters for MySQL
205
-
206
- Args:
207
- username: Raw username from config
208
-
209
- Returns:
210
- Sanitized username
211
-
212
- Raises:
213
- ValueError: If username is invalid
214
- """
215
- if not username:
216
- raise ValueError("Username cannot be empty")
217
-
218
- # Replace hyphens with underscores, remove other invalid chars
219
- sanitized = username.replace('-', '_')
220
- sanitized = re.sub(r'[^a-zA-Z0-9_]', '', sanitized)
221
-
222
- if not sanitized:
223
- raise ValueError(f"Username '{username}' contains no valid characters")
224
-
225
- # Check if it starts with a number
226
- if sanitized[0].isdigit():
227
- raise ValueError(
228
- f"Username '{username}' (sanitized to '{sanitized}') cannot start with a number. "
229
- f"Please ensure the username begins with a letter."
230
- )
231
-
232
- # Truncate to 16 characters for MySQL (other engines may vary)
233
- if len(sanitized) > 16:
234
- sanitized = sanitized[:16]
235
-
236
- # Log if sanitization changed the username
237
- if sanitized != username:
238
- logger.info(f"Sanitized username from '{username}' to '{sanitized}'")
239
-
240
- return sanitized
@@ -1 +0,0 @@
1
- __version__ = "0.15.12"
File without changes
File without changes
File without changes