dbt-platform-helper 12.2.4__py3-none-any.whl → 12.4.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.

Potentially problematic release.


This version of dbt-platform-helper might be problematic. Click here for more details.

Files changed (33) hide show
  1. dbt_platform_helper/COMMANDS.md +6 -1
  2. dbt_platform_helper/commands/codebase.py +9 -80
  3. dbt_platform_helper/commands/conduit.py +25 -45
  4. dbt_platform_helper/commands/config.py +4 -4
  5. dbt_platform_helper/commands/copilot.py +13 -15
  6. dbt_platform_helper/commands/database.py +17 -4
  7. dbt_platform_helper/commands/environment.py +3 -2
  8. dbt_platform_helper/commands/secrets.py +1 -1
  9. dbt_platform_helper/domain/codebase.py +81 -63
  10. dbt_platform_helper/domain/conduit.py +42 -93
  11. dbt_platform_helper/domain/database_copy.py +48 -42
  12. dbt_platform_helper/domain/maintenance_page.py +8 -8
  13. dbt_platform_helper/platform_exception.py +5 -0
  14. dbt_platform_helper/providers/aws.py +32 -0
  15. dbt_platform_helper/providers/cloudformation.py +129 -100
  16. dbt_platform_helper/providers/copilot.py +33 -16
  17. dbt_platform_helper/providers/ecs.py +97 -74
  18. dbt_platform_helper/providers/load_balancers.py +11 -5
  19. dbt_platform_helper/providers/secrets.py +100 -59
  20. dbt_platform_helper/providers/validation.py +19 -0
  21. dbt_platform_helper/utils/application.py +14 -2
  22. dbt_platform_helper/utils/arn_parser.py +1 -1
  23. dbt_platform_helper/utils/aws.py +38 -12
  24. dbt_platform_helper/utils/git.py +2 -2
  25. dbt_platform_helper/utils/validation.py +57 -18
  26. dbt_platform_helper/utils/versioning.py +8 -8
  27. {dbt_platform_helper-12.2.4.dist-info → dbt_platform_helper-12.4.0.dist-info}/METADATA +1 -1
  28. {dbt_platform_helper-12.2.4.dist-info → dbt_platform_helper-12.4.0.dist-info}/RECORD +31 -30
  29. dbt_platform_helper/addons-template-map.yml +0 -29
  30. dbt_platform_helper/exceptions.py +0 -81
  31. {dbt_platform_helper-12.2.4.dist-info → dbt_platform_helper-12.4.0.dist-info}/LICENSE +0 -0
  32. {dbt_platform_helper-12.2.4.dist-info → dbt_platform_helper-12.4.0.dist-info}/WHEEL +0 -0
  33. {dbt_platform_helper-12.2.4.dist-info → dbt_platform_helper-12.4.0.dist-info}/entry_points.txt +0 -0
@@ -765,6 +765,7 @@ platform-helper database (dump|load|copy)
765
765
  ```
766
766
  platform-helper database dump --from <from_env> --database <database>
767
767
  [--app <application>] [--from-vpc <from_vpc>]
768
+ [--filename <filename>]
768
769
  ```
769
770
 
770
771
  ## Options
@@ -777,6 +778,8 @@ platform-helper database dump --from <from_env> --database <database>
777
778
  - The name of the database you are dumping data from
778
779
  - `--from-vpc <text>`
779
780
  - The vpc the specified environment is running in. Required unless you are running the command from your deploy repo
781
+ - `--filename <text>`
782
+ - Specify a name for the database dump file. Recommended if the same dump database is being used for multiple load environments
780
783
  - `--help <boolean>` _Defaults to False._
781
784
  - Show this message and exit.
782
785
 
@@ -791,7 +794,7 @@ platform-helper database dump --from <from_env> --database <database>
791
794
  ```
792
795
  platform-helper database load --to <to_env> --database <database>
793
796
  [--app <application>] [--to-vpc <to_vpc>]
794
- [--auto-approve]
797
+ [--filename <filename>] [--auto-approve]
795
798
  ```
796
799
 
797
800
  ## Options
@@ -806,6 +809,8 @@ platform-helper database load --to <to_env> --database <database>
806
809
  - The vpc the specified environment is running in. Required unless you are running the command from your deploy repo
807
810
  - `--auto-approve <boolean>` _Defaults to False._
808
811
 
812
+ - `--filename <text>`
813
+ - Specify a name for the database dump file. Recommended if the same dump database is being used for multiple load environments
809
814
  - `--help <boolean>` _Defaults to False._
810
815
  - Show this message and exit.
811
816
 
