dbt-platform-helper 13.1.0__py3-none-any.whl → 15.16.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.
Files changed (95) hide show
  1. dbt_platform_helper/COMMANDS.md +107 -27
  2. dbt_platform_helper/commands/application.py +5 -6
  3. dbt_platform_helper/commands/codebase.py +31 -10
  4. dbt_platform_helper/commands/conduit.py +3 -5
  5. dbt_platform_helper/commands/config.py +20 -311
  6. dbt_platform_helper/commands/copilot.py +18 -391
  7. dbt_platform_helper/commands/database.py +17 -9
  8. dbt_platform_helper/commands/environment.py +20 -14
  9. dbt_platform_helper/commands/generate.py +0 -3
  10. dbt_platform_helper/commands/internal.py +140 -0
  11. dbt_platform_helper/commands/notify.py +58 -78
  12. dbt_platform_helper/commands/pipeline.py +23 -19
  13. dbt_platform_helper/commands/secrets.py +39 -93
  14. dbt_platform_helper/commands/version.py +7 -12
  15. dbt_platform_helper/constants.py +52 -7
  16. dbt_platform_helper/domain/codebase.py +89 -39
  17. dbt_platform_helper/domain/conduit.py +335 -76
  18. dbt_platform_helper/domain/config.py +381 -0
  19. dbt_platform_helper/domain/copilot.py +398 -0
  20. dbt_platform_helper/domain/copilot_environment.py +8 -8
  21. dbt_platform_helper/domain/database_copy.py +2 -2
  22. dbt_platform_helper/domain/maintenance_page.py +254 -430
  23. dbt_platform_helper/domain/notify.py +64 -0
  24. dbt_platform_helper/domain/pipelines.py +43 -35
  25. dbt_platform_helper/domain/plans.py +41 -0
  26. dbt_platform_helper/domain/secrets.py +279 -0
  27. dbt_platform_helper/domain/service.py +570 -0
  28. dbt_platform_helper/domain/terraform_environment.py +14 -13
  29. dbt_platform_helper/domain/update_alb_rules.py +412 -0
  30. dbt_platform_helper/domain/versioning.py +249 -0
  31. dbt_platform_helper/{providers → entities}/platform_config_schema.py +75 -82
  32. dbt_platform_helper/entities/semantic_version.py +83 -0
  33. dbt_platform_helper/entities/service.py +339 -0
  34. dbt_platform_helper/platform_exception.py +4 -0
  35. dbt_platform_helper/providers/autoscaling.py +24 -0
  36. dbt_platform_helper/providers/aws/__init__.py +0 -0
  37. dbt_platform_helper/providers/aws/exceptions.py +70 -0
  38. dbt_platform_helper/providers/aws/interfaces.py +13 -0
  39. dbt_platform_helper/providers/aws/opensearch.py +23 -0
  40. dbt_platform_helper/providers/aws/redis.py +21 -0
  41. dbt_platform_helper/providers/aws/sso_auth.py +75 -0
  42. dbt_platform_helper/providers/cache.py +40 -4
  43. dbt_platform_helper/providers/cloudformation.py +1 -1
  44. dbt_platform_helper/providers/config.py +137 -19
  45. dbt_platform_helper/providers/config_validator.py +112 -51
  46. dbt_platform_helper/providers/copilot.py +24 -16
  47. dbt_platform_helper/providers/ecr.py +89 -7
  48. dbt_platform_helper/providers/ecs.py +228 -36
  49. dbt_platform_helper/providers/environment_variable.py +24 -0
  50. dbt_platform_helper/providers/files.py +1 -1
  51. dbt_platform_helper/providers/io.py +36 -4
  52. dbt_platform_helper/providers/kms.py +22 -0
  53. dbt_platform_helper/providers/load_balancers.py +402 -42
  54. dbt_platform_helper/providers/logs.py +72 -0
  55. dbt_platform_helper/providers/parameter_store.py +134 -0
  56. dbt_platform_helper/providers/s3.py +21 -0
  57. dbt_platform_helper/providers/schema_migrations/__init__.py +0 -0
  58. dbt_platform_helper/providers/schema_migrations/schema_v0_to_v1_migration.py +43 -0
  59. dbt_platform_helper/providers/schema_migrator.py +77 -0
  60. dbt_platform_helper/providers/secrets.py +5 -5
  61. dbt_platform_helper/providers/slack_channel_notifier.py +62 -0
  62. dbt_platform_helper/providers/terraform_manifest.py +121 -19
  63. dbt_platform_helper/providers/version.py +106 -23
  64. dbt_platform_helper/providers/version_status.py +27 -0
  65. dbt_platform_helper/providers/vpc.py +36 -5
  66. dbt_platform_helper/providers/yaml_file.py +58 -2
  67. dbt_platform_helper/templates/environment-pipelines/main.tf +4 -3
  68. dbt_platform_helper/templates/svc/overrides/cfn.patches.yml +5 -0
  69. dbt_platform_helper/utilities/decorators.py +103 -0
  70. dbt_platform_helper/utils/application.py +119 -22
  71. dbt_platform_helper/utils/aws.py +39 -150
  72. dbt_platform_helper/utils/deep_merge.py +10 -0
  73. dbt_platform_helper/utils/git.py +1 -14
  74. dbt_platform_helper/utils/validation.py +1 -1
  75. {dbt_platform_helper-13.1.0.dist-info → dbt_platform_helper-15.16.0.dist-info}/METADATA +11 -20
  76. dbt_platform_helper-15.16.0.dist-info/RECORD +118 -0
  77. {dbt_platform_helper-13.1.0.dist-info → dbt_platform_helper-15.16.0.dist-info}/WHEEL +1 -1
  78. platform_helper.py +3 -1
  79. terraform/elasticache-redis/plans.yml +85 -0
  80. terraform/opensearch/plans.yml +71 -0
  81. terraform/postgres/plans.yml +128 -0
  82. dbt_platform_helper/addon-plans.yml +0 -224
  83. dbt_platform_helper/providers/aws.py +0 -37
  84. dbt_platform_helper/providers/opensearch.py +0 -36
  85. dbt_platform_helper/providers/redis.py +0 -34
  86. dbt_platform_helper/providers/semantic_version.py +0 -126
  87. dbt_platform_helper/templates/svc/manifest-backend.yml +0 -69
  88. dbt_platform_helper/templates/svc/manifest-public.yml +0 -109
  89. dbt_platform_helper/utils/cloudfoundry.py +0 -14
  90. dbt_platform_helper/utils/files.py +0 -53
  91. dbt_platform_helper/utils/manifests.py +0 -18
  92. dbt_platform_helper/utils/versioning.py +0 -238
  93. dbt_platform_helper-13.1.0.dist-info/RECORD +0 -96
  94. {dbt_platform_helper-13.1.0.dist-info → dbt_platform_helper-15.16.0.dist-info}/entry_points.txt +0 -0
  95. {dbt_platform_helper-13.1.0.dist-info → dbt_platform_helper-15.16.0.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,398 @@
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 botocore
9
+ import botocore.errorfactory
10
+
11
+ from dbt_platform_helper.constants import PLATFORM_CONFIG_FILE
12
+ from dbt_platform_helper.domain.copilot_environment import CopilotTemplating
13
+ from dbt_platform_helper.domain.plans import PlanLoader
14
+ from dbt_platform_helper.providers.config import ConfigProvider
15
+ from dbt_platform_helper.providers.files import FileProvider
16
+ from dbt_platform_helper.providers.io import ClickIOProvider
17
+ from dbt_platform_helper.providers.kms import KMSProvider
18
+ from dbt_platform_helper.providers.parameter_store import ParameterStore
19
+ from dbt_platform_helper.providers.yaml_file import YamlFileProvider
20
+ from dbt_platform_helper.utils.application import get_application_name
21
+ from dbt_platform_helper.utils.application import load_application
22
+ from dbt_platform_helper.utils.template import ADDON_TEMPLATE_MAP
23
+ from dbt_platform_helper.utils.template import camel_case
24
+ from dbt_platform_helper.utils.template import setup_templates
25
+ from dbt_platform_helper.utils.validation import validate_addons
26
+
27
+
28
+ class Copilot:
29
+
30
+ PACKAGE_DIR = Path(__file__).resolve().parent.parent
31
+
32
+ SERVICE_TYPES = [
33
+ "Load Balanced Web Service",
34
+ "Backend Service",
35
+ "Request-Driven Web Service",
36
+ "Static Site",
37
+ "Worker Service",
38
+ ]
39
+
40
+ def __init__(
41
+ self,
42
+ config_provider: ConfigProvider,
43
+ parameter_provider: ParameterStore,
44
+ file_provider: FileProvider,
45
+ copilot_templating: CopilotTemplating,
46
+ kms_provider: KMSProvider,
47
+ session,
48
+ io: ClickIOProvider = ClickIOProvider(),
49
+ plan_manager: PlanLoader = PlanLoader(),
50
+ yaml_file_provider: YamlFileProvider = YamlFileProvider,
51
+ ):
52
+ self.config_provider = config_provider
53
+ self.parameter_provider = parameter_provider
54
+ self.file_provider = file_provider
55
+ self.copilot_templating = copilot_templating
56
+ self.kms_provider = kms_provider
57
+ self.io = io
58
+ self.plan_manager = plan_manager
59
+ self.yaml_file_provider = yaml_file_provider
60
+ self.session = session
61
+
62
+ def make_addons(self):
63
+ config = self.config_provider.load_and_validate_platform_config()
64
+
65
+ templates = setup_templates()
66
+ extensions = self._get_extensions()
67
+ application_name = get_application_name()
68
+
69
+ self.io.info("\n>>> Generating Terraform compatible addons CloudFormation\n")
70
+
71
+ output_dir = Path(".").absolute()
72
+ env_path = Path(f"copilot/environments/")
73
+ env_addons_path = env_path / "addons"
74
+ env_overrides_path = env_path / "overrides"
75
+
76
+ self._cleanup_old_files(extensions, output_dir, env_addons_path, env_overrides_path)
77
+ self._generate_env_overrides(output_dir)
78
+
79
+ svc_names = self._list_copilot_local_services()
80
+ base_path = Path(".")
81
+ for svc_name in svc_names:
82
+ self._generate_svc_overrides(base_path, templates, svc_name)
83
+
84
+ services = []
85
+ for ext_name, ext_data in extensions.items():
86
+ extension = {**ext_data}
87
+ addon_type = extension.pop("type")
88
+ environments = extension.pop("environments")
89
+ environment_addon_config = {
90
+ "addon_type": addon_type,
91
+ "environments": environments,
92
+ "name": extension.get("name", None) or ext_name,
93
+ "prefix": camel_case(ext_name),
94
+ "secret_name": ext_name.upper().replace("-", "_"),
95
+ **extension,
96
+ }
97
+
98
+ services.append(environment_addon_config)
99
+
100
+ service_addon_config = {
101
+ "application_name": application_name,
102
+ "name": extension.get("name", None) or ext_name,
103
+ "prefix": camel_case(ext_name),
104
+ "environments": environments,
105
+ **extension,
106
+ }
107
+
108
+ log_destination_arns = self._get_log_destination_arn()
109
+
110
+ if addon_type in ["s3", "s3-policy"]:
111
+ if extensions[ext_name].get("serve_static_content"):
112
+ continue
113
+
114
+ s3_kms_arns = self._get_s3_kms_alias_arns(application_name, environments)
115
+ for environment_name in environments:
116
+ environments[environment_name]["kms_key_arn"] = s3_kms_arns.get(
117
+ environment_name, "kms-key-not-found"
118
+ )
119
+
120
+ self._generate_service_addons(
121
+ extension,
122
+ ext_name,
123
+ addon_type,
124
+ output_dir,
125
+ service_addon_config,
126
+ templates,
127
+ log_destination_arns,
128
+ )
129
+
130
+ environments = self.config_provider.apply_environment_defaults(config)["environments"]
131
+
132
+ self.copilot_templating.generate_cross_account_s3_policies(environments, extensions)
133
+
134
+ self.io.info(templates.get_template("addon-instructions.txt").render(services=services))
135
+
136
+ def _list_copilot_local_environments(self):
137
+ return [
138
+ path.parent.parts[-1] for path in Path("./copilot/environments/").glob("*/manifest.yml")
139
+ ]
140
+
141
+ def _is_service(self, path: PosixPath) -> bool:
142
+
143
+ manifest_file = self.yaml_file_provider.load(path)
144
+ if not manifest_file or not manifest_file.get("type"):
145
+ self.io.abort_with_error(f"No type defined in manifest file {str(path)}; exiting")
146
+
147
+ return manifest_file.get("type") in self.SERVICE_TYPES
148
+
149
+ def _list_copilot_local_services(self):
150
+ return [
151
+ path.parent.parts[-1]
152
+ for path in Path("./copilot/").glob("*/manifest.yml")
153
+ if self._is_service(path)
154
+ ]
155
+
156
+ def _validate_and_normalise_extensions_config(self, config_file, key_in_config_file=None):
157
+ """Load a config file, validate it against the extensions schemas and
158
+ return the normalised config dict."""
159
+
160
+ def _lookup_plan(addon_type, env_conf):
161
+ plan = env_conf.pop("plan", None)
162
+ conf = addon_plans[addon_type][plan] if plan else {}
163
+
164
+ # Make a copy of the addon plan config so subsequent
165
+ # calls do not override the root object
166
+ conf = conf.copy()
167
+
168
+ conf.update(env_conf)
169
+
170
+ return conf
171
+
172
+ def _normalise_keys(source: dict):
173
+ return {k.replace("-", "_"): v for k, v in source.items()}
174
+
175
+ addon_plans = self.plan_manager.load()
176
+
177
+ # load and validate config
178
+ config = self.yaml_file_provider.load(config_file)
179
+
180
+ if config and key_in_config_file:
181
+ config = config[key_in_config_file]
182
+
183
+ # empty file
184
+ if not config:
185
+ return {}
186
+
187
+ errors = validate_addons(config)
188
+
189
+ if errors:
190
+ self.io.error(f"Errors found in {config_file}:")
191
+ for addon, error in errors.items():
192
+ self.io.error(f"Addon '{addon}': {error}")
193
+ self.io.abort_with_error("Invalid platform-config.yml provided, see above warnings")
194
+
195
+ env_names = self._list_copilot_local_environments()
196
+ svc_names = self._list_copilot_local_services()
197
+
198
+ if not env_names:
199
+ self.io.abort_with_error("No environments found in ./copilot/environments; exiting")
200
+
201
+ if not svc_names:
202
+ self.io.abort_with_error("No services found in ./copilot/; exiting")
203
+
204
+ normalised_config = {}
205
+ config_has_errors = False
206
+ for addon_name, addon_config in config.items():
207
+ addon_type = addon_config["type"]
208
+ normalised_config[addon_name] = copy.deepcopy(addon_config)
209
+
210
+ if "services" in normalised_config[addon_name]:
211
+ if normalised_config[addon_name]["services"] == "__all__":
212
+ normalised_config[addon_name]["services"] = svc_names
213
+
214
+ if not set(normalised_config[addon_name]["services"]).issubset(set(svc_names)):
215
+ self.io.error(
216
+ f"Services listed in {addon_name}.services do not exist in ./copilot/"
217
+ )
218
+ config_has_errors = True
219
+
220
+ environments = normalised_config[addon_name].pop("environments", {})
221
+ default = environments.pop("*", environments.pop("default", {}))
222
+
223
+ initial = _lookup_plan(addon_type, default)
224
+
225
+ missing_envs = set(environments.keys()) - set(env_names)
226
+ if missing_envs:
227
+ self.io.error(
228
+ f"Environment keys listed in {addon_name} do not match those defined in ./copilot/environments"
229
+ )
230
+ self.io.error(f" Missing environments: {', '.join(sorted(missing_envs))}")
231
+ config_has_errors = True
232
+
233
+ if config_has_errors:
234
+ continue
235
+
236
+ normalised_environments = {}
237
+
238
+ for env in env_names:
239
+ normalised_environments[env] = _normalise_keys(initial)
240
+
241
+ for env_name, env_config in environments.items():
242
+ if env_config is None:
243
+ env_config = {}
244
+ normalised_environments[env_name].update(
245
+ _lookup_plan(addon_type, _normalise_keys(env_config))
246
+ )
247
+
248
+ normalised_config[addon_name]["environments"] = normalised_environments
249
+
250
+ if config_has_errors:
251
+ self.io.abort_with_error("Configuration has errors. Exiting.")
252
+
253
+ return normalised_config
254
+
255
+ def _get_log_destination_arn(self):
256
+ """Get destination arns stored in param store in projects aws
257
+ account."""
258
+
259
+ try:
260
+ destination_arns = self.parameter_provider.get_ssm_parameter_by_name(
261
+ "/copilot/tools/central_log_groups"
262
+ )
263
+ except botocore.errorfactory.ParameterNotFound:
264
+ self.io.abort_with_error(
265
+ "No aws central log group defined in Parameter Store at location /copilot/tools/central_log_groups; exiting"
266
+ )
267
+
268
+ return json.loads(destination_arns["Value"])
269
+
270
+ def _generate_svc_overrides(self, base_path, templates, name):
271
+ self.io.info(f"\n>>> Generating service overrides for {name}\n")
272
+ overrides_path = base_path.joinpath(f"copilot/{name}/overrides")
273
+ overrides_path.mkdir(parents=True, exist_ok=True)
274
+ overrides_file = overrides_path.joinpath("cfn.patches.yml")
275
+ overrides_file.write_text(templates.get_template("svc/overrides/cfn.patches.yml").render())
276
+
277
+ def _get_s3_kms_alias_arns(self, application_name, config):
278
+ application = load_application(application_name, self.session)
279
+ arns = {}
280
+
281
+ for environment_name in application.environments:
282
+ kms_provider = self.kms_provider(
283
+ application.environments[environment_name].session.client("kms")
284
+ )
285
+
286
+ if environment_name not in config:
287
+ continue
288
+
289
+ if "bucket_name" not in config[environment_name]:
290
+ continue
291
+
292
+ bucket_name = config[environment_name]["bucket_name"]
293
+ alias_name = f"alias/{application_name}-{environment_name}-{bucket_name}-key"
294
+
295
+ try:
296
+ response = kms_provider.describe_key(alias_name)
297
+
298
+ # Boto3 classifies all AWS service errors and exceptions as ClientError exceptions
299
+ except botocore.exceptions.ClientError as error:
300
+ if error.response["Error"]["Code"] == "NotFoundException":
301
+ pass
302
+ else:
303
+ arns[environment_name] = response["KeyMetadata"]["Arn"]
304
+
305
+ return arns
306
+
307
+ def _get_extensions(self):
308
+ config = self._validate_and_normalise_extensions_config(
309
+ self.PACKAGE_DIR / "default-extensions.yml"
310
+ )
311
+ project_config = self._validate_and_normalise_extensions_config(
312
+ PLATFORM_CONFIG_FILE, "extensions"
313
+ )
314
+ config.update(project_config)
315
+ return config
316
+
317
+ def _generate_override_files(self, base_path, file_path, output_dir):
318
+ def generate_files_for_dir(pattern):
319
+ for file in file_path.glob(pattern):
320
+ if file.is_file():
321
+ contents = file.read_text()
322
+ file_name = str(file).removeprefix(f"{file_path}/")
323
+ self.io.info(
324
+ self.file_provider.mkfile(
325
+ base_path,
326
+ output_dir / file_name,
327
+ contents,
328
+ overwrite=True,
329
+ )
330
+ )
331
+
332
+ generate_files_for_dir("*")
333
+ generate_files_for_dir("bin/*")
334
+
335
+ def _generate_env_overrides(self, output_dir):
336
+ path = "templates/env/terraform-overrides"
337
+ self.io.info("\n>>> Generating Environment overrides\n")
338
+ overrides_path = output_dir.joinpath(f"copilot/environments/overrides")
339
+ overrides_path.mkdir(parents=True, exist_ok=True)
340
+ template_overrides_path = Path(__file__).parent.parent.joinpath(path)
341
+ self._generate_override_files(Path("."), template_overrides_path, overrides_path)
342
+
343
+ def _generate_service_addons(
344
+ self,
345
+ addon_config,
346
+ addon_name,
347
+ addon_type,
348
+ output_dir,
349
+ service_addon_config,
350
+ templates,
351
+ log_destination_arns,
352
+ ):
353
+ # generate svc addons
354
+ for addon_template in ADDON_TEMPLATE_MAP.get(addon_type, []):
355
+ template = templates.get_template(addon_template)
356
+
357
+ for svc in addon_config.get("services", []):
358
+ service_path = Path(f"copilot/{svc}/addons/")
359
+
360
+ contents = template.render(
361
+ {
362
+ "addon_config": service_addon_config,
363
+ "log_destination": log_destination_arns,
364
+ }
365
+ )
366
+
367
+ (output_dir / service_path).mkdir(parents=True, exist_ok=True)
368
+ self.io.info(
369
+ self.file_provider.mkfile(
370
+ output_dir, service_path / f"{addon_name}.yml", contents, overwrite=True
371
+ )
372
+ )
373
+
374
+ def _cleanup_old_files(self, config, output_dir, env_addons_path, env_overrides_path):
375
+ def _rmdir(path):
376
+ if not path.exists():
377
+ return
378
+ for f in path.iterdir():
379
+ if f.is_file():
380
+ f.unlink()
381
+ if f.is_dir():
382
+ _rmdir(f)
383
+ f.rmdir()
384
+
385
+ _rmdir(output_dir / env_addons_path)
386
+ _rmdir(output_dir / env_overrides_path)
387
+
388
+ all_services = set()
389
+ for services in [v["services"] for v in config.values() if "services" in v]:
390
+ all_services.update(services)
391
+
392
+ for service in all_services:
393
+ svc_addons_dir = Path(output_dir, "copilot", service, "addons")
394
+ if not svc_addons_dir.exists():
395
+ continue
396
+ for f in svc_addons_dir.iterdir():
397
+ if f.is_file():
398
+ 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: DBTP-1954: - 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(
@@ -77,7 +77,7 @@ class CopilotEnvironment:
77
77
  )
78
78
  )
