dbt-platform-helper 12.5.0__py3-none-any.whl → 12.6.0__py3-none-any.whl

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.
Files changed (40) hide show
  1. dbt_platform_helper/COMMANDS.md +39 -38
  2. dbt_platform_helper/commands/codebase.py +5 -8
  3. dbt_platform_helper/commands/conduit.py +2 -2
  4. dbt_platform_helper/commands/config.py +1 -1
  5. dbt_platform_helper/commands/copilot.py +4 -2
  6. dbt_platform_helper/commands/environment.py +40 -24
  7. dbt_platform_helper/commands/pipeline.py +6 -171
  8. dbt_platform_helper/constants.py +1 -0
  9. dbt_platform_helper/domain/codebase.py +20 -23
  10. dbt_platform_helper/domain/conduit.py +10 -12
  11. dbt_platform_helper/domain/config_validator.py +40 -7
  12. dbt_platform_helper/domain/copilot_environment.py +135 -131
  13. dbt_platform_helper/domain/database_copy.py +45 -42
  14. dbt_platform_helper/domain/maintenance_page.py +220 -183
  15. dbt_platform_helper/domain/pipelines.py +212 -0
  16. dbt_platform_helper/domain/terraform_environment.py +68 -35
  17. dbt_platform_helper/domain/test_platform_terraform_manifest_generator.py +100 -0
  18. dbt_platform_helper/providers/cache.py +1 -2
  19. dbt_platform_helper/providers/cloudformation.py +12 -1
  20. dbt_platform_helper/providers/config.py +21 -13
  21. dbt_platform_helper/providers/copilot.py +2 -0
  22. dbt_platform_helper/providers/files.py +26 -0
  23. dbt_platform_helper/providers/io.py +31 -0
  24. dbt_platform_helper/providers/load_balancers.py +29 -3
  25. dbt_platform_helper/providers/platform_config_schema.py +10 -7
  26. dbt_platform_helper/providers/vpc.py +106 -0
  27. dbt_platform_helper/providers/yaml_file.py +3 -14
  28. dbt_platform_helper/templates/COMMANDS.md.jinja +5 -3
  29. dbt_platform_helper/templates/pipelines/codebase/overrides/package-lock.json +819 -623
  30. dbt_platform_helper/utils/application.py +32 -34
  31. dbt_platform_helper/utils/aws.py +0 -50
  32. dbt_platform_helper/utils/files.py +8 -23
  33. dbt_platform_helper/utils/messages.py +2 -3
  34. dbt_platform_helper/utils/platform_config.py +0 -7
  35. dbt_platform_helper/utils/versioning.py +12 -0
  36. {dbt_platform_helper-12.5.0.dist-info → dbt_platform_helper-12.6.0.dist-info}/METADATA +2 -2
  37. {dbt_platform_helper-12.5.0.dist-info → dbt_platform_helper-12.6.0.dist-info}/RECORD +40 -35
  38. {dbt_platform_helper-12.5.0.dist-info → dbt_platform_helper-12.6.0.dist-info}/WHEEL +1 -1
  39. {dbt_platform_helper-12.5.0.dist-info → dbt_platform_helper-12.6.0.dist-info}/LICENSE +0 -0
  40. {dbt_platform_helper-12.5.0.dist-info → dbt_platform_helper-12.6.0.dist-info}/entry_points.txt +0 -0
@@ -3,22 +3,22 @@ from collections.abc import Callable
3
3
  from pathlib import Path
4
4
 
5
5
  import boto3
6
- import click
7
6
  from boto3 import Session
8
7
 
9
8
  from dbt_platform_helper.constants import PLATFORM_CONFIG_FILE
10
9
  from dbt_platform_helper.domain.config_validator import ConfigValidator
11
- from dbt_platform_helper.domain.maintenance_page import MaintenancePageProvider
12
- from dbt_platform_helper.providers.aws import AWSException
10
+ from dbt_platform_helper.domain.maintenance_page import MaintenancePage
13
11
  from dbt_platform_helper.providers.config import ConfigProvider
12
+ from dbt_platform_helper.providers.io import ClickIOProvider
13
+ from dbt_platform_helper.providers.io import ClickIOProviderException
14
+ from dbt_platform_helper.providers.vpc import Vpc
15
+ from dbt_platform_helper.providers.vpc import VpcProvider
16
+ from dbt_platform_helper.providers.vpc import VpcProviderException
14
17
  from dbt_platform_helper.utils.application import Application
15
18
  from dbt_platform_helper.utils.application import ApplicationNotFoundException
16
19
  from dbt_platform_helper.utils.application import load_application
