dbt-platform-helper 13.1.1__py3-none-any.whl → 13.2.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 (42) hide show
  1. dbt_platform_helper/commands/application.py +3 -5
  2. dbt_platform_helper/commands/codebase.py +2 -4
  3. dbt_platform_helper/commands/conduit.py +2 -4
  4. dbt_platform_helper/commands/config.py +19 -17
  5. dbt_platform_helper/commands/copilot.py +13 -390
  6. dbt_platform_helper/commands/environment.py +6 -6
  7. dbt_platform_helper/commands/generate.py +2 -3
  8. dbt_platform_helper/commands/notify.py +2 -4
  9. dbt_platform_helper/commands/pipeline.py +2 -4
  10. dbt_platform_helper/commands/secrets.py +2 -4
  11. dbt_platform_helper/commands/version.py +2 -2
  12. dbt_platform_helper/domain/codebase.py +14 -11
  13. dbt_platform_helper/domain/copilot.py +397 -0
  14. dbt_platform_helper/domain/copilot_environment.py +6 -6
  15. dbt_platform_helper/domain/maintenance_page.py +227 -431
  16. dbt_platform_helper/domain/pipelines.py +1 -1
  17. dbt_platform_helper/domain/terraform_environment.py +1 -1
  18. dbt_platform_helper/domain/versioning.py +157 -0
  19. dbt_platform_helper/providers/aws/interfaces.py +13 -0
  20. dbt_platform_helper/providers/aws/opensearch.py +23 -0
  21. dbt_platform_helper/providers/aws/redis.py +21 -0
  22. dbt_platform_helper/providers/cache.py +40 -4
  23. dbt_platform_helper/providers/config_validator.py +15 -14
  24. dbt_platform_helper/providers/copilot.py +1 -1
  25. dbt_platform_helper/providers/io.py +17 -0
  26. dbt_platform_helper/providers/kms.py +22 -0
  27. dbt_platform_helper/providers/load_balancers.py +269 -43
  28. dbt_platform_helper/providers/semantic_version.py +33 -10
  29. dbt_platform_helper/providers/version.py +42 -0
  30. dbt_platform_helper/providers/yaml_file.py +0 -1
  31. dbt_platform_helper/utils/application.py +14 -0
  32. dbt_platform_helper/utils/aws.py +27 -4
  33. dbt_platform_helper/utils/tool_versioning.py +96 -0
  34. {dbt_platform_helper-13.1.1.dist-info → dbt_platform_helper-13.2.0.dist-info}/METADATA +3 -4
  35. {dbt_platform_helper-13.1.1.dist-info → dbt_platform_helper-13.2.0.dist-info}/RECORD +39 -35
  36. dbt_platform_helper/providers/opensearch.py +0 -36
  37. dbt_platform_helper/providers/redis.py +0 -34
  38. dbt_platform_helper/utils/versioning.py +0 -238
  39. /dbt_platform_helper/providers/{aws.py → aws/exceptions.py} +0 -0
  40. {dbt_platform_helper-13.1.1.dist-info → dbt_platform_helper-13.2.0.dist-info}/LICENSE +0 -0
  41. {dbt_platform_helper-13.1.1.dist-info → dbt_platform_helper-13.2.0.dist-info}/WHEEL +0 -0
  42. {dbt_platform_helper-13.1.1.dist-info → dbt_platform_helper-13.2.0.dist-info}/entry_points.txt +0 -0
@@ -2,16 +2,14 @@ import click
2
2
  from slack_sdk import WebClient
3
3
  from slack_sdk.models import blocks
4
4
 
5
+ from dbt_platform_helper.domain.versioning import PlatformHelperVersioning
5
6
  from dbt_platform_helper.utils.arn_parser import ARN
6
7
  from dbt_platform_helper.utils.click import ClickDocOptGroup
7
- from dbt_platform_helper.utils.versioning import (
8
- check_platform_helper_version_needs_update,
9
- )
10
8
 
11
9
 
12
10
  @click.group(cls=ClickDocOptGroup, help="Send Slack notifications")
13
11
  def notify():
14
- check_platform_helper_version_needs_update()
12
+ PlatformHelperVersioning().check_if_needs_update()
15
13
 
16
14
 
