dbt-platform-helper 15.6.0__tar.gz → 15.8.0__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 dbt-platform-helper might be problematic. Click here for more details.

Files changed (111) hide show
  1. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/PKG-INFO +4 -5
  2. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/COMMANDS.md +51 -0
  3. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/commands/application.py +2 -1
  4. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/commands/secrets.py +0 -20
  5. dbt_platform_helper-15.8.0/dbt_platform_helper/commands/service.py +53 -0
  6. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/constants.py +8 -0
  7. dbt_platform_helper-15.8.0/dbt_platform_helper/domain/service.py +153 -0
  8. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/entities/platform_config_schema.py +20 -5
  9. dbt_platform_helper-15.8.0/dbt_platform_helper/entities/service.py +114 -0
  10. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/config.py +28 -0
  11. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/config_validator.py +23 -0
  12. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/environment_variable.py +2 -2
  13. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/load_balancers.py +3 -2
  14. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/terraform_manifest.py +74 -4
  15. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/svc/overrides/cfn.patches.yml +5 -0
  16. dbt_platform_helper-15.8.0/dbt_platform_helper/utils/deep_merge.py +10 -0
  17. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/platform_helper.py +2 -0
  18. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/pyproject.toml +6 -7
  19. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/LICENSE +0 -0
  20. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/README.md +0 -0
  21. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/__init__.py +0 -0
  22. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/commands/__init__.py +0 -0
  23. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/commands/codebase.py +0 -0
  24. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/commands/conduit.py +0 -0
  25. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/commands/config.py +0 -0
  26. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/commands/copilot.py +0 -0
  27. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/commands/database.py +0 -0
  28. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/commands/environment.py +0 -0
  29. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/commands/generate.py +0 -0
  30. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/commands/notify.py +0 -0
  31. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/commands/pipeline.py +0 -0
  32. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/commands/version.py +0 -0
  33. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/default-extensions.yml +0 -0
  34. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/domain/__init__.py +0 -0
  35. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/domain/codebase.py +0 -0
  36. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/domain/conduit.py +0 -0
  37. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/domain/config.py +0 -0
  38. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/domain/copilot.py +0 -0
  39. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/domain/copilot_environment.py +0 -0
  40. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/domain/database_copy.py +0 -0
  41. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/domain/maintenance_page.py +0 -0
  42. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/domain/notify.py +0 -0
  43. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/domain/pipelines.py +0 -0
  44. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/domain/plans.py +0 -0
  45. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/domain/terraform_environment.py +0 -0
  46. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/domain/versioning.py +0 -0
  47. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/entities/semantic_version.py +0 -0
  48. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/jinja2_tags.py +0 -0
  49. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/platform_exception.py +0 -0
  50. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/__init__.py +0 -0
  51. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/aws/__init__.py +0 -0
  52. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/aws/exceptions.py +0 -0
  53. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/aws/interfaces.py +0 -0
  54. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/aws/opensearch.py +0 -0
  55. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/aws/redis.py +0 -0
  56. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/aws/sso_auth.py +0 -0
  57. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/cache.py +0 -0
  58. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/cloudformation.py +0 -0
  59. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/copilot.py +0 -0
  60. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/ecr.py +0 -0
  61. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/ecs.py +0 -0
  62. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/files.py +0 -0
  63. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/io.py +0 -0
  64. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/kms.py +0 -0
  65. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/parameter_store.py +0 -0
  66. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/schema_migrations/__init__.py +0 -0
  67. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/schema_migrations/schema_v0_to_v1_migration.py +0 -0
  68. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/schema_migrator.py +0 -0
  69. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/secrets.py +0 -0
  70. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/slack_channel_notifier.py +0 -0
  71. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/validation.py +0 -0
  72. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/version.py +0 -0
  73. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/version_status.py +0 -0
  74. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/vpc.py +0 -0
  75. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/providers/yaml_file.py +0 -0
  76. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/.copilot/config.yml +0 -0
  77. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/.copilot/image_build_run.sh +0 -0
  78. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/.copilot/phases/build.sh +0 -0
  79. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/.copilot/phases/install.sh +0 -0
  80. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/.copilot/phases/post_build.sh +0 -0
  81. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/.copilot/phases/pre_build.sh +0 -0
  82. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/COMMANDS.md.jinja +0 -0
  83. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/addon-instructions.txt +0 -0
  84. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/addons/README.md +0 -0
  85. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/addons/svc/appconfig-ipfilter.yml +0 -0
  86. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/addons/svc/prometheus-policy.yml +0 -0
  87. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/addons/svc/s3-cross-account-policy.yml +0 -0
  88. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/addons/svc/s3-policy.yml +0 -0
  89. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/addons/svc/subscription-filter.yml +0 -0
  90. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/ci-codebuild-role-policy.json +0 -0
  91. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/create-codebuild-role.json +0 -0
  92. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/custom-codebuild-role-policy.json +0 -0
  93. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/env/manifest.yml +0 -0
  94. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/env/terraform-overrides/cfn.patches.yml +0 -0
  95. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/environment-pipelines/main.tf +0 -0
  96. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/svc/maintenance_pages/default.html +0 -0
  97. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/svc/maintenance_pages/dmas-migration.html +0 -0
  98. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/templates/svc/maintenance_pages/migration.html +0 -0
  99. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/utilities/decorators.py +0 -0
  100. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/utils/__init__.py +0 -0
  101. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/utils/application.py +0 -0
  102. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/utils/arn_parser.py +0 -0
  103. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/utils/aws.py +0 -0
  104. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/utils/click.py +0 -0
  105. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/utils/git.py +0 -0
  106. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/utils/messages.py +0 -0
  107. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/utils/template.py +0 -0
  108. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/dbt_platform_helper/utils/validation.py +0 -0
  109. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/terraform/elasticache-redis/plans.yml +0 -0
  110. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/terraform/opensearch/plans.yml +0 -0
  111. {dbt_platform_helper-15.6.0 → dbt_platform_helper-15.8.0}/terraform/postgres/plans.yml +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dbt-platform-helper