@@ -1,18 +1,8 @@
1
- import json
2
- import os
3
-
4
1
  import click
5
2
 
6
3
  from dbt_platform_helper.domain.codebase import Codebase
7
- from dbt_platform_helper.exceptions import ApplicationDeploymentNotTriggered
8
- from dbt_platform_helper.exceptions import ApplicationEnvironmentNotFoundError
9
- from dbt_platform_helper.exceptions import ApplicationNotFoundError
10
- from dbt_platform_helper.exceptions import CopilotCodebaseNotFoundError
11
- from dbt_platform_helper.exceptions import ImageNotFoundError
12
- from dbt_platform_helper.exceptions import NoCopilotCodebasesFoundError
13
- from dbt_platform_helper.exceptions import NotInCodeBaseRepositoryError
4
+ from dbt_platform_helper.platform_exception import PlatformException
14
5
  from dbt_platform_helper.utils.click import ClickDocOptGroup
15
- from dbt_platform_helper.utils.git import CommitNotFoundError
16
6
  from dbt_platform_helper.utils.versioning import (
17
7
  check_platform_helper_version_needs_update,
18
8
  )
@@ -29,12 +19,8 @@ def prepare():
29
19
  """Sets up an application codebase for use within a DBT platform project."""
30
20
  try:
31
21
  Codebase().prepare()
32
- except NotInCodeBaseRepositoryError:
33
- # TODO: Set exception message in the exceptions and just output the message in the command code
34
- click.secho(
35
- "You are in the deploy repository; make sure you are in the application codebase repository.",
36
- fg="red",
37
- )
22
+ except PlatformException as err:
23
+ click.secho(str(err), fg="red")
38
24
  raise click.Abort
39
25
 
40
26
 
@@ -50,17 +36,8 @@ def list(app, with_images):
50
36
  """List available codebases for the application."""
51
37
  try:
52
38
  Codebase().list(app, with_images)
53
- except NoCopilotCodebasesFoundError:
54
- click.secho(
55
- f"""No codebases found for application "{app}""",
56
- fg="red",
57
- )
58
- raise click.Abort
59
- except ApplicationNotFoundError:
60
- click.secho(
61
- f"""The account "{os.environ.get("AWS_PROFILE")}" does not contain the application "{app}"; ensure you have set the environment variable "AWS_PROFILE" correctly.""",
62
- fg="red",
63
- )
39
+ except PlatformException as err:
40
+ click.secho(str(err), fg="red")
64
41
  raise click.Abort
65
42
 
66
43
 
@@ -76,23 +53,8 @@ def build(app, codebase, commit):
76
53
  """Trigger a CodePipeline pipeline based build."""
77
54
  try:
78
55
  Codebase().build(app, codebase, commit)
79
- except ApplicationNotFoundError:
80
- click.secho(
81
- f"""The account "{os.environ.get("AWS_PROFILE")}" does not contain the application "{app}"; ensure you have set the environment variable "AWS_PROFILE" correctly.""",
82
- fg="red",
83
- )
84
- raise click.Abort
85
- except CommitNotFoundError:
86
- click.secho(
87
- f'The commit hash "{commit}" either does not exist or you need to run `git fetch`.',
88
- fg="red",
89
- )
90
- raise click.Abort
91
- except ApplicationDeploymentNotTriggered:
92
- click.secho(
93
- f"Your build for {codebase} was not triggered.",
94
- fg="red",
95
- )
56
+ except PlatformException as err:
57
+ click.secho(str(err), fg="red")
96
58
  raise click.Abort
97
59
 
98
60
 
@@ -108,39 +70,6 @@ def build(app, codebase, commit):
108
70
  def deploy(app, env, codebase, commit):
109
71
  try:
110
72
  Codebase().deploy(app, env, codebase, commit)
111
- except ApplicationNotFoundError:
112
- # TODO: Set exception message in the exceptions and just output the message in the command code
113
- click.secho(
114
- f"""The account "{os.environ.get("AWS_PROFILE")}" does not contain the application "{app}"; ensure you have set the environment variable "AWS_PROFILE" correctly.""",
115
- fg="red",
116
- )
117
- raise click.Abort
118
- except ApplicationEnvironmentNotFoundError:
119
- click.secho(
120
- f"""The environment "{env}" either does not exist or has not been deployed.""",
121
- fg="red",
122
- )
123
- raise click.Abort
124
- except (
125
- CopilotCodebaseNotFoundError,
126
- # TODO: Catch this error earlier and throw a more meaningful error, maybe it's CopilotCodebaseNotFoundError?
127
- json.JSONDecodeError,
128
- ):
129
- click.secho(
130
- f"""The codebase "{codebase}" either does not exist or has not been deployed.""",
131
- fg="red",
132
- )
133
- raise click.Abort
134
- except ImageNotFoundError:
135
- click.secho(
136
- f'The commit hash "{commit}" has not been built into an image, try the '
137
- "`platform-helper codebase build` command first.",
138
- fg="red",
139
- )
140
- raise click.Abort
141
- except ApplicationDeploymentNotTriggered:
142
- click.secho(
143
- f"Your deployment for {codebase} was not triggered.",
144
- fg="red",
145
- )
73
+ except PlatformException as err:
74
+ click.secho(str(err), fg="red")
146
75
  raise click.Abort