17
15
  @notify.command(
@@ -3,6 +3,7 @@ import click
3
3
 
4
4
  from dbt_platform_helper.constants import DEFAULT_TERRAFORM_PLATFORM_MODULES_VERSION
5
5
  from dbt_platform_helper.domain.pipelines import Pipelines
6
+ from dbt_platform_helper.domain.versioning import PlatformHelperVersioning
6
7
  from dbt_platform_helper.providers.config import ConfigProvider
7
8
  from dbt_platform_helper.providers.config_validator import ConfigValidator
8
9
  from dbt_platform_helper.providers.ecr import ECRProvider
@@ -11,15 +12,12 @@ from dbt_platform_helper.providers.terraform_manifest import TerraformManifestPr
11
12
  from dbt_platform_helper.utils.aws import get_codestar_connection_arn
12
13
  from dbt_platform_helper.utils.click import ClickDocOptGroup
13
14
  from dbt_platform_helper.utils.git import git_remote
14
- from dbt_platform_helper.utils.versioning import (
15
- check_platform_helper_version_needs_update,
16
- )
17
15
 
18
16
 
19
17
  @click.group(chain=True, cls=ClickDocOptGroup)
20
18
  def pipeline():
21
19
  """Pipeline commands."""
22
- check_platform_helper_version_needs_update()
20
+ PlatformHelperVersioning().check_if_needs_update()
23
21
 
24
22
 
25
23
  @pipeline.command()
@@ -6,15 +6,13 @@ import click
6
6
  from botocore.exceptions import ClientError
7
7
  from cloudfoundry_client.client import CloudFoundryClient
8
8
 
9
+ from dbt_platform_helper.domain.versioning import PlatformHelperVersioning
9
10
  from dbt_platform_helper.utils.application import get_application_name
10
11
  from dbt_platform_helper.utils.aws import SSM_BASE_PATH
11
12
  from dbt_platform_helper.utils.aws import get_aws_session_or_abort
12
13
  from dbt_platform_helper.utils.aws import get_ssm_secrets
13
14
  from dbt_platform_helper.utils.aws import set_ssm_param
14
15
  from dbt_platform_helper.utils.click import ClickDocOptGroup
15
- from dbt_platform_helper.utils.versioning import (
16
- check_platform_helper_version_needs_update,
17
- )
18
16
 
19
17
 
20
18
  def secret_should_be_skipped(secret_name):
@@ -42,7 +40,7 @@ def get_paas_env_vars(client: CloudFoundryClient, paas: str) -> dict:
42
40
 
43
41
  @click.group(chain=True, cls=ClickDocOptGroup)
44
42
  def secrets():
45
- check_platform_helper_version_needs_update()
43
+ PlatformHelperVersioning().check_if_needs_update()
46
44
 
47
45
 
48
46
  @secrets.command()
@@ -1,9 +1,9 @@
1
1
  import click
2
2
 
3
+ from dbt_platform_helper.domain.versioning import PlatformHelperVersioning
3
4
  from dbt_platform_helper.platform_exception import PlatformException
4
5
  from dbt_platform_helper.providers.io import ClickIOProvider
5
6
  from dbt_platform_helper.utils.click import ClickDocOptGroup
6
- from dbt_platform_helper.utils.versioning import RequiredVersion
7
7
 
8
8
 
9
9
  @click.group(chain=True, cls=ClickDocOptGroup)
@@ -32,6 +32,6 @@ def get_platform_helper_for_project(pipeline):
32
32
  - Fall back on the version in the deprecated '.platform-helper-version' file
33
33
  """
34
34
  try:
35
- RequiredVersion().get_required_version(pipeline)
35
+ PlatformHelperVersioning().get_required_version(pipeline)
36
36
  except PlatformException as err:
37
37
  ClickIOProvider().abort_with_error(str(err))
@@ -12,12 +12,16 @@ from dbt_platform_helper.platform_exception import PlatformException
12
12
  from dbt_platform_helper.providers.files import FileProvider
13
13
  from dbt_platform_helper.providers.io import ClickIOProvider
14
14
  from dbt_platform_helper.utils.application import Application
15
- from dbt_platform_helper.utils.application import ApplicationException
15
+ from dbt_platform_helper.utils.application import (
16
+ ApplicationEnvironmentNotFoundException,
17
+ )
16
18
  from dbt_platform_helper.utils.application import load_application
17
19
  from dbt_platform_helper.utils.aws import check_image_exists
18
20
  from dbt_platform_helper.utils.aws import get_aws_session_or_abort
19
21
  from dbt_platform_helper.utils.aws import get_build_url_from_arn
20
22
  from dbt_platform_helper.utils.aws import get_build_url_from_pipeline_execution_id
23
+ from dbt_platform_helper.utils.aws import get_image_build_project
24
+ from dbt_platform_helper.utils.aws import get_manual_release_pipeline
21
25
  from dbt_platform_helper.utils.aws import list_latest_images
22
26
  from dbt_platform_helper.utils.aws import start_build_extraction
23
27
  from dbt_platform_helper.utils.aws import start_pipeline_and_return_execution_id
@@ -32,6 +36,8 @@ class Codebase:
32
36
  load_application: Callable[[str], Application] = load_application,
33
37
  get_aws_session_or_abort: Callable[[str], Session] = get_aws_session_or_abort,
34
38
  check_image_exists: Callable[[str], str] = check_image_exists,
39
+ get_image_build_project: Callable[[str], str] = get_image_build_project,
40
+ get_manual_release_pipeline: Callable[[str], str] = get_manual_release_pipeline,
35
41
  get_build_url_from_arn: Callable[[str], str] = get_build_url_from_arn,
36
42
  get_build_url_from_pipeline_execution_id: Callable[
37
43
  [str], str
@@ -48,6 +54,8 @@ class Codebase:
48
54
  self.load_application = load_application
49
55
  self.get_aws_session_or_abort = get_aws_session_or_abort
50
56
  self.check_image_exists = check_image_exists
57
+ self.get_image_build_project = get_image_build_project
58
+ self.get_manual_release_pipeline = get_manual_release_pipeline
51
59
  self.get_build_url_from_arn = get_build_url_from_arn
52
60
  self.get_build_url_from_pipeline_execution_id = get_build_url_from_pipeline_execution_id
53
61
  self.list_latest_images = list_latest_images
@@ -124,12 +132,13 @@ class Codebase:
124
132
  self.check_if_commit_exists(commit)
125
133
 
126
134
  codebuild_client = session.client("codebuild")
135
+ project_name = self.get_image_build_project(codebuild_client, app, codebase)
127
136
  build_url = self.__start_build_with_confirmation(
128
137
  codebuild_client,
129
138
  self.get_build_url_from_arn,
130
139
  f'You are about to build "{app}" for "{codebase}" with commit "{commit}". Do you want to continue?',
131
140
  {
132
- "projectName": f"{app}-{codebase}-codebase-pipeline-image-build",
141
+ "projectName": project_name,
133
142
  "artifactsOverride": {"type": "NO_ARTIFACTS"},
134
143
  "sourceVersion": commit,
135
144
  },
@@ -148,13 +157,14 @@ class Codebase:
148
157
 
149
158
  application = self.load_application(app, default_session=session)
150
159
  if not application.environments.get(env):
151
- raise ApplicationEnvironmentNotFoundException(env)
160
+ raise ApplicationEnvironmentNotFoundException(application.name, env)
152
161
 
153
162
  self.check_image_exists(session, application, codebase, commit)
154
163
 
155
- pipeline_name = f"{app}-{codebase}-manual-release-pipeline"
156
164
  codepipeline_client = session.client("codepipeline")
157
165
 
166
+ pipeline_name = self.get_manual_release_pipeline(codepipeline_client, app, codebase)
167
+
158
168
  build_url = self.__start_pipeline_execution_with_confirmation(
159
169
  codepipeline_client,
160
170
  self.get_build_url_from_pipeline_execution_id,
@@ -242,13 +252,6 @@ class ApplicationDeploymentNotTriggered(PlatformException):
242
252
  super().__init__(f"""Your deployment for {codebase} was not triggered.""")
243
253
 
244
254
 
245
- class ApplicationEnvironmentNotFoundException(ApplicationException):
246
- def __init__(self, environment: str):
247
- super().__init__(
248
- f"""The environment "{environment}" either does not exist or has not been deployed."""
249
- )
250
-
251
-
252
255
  class NotInCodeBaseRepositoryException(PlatformException):
253
256
  def __init__(self):
254
257
  super().__init__(
@@ -0,0 +1,397 @@
1
+ #!/usr/bin/env python
2
+
3
+ import copy
4
+ import json
5
+ from pathlib import Path
6
+ from pathlib import PosixPath
7
+
8
+ import click
9
+ import yaml
10
+ from schema import SchemaError
11
+
12
+ from dbt_platform_helper.constants import PLATFORM_CONFIG_FILE
13
+ from dbt_platform_helper.domain.copilot_environment import CopilotTemplating
14
+ from dbt_platform_helper.providers.config import ConfigProvider
15
+ from dbt_platform_helper.providers.files import FileProvider
16
+ from dbt_platform_helper.providers.kms import KMSProvider
17
+ from dbt_platform_helper.utils.application import get_application_name
18
+ from dbt_platform_helper.utils.application import load_application
19
+ from dbt_platform_helper.utils.aws import get_aws_session_or_abort
20
+ from dbt_platform_helper.utils.files import generate_override_files
21
+ from dbt_platform_helper.utils.template import ADDON_TEMPLATE_MAP
22
+ from dbt_platform_helper.utils.template import camel_case
23
+ from dbt_platform_helper.utils.template import setup_templates
24
+ from dbt_platform_helper.utils.validation import validate_addons
25
+
26
+
27
+ class Copilot:
28
+
29
+ PACKAGE_DIR = Path(__file__).resolve().parent.parent
30
+
31
+ # TODO Remove and test
32
+ WAF_ACL_ARN_KEY = "waf-acl-arn"
33
+
34
+ SERVICE_TYPES = [
35
+ "Load Balanced Web Service",
36
+ "Backend Service",
37
+ "Request-Driven Web Service",
38
+ "Static Site",
39
+ "Worker Service",
40
+ ]
41
+
42
+ def __init__(
43
+ self,
44
+ config_provider: ConfigProvider,
45
+ file_provider: FileProvider,
46
+ copilot_templating: CopilotTemplating,
47
+ kms_provider: KMSProvider,
48
+ ):
49
+ self.config_provider = config_provider
50
+ self.file_provider = file_provider
51
+ self.copilot_templating = copilot_templating
52
+ self.kms_provider = kms_provider
53
+
54
+ def list_copilot_local_environments(self):
55
+ return [
56
+ path.parent.parts[-1] for path in Path("./copilot/environments/").glob("*/manifest.yml")
57
+ ]
58
+
59
+ def is_service(self, path: PosixPath) -> bool:
60
+ with open(path) as manifest_file:
61
+ data = yaml.safe_load(manifest_file)
62
+ if not data or not data.get("type"):
63
+ click.echo(
64
+ click.style(f"No type defined in manifest file {str(path)}; exiting", fg="red")
65
+ )
66
+ exit(1)
67
+
68
+ return data.get("type") in self.SERVICE_TYPES
69
+
70
+ def list_copilot_local_services(self):
71
+ return [
72
+ path.parent.parts[-1]
73
+ for path in Path("./copilot/").glob("*/manifest.yml")
74
+ if self.is_service(path)
75
+ ]
76
+
77
+ def _validate_and_normalise_extensions_config(self, config_file, key_in_config_file=None):
78
+ """Load a config file, validate it against the extensions schemas and
79
+ return the normalised config dict."""
80
+
81
+ def _lookup_plan(addon_type, env_conf):
82
+ plan = env_conf.pop("plan", None)
83
+ conf = addon_plans[addon_type][plan] if plan else {}
84
+
85
+ # Make a copy of the addon plan config so subsequent
86
+ # calls do not override the root object
87
+ conf = conf.copy()
88
+
89
+ conf.update(env_conf)
90
+
91
+ return conf
92
+
93
+ def _normalise_keys(source: dict):
94
+ return {k.replace("-", "_"): v for k, v in source.items()}
95
+
96
+ with open(self.PACKAGE_DIR / "addon-plans.yml", "r") as fd:
97
+ addon_plans = yaml.safe_load(fd)
98
+
99
+ # load and validate config
100
+ with open(config_file, "r") as fd:
101
+ config = yaml.safe_load(fd)
102
+
103
+ if config and key_in_config_file:
104
+ config = config[key_in_config_file]
105
+
106
+ # empty file
107
+ if not config:
108
+ return {}
109
+
110
+ errors = validate_addons(config)
111
+
112
+ if errors:
113
+ click.echo(click.style(f"Errors found in {config_file}:", fg="red"))
114
+ for addon, error in errors.items():
115
+ click.echo(click.style(f"Addon '{addon}': {error}", fg="red"))
116
+ exit(1)
117
+
118
+ env_names = self.list_copilot_local_environments()
119
+ svc_names = self.list_copilot_local_services()
120
+
121
+ if not env_names:
122
+ click.echo(
123
+ click.style(f"No environments found in ./copilot/environments; exiting", fg="red")
124
+ )
125
+ exit(1)
126
+
127
+ if not svc_names:
128
+ click.echo(click.style(f"No services found in ./copilot/; exiting", fg="red"))
129
+ exit(1)
130
+
131
+ normalised_config = {}
132
+ config_has_errors = False
133
+ for addon_name, addon_config in config.items():
134
+ addon_type = addon_config["type"]
135
+ normalised_config[addon_name] = copy.deepcopy(addon_config)
136
+
137
+ if "services" in normalised_config[addon_name]:
138
+ if normalised_config[addon_name]["services"] == "__all__":
139
+ normalised_config[addon_name]["services"] = svc_names
140
+
141
+ if not set(normalised_config[addon_name]["services"]).issubset(set(svc_names)):
142
+ click.echo(
143
+ click.style(
144
+ f"Services listed in {addon_name}.services do not exist in ./copilot/",
145
+ fg="red",
146
+ ),
147
+ )
148
+ config_has_errors = True
149
+
150
+ environments = normalised_config[addon_name].pop("environments", {})
151
+ default = environments.pop("*", environments.pop("default", {}))
152
+
153
+ initial = _lookup_plan(addon_type, default)
154
+
155
+ missing_envs = set(environments.keys()) - set(env_names)
156
+ if missing_envs:
157
+ click.echo(
158
+ click.style(
159
+ f"Environment keys listed in {addon_name} do not match those defined in ./copilot/environments.",
160
+ fg="red",
161
+ )
162
+ ),
163
+ click.echo(
164
+ click.style(
165
+ f" Missing environments: {', '.join(sorted(missing_envs))}",
166
+ fg="white",
167
+ ),
168
+ )
169
+ config_has_errors = True
170
+
171
+ if config_has_errors:
172
+ continue
173
+
174
+ normalised_environments = {}
175
+
176
+ for env in env_names:
177
+ normalised_environments[env] = _normalise_keys(initial)
178
+
179
+ for env_name, env_config in environments.items():
180
+ if env_config is None:
181
+ env_config = {}
182
+ normalised_environments[env_name].update(
183
+ _lookup_plan(addon_type, _normalise_keys(env_config))
184
+ )
185
+
186
+ normalised_config[addon_name]["environments"] = normalised_environments
187
+
188
+ if config_has_errors:
189
+ exit(1)
190
+
191
+ return normalised_config
192
+
193
+ def get_log_destination_arn(self):
194
+ """Get destination arns stored in param store in projects aws
195
+ account."""
196
+ session = get_aws_session_or_abort()
197
+ client = session.client("ssm", region_name="eu-west-2")
198
+ response = client.get_parameters(Names=["/copilot/tools/central_log_groups"])
199
+
200
+ if not response["Parameters"]:
201
+ click.echo(
202
+ click.style(
203
+ "No aws central log group defined in Parameter Store at location /copilot/tools/central_log_groups; exiting",
204
+ fg="red",
205
+ )
206
+ )
207
+ exit(1)
208
+
209
+ destination_arns = json.loads(response["Parameters"][0]["Value"])
210
+ return destination_arns
211
+
212
+ def _generate_svc_overrides(self, base_path, templates, name):
213
+ click.echo(f"\n>>> Generating service overrides for {name}\n")
214
+ overrides_path = base_path.joinpath(f"copilot/{name}/overrides")
215
+ overrides_path.mkdir(parents=True, exist_ok=True)
216
+ overrides_file = overrides_path.joinpath("cfn.patches.yml")
217
+ overrides_file.write_text(templates.get_template("svc/overrides/cfn.patches.yml").render())
218
+
219
+ def _get_s3_kms_alias_arns(self, session, application_name, config):
220
+ application = load_application(application_name, session)
221
+ arns = {}
222
+
223
+ for environment_name in application.environments:
224
+ if environment_name not in config:
225
+ continue
226
+
227
+ if "bucket_name" not in config[environment_name]:
228
+ continue
229
+
230
+ bucket_name = config[environment_name]["bucket_name"]
231
+ kms_client = application.environments[environment_name].session.client("kms")
232
+ alias_name = f"alias/{application_name}-{environment_name}-{bucket_name}-key"
233
+
234
+ try:
235
+ response = kms_client.describe_key(KeyId=alias_name)
236
+ except kms_client.exceptions.NotFoundException:
237
+ pass
238
+ else:
239
+ arns[environment_name] = response["KeyMetadata"]["Arn"]
240
+
241
+ return arns
242
+
243
+ def make_addons(self):
244
+ self.config_provider.config_file_check()
245
+ try:
246
+ config = self.config_provider.load_and_validate_platform_config()
247
+ except SchemaError as ex:
248
+ click.secho(f"Invalid `{PLATFORM_CONFIG_FILE}` file: {str(ex)}", fg="red")
249
+ raise click.Abort
250
+
251
+ templates = setup_templates()
252
+ extensions = self._get_extensions()
253
+ session = get_aws_session_or_abort()
254
+
255
+ application_name = get_application_name()
256
+
257
+ click.echo("\n>>> Generating Terraform compatible addons CloudFormation\n")
258
+
259
+ output_dir = Path(".").absolute()
260
+ env_path = Path(f"copilot/environments/")
261
+ env_addons_path = env_path / "addons"
262
+ env_overrides_path = env_path / "overrides"
263
+
264
+ self._cleanup_old_files(extensions, output_dir, env_addons_path, env_overrides_path)
265
+ self._generate_env_overrides(output_dir)
266
+
267
+ svc_names = self.list_copilot_local_services()
268
+ base_path = Path(".")
269
+ for svc_name in svc_names:
270
+ self._generate_svc_overrides(base_path, templates, svc_name)
271
+
272
+ services = []
273
+ for ext_name, ext_data in extensions.items():
274
+ extension = {**ext_data}
275
+ addon_type = extension.pop("type")
276
+ environments = extension.pop("environments")
277
+ environment_addon_config = {
278
+ "addon_type": addon_type,
279
+ "environments": environments,
280
+ "name": extension.get("name", None) or ext_name,
281
+ "prefix": camel_case(ext_name),
282
+ "secret_name": ext_name.upper().replace("-", "_"),
283
+ **extension,
284
+ }
285
+
286
+ services.append(environment_addon_config)
287
+
288
+ service_addon_config = {
289
+ "application_name": application_name,
290
+ "name": extension.get("name", None) or ext_name,
291
+ "prefix": camel_case(ext_name),
292
+ "environments": environments,
293
+ **extension,
294
+ }
295
+
296
+ log_destination_arns = self.get_log_destination_arn()
297
+
298
+ if addon_type in ["s3", "s3-policy"]:
299
+ if extensions[ext_name].get("serve_static_content"):
300
+ continue
301
+
302
+ s3_kms_arns = self._get_s3_kms_alias_arns(session, application_name, environments)
303
+ for environment_name in environments:
304
+ environments[environment_name]["kms_key_arn"] = s3_kms_arns.get(
305
+ environment_name, "kms-key-not-found"
306
+ )
307
+
308
+ self._generate_service_addons(
309
+ extension,
310
+ ext_name,
311
+ addon_type,
312
+ output_dir,
313
+ service_addon_config,
314
+ templates,
315
+ log_destination_arns,
316
+ )
317
+
318
+ environments = self.config_provider.apply_environment_defaults(config)["environments"]
319
+
320
+ self.copilot_templating.generate_cross_account_s3_policies(environments, extensions)
321
+
322
+ click.echo(templates.get_template("addon-instructions.txt").render(services=services))
323
+
324
+ def _get_extensions(self):
325
+ config = self._validate_and_normalise_extensions_config(
326
+ self.PACKAGE_DIR / "default-extensions.yml"
327
+ )
328
+ project_config = self._validate_and_normalise_extensions_config(
329
+ PLATFORM_CONFIG_FILE, "extensions"
330
+ )
331
+ config.update(project_config)
332
+ return config
333
+
334
+ def _generate_env_overrides(self, output_dir):
335
+ path = "templates/env/terraform-overrides"
336
+ click.echo("\n>>> Generating Environment overrides\n")
337
+ overrides_path = output_dir.joinpath(f"copilot/environments/overrides")
338
+ overrides_path.mkdir(parents=True, exist_ok=True)
339
+ template_overrides_path = Path(__file__).parent.parent.joinpath(path)
340
+ generate_override_files(Path("."), template_overrides_path, overrides_path)
341
+
342
+ def _generate_service_addons(
343
+ self,
344
+ addon_config,
345
+ addon_name,
346
+ addon_type,
347
+ output_dir,
348
+ service_addon_config,
349
+ templates,
350
+ log_destination_arns,
351
+ ):
352
+ # generate svc addons
353
+ for addon_template in ADDON_TEMPLATE_MAP.get(addon_type, []):
354
+ template = templates.get_template(addon_template)
355
+
356
+ for svc in addon_config.get("services", []):
357
+ service_path = Path(f"copilot/{svc}/addons/")
358
+
359
+ contents = template.render(
360
+ {
361
+ "addon_config": service_addon_config,
362
+ "log_destination": log_destination_arns,
363
+ }
364
+ )
365
+
366
+ (output_dir / service_path).mkdir(parents=True, exist_ok=True)
367
+ click.echo(
368
+ self.file_provider.mkfile(
369
+ output_dir, service_path / f"{addon_name}.yml", contents, overwrite=True
370
+ )
371
+ )
372
+
373
+ def _cleanup_old_files(self, config, output_dir, env_addons_path, env_overrides_path):
374
+ def _rmdir(path):
375
+ if not path.exists():
376
+ return
377
+ for f in path.iterdir():
378
+ if f.is_file():
379
+ f.unlink()
380
+ if f.is_dir():
381
+ _rmdir(f)
382
+ f.rmdir()
383
+
384
+ _rmdir(output_dir / env_addons_path)
385
+ _rmdir(output_dir / env_overrides_path)
386
+
387
+ all_services = set()
388
+ for services in [v["services"] for v in config.values() if "services" in v]:
389
+ all_services.update(services)
390
+
391
+ for service in all_services:
392
+ svc_addons_dir = Path(output_dir, "copilot", service, "addons")
393
+ if not svc_addons_dir.exists():
394
+ continue
395
+ for f in svc_addons_dir.iterdir():
396
+ if f.is_file():
397
+ f.unlink()
@@ -10,9 +10,7 @@ from dbt_platform_helper.providers.cloudformation import CloudFormation
10
10
  from dbt_platform_helper.providers.config import ConfigProvider
11
11
  from dbt_platform_helper.providers.files import FileProvider
12
12
  from dbt_platform_helper.providers.io import ClickIOProvider
13
- from dbt_platform_helper.providers.load_balancers import (
14
- get_https_certificate_for_application,
15
- )
13
+ from dbt_platform_helper.providers.load_balancers import LoadBalancerProvider
16
14
  from dbt_platform_helper.providers.vpc import Vpc
17
15
  from dbt_platform_helper.providers.vpc import VpcNotFoundForNameException
18
16
  from dbt_platform_helper.providers.vpc import VpcProvider
@@ -27,9 +25,10 @@ class CopilotEnvironment:
27
25
  config_provider: ConfigProvider,
28
26
  vpc_provider: VpcProvider = None,
29
27
  cloudformation_provider: CloudFormation = None,
30
- session: Session = None, # TODO - this is a temporary fix, will fall away once the Loadbalancer provider is in place.
28
+ session: Session = None, # TODO - this is a temporary fix, will fall away once _get_environment_vpc is updated.
31
29
  copilot_templating=None,
32
30
  io: ClickIOProvider = ClickIOProvider(),
31
+ load_balancer_provider: LoadBalancerProvider = LoadBalancerProvider,
33
32
  ):
34
33
  self.config_provider = config_provider
35
34
  self.vpc_provider = vpc_provider
@@ -38,6 +37,7 @@ class CopilotEnvironment:
38
37
  )
39
38
  self.io = io
40
39
  self.session = session
40
+ self.load_balancer = load_balancer_provider(session)
41
41
  self.cloudformation_provider = cloudformation_provider
42
42
 
43
43
  def generate(self, environment_name: str) -> None:
@@ -56,8 +56,8 @@ class CopilotEnvironment:
56
56
 
57
57
  app_name = platform_config["application"]
58
58
 
59
- certificate_arn = get_https_certificate_for_application(
60
- self.session, app_name, environment_name
59
+ certificate_arn = self.load_balancer.get_https_certificate_for_application(
60
+ app_name, environment_name
61
61
  )
62
62
 
63
63
  vpc = self._get_environment_vpc(