cdk-factory 0.15.11__tar.gz → 0.15.13__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 (160) hide show
  1. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/PKG-INFO +1 -1
  2. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/pyproject.toml +1 -1
  3. cdk_factory-0.15.13/src/cdk_factory/configurations/resources/rds.py +382 -0
  4. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/pipeline/pipeline_factory.py +1 -0
  5. cdk_factory-0.15.13/src/cdk_factory/stack/stack_factory.py +88 -0
  6. cdk_factory-0.15.13/src/cdk_factory/version.py +1 -0
  7. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/workload/workload_factory.py +1 -0
  8. cdk_factory-0.15.11/src/cdk_factory/configurations/resources/rds.py +0 -148
  9. cdk_factory-0.15.11/src/cdk_factory/stack/stack_factory.py +0 -54
  10. cdk_factory-0.15.11/src/cdk_factory/version.py +0 -1
  11. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/.gitignore +0 -0
  12. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/.windsurfrules +0 -0
  13. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/LICENSE +0 -0
  14. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/README.md +0 -0
  15. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/archive/README.md +0 -0
  16. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/archive/migrate_to_enhanced_ssm.py +0 -0
  17. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/examples/json-imports/README.md +0 -0
  18. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/examples/separate-api-gateway/README.md +0 -0
  19. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/examples/separate-api-gateway/api-gateway-stack.json +0 -0
  20. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/examples/separate-api-gateway/config.json +0 -0
  21. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/examples/separate-api-gateway/lambda-stack.json +0 -0
  22. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/mypy.ini +0 -0
  23. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/publish_to_pypi.py +0 -0
  24. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/publish_to_pypi.sh +0 -0
  25. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/pysetup.py +0 -0
  26. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/pysetup.sh +0 -0
  27. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/requirements.dev.txt +0 -0
  28. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/requirements.tests.txt +0 -0
  29. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/requirements.txt +0 -0
  30. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/run-checks.sh +0 -0
  31. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/run-tests-clean-venv.sh +0 -0
  32. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/run-tests.sh +0 -0
  33. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/scripts/cloudfront-cleanup.sh +0 -0
  34. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/__init__.py +0 -0
  35. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/app.py +0 -0
  36. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/builds/README.md +0 -0
  37. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/cdk.json +0 -0
  38. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/cli.py +0 -0
  39. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/commands/command_loader.py +0 -0
  40. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/base_config.py +0 -0
  41. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/cdk_config.py +0 -0
  42. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/deployment.py +0 -0
  43. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/deployment_wave.py +0 -0
  44. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/devops.py +0 -0
  45. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/enhanced_base_config.py +0 -0
  46. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/enhanced_ssm_config.py +0 -0
  47. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/management.py +0 -0
  48. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/pipeline.py +0 -0
  49. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/pipeline_stage.py +0 -0
  50. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/_resources.py +0 -0
  51. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/api_gateway.py +0 -0
  52. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/apigateway_route_config.py +0 -0
  53. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/auto_scaling.py +0 -0
  54. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/cloudfront.py +0 -0
  55. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/cloudwatch_widget.py +0 -0
  56. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/code_artifact.py +0 -0
  57. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/code_artifact_login.py +0 -0
  58. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/code_repository.py +0 -0
  59. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/cognito.py +0 -0
  60. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/docker.py +0 -0
  61. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/dynamodb.py +0 -0
  62. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/ecr.py +0 -0
  63. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/ecs_service.py +0 -0
  64. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/exisiting.py +0 -0
  65. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/lambda_edge.py +0 -0
  66. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/lambda_function.py +0 -0
  67. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/lambda_layers.py +0 -0
  68. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/lambda_triggers.py +0 -0
  69. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/load_balancer.py +0 -0
  70. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/monitoring.py +0 -0
  71. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/resource_mapping.py +0 -0
  72. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/resource_naming.py +0 -0
  73. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/resource_types.py +0 -0
  74. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/route53.py +0 -0
  75. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/route53_hosted_zone.py +0 -0
  76. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/rum.py +0 -0
  77. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/s3.py +0 -0
  78. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/security_group.py +0 -0
  79. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/security_group_full_stack.py +0 -0
  80. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/sqs.py +0 -0
  81. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/resources/vpc.py +0 -0
  82. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/stack.py +0 -0
  83. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/configurations/workload.py +0 -0
  84. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/constructs/cloudfront/cloudfront_distribution_construct.py +0 -0
  85. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/constructs/ecr/ecr_construct.py +0 -0
  86. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/constructs/lambdas/lambda_function_construct.py +0 -0
  87. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/constructs/lambdas/lambda_function_docker_construct.py +0 -0
  88. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/constructs/lambdas/lambda_function_role_construct.py +0 -0
  89. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/constructs/lambdas/policies/policy_docs.py +0 -0
  90. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/constructs/lambdas/policies/policy_statements.py +0 -0
  91. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/constructs/s3_buckets/s3_bucket_construct.py +0 -0
  92. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/constructs/s3_buckets/s3_bucket_replication_destination_construct.py +0 -0
  93. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/constructs/s3_buckets/s3_bucket_replication_source_construct.py +0 -0
  94. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/constructs/sqs/policies/sqs_policies.py +0 -0
  95. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/interfaces/enhanced_ssm_parameter_mixin.py +0 -0
  96. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/interfaces/istack.py +0 -0
  97. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/interfaces/live_ssm_resolver.py +0 -0
  98. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/interfaces/ssm_parameter_mixin.py +0 -0
  99. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/lambdas/edge/ip_gate/handler.py +0 -0
  100. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/lambdas/health_handler.py +0 -0
  101. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/pipeline/path_utils.py +0 -0
  102. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/pipeline/security/policies.py +0 -0
  103. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/pipeline/security/roles.py +0 -0
  104. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/pipeline/stage.py +0 -0
  105. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack/istack.py +0 -0
  106. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack/stack_module_loader.py +0 -0
  107. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack/stack_module_registry.py +0 -0
  108. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack/stack_modules.py +0 -0
  109. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/__init__.py +0 -0
  110. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/api_gateway/api_gateway_stack.py +0 -0
  111. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/auto_scaling/__init__.py +0 -0
  112. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/auto_scaling/auto_scaling_stack.py +0 -0
  113. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/aws_lambdas/lambda_stack.py +0 -0
  114. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/buckets/README.md +0 -0
  115. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/buckets/bucket_stack.py +0 -0
  116. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/cloudfront/__init__.py +0 -0
  117. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/cloudfront/cloudfront_stack.py +0 -0
  118. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/code_artifact/code_artifact_stack.py +0 -0
  119. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/cognito/cognito_stack.py +0 -0
  120. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/dynamodb/dynamodb_stack.py +0 -0
  121. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/ecr/README.md +0 -0
  122. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/ecr/ecr_stack.py +0 -0
  123. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/ecs/__init__.py +0 -0
  124. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/ecs/ecs_service_stack.py +0 -0
  125. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/lambda_edge/__init__.py +0 -0
  126. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/lambda_edge/lambda_edge_stack.py +0 -0
  127. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/load_balancer/__init__.py +0 -0
  128. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/load_balancer/load_balancer_stack.py +0 -0
  129. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/monitoring/__init__.py +0 -0
  130. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/monitoring/monitoring_stack.py +0 -0
  131. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/rds/__init__.py +0 -0
  132. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/rds/rds_stack.py +0 -0
  133. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/route53/__init__.py +0 -0
  134. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/route53/route53_stack.py +0 -0
  135. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/rum/__init__.py +0 -0
  136. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/rum/rum_stack.py +0 -0
  137. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/security_group/__init__.py +0 -0
  138. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/security_group/security_group_full_stack.py +0 -0
  139. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/security_group/security_group_stack.py +0 -0
  140. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/simple_queue_service/sqs_stack.py +0 -0
  141. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/stack_base.py +0 -0
  142. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/vpc/__init__.py +0 -0
  143. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/vpc/vpc_stack.py +0 -0
  144. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stack_library/websites/static_website_stack.py +0 -0
  145. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/stages/websites/static_website_stage.py +0 -0
  146. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/templates/README.md +0 -0
  147. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/templates/app.py.template +0 -0
  148. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/templates/cdk.json.template +0 -0
  149. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/utilities/api_gateway_integration_utility.py +0 -0
  150. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/utilities/commandline_args.py +0 -0
  151. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/utilities/configuration_loader.py +0 -0
  152. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/utilities/docker_utilities.py +0 -0
  153. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/utilities/environment_services.py +0 -0
  154. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/utilities/file_operations.py +0 -0
  155. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/utilities/git_utilities.py +0 -0
  156. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/utilities/json_loading_utility.py +0 -0
  157. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/utilities/lambda_function_utilities.py +0 -0
  158. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/utilities/os_execute.py +0 -0
  159. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/src/cdk_factory/utils/api_gateway_utilities.py +0 -0
  160. {cdk_factory-0.15.11 → cdk_factory-0.15.13}/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.11
