dbt-platform-helper 12.2.4__tar.gz → 12.3.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 (98) hide show
  1. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/PKG-INFO +1 -1
  2. dbt_platform_helper-12.3.0/dbt_platform_helper/commands/codebase.py +75 -0
  3. dbt_platform_helper-12.3.0/dbt_platform_helper/commands/conduit.py +58 -0
  4. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/commands/secrets.py +1 -1
  5. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/domain/codebase.py +60 -60
  6. dbt_platform_helper-12.3.0/dbt_platform_helper/domain/conduit.py +127 -0
  7. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/domain/database_copy.py +42 -37
  8. dbt_platform_helper-12.3.0/dbt_platform_helper/exceptions.py +147 -0
  9. dbt_platform_helper-12.3.0/dbt_platform_helper/providers/cloudformation.py +127 -0
  10. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/providers/copilot.py +32 -12
  11. dbt_platform_helper-12.3.0/dbt_platform_helper/providers/ecs.py +87 -0
  12. dbt_platform_helper-12.3.0/dbt_platform_helper/providers/secrets.py +85 -0
  13. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/utils/application.py +1 -1
  14. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/utils/aws.py +29 -6
  15. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/utils/validation.py +39 -14
  16. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/pyproject.toml +1 -1
  17. dbt_platform_helper-12.2.4/dbt_platform_helper/commands/codebase.py +0 -146
  18. dbt_platform_helper-12.2.4/dbt_platform_helper/commands/conduit.py +0 -78
  19. dbt_platform_helper-12.2.4/dbt_platform_helper/domain/conduit.py +0 -172
  20. dbt_platform_helper-12.2.4/dbt_platform_helper/exceptions.py +0 -81
  21. dbt_platform_helper-12.2.4/dbt_platform_helper/providers/cloudformation.py +0 -105
  22. dbt_platform_helper-12.2.4/dbt_platform_helper/providers/ecs.py +0 -79
  23. dbt_platform_helper-12.2.4/dbt_platform_helper/providers/secrets.py +0 -85
  24. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/LICENSE +0 -0
  25. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/COMMANDS.md +0 -0
  26. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/README.md +0 -0
  27. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/__init__.py +0 -0
  28. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/addon-plans.yml +0 -0
  29. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/addons-template-map.yml +0 -0
  30. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/commands/__init__.py +0 -0
  31. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/commands/application.py +0 -0
  32. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/commands/config.py +0 -0
  33. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/commands/copilot.py +0 -0
  34. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/commands/database.py +0 -0
  35. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/commands/environment.py +0 -0
  36. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/commands/generate.py +0 -0
  37. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/commands/notify.py +0 -0
  38. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/commands/pipeline.py +0 -0
  39. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/commands/version.py +0 -0
  40. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/constants.py +0 -0
  41. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/default-extensions.yml +0 -0
  42. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/domain/__init__.py +0 -0
  43. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/domain/maintenance_page.py +0 -0
  44. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/jinja2_tags.py +0 -0
  45. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/providers/__init__.py +0 -0
  46. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/providers/load_balancers.py +0 -0
  47. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/.copilot/config.yml +0 -0
  48. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/.copilot/image_build_run.sh +0 -0
  49. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/.copilot/phases/build.sh +0 -0
  50. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/.copilot/phases/install.sh +0 -0
  51. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/.copilot/phases/post_build.sh +0 -0
  52. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/.copilot/phases/pre_build.sh +0 -0
  53. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/COMMANDS.md.jinja +0 -0
  54. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/addon-instructions.txt +0 -0
  55. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/addons/README.md +0 -0
  56. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/addons/svc/appconfig-ipfilter.yml +0 -0
  57. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/addons/svc/prometheus-policy.yml +0 -0
  58. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/addons/svc/s3-policy.yml +0 -0
  59. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/addons/svc/subscription-filter.yml +0 -0
  60. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/ci-codebuild-role-policy.json +0 -0
  61. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/create-codebuild-role.json +0 -0
  62. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/custom-codebuild-role-policy.json +0 -0
  63. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/env/manifest.yml +0 -0
  64. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/env/terraform-overrides/cfn.patches.yml +0 -0
  65. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/environment-pipelines/main.tf +0 -0
  66. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/environments/main.tf +0 -0
  67. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/pipelines/codebase/manifest.yml +0 -0
  68. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/pipelines/codebase/overrides/.gitignore +0 -0
  69. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/pipelines/codebase/overrides/bin/override.ts +0 -0
  70. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/pipelines/codebase/overrides/buildspec.deploy.yml +0 -0
  71. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/pipelines/codebase/overrides/buildspec.image.yml +0 -0
  72. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/pipelines/codebase/overrides/cdk.json +0 -0
  73. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/pipelines/codebase/overrides/package-lock.json +0 -0
  74. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/pipelines/codebase/overrides/package.json +0 -0
  75. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/pipelines/codebase/overrides/stack.ts +0 -0
  76. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/pipelines/codebase/overrides/tsconfig.json +0 -0
  77. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/pipelines/codebase/overrides/types.ts +0 -0
  78. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/pipelines/environments/buildspec.yml +0 -0
  79. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/pipelines/environments/manifest.yml +0 -0
  80. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/pipelines/environments/overrides/cfn.patches.yml +0 -0
  81. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/svc/maintenance_pages/default.html +0 -0
  82. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/svc/maintenance_pages/dmas-migration.html +0 -0
  83. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/svc/maintenance_pages/migration.html +0 -0
  84. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/svc/manifest-backend.yml +0 -0
  85. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/svc/manifest-public.yml +0 -0
  86. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/templates/svc/overrides/cfn.patches.yml +0 -0
  87. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/utils/__init__.py +0 -0
  88. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/utils/arn_parser.py +0 -0
  89. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/utils/click.py +0 -0
  90. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/utils/cloudfoundry.py +0 -0
  91. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/utils/files.py +0 -0
  92. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/utils/git.py +0 -0
  93. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/utils/manifests.py +0 -0
  94. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/utils/messages.py +0 -0
  95. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/utils/platform_config.py +0 -0
  96. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/utils/template.py +0 -0
  97. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/dbt_platform_helper/utils/versioning.py +0 -0
  98. {dbt_platform_helper-12.2.4 → dbt_platform_helper-12.3.0}/platform_helper.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dbt-platform-helper
