cdk-factory 0.18.12__tar.gz → 0.18.15__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 (167) hide show
  1. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/PKG-INFO +1 -1
  2. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/pyproject.toml +1 -1
  3. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/ecs_service.py +24 -2
  4. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/route53.py +5 -0
  5. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/interfaces/standardized_ssm_mixin.py +17 -0
  6. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/cloudfront/cloudfront_stack.py +8 -3
  7. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/ecs/ecs_service_stack.py +1 -1
  8. cdk_factory-0.18.15/src/cdk_factory/stack_library/route53/route53_stack.py +449 -0
  9. cdk_factory-0.18.15/src/cdk_factory/version.py +1 -0
  10. cdk_factory-0.18.12/src/cdk_factory/stack_library/route53/route53_stack.py +0 -210
  11. cdk_factory-0.18.12/src/cdk_factory/version.py +0 -1
  12. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/.gitignore +0 -0
  13. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/.windsurfrules +0 -0
  14. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/LICENSE +0 -0
  15. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/README.md +0 -0
  16. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/REFACTORING_PLAN.md +0 -0
  17. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/archive/README.md +0 -0
  18. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/archive/migrate_to_enhanced_ssm.py +0 -0
  19. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/examples/json-imports/README.md +0 -0
  20. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/examples/separate-api-gateway/README.md +0 -0
  21. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/examples/separate-api-gateway/api-gateway-stack.json +0 -0
  22. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/examples/separate-api-gateway/config.json +0 -0
  23. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/examples/separate-api-gateway/lambda-stack.json +0 -0
  24. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/mypy.ini +0 -0
  25. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/publish_to_pypi.py +0 -0
  26. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/publish_to_pypi.sh +0 -0
  27. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/pysetup.py +0 -0
  28. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/pysetup.sh +0 -0
  29. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/requirements.dev.txt +0 -0
  30. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/requirements.tests.txt +0 -0
  31. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/requirements.txt +0 -0
  32. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/run-checks.sh +0 -0
  33. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/run-tests-clean-venv.sh +0 -0
  34. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/run-tests.sh +0 -0
  35. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/scripts/cloudfront-cleanup.sh +0 -0
  36. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/__init__.py +0 -0
  37. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/app.py +0 -0
  38. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/builds/README.md +0 -0
  39. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/cdk.json +0 -0
  40. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/cli.py +0 -0
  41. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/commands/command_loader.py +0 -0
  42. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/base_config.py +0 -0
  43. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/cdk_config.py +0 -0
  44. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/deployment.py +0 -0
  45. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/deployment_wave.py +0 -0
  46. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/devops.py +0 -0
  47. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/enhanced_base_config.py +0 -0
  48. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/enhanced_ssm_config.py +0 -0
  49. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/management.py +0 -0
  50. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/pipeline.py +0 -0
  51. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/pipeline_stage.py +0 -0
  52. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/_resources.py +0 -0
  53. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/acm.py +0 -0
  54. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/api_gateway.py +0 -0
  55. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/apigateway_route_config.py +0 -0
  56. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/auto_scaling.py +0 -0
  57. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/cloudfront.py +0 -0
  58. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/cloudwatch_widget.py +0 -0
  59. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/code_artifact.py +0 -0
  60. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/code_artifact_login.py +0 -0
  61. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/code_repository.py +0 -0
  62. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/cognito.py +0 -0
  63. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/docker.py +0 -0
  64. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/dynamodb.py +0 -0
  65. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/ecr.py +0 -0
  66. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/ecs_cluster.py +0 -0
  67. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/exisiting.py +0 -0
  68. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/lambda_edge.py +0 -0
  69. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/lambda_function.py +0 -0
  70. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/lambda_layers.py +0 -0
  71. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/lambda_triggers.py +0 -0
  72. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/load_balancer.py +0 -0
  73. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/monitoring.py +0 -0
  74. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/rds.py +0 -0
  75. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/resource_mapping.py +0 -0
  76. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/resource_naming.py +0 -0
  77. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/resource_types.py +0 -0
  78. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/route53_hosted_zone.py +0 -0
  79. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/rum.py +0 -0
  80. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/s3.py +0 -0
  81. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/security_group.py +0 -0
  82. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/security_group_full_stack.py +0 -0
  83. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/sqs.py +0 -0
  84. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/resources/vpc.py +0 -0
  85. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/stack.py +0 -0
  86. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/configurations/workload.py +0 -0
  87. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/constructs/cloudfront/cloudfront_distribution_construct.py +0 -0
  88. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/constructs/ecr/ecr_construct.py +0 -0
  89. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/constructs/lambdas/lambda_function_construct.py +0 -0
  90. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/constructs/lambdas/lambda_function_docker_construct.py +0 -0
  91. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/constructs/lambdas/lambda_function_role_construct.py +0 -0
  92. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/constructs/lambdas/policies/policy_docs.py +0 -0
  93. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/constructs/lambdas/policies/policy_statements.py +0 -0
  94. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/constructs/s3_buckets/s3_bucket_construct.py +0 -0
  95. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/constructs/s3_buckets/s3_bucket_replication_destination_construct.py +0 -0
  96. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/constructs/s3_buckets/s3_bucket_replication_source_construct.py +0 -0
  97. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/constructs/sqs/policies/sqs_policies.py +0 -0
  98. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/interfaces/istack.py +0 -0
  99. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/interfaces/live_ssm_resolver.py +0 -0
  100. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/interfaces/networked_stack_mixin.py +0 -0
  101. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/interfaces/vpc_provider_mixin.py +0 -0
  102. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/lambdas/edge/ip_gate/handler.py +0 -0
  103. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/lambdas/health_handler.py +0 -0
  104. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/pipeline/path_utils.py +0 -0
  105. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/pipeline/pipeline_factory.py +0 -0
  106. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/pipeline/security/policies.py +0 -0
  107. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/pipeline/security/roles.py +0 -0
  108. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/pipeline/stage.py +0 -0
  109. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack/istack.py +0 -0
  110. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack/stack_factory.py +0 -0
  111. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack/stack_module_loader.py +0 -0
  112. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack/stack_module_registry.py +0 -0
  113. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack/stack_modules.py +0 -0
  114. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/__init__.py +0 -0
  115. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/acm/__init__.py +0 -0
  116. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/acm/acm_stack.py +0 -0
  117. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/api_gateway/api_gateway_stack.py +0 -0
  118. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/auto_scaling/__init__.py +0 -0
  119. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/auto_scaling/auto_scaling_stack.py +0 -0
  120. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/aws_lambdas/lambda_stack.py +0 -0
  121. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/buckets/README.md +0 -0
  122. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/buckets/bucket_stack.py +0 -0
  123. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/cloudfront/__init__.py +0 -0
  124. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/code_artifact/code_artifact_stack.py +0 -0
  125. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/cognito/cognito_stack.py +0 -0
  126. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/dynamodb/dynamodb_stack.py +0 -0
  127. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/ecr/README.md +0 -0
  128. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/ecr/ecr_stack.py +0 -0
  129. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/ecs/__init__.py +0 -0
  130. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/ecs/ecs_cluster_stack.py +0 -0
  131. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/lambda_edge/__init__.py +0 -0
  132. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/lambda_edge/lambda_edge_stack.py +0 -0
  133. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/load_balancer/__init__.py +0 -0
  134. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/load_balancer/load_balancer_stack.py +0 -0
  135. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/monitoring/__init__.py +0 -0
  136. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/monitoring/monitoring_stack.py +0 -0
  137. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/rds/__init__.py +0 -0
  138. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/rds/rds_stack.py +0 -0
  139. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/route53/__init__.py +0 -0
  140. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/rum/__init__.py +0 -0
  141. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/rum/rum_stack.py +0 -0
  142. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/security_group/__init__.py +0 -0
  143. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/security_group/security_group_full_stack.py +0 -0
  144. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/security_group/security_group_stack.py +0 -0
  145. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/simple_queue_service/sqs_stack.py +0 -0
  146. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/stack_base.py +0 -0
  147. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/vpc/__init__.py +0 -0
  148. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/vpc/vpc_stack.py +0 -0
  149. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stack_library/websites/static_website_stack.py +0 -0
  150. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/stages/websites/static_website_stage.py +0 -0
  151. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/templates/README.md +0 -0
  152. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/templates/app.py.template +0 -0
  153. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/templates/cdk.json.template +0 -0
  154. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/utilities/api_gateway_integration_utility.py +0 -0
  155. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/utilities/commandline_args.py +0 -0
  156. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/utilities/configuration_loader.py +0 -0
  157. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/utilities/docker_utilities.py +0 -0
  158. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/utilities/environment_services.py +0 -0
  159. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/utilities/file_operations.py +0 -0
  160. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/utilities/git_utilities.py +0 -0
  161. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/utilities/json_loading_utility.py +0 -0
  162. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/utilities/lambda_function_utilities.py +0 -0
  163. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/utilities/os_execute.py +0 -0
  164. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/utils/api_gateway_utilities.py +0 -0
  165. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/validation/config_validator.py +0 -0
  166. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/src/cdk_factory/workload/workload_factory.py +0 -0
  167. {cdk_factory-0.18.12 → cdk_factory-0.18.15}/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.18.12