17
- from dbt_platform_helper.utils.aws import Vpc
18
20
  from dbt_platform_helper.utils.aws import get_connection_string
19
- from dbt_platform_helper.utils.aws import get_vpc_info_by_name
20
21
  from dbt_platform_helper.utils.aws import wait_for_log_group_to_exist
21
- from dbt_platform_helper.utils.messages import abort_with_error
22
22
 
23
23
 
24
24
  class DatabaseCopy:
@@ -28,32 +28,28 @@ class DatabaseCopy:
28
28
  database: str,
29
29
  auto_approve: bool = False,
30
30
  load_application: Callable[[str], Application] = load_application,
31
- vpc_config: Callable[[Session, str, str, str], Vpc] = get_vpc_info_by_name,
31
+ # TODO We inject VpcProvider as a callable here so that it can be instantiated within the method. To be improved
32
+ vpc_provider: Callable[[Session], VpcProvider] = VpcProvider,
32
33
  db_connection_string: Callable[
33
34
  [Session, str, str, str, Callable], str
34
35
  ] = get_connection_string,
35
- maintenance_page_provider: Callable[
36
- [str, str, list[str], str, str], None
37
- ] = MaintenancePageProvider(),
38
- input: Callable[[str], str] = click.prompt,
39
- echo: Callable[[str], str] = click.secho,
40
- abort: Callable[[str], None] = abort_with_error,
36
+ maintenance_page: Callable[[str, str, list[str], str, str], None] = MaintenancePage,
37
+ io: ClickIOProvider = ClickIOProvider(),
41
38
  config_provider: ConfigProvider = ConfigProvider(ConfigValidator()),
42
39
  ):
43
40
  self.app = app
44
41
  self.database = database
45
42
  self.auto_approve = auto_approve
46
- self.vpc_config = vpc_config
43
+ self.vpc_provider = vpc_provider
47
44
  self.db_connection_string = db_connection_string
48
- self.maintenance_page_provider = maintenance_page_provider
49
- self.input = input
50
- self.echo = echo
51
- self.abort = abort
45
+ self.io = io
52
46
  self.config_provider = config_provider
53
47
 
54
48
  if not self.app:
55
49
  if not Path(PLATFORM_CONFIG_FILE).exists():
56
- self.abort("You must either be in a deploy repo, or provide the --app option.")
50
+ self.io.abort_with_error(
51
+ "You must either be in a deploy repo, or provide the --app option."
52
+ )
57
53
 
58
54
  config = self.config_provider.load_and_validate_platform_config()
59
55
  self.app = config["application"]
@@ -61,7 +57,9 @@ class DatabaseCopy:
61
57
  try:
62
58
  self.application = load_application(self.app)
63
59
  except ApplicationNotFoundException:
64
- abort(f"No such application '{app}'.")
60
+ self.io.abort_with_error(f"No such application '{app}'.")
61
+
62
+ self.maintenance_page = maintenance_page(self.application)
65
63
 
66
64
  def _execute_operation(self, is_dump: bool, env: str, vpc_name: str, filename: str):
67
65
  vpc_name = self.enrich_vpc_name(env, vpc_name)
@@ -69,16 +67,17 @@ class DatabaseCopy:
69
67
  environments = self.application.environments
70
68
  environment = environments.get(env)
71
69
  if not environment:
72
- self.abort(
70
+ self.io.abort_with_error(
73
71
  f"No such environment '{env}'. Available environments are: {', '.join(environments.keys())}"
74
72
  )
75
73
 
76
74
  env_session = environment.session
77
75
 
78
76
  try:
79
- vpc_config = self.vpc_config(env_session, self.app, env, vpc_name)
80
- except AWSException as ex:
81
- self.abort(str(ex))
77
+ vpc_provider = self.vpc_provider(env_session)
78
+ vpc_config = vpc_provider.get_vpc(self.app, env, vpc_name)
79
+ except VpcProviderException as ex:
80
+ self.io.abort_with_error(str(ex))
82
81
 
83
82
  database_identifier = f"{self.app}-{env}-{self.database}"
84
83
 
@@ -87,31 +86,32 @@ class DatabaseCopy:
87
86
  env_session, self.app, env, database_identifier
88
87
  )
89
88
  except Exception as exc:
90
- self.abort(f"{exc} (Database: {database_identifier})")
89
+ self.io.abort_with_error(f"{exc} (Database: {database_identifier})")
91
90
 
92
91
  try:
93
92
  task_arn = self.run_database_copy_task(
94
93
  env_session, env, vpc_config, is_dump, db_connection_string, filename
95
94
  )