3
+ Version: 0.15.13
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.11"
36
+ version = "0.15.13"
37
37
  authors = [
38
38
  { name="Eric Wilson", email="eric.wilson@geekcafe.com" }
39
39
  ]
@@ -0,0 +1,382 @@
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
+ """Log types to export to CloudWatch"""
184
+ return self.__config.get("cloudwatch_logs_exports", ["postgresql"])
185
+
186
+ @property
187
+ def removal_policy(self) -> str:
188
+ """Removal policy for the database"""
189
+ return self.__config.get("removal_policy", "retain")
190
+
191
+ @property
192
+ def existing_instance_id(self) -> Optional[str]:
193
+ """Existing RDS instance ID to import (if using existing)"""
194
+ return self.__config.get("existing_instance_id")
195
+
196
+ @property
197
+ def tags(self) -> Dict[str, str]:
198
+ """Tags to apply to the RDS instance"""
199
+ return self.__config.get("tags", {})
200
+
201
+ @property
202
+ def vpc_id(self) -> str | None:
203
+ """Returns the VPC ID for the Security Group"""
204
+ return self.__config.get("vpc_id")
205
+
206
+ @vpc_id.setter
207
+ def vpc_id(self, value: str):
208
+ """Sets the VPC ID for the Security Group"""
209
+ self.__config["vpc_id"] = value
210
+
211
+ @property
212
+ def ssm_imports(self) -> Dict[str, str]:
213
+ """SSM parameter imports for the RDS instance"""
214
+ # Check both nested and flat structures for backwards compatibility
215
+ if "ssm" in self.__config and "imports" in self.__config["ssm"]:
216
+ return self.__config["ssm"]["imports"]
217
+ return self.__config.get("ssm_imports", {})
218
+
219
+ @property
220
+ def ssm_exports(self) -> Dict[str, str]:
221
+ """SSM parameter exports for the RDS instance"""
222
+ # Check both nested and flat structures for backwards compatibility
223
+ if "ssm" in self.__config and "exports" in self.__config["ssm"]:
224
+ return self.__config["ssm"]["exports"]
225
+ return self.__config.get("ssm_exports", {})
226
+
227
+ def _sanitize_database_name(self, name: str) -> str:
228
+ """
229
+ Sanitize database name to meet RDS requirements (engine-specific).
230
+ Implements rules from RDS documentation for each engine type.
231
+
232
+ Args:
233
+ name: Raw database name from config
234
+
235
+ Returns:
236
+ Sanitized database name
237
+
238
+ Raises:
239
+ ValueError: If name cannot be sanitized to meet requirements
240
+ """
241
+ if not name:
242
+ raise ValueError("Database name cannot be empty")
243
+
244
+ engine = self.engine.lower()
245
+ sanitized, notes = self._sanitize_db_name_impl(engine, name)
246
+
247
+ if notes:
248
+ logger.info(f"Sanitized database name from '{name}' to '{sanitized}': {', '.join(notes)}")
249
+
250
+ return sanitized
251
+
252
+ def _sanitize_db_name_impl(self, engine: str, name: str) -> Tuple[str, List[str]]:
253
+ """
254
+ Engine-specific database name sanitization.
255
+ Based on AWS RDS naming requirements:
256
+ - MySQL/MariaDB: 1-64 chars, start with letter, letters/digits/underscore
257
+ - PostgreSQL: 1-63 chars, start with letter, letters/digits/underscore
258
+ - SQL Server: 1-128 chars, start with letter, letters/digits/underscore
259
+ - Oracle: 1-8 chars (SID), alphanumeric only, start with letter
260
+ """
261
+ notes: List[str] = []
262
+
263
+ # Determine engine-specific limits
264
+ if engine in ("mysql", "mariadb", "aurora-mysql"):
265
+ allowed_chars = r"A-Za-z0-9_"
266
+ max_len = 64
267
+ elif engine in ("postgres", "postgresql", "aurora-postgres", "aurora-postgresql"):
268
+ allowed_chars = r"A-Za-z0-9_"
269
+ max_len = 63
270
+ elif engine in ("sqlserver", "sqlserver-ee", "sqlserver-se", "sqlserver-ex", "sqlserver-web"):
271
+ allowed_chars = r"A-Za-z0-9_"
272
+ max_len = 128
273
+ elif engine in ("oracle", "oracle-ee", "oracle-se2", "oracle-se1"):
274
+ allowed_chars = r"A-Za-z0-9" # No underscore for Oracle SID
275
+ max_len = 8
276
+ else:
277
+ # Default to conservative rules
278
+ allowed_chars = r"A-Za-z0-9_"
279
+ max_len = 64
280
+ notes.append(f"unknown engine '{engine}', using default MySQL rules")
281
+
282
+ # Replace hyphens with underscores (except Oracle which doesn't allow underscores)
283
+ s = name
284
+ if "oracle" not in engine:
285
+ s = s.replace("-", "_")
286
+ if "_" in name and "-" in name:
287
+ notes.append("replaced hyphens with underscores")
288
+
289
+ # Strip disallowed characters
290
+ s_clean = re.sub(f"[^{allowed_chars}]", "", s)
291
+ if s_clean != s:
292
+ notes.append("removed invalid characters")
293
+ s = s_clean
294
+
295
+ if not s:
296
+ raise ValueError(f"Database name '{name}' contains no valid characters after sanitization")
297
+
298
+ # Must start with a letter
299
+ if not re.match(r"^[A-Za-z]", s):
300
+ s = f"db{s}"
301
+ notes.append("prefixed with 'db' to start with a letter")
302
+
303
+ # Truncate to max length
304
+ if len(s) > max_len:
305
+ s = s[:max_len]
306
+ notes.append(f"truncated to {max_len} characters")
307
+
308
+ # SQL Server: can't start with 'rdsadmin'
309
+ if "sqlserver" in engine and s.lower().startswith("rdsadmin"):
310
+ s = f"db_{s}"
311
+ notes.append("prefixed to avoid 'rdsadmin' (SQL Server restriction)")
312
+
313
+ return s, notes
314
+
315
+ def _sanitize_username(self, username: str) -> str:
316
+ """
317
+ Sanitize master username to meet RDS requirements:
318
+ - Must begin with a letter (a-z, A-Z)
319
+ - Can contain alphanumeric characters and underscores
320
+ - Max 16 characters (AWS RDS master username limit)
321
+ - Cannot be a reserved word
322
+
323
+ Args:
324
+ username: Raw username from config
325
+
326
+ Returns:
327
+ Sanitized username
328
+
329
+ Raises:
330
+ ValueError: If username is invalid
331
+ """
332
+ if not username:
333
+ raise ValueError("Username cannot be empty")
334
+
335
+ sanitized, notes = self._sanitize_master_username_impl(username)
336
+
337
+ if notes:
338
+ logger.info(f"Sanitized username from '{username}' to '{sanitized}': {', '.join(notes)}")
339
+
340
+ return sanitized
341
+
342
+ def _sanitize_master_username_impl(self, username: str) -> Tuple[str, List[str]]:
343
+ """
344
+ Sanitize master username according to AWS RDS rules:
345
+ - 1-16 characters
346
+ - Start with a letter
347
+ - Letters, digits, underscore only
348
+ - Not a reserved word
349
+ """
350
+ notes: List[str] = []
351
+ s = username
352
+
353
+ # Replace hyphens with underscores, remove other invalid chars
354
+ s = s.replace("-", "_")
355
+ s_clean = re.sub(r"[^A-Za-z0-9_]", "", s)
356
+ if s_clean != s:
357
+ notes.append("removed invalid characters")
358
+ s = s_clean
359
+
360
+ if not s:
361
+ raise ValueError(f"Username '{username}' contains no valid characters after sanitization")
362
+
363
+ # Must start with a letter
364
+ if not re.match(r"^[A-Za-z]", s):
365
+ s = f"user{s}"
366
+ notes.append("prefixed with 'user' to start with a letter")
367
+
368
+ # Truncate to 16 characters
369
+ if len(s) > 16:
370
+ s = s[:16]
371
+ notes.append("truncated to 16 characters")
372
+
373
+ # Check against common reserved words
374
+ reserved = {"postgres", "mysql", "root", "admin", "rdsadmin", "system", "sa", "user"}
375
+ if s.lower() in reserved:
376
+ s = f"{s}_usr"
377
+ # Re-truncate if needed after adding suffix
378
+ if len(s) > 16:
379
+ s = s[:16]
380
+ notes.append("appended '_usr' to avoid reserved username")
381
+
382
+ return s, notes
@@ -305,6 +305,7 @@ class PipelineFactoryStack(IStack):
305
305
  scope=pipeline_stage,
