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.
- dbt_platform_helper/COMMANDS.md +39 -38
- dbt_platform_helper/commands/codebase.py +5 -8
- dbt_platform_helper/commands/conduit.py +2 -2
- dbt_platform_helper/commands/config.py +1 -1
- dbt_platform_helper/commands/copilot.py +4 -2
- dbt_platform_helper/commands/environment.py +40 -24
- dbt_platform_helper/commands/pipeline.py +6 -171
- dbt_platform_helper/constants.py +1 -0
- dbt_platform_helper/domain/codebase.py +20 -23
- dbt_platform_helper/domain/conduit.py +10 -12
- dbt_platform_helper/domain/config_validator.py +40 -7
- dbt_platform_helper/domain/copilot_environment.py +135 -131
- dbt_platform_helper/domain/database_copy.py +45 -42
- dbt_platform_helper/domain/maintenance_page.py +220 -183
- dbt_platform_helper/domain/pipelines.py +212 -0
- dbt_platform_helper/domain/terraform_environment.py +68 -35
- dbt_platform_helper/domain/test_platform_terraform_manifest_generator.py +100 -0
- dbt_platform_helper/providers/cache.py +1 -2
- dbt_platform_helper/providers/cloudformation.py +12 -1
- dbt_platform_helper/providers/config.py +21 -13
- dbt_platform_helper/providers/copilot.py +2 -0
- dbt_platform_helper/providers/files.py +26 -0
- dbt_platform_helper/providers/io.py +31 -0
- dbt_platform_helper/providers/load_balancers.py +29 -3
- dbt_platform_helper/providers/platform_config_schema.py +10 -7
- dbt_platform_helper/providers/vpc.py +106 -0
- dbt_platform_helper/providers/yaml_file.py +3 -14
- dbt_platform_helper/templates/COMMANDS.md.jinja +5 -3
- dbt_platform_helper/templates/pipelines/codebase/overrides/package-lock.json +819 -623
- dbt_platform_helper/utils/application.py +32 -34
- dbt_platform_helper/utils/aws.py +0 -50
- dbt_platform_helper/utils/files.py +8 -23
- dbt_platform_helper/utils/messages.py +2 -3
- dbt_platform_helper/utils/platform_config.py +0 -7
- dbt_platform_helper/utils/versioning.py +12 -0
- {dbt_platform_helper-12.5.0.dist-info → dbt_platform_helper-12.6.0.dist-info}/METADATA +2 -2
- {dbt_platform_helper-12.5.0.dist-info → dbt_platform_helper-12.6.0.dist-info}/RECORD +40 -35
- {dbt_platform_helper-12.5.0.dist-info → dbt_platform_helper-12.6.0.dist-info}/WHEEL +1 -1
- {dbt_platform_helper-12.5.0.dist-info → dbt_platform_helper-12.6.0.dist-info}/LICENSE +0 -0
- {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
|
|
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
|
-
|
|
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
|
-
|
|
36
|
-
|
|
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.
|
|
43
|
+
self.vpc_provider = vpc_provider
|
|
47
44
|
self.db_connection_string = db_connection_string
|
|
48
|
-
self.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
105
|
-
self.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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.
|
|
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.
|
|
222
|
+
self.io.abort_with_error(
|
|
223
|
+
"Task aborted abnormally. See logs above for details."
|
|
224
|
+
)
|
|
222
225
|
stopped = True
|
|
223
|
-
self.
|
|
226
|
+
self.io.info(message)
|
|
224
227
|
|
|
225
228
|
def account_id(self, env):
|
|
226
229
|
envs = self.application.environments
|