3
- Version: 12.2.4
3
+ Version: 12.3.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
@@ -0,0 +1,75 @@
1
+ import click
2
+
3
+ from dbt_platform_helper.domain.codebase import Codebase
4
+ from dbt_platform_helper.exceptions import PlatformException
5
+ from dbt_platform_helper.utils.click import ClickDocOptGroup
6
+ from dbt_platform_helper.utils.versioning import (
7
+ check_platform_helper_version_needs_update,
8
+ )
9
+
10
+
11
+ @click.group(chain=True, cls=ClickDocOptGroup)
12
+ def codebase():
13
+ """Codebase commands."""
14
+ check_platform_helper_version_needs_update()
15
+
16
+
17
+ @codebase.command()
18
+ def prepare():
19
+ """Sets up an application codebase for use within a DBT platform project."""
20
+ try:
21
+ Codebase().prepare()
22
+ except PlatformException as err:
23
+ click.secho(str(err), fg="red")
24
+ raise click.Abort
25
+
26
+
27
+ @codebase.command()
28
+ @click.option("--app", help="AWS application name", required=True)
29
+ @click.option(
30
+ "--with-images",
31
+ help="List up to the last 10 images tagged for this codebase",
32
+ default=False,
33
+ is_flag=True,
34
+ )
35
+ def list(app, with_images):
36
+ """List available codebases for the application."""
37
+ try:
38
+ Codebase().list(app, with_images)
39
+ except PlatformException as err:
40
+ click.secho(str(err), fg="red")
41
+ raise click.Abort
42
+
43
+
44
+ @codebase.command()
45
+ @click.option("--app", help="AWS application name", required=True)
46
+ @click.option(
47
+ "--codebase",
48
+ help="The codebase name as specified in the platform-config.yml file",
49
+ required=True,
50
+ )
51
+ @click.option("--commit", help="GitHub commit hash", required=True)
52
+ def build(app, codebase, commit):
53
+ """Trigger a CodePipeline pipeline based build."""
54
+ try:
55
+ Codebase().build(app, codebase, commit)
56
+ except PlatformException as err:
57
+ click.secho(str(err), fg="red")
58
+ raise click.Abort
59
+
60
+
61
+ @codebase.command()
62
+ @click.option("--app", help="AWS application name", required=True)
63
+ @click.option("--env", help="AWS Copilot environment", required=True)
64
+ @click.option(
65
+ "--codebase",
66
+ help="The codebase name as specified in the platform-config.yml file",
67
+ required=True,
68
+ )
69
+ @click.option("--commit", help="GitHub commit hash", required=True)
70
+ def deploy(app, env, codebase, commit):
71
+ try:
72
+ Codebase().deploy(app, env, codebase, commit)
73
+ except PlatformException as err:
74
+ click.secho(str(err), fg="red")
75
+ raise click.Abort
@@ -0,0 +1,58 @@
1
+ import click
2
+
3
+ from dbt_platform_helper.domain.conduit import Conduit
4
+ from dbt_platform_helper.exceptions import AWSException
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
8
+ from dbt_platform_helper.utils.application import load_application
9
+ from dbt_platform_helper.utils.click import ClickDocOptCommand
10
+ from dbt_platform_helper.utils.versioning import (
11
+ check_platform_helper_version_needs_update,
12
+ )
13
+
14
+ CONDUIT_ACCESS_OPTIONS = ["read", "write", "admin"]
15
+
16
+
17
+ @click.command(cls=ClickDocOptCommand)
18
+ @click.argument("addon_name", type=str, required=True)
19
+ @click.option("--app", help="Application name", required=True)
20
+ @click.option("--env", help="Environment name", required=True)
21
+ @click.option(
22
+ "--access",
23
+ default="read",
24
+ type=click.Choice(CONDUIT_ACCESS_OPTIONS),
25
+ help="Allow read, write or admin access to the database addons.",
26
+ )
27
+ def conduit(addon_name: str, app: str, env: str, access: str):
28
+ """Opens a shell for a given addon_name create a conduit connection to
29
+ interact with postgres, opensearch or redis."""
30
+ check_platform_helper_version_needs_update()
31
+ application = load_application(app)
32
+
33
+ try:
34
+ secrets_provider: Secrets = Secrets(
35
+ application.environments[env].session.client("ssm"),
36
+ application.environments[env].session.client("secretsmanager"),
37
+ application.name,
38
+ env,
39
+ )
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"),
44
+ )
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,
51
+ )
52
+
53
+ Conduit(application, secrets_provider, cloudformation_provider, ecs_provider).start(
54
+ env, addon_name, access
55
+ )
56
+ except AWSException as err:
57
+ click.secho(str(err), fg="red")
58
+ raise click.Abort
@@ -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
 