79
79
 
80
- # TODO: There should always be a vpc_name as defaults have been applied to the config. This function can
80
+ # TODO: DBTP-1954: There should always be a vpc_name as defaults have been applied to the config. This function can
81
81
  # probably fall away. We shouldn't need to check 3 different names (vpc_name, session.profile_name, {session.profile_name}-{env_name})
82
82
  # To be checked.
83
83
  def _get_environment_vpc(self, session: Session, app_name, env_name: str, vpc_name: str) -> Vpc:
@@ -134,7 +134,7 @@ class CopilotTemplating:
134
134
  self,
135
135
  file_provider: FileProvider = FileProvider(),
136
136
  io: ClickIOProvider = ClickIOProvider(),
137
- # TODO file_provider can be moved up a layer. File writing can be the responsibility of CopilotEnvironment generate
137
+ # TODO: DBTP-1958: file_provider can be moved up a layer. File writing can be the responsibility of CopilotEnvironment generate
138
138
  # Or we align with PlatformTerraformManifestGenerator and rename from Templating to reflect the file writing responsibility
139
139
  ):
140
140
  self.file_provider = file_provider
@@ -28,7 +28,7 @@ class DatabaseCopy:
28
28
  database: str,
29
29
  auto_approve: bool = False,
30
30
  load_application: Callable[[str], Application] = load_application,
31
- # TODO We inject VpcProvider as a callable here so that it can be instantiated within the method. To be improved
31
+ # TODO: DBTP-1960: We inject VpcProvider as a callable here so that it can be instantiated within the method. To be improved
32
32
  vpc_provider: Callable[[Session], VpcProvider] = VpcProvider,
33
33
  db_connection_string: Callable[
34
34
  [Session, str, str, str, Callable], str
@@ -68,7 +68,7 @@ class DatabaseCopy:
68
68
  environment = environments.get(env)
69
69
  if not environment:
70
70
  self.io.abort_with_error(
71
- f"No such environment '{env}'. Available environments are: {', '.join(environments.keys())}"
71
+ f"Environment '{env}' cannot be found in your account configuration in parameter store. Available environments are: {', '.join(environments.keys())}. Please check that the Terraform infrastructure for your environment is up to date."
72
72
  )
73
73
 
74
74
  env_session = environment.session