@@ -1,14 +1,10 @@
1
1
  import click
2
2
 
3
- from dbt_platform_helper.constants import CONDUIT_ADDON_TYPES
4
3
  from dbt_platform_helper.domain.conduit import Conduit
5
- from dbt_platform_helper.exceptions import AddonNotFoundError
6
- from dbt_platform_helper.exceptions import AddonTypeMissingFromConfigError
7
- from dbt_platform_helper.exceptions import CreateTaskTimeoutError
8
- from dbt_platform_helper.exceptions import InvalidAddonTypeError
9
- from dbt_platform_helper.exceptions import NoClusterError
10
- from dbt_platform_helper.exceptions import ParameterNotFoundError
11
- from dbt_platform_helper.providers.secrets import SecretNotFoundError
4
+ from dbt_platform_helper.platform_exception import PlatformException
5
+ from dbt_platform_helper.providers.cloudformation import CloudFormation
6
+ from dbt_platform_helper.providers.ecs import ECS
7
+ from dbt_platform_helper.providers.secrets import Secrets
12
8
  from dbt_platform_helper.utils.application import load_application
13
9
  from dbt_platform_helper.utils.click import ClickDocOptCommand
14
10
  from dbt_platform_helper.utils.versioning import (
@@ -35,44 +31,28 @@ def conduit(addon_name: str, app: str, env: str, access: str):
35
31
  application = load_application(app)
36
32
 
37
33
  try:
38
- Conduit(application).start(env, addon_name, access)
39
- except NoClusterError:
40
- # TODO: Set exception message in the exceptions and just output the message in the command code, should be able to catch all errors in one block
41
- click.secho(f"""No ECS cluster found for "{app}" in "{env}" environment.""", fg="red")
42
- exit(1)
43
- except SecretNotFoundError as err:
44
- click.secho(
45
- f"""No secret called "{err}" for "{app}" in "{env}" environment.""",
46
- fg="red",
34
+ secrets_provider: Secrets = Secrets(
35
+ application.environments[env].session.client("ssm"),
36
+ application.environments[env].session.client("secretsmanager"),
37
+ application.name,
38
+ env,
47
39
  )
48
- exit(1)
49
- except CreateTaskTimeoutError:
50
- click.secho(
51
- f"""Client ({addon_name}) ECS task has failed to start for "{app}" in "{env}" environment.""",
52
- fg="red",
40
+ cloudformation_provider: CloudFormation = CloudFormation(
41
+ application.environments[env].session.client("cloudformation"),
42
+ application.environments[env].session.client("iam"),
43
+ application.environments[env].session.client("ssm"),
53
44
  )
54
- exit(1)
55
- except ParameterNotFoundError:
56
- click.secho(
57
- f"""No parameter called "/copilot/applications/{app}/environments/{env}/addons". Try deploying the "{app}" "{env}" environment.""",
58
- fg="red",
59
- )
60
- exit(1)
61
- except AddonNotFoundError:
62
- click.secho(
63
- f"""Addon "{addon_name}" does not exist.""",
64
- fg="red",
65
- )
66
- exit(1)
67
- except InvalidAddonTypeError as err:
68
- click.secho(
69
- f"""Addon type "{err.addon_type}" is not supported, we support: {", ".join(CONDUIT_ADDON_TYPES)}.""",
70
- fg="red",
45
+
46
+ ecs_provider: ECS = ECS(
47
+ application.environments[env].session.client("ecs"),
48
+ application.environments[env].session.client("ssm"),
49
+ application.name,
50
+ env,
71
51
  )
72
- exit(1)
73
- except AddonTypeMissingFromConfigError:
74
- click.secho(
75
- f"""The configuration for the addon {addon_name}, is missconfigured and missing the addon type.""",
76
- fg="red",
52
+
53
+ Conduit(application, secrets_provider, cloudformation_provider, ecs_provider).start(
54
+ env, addon_name, access
77
55
  )
78
- exit(1)
56
+ except PlatformException as err:
57
+ click.secho(str(err), fg="red")
58
+ raise click.Abort
@@ -8,8 +8,8 @@ import botocore
8
8
  import click
9
9
  from prettytable import PrettyTable
10
10
 
11
- from dbt_platform_helper.exceptions import IncompatibleMajorVersion
12
- from dbt_platform_helper.exceptions import ValidationException
11
+ from dbt_platform_helper.providers.validation import IncompatibleMajorVersionException
12
+ from dbt_platform_helper.providers.validation import ValidationException
13
13
  from dbt_platform_helper.utils import versioning
14
14
  from dbt_platform_helper.utils.click import ClickDocOptGroup
15
15
  from dbt_platform_helper.utils.validation import config_file_check
@@ -110,7 +110,7 @@ def deployment():
110
110
  str(template_file.resolve())
111
111
  )
112
112
  versioning.validate_template_version(local_version, str(template_file.resolve()))
113
- except IncompatibleMajorVersion:
113
+ except IncompatibleMajorVersionException:
114
114
  local_compatible_symbol = no
115
115
  compatible = False
116
116
  recommendations["dbt-platform-helper-upgrade"] = RECOMMENDATIONS[
@@ -134,7 +134,7 @@ def deployment():
134
134
  str(template_file.resolve())
135
135
  )
136
136
  versioning.validate_template_version(latest_release, str(template_file.resolve()))
137
- except IncompatibleMajorVersion:
137
+ except IncompatibleMajorVersionException:
138
138
  latest_compatible_symbol = no
139
139
  compatible = False
140
140
  except ValidationException:
@@ -35,6 +35,14 @@ SERVICE_TYPES = [
35
35
  "Worker Service",
36
36
  ]
37
37
 
38
+ ADDON_TEMPLATE_MAP = {
39
+ "s3": ["addons/svc/s3-policy.yml"],
40
+ "s3-policy": ["addons/svc/s3-policy.yml"],
41
+ "appconfig-ipfilter": ["addons/svc/appconfig-ipfilter.yml"],
42
+ "subscription-filter": ["addons/svc/subscription-filter.yml"],
43
+ "prometheus-policy": ["addons/svc/prometheus-policy.yml"],
44
+ }
45
+
38
46
 
39
47
  def list_copilot_local_environments():
40
48
  return [
@@ -248,9 +256,6 @@ def make_addons():
248
256
 
249
257
  application_name = get_application_name()
250
258
 
251
- with open(PACKAGE_DIR / "addons-template-map.yml") as fd:
252
- addon_template_map = yaml.safe_load(fd)
253
-
254
259
  click.echo("\n>>> Generating Terraform compatible addons CloudFormation\n")
255
260
 
256
261
  env_path = Path(f"copilot/environments/")
@@ -270,11 +275,6 @@ def make_addons():
270
275
  print(f">>>>>>>>> {addon_name}")
271
276
  addon_type = addon_config.pop("type")
272
277
  environments = addon_config.pop("environments")
273
- if addon_template_map[addon_type].get("requires_addons_parameters", False):
274
- pass
275
- if addon_type in ["postgres"]:
276
- pass
277
-
278
278
  environment_addon_config = {
279
279
  "addon_type": addon_type,
280
280
  "environments": environments,
@@ -309,7 +309,6 @@ def make_addons():
309
309
  _generate_service_addons(
310
310
  addon_config,
311
311
  addon_name,
312
- addon_template_map,
313
312
  addon_type,
314
313
  output_dir,
315
314
  service_addon_config,
@@ -339,7 +338,6 @@ def _generate_env_overrides(output_dir):
339
338
  def _generate_service_addons(
340
339
  addon_config,
341
340
  addon_name,
342
- addon_template_map,
343
341
  addon_type,
344
342
  output_dir,
345
343
  service_addon_config,
@@ -347,8 +345,8 @@ def _generate_service_addons(
347
345
  log_destination_arns,
348
346
  ):
349
347
  # generate svc addons
350
- for addon in addon_template_map[addon_type].get("svc", []):
351
- template = templates.get_template(addon["template"])
348
+ for addon_template in ADDON_TEMPLATE_MAP.get(addon_type, []):
349
+ template = templates.get_template(addon_template)
352
350
 
353
351
  for svc in addon_config.get("services", []):
354
352
  service_path = Path(f"copilot/{svc}/addons/")
@@ -360,10 +358,10 @@ def _generate_service_addons(
360
358
  }
361
359
  )
362
360
 
363
- filename = addon.get("filename", f"{addon_name}.yml")
364
-
365
361
  (output_dir / service_path).mkdir(parents=True, exist_ok=True)
366
- click.echo(mkfile(output_dir, service_path / filename, contents, overwrite=True))
362
+ click.echo(
363
+ mkfile(output_dir, service_path / f"{addon_name}.yml", contents, overwrite=True)
364
+ )
367
365
 
368
366
 
369
367
  def _cleanup_old_files(config, output_dir, env_addons_path, env_overrides_path):
@@ -31,10 +31,16 @@ def database():
31
31
  type=str,
32
32
  help="The vpc the specified environment is running in. Required unless you are running the command from your deploy repo",
33
33
  )
34
- def dump(app, from_env, database, from_vpc):
34
+ @click.option(
35
+ "--filename",
36
+ type=str,
37
+ help="Specify a name for the database dump file. Recommended if the same dump database is being used for multiple load environments",
38
+ )
39
+ def dump(app, from_env, database, from_vpc, filename):
35
40
  """Dump a database into an S3 bucket."""
36
41
  data_copy = DatabaseCopy(app, database)
37
- data_copy.dump(from_env, from_vpc)
42
+ data_copy.dump(from_env, from_vpc, filename)
43
+ # Todo: Catch expected errors and output message
38
44
 
39
45
 
40
46
  @database.command(name="load")
@@ -55,10 +61,16 @@ def dump(app, from_env, database, from_vpc):
55
61
  help="The vpc the specified environment is running in. Required unless you are running the command from your deploy repo",
56
62
  )
57
63
  @click.option("--auto-approve/--no-auto-approve", default=False)
58
- def load(app, to_env, database, to_vpc, auto_approve):
64
+ @click.option(
65
+ "--filename",
66
+ type=str,
67
+ help="Specify a name for the database dump file. Recommended if the same dump database is being used for multiple load environments",
68
+ )
69
+ def load(app, to_env, database, to_vpc, auto_approve, filename):
59
70
  """Load a database from an S3 bucket."""
60
71
  data_copy = DatabaseCopy(app, database, auto_approve)
61
- data_copy.load(to_env, to_vpc)
72
+ data_copy.load(to_env, to_vpc, filename)
73
+ # Todo: Catch expected errors and output message
62
74
 
63
75
 
64
76
  @database.command(name="copy")
@@ -110,3 +122,4 @@ def copy(
110
122
  """Copy a database between environments."""
111
123
  data_copy = DatabaseCopy(app, database, auto_approve)
112
124
  data_copy.copy(from_env, to_env, from_vpc, to_vpc, svc, template, no_maintenance_page)
125
+ # Todo: Catch expected errors and output message
@@ -5,6 +5,7 @@ from schema import SchemaError
5
5
  from dbt_platform_helper.constants import DEFAULT_TERRAFORM_PLATFORM_MODULES_VERSION
6
6
  from dbt_platform_helper.constants import PLATFORM_CONFIG_FILE
7
7
  from dbt_platform_helper.domain.maintenance_page import MaintenancePageProvider
8
+ from dbt_platform_helper.platform_exception import PlatformException
8
9
  from dbt_platform_helper.providers.load_balancers import find_https_listener
9
10
  from dbt_platform_helper.utils.aws import get_aws_session_or_abort
10
11
  from dbt_platform_helper.utils.click import ClickDocOptGroup
@@ -238,10 +239,10 @@ def find_https_certificate(session: boto3.Session, app: str, env: str) -> str:
238
239
  try:
239
240
  certificate_arn = next(c["CertificateArn"] for c in certificates if c["IsDefault"])
240
241
  except StopIteration:
241
- raise CertificateNotFoundError()
242
+ raise CertificateNotFoundException()
242
243
 
243
244
  return certificate_arn
244
245
 
245
246
 
246
- class CertificateNotFoundError(Exception):
247
+ class CertificateNotFoundException(PlatformException):
247
248
  pass
@@ -102,7 +102,6 @@ def list(app, env):
102
102
  params = dict(Path=path, Recursive=False, WithDecryption=True, MaxResults=10)
103
103
  secrets = []
104
104
 
105
- # TODO: refactor shared code with get_ssm_secret_names - Check if this is still valid
106
105
  while True:
107
106
  response = client.get_parameters_by_path(**params)
108
107
 
@@ -114,6 +113,7 @@ def list(app, env):
114
113
  else:
115
114
  break
116
115
 
116
+ # Todo: When we refactor this, the above could probably just use dbt_platform_helper.utils.aws.get_ssm_secret_names so we would end up with print("\n".join(get_ssm_secret_names(app, env)))
117
117
  print("\n".join(sorted(secrets)))
118
118
 
119
119