@@ -11,7 +11,6 @@ from boto3 import Session
11
11
 
12
12
  from dbt_platform_helper.exceptions import ApplicationDeploymentNotTriggered
13
13
  from dbt_platform_helper.exceptions import ApplicationEnvironmentNotFoundError
14
- from dbt_platform_helper.exceptions import NoCopilotCodebasesFoundError
15
14
  from dbt_platform_helper.exceptions import NotInCodeBaseRepositoryError
16
15
  from dbt_platform_helper.utils.application import Application
17
16
  from dbt_platform_helper.utils.application import load_application
@@ -29,31 +28,31 @@ from dbt_platform_helper.utils.template import setup_templates
29
28
  class Codebase:
30
29
  def __init__(
31
30
  self,
32
- input_fn: Callable[[str], str] = click.prompt,
33
- echo_fn: Callable[[str], str] = click.secho,
34
- confirm_fn: Callable[[str], bool] = click.confirm,
35
- load_application_fn: Callable[[str], Application] = load_application,
36
- get_aws_session_or_abort_fn: Callable[[str], Session] = get_aws_session_or_abort,
37
- check_codebase_exists_fn: Callable[[str], str] = check_codebase_exists,
38
- check_image_exists_fn: Callable[[str], str] = check_image_exists,
39
- get_build_url_from_arn_fn: Callable[[str], str] = get_build_url_from_arn,
40
- list_latest_images_fn: Callable[[str], str] = list_latest_images,
41
- start_build_extraction_fn: Callable[[str], str] = start_build_extraction,
42
- check_if_commit_exists_fn: Callable[[str], str] = check_if_commit_exists,
43
- subprocess: Callable[[str], str] = subprocess.run,
31
+ input: Callable[[str], str] = click.prompt,
32
+ echo: Callable[[str], str] = click.secho,
33
+ confirm: Callable[[str], bool] = click.confirm,
34
+ load_application: Callable[[str], Application] = load_application,
35
+ get_aws_session_or_abort: Callable[[str], Session] = get_aws_session_or_abort,
36
+ check_codebase_exists: Callable[[str], str] = check_codebase_exists,
37
+ check_image_exists: Callable[[str], str] = check_image_exists,
38
+ get_build_url_from_arn: Callable[[str], str] = get_build_url_from_arn,
39
+ list_latest_images: Callable[[str], str] = list_latest_images,
40
+ start_build_extraction: Callable[[str], str] = start_build_extraction,
41
+ check_if_commit_exists: Callable[[str], str] = check_if_commit_exists,
42
+ run_subprocess: Callable[[str], str] = subprocess.run,
44
43
  ):