306
306
  id=stack_config.name,
307
307
  deployment=deployment,
308
+ stack_config=stack_config,
308
309
  add_env_context=self.add_env_context,
309
310
  **kwargs,
310
311
  )
@@ -0,0 +1,88 @@
1
+ """
2
+ Geek Cafe, LLC
3
+ Maintainers: Eric Wilson
4
+ MIT License. See Project Root for the license information.
5
+ """
6
+
7
+ from typing import Type, Dict, Any, Optional
8
+
9
+ from aws_cdk import Environment
10
+ from cdk_factory.interfaces.istack import IStack
11
+ from cdk_factory.stack.stack_module_loader import ModuleLoader
12
+ from cdk_factory.stack.stack_module_registry import modules
13
+ from cdk_factory.configurations.deployment import DeploymentConfig
14
+ from cdk_factory.configurations.stack import StackConfig
15
+
16
+
17
+ class StackFactory:
18
+ """Stack Factory"""
19
+
20
+ # Default descriptions by module type
21
+ DEFAULT_DESCRIPTIONS = {
22
+ "vpc_stack": "VPC infrastructure with public and private subnets across multiple availability zones",
23
+ "security_group_stack": "Security groups for network access control",
24
+ "security_group_full_stack": "Security groups for ALB, ECS, RDS, and monitoring",
25
+ "rds_stack": "Managed relational database instance with automated backups",
26
+ "s3_bucket_stack": "S3 bucket for object storage",
27
+ "media_bucket_stack": "S3 bucket for media asset storage with CDN integration",
28
+ "static_website_stack": "Static website hosted on S3 with CloudFront distribution",
29
+ "ecs_service_stack": "ECS service with auto-scaling and load balancing",
30
+ "lambda_stack": "Lambda function for serverless compute",
31
+ "api_gateway_stack": "API Gateway for REST API endpoints",
32
+ "cloudfront_stack": "CloudFront CDN distribution",
33
+ "monitoring_stack": "CloudWatch monitoring, alarms, and dashboards",
34
+ "ecr_stack": "Elastic Container Registry for Docker images",
35
+ }
36
+
37
+ def __init__(self):
38
+ ml: ModuleLoader = ModuleLoader()
39
+
40
+ ml.load_known_modules()
41
+
42
+ def load_module(
43
+ self,
44
+ module_name: str,
45
+ scope,
46
+ id: str, # pylint: disable=redefined-builtin
47
+ deployment: Optional[DeploymentConfig] = None,
48
+ stack_config: Optional[StackConfig] = None,
49
+ add_env_context: bool = True,
50
+ **kwargs,
51
+ ) -> IStack:
52
+ """Loads a particular module"""
53
+ # print(f"loading module: {module_name}")
54
+ stack_class: Type[IStack] = modules.get(module_name)
55
+ if not stack_class:
56
+ raise ValueError(f"Failed to load module: {module_name}")
57
+
58
+ # Add environment information if deployment is provided and add_env_context is True
59
+ if deployment and add_env_context:
60
+ env_kwargs = self._get_environment_kwargs(deployment)
61
+ kwargs.update(env_kwargs)
62
+
63
+ # Add description if not already provided in kwargs
64
+ if "description" not in kwargs:
65
+ description = self._get_stack_description(module_name, stack_config)
66
+ if description:
67
+ kwargs["description"] = description
68
+
69
+ module = stack_class(scope=scope, id=id, **kwargs)
70
+
71
+ return module
72
+
73
+ def _get_environment_kwargs(self, deployment: DeploymentConfig) -> Dict[str, Any]:
74
+ """Get environment kwargs from deployment config"""
75
+ env = Environment(
76
+ account=deployment.account,
77
+ region=deployment.region
78
+ )
79
+ return {"env": env}
80
+
81
+ def _get_stack_description(self, module_name: str, stack_config: Optional[StackConfig] = None) -> Optional[str]:
82
+ """Get stack description from config or default"""
83
+ # First check if stack_config has a description
84
+ if stack_config and stack_config.description:
85
+ return stack_config.description
86
+
87
+ # Otherwise use default description based on module type
88
+ return self.DEFAULT_DESCRIPTIONS.get(module_name)
@@ -0,0 +1 @@
1
+ __version__ = "0.15.13"
@@ -124,6 +124,7 @@ class WorkloadFactory:
124
124
  scope=self.app,