3
+ Version: 0.18.15
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.18.12"
36
+ version = "0.18.15"
37
37
  authors = [
38
38
  { name="Eric Wilson", email="eric.wilson@geekcafe.com" }
39
39
  ]
@@ -83,14 +83,27 @@ class EcsServiceConfig:
83
83
  """Whether to assign public IP addresses"""
84
84
  return self._config.get("assign_public_ip", False)
85
85
 
86
+ @property
87
+ def load_balancer_config(self) -> Dict[str, Any]:
88
+ """Load balancer configuration"""
89
+ return self._config.get("load_balancer", {})
90
+
86
91
  @property
87
92
  def target_group_arns(self) -> List[str]:
88
93
  """Target group ARNs for load balancing"""
94
+ # Check if load_balancer config has target_group_arn
95
+ if self.load_balancer_config and self.load_balancer_config.get("target_group_arn"):
96
+ arn = self.load_balancer_config["target_group_arn"]
97
+ if arn and arn != "arn:aws:elasticloadbalancing:placeholder":
98
+ return [arn]
89
99
  return self._config.get("target_group_arns", [])
90
100
 
91
101
  @property
92
102
  def container_port(self) -> int:
93
103
  """Container port for load balancer"""
104
+ # Check load_balancer config first
105
+ if self.load_balancer_config and self.load_balancer_config.get("container_port"):
106
+ return self.load_balancer_config["container_port"]
94
107
  return self._config.get("container_port", 80)