45
- self.input_fn = input_fn
46
- self.echo_fn = echo_fn
47
- self.confirm_fn = confirm_fn
48
- self.load_application_fn = load_application_fn
49
- self.get_aws_session_or_abort_fn = get_aws_session_or_abort_fn
50
- self.check_codebase_exists_fn = check_codebase_exists_fn
51
- self.check_image_exists_fn = check_image_exists_fn
52
- self.get_build_url_from_arn_fn = get_build_url_from_arn_fn
53
- self.list_latest_images_fn = list_latest_images_fn
54
- self.start_build_extraction_fn = start_build_extraction_fn
55
- self.check_if_commit_exists_fn = check_if_commit_exists_fn
56
- self.subprocess = subprocess
44
+ self.input = input
45
+ self.echo = echo
46
+ self.confirm = confirm
47
+ self.load_application = load_application
48
+ self.get_aws_session_or_abort = get_aws_session_or_abort
49
+ self.check_codebase_exists = check_codebase_exists
50
+ self.check_image_exists = check_image_exists
51
+ self.get_build_url_from_arn = get_build_url_from_arn
52
+ self.list_latest_images = list_latest_images
53
+ self.start_build_extraction = start_build_extraction
54
+ self.check_if_commit_exists = check_if_commit_exists
55
+ self.run_subprocess = run_subprocess
57
56
 
58
57
  def prepare(self):