3
- Version: 15.6.0
3
+ Version: 15.8.0
4
4
  Summary: Set of tools to help transfer applications/services from GOV.UK PaaS to DBT PaaS augmenting AWS Copilot.
5
5
  License: MIT
6
6
  Author: Department for Business and Trade Platform Team
7
7
  Author-email: sre-team@digital.trade.gov.uk
8
- Requires-Python: >=3.9, !=2.7.*, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*, !=3.7.*, !=3.8.*
8
+ Requires-Python: >3.9.1,<4.0
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Programming Language :: Python :: 3
11
11
  Classifier: Programming Language :: Python :: 3.10
@@ -13,7 +13,7 @@ Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
14
  Classifier: Programming Language :: Python :: 3.13
15
15
  Requires-Dist: Jinja2 (==3.1.6)
16
- Requires-Dist: PyYAML (==6.0.1)
16
+ Requires-Dist: PyYAML (==6.0.2)
17
17
  Requires-Dist: aiohttp (>=3.11.16,<4.0.0)
18
18
  Requires-Dist: boto3 (>=1.35.2,<2.0.0)
19
19
  Requires-Dist: boto3-stubs (>=1.26.148,<2.0.0)
@@ -23,7 +23,6 @@ Requires-Dist: cfn-flip (==1.3.0)
23
23
  Requires-Dist: cfn-lint (>=1.4.2,<2.0.0)
24
24
  Requires-Dist: checkov (>=3.2.405,<4.0.0)
25
25
  Requires-Dist: click (>=8.1.3,<9.0.0)
26
- Requires-Dist: cloudfoundry-client (==1.35.2)
27
26
  Requires-Dist: cryptography (>=44.0.1,<45)
28
27
  Requires-Dist: jinja2-simple-tags (>=0.5.0,<0.6.0)
29
28
  Requires-Dist: jsonschema (>=4.17.0,<4.18.0)
@@ -34,7 +33,7 @@ Requires-Dist: requests (>=2.31.0,<3.0.0)
34
33
  Requires-Dist: schema (==0.7.5)
35
34
  Requires-Dist: semver (>=3.0.2,<4.0.0)
36
35
  Requires-Dist: slack-sdk (>=3.27.1,<4.0.0)
37
- Requires-Dist: tomlkit (>=0.12.2,<0.13.0)
36
+ Requires-Dist: tomlkit (>=0.12.2,<0.14.0)
38
37
  Requires-Dist: yamllint (>=1.35.1,<2.0.0)
39
38
  Description-Content-Type: text/markdown
40
39
 