95
108
 
96
109
  @property
@@ -138,8 +151,17 @@ class EcsServiceConfig:
138
151
  """SSM parameter imports"""
139
152
  # Check both nested and flat structures for backwards compatibility
140
153
  if "ssm" in self._config and "imports" in self._config["ssm"]:
141
- return self._config["ssm"]["imports"]
142
- return self.ssm.get("imports", {})
154
+ imports = self._config["ssm"]["imports"]
155
+ else:
156
+ imports = self.ssm.get("imports", {})
157
+
158
+ # Add load_balancer SSM imports if they exist
159
+ if self.load_balancer_config and "ssm" in self.load_balancer_config:
160
+ lb_ssm = self.load_balancer_config["ssm"]
161
+ if "imports" in lb_ssm:
162
+ imports.update(lb_ssm["imports"])
163
+
164
+ return imports
143
165
 
144
166
  @property
145
167
  def deployment_type(self) -> str:
@@ -106,3 +106,8 @@ class Route53Config:
106
106
  def tags(self) -> Dict[str, str]:
107
107
  """Tags to apply to the Route53 resources"""
108
108
  return self.__config.get("tags", {})
109
+
110
+ @property
111
+ def records(self) -> List[Dict[str, Any]]:
112
+ """Records to create"""
113
+ return self.__config.get("records", [])
@@ -269,6 +269,23 @@ class StandardizedSsmMixin:
269
269
 
270
270
  return exported_params
271
271
 