59
58
  """Sets up an application codebase for use within a DBT platform
@@ -61,13 +60,15 @@ class Codebase:
61
60
  templates = setup_templates()
62
61
 
63
62
  repository = (
64
- self.subprocess(["git", "remote", "get-url", "origin"], capture_output=True, text=True)
63
+ self.run_subprocess(
64
+ ["git", "remote", "get-url", "origin"], capture_output=True, text=True
65
+ )
65
66
  .stdout.split("/")[-1]
66
67
  .strip()
67
68
  .removesuffix(".git")
68
69
  )
69
70
  if repository.endswith("-deploy") or Path("./copilot").exists():
70
- raise NotInCodeBaseRepositoryError
71
+ raise NotInCodeBaseRepositoryError()
71
72
 
72
73
  builder_configuration_url = "https://raw.githubusercontent.com/uktrade/ci-image-builder/main/image_builder/configuration/builder_configuration.yml"
73
74
  builder_configuration_response = requests.get(builder_configuration_url)
@@ -91,7 +92,7 @@ class Codebase:
91
92
  config_contents = templates.get_template(f".copilot/config.yml").render(
92
93
  repository=repository, builder_version=builder_version
93
94
  )
94
- self.echo_fn(
95
+ self.echo(
95
96
  mkfile(
96
97
  Path("."), ".copilot/image_build_run.sh", image_build_run_contents, overwrite=True
97
98
  )
@@ -100,27 +101,27 @@ class Codebase:
100
101
  image_build_run_file = Path(".copilot/image_build_run.sh")
101
102
  image_build_run_file.chmod(image_build_run_file.stat().st_mode | stat.S_IEXEC)
102
103
 
103
- self.echo_fn(mkfile(Path("."), ".copilot/config.yml", config_contents, overwrite=True))
104
+ self.echo(mkfile(Path("."), ".copilot/config.yml", config_contents, overwrite=True))
104
105
 
105
106
  for phase in ["build", "install", "post_build", "pre_build"]:
106
107
  phase_contents = templates.get_template(f".copilot/phases/{phase}.sh").render()
107
108
 
108
- self.echo_fn(
109
+ self.echo(
109
110
  mkfile(Path("./.copilot"), f"phases/{phase}.sh", phase_contents, overwrite=True)
110
111
  )
111
112
 
112
113
  def build(self, app: str, codebase: str, commit: str):
113
114
  """Trigger a CodePipeline pipeline based build."""
114
- session = self.get_aws_session_or_abort_fn()
115
- self.load_application_fn(app, default_session=session)
115
+ session = self.get_aws_session_or_abort()
116
+ self.load_application(app, default_session=session)
116
117
 
117
- self.check_if_commit_exists_fn(commit)
118
+ self.check_if_commit_exists(commit)
118
119
 
119
120
  codebuild_client = session.client("codebuild")
120
121
  build_url = self.__start_build_with_confirmation(
121
- self.confirm_fn,
122
+ self.confirm,
122
123
  codebuild_client,
123
- self.get_build_url_from_arn_fn,
124
+ self.get_build_url_from_arn,
124
125
  f'You are about to build "{app}" for "{codebase}" with commit "{commit}". Do you want to continue?',
125
126
  {
126
127
  "projectName": f"codebuild-{app}-{codebase}",
@@ -130,29 +131,29 @@ class Codebase:
130
131
  )
131
132
 
132
133
  if build_url:
133
- return self.echo_fn(
134
+ return self.echo(
134
135
  f"Your build has been triggered. Check your build progress in the AWS Console: {build_url}"
135
136
  )
136
137
 
137
- raise ApplicationDeploymentNotTriggered()
138
+ raise ApplicationDeploymentNotTriggered(codebase)
138
139
 
139
140
  def deploy(self, app, env, codebase, commit):
140
141
  """Trigger a CodePipeline pipeline based deployment."""
141
- session = self.get_aws_session_or_abort_fn()
142
+ session = self.get_aws_session_or_abort()
142
143
 
143
- application = self.load_application_fn(app, default_session=session)
144
+ application = self.load_application(app, default_session=session)
144
145
  if not application.environments.get(env):
145
- raise ApplicationEnvironmentNotFoundError()
146
+ raise ApplicationEnvironmentNotFoundError(env)
146
147
 
147
- self.check_codebase_exists_fn(session, application, codebase)
148
+ self.check_codebase_exists(session, application, codebase)
148
149
 
149
- self.check_image_exists_fn(session, application, codebase, commit)
150
+ self.check_image_exists(session, application, codebase, commit)
150
151
 
151
152
  codebuild_client = session.client("codebuild")
152
153
  build_url = self.__start_build_with_confirmation(
153
- self.confirm_fn,
154
+ self.confirm,
154
155
  codebuild_client,
155
- self.get_build_url_from_arn_fn,
156
+ self.get_build_url_from_arn,
156
157
  f'You are about to deploy "{app}" for "{codebase}" with commit "{commit}" to the "{env}" environment. Do you want to continue?',
157
158
  {
158
159
  "projectName": f"pipeline-{application.name}-{codebase}-BuildProject",
@@ -166,34 +167,34 @@ class Codebase:
166
167
  )
167
168
 
168
169
  if build_url:
169
- return self.echo_fn(
170
+ return self.echo(
170
171
  "Your deployment has been triggered. Check your build progress in the AWS Console: "
171
172
  f"{build_url}",
172
173
  )
173
174
 
174
- raise ApplicationDeploymentNotTriggered()
175
+ raise ApplicationDeploymentNotTriggered(codebase)
175
176
 
176
177
  def list(self, app: str, with_images: bool):
177
178
  """List available codebases for the application."""
178
- session = self.get_aws_session_or_abort_fn()
179
- application = self.load_application_fn(app, session)
179
+ session = self.get_aws_session_or_abort()
180
+ application = self.load_application(app, session)
180
181
  ssm_client = session.client("ssm")
181
182
  ecr_client = session.client("ecr")
182
183
  codebases = self.__get_codebases(application, ssm_client)
183
184
 
184
- self.echo_fn("The following codebases are available:")
185
+ self.echo("The following codebases are available:")
185
186
 
186
187
  for codebase in codebases:
187
- self.echo_fn(f"- {codebase['name']} (https://github.com/{codebase['repository']})")
188
+ self.echo(f"- {codebase['name']} (https://github.com/{codebase['repository']})")
188
189
  if with_images:
189
- self.list_latest_images_fn(
190
+ self.list_latest_images(
190
191
  ecr_client,
191
192
  f"{application.name}/{codebase['name']}",
192
193
  codebase["repository"],
193
- self.echo_fn,
194
+ self.echo,
194
195
  )
195
196
 
196
- self.echo_fn("")
197
+ self.echo("")
197
198
 
198
199
  def __get_codebases(self, application, ssm_client):
199
200
  parameters = ssm_client.get_parameters_by_path(
@@ -204,19 +205,18 @@ class Codebase:
204
205
  codebases = [json.loads(p["Value"]) for p in parameters]
205
206
 
206
207
  if not codebases:
207
- # TODO Is this really an error? Or just no codebases so we could return an empty list?
208
- raise NoCopilotCodebasesFoundError
208
+ return []
209
209
  return codebases
210
210
 
211
211
  def __start_build_with_confirmation(
212
212
  self,
213
- confirm_fn,
213
+ confirm,
214
214
  codebuild_client,
215
- get_build_url_from_arn_fn,
215
+ get_build_url_from_arn,
216
216
  confirmation_message,
217
217
  build_options,
218
218
  ):
219
- if confirm_fn(confirmation_message):
220
- build_arn = self.start_build_extraction_fn(codebuild_client, build_options)
221
- return get_build_url_from_arn_fn(build_arn)
219
+ if confirm(confirmation_message):
220
+ build_arn = self.start_build_extraction(codebuild_client, build_options)
221
+ return get_build_url_from_arn(build_arn)
222
222
  return None
@@ -0,0 +1,127 @@
1
+ import subprocess
2
+ from collections.abc import Callable
3
+
4
+ import click
5
+
6
+ from dbt_platform_helper.providers.cloudformation import CloudFormation
7
+ from dbt_platform_helper.providers.copilot import connect_to_addon_client_task
8
+ from dbt_platform_helper.providers.copilot import create_addon_client_task
9
+ from dbt_platform_helper.providers.copilot import create_postgres_admin_task
10
+ from dbt_platform_helper.providers.ecs import ECS
11
+ from dbt_platform_helper.providers.secrets import Secrets
12
+ from dbt_platform_helper.utils.application import Application
13
+
14
+
15
+ class Conduit:
16
+ def __init__(
17
+ self,
18
+ application: Application,
19
+ secrets_provider: Secrets,
20
+ cloudformation_provider: CloudFormation,
21
+ ecs_provider: ECS,
22
+ echo: Callable[[str], str] = click.secho,
23
+ subprocess: subprocess = subprocess,
24
+ connect_to_addon_client_task=connect_to_addon_client_task,
25
+ create_addon_client_task=create_addon_client_task,
26
+ create_postgres_admin_task=create_postgres_admin_task,
27
+ ):
28
+
29
+ self.application = application
30
+ self.secrets_provider = secrets_provider
31
+ self.cloudformation_provider = cloudformation_provider
32
+ self.ecs_provider = ecs_provider
33
+ self.subprocess = subprocess
34
+ self.echo = echo
35
+ self.connect_to_addon_client_task = connect_to_addon_client_task
36
+ self.create_addon_client_task = create_addon_client_task
37
+ self.create_postgres_admin_task = create_postgres_admin_task
38
+
39
+ def start(self, env: str, addon_name: str, access: str = "read"):
40
+ clients = self._initialise_clients(env)
41
+ addon_type, cluster_arn, parameter_name, task_name = self._get_addon_details(
42
+ addon_name, access
43
+ )
44
+
45
+ self.echo(f"Checking if a conduit task is already running for {addon_type}")
46
+ task_arns = self.ecs_provider.get_ecs_task_arns(cluster_arn, task_name)
47
+ if not task_arns:
48
+ self.echo("Creating conduit task")
49
+ self.create_addon_client_task(
50
+ clients["iam"],
51
+ clients["ssm"],
52
+ clients["secrets_manager"],
53
+ self.subprocess,
54
+ self.application,
55
+ env,
56
+ addon_type,
57
+ addon_name,
58
+ task_name,
59
+ access,
60
+ )
61
+
62
+ self.echo("Updating conduit task")
63
+ self._update_stack_resources(
64
+ self.application.name,
65
+ env,
66
+ addon_type,
67
+ addon_name,
68
+ task_name,
69
+ parameter_name,
70
+ access,
71
+ )
72
+
73
+ task_arns = self.ecs_provider.get_ecs_task_arns(cluster_arn, task_name)
74
+
75
+ else:
76
+ self.echo("Conduit task already running")
77
+
78
+ self.echo(f"Checking if exec is available for conduit task...")
79
+
80
+ self.ecs_provider.ecs_exec_is_available(cluster_arn, task_arns)
81
+
82
+ self.echo("Connecting to conduit task")
83
+ self.connect_to_addon_client_task(
84
+ clients["ecs"], self.subprocess, self.application.name, env, cluster_arn, task_name
85
+ )
86
+
87
+ def _initialise_clients(self, env):
88
+ return {
89
+ "ecs": self.application.environments[env].session.client("ecs"),
90
+ "iam": self.application.environments[env].session.client("iam"),
91
+ "ssm": self.application.environments[env].session.client("ssm"),
92
+ "cloudformation": self.application.environments[env].session.client("cloudformation"),
93
+ "secrets_manager": self.application.environments[env].session.client("secretsmanager"),
94
+ }
95
+
96
+ def _get_addon_details(self, addon_name, access):
97
+ addon_type = self.secrets_provider.get_addon_type(addon_name)
98
+ cluster_arn = self.ecs_provider.get_cluster_arn()
99
+ parameter_name = self.secrets_provider.get_parameter_name(addon_type, addon_name, access)
100
+ task_name = self.ecs_provider.get_or_create_task_name(addon_name, parameter_name)
101
+
102
+ return addon_type, cluster_arn, parameter_name, task_name
103
+
104
+ def _update_stack_resources(
105
+ self,
106
+ app_name,
107
+ env,
108
+ addon_type,
109
+ addon_name,
110
+ task_name,
111
+ parameter_name,
112
+ access,
113
+ ):
114
+ self.cloudformation_provider.add_stack_delete_policy_to_task_role(task_name)
115
+ stack_name = self.cloudformation_provider.update_conduit_stack_resources(
116
+ app_name,
117
+ env,
118
+ addon_type,
119
+ addon_name,
120
+ task_name,
121
+ parameter_name,
122
+ access,
123
+ )
124
+ self.echo("Waiting for conduit task update to complete...")
125
+ self.cloudformation_provider.wait_for_cloudformation_to_reach_status(
126
+ "stack_update_complete", stack_name
127
+ )