@@ -27,6 +27,8 @@
27
27
  - [platform-helper secrets](#platform-helper-secrets)
28
28
  - [platform-helper secrets copy](#platform-helper-secrets-copy)
29
29
  - [platform-helper secrets list](#platform-helper-secrets-list)
30
+ - [platform-helper service](#platform-helper-service)
31
+ - [platform-helper service generate](#platform-helper-service-generate)
30
32
  - [platform-helper notify](#platform-helper-notify)
31
33
  - [platform-helper notify environment-progress](#platform-helper-notify-environment-progress)
32
34
  - [platform-helper notify post-message](#platform-helper-notify-post-message)
@@ -66,6 +68,7 @@ platform-helper <command> [--version]
66
68
  - [`notify` ↪](#platform-helper-notify)
67
69
  - [`pipeline` ↪](#platform-helper-pipeline)
68
70
  - [`secrets` ↪](#platform-helper-secrets)
71
+ - [`service` ↪](#platform-helper-service)
69
72
  - [`version` ↪](#platform-helper-version)
70
73
 
71
74
  # platform-helper application
@@ -660,6 +663,54 @@ platform-helper secrets list <application> <environment>
660
663
  - `--help <boolean>` _Defaults to False._
661
664
  - Show this message and exit.
662
665
 
666
+ # platform-helper service
667
+
668
+ [↩ Parent](#platform-helper)
669
+
670
+ Commands affecting services.
671
+
672
+ ## Usage
673
+
674
+ ```
675
+ platform-helper service generate
676
+ ```
677
+
678
+ ## Options
679
+
680
+ - `--help <boolean>` _Defaults to False._
681
+ - Show this message and exit.
682
+
683
+ ## Commands
684
+
685
+ - [`generate` ↪](#platform-helper-service-generate)
686
+
687
+ # platform-helper service generate
688
+
689
+ [↩ Parent](#platform-helper-service)
690
+
691
+ Generate terraform manifest for the specified service(s).
692
+
693
+ ## Usage
694
+
695
+ ```
696
+ platform-helper service generate [--name <name>] [--environment <environment>]
697
+ [--image-tag <image_tag>]
698
+ ```
699
+
700
+ ## Options
701
+
702
+ - `--name
703
+ -n <text>`
704
+ - The name of the service to generate a manifest for. Multiple values accepted.
705
+ - `--environment
706
+ -e <text>`
707
+ - The name of the environment to generate service manifests for. Multiple values accepted.
708
+ - `--image-tag
709
+ -i <text>`
710
+ - Docker image tag to deploy for the service. Overrides the $IMAGE_TAG environment variable.
711
+ - `--help <boolean>` _Defaults to False._
712
+ - Show this message and exit.
713
+
663
714
  # platform-helper notify
664
715
 
665
716
  [↩ Parent](#platform-helper)
@@ -281,12 +281,13 @@ def task_stats(env, app, disk, storage, network):
281
281
  memory,
282
282
  dsk,
283
283
  ) in cpu_response["results"]:
284
+ cpu_value = f"{float(cpu['value']):.1f}" + "%"
284
285
  values = [
285
286
  f"{YELLOW}{taskdef['value'].split('-')[-1]}",
286
287
  f"{YELLOW}{task['value']}",
287
288
  f"{YELLOW}{task_def_revision['value']}",
288
289
  f"{YELLOW}{status['value']}",
289
- f"{YELLOW}{'%.1f' % float(cpu['value']) + '%'}",
290
+ f"{YELLOW}{cpu_value}",
290
291
  f"{YELLOW}{memory['value'] + 'M'}",
291
292
  ]
292
293
 
@@ -4,7 +4,6 @@ from pathlib import Path
4
4
 
5
5
  import click
6
6
  from botocore.exceptions import ClientError
7
- from cloudfoundry_client.client import CloudFoundryClient
8
7
 
9
8
  from dbt_platform_helper.domain.versioning import PlatformHelperVersioning
10
9
  from dbt_platform_helper.utils.application import get_application_name
@@ -19,25 +18,6 @@ def secret_should_be_skipped(secret_name):
19
18
  return "AWS_" in secret_name
20
19
 
21
20
 
22
- def get_paas_env_vars(client: CloudFoundryClient, paas: str) -> dict:
23
- org, space, app = paas.split("/")
24
-
25
- env_vars = None
26
-
27
- for paas_org in client.v2.organizations:
28
- if paas_org["entity"]["name"] == org:
29
- for paas_space in paas_org.spaces():
30
- if paas_space["entity"]["name"] == space:
31
- for paas_app in paas_space.apps():
32
- if paas_app["entity"]["name"] == app:
33
- env_vars = paas_app["entity"]["environment_json"]
34
-
35
- if not env_vars:
36
- raise Exception(f"Application {paas} not found")
37
-
38
- return dict(env_vars)
39
-
40
-
41
21
  @click.group(chain=True, cls=ClickDocOptGroup)
42
22
  def secrets():
43
23
  PlatformHelperVersioning().check_if_needs_update()
@@ -0,0 +1,53 @@
1
+ import click
2
+
3
+ from dbt_platform_helper.domain.service import ServiceManager
4
+ from dbt_platform_helper.domain.versioning import PlatformHelperVersioning
5
+ from dbt_platform_helper.platform_exception import PlatformException
6
+ from dbt_platform_helper.providers.io import ClickIOProvider
7
+ from dbt_platform_helper.utils.click import ClickDocOptGroup
8
+
9
+
10
+ @click.group(cls=ClickDocOptGroup)
11
+ def service():
12
+ """Commands affecting services."""
13
+ PlatformHelperVersioning().check_if_needs_update()
14
+
15
+
16
+ @service.command(help="Generate terraform manifest for the specified service(s).")
17
+ @click.option(
18
+ "--name",
19
+ "-n",
20
+ required=False,
21
+ help="The name of the service to generate a manifest for. Multiple values accepted.",
22
+ multiple=True,
23
+ )
24
+ @click.option(
25
+ "--environment",
26
+ "-e",
27
+ required=False,
28
+ multiple=True,
29
+ help="The name of the environment to generate service manifests for. Multiple values accepted.",
30
+ )
31
+ @click.option(
32
+ "--image-tag",
33
+ "-i",
34
+ required=False,
35
+ help="Docker image tag to deploy for the service. Overrides the $IMAGE_TAG environment variable.",
36
+ )
37
+ def generate(name, environment, image_tag):
38
+ """Validates the service-config.yml format, applies the environment-specific
39
+ overrides, and generates a Terraform manifest at
40
+ /terraform/services/<environment>/<service>/main.tf.json."""
41
+
42
+ services = list(name)
43
+ environments = list(environment)
44
+ click_io = ClickIOProvider()
45
+
46
+ try:
47
+ service_manager = ServiceManager()
48
+ service_manager.generate(
49
+ environments=environments, services=services, image_tag_flag=image_tag
50
+ )
51
+
52
+ except PlatformException as err:
53
+ click_io.abort_with_error(str(err))
@@ -1,5 +1,7 @@
1
1
  # TODO: DBTP-1888: Move to Config provider
2
2
  PLATFORM_CONFIG_FILE = "platform-config.yml"
3
+ SERVICE_DIRECTORY = "services"
4
+ SERVICE_CONFIG_FILE = "service-config.yml"
3
5
  PLATFORM_HELPER_VERSION_OVERRIDE_KEY = "PLATFORM_HELPER_VERSION_OVERRIDE"
4
6
  TERRAFORM_EXTENSIONS_MODULE_SOURCE_OVERRIDE_ENV_VAR = "TERRAFORM_EXTENSIONS_MODULE_SOURCE_OVERRIDE"
5
7
  TERRAFORM_ENVIRONMENT_PIPELINES_MODULE_SOURCE_OVERRIDE_ENV_VAR = (
@@ -8,6 +10,11 @@ TERRAFORM_ENVIRONMENT_PIPELINES_MODULE_SOURCE_OVERRIDE_ENV_VAR = (
8
10
  TERRAFORM_CODEBASE_PIPELINES_MODULE_SOURCE_OVERRIDE_ENV_VAR = (
9
11
  "TERRAFORM_CODEBASE_PIPELINES_MODULE_SOURCE_OVERRIDE"
10
12
  )
13
+ TERRAFORM_ECS_SERVICE_MODULE_SOURCE_OVERRIDE_ENV_VAR = (
14
+ "TERRAFORM_ECS_SERVICE_MODULE_SOURCE_OVERRIDE"
15
+ )
16
+ TERRAFORM_MODULE_SOURCE_TYPE_ENV_VAR = "TERRAFORM_MODULE_SOURCE_TYPE" # "LOCAL", "SSH", "OVERRIDE"
17
+ IMAGE_TAG_ENV_VAR = "IMAGE_TAG"
11
18
  PLATFORM_HELPER_PACKAGE_NAME = "dbt-platform-helper"
12
19
  SUPPORTED_TERRAFORM_VERSION = "~> 1.8"
13
20
  SUPPORTED_AWS_PROVIDER_VERSION = "~> 5"
@@ -15,6 +22,7 @@ FIRST_UPGRADABLE_PLATFORM_HELPER_MAJOR_VERSION = 13
15
22
 
16
23
  MERGED_TPM_PLATFORM_HELPER_VERSION = 14
17
24
  PLATFORM_CONFIG_SCHEMA_VERSION = 1
25
+ SERVICE_CONFIG_SCHEMA_VERSION = 1
18
26
 
19
27
  # Keys
20
28
  CODEBASE_PIPELINES_KEY = "codebase_pipelines"
@@ -0,0 +1,153 @@
1
+ from datetime import datetime
2
+ from importlib.metadata import version
3
+ from pathlib import Path
4
+
5
+ from dbt_platform_helper.constants import IMAGE_TAG_ENV_VAR
6
+ from dbt_platform_helper.constants import PLATFORM_HELPER_VERSION_OVERRIDE_KEY
7
+ from dbt_platform_helper.constants import SERVICE_CONFIG_FILE
8
+ from dbt_platform_helper.constants import SERVICE_DIRECTORY
9
+ from dbt_platform_helper.constants import (
10
+ TERRAFORM_ECS_SERVICE_MODULE_SOURCE_OVERRIDE_ENV_VAR,
11
+ )
12
+ from dbt_platform_helper.constants import TERRAFORM_MODULE_SOURCE_TYPE_ENV_VAR
13
+ from dbt_platform_helper.domain.terraform_environment import (
14
+ EnvironmentNotFoundException,
15
+ )
16
+ from dbt_platform_helper.entities.service import ServiceConfig
17
+ from dbt_platform_helper.platform_exception import PlatformException
18
+ from dbt_platform_helper.providers.config import ConfigLoader
19
+ from dbt_platform_helper.providers.config import ConfigProvider
20
+ from dbt_platform_helper.providers.config_validator import ConfigValidator
21
+ from dbt_platform_helper.providers.environment_variable import (
22
+ EnvironmentVariableProvider,
23
+ )
24
+ from dbt_platform_helper.providers.io import ClickIOProvider
25
+ from dbt_platform_helper.providers.terraform_manifest import TerraformManifestProvider
26
+ from dbt_platform_helper.providers.yaml_file import YamlFileProvider
27
+ from dbt_platform_helper.utils.application import load_application
28
+ from dbt_platform_helper.utils.deep_merge import deep_merge
29
+
30
+ # TODO add schema version too service config
31
+
32
+
33
+ class ServiceManager:
34
+ def __init__(
35
+ self,
36
+ config_provider=ConfigProvider(ConfigValidator()),
37
+ loader: ConfigLoader = ConfigLoader(),
38
+ io: ClickIOProvider = ClickIOProvider(),
39
+ file_provider=YamlFileProvider,
40
+ environment_variable_provider: EnvironmentVariableProvider = None,
41
+ manifest_provider: TerraformManifestProvider = None,
42
+ platform_helper_version_override: str = None,
43
+ load_application=load_application,
44
+ ):
45
+
46
+ self.file_provider = file_provider
47
+ self.config_provider = config_provider
48
+ self.loader = loader
49
+ self.io = io
50
+ self.environment_variable_provider = (
51
+ environment_variable_provider or EnvironmentVariableProvider()
52
+ )
53
+ self.manifest_provider = manifest_provider or TerraformManifestProvider()
54
+ self.platform_helper_version_override = (
55
+ platform_helper_version_override
56
+ or self.environment_variable_provider.get(PLATFORM_HELPER_VERSION_OVERRIDE_KEY)
57
+ )
58
+ self.load_application = load_application
59
+
60
+ def generate(self, environments: list[str], services: list[str], image_tag_flag: str = None):
61
+
62
+ config = self.config_provider.get_enriched_config()
63
+ application_name = config.get("application", "")
64
+ application = self.load_application(app=application_name)
65
+
66
+ if not environments:
67
+ for environment in application.environments:
68
+ environments.append(environment)
69
+ else:
70
+ for environment in environments:
71
+ if environment not in application.environments:
72
+ raise EnvironmentNotFoundException(
73
+ f"cannot generate terraform for environment {environment}. It does not exist in your configuration"
74
+ )
75
+
76
+ if not services:
77
+ try:
78
+ for dir in Path("services").iterdir():
79
+ if dir.is_dir():
80
+ config_path = dir / SERVICE_CONFIG_FILE
81
+ if config_path.exists():
82
+ services.append(dir.name)
83
+ else:
84
+ self.io.warn(
85
+ f"Failed loading service name from {dir.name}.\n"
86
+ "Please ensure that your '/services' directory follows the correct structure (i.e. /services/<service_name>/service-config.yml) and the 'service-config.yml' contents are correct."
87
+ )
88
+ except Exception as e:
89
+ self.io.abort_with_error(f"Failed extracting services with exception, {e}")
90
+ service_models = []
91
+ for service in services:
92
+ service_models.append(
93
+ self.loader.load_into_model(
94
+ f"{SERVICE_DIRECTORY}/{service}/{SERVICE_CONFIG_FILE}",
95
+ ServiceConfig,
96
+ )
97
+ )
98
+
99
+ platform_helper_version_for_template: str = (
100
+ self.platform_helper_version_override
101
+ or config.get("default_versions", {}).get("platform-helper")
102
+ )
103
+
104
+ source_type = self.environment_variable_provider.get(TERRAFORM_MODULE_SOURCE_TYPE_ENV_VAR)
105
+
106
+ if source_type == "LOCAL":
107
+ module_source_override = ServiceConfig.local_terraform_source
108
+ elif source_type == "OVERRIDE":
109
+ module_source_override = self.environment_variable_provider.get(
110
+ TERRAFORM_ECS_SERVICE_MODULE_SOURCE_OVERRIDE_ENV_VAR
111
+ )
112
+ else:
113
+ module_source_override = None
114
+
115
+ image_tag = image_tag_flag or self.environment_variable_provider.get(IMAGE_TAG_ENV_VAR)
116
+ if not image_tag:
117
+ raise PlatformException(
118
+ f"An image tag must be provided to deploy a service. This can be set by the $IMAGE_TAG environment variable, or the --image-tag flag."
119
+ )
120
+
121
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
122
+
123
+ for service in service_models:
124
+
125
+ for environment in environments:
126
+
127
+ model_dump = service.model_dump(exclude_none=True)
128
+ env_overrides = model_dump.get("environments", {}).get(environment)
129
+ if env_overrides:
130
+ merged_config = deep_merge(model_dump, env_overrides)
131
+ else:
132
+ merged_config = model_dump.copy()
133
+ merged_config.pop("environments", None)
134
+
135
+ output_path = Path(
136
+ f"terraform/{SERVICE_DIRECTORY}/{environment}/{service.name}/{SERVICE_CONFIG_FILE}"
137
+ )
138
+ output_path.parent.mkdir(parents=True, exist_ok=True)
139
+
140
+ self.file_provider.write(
141
+ str(output_path),
142
+ merged_config,
143
+ f"# WARNING: This is an autogenerated file, not for manual editing.\n# Generated by platform-helper {version('dbt-platform-helper')} / {timestamp}.\n",
144
+ )
145
+
146
+ self.manifest_provider.generate_service_config(
147
+ service,
148
+ environment,
149
+ image_tag,
150
+ platform_helper_version_for_template,
151
+ config,
152
+ module_source_override,
153
+ )
@@ -152,7 +152,7 @@ class PlatformConfigSchema:
152
152
  {
153
153
  "name": str,
154
154
  Optional("requires_approval"): bool,
155
- }
155
+ },
156
156
  ],
157
157
  },
158
158
  {
@@ -167,9 +167,16 @@ class PlatformConfigSchema:
167
167
  },
168
168
  ),
169
169
  ],
170
+ Optional("cache_invalidation"): {
171
+ "domains": PlatformConfigSchema.__cache_invalidation_domains_schema(),
172
+ },
170
173
  },
171
174
  }
172
175
 
176
+ @staticmethod
177
+ def __cache_invalidation_domains_schema() -> dict:
178
+ return {str: {"paths": [str], "environment": str}}
179
+
173
180
  @staticmethod
174
181
  def __default_versions_schema() -> dict:
175
182
  return {
@@ -403,11 +410,19 @@ class PlatformConfigSchema:
403
410
  Optional("environments"): {
404
411
  Optional(PlatformConfigSchema.__valid_environment_name()): {
405
412
  "team_name": str,
406
- "contact_name": str,
407
- "contact_email": str,
408
- "documentation_url": str,
413
+ Optional("contact_name"): str,
414
+ Optional("contact_email"): str,
415
+ Optional("contacts"): [
416
+ {
417
+ "name": str,
418
+ "type": str,
419
+ "contact": str,
420
+ }
421
+ ],
422
+ Optional("documentation_url"): str,
409
423
  "services_to_monitor": dict,
410
- }
424
+ Optional("description"): str,
425
+ },
411
426
  },
412
427
  }
413
428
 
@@ -0,0 +1,114 @@
1
+ from typing import ClassVar
2
+ from typing import Dict
3
+ from typing import Optional
4
+ from typing import Union
5
+
6
+ from pydantic import BaseModel
7
+ from pydantic import Field
8
+
9
+
10
+ class HealthCheck(BaseModel):
11
+ path: Optional[str] = Field(description="""Path the healthcheck calls""", default=None)
12
+ port: Optional[int] = Field(description="""Port the healthcheck calls""", default=None)
13
+ success_codes: Optional[str] = Field(
14
+ description="""The success codes the healthcheck looks for""", default=None
15
+ )
16
+ healthy_threshold: Optional[int] = Field(description="""The number of """, default=None)
17
+ unhealthy_threshold: Optional[int] = Field(description="""The number of """, default=None)
18
+ interval: Optional[str] = Field(
19
+ description="""The interval inbetween health check calls""", default=None
20
+ )
21
+ timeout: Optional[str] = Field(
22
+ description="""The timeout for a healthcheck call""", default=None
23
+ )
24
+ grace_period: Optional[str] = Field(description="""The time""", default=None)
25
+
26
+
27
+ class Http(BaseModel):
28
+ path: Optional[str] = Field(
29
+ description="""Requests to this path will be forwarded to your service.""", default=None
30
+ )
31
+ alb: Optional[str] = Field(default=None)
32
+ target_container: Optional[str] = Field(
33
+ description="""Target container for the requests""", default=None
34
+ )
35
+ healthcheck: Optional[HealthCheck] = Field(default=None)
36
+
37
+
38
+ class Sidecar(BaseModel):
39
+ port: int = Field()
40
+ image: str = Field()
41
+ essential: Optional[bool] = Field(default=None)
42
+ variables: Optional[Dict[str, Union[str, int, bool]]] = Field(default=None)
43
+ secrets: Optional[Dict[str, str]] = Field(default=None)
44
+
45
+
46
+ class SidecarOverride(BaseModel):
47
+ port: Optional[int] = Field(default=None)
48
+ image: Optional[str] = Field(default=None)
49
+ essential: Optional[bool] = Field(default=None)
50
+ variables: Optional[Dict[str, Union[str, int, bool]]] = Field(default=None)
51
+ secrets: Optional[Dict[str, str]] = Field(default=None)
52
+
53
+
54
+ class Image(BaseModel):
55
+ build: Optional[str] = Field(default=None)
56
+ location: Optional[str] = Field(default=None)
57
+ port: int = Field()
58
+
59
+
60
+ class VPC(BaseModel):
61
+ placement: str = Field()
62
+
63
+
64
+ class Network(BaseModel):
65
+ connect: bool = Field(
66
+ description="Enable Service Connect for intra-environment traffic between services."
67
+ )
68
+ vpc: Optional[VPC] = Field(default=None)
69
+
70
+
71
+ class Storage(BaseModel):
72
+ readonly_fs: bool
73
+
74
+
75
+ class ServiceConfigEnvironmentOverride(BaseModel):
76
+ http: Optional[Http] = Field(default=None)
77
+ sidecars: Optional[Dict[str, SidecarOverride]] = Field(default=None)
78
+ image: Optional[Image] = Field(default=None)
79
+
80
+ cpu: Optional[int] = Field(default=None)
81
+ memory: Optional[int] = Field(default=None)
82
+ count: Optional[int] = Field(default=None)
83
+ exec: Optional[bool] = Field(default=None)
84
+ network: Optional[Network] = Field(default=None)
85
+
86
+ storage: Optional[Storage] = Field(default=None)
87
+
88
+ variables: Optional[Dict[str, Union[str, int, bool]]] = Field(default=None)
89
+ secrets: Optional[Dict[str, str]] = Field(default=None)
90
+
91
+
92
+ class ServiceConfig(BaseModel):
93
+ name: str = Field(description="""Name of the Service.""")
94
+ type: str = Field(description="""The type of service""")
95
+
96
+ http: Optional[Http] = Field(default=None) # TODO http required if service type load balancer
97
+ sidecars: Optional[Dict[str, Sidecar]] = Field(default=None)
98
+ image: Image = Field()
99
+
100
+ cpu: int = Field()
101
+ memory: int = Field()
102
+ count: int = Field()
103
+ exec: Optional[bool] = Field(default=None)
104
+ network: Optional[Network] = Field(default=None)
105
+
106
+ storage: Optional[Storage] = Field(default=None)
107
+
108
+ variables: Optional[Dict[str, Union[str, int, bool]]] = Field(default=None)
109
+ secrets: Optional[Dict[str, str]] = Field(default=None)
110
+ # Environment overrides can override almost the full config
111
+ environments: Optional[Dict[str, ServiceConfigEnvironmentOverride]] = Field(default=None)
112
+
113
+ # Class based variable used when handling the obejct
114
+ local_terraform_source: ClassVar[str] = "../../../../../platform-tools/terraform/ecs-service"
@@ -25,6 +25,34 @@ PLEASE_UPGRADE_TO_V13_MESSAGE = """Please ensure that you have already upgraded
25
25
  Then upgrade platform-helper to version {installed_platform_helper_version} and run 'platform-helper config migrate' to upgrade the configuration to the current schema version."""
26
26
 
27
27
 
28
+ class ConfigLoader:
29
+ def __init__(self, file_provider=YamlFileProvider, io: ClickIOProvider = ClickIOProvider()):
30
+ self.io = io
31
+ self.file_provider = file_provider
32
+
33
+ def load_into_model(self, path, model):
34
+ try:
35
+ file_content = self.file_provider.load(path)
36
+ return model(**file_content)
37
+ except FileNotFoundException as e:
38
+ self.io.abort_with_error(
39
+ f"{e} Please check it exists and you are in the root directory of your -deploy repository."
40
+ )
41
+ except FileProviderException as e:
42
+ self.io.abort_with_error(f"Error loading configuration from {path}: {e}")
43
+
44
+ def load(self, path):
45
+ try:
46
+ file_content = self.file_provider.load(path)
47
+ return file_content
48
+ except FileNotFoundException as e:
49
+ self.io.abort_with_error(
50
+ f"{e} Please check it exists and you are in the root directory of your -deploy repository."
51
+ )
52
+ except FileProviderException as e:
53
+ self.io.abort_with_error(f"Error loading configuration from {path}: {e}")
54
+
55
+
28
56
  class ConfigProvider:
29
57
  def __init__(
30
58
  self,
@@ -29,6 +29,7 @@ class ConfigValidator:
29
29
  self.validate_environment_pipelines_triggers,
30
30
  self.validate_database_copy_section,
31
31
  self.validate_database_migration_input_sources,
32
+ self.validate_cache_invalidation_config,
32
33
  ]
33
34
  self.io = io
34
35
  self.session = session
@@ -232,3 +233,25 @@ class ConfigValidator:
232
233
  )
233
234
  if errors:
234
235
  raise ConfigValidatorError("\n".join(errors))
236
+
237
+ def validate_cache_invalidation_config(self, config: dict):
238
+ codebase_pipelines = config.get("codebase_pipelines")
239
+ if not codebase_pipelines:
240
+ return
241
+
242
+ errors = []
243
+
244
+ all_environments = [env for env in config.get("environments", {}).keys() if not env == "*"]
245
+
246
+ for codebase in codebase_pipelines.values():
247
+ cache_invalidation_config = codebase.get("cache_invalidation")
248
+ if cache_invalidation_config:
249
+ for domain, config in cache_invalidation_config.get("domains").items():
250
+ environment = config.get("environment")
251
+ if environment not in all_environments:
252
+ errors.append(
253
+ f"Error in cache invalidation configuration for the domain '{domain}'. Environment '{environment}' is not defined for this application"
254
+ )
255
+
256
+ if errors:
257
+ raise ConfigValidatorError("\n".join(errors))
@@ -7,12 +7,12 @@ from dbt_platform_helper.platform_exception import PlatformException
7
7
  class EnvironmentVariableProvider:
8
8
 
9
9
  @staticmethod
10
- def get(env_var: str) -> Optional[str]:
10
+ def get(env_var: str, default=None) -> Optional[str]:
11
11
  """Returns the stripped value or None if not set or empty."""
12
12
  value = os.environ.get(env_var)
13
13
  if value and value.strip():
14
14
  return value.strip()
15
- return None
15
+ return default
16
16
 
17
17
  @staticmethod
18
18
  def get_required(env_var: str) -> str:
@@ -149,8 +149,9 @@ class LoadBalancerProvider:
149
149
 
150
150
  for rule in rules:
151
151
  for action in rule["Actions"]:
152
- if action["Type"] == "forward" and action["TargetGroupArn"] == target_group_arn:
153
- conditions = rule["Conditions"]
152
+ if "TargetGroupArn" in action:
153
+ if action["Type"] == "forward" and action["TargetGroupArn"] == target_group_arn:
154
+ conditions = rule["Conditions"]
154
155
 
155
156
  if not conditions:
156
157
  raise ListenerRuleConditionsNotFoundException(listener_arn)