272
+ def resolve_ssm_value(self, scope: Construct, value: str, unique_id: str)-> str:
273
+ if isinstance(value, str) and value.startswith("{{ssm:") and value.endswith("}}"):
274
+ # Extract SSM parameter path
275
+ ssm_param_path = value[6:-2] # Remove {{ssm: and }}
276
+
277
+ # Import SSM parameter - this creates a token that resolves at deployment time
278
+ param = ssm.StringParameter.from_string_parameter_name(
279
+ scope=scope,
280
+ id=f"{unique_id}-env-{hash(ssm_param_path) % 10000}",
281
+ string_parameter_name=ssm_param_path
282
+ )
283
+ resolved_value = param.string_value
284
+ logger.info(f"Resolved SSM parameter {ssm_param_path}")
285
+ return resolved_value
286
+ else:
287
+ return value
288
+
272
289
  def _resolve_ssm_import(self, import_value: Union[str, List[str]], import_key: str) -> Union[str, List[str]]:
273
290
  """
274
291
  Resolve SSM import value with proper error handling and validation.
@@ -13,6 +13,7 @@ from aws_cdk import (
13
13
  aws_cloudfront as cloudfront,
14
14
  aws_cloudfront_origins as origins,
15
15
  aws_certificatemanager as acm,
16
+ aws_route53 as route53,
16
17
  aws_lambda as _lambda,
17
18
  aws_ssm as ssm,
18
19
  CfnOutput,
@@ -173,14 +174,18 @@ class CloudFrontStack(IStack):
173
174
  return
174
175
 
175
176
  # Create the certificate
177
+ # Get hosted zone from SSM imports
178
+ hosted_zone_id = cert_config.get("hosted_zone_id")
179
+ hosted_zone = route53.HostedZone.from_hosted_zone_id(
180
+ self, "HostedZone", hosted_zone_id
181
+ )
182
+
176
183
  self.certificate = acm.Certificate(
177
184
  self,
178
185
  "Certificate",
179
186
  domain_name=domain_name,
180
187
  subject_alternative_names=self.cf_config.aliases,
181
- validation_method=acm.ValidationMethod.from_string(
182
- cert_config.get("validation_method", "DNS")
183
- ),
188
+ validation=acm.CertificateValidation.from_dns(hosted_zone=hosted_zone),
184
189
  )
185
190
  logger.info(f"Created new ACM certificate for domain: {domain_name}")
186
191
  return
@@ -563,7 +563,7 @@ class EcsServiceStack(IStack, VPCProviderMixin, StandardizedSsmMixin):
563
563
  for param_key, param_name in ssm_imports.items():
564
564
  if 'target_group' in param_key.lower() or 'tg' in param_key.lower():
565
565
  try:
566
- param_value = self.get_ssm_parameter_value(param_name)
566
+ param_value = self.get_ssm_imported_value(param_name)
567
567
  if param_value and param_value.startswith('arn:'):
568
568
  target_group_arns.append(param_value)
569
569
  except Exception as e:
@@ -0,0 +1,449 @@
1
+ """
2
+ Route53 Stack Pattern for CDK-Factory
3
+ Maintainers: Eric Wilson
4
+ MIT License. See Project Root for the license information.
5
+ """
6
+
7
+ from typing import Dict, Any, List, Optional
8
+
9
+ import aws_cdk as cdk
10
+ from aws_cdk import (
11
+ aws_route53 as route53,
12
+ aws_route53_targets as targets,
13
+ aws_certificatemanager as acm,
14
+ aws_elasticloadbalancingv2 as elbv2,
15
+ aws_cloudfront as cloudfront,
16
+ Duration,
17
+ CfnOutput,
18
+ )
19
+ from aws_lambda_powertools import Logger
20
+ from constructs import Construct
21
+
22
+ from cdk_factory.configurations.deployment import DeploymentConfig
23
+ from cdk_factory.configurations.stack import StackConfig
24
+ from cdk_factory.configurations.resources.route53 import Route53Config
25
+ from cdk_factory.interfaces.istack import IStack
26
+ from cdk_factory.interfaces.standardized_ssm_mixin import StandardizedSsmMixin
27
+ from cdk_factory.stack.stack_module_registry import register_stack
28
+ from cdk_factory.workload.workload_factory import WorkloadConfig
29
+
30
+ logger = Logger(service="Route53Stack")
31
+
32
+
33
+ @register_stack("route53_library_module")
34
+ @register_stack("route53_stack")
35
+ class Route53Stack(IStack, StandardizedSsmMixin):
36
+ """
37
+ Reusable stack for AWS Route53.
38
+ Supports creating hosted zones, DNS records, and certificate validation.
39
+ """
40
+
41
+ def __init__(self, scope: Construct, id: str, **kwargs) -> None:
42
+ super().__init__(scope, id, **kwargs)
43
+
44
+ self.route53_config = None
45
+ self.stack_config = None
46
+ self.deployment = None
47
+ self.workload = None
48
+ self.hosted_zone = None
49
+ self.certificate = None
50
+ self.records = {}
51
+ self._distribution_cache = {} # Cache for reusing distributions
52
+
53
+ def build(self, stack_config: StackConfig, deployment: DeploymentConfig, workload: WorkloadConfig) -> None:
54
+ """Build the Route53 stack"""
55
+ self._build(stack_config, deployment, workload)
56
+
57
+ def _build(self, stack_config: StackConfig, deployment: DeploymentConfig, workload: WorkloadConfig) -> None:
58
+ """Internal build method for the Route53 stack"""
59
+ self.stack_config = stack_config
60
+ self.deployment = deployment
61
+ self.workload = workload
62
+
63
+ self.route53_config = Route53Config(stack_config.dictionary.get("route53", {}), deployment)
64
+
65
+ # Get or create hosted zone
66
+ self.hosted_zone = self._get_or_create_hosted_zone()
67
+
68
+ # Create certificate if needed (DEPRECATED - use dedicated ACM stack)
69
+ if self.route53_config.create_certificate:
70
+ logger.warning(
71
+ "Creating certificates in Route53Stack is deprecated. "
72
+ "Please use the dedicated 'acm_stack' module for certificate management. "
73
+ "This feature will be maintained for backward compatibility."
74
+ )
75
+ self.certificate = self._create_certificate()
76
+
77
+ # Create DNS records
78
+ self._create_dns_records()
79
+
80
+ # Add outputs
81
+ self._add_outputs()
82
+
83
+ def _get_or_create_hosted_zone(self) -> route53.IHostedZone:
84
+ """Get an existing hosted zone or create a new one"""
85
+ if self.route53_config.existing_hosted_zone_id:
86
+ # Import existing hosted zone
87
+ return route53.HostedZone.from_hosted_zone_attributes(
88
+ self,
89
+ "ImportedHostedZone",
90
+ hosted_zone_id=self.route53_config.existing_hosted_zone_id,
91
+ zone_name=self.route53_config.domain_name
92
+ )
93
+ elif self.route53_config.create_hosted_zone:
94
+ # Create new hosted zone
95
+ return route53.PublicHostedZone(
96
+ self,
97
+ "HostedZone",
98
+ zone_name=self.route53_config.domain_name,
99
+ comment=f"Hosted zone for {self.route53_config.domain_name}"
100
+ )
101
+ else:
102
+ # Look up hosted zone by name
103
+ return route53.HostedZone.from_lookup(
104
+ self,
105
+ "LookedUpHostedZone",
106
+ domain_name=self.route53_config.domain_name
107
+ )
108
+
109
+ def _create_certificate(self) -> acm.Certificate:
110
+ """Create an ACM certificate with DNS validation"""
111
+ certificate = acm.Certificate(
112
+ self,
113
+ "Certificate",
114
+ domain_name=self.route53_config.domain_name,
115
+ validation=acm.CertificateValidation.from_dns(self.hosted_zone),
116
+ subject_alternative_names=self.route53_config.subject_alternative_names
117
+ )
118
+
119
+ return certificate
120
+
121
+ def _create_dns_records(self) -> None:
122
+ self._create_dns_records_old()
123
+ self._create_dns_records_new()
124
+
125
+
126
+ def _get_or_create_cloudfront_distribution(self, distribution_domain: str, distribution_id: str) -> cloudfront.Distribution:
127
+ """Get or create a CloudFront distribution, reusing if already created"""
128
+ # Create a unique cache key from distribution domain and ID
129
+ cache_key = f"{distribution_domain}-{distribution_id}"
130
+
131
+ if cache_key not in self._distribution_cache:
132
+ # Create the distribution construct with a unique ID
133
+ unique_id = f"CF-{distribution_domain.replace('.', '-').replace('*', 'wildcard')}-{hash(cache_key) % 10000}"
134
+ distribution = cloudfront.Distribution.from_distribution_attributes(
135
+ self, unique_id,
136
+ domain_name=distribution_domain,
137
+ distribution_id=distribution_id
138
+ )
139
+ self._distribution_cache[cache_key] = distribution
140
+ logger.info(f"Created CloudFront distribution construct for {distribution_domain}")
141
+
142
+ return self._distribution_cache[cache_key]
143
+
144
+ def _create_dns_records_new(self) -> None:
145
+ """Create DNS records based on configuration - generic implementation"""
146
+
147
+ missing_configurations = []
148
+
149
+ for record in self.route53_config.records:
150
+ record_name = record.get("name", "")
151
+ record_type = record.get("type", "")
152
+
153
+ if not record_name or not record_type:
154
+ message = f"Record missing name or type: {record}"
155
+ logger.warning(message)
156
+ missing_configurations.append(message)
157
+ continue
158
+
159
+ # Handle alias records
160
+ if "alias" in record:
161
+ alias_config = record["alias"]
162
+ target_type = alias_config.get("target_type", "")
163
+ target_value = alias_config.get("target_value", "")
164
+ hosted_zone_id = alias_config.get("hosted_zone_id", "")
165
+
166
+ unique_id = f"{record_name}-{record_type}"
167
+ # Handle SSM parameter references in target_value
168
+ target_value = self.resolve_ssm_value(self, target_value, unique_id=unique_id)
169
+
170
+ if not target_type or not target_value:
171
+ message = f"Alias record missing target_type or target_value: {record}"
172
+ logger.warning(message)
173
+ missing_configurations.append(message)
174
+ continue
175
+
176
+ # Create appropriate target based on type
177
+ alias_target = None
178
+ if target_type == "cloudfront":
179
+ # CloudFront distribution target
180
+ distribution_domain = target_value
181
+ distribution_id = alias_config.get("distribution_id", "")
182
+ if not distribution_id:
183
+ message = f"Alias record missing distribution_id: {record}"
184
+ logger.warning(message)
185
+ missing_configurations.append(message)
186
+ continue
187
+
188
+ # Get or create the distribution (reuses if already created)
189
+ distribution = self._get_or_create_cloudfront_distribution(distribution_domain, distribution_id)
190
+ alias_target = route53.RecordTarget.from_alias(
191
+ targets.CloudFrontTarget(distribution)
192
+ )
193
+ elif target_type == "loadbalancer" or target_type == "alb":
194
+ # Load Balancer target
195
+ alias_target = route53.RecordTarget.from_alias(
196
+ targets.LoadBalancerTarget(
197
+ elbv2.ApplicationLoadBalancer.from_load_balancer_attributes(
198
+ self, f"ALB-{record_name}",
199
+ load_balancer_dns_name=target_value,
200
+ load_balancer_canonical_hosted_zone_id=hosted_zone_id
201
+ )
202
+ )
203
+ )
204
+ elif target_type == "elbv2":
205
+ # Generic ELBv2 target
206
+ alias_target = route53.RecordTarget.from_alias(
207
+ targets.LoadBalancerTarget(
208
+ elbv2.ApplicationLoadBalancer.from_load_balancer_attributes(
209
+ self, f"ELB-{record_name}",
210
+ load_balancer_dns_name=target_value,
211
+ load_balancer_canonical_hosted_zone_id=hosted_zone_id
212
+ )
213
+ )
214
+ )
215
+ else:
216
+ message = f"Unsupported alias target type: {target_type}"
217
+ logger.warning(message)
218
+ missing_configurations.append(message)
219
+ continue
220
+
221
+ # Create the alias record
222
+ route53.ARecord(
223
+ self,
224
+ f"AliasRecord-{record_name}-{record_type}",
225
+ zone=self.hosted_zone,
226
+ record_name=record_name,
227
+ target=alias_target,
228
+ ttl=cdk.Duration.seconds(record.get("ttl", 300))
229
+ ) if record_type == "A" else route53.AaaaRecord(
230
+ self,
231
+ f"AliasRecord-{record_name}-{record_type}",
232
+ zone=self.hosted_zone,
233
+ record_name=record_name,
234
+ target=alias_target,
235
+ ttl=cdk.Duration.seconds(record.get("ttl", 300))
236
+ )
237
+
238
+ # Handle standard records with values
239
+ elif "values" in record:
240
+ values = record["values"]
241
+ if not isinstance(values, list):
242
+ values = [values]
243
+
244
+ # Handle SSM parameter references in values
245
+ processed_values = []
246
+ for value in values:
247
+ if "{{ssm:" in str(value) and "}}" in str(value):
248
+ # Extract SSM parameter path from template like {{ssm:/path/to/parameter}}
249
+ ssm_path = str(value).split("{{ssm:")[1].split("}}")[0]
250
+ resolved_value = self.get_ssm_imported_value(ssm_path)
251
+ processed_values.append(resolved_value)
252
+ else:
253
+ processed_values.append(value)
254
+
255
+ values = processed_values
256
+ ttl = record.get("ttl", 300)
257
+
258
+ # Create standard record based on type
259
+ if record_type == "A":
260
+ route53.ARecord(
261
+ self,
262
+ f"Record-{record_name}",
263
+ zone=self.hosted_zone,
264
+ record_name=record_name,
265
+ target=route53.RecordTarget.from_ip_addresses(*values),
266
+ ttl=cdk.Duration.seconds(ttl)
267
+ )
268
+ elif record_type == "AAAA":
269
+ route53.AaaaRecord(
270
+ self,
271
+ f"Record-{record_name}",
272
+ zone=self.hosted_zone,
273
+ record_name=record_name,
274
+ target=route53.RecordTarget.from_ip_addresses(*values),
275
+ ttl=cdk.Duration.seconds(ttl)
276
+ )
277
+ elif record_type == "CNAME":
278
+ route53.CnameRecord(
279
+ self,
280
+ f"Record-{record_name}",
281
+ zone=self.hosted_zone,
282
+ record_name=record_name,
283
+ domain_name=values[0], # CNAME only supports single value
284
+ ttl=cdk.Duration.seconds(ttl)
285
+ )
286
+ elif record_type == "MX":
287
+ # MX records need special handling for preference values
288
+ mx_targets = []
289
+ for value in values:
290
+ if isinstance(value, str) and " " in value:
291
+ preference, domain = value.split(" ", 1)
292
+ mx_targets.append(route53.MxRecordValue(
293
+ domain_name=domain.strip(),
294
+ preference=int(preference.strip())
295
+ ))
296
+ else:
297
+ logger.warning(f"Invalid MX record format: {value}")
298
+
299
+ if mx_targets:
300
+ route53.MxRecord(
301
+ self,
302
+ f"Record-{record_name}",
303
+ zone=self.hosted_zone,
304
+ record_name=record_name,
305
+ values=mx_targets,
306
+ ttl=cdk.Duration.seconds(ttl)
307
+ )
308
+ elif record_type == "TXT":
309
+ route53.TxtRecord(
310
+ self,
311
+ f"Record-{record_name}",
312
+ zone=self.hosted_zone,
313
+ record_name=record_name,
314
+ values=values,
315
+ ttl=cdk.Duration.seconds(ttl)
316
+ )
317
+ elif record_type == "NS":
318
+ route53.NsRecord(
319
+ self,
320
+ f"Record-{record_name}",
321
+ zone=self.hosted_zone,
322
+ record_name=record_name,
323
+ values=values,
324
+ ttl=cdk.Duration.seconds(ttl)
325
+ )
326
+ else:
327
+ message = f"Unsupported record type: {record_type}"
328
+ logger.warning(message)
329
+ missing_configurations.append(message)
330
+ continue
331
+
332
+ else:
333
+ message = f"Record missing 'alias' or 'values' configuration: {record}"
334
+ logger.warning(message)
335
+ missing_configurations.append(message)
336
+ continue
337
+
338
+ if missing_configurations and len(missing_configurations) > 0:
339
+ # print all missing configurations
340
+ print("Missing configurations:")
341
+ for message in missing_configurations:
342
+ print(message)
343
+
344
+ messages = "\n".join(missing_configurations)
345
+ raise ValueError(f"Missing Configurations:\n{messages}")
346
+
347
+ def _create_dns_records_old(self) -> None:
348
+ """Create DNS records based on configuration"""
349
+ # Create alias records
350
+ for alias_record in self.route53_config.aliases:
351
+ record_name = alias_record.get("name", "")
352
+ target_type = alias_record.get("target_type", "")
353
+ target_value = alias_record.get("target_value", "")
354
+
355
+ # target value needs to handle SSM parameters
356
+ if "{{ssm:" in target_value and "}}" in target_value:
357
+ # Extract SSM parameter path from template like {{ssm:/path/to/parameter}}
358
+ ssm_path = target_value.split("{{ssm:")[1].split("}}")[0]
359
+ target_value = self.get_ssm_imported_value(ssm_path)
360
+
361
+ if not record_name or not target_type or not target_value:
362
+ continue
363
+
364
+ # Determine the alias target
365
+ alias_target = None
366
+ if target_type == "alb":
367
+ # Get the ALB from the workload if available
368
+ if hasattr(self.workload, "load_balancer"):
369
+ alb = self.workload.load_balancer
370
+ alias_target = route53.RecordTarget.from_alias(targets.LoadBalancerTarget(alb))
371
+ else:
372
+ # Try to get ALB from target value
373
+ alb = elbv2.ApplicationLoadBalancer.from_lookup(
374
+ self,
375
+ f"ALB-{record_name}",
376
+ load_balancer_arn=target_value
377
+ )
378
+ alias_target = route53.RecordTarget.from_alias(targets.LoadBalancerTarget(alb))
379
+ elif target_type == "cloudfront":
380
+ # For CloudFront, we would need the distribution
381
+ # This is a simplified implementation
382
+ pass
383
+
384
+ if alias_target:
385
+ record = route53.ARecord(
386
+ self,
387
+ f"AliasRecord-{record_name}",
388
+ zone=self.hosted_zone,
389
+ record_name=record_name,
390
+ target=alias_target
391
+ )
392
+ self.records[record_name] = record
393
+
394
+ # Create CNAME records
395
+ for cname_record in self.route53_config.cname_records:
396
+ record_name = cname_record.get("name", "")
397
+ target_domain = cname_record.get("target_domain", "")
398
+ ttl = cname_record.get("ttl", 300)
399
+
400
+ if not record_name or not target_domain:
401
+ continue
402
+
403
+ record = route53.CnameRecord(
404
+ self,
405
+ f"CnameRecord-{record_name}",
406
+ zone=self.hosted_zone,
407
+ record_name=record_name,
408
+ domain_name=target_domain,
409
+ ttl=cdk.Duration.seconds(ttl)
410
+ )
411
+ self.records[record_name] = record
412
+
413
+ def _add_outputs(self) -> None:
414
+ """Add CloudFormation outputs for the Route53 resources"""
415
+ # Hosted Zone ID
416
+ if self.hosted_zone:
417
+ cdk.CfnOutput(
418
+ self,
419
+ "HostedZoneId",
420
+ value=self.hosted_zone.hosted_zone_id,
421
+ export_name=f"{self.deployment.build_resource_name('hosted-zone')}-id"
422
+ )
423
+
424
+ # Hosted Zone Name Servers
425
+ if hasattr(self.hosted_zone, "name_servers") and self.hosted_zone.name_servers:
426
+ cdk.CfnOutput(
427
+ self,
428
+ "NameServers",
429
+ value=",".join(self.hosted_zone.name_servers),
430
+ export_name=f"{self.deployment.build_resource_name('hosted-zone')}-name-servers"
431
+ )
432
+
433
+ # Certificate ARN
434
+ if self.certificate:
435
+ cdk.CfnOutput(
436
+ self,
437
+ "CertificateArn",
438
+ value=self.certificate.certificate_arn,
439
+ export_name=f"{self.deployment.build_resource_name('certificate')}-arn"
440
+ )
441
+
442
+ # Record names
443
+ for name, record in self.records.items():
444
+ cdk.CfnOutput(
445
+ self,
446
+ f"Record-{name}",
447
+ value=name,
448
+ export_name=f"{self.deployment.build_resource_name('record')}-{name}"
449
+ )
@@ -0,0 +1 @@
1
+ __version__ = "0.18.15"