96
95
  except Exception as exc:
97
- self.abort(f"{exc} (Account id: {self.account_id(env)})")
96
+ self.io.abort_with_error(f"{exc} (Account id: {self.account_id(env)})")
98
97
 
99
98
  if is_dump:
100
99
  message = f"Dumping {self.database} from the {env} environment into S3"
101
100
  else:
102
101
  message = f"Loading data into {self.database} in the {env} environment from S3"
103
102
 
104
- self.echo(message, fg="white", bold=True)
105
- self.echo(
106
- f"Task {task_arn} started. Waiting for it to complete (this may take some time)...",
107
- fg="white",
103
+ self.io.info(message)
104
+ self.io.info(
105
+ f"Task {task_arn} started. Waiting for it to complete (this may take some time)..."
108
106
  )
109
107
  self.tail_logs(is_dump, env)
110
108
 
111
109
  def enrich_vpc_name(self, env, vpc_name):
112
110
  if not vpc_name:
113
111
  if not Path(PLATFORM_CONFIG_FILE).exists():
114
- self.abort("You must either be in a deploy repo, or provide the vpc name option.")
112
+ self.io.abort_with_error(
113
+ "You must either be in a deploy repo, or provide the vpc name option."
114
+ )
115
115
  config = self.config_provider.load_and_validate_platform_config()
116
116
  env_config = self.config_provider.apply_environment_defaults(config)["environments"]
117
117
  vpc_name = env_config.get(env, {}).get("vpc")
@@ -145,7 +145,7 @@ class DatabaseCopy:
145
145
  ],
146
146
  networkConfiguration={
147
147
  "awsvpcConfiguration": {
148
- "subnets": vpc_config.subnets,
148
+ "subnets": vpc_config.private_subnets,
149
149
  "securityGroups": vpc_config.security_groups,
150
150
  "assignPublicIp": "DISABLED",
151
151
  }
@@ -181,26 +181,27 @@ class DatabaseCopy:
181
181
  ):
182
182
  to_vpc = self.enrich_vpc_name(to_env, to_vpc)
183
183
  if not no_maintenance_page:
184
- self.maintenance_page_provider.activate(self.app, to_env, services, template, to_vpc)
184
+ self.maintenance_page.activate(to_env, services, template, to_vpc)
185
185
  self.dump(from_env, from_vpc, f"data_dump_{to_env}")
186
186
  self.load(to_env, to_vpc, f"data_dump_{to_env}")
187
187
  if not no_maintenance_page:
188
- self.maintenance_page_provider.deactivate(self.app, to_env)
188
+ self.maintenance_page.deactivate(to_env)
189
189
 
190
190
  def is_confirmed_ready_to_load(self, env: str) -> bool:
191
191
  if self.auto_approve:
192
192
  return True
193
-
194
- user_input = self.input(
195
- f"\nWARNING: the load operation is destructive and will delete the {self.database} database in the {env} environment. Continue? (y/n)"
196
- )
197
- return user_input.lower().strip() in ["y", "yes"]
193
+ try:
194
+ return self.io.confirm(
195
+ f"\nWARNING: the load operation is destructive and will delete the {self.database} database in the {env} environment. Continue?"
196
+ )
197
+ except ClickIOProviderException:
198
+ return False
198
199
 
199
200
  def tail_logs(self, is_dump: bool, env: str):
200
201
  action = "dump" if is_dump else "load"
201
202
  log_group_name = f"/ecs/{self.app}-{env}-{self.database}-{action}"
202
203
  log_group_arn = f"arn:aws:logs:eu-west-2:{self.account_id(env)}:log-group:{log_group_name}"
203
- self.echo(f"Tailing {log_group_name} logs", fg="yellow")
204
+ self.io.warn(f"Tailing {log_group_name} logs")
204
205
  session = self.application.environments[env].session
205
206
  log_client = session.client("logs")
206
207
  wait_for_log_group_to_exist(log_client, log_group_name)
@@ -218,9 +219,11 @@ class DatabaseCopy:
218
219
  match = re.match(r"(Stopping|Aborting) data (load|dump).*", message)
219
220
  if match:
220
221
  if match.group(1) == "Aborting":
221
- self.abort("Task aborted abnormally. See logs above for details.")
222
+ self.io.abort_with_error(
223
+ "Task aborted abnormally. See logs above for details."
224
+ )
222
225
  stopped = True
223
- self.echo(message)
226
+ self.io.info(message)
224
227
 
225
228
  def account_id(self, env):
226
229
  envs = self.application.environments