125
125
  id=stack.name,
126
126
  deployment=deployment,
127
+ stack_config=stack,
127
128
  add_env_context=self.add_env_context,
128
129
  **kwargs,
129
130
  )
@@ -1,148 +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
- from typing import Any, Dict, List, Optional
8
- from cdk_factory.configurations.enhanced_base_config import EnhancedBaseConfig
9
-
10
-
11
- class RdsConfig(EnhancedBaseConfig):
12
- """
13
- RDS Configuration - supports RDS database settings.
14
- Each property reads from the config dict and provides a sensible default if not set.
15
- """
16
-
17
- def __init__(self, config: dict, deployment) -> None:
18
- super().__init__(config or {}, resource_type="rds", resource_name=config.get("name", "rds") if config else "rds")
19
- self.__config = config or {}
20
- self.__deployment = deployment
21
-
22
- @property
23
- def name(self) -> str:
24
- """RDS instance name"""
25
- return self.__config.get("name", "database")
26
-
27
- @property
28
- def engine(self) -> str:
29
- """Database engine"""
30
- return self.__config.get("engine", "postgres")
31
-
32
- @property
33
- def engine_version(self) -> str:
34
- """Database engine version"""
35
- engine_version = self.__config.get("engine_version")
36
- if not engine_version:
37
- raise ValueError("No engine version found")
38
- return engine_version
39
-
40
- @property
41
- def instance_class(self) -> str:
42
- """Database instance class"""
43
- return self.__config.get("instance_class", "t3.micro")
44
-
45
- @property
46
- def database_name(self) -> str:
47
- """Name of the database to create"""
48
- return self.__config.get("database_name", "appdb")
49
-
50
- @property
51
- def username(self) -> str:
52
- """Master username for the database"""
53
- return self.__config.get("username", "appuser")
54
-
55
- @property
56
- def secret_name(self) -> str:
57
- """Name of the secret to store credentials"""
58
- env_name = self.__deployment.environment if self.__deployment else None
59
- if not env_name:
60
- raise ValueError("No environment found for RDS secret name. Please add an environment to the deployment.")
61
- return self.__config.get("secret_name", f"/{env_name}/db/creds")
62
-
63
- @property
64
- def allocated_storage(self) -> int:
65
- """Allocated storage in GB"""
66
- # Ensure we return an integer
67
- return int(self.__config.get("allocated_storage", 20))
68
-
69
- @property
70
- def storage_encrypted(self) -> bool:
71
- """Whether storage is encrypted"""
72
- return self.__config.get("storage_encrypted", True)
73
-
74
- @property
75
- def multi_az(self) -> bool:
76
- """Whether to enable Multi-AZ deployment"""
77
- return self.__config.get("multi_az", False)
78
-
79
- @property
80
- def backup_retention(self) -> int:
81
- """Backup retention period in days"""
82
- return self.__config.get("backup_retention", 7)
83
-
84
- @property
85
- def deletion_protection(self) -> bool:
86
- """Whether deletion protection is enabled"""
87
- return self.__config.get("deletion_protection", False)
88
-
89
- @property
90
- def enable_performance_insights(self) -> bool:
91
- """Whether to enable Performance Insights"""
92
- return self.__config.get("enable_performance_insights", True)
93
-
94
- @property
95
- def subnet_group_name(self) -> str:
96
- """Subnet group name for database placement"""
97
- return self.__config.get("subnet_group_name", "db")
98
-
99
- @property
100
- def security_group_ids(self) -> List[str]:
101
- """Security group IDs for the database"""
102
- return self.__config.get("security_group_ids", [])
103
-
104
- @property
105
- def cloudwatch_logs_exports(self) -> List[str]:
106
- """Log types to export to CloudWatch"""
107
- return self.__config.get("cloudwatch_logs_exports", ["postgresql"])
108
-
109
- @property
110
- def removal_policy(self) -> str:
111
- """Removal policy for the database"""
112
- return self.__config.get("removal_policy", "retain")
113
-
114
- @property
115
- def existing_instance_id(self) -> Optional[str]:
116
- """Existing RDS instance ID to import (if using existing)"""
117
- return self.__config.get("existing_instance_id")
118
-
119
- @property
120
- def tags(self) -> Dict[str, str]:
121
- """Tags to apply to the RDS instance"""
122
- return self.__config.get("tags", {})
123
-
124
- @property
125
- def vpc_id(self) -> str | None:
126
- """Returns the VPC ID for the Security Group"""
127
- return self.__config.get("vpc_id")
128
-
129
- @vpc_id.setter
130
- def vpc_id(self, value: str):
131
- """Sets the VPC ID for the Security Group"""
132
- self.__config["vpc_id"] = value
133
-
134
- @property
135
- def ssm_imports(self) -> Dict[str, str]:
136
- """SSM parameter imports for the RDS instance"""
137
- # Check both nested and flat structures for backwards compatibility
138
- if "ssm" in self.__config and "imports" in self.__config["ssm"]:
139
- return self.__config["ssm"]["imports"]
140
- return self.__config.get("ssm_imports", {})
141
-
142
- @property
143
- def ssm_exports(self) -> Dict[str, str]:
144
- """SSM parameter exports for the RDS instance"""
145
- # Check both nested and flat structures for backwards compatibility
146
- if "ssm" in self.__config and "exports" in self.__config["ssm"]:
147
- return self.__config["ssm"]["exports"]
148
- return self.__config.get("ssm_exports", {})