dbt-platform-helper 12.1.0__tar.gz → 12.2.1__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.
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/PKG-INFO +2 -1
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/COMMANDS.md +5 -4
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/commands/application.py +1 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/commands/codebase.py +3 -2
- dbt_platform_helper-12.2.1/dbt_platform_helper/commands/conduit.py +78 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/commands/secrets.py +1 -1
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/constants.py +12 -2
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/domain/codebase.py +1 -1
- dbt_platform_helper-12.2.1/dbt_platform_helper/domain/conduit.py +172 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/exceptions.py +33 -0
- dbt_platform_helper-12.2.1/dbt_platform_helper/providers/cloudformation.py +105 -0
- dbt_platform_helper-12.2.1/dbt_platform_helper/providers/copilot.py +144 -0
- dbt_platform_helper-12.2.1/dbt_platform_helper/providers/ecs.py +79 -0
- dbt_platform_helper-12.2.1/dbt_platform_helper/providers/secrets.py +85 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/addons/svc/prometheus-policy.yml +2 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/pipelines/environments/manifest.yml +0 -1
- dbt_platform_helper-12.2.1/dbt_platform_helper/utils/__init__.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/utils/validation.py +22 -1
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/pyproject.toml +1 -1
- dbt_platform_helper-12.1.0/dbt_platform_helper/commands/conduit.py +0 -453
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/LICENSE +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/README.md +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/__init__.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/addon-plans.yml +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/addons-template-map.yml +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/commands/__init__.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/commands/config.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/commands/copilot.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/commands/database.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/commands/environment.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/commands/generate.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/commands/notify.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/commands/pipeline.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/commands/version.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/default-extensions.yml +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/domain/__init__.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/domain/database_copy.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/domain/maintenance_page.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/jinja2_tags.py +0 -0
- {dbt_platform_helper-12.1.0/dbt_platform_helper/utils → dbt_platform_helper-12.2.1/dbt_platform_helper/providers}/__init__.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/providers/load_balancers.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/.copilot/config.yml +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/.copilot/image_build_run.sh +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/.copilot/phases/build.sh +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/.copilot/phases/install.sh +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/.copilot/phases/post_build.sh +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/.copilot/phases/pre_build.sh +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/COMMANDS.md.jinja +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/addon-instructions.txt +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/addons/README.md +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/addons/svc/appconfig-ipfilter.yml +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/addons/svc/s3-policy.yml +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/addons/svc/subscription-filter.yml +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/ci-codebuild-role-policy.json +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/create-codebuild-role.json +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/custom-codebuild-role-policy.json +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/env/manifest.yml +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/env/terraform-overrides/cfn.patches.yml +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/environment-pipelines/main.tf +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/environments/main.tf +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/pipelines/codebase/manifest.yml +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/pipelines/codebase/overrides/.gitignore +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/pipelines/codebase/overrides/bin/override.ts +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/pipelines/codebase/overrides/buildspec.deploy.yml +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/pipelines/codebase/overrides/buildspec.image.yml +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/pipelines/codebase/overrides/cdk.json +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/pipelines/codebase/overrides/package-lock.json +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/pipelines/codebase/overrides/package.json +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/pipelines/codebase/overrides/stack.ts +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/pipelines/codebase/overrides/tsconfig.json +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/pipelines/codebase/overrides/types.ts +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/pipelines/environments/buildspec.yml +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/pipelines/environments/overrides/cfn.patches.yml +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/svc/maintenance_pages/default.html +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/svc/maintenance_pages/dmas-migration.html +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/svc/maintenance_pages/migration.html +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/svc/manifest-backend.yml +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/svc/manifest-public.yml +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/templates/svc/overrides/cfn.patches.yml +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/utils/application.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/utils/arn_parser.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/utils/aws.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/utils/click.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/utils/cloudfoundry.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/utils/files.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/utils/git.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/utils/manifests.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/utils/messages.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/utils/platform_config.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/utils/template.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/utils/versioning.py +0 -0
- {dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/platform_helper.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dbt-platform-helper
|
|
3
|
-
Version: 12.1
|
|
3
|
+
Version: 12.2.1
|
|
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
|
|
@@ -12,6 +12,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.10
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
16
|
Requires-Dist: Jinja2 (==3.1.4)
|
|
16
17
|
Requires-Dist: PyYAML (==6.0.1)
|
|
17
18
|
Requires-Dist: aiohttp (>=3.8.4,<4.0.0)
|
|
@@ -256,7 +256,8 @@ platform-helper codebase deploy --app <application> --env <environment> --codeba
|
|
|
256
256
|
|
|
257
257
|
[↩ Parent](#platform-helper)
|
|
258
258
|
|
|
259
|
-
|
|
259
|
+
Opens a shell for a given addon_name create a conduit connection to
|
|
260
|
+
interact with postgres, opensearch or redis.
|
|
260
261
|
|
|
261
262
|
## Usage
|
|
262
263
|
|
|
@@ -272,11 +273,11 @@ platform-helper conduit <addon_name>
|
|
|
272
273
|
## Options
|
|
273
274
|
|
|
274
275
|
- `--app <text>`
|
|
275
|
-
-
|
|
276
|
+
- Application name
|
|
276
277
|
- `--env <text>`
|
|
277
|
-
-
|
|
278
|
+
- Environment name
|
|
278
279
|
- `--access <choice>` _Defaults to read._
|
|
279
|
-
- Allow write or admin access to database addons
|
|
280
|
+
- Allow read, write or admin access to the database addons.
|
|
280
281
|
- `--help <boolean>` _Defaults to False._
|
|
281
282
|
- Show this message and exit.
|
|
282
283
|
|
{dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/commands/codebase.py
RENAMED
|
@@ -30,7 +30,7 @@ def prepare():
|
|
|
30
30
|
try:
|
|
31
31
|
Codebase().prepare()
|
|
32
32
|
except NotInCodeBaseRepositoryError:
|
|
33
|
-
# TODO
|
|
33
|
+
# TODO: Set exception message in the exceptions and just output the message in the command code
|
|
34
34
|
click.secho(
|
|
35
35
|
"You are in the deploy repository; make sure you are in the application codebase repository.",
|
|
36
36
|
fg="red",
|
|
@@ -109,6 +109,7 @@ def deploy(app, env, codebase, commit):
|
|
|
109
109
|
try:
|
|
110
110
|
Codebase().deploy(app, env, codebase, commit)
|
|
111
111
|
except ApplicationNotFoundError:
|
|
112
|
+
# TODO: Set exception message in the exceptions and just output the message in the command code
|
|
112
113
|
click.secho(
|
|
113
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.""",
|
|
114
115
|
fg="red",
|
|
@@ -120,9 +121,9 @@ def deploy(app, env, codebase, commit):
|
|
|
120
121
|
fg="red",
|
|
121
122
|
)
|
|
122
123
|
raise click.Abort
|
|
123
|
-
# TODO: don't hide json decode error
|
|
124
124
|
except (
|
|
125
125
|
CopilotCodebaseNotFoundError,
|
|
126
|
+
# TODO: Catch this error earlier and throw a more meaningful error, maybe it's CopilotCodebaseNotFoundError?
|
|
126
127
|
json.JSONDecodeError,
|
|
127
128
|
):
|
|
128
129
|
click.secho(
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from dbt_platform_helper.constants import CONDUIT_ADDON_TYPES
|
|
4
|
+
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
|
|
12
|
+
from dbt_platform_helper.utils.application import load_application
|
|
13
|
+
from dbt_platform_helper.utils.click import ClickDocOptCommand
|
|
14
|
+
from dbt_platform_helper.utils.versioning import (
|
|
15
|
+
check_platform_helper_version_needs_update,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
CONDUIT_ACCESS_OPTIONS = ["read", "write", "admin"]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@click.command(cls=ClickDocOptCommand)
|
|
22
|
+
@click.argument("addon_name", type=str, required=True)
|
|
23
|
+
@click.option("--app", help="Application name", required=True)
|
|
24
|
+
@click.option("--env", help="Environment name", required=True)
|
|
25
|
+
@click.option(
|
|
26
|
+
"--access",
|
|
27
|
+
default="read",
|
|
28
|
+
type=click.Choice(CONDUIT_ACCESS_OPTIONS),
|
|
29
|
+
help="Allow read, write or admin access to the database addons.",
|
|
30
|
+
)
|
|
31
|
+
def conduit(addon_name: str, app: str, env: str, access: str):
|
|
32
|
+
"""Opens a shell for a given addon_name create a conduit connection to
|
|
33
|
+
interact with postgres, opensearch or redis."""
|
|
34
|
+
check_platform_helper_version_needs_update()
|
|
35
|
+
application = load_application(app)
|
|
36
|
+
|
|
37
|
+
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",
|
|
47
|
+
)
|
|
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",
|
|
53
|
+
)
|
|
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",
|
|
71
|
+
)
|
|
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",
|
|
77
|
+
)
|
|
78
|
+
exit(1)
|
{dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/commands/secrets.py
RENAMED
|
@@ -102,7 +102,7 @@ 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
|
|
105
|
+
# TODO: refactor shared code with get_ssm_secret_names - Check if this is still valid
|
|
106
106
|
while True:
|
|
107
107
|
response = client.get_parameters_by_path(**params)
|
|
108
108
|
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
PLATFORM_CONFIG_FILE = "platform-config.yml"
|
|
2
2
|
PLATFORM_HELPER_VERSION_FILE = ".platform-helper-version"
|
|
3
|
-
CODEBASE_PIPELINES_KEY = "codebase_pipelines"
|
|
4
|
-
ENVIRONMENTS_KEY = "environments"
|
|
5
3
|
DEFAULT_TERRAFORM_PLATFORM_MODULES_VERSION = "5"
|
|
6
4
|
PLATFORM_HELPER_CACHE_FILE = ".platform-helper-config-cache.yml"
|
|
5
|
+
|
|
6
|
+
# Keys
|
|
7
|
+
CODEBASE_PIPELINES_KEY = "codebase_pipelines"
|
|
8
|
+
ENVIRONMENTS_KEY = "environments"
|
|
9
|
+
|
|
10
|
+
# Conduit
|
|
11
|
+
CONDUIT_ADDON_TYPES = [
|
|
12
|
+
"opensearch",
|
|
13
|
+
"postgres",
|
|
14
|
+
"redis",
|
|
15
|
+
]
|
|
16
|
+
CONDUIT_DOCKER_IMAGE_LOCATION = "public.ecr.aws/uktrade/tunnel"
|
{dbt_platform_helper-12.1.0 → dbt_platform_helper-12.2.1}/dbt_platform_helper/domain/codebase.py
RENAMED
|
@@ -195,7 +195,6 @@ class Codebase:
|
|
|
195
195
|
|
|
196
196
|
self.echo_fn("")
|
|
197
197
|
|
|
198
|
-
# TODO return empty list without exception
|
|
199
198
|
def __get_codebases(self, application, ssm_client):
|
|
200
199
|
parameters = ssm_client.get_parameters_by_path(
|
|
201
200
|
Path=f"/copilot/applications/{application.name}/codebases",
|
|
@@ -205,6 +204,7 @@ class Codebase:
|
|
|
205
204
|
codebases = [json.loads(p["Value"]) for p in parameters]
|
|
206
205
|
|
|
207
206
|
if not codebases:
|
|
207
|
+
# TODO Is this really an error? Or just no codebases so we could return an empty list?
|
|
208
208
|
raise NoCopilotCodebasesFoundError
|
|
209
209
|
return codebases
|
|
210
210
|
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
from collections.abc import Callable
|
|
3
|
+
|
|
4
|
+
import click
|
|
5
|
+
|
|
6
|
+
from dbt_platform_helper.exceptions import ECSAgentNotRunning
|
|
7
|
+
from dbt_platform_helper.providers.cloudformation import (
|
|
8
|
+
add_stack_delete_policy_to_task_role,
|
|
9
|
+
)
|
|
10
|
+
from dbt_platform_helper.providers.cloudformation import update_conduit_stack_resources
|
|
11
|
+
from dbt_platform_helper.providers.cloudformation import (
|
|
12
|
+
wait_for_cloudformation_to_reach_status,
|
|
13
|
+
)
|
|
14
|
+
from dbt_platform_helper.providers.copilot import connect_to_addon_client_task
|
|
15
|
+
from dbt_platform_helper.providers.copilot import create_addon_client_task
|
|
16
|
+
from dbt_platform_helper.providers.copilot import create_postgres_admin_task
|
|
17
|
+
from dbt_platform_helper.providers.ecs import ecs_exec_is_available
|
|
18
|
+
from dbt_platform_helper.providers.ecs import get_cluster_arn
|
|
19
|
+
from dbt_platform_helper.providers.ecs import get_ecs_task_arns
|
|
20
|
+
from dbt_platform_helper.providers.ecs import get_or_create_task_name
|
|
21
|
+
from dbt_platform_helper.providers.secrets import get_addon_type
|
|
22
|
+
from dbt_platform_helper.providers.secrets import get_parameter_name
|
|
23
|
+
from dbt_platform_helper.utils.application import Application
|
|
24
|
+
from dbt_platform_helper.utils.messages import abort_with_error
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Conduit:
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
application: Application,
|
|
31
|
+
echo_fn: Callable[[str], str] = click.secho,
|
|
32
|
+
subprocess_fn: subprocess = subprocess,
|
|
33
|
+
get_ecs_task_arns_fn=get_ecs_task_arns,
|
|
34
|
+
connect_to_addon_client_task_fn=connect_to_addon_client_task,
|
|
35
|
+
create_addon_client_task_fn=create_addon_client_task,
|
|
36
|
+
create_postgres_admin_task_fn=create_postgres_admin_task,
|
|
37
|
+
get_addon_type_fn=get_addon_type,
|
|
38
|
+
ecs_exec_is_available_fn=ecs_exec_is_available,
|
|
39
|
+
get_cluster_arn_fn=get_cluster_arn,
|
|
40
|
+
get_parameter_name_fn=get_parameter_name,
|
|
41
|
+
get_or_create_task_name_fn=get_or_create_task_name,
|
|
42
|
+
add_stack_delete_policy_to_task_role_fn=add_stack_delete_policy_to_task_role,
|
|
43
|
+
update_conduit_stack_resources_fn=update_conduit_stack_resources,
|
|
44
|
+
wait_for_cloudformation_to_reach_status_fn=wait_for_cloudformation_to_reach_status,
|
|
45
|
+
abort_fn=abort_with_error,
|
|
46
|
+
):
|
|
47
|
+
|
|
48
|
+
self.application = application
|
|
49
|
+
self.subprocess_fn = subprocess_fn
|
|
50
|
+
self.echo_fn = echo_fn
|
|
51
|
+
self.get_ecs_task_arns_fn = get_ecs_task_arns_fn
|
|
52
|
+
self.connect_to_addon_client_task_fn = connect_to_addon_client_task_fn
|
|
53
|
+
self.create_addon_client_task_fn = create_addon_client_task_fn
|
|
54
|
+
self.create_postgres_admin_task = create_postgres_admin_task_fn
|
|
55
|
+
self.get_addon_type_fn = get_addon_type_fn
|
|
56
|
+
self.ecs_exec_is_available_fn = ecs_exec_is_available_fn
|
|
57
|
+
self.get_cluster_arn_fn = get_cluster_arn_fn
|
|
58
|
+
self.get_parameter_name_fn = get_parameter_name_fn
|
|
59
|
+
self.get_or_create_task_name_fn = get_or_create_task_name_fn
|
|
60
|
+
self.add_stack_delete_policy_to_task_role_fn = add_stack_delete_policy_to_task_role_fn
|
|
61
|
+
self.update_conduit_stack_resources_fn = update_conduit_stack_resources_fn
|
|
62
|
+
self.wait_for_cloudformation_to_reach_status_fn = wait_for_cloudformation_to_reach_status_fn
|
|
63
|
+
self.abort_fn = abort_fn
|
|
64
|
+
|
|
65
|
+
def start(self, env: str, addon_name: str, access: str = "read"):
|
|
66
|
+
clients = self._initialise_clients(env)
|
|
67
|
+
addon_type, cluster_arn, parameter_name, task_name = self._get_addon_details(
|
|
68
|
+
env, addon_name, access
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
self.echo_fn(f"Checking if a conduit task is already running for {addon_type}")
|
|
72
|
+
task_arn = self.get_ecs_task_arns_fn(clients["ecs"], cluster_arn, task_name)
|
|
73
|
+
if not task_arn:
|
|
74
|
+
self.echo_fn("Creating conduit task")
|
|
75
|
+
self.create_addon_client_task_fn(
|
|
76
|
+
clients["iam"],
|
|
77
|
+
clients["ssm"],
|
|
78
|
+
clients["secrets_manager"],
|
|
79
|
+
self.subprocess_fn,
|
|
80
|
+
self.application,
|
|
81
|
+
env,
|
|
82
|
+
addon_type,
|
|
83
|
+
addon_name,
|
|
84
|
+
task_name,
|
|
85
|
+
access,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
self.echo_fn("Updating conduit task")
|
|
89
|
+
self._update_stack_resources(
|
|
90
|
+
clients["cloudformation"],
|
|
91
|
+
clients["iam"],
|
|
92
|
+
clients["ssm"],
|
|
93
|
+
self.application.name,
|
|
94
|
+
env,
|
|
95
|
+
addon_type,
|
|
96
|
+
addon_name,
|
|
97
|
+
task_name,
|
|
98
|
+
parameter_name,
|
|
99
|
+
access,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
task_arn = self.get_ecs_task_arns_fn(clients["ecs"], cluster_arn, task_name)
|
|
103
|
+
|
|
104
|
+
else:
|
|
105
|
+
self.echo_fn("Conduit task already running")
|
|
106
|
+
|
|
107
|
+
self.echo_fn(f"Checking if exec is available for conduit task...")
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
self.ecs_exec_is_available_fn(clients["ecs"], cluster_arn, task_arn)
|
|
111
|
+
except ECSAgentNotRunning:
|
|
112
|
+
self.abort_fn('ECS exec agent never reached "RUNNING" status')
|
|
113
|
+
|
|
114
|
+
self.echo_fn("Connecting to conduit task")
|
|
115
|
+
self.connect_to_addon_client_task_fn(
|
|
116
|
+
clients["ecs"], self.subprocess_fn, self.application.name, env, cluster_arn, task_name
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
def _initialise_clients(self, env):
|
|
120
|
+
return {
|
|
121
|
+
"ecs": self.application.environments[env].session.client("ecs"),
|
|
122
|
+
"iam": self.application.environments[env].session.client("iam"),
|
|
123
|
+
"ssm": self.application.environments[env].session.client("ssm"),
|
|
124
|
+
"cloudformation": self.application.environments[env].session.client("cloudformation"),
|
|
125
|
+
"secrets_manager": self.application.environments[env].session.client("secretsmanager"),
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
def _get_addon_details(self, env, addon_name, access):
|
|
129
|
+
ssm_client = self.application.environments[env].session.client("ssm")
|
|
130
|
+
ecs_client = self.application.environments[env].session.client("ecs")
|
|
131
|
+
|
|
132
|
+
addon_type = self.get_addon_type_fn(ssm_client, self.application.name, env, addon_name)
|
|
133
|
+
cluster_arn = self.get_cluster_arn_fn(ecs_client, self.application.name, env)
|
|
134
|
+
parameter_name = self.get_parameter_name_fn(
|
|
135
|
+
self.application.name, env, addon_type, addon_name, access
|
|
136
|
+
)
|
|
137
|
+
task_name = self.get_or_create_task_name_fn(
|
|
138
|
+
ssm_client, self.application.name, env, addon_name, parameter_name
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
return addon_type, cluster_arn, parameter_name, task_name
|
|
142
|
+
|
|
143
|
+
def _update_stack_resources(
|
|
144
|
+
self,
|
|
145
|
+
cloudformation_client,
|
|
146
|
+
iam_client,
|
|
147
|
+
ssm_client,
|
|
148
|
+
app_name,
|
|
149
|
+
env,
|
|
150
|
+
addon_type,
|
|
151
|
+
addon_name,
|
|
152
|
+
task_name,
|
|
153
|
+
parameter_name,
|
|
154
|
+
access,
|
|
155
|
+
):
|
|
156
|
+
self.add_stack_delete_policy_to_task_role_fn(cloudformation_client, iam_client, task_name)
|
|
157
|
+
stack_name = self.update_conduit_stack_resources_fn(
|
|
158
|
+
cloudformation_client,
|
|
159
|
+
iam_client,
|
|
160
|
+
ssm_client,
|
|
161
|
+
app_name,
|
|
162
|
+
env,
|
|
163
|
+
addon_type,
|
|
164
|
+
addon_name,
|
|
165
|
+
task_name,
|
|
166
|
+
parameter_name,
|
|
167
|
+
access,
|
|
168
|
+
)
|
|
169
|
+
self.echo_fn("Waiting for conduit task update to complete...")
|
|
170
|
+
self.wait_for_cloudformation_to_reach_status_fn(
|
|
171
|
+
cloudformation_client, "stack_update_complete", stack_name
|
|
172
|
+
)
|
|
@@ -20,6 +20,31 @@ class IncompatibleMinorVersion(ValidationException):
|
|
|
20
20
|
self.check_version = check_version
|
|
21
21
|
|
|
22
22
|
|
|
23
|
+
class NoClusterError(AWSException):
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class CreateTaskTimeoutError(AWSException):
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ParameterNotFoundError(AWSException):
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class AddonNotFoundError(AWSException):
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class InvalidAddonTypeError(AWSException):
|
|
40
|
+
def __init__(self, addon_type):
|
|
41
|
+
self.addon_type = addon_type
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class AddonTypeMissingFromConfigError(AWSException):
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
|
|
23
48
|
class CopilotCodebaseNotFoundError(Exception):
|
|
24
49
|
pass
|
|
25
50
|
|
|
@@ -46,3 +71,11 @@ class ApplicationNotFoundError(Exception):
|
|
|
46
71
|
|
|
47
72
|
class ApplicationEnvironmentNotFoundError(Exception):
|
|
48
73
|
pass
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class SecretNotFoundError(AWSException):
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class ECSAgentNotRunning(AWSException):
|
|
81
|
+
pass
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from cfn_tools import dump_yaml
|
|
4
|
+
from cfn_tools import load_yaml
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def add_stack_delete_policy_to_task_role(cloudformation_client, iam_client, task_name: str):
|
|
8
|
+
|
|
9
|
+
stack_name = f"task-{task_name}"
|
|
10
|
+
stack_resources = cloudformation_client.list_stack_resources(StackName=stack_name)[
|
|
11
|
+
"StackResourceSummaries"
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
for resource in stack_resources:
|
|
15
|
+
if resource["LogicalResourceId"] == "DefaultTaskRole":
|
|
16
|
+
task_role_name = resource["PhysicalResourceId"]
|
|
17
|
+
iam_client.put_role_policy(
|
|
18
|
+
RoleName=task_role_name,
|
|
19
|
+
PolicyName="DeleteCloudFormationStack",
|
|
20
|
+
PolicyDocument=json.dumps(
|
|
21
|
+
{
|
|
22
|
+
"Version": "2012-10-17",
|
|
23
|
+
"Statement": [
|
|
24
|
+
{
|
|
25
|
+
"Action": ["cloudformation:DeleteStack"],
|
|
26
|
+
"Effect": "Allow",
|
|
27
|
+
"Resource": f"arn:aws:cloudformation:*:*:stack/{stack_name}/*",
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def update_conduit_stack_resources(
|
|
36
|
+
cloudformation_client,
|
|
37
|
+
iam_client,
|
|
38
|
+
ssm_client,
|
|
39
|
+
application_name: str,
|
|
40
|
+
env: str,
|
|
41
|
+
addon_type: str,
|
|
42
|
+
addon_name: str,
|
|
43
|
+
task_name: str,
|
|
44
|
+
parameter_name: str,
|
|
45
|
+
access: str,
|
|
46
|
+
):
|
|
47
|
+
|
|
48
|
+
conduit_stack_name = f"task-{task_name}"
|
|
49
|
+
template = cloudformation_client.get_template(StackName=conduit_stack_name)
|
|
50
|
+
template_yml = load_yaml(template["TemplateBody"])
|
|
51
|
+
template_yml["Resources"]["LogGroup"]["DeletionPolicy"] = "Retain"
|
|
52
|
+
template_yml["Resources"]["TaskNameParameter"] = load_yaml(
|
|
53
|
+
f"""
|
|
54
|
+
Type: AWS::SSM::Parameter
|
|
55
|
+
Properties:
|
|
56
|
+
Name: {parameter_name}
|
|
57
|
+
Type: String
|
|
58
|
+
Value: {task_name}
|
|
59
|
+
"""
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
log_filter_role_arn = iam_client.get_role(RoleName="CWLtoSubscriptionFilterRole")["Role"]["Arn"]
|
|
63
|
+
|
|
64
|
+
destination_log_group_arns = json.loads(
|
|
65
|
+
ssm_client.get_parameter(Name="/copilot/tools/central_log_groups")["Parameter"]["Value"]
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
destination_arn = destination_log_group_arns["dev"]
|
|
69
|
+
if env.lower() in ("prod", "production"):
|
|
70
|
+
destination_arn = destination_log_group_arns["prod"]
|
|
71
|
+
|
|
72
|
+
template_yml["Resources"]["SubscriptionFilter"] = load_yaml(
|
|
73
|
+
f"""
|
|
74
|
+
Type: AWS::Logs::SubscriptionFilter
|
|
75
|
+
DeletionPolicy: Retain
|
|
76
|
+
Properties:
|
|
77
|
+
RoleArn: {log_filter_role_arn}
|
|
78
|
+
LogGroupName: /copilot/{task_name}
|
|
79
|
+
FilterName: /copilot/conduit/{application_name}/{env}/{addon_type}/{addon_name}/{task_name.rsplit("-", 1)[1]}/{access}
|
|
80
|
+
FilterPattern: ''
|
|
81
|
+
DestinationArn: {destination_arn}
|
|
82
|
+
"""
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
params = []
|
|
86
|
+
if "Parameters" in template_yml:
|
|
87
|
+
for param in template_yml["Parameters"]:
|
|
88
|
+
# TODO testing missed in codecov, update test to assert on method call below with params including ExistingParameter from cloudformation template.
|
|
89
|
+
params.append({"ParameterKey": param, "UsePreviousValue": True})
|
|
90
|
+
|
|
91
|
+
cloudformation_client.update_stack(
|
|
92
|
+
StackName=conduit_stack_name,
|
|
93
|
+
TemplateBody=dump_yaml(template_yml),
|
|
94
|
+
Parameters=params,
|
|
95
|
+
Capabilities=["CAPABILITY_IAM"],
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
return conduit_stack_name
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
# TODO Catch errors and raise a more human friendly Exception is the CloudFormation stack goes into a "unhappy" state, e.g. ROLLBACK_IN_PROGRESS. Currently we get things like botocore.exceptions.WaiterError: Waiter StackUpdateComplete failed: Waiter encountered a terminal failure state: For expression "Stacks[].StackStatus" we matched expected path: "UPDATE_ROLLBACK_COMPLETE" at least once
|
|
102
|
+
def wait_for_cloudformation_to_reach_status(cloudformation_client, stack_status, stack_name):
|
|
103
|
+
|
|
104
|
+
waiter = cloudformation_client.get_waiter(stack_status)
|
|
105
|
+
waiter.wait(StackName=stack_name, WaiterConfig={"Delay": 5, "MaxAttempts": 20})
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
from botocore.exceptions import ClientError
|
|
5
|
+
|
|
6
|
+
from dbt_platform_helper.constants import CONDUIT_DOCKER_IMAGE_LOCATION
|
|
7
|
+
from dbt_platform_helper.exceptions import CreateTaskTimeoutError
|
|
8
|
+
from dbt_platform_helper.providers.ecs import get_ecs_task_arns
|
|
9
|
+
from dbt_platform_helper.providers.secrets import get_connection_secret_arn
|
|
10
|
+
from dbt_platform_helper.providers.secrets import (
|
|
11
|
+
get_postgres_connection_data_updated_with_master_secret,
|
|
12
|
+
)
|
|
13
|
+
from dbt_platform_helper.utils.application import Application
|
|
14
|
+
from dbt_platform_helper.utils.messages import abort_with_error
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def create_addon_client_task(
|
|
18
|
+
iam_client,
|
|
19
|
+
ssm_client,
|
|
20
|
+
secrets_manager_client,
|
|
21
|
+
subprocess,
|
|
22
|
+
application: Application,
|
|
23
|
+
env: str,
|
|
24
|
+
addon_type: str,
|
|
25
|
+
addon_name: str,
|
|
26
|
+
task_name: str,
|
|
27
|
+
access: str,
|
|
28
|
+
):
|
|
29
|
+
secret_name = f"/copilot/{application.name}/{env}/secrets/{_normalise_secret_name(addon_name)}"
|
|
30
|
+
|
|
31
|
+
if addon_type == "postgres":
|
|
32
|
+
if access == "read":
|
|
33
|
+
secret_name += "_READ_ONLY_USER"
|
|
34
|
+
elif access == "write":
|
|
35
|
+
secret_name += "_APPLICATION_USER"
|
|
36
|
+
elif access == "admin":
|
|
37
|
+
create_postgres_admin_task(
|
|
38
|
+
ssm_client,
|
|
39
|
+
secrets_manager_client,
|
|
40
|
+
subprocess,
|
|
41
|
+
application,
|
|
42
|
+
addon_name,
|
|
43
|
+
addon_type,
|
|
44
|
+
env,
|
|
45
|
+
secret_name,
|
|
46
|
+
task_name,
|
|
47
|
+
)
|
|
48
|
+
return
|
|
49
|
+
elif addon_type == "redis" or addon_type == "opensearch":
|
|
50
|
+
secret_name += "_ENDPOINT"
|
|
51
|
+
|
|
52
|
+
role_name = f"{addon_name}-{application.name}-{env}-conduitEcsTask"
|
|
53
|
+
|
|
54
|
+
try:
|
|
55
|
+
iam_client.get_role(RoleName=role_name)
|
|
56
|
+
execution_role = f"--execution-role {role_name} "
|
|
57
|
+
except ClientError as ex:
|
|
58
|
+
execution_role = ""
|
|
59
|
+
# We cannot check for botocore.errorfactory.NoSuchEntityException as botocore generates that class on the fly as part of errorfactory.
|
|
60
|
+
# factory. Checking the error code is the recommended way of handling these exceptions.
|
|
61
|
+
if ex.response.get("Error", {}).get("Code", None) != "NoSuchEntity":
|
|
62
|
+
# TODO Raise an exception to be caught at the command layer
|
|
63
|
+
abort_with_error(
|
|
64
|
+
f"cannot obtain Role {role_name}: {ex.response.get('Error', {}).get('Message', '')}"
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
subprocess.call(
|
|
68
|
+
f"copilot task run --app {application.name} --env {env} "
|
|
69
|
+
f"--task-group-name {task_name} "
|
|
70
|
+
f"{execution_role}"
|
|
71
|
+
f"--image {CONDUIT_DOCKER_IMAGE_LOCATION}:{addon_type} "
|
|
72
|
+
f"--secrets CONNECTION_SECRET={get_connection_secret_arn(ssm_client,secrets_manager_client, secret_name)} "
|
|
73
|
+
"--platform-os linux "
|
|
74
|
+
"--platform-arch arm64",
|
|
75
|
+
shell=True,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def create_postgres_admin_task(
|
|
80
|
+
ssm_client,
|
|
81
|
+
secrets_manager_client,
|
|
82
|
+
subprocess,
|
|
83
|
+
app: Application,
|
|
84
|
+
addon_name: str,
|
|
85
|
+
addon_type: str,
|
|
86
|
+
env: str,
|
|
87
|
+
secret_name: str,
|
|
88
|
+
task_name: str,
|
|
89
|
+
):
|
|
90
|
+
read_only_secret_name = secret_name + "_READ_ONLY_USER"
|
|
91
|
+
master_secret_name = (
|
|
92
|
+
f"/copilot/{app.name}/{env}/secrets/{_normalise_secret_name(addon_name)}_RDS_MASTER_ARN"
|
|
93
|
+
)
|
|
94
|
+
master_secret_arn = ssm_client.get_parameter(Name=master_secret_name, WithDecryption=True)[
|
|
95
|
+
"Parameter"
|
|
96
|
+
]["Value"]
|
|
97
|
+
connection_string = json.dumps(
|
|
98
|
+
get_postgres_connection_data_updated_with_master_secret(
|
|
99
|
+
ssm_client, secrets_manager_client, read_only_secret_name, master_secret_arn
|
|
100
|
+
)
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
subprocess.call(
|
|
104
|
+
f"copilot task run --app {app.name} --env {env} "
|
|
105
|
+
f"--task-group-name {task_name} "
|
|
106
|
+
f"--image {CONDUIT_DOCKER_IMAGE_LOCATION}:{addon_type} "
|
|
107
|
+
f"--env-vars CONNECTION_SECRET='{connection_string}' "
|
|
108
|
+
"--platform-os linux "
|
|
109
|
+
"--platform-arch arm64",
|
|
110
|
+
shell=True,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def connect_to_addon_client_task(
|
|
115
|
+
ecs_client,
|
|
116
|
+
subprocess,
|
|
117
|
+
application_name,
|
|
118
|
+
env,
|
|
119
|
+
cluster_arn,
|
|
120
|
+
task_name,
|
|
121
|
+
addon_client_is_running_fn=get_ecs_task_arns,
|
|
122
|
+
):
|
|
123
|
+
running = False
|
|
124
|
+
tries = 0
|
|
125
|
+
while tries < 15 and not running:
|
|
126
|
+
tries += 1
|
|
127
|
+
if addon_client_is_running_fn(ecs_client, cluster_arn, task_name):
|
|
128
|
+
subprocess.call(
|
|
129
|
+
"copilot task exec "
|
|
130
|
+
f"--app {application_name} --env {env} "
|
|
131
|
+
f"--name {task_name} "
|
|
132
|
+
f"--command bash",
|
|
133
|
+
shell=True,
|
|
134
|
+
)
|
|
135
|
+
running = True
|
|
136
|
+
|
|
137
|
+
time.sleep(1)
|
|
138
|
+
|
|
139
|
+
if not running:
|
|
140
|
+
raise CreateTaskTimeoutError
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _normalise_secret_name(addon_name: str) -> str:
|
|
144
|
+
return addon_name.replace("-", "_").upper()
|