dbt-platform-helper 13.1.2__py3-none-any.whl → 13.3.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.
- dbt_platform_helper/commands/application.py +2 -4
- dbt_platform_helper/commands/codebase.py +11 -7
- dbt_platform_helper/commands/conduit.py +1 -3
- dbt_platform_helper/commands/config.py +12 -314
- dbt_platform_helper/commands/copilot.py +14 -8
- dbt_platform_helper/commands/database.py +17 -9
- dbt_platform_helper/commands/environment.py +5 -6
- dbt_platform_helper/commands/generate.py +2 -3
- dbt_platform_helper/commands/notify.py +1 -3
- dbt_platform_helper/commands/pipeline.py +1 -3
- dbt_platform_helper/commands/secrets.py +1 -3
- dbt_platform_helper/commands/version.py +2 -2
- dbt_platform_helper/domain/codebase.py +17 -9
- dbt_platform_helper/domain/config.py +345 -0
- dbt_platform_helper/domain/copilot.py +158 -157
- dbt_platform_helper/domain/maintenance_page.py +42 -15
- dbt_platform_helper/domain/pipelines.py +1 -1
- dbt_platform_helper/domain/terraform_environment.py +1 -1
- dbt_platform_helper/domain/versioning.py +161 -30
- dbt_platform_helper/providers/aws/__init__.py +0 -0
- dbt_platform_helper/providers/{aws.py → aws/exceptions.py} +10 -0
- dbt_platform_helper/providers/aws/interfaces.py +13 -0
- dbt_platform_helper/providers/aws/opensearch.py +23 -0
- dbt_platform_helper/providers/aws/redis.py +21 -0
- dbt_platform_helper/providers/aws/sso_auth.py +61 -0
- dbt_platform_helper/providers/cache.py +40 -4
- dbt_platform_helper/providers/config.py +2 -1
- dbt_platform_helper/providers/config_validator.py +28 -25
- dbt_platform_helper/providers/copilot.py +1 -1
- dbt_platform_helper/providers/io.py +5 -2
- dbt_platform_helper/providers/kms.py +22 -0
- dbt_platform_helper/providers/load_balancers.py +26 -15
- dbt_platform_helper/providers/parameter_store.py +47 -0
- dbt_platform_helper/providers/platform_config_schema.py +17 -0
- dbt_platform_helper/providers/semantic_version.py +18 -88
- dbt_platform_helper/providers/terraform_manifest.py +1 -0
- dbt_platform_helper/providers/version.py +102 -26
- dbt_platform_helper/providers/version_status.py +80 -0
- dbt_platform_helper/providers/yaml_file.py +0 -1
- dbt_platform_helper/utils/aws.py +24 -142
- dbt_platform_helper/utils/git.py +3 -1
- dbt_platform_helper/utils/tool_versioning.py +12 -0
- {dbt_platform_helper-13.1.2.dist-info → dbt_platform_helper-13.3.0.dist-info}/METADATA +2 -2
- {dbt_platform_helper-13.1.2.dist-info → dbt_platform_helper-13.3.0.dist-info}/RECORD +48 -47
- {dbt_platform_helper-13.1.2.dist-info → dbt_platform_helper-13.3.0.dist-info}/WHEEL +1 -1
- platform_helper.py +1 -1
- dbt_platform_helper/providers/opensearch.py +0 -36
- dbt_platform_helper/providers/platform_helper_versioning.py +0 -107
- dbt_platform_helper/providers/redis.py +0 -34
- dbt_platform_helper/templates/svc/manifest-backend.yml +0 -69
- dbt_platform_helper/templates/svc/manifest-public.yml +0 -109
- dbt_platform_helper/utils/cloudfoundry.py +0 -14
- dbt_platform_helper/utils/files.py +0 -59
- dbt_platform_helper/utils/manifests.py +0 -18
- dbt_platform_helper/utils/versioning.py +0 -91
- {dbt_platform_helper-13.1.2.dist-info → dbt_platform_helper-13.3.0.dist-info}/LICENSE +0 -0
- {dbt_platform_helper-13.1.2.dist-info → dbt_platform_helper-13.3.0.dist-info}/entry_points.txt +0 -0
|
@@ -5,18 +5,19 @@ import json
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from pathlib import PosixPath
|
|
7
7
|
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
from schema import SchemaError
|
|
8
|
+
import botocore
|
|
9
|
+
import botocore.errorfactory
|
|
11
10
|
|
|
12
11
|
from dbt_platform_helper.constants import PLATFORM_CONFIG_FILE
|
|
13
12
|
from dbt_platform_helper.domain.copilot_environment import CopilotTemplating
|
|
14
13
|
from dbt_platform_helper.providers.config import ConfigProvider
|
|
15
14
|
from dbt_platform_helper.providers.files import FileProvider
|
|
15
|
+
from dbt_platform_helper.providers.io import ClickIOProvider
|
|
16
|
+
from dbt_platform_helper.providers.kms import KMSProvider
|
|
17
|
+
from dbt_platform_helper.providers.parameter_store import ParameterStore
|
|
18
|
+
from dbt_platform_helper.providers.yaml_file import YamlFileProvider
|
|
16
19
|
from dbt_platform_helper.utils.application import get_application_name
|
|
17
20
|
from dbt_platform_helper.utils.application import load_application
|
|
18
|
-
from dbt_platform_helper.utils.aws import get_aws_session_or_abort
|
|
19
|
-
from dbt_platform_helper.utils.files import generate_override_files
|
|
20
21
|
from dbt_platform_helper.utils.template import ADDON_TEMPLATE_MAP
|
|
21
22
|
from dbt_platform_helper.utils.template import camel_case
|
|
22
23
|
from dbt_platform_helper.utils.template import setup_templates
|
|
@@ -27,9 +28,6 @@ class Copilot:
|
|
|
27
28
|
|
|
28
29
|
PACKAGE_DIR = Path(__file__).resolve().parent.parent
|
|
29
30
|
|
|
30
|
-
# TODO Remove and test
|
|
31
|
-
WAF_ACL_ARN_KEY = "waf-acl-arn"
|
|
32
|
-
|
|
33
31
|
SERVICE_TYPES = [
|
|
34
32
|
"Load Balanced Web Service",
|
|
35
33
|
"Backend Service",
|
|
@@ -41,34 +39,115 @@ class Copilot:
|
|
|
41
39
|
def __init__(
|
|
42
40
|
self,
|
|
43
41
|
config_provider: ConfigProvider,
|
|
42
|
+
parameter_provider: ParameterStore,
|
|
44
43
|
file_provider: FileProvider,
|
|
45
44
|
copilot_templating: CopilotTemplating,
|
|
45
|
+
kms_provider: KMSProvider,
|
|
46
|
+
session,
|
|
47
|
+
io: ClickIOProvider = ClickIOProvider(),
|
|
48
|
+
yaml_file_provider: YamlFileProvider = YamlFileProvider,
|
|
46
49
|
):
|
|
47
50
|
self.config_provider = config_provider
|
|
51
|
+
self.parameter_provider = parameter_provider
|
|
48
52
|
self.file_provider = file_provider
|
|
49
53
|
self.copilot_templating = copilot_templating
|
|
54
|
+
self.kms_provider = kms_provider
|
|
55
|
+
self.io = io
|
|
56
|
+
self.yaml_file_provider = yaml_file_provider
|
|
57
|
+
self.session = session
|
|
58
|
+
|
|
59
|
+
def make_addons(self):
|
|
60
|
+
config = self.config_provider.load_and_validate_platform_config()
|
|
61
|
+
|
|
62
|
+
templates = setup_templates()
|
|
63
|
+
extensions = self._get_extensions()
|
|
64
|
+
application_name = get_application_name()
|
|
65
|
+
|
|
66
|
+
self.io.info("\n>>> Generating Terraform compatible addons CloudFormation\n")
|
|
67
|
+
|
|
68
|
+
output_dir = Path(".").absolute()
|
|
69
|
+
env_path = Path(f"copilot/environments/")
|
|
70
|
+
env_addons_path = env_path / "addons"
|
|
71
|
+
env_overrides_path = env_path / "overrides"
|
|
72
|
+
|
|
73
|
+
self._cleanup_old_files(extensions, output_dir, env_addons_path, env_overrides_path)
|
|
74
|
+
self._generate_env_overrides(output_dir)
|
|
75
|
+
|
|
76
|
+
svc_names = self._list_copilot_local_services()
|
|
77
|
+
base_path = Path(".")
|
|
78
|
+
for svc_name in svc_names:
|
|
79
|
+
self._generate_svc_overrides(base_path, templates, svc_name)
|
|
50
80
|
|
|
51
|
-
|
|
81
|
+
services = []
|
|
82
|
+
for ext_name, ext_data in extensions.items():
|
|
83
|
+
extension = {**ext_data}
|
|
84
|
+
addon_type = extension.pop("type")
|
|
85
|
+
environments = extension.pop("environments")
|
|
86
|
+
environment_addon_config = {
|
|
87
|
+
"addon_type": addon_type,
|
|
88
|
+
"environments": environments,
|
|
89
|
+
"name": extension.get("name", None) or ext_name,
|
|
90
|
+
"prefix": camel_case(ext_name),
|
|
91
|
+
"secret_name": ext_name.upper().replace("-", "_"),
|
|
92
|
+
**extension,
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
services.append(environment_addon_config)
|
|
96
|
+
|
|
97
|
+
service_addon_config = {
|
|
98
|
+
"application_name": application_name,
|
|
99
|
+
"name": extension.get("name", None) or ext_name,
|
|
100
|
+
"prefix": camel_case(ext_name),
|
|
101
|
+
"environments": environments,
|
|
102
|
+
**extension,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
log_destination_arns = self._get_log_destination_arn()
|
|
106
|
+
|
|
107
|
+
if addon_type in ["s3", "s3-policy"]:
|
|
108
|
+
if extensions[ext_name].get("serve_static_content"):
|
|
109
|
+
continue
|
|
110
|
+
|
|
111
|
+
s3_kms_arns = self._get_s3_kms_alias_arns(application_name, environments)
|
|
112
|
+
for environment_name in environments:
|
|
113
|
+
environments[environment_name]["kms_key_arn"] = s3_kms_arns.get(
|
|
114
|
+
environment_name, "kms-key-not-found"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
self._generate_service_addons(
|
|
118
|
+
extension,
|
|
119
|
+
ext_name,
|
|
120
|
+
addon_type,
|
|
121
|
+
output_dir,
|
|
122
|
+
service_addon_config,
|
|
123
|
+
templates,
|
|
124
|
+
log_destination_arns,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
environments = self.config_provider.apply_environment_defaults(config)["environments"]
|
|
128
|
+
|
|
129
|
+
self.copilot_templating.generate_cross_account_s3_policies(environments, extensions)
|
|
130
|
+
|
|
131
|
+
self.io.info(templates.get_template("addon-instructions.txt").render(services=services))
|
|
132
|
+
|
|
133
|
+
def _list_copilot_local_environments(self):
|
|
52
134
|
return [
|
|
53
135
|
path.parent.parts[-1] for path in Path("./copilot/environments/").glob("*/manifest.yml")
|
|
54
136
|
]
|
|
55
137
|
|
|
56
|
-
def
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
click.style(f"No type defined in manifest file {str(path)}; exiting", fg="red")
|
|
62
|
-
)
|
|
63
|
-
exit(1)
|
|
138
|
+
def _is_service(self, path: PosixPath) -> bool:
|
|
139
|
+
|
|
140
|
+
manifest_file = self.yaml_file_provider.load(path)
|
|
141
|
+
if not manifest_file or not manifest_file.get("type"):
|
|
142
|
+
self.io.abort_with_error(f"No type defined in manifest file {str(path)}; exiting")
|
|
64
143
|
|
|
65
|
-
|
|
144
|
+
return manifest_file.get("type") in self.SERVICE_TYPES
|
|
66
145
|
|
|
67
|
-
def
|
|
146
|
+
def _list_copilot_local_services(self):
|
|
68
147
|
return [
|
|
69
148
|
path.parent.parts[-1]
|
|
70
149
|
for path in Path("./copilot/").glob("*/manifest.yml")
|
|
71
|
-
if self.
|
|
150
|
+
if self._is_service(path)
|
|
72
151
|
]
|
|
73
152
|
|
|
74
153
|
def _validate_and_normalise_extensions_config(self, config_file, key_in_config_file=None):
|
|
@@ -90,12 +169,10 @@ class Copilot:
|
|
|
90
169
|
def _normalise_keys(source: dict):
|
|
91
170
|
return {k.replace("-", "_"): v for k, v in source.items()}
|
|
92
171
|
|
|
93
|
-
|
|
94
|
-
addon_plans = yaml.safe_load(fd)
|
|
172
|
+
addon_plans = self.yaml_file_provider.load(self.PACKAGE_DIR / "addon-plans.yml")
|
|
95
173
|
|
|
96
174
|
# load and validate config
|
|
97
|
-
|
|
98
|
-
config = yaml.safe_load(fd)
|
|
175
|
+
config = self.yaml_file_provider.load(config_file)
|
|
99
176
|
|
|
100
177
|
if config and key_in_config_file:
|
|
101
178
|
config = config[key_in_config_file]
|
|
@@ -107,23 +184,19 @@ class Copilot:
|
|
|
107
184
|
errors = validate_addons(config)
|
|
108
185
|
|
|
109
186
|
if errors:
|
|
110
|
-
|
|
187
|
+
self.io.error(f"Errors found in {config_file}:")
|
|
111
188
|
for addon, error in errors.items():
|
|
112
|
-
|
|
113
|
-
|
|
189
|
+
self.io.error(f"Addon '{addon}': {error}")
|
|
190
|
+
self.io.abort_with_error("Invalid platform-config.yml provided, see above warnings")
|
|
114
191
|
|
|
115
|
-
env_names = self.
|
|
116
|
-
svc_names = self.
|
|
192
|
+
env_names = self._list_copilot_local_environments()
|
|
193
|
+
svc_names = self._list_copilot_local_services()
|
|
117
194
|
|
|
118
195
|
if not env_names:
|
|
119
|
-
|
|
120
|
-
click.style(f"No environments found in ./copilot/environments; exiting", fg="red")
|
|
121
|
-
)
|
|
122
|
-
exit(1)
|
|
196
|
+
self.io.abort_with_error("No environments found in ./copilot/environments; exiting")
|
|
123
197
|
|
|
124
198
|
if not svc_names:
|
|
125
|
-
|
|
126
|
-
exit(1)
|
|
199
|
+
self.io.abort_with_error("No services found in ./copilot/; exiting")
|
|
127
200
|
|
|
128
201
|
normalised_config = {}
|
|
129
202
|
config_has_errors = False
|
|
@@ -136,11 +209,8 @@ class Copilot:
|
|
|
136
209
|
normalised_config[addon_name]["services"] = svc_names
|
|
137
210
|
|
|
138
211
|
if not set(normalised_config[addon_name]["services"]).issubset(set(svc_names)):
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
f"Services listed in {addon_name}.services do not exist in ./copilot/",
|
|
142
|
-
fg="red",
|
|
143
|
-
),
|
|
212
|
+
self.io.error(
|
|
213
|
+
f"Services listed in {addon_name}.services do not exist in ./copilot/"
|
|
144
214
|
)
|
|
145
215
|
config_has_errors = True
|
|
146
216
|
|
|
@@ -151,18 +221,10 @@ class Copilot:
|
|
|
151
221
|
|
|
152
222
|
missing_envs = set(environments.keys()) - set(env_names)
|
|
153
223
|
if missing_envs:
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
f"Environment keys listed in {addon_name} do not match those defined in ./copilot/environments.",
|
|
157
|
-
fg="red",
|
|
158
|
-
)
|
|
159
|
-
),
|
|
160
|
-
click.echo(
|
|
161
|
-
click.style(
|
|
162
|
-
f" Missing environments: {', '.join(sorted(missing_envs))}",
|
|
163
|
-
fg="white",
|
|
164
|
-
),
|
|
224
|
+
self.io.error(
|
|
225
|
+
f"Environment keys listed in {addon_name} do not match those defined in ./copilot/environments"
|
|
165
226
|
)
|
|
227
|
+
self.io.error(f" Missing environments: {', '.join(sorted(missing_envs))}")
|
|
166
228
|
config_has_errors = True
|
|
167
229
|
|
|
168
230
|
if config_has_errors:
|
|
@@ -183,41 +245,41 @@ class Copilot:
|
|
|
183
245
|
normalised_config[addon_name]["environments"] = normalised_environments
|
|
184
246
|
|
|
185
247
|
if config_has_errors:
|
|
186
|
-
|
|
248
|
+
self.io.abort_with_error("Configuration has errors. Exiting.")
|
|
187
249
|
|
|
188
250
|
return normalised_config
|
|
189
251
|
|
|
190
|
-
def
|
|
252
|
+
def _get_log_destination_arn(self):
|
|
191
253
|
"""Get destination arns stored in param store in projects aws
|
|
192
254
|
account."""
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
fg="red",
|
|
202
|
-
)
|
|
255
|
+
|
|
256
|
+
try:
|
|
257
|
+
destination_arns = self.parameter_provider.get_ssm_parameter_by_name(
|
|
258
|
+
"/copilot/tools/central_log_groups"
|
|
259
|
+
)
|
|
260
|
+
except botocore.errorfactory.ParameterNotFound:
|
|
261
|
+
self.io.abort_with_error(
|
|
262
|
+
"No aws central log group defined in Parameter Store at location /copilot/tools/central_log_groups; exiting"
|
|
203
263
|
)
|
|
204
|
-
exit(1)
|
|
205
264
|
|
|
206
|
-
|
|
207
|
-
return destination_arns
|
|
265
|
+
return json.loads(destination_arns["Value"])
|
|
208
266
|
|
|
209
267
|
def _generate_svc_overrides(self, base_path, templates, name):
|
|
210
|
-
|
|
268
|
+
self.io.info(f"\n>>> Generating service overrides for {name}\n")
|
|
211
269
|
overrides_path = base_path.joinpath(f"copilot/{name}/overrides")
|
|
212
270
|
overrides_path.mkdir(parents=True, exist_ok=True)
|
|
213
271
|
overrides_file = overrides_path.joinpath("cfn.patches.yml")
|
|
214
272
|
overrides_file.write_text(templates.get_template("svc/overrides/cfn.patches.yml").render())
|
|
215
273
|
|
|
216
|
-
def _get_s3_kms_alias_arns(self,
|
|
217
|
-
application = load_application(application_name, session)
|
|
274
|
+
def _get_s3_kms_alias_arns(self, application_name, config):
|
|
275
|
+
application = load_application(application_name, self.session)
|
|
218
276
|
arns = {}
|
|
219
277
|
|
|
220
278
|
for environment_name in application.environments:
|
|
279
|
+
kms_provider = self.kms_provider(
|
|
280
|
+
application.environments[environment_name].session.client("kms")
|
|
281
|
+
)
|
|
282
|
+
|
|
221
283
|
if environment_name not in config:
|
|
222
284
|
continue
|
|
223
285
|
|
|
@@ -225,99 +287,20 @@ class Copilot:
|
|
|
225
287
|
continue
|
|
226
288
|
|
|
227
289
|
bucket_name = config[environment_name]["bucket_name"]
|
|
228
|
-
kms_client = application.environments[environment_name].session.client("kms")
|
|
229
290
|
alias_name = f"alias/{application_name}-{environment_name}-{bucket_name}-key"
|
|
230
291
|
|
|
231
292
|
try:
|
|
232
|
-
response =
|
|
233
|
-
|
|
234
|
-
|
|
293
|
+
response = kms_provider.describe_key(alias_name)
|
|
294
|
+
|
|
295
|
+
# Boto3 classifies all AWS service errors and exceptions as ClientError exceptions
|
|
296
|
+
except botocore.exceptions.ClientError as error:
|
|
297
|
+
if error.response["Error"]["Code"] == "NotFoundException":
|
|
298
|
+
pass
|
|
235
299
|
else:
|
|
236
300
|
arns[environment_name] = response["KeyMetadata"]["Arn"]
|
|
237
301
|
|
|
238
302
|
return arns
|
|
239
303
|
|
|
240
|
-
def make_addons(self):
|
|
241
|
-
self.config_provider.config_file_check()
|
|
242
|
-
try:
|
|
243
|
-
config = self.config_provider.load_and_validate_platform_config()
|
|
244
|
-
except SchemaError as ex:
|
|
245
|
-
click.secho(f"Invalid `{PLATFORM_CONFIG_FILE}` file: {str(ex)}", fg="red")
|
|
246
|
-
raise click.Abort
|
|
247
|
-
|
|
248
|
-
templates = setup_templates()
|
|
249
|
-
extensions = self._get_extensions()
|
|
250
|
-
session = get_aws_session_or_abort()
|
|
251
|
-
|
|
252
|
-
application_name = get_application_name()
|
|
253
|
-
|
|
254
|
-
click.echo("\n>>> Generating Terraform compatible addons CloudFormation\n")
|
|
255
|
-
|
|
256
|
-
output_dir = Path(".").absolute()
|
|
257
|
-
env_path = Path(f"copilot/environments/")
|
|
258
|
-
env_addons_path = env_path / "addons"
|
|
259
|
-
env_overrides_path = env_path / "overrides"
|
|
260
|
-
|
|
261
|
-
self._cleanup_old_files(extensions, output_dir, env_addons_path, env_overrides_path)
|
|
262
|
-
self._generate_env_overrides(output_dir)
|
|
263
|
-
|
|
264
|
-
svc_names = self.list_copilot_local_services()
|
|
265
|
-
base_path = Path(".")
|
|
266
|
-
for svc_name in svc_names:
|
|
267
|
-
self._generate_svc_overrides(base_path, templates, svc_name)
|
|
268
|
-
|
|
269
|
-
services = []
|
|
270
|
-
for ext_name, ext_data in extensions.items():
|
|
271
|
-
extension = {**ext_data}
|
|
272
|
-
addon_type = extension.pop("type")
|
|
273
|
-
environments = extension.pop("environments")
|
|
274
|
-
environment_addon_config = {
|
|
275
|
-
"addon_type": addon_type,
|
|
276
|
-
"environments": environments,
|
|
277
|
-
"name": extension.get("name", None) or ext_name,
|
|
278
|
-
"prefix": camel_case(ext_name),
|
|
279
|
-
"secret_name": ext_name.upper().replace("-", "_"),
|
|
280
|
-
**extension,
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
services.append(environment_addon_config)
|
|
284
|
-
|
|
285
|
-
service_addon_config = {
|
|
286
|
-
"application_name": application_name,
|
|
287
|
-
"name": extension.get("name", None) or ext_name,
|
|
288
|
-
"prefix": camel_case(ext_name),
|
|
289
|
-
"environments": environments,
|
|
290
|
-
**extension,
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
log_destination_arns = self.get_log_destination_arn()
|
|
294
|
-
|
|
295
|
-
if addon_type in ["s3", "s3-policy"]:
|
|
296
|
-
if extensions[ext_name].get("serve_static_content"):
|
|
297
|
-
continue
|
|
298
|
-
|
|
299
|
-
s3_kms_arns = self._get_s3_kms_alias_arns(session, application_name, environments)
|
|
300
|
-
for environment_name in environments:
|
|
301
|
-
environments[environment_name]["kms_key_arn"] = s3_kms_arns.get(
|
|
302
|
-
environment_name, "kms-key-not-found"
|
|
303
|
-
)
|
|
304
|
-
|
|
305
|
-
self._generate_service_addons(
|
|
306
|
-
extension,
|
|
307
|
-
ext_name,
|
|
308
|
-
addon_type,
|
|
309
|
-
output_dir,
|
|
310
|
-
service_addon_config,
|
|
311
|
-
templates,
|
|
312
|
-
log_destination_arns,
|
|
313
|
-
)
|
|
314
|
-
|
|
315
|
-
environments = self.config_provider.apply_environment_defaults(config)["environments"]
|
|
316
|
-
|
|
317
|
-
self.copilot_templating.generate_cross_account_s3_policies(environments, extensions)
|
|
318
|
-
|
|
319
|
-
click.echo(templates.get_template("addon-instructions.txt").render(services=services))
|
|
320
|
-
|
|
321
304
|
def _get_extensions(self):
|
|
322
305
|
config = self._validate_and_normalise_extensions_config(
|
|
323
306
|
self.PACKAGE_DIR / "default-extensions.yml"
|
|
@@ -328,13 +311,31 @@ class Copilot:
|
|
|
328
311
|
config.update(project_config)
|
|
329
312
|
return config
|
|
330
313
|
|
|
314
|
+
def _generate_override_files(self, base_path, file_path, output_dir):
|
|
315
|
+
def generate_files_for_dir(pattern):
|
|
316
|
+
for file in file_path.glob(pattern):
|
|
317
|
+
if file.is_file():
|
|
318
|
+
contents = file.read_text()
|
|
319
|
+
file_name = str(file).removeprefix(f"{file_path}/")
|
|
320
|
+
self.io.info(
|
|
321
|
+
self.file_provider.mkfile(
|
|
322
|
+
base_path,
|
|
323
|
+
output_dir / file_name,
|
|
324
|
+
contents,
|
|
325
|
+
overwrite=True,
|
|
326
|
+
)
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
generate_files_for_dir("*")
|
|
330
|
+
generate_files_for_dir("bin/*")
|
|
331
|
+
|
|
331
332
|
def _generate_env_overrides(self, output_dir):
|
|
332
333
|
path = "templates/env/terraform-overrides"
|
|
333
|
-
|
|
334
|
+
self.io.info("\n>>> Generating Environment overrides\n")
|
|
334
335
|
overrides_path = output_dir.joinpath(f"copilot/environments/overrides")
|
|
335
336
|
overrides_path.mkdir(parents=True, exist_ok=True)
|
|
336
337
|
template_overrides_path = Path(__file__).parent.parent.joinpath(path)
|
|
337
|
-
|
|
338
|
+
self._generate_override_files(Path("."), template_overrides_path, overrides_path)
|
|
338
339
|
|
|
339
340
|
def _generate_service_addons(
|
|
340
341
|
self,
|
|
@@ -361,7 +362,7 @@ class Copilot:
|
|
|
361
362
|
)
|
|
362
363
|
|
|
363
364
|
(output_dir / service_path).mkdir(parents=True, exist_ok=True)
|
|
364
|
-
|
|
365
|
+
self.io.info(
|
|
365
366
|
self.file_provider.mkfile(
|
|
366
367
|
output_dir, service_path / f"{addon_name}.yml", contents, overwrite=True
|
|
367
368
|
)
|
|
@@ -38,20 +38,14 @@ class FailedToActivateMaintenancePageException(MaintenancePageException):
|
|
|
38
38
|
application_name: str,
|
|
39
39
|
env: str,
|
|
40
40
|
original_exception: Exception,
|
|
41
|
-
rolled_back_rules: dict[str, bool] = {},
|
|
42
41
|
):
|
|
43
42
|
super().__init__(
|
|
44
43
|
f"Maintenance page failed to activate for the {application_name} application in environment {env}."
|
|
45
44
|
)
|
|
46
45
|
self.orginal_exception = original_exception
|
|
47
|
-
self.rolled_back_rules = rolled_back_rules
|
|
48
46
|
|
|
49
47
|
def __str__(self):
|
|
50
|
-
return (
|
|
51
|
-
f"{super().__str__()}\n"
|
|
52
|
-
f"Rolled-back rules: {self.rolled_back_rules }\n"
|
|
53
|
-
f"Original exception: {self.orginal_exception}"
|
|
54
|
-
)
|
|
48
|
+
return f"{super().__str__()}\n" f"Original exception: {self.orginal_exception}"
|
|
55
49
|
|
|
56
50
|
|
|
57
51
|
# TODO should this be in its own provider, inside the VPC one, what logic is this sepcific too?
|
|
@@ -187,6 +181,15 @@ class MaintenancePage:
|
|
|
187
181
|
listener_arn, target_group_arn
|
|
188
182
|
)
|
|
189
183
|
|
|
184
|
+
self.io.debug(
|
|
185
|
+
f"""
|
|
186
|
+
#----------------------------------------------------------#
|
|
187
|
+
# Creating listener rules for service {svc.name.ljust(21, " ")}#
|
|
188
|
+
#----------------------------------------------------------#
|
|
189
|
+
|
|
190
|
+
""",
|
|
191
|
+
)
|
|
192
|
+
|
|
190
193
|
for ip in allowed_ips:
|
|
191
194
|
self.load_balancer.create_header_rule(
|
|
192
195
|
listener_arn,
|
|
@@ -196,6 +199,7 @@ class MaintenancePage:
|
|
|
196
199
|
"AllowedIps",
|
|
197
200
|
next(rule_priority),
|
|
198
201
|
service_conditions,
|
|
202
|
+
[{"Key": "service", "Value": svc.name}],
|
|
199
203
|
)
|
|
200
204
|
self.load_balancer.create_source_ip_rule(
|
|
201
205
|
listener_arn,
|
|
@@ -204,6 +208,7 @@ class MaintenancePage:
|
|
|
204
208
|
"AllowedSourceIps",
|
|
205
209
|
next(rule_priority),
|
|
206
210
|
service_conditions,
|
|
211
|
+
[{"Key": "service", "Value": svc.name}],
|
|
207
212
|
)
|
|
208
213
|
|
|
209
214
|
self.load_balancer.create_header_rule(
|
|
@@ -214,6 +219,7 @@ class MaintenancePage:
|
|
|
214
219
|
"BypassIpFilter",
|
|
215
220
|
next(rule_priority),
|
|
216
221
|
service_conditions,
|
|
222
|
+
[{"Key": "service", "Value": svc.name}],
|
|
217
223
|
)
|
|
218
224
|
|
|
219
225
|
# add to accumilating list of conditions for maintenace page rule
|
|
@@ -262,27 +268,48 @@ class MaintenancePage:
|
|
|
262
268
|
],
|
|
263
269
|
)
|
|
264
270
|
except Exception as e:
|
|
265
|
-
|
|
271
|
+
self.__clean_up_maintenance_page_rules(listener_arn)
|
|
266
272
|
raise FailedToActivateMaintenancePageException(
|
|
267
|
-
app, env, f"{e}:\n {traceback.format_exc()}"
|
|
273
|
+
app, env, f"{e}:\n {traceback.format_exc()}"
|
|
268
274
|
)
|
|
269
275
|
|
|
270
276
|
def __clean_up_maintenance_page_rules(
|
|
271
277
|
self, listener_arn: str, fail_when_not_deleted: bool = False
|
|
272
|
-
) ->
|
|
278
|
+
) -> None:
|
|
273
279
|
|
|
274
280
|
tag_descriptions = self.load_balancer.get_rules_tag_descriptions_by_listener_arn(
|
|
275
281
|
listener_arn
|
|
276
282
|
)
|
|
277
283
|
|
|
278
|
-
|
|
284
|
+
# keep track of rules deleted
|
|
285
|
+
deleted_rules = {"MaintenancePage": 0}
|
|
279
286
|
for name in ["MaintenancePage", "AllowedIps", "BypassIpFilter", "AllowedSourceIps"]:
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
287
|
+
deleted_list = self.load_balancer.delete_listener_rule_by_tags(tag_descriptions, name)
|
|
288
|
+
|
|
289
|
+
# track the rules deleted grouped by service
|
|
290
|
+
for deleted_rule in deleted_list:
|
|
291
|
+
tags = {t["Key"]: t["Value"] for t in deleted_rule["Tags"]}
|
|
292
|
+
if "service" in tags:
|
|
293
|
+
if tags["service"] not in deleted_rules:
|
|
294
|
+
deleted_rules[tags["service"]] = {
|
|
295
|
+
"AllowedIps": 0,
|
|
296
|
+
"BypassIpFilter": 0,
|
|
297
|
+
"AllowedSourceIps": 0,
|
|
298
|
+
}
|
|
299
|
+
deleted_rules[tags["service"]][name] += 1
|
|
300
|
+
elif tags.get("name") == "MaintenancePage":
|
|
301
|
+
deleted_rules["MaintenancePage"] += 1
|
|
302
|
+
|
|
303
|
+
if (
|
|
304
|
+
fail_when_not_deleted
|
|
305
|
+
and name == "MaintenancePage"
|
|
306
|
+
and deleted_rules["MaintenancePage"] == 0
|
|
307
|
+
):
|
|
283
308
|
raise ListenerRuleNotFoundException()
|
|
284
309
|
|
|
285
|
-
|
|
310
|
+
self.io.warn(
|
|
311
|
+
f"Rules deleted by type and grouped by service: {deleted_rules}",
|
|
312
|
+
)
|
|
286
313
|
|
|
287
314
|
def __remove_maintenance_page(self, listener_arn: str) -> dict[str, bool]:
|
|
288
315
|
self.__clean_up_maintenance_page_rules(listener_arn, True)
|
|
@@ -14,7 +14,7 @@ from dbt_platform_helper.providers.io import ClickIOProvider
|
|
|
14
14
|
from dbt_platform_helper.providers.terraform_manifest import TerraformManifestProvider
|
|
15
15
|
from dbt_platform_helper.utils.application import get_application_name
|
|
16
16
|
from dbt_platform_helper.utils.template import setup_templates
|
|
17
|
-
from dbt_platform_helper.utils.
|
|
17
|
+
from dbt_platform_helper.utils.tool_versioning import (
|
|
18
18
|
get_required_terraform_platform_modules_version,
|
|
19
19
|
)
|
|
20
20
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from dbt_platform_helper.platform_exception import PlatformException
|
|
2
2
|
from dbt_platform_helper.providers.io import ClickIOProvider
|
|
3
3
|
from dbt_platform_helper.providers.terraform_manifest import TerraformManifestProvider
|
|
4
|
-
from dbt_platform_helper.utils.
|
|
4
|
+
from dbt_platform_helper.utils.tool_versioning import (
|
|
5
5
|
get_required_terraform_platform_modules_version,
|
|
6
6
|
)
|
|
7
7
|
|