dbt-platform-helper 13.4.1__py3-none-any.whl → 14.1.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.md +26 -57
- dbt_platform_helper/commands/config.py +9 -0
- dbt_platform_helper/commands/environment.py +3 -7
- dbt_platform_helper/commands/notify.py +24 -77
- dbt_platform_helper/commands/pipeline.py +6 -12
- dbt_platform_helper/commands/secrets.py +1 -1
- dbt_platform_helper/constants.py +7 -5
- dbt_platform_helper/domain/codebase.py +0 -5
- dbt_platform_helper/domain/config.py +16 -9
- dbt_platform_helper/domain/copilot_environment.py +3 -3
- dbt_platform_helper/domain/database_copy.py +1 -1
- dbt_platform_helper/domain/maintenance_page.py +3 -3
- dbt_platform_helper/domain/notify.py +64 -0
- dbt_platform_helper/domain/pipelines.py +20 -16
- dbt_platform_helper/domain/terraform_environment.py +18 -11
- dbt_platform_helper/domain/versioning.py +18 -78
- dbt_platform_helper/providers/aws/exceptions.py +1 -1
- dbt_platform_helper/providers/cloudformation.py +1 -1
- dbt_platform_helper/providers/config.py +119 -17
- dbt_platform_helper/providers/config_validator.py +4 -31
- dbt_platform_helper/providers/copilot.py +3 -3
- dbt_platform_helper/providers/io.py +1 -1
- dbt_platform_helper/providers/load_balancers.py +6 -6
- dbt_platform_helper/providers/platform_config_schema.py +24 -29
- dbt_platform_helper/providers/schema_migrations/__init__.py +0 -0
- dbt_platform_helper/providers/schema_migrations/schema_v0_to_v1_migration.py +43 -0
- dbt_platform_helper/providers/schema_migrator.py +77 -0
- dbt_platform_helper/providers/secrets.py +5 -5
- dbt_platform_helper/providers/semantic_version.py +6 -1
- dbt_platform_helper/providers/slack_channel_notifier.py +62 -0
- dbt_platform_helper/providers/terraform_manifest.py +8 -10
- dbt_platform_helper/providers/version.py +1 -18
- dbt_platform_helper/providers/version_status.py +8 -61
- dbt_platform_helper/providers/yaml_file.py +23 -1
- dbt_platform_helper/templates/environment-pipelines/main.tf +1 -1
- dbt_platform_helper/utils/application.py +1 -1
- dbt_platform_helper/utils/aws.py +3 -3
- dbt_platform_helper/utils/git.py +0 -15
- {dbt_platform_helper-13.4.1.dist-info → dbt_platform_helper-14.1.0.dist-info}/METADATA +5 -4
- {dbt_platform_helper-13.4.1.dist-info → dbt_platform_helper-14.1.0.dist-info}/RECORD +44 -41
- platform_helper.py +0 -2
- dbt_platform_helper/commands/version.py +0 -37
- dbt_platform_helper/utils/tool_versioning.py +0 -12
- {dbt_platform_helper-13.4.1.dist-info → dbt_platform_helper-14.1.0.dist-info}/LICENSE +0 -0
- {dbt_platform_helper-13.4.1.dist-info → dbt_platform_helper-14.1.0.dist-info}/WHEEL +0 -0
- {dbt_platform_helper-13.4.1.dist-info → dbt_platform_helper-14.1.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import os
|
|
1
2
|
from collections.abc import Callable
|
|
2
3
|
from os import makedirs
|
|
3
4
|
from pathlib import Path
|
|
@@ -5,6 +6,7 @@ from shutil import rmtree
|
|
|
5
6
|
|
|
6
7
|
from dbt_platform_helper.constants import CODEBASE_PIPELINES_KEY
|
|
7
8
|
from dbt_platform_helper.constants import ENVIRONMENT_PIPELINES_KEY
|
|
9
|
+
from dbt_platform_helper.constants import PLATFORM_HELPER_VERSION_OVERRIDE_KEY
|
|
8
10
|
from dbt_platform_helper.constants import SUPPORTED_AWS_PROVIDER_VERSION
|
|
9
11
|
from dbt_platform_helper.constants import SUPPORTED_TERRAFORM_VERSION
|
|
10
12
|
from dbt_platform_helper.providers.config import ConfigProvider
|
|
@@ -14,9 +16,6 @@ from dbt_platform_helper.providers.io import ClickIOProvider
|
|
|
14
16
|
from dbt_platform_helper.providers.terraform_manifest import TerraformManifestProvider
|
|
15
17
|
from dbt_platform_helper.utils.application import get_application_name
|
|
16
18
|
from dbt_platform_helper.utils.template import setup_templates
|
|
17
|
-
from dbt_platform_helper.utils.tool_versioning import (
|
|
18
|
-
get_required_terraform_platform_modules_version,
|
|
19
|
-
)
|
|
20
19
|
|
|
21
20
|
|
|
22
21
|
class Pipelines:
|
|
@@ -29,6 +28,7 @@ class Pipelines:
|
|
|
29
28
|
get_codestar_arn: Callable[[str], str],
|
|
30
29
|
io: ClickIOProvider = ClickIOProvider(),
|
|
31
30
|
file_provider: FileProvider = FileProvider(),
|
|
31
|
+
platform_helper_version_override: str = None,
|
|
32
32
|
):
|
|
33
33
|
self.config_provider = config_provider
|
|
34
34
|
self.get_git_remote = get_git_remote
|
|
@@ -37,8 +37,14 @@ class Pipelines:
|
|
|
37
37
|
self.ecr_provider = ecr_provider
|
|
38
38
|
self.io = io
|
|
39
39
|
self.file_provider = file_provider
|
|
40
|
+
self.platform_helper_version_override = platform_helper_version_override or os.environ.get(
|
|
41
|
+
PLATFORM_HELPER_VERSION_OVERRIDE_KEY
|
|
42
|
+
)
|
|
40
43
|
|
|
41
|
-
def generate(
|
|
44
|
+
def generate(
|
|
45
|
+
self,
|
|
46
|
+
deploy_branch: str,
|
|
47
|
+
):
|
|
42
48
|
platform_config = self.config_provider.load_and_validate_platform_config()
|
|
43
49
|
|
|
44
50
|
has_codebase_pipelines = CODEBASE_PIPELINES_KEY in platform_config
|
|
@@ -48,10 +54,6 @@ class Pipelines:
|
|
|
48
54
|
self.io.warn("No pipelines defined: nothing to do.")
|
|
49
55
|
return
|
|
50
56
|
|
|
51
|
-
platform_config_terraform_modules_default_version = platform_config.get(
|
|
52
|
-
"default_versions", {}
|
|
53
|
-
).get("terraform-platform-modules", "")
|
|
54
|
-
|
|
55
57
|
app_name = get_application_name()
|
|
56
58
|
|
|
57
59
|
git_repo = self.get_git_remote()
|
|
@@ -67,12 +69,14 @@ class Pipelines:
|
|
|
67
69
|
|
|
68
70
|
self._clean_pipeline_config(copilot_pipelines_dir)
|
|
69
71
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
platform_config_terraform_modules_default_version,
|
|
72
|
+
platform_helper_version_for_template: str = platform_config.get("default_versions", {}).get(
|
|
73
|
+
"platform-helper"
|
|
73
74
|
)
|
|
74
75
|
|
|
75
|
-
|
|
76
|
+
if self.platform_helper_version_override:
|
|
77
|
+
platform_helper_version_for_template = self.platform_helper_version_override
|
|
78
|
+
|
|
79
|
+
# TODO: DBTP-1965: - this whole code block/if-statement can fall away once the deploy_repository is a required key.
|
|
76
80
|
deploy_repository = ""
|
|
77
81
|
if "deploy_repository" in platform_config.keys():
|
|
78
82
|
deploy_repository = f"{platform_config['deploy_repository']}"
|
|
@@ -95,7 +99,7 @@ class Pipelines:
|
|
|
95
99
|
platform_config["application"],
|
|
96
100
|
deploy_repository,
|
|
97
101
|
account,
|
|
98
|
-
|
|
102
|
+
platform_helper_version_for_template,
|
|
99
103
|
deploy_branch,
|
|
100
104
|
)
|
|
101
105
|
|
|
@@ -114,7 +118,7 @@ class Pipelines:
|
|
|
114
118
|
|
|
115
119
|
self.terraform_manifest_provider.generate_codebase_pipeline_config(
|
|
116
120
|
platform_config,
|
|
117
|
-
|
|
121
|
+
platform_helper_version_for_template,
|
|
118
122
|
ecrs_that_need_importing,
|
|
119
123
|
deploy_repository,
|
|
120
124
|
)
|
|
@@ -129,7 +133,7 @@ class Pipelines:
|
|
|
129
133
|
application: str,
|
|
130
134
|
deploy_repository: str,
|
|
131
135
|
aws_account: str,
|
|
132
|
-
|
|
136
|
+
platform_helper_version: str,
|
|
133
137
|
deploy_branch: str,
|
|
134
138
|
):
|
|
135
139
|
env_pipeline_template = setup_templates().get_template("environment-pipelines/main.tf")
|
|
@@ -139,7 +143,7 @@ class Pipelines:
|
|
|
139
143
|
"application": application,
|
|
140
144
|
"deploy_repository": deploy_repository,
|
|
141
145
|
"aws_account": aws_account,
|
|
142
|
-
"
|
|
146
|
+
"platform_helper_version": platform_helper_version,
|
|
143
147
|
"deploy_branch": deploy_branch,
|
|
144
148
|
"terraform_version": SUPPORTED_TERRAFORM_VERSION,
|
|
145
149
|
"aws_provider_version": SUPPORTED_AWS_PROVIDER_VERSION,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from dbt_platform_helper.constants import PLATFORM_HELPER_VERSION_OVERRIDE_KEY
|
|
1
4
|
from dbt_platform_helper.platform_exception import PlatformException
|
|
2
5
|
from dbt_platform_helper.providers.io import ClickIOProvider
|
|
3
6
|
from dbt_platform_helper.providers.terraform_manifest import TerraformManifestProvider
|
|
4
|
-
from dbt_platform_helper.utils.tool_versioning import (
|
|
5
|
-
get_required_terraform_platform_modules_version,
|
|
6
|
-
)
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class TerraformEnvironmentException(PlatformException):
|
|
@@ -20,12 +20,20 @@ class TerraformEnvironment:
|
|
|
20
20
|
config_provider,
|
|
21
21
|
manifest_provider: TerraformManifestProvider = None,
|
|
22
22
|
io: ClickIOProvider = ClickIOProvider(),
|
|
23
|
+
platform_helper_version_override: str = None,
|
|
23
24
|
):
|
|
24
25
|
self.io = io
|
|
25
26
|
self.config_provider = config_provider
|
|
26
27
|
self.manifest_provider = manifest_provider or TerraformManifestProvider()
|
|
28
|
+
self.platform_helper_version_override = platform_helper_version_override or os.environ.get(
|
|
29
|
+
PLATFORM_HELPER_VERSION_OVERRIDE_KEY
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
def generate(
|
|
33
|
+
self,
|
|
34
|
+
environment_name: str,
|
|
35
|
+
):
|
|
27
36
|
|
|
28
|
-
def generate(self, environment_name, terraform_platform_modules_version_override=None):
|
|
29
37
|
config = self.config_provider.get_enriched_config()
|
|
30
38
|
|
|
31
39
|
if environment_name not in config.get("environments").keys():
|
|
@@ -33,14 +41,13 @@ class TerraformEnvironment:
|
|
|
33
41
|
f"cannot generate terraform for environment {environment_name}. It does not exist in your configuration"
|
|
34
42
|
)
|
|
35
43
|
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
)
|
|
39
|
-
terraform_platform_modules_version = get_required_terraform_platform_modules_version(
|
|
40
|
-
terraform_platform_modules_version_override,
|
|
41
|
-
platform_config_terraform_modules_default_version,
|
|
44
|
+
platform_helper_version_for_template: str = config.get("default_versions", {}).get(
|
|
45
|
+
"platform-helper"
|
|
42
46
|
)
|
|
43
47
|
|
|
48
|
+
if self.platform_helper_version_override:
|
|
49
|
+
platform_helper_version_for_template = self.platform_helper_version_override
|
|
50
|
+
|
|
44
51
|
self.manifest_provider.generate_environment_config(
|
|
45
|
-
config, environment_name,
|
|
52
|
+
config, environment_name, platform_helper_version_for_template
|
|
46
53
|
)
|
|
@@ -12,14 +12,11 @@ from dbt_platform_helper.providers.semantic_version import (
|
|
|
12
12
|
from dbt_platform_helper.providers.semantic_version import SemanticVersion
|
|
13
13
|
from dbt_platform_helper.providers.version import AWSCLIInstalledVersionProvider
|
|
14
14
|
from dbt_platform_helper.providers.version import CopilotInstalledVersionProvider
|
|
15
|
-
from dbt_platform_helper.providers.version import DeprecatedVersionFileVersionProvider
|
|
16
15
|
from dbt_platform_helper.providers.version import GithubLatestVersionProvider
|
|
17
16
|
from dbt_platform_helper.providers.version import InstalledVersionProvider
|
|
18
17
|
from dbt_platform_helper.providers.version import PyPiLatestVersionProvider
|
|
19
18
|
from dbt_platform_helper.providers.version import VersionProvider
|
|
20
|
-
from dbt_platform_helper.providers.version_status import PlatformHelperVersionStatus
|
|
21
19
|
from dbt_platform_helper.providers.version_status import VersionStatus
|
|
22
|
-
from dbt_platform_helper.providers.yaml_file import YamlFileProvider
|
|
23
20
|
|
|
24
21
|
|
|
25
22
|
def running_as_installed_package():
|
|
@@ -31,24 +28,20 @@ def skip_version_checks():
|
|
|
31
28
|
|
|
32
29
|
|
|
33
30
|
class PlatformHelperVersionNotFoundException(PlatformException):
|
|
34
|
-
def __init__(self):
|
|
35
|
-
super().__init__(
|
|
31
|
+
def __init__(self, message=None):
|
|
32
|
+
super().__init__(message or "Platform helper version could not be resolved.")
|
|
36
33
|
|
|
37
34
|
|
|
38
35
|
class PlatformHelperVersioning:
|
|
39
36
|
def __init__(
|
|
40
37
|
self,
|
|
41
38
|
io: ClickIOProvider = ClickIOProvider(),
|
|
42
|
-
version_file_version_provider: DeprecatedVersionFileVersionProvider = DeprecatedVersionFileVersionProvider(
|
|
43
|
-
YamlFileProvider
|
|
44
|
-
),
|
|
45
39
|
config_provider: ConfigProvider = ConfigProvider(),
|
|
46
40
|
latest_version_provider: VersionProvider = PyPiLatestVersionProvider,
|
|
47
41
|
installed_version_provider: InstalledVersionProvider = InstalledVersionProvider(),
|
|
48
42
|
skip_versioning_checks: bool = None,
|
|
49
43
|
):
|
|
50
44
|
self.io = io
|
|
51
|
-
self.version_file_version_provider = version_file_version_provider
|
|
52
45
|
self.config_provider = config_provider
|
|
53
46
|
self.latest_version_provider = latest_version_provider
|
|
54
47
|
self.installed_version_provider = installed_version_provider
|
|
@@ -56,10 +49,9 @@ class PlatformHelperVersioning:
|
|
|
56
49
|
skip_versioning_checks if skip_versioning_checks is not None else skip_version_checks()
|
|
57
50
|
)
|
|
58
51
|
|
|
59
|
-
def get_required_version(self
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
required_version = self._resolve_required_version(pipeline, version_status)
|
|
52
|
+
def get_required_version(self):
|
|
53
|
+
platform_config = self.config_provider.load_and_validate_platform_config()
|
|
54
|
+
required_version = platform_config.get("default_versions", {}).get("platform-helper")
|
|
63
55
|
self.io.info(required_version)
|
|
64
56
|
return required_version
|
|
65
57
|
|
|
@@ -68,25 +60,24 @@ class PlatformHelperVersioning:
|
|
|
68
60
|
if self.skip_versioning_checks:
|
|
69
61
|
return
|
|
70
62
|
|
|
71
|
-
version_status = self.
|
|
72
|
-
self.
|
|
63
|
+
version_status = self.get_version_status()
|
|
64
|
+
required_version = self.get_required_version()
|
|
73
65
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
)
|
|
66
|
+
if SemanticVersion.is_semantic_version(required_version):
|
|
67
|
+
required_version_semver = SemanticVersion.from_string(required_version)
|
|
77
68
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
69
|
+
if not version_status.installed == required_version_semver:
|
|
70
|
+
message = (
|
|
71
|
+
f"WARNING: You are running platform-helper v{version_status.installed} against "
|
|
72
|
+
f"v{required_version_semver} specified for the project."
|
|
73
|
+
)
|
|
74
|
+
self.io.warn(message)
|
|
84
75
|
|
|
85
76
|
def check_if_needs_update(self):
|
|
86
77
|
if self.skip_versioning_checks:
|
|
87
78
|
return
|
|
88
79
|
|
|
89
|
-
version_status = self.
|
|
80
|
+
version_status = self.get_version_status()
|
|
90
81
|
|
|
91
82
|
message = (
|
|
92
83
|
f"You are running platform-helper v{version_status.installed}, upgrade to "
|
|
@@ -101,65 +92,14 @@ class PlatformHelperVersioning:
|
|
|
101
92
|
except IncompatibleMinorVersionException:
|
|
102
93
|
self.io.warn(message)
|
|
103
94
|
|
|
104
|
-
def
|
|
105
|
-
self,
|
|
106
|
-
include_project_versions: bool = True,
|
|
107
|
-
) -> PlatformHelperVersionStatus:
|
|
95
|
+
def get_version_status(self) -> VersionStatus:
|
|
108
96
|
locally_installed_version = self.installed_version_provider.get_semantic_version(
|
|
109
97
|
"dbt-platform-helper"
|
|
110
98
|
)
|
|
111
99
|
|
|
112
100
|
latest_release = self.latest_version_provider.get_semantic_version("dbt-platform-helper")
|
|
113
101
|
|
|
114
|
-
|
|
115
|
-
return PlatformHelperVersionStatus(
|
|
116
|
-
installed=locally_installed_version,
|
|
117
|
-
latest=latest_release,
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
platform_config_default, pipeline_overrides = None, {}
|
|
121
|
-
|
|
122
|
-
platform_config = self.config_provider.load_unvalidated_config_file()
|
|
123
|
-
|
|
124
|
-
if platform_config:
|
|
125
|
-
platform_config_default = SemanticVersion.from_string(
|
|
126
|
-
platform_config.get("default_versions", {}).get("platform-helper")
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
pipeline_overrides = {
|
|
130
|
-
name: pipeline.get("versions", {}).get("platform-helper")
|
|
131
|
-
for name, pipeline in platform_config.get("environment_pipelines", {}).items()
|
|
132
|
-
if pipeline.get("versions", {}).get("platform-helper")
|
|
133
|
-
}
|
|
134
|
-
out = PlatformHelperVersionStatus(
|
|
135
|
-
installed=locally_installed_version,
|
|
136
|
-
latest=latest_release,
|
|
137
|
-
deprecated_version_file=self.version_file_version_provider.get_semantic_version(),
|
|
138
|
-
platform_config_default=platform_config_default,
|
|
139
|
-
pipeline_overrides=pipeline_overrides,
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
return out
|
|
143
|
-
|
|
144
|
-
def _resolve_required_version(
|
|
145
|
-
self, pipeline: str = None, version_status: PlatformHelperVersionStatus = None
|
|
146
|
-
) -> str:
|
|
147
|
-
pipeline_version = version_status.pipeline_overrides.get(pipeline)
|
|
148
|
-
version_precedence = [
|
|
149
|
-
pipeline_version,
|
|
150
|
-
version_status.platform_config_default,
|
|
151
|
-
version_status.deprecated_version_file,
|
|
152
|
-
]
|
|
153
|
-
non_null_version_precedence = [
|
|
154
|
-
f"{v}" if isinstance(v, SemanticVersion) else v for v in version_precedence if v
|
|
155
|
-
]
|
|
156
|
-
|
|
157
|
-
out = non_null_version_precedence[0] if non_null_version_precedence else None
|
|
158
|
-
|
|
159
|
-
if not out:
|
|
160
|
-
raise PlatformHelperVersionNotFoundException
|
|
161
|
-
|
|
162
|
-
return out
|
|
102
|
+
return VersionStatus(installed=locally_installed_version, latest=latest_release)
|
|
163
103
|
|
|
164
104
|
|
|
165
105
|
class AWSVersioning:
|
|
@@ -29,7 +29,7 @@ class LogGroupNotFoundException(AWSException):
|
|
|
29
29
|
super().__init__(f"""No log group called "{log_group_name}".""")
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
#
|
|
32
|
+
# TODO: DBTP-1976: This should probably be in the AWS Copilot provider, but was causing circular import when we tried it pre refactoring the utils/aws.py
|
|
33
33
|
class CopilotCodebaseNotFoundException(PlatformException):
|
|
34
34
|
def __init__(self, codebase: str):
|
|
35
35
|
super().__init__(
|
|
@@ -8,7 +8,7 @@ from dbt_platform_helper.platform_exception import PlatformException
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class CloudFormation:
|
|
11
|
-
# TODO add handling for optional client parameters to handle case of calling boto API with None
|
|
11
|
+
# TODO: DBTP-1966: add handling for optional client parameters to handle case of calling boto API with None
|
|
12
12
|
def __init__(self, cloudformation_client, iam_client=None, ssm_client=None):
|
|
13
13
|
self.cloudformation_client = cloudformation_client
|
|
14
14
|
self.iam_client = iam_client
|
|
@@ -1,41 +1,59 @@
|
|
|
1
1
|
from copy import deepcopy
|
|
2
|
+
from datetime import datetime
|
|
2
3
|
from pathlib import Path
|
|
3
4
|
|
|
4
5
|
from schema import SchemaError
|
|
5
6
|
|
|
7
|
+
from dbt_platform_helper.constants import FIRST_UPGRADABLE_PLATFORM_HELPER_MAJOR_VERSION
|
|
6
8
|
from dbt_platform_helper.constants import PLATFORM_CONFIG_FILE
|
|
9
|
+
from dbt_platform_helper.constants import PLATFORM_CONFIG_SCHEMA_VERSION
|
|
10
|
+
from dbt_platform_helper.constants import PLATFORM_HELPER_PACKAGE_NAME
|
|
7
11
|
from dbt_platform_helper.providers.config_validator import ConfigValidator
|
|
8
12
|
from dbt_platform_helper.providers.config_validator import ConfigValidatorError
|
|
9
13
|
from dbt_platform_helper.providers.io import ClickIOProvider
|
|
10
14
|
from dbt_platform_helper.providers.platform_config_schema import PlatformConfigSchema
|
|
15
|
+
from dbt_platform_helper.providers.semantic_version import SemanticVersion
|
|
16
|
+
from dbt_platform_helper.providers.version import InstalledVersionProvider
|
|
11
17
|
from dbt_platform_helper.providers.yaml_file import FileNotFoundException
|
|
12
18
|
from dbt_platform_helper.providers.yaml_file import FileProviderException
|
|
13
19
|
from dbt_platform_helper.providers.yaml_file import YamlFileProvider
|
|
14
20
|
|
|
21
|
+
SCHEMA_VERSION_MESSAGE = """Installed version: platform-helper: {installed_platform_helper_version} (schema version: {installed_schema_version})
|
|
22
|
+
'platform-config.yml' version: platform-helper: {config_platform_helper_version} (schema version: {config_schema_version})"""
|
|
23
|
+
PLEASE_UPGRADE_TO_V13_MESSAGE = """Please ensure that you have already upgraded to platform-helper 13, following the instructions in https://platform.readme.trade.gov.uk/reference/upgrading-platform-helper/.
|
|
24
|
+
|
|
25
|
+
Then upgrade platform-helper to version {installed_platform_helper_version} and run 'platform-helper config migrate' to upgrade the configuration to the current schema version."""
|
|
26
|
+
|
|
15
27
|
|
|
16
28
|
class ConfigProvider:
|
|
17
29
|
def __init__(
|
|
18
30
|
self,
|
|
19
|
-
config_validator: ConfigValidator =
|
|
20
|
-
file_provider: YamlFileProvider =
|
|
21
|
-
io: ClickIOProvider =
|
|
31
|
+
config_validator: ConfigValidator = ConfigValidator(),
|
|
32
|
+
file_provider: YamlFileProvider = YamlFileProvider,
|
|
33
|
+
io: ClickIOProvider = ClickIOProvider(),
|
|
34
|
+
schema_version_for_installed_platform_helper: int = PLATFORM_CONFIG_SCHEMA_VERSION,
|
|
35
|
+
installed_version_provider: InstalledVersionProvider = InstalledVersionProvider,
|
|
22
36
|
):
|
|
23
37
|
self.config = {}
|
|
24
|
-
self.validator = config_validator
|
|
25
|
-
self.io = io
|
|
26
|
-
self.file_provider = file_provider
|
|
27
|
-
|
|
28
|
-
|
|
38
|
+
self.validator = config_validator
|
|
39
|
+
self.io = io
|
|
40
|
+
self.file_provider = file_provider
|
|
41
|
+
self.schema_version_for_installed_platform_helper = (
|
|
42
|
+
schema_version_for_installed_platform_helper
|
|
43
|
+
)
|
|
44
|
+
self.installed_version_provider = installed_version_provider
|
|
45
|
+
|
|
46
|
+
# TODO: DBTP-1964: refactor so that apply_environment_defaults isn't set, discarded and set again
|
|
29
47
|
def get_enriched_config(self):
|
|
30
48
|
return self.apply_environment_defaults(self.load_and_validate_platform_config())
|
|
31
49
|
|
|
32
50
|
def _validate_platform_config(self):
|
|
33
51
|
PlatformConfigSchema.schema().validate(self.config)
|
|
34
|
-
|
|
35
|
-
# TODO= logically this isn't validation but loading + parsing, to move.
|
|
52
|
+
# TODO: DBTP-1964: = logically this isn't validation but loading + parsing, to move.
|
|
36
53
|
# also, we apply defaults but discard that data. Should we just apply
|
|
37
54
|
# defaults to config returned by load_and_validate
|
|
38
55
|
enriched_config = ConfigProvider.apply_environment_defaults(self.config)
|
|
56
|
+
|
|
39
57
|
try:
|
|
40
58
|
self.validator.run_validations(enriched_config)
|
|
41
59
|
except ConfigValidatorError as exc:
|
|
@@ -51,6 +69,8 @@ class ConfigProvider:
|
|
|
51
69
|
except FileProviderException as e:
|
|
52
70
|
self.io.abort_with_error(f"Error loading configuration from {path}: {e}")
|
|
53
71
|
|
|
72
|
+
self._validate_schema_version()
|
|
73
|
+
|
|
54
74
|
try:
|
|
55
75
|
self._validate_platform_config()
|
|
56
76
|
except SchemaError as e:
|
|
@@ -58,13 +78,90 @@ class ConfigProvider:
|
|
|
58
78
|
|
|
59
79
|
return self.config
|
|
60
80
|
|
|
81
|
+
def _abort_due_to_schema_version_error(self, config_description: str, action_required: str):
|
|
82
|
+
self.io.abort_with_error(
|
|
83
|
+
"\n".join(
|
|
84
|
+
[
|
|
85
|
+
config_description,
|
|
86
|
+
"",
|
|
87
|
+
action_required,
|
|
88
|
+
]
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
def _validate_schema_version(self):
|
|
93
|
+
config_schema_version = self.config.get("schema_version")
|
|
94
|
+
config_platform_helper_version = self.config.get("default_versions", {}).get(
|
|
95
|
+
"platform-helper", ""
|
|
96
|
+
)
|
|
97
|
+
header = SCHEMA_VERSION_MESSAGE.format(
|
|
98
|
+
installed_platform_helper_version=self._installed_platform_helper_version(),
|
|
99
|
+
installed_schema_version=self.schema_version_for_installed_platform_helper,
|
|
100
|
+
config_platform_helper_version=(
|
|
101
|
+
config_platform_helper_version if config_platform_helper_version else "N/A"
|
|
102
|
+
),
|
|
103
|
+
config_schema_version=(config_schema_version if config_schema_version else "N/A"),
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
if config_schema_version:
|
|
107
|
+
self._handle_schema_version_mismatch(config_schema_version, header)
|
|
108
|
+
else:
|
|
109
|
+
self._handle_missing_schema_version(config_platform_helper_version, header)
|
|
110
|
+
|
|
111
|
+
def _handle_schema_version_mismatch(self, platform_config_schema_version: int, header: str):
|
|
112
|
+
platform_config_schema_version_is_old = (
|
|
113
|
+
platform_config_schema_version < self.schema_version_for_installed_platform_helper
|
|
114
|
+
)
|
|
115
|
+
installed_platform_helper_is_old = (
|
|
116
|
+
platform_config_schema_version > self.schema_version_for_installed_platform_helper
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
if platform_config_schema_version_is_old:
|
|
120
|
+
self._abort_due_to_schema_version_error(
|
|
121
|
+
header,
|
|
122
|
+
"Please upgrade your platform-config.yml by running 'platform-helper config migrate'.",
|
|
123
|
+
)
|
|
124
|
+
elif installed_platform_helper_is_old:
|
|
125
|
+
self._abort_due_to_schema_version_error(
|
|
126
|
+
header,
|
|
127
|
+
f"Please update your platform-helper to a version that supports schema_version: {platform_config_schema_version}.",
|
|
128
|
+
)
|
|
129
|
+
# else the schema_version is the correct one so continue.
|
|
130
|
+
|
|
131
|
+
def _handle_missing_schema_version(self, config_platform_helper_version: str, header: str):
|
|
132
|
+
config_p_h_version_semver = SemanticVersion.from_string(config_platform_helper_version)
|
|
133
|
+
major_version = config_p_h_version_semver and config_p_h_version_semver.major
|
|
134
|
+
platform_config_is_old_but_supported_by_migrations = (
|
|
135
|
+
major_version and major_version == FIRST_UPGRADABLE_PLATFORM_HELPER_MAJOR_VERSION
|
|
136
|
+
)
|
|
137
|
+
platform_config_is_old = (
|
|
138
|
+
major_version and major_version < FIRST_UPGRADABLE_PLATFORM_HELPER_MAJOR_VERSION
|
|
139
|
+
)
|
|
140
|
+
platform_config_is_really_old = not major_version
|
|
141
|
+
installed_platform_helper_version = self._installed_platform_helper_version()
|
|
142
|
+
|
|
143
|
+
if platform_config_is_old_but_supported_by_migrations:
|
|
144
|
+
self._abort_due_to_schema_version_error(
|
|
145
|
+
header,
|
|
146
|
+
f"Please upgrade your platform-config.yml to be compatible with {installed_platform_helper_version} by running: 'platform-helper config migrate'.",
|
|
147
|
+
)
|
|
148
|
+
elif platform_config_is_old or platform_config_is_really_old:
|
|
149
|
+
self._abort_due_to_schema_version_error(
|
|
150
|
+
header,
|
|
151
|
+
PLEASE_UPGRADE_TO_V13_MESSAGE.format(
|
|
152
|
+
installed_platform_helper_version=installed_platform_helper_version,
|
|
153
|
+
),
|
|
154
|
+
)
|
|
155
|
+
# if major_version and major_version > FIRST_UPGRADABLE_PLATFORM_HELPER_MAJOR_VERSION then
|
|
156
|
+
# the platform-config.yml is malformed and so should progress to validation if appropriate.
|
|
157
|
+
|
|
61
158
|
def load_unvalidated_config_file(self, path=PLATFORM_CONFIG_FILE):
|
|
62
159
|
try:
|
|
63
160
|
return self.file_provider.load(path)
|
|
64
161
|
except FileProviderException:
|
|
65
162
|
return {}
|
|
66
163
|
|
|
67
|
-
# TODO remove function and push logic to where this is called.
|
|
164
|
+
# TODO: DBTP-1888: remove function and push logic to where this is called.
|
|
68
165
|
# removed usage from config domain, code is very generic and doesn't require the overhead of a function
|
|
69
166
|
def config_file_check(self, path=PLATFORM_CONFIG_FILE):
|
|
70
167
|
if not Path(path).exists():
|
|
@@ -86,17 +183,12 @@ class ConfigProvider:
|
|
|
86
183
|
name: data if data else {} for name, data in environments.items() if name != "*"
|
|
87
184
|
}
|
|
88
185
|
|
|
89
|
-
|
|
186
|
+
config.get("default_versions", {})
|
|
90
187
|
|
|
91
188
|
def combine_env_data(data):
|
|
92
189
|
return {
|
|
93
190
|
**env_defaults,
|
|
94
191
|
**data,
|
|
95
|
-
"versions": {
|
|
96
|
-
**default_versions,
|
|
97
|
-
**env_defaults.get("versions", {}),
|
|
98
|
-
**data.get("versions", {}),
|
|
99
|
-
},
|
|
100
192
|
}
|
|
101
193
|
|
|
102
194
|
defaulted_envs = {
|
|
@@ -107,3 +199,13 @@ class ConfigProvider:
|
|
|
107
199
|
enriched_config["environments"] = defaulted_envs
|
|
108
200
|
|
|
109
201
|
return enriched_config
|
|
202
|
+
|
|
203
|
+
def write_platform_config(self, new_platform_config):
|
|
204
|
+
current_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
205
|
+
message = f"# Generated by platform-helper {self._installed_platform_helper_version()} / {current_date}.\n\n"
|
|
206
|
+
self.file_provider.write(PLATFORM_CONFIG_FILE, new_platform_config, message)
|
|
207
|
+
|
|
208
|
+
def _installed_platform_helper_version(self) -> str:
|
|
209
|
+
return str(
|
|
210
|
+
self.installed_version_provider.get_semantic_version(PLATFORM_HELPER_PACKAGE_NAME)
|
|
211
|
+
)
|
|
@@ -89,16 +89,16 @@ class ConfigValidator:
|
|
|
89
89
|
return self._validate_extension_supported_versions(
|
|
90
90
|
config=config,
|
|
91
91
|
aws_provider=Redis(self._get_client("elasticache")),
|
|
92
|
-
extension_type="redis", # TODO this is information which can live in the RedisProvider
|
|
93
|
-
version_key="engine", # TODO this is information which can live in the RedisProvider
|
|
92
|
+
extension_type="redis", # TODO: DBTP-1888: this is information which can live in the RedisProvider
|
|
93
|
+
version_key="engine", # TODO: DBTP-1888: this is information which can live in the RedisProvider
|
|
94
94
|
)
|
|
95
95
|
|
|
96
96
|
def validate_supported_opensearch_versions(self, config):
|
|
97
97
|
return self._validate_extension_supported_versions(
|
|
98
98
|
config=config,
|
|
99
99
|
aws_provider=Opensearch(self._get_client("opensearch")),
|
|
100
|
-
extension_type="opensearch", # TODO this is information which can live in the OpensearchProvider
|
|
101
|
-
version_key="engine", # TODO this is information which can live in the OpensearchProvider
|
|
100
|
+
extension_type="opensearch", # TODO: DBTP-1888: this is information which can live in the OpensearchProvider
|
|
101
|
+
version_key="engine", # TODO: DBTP-1888: this is information which can live in the OpensearchProvider
|
|
102
102
|
)
|
|
103
103
|
|
|
104
104
|
def validate_environment_pipelines(self, config):
|
|
@@ -180,21 +180,6 @@ class ConfigValidator:
|
|
|
180
180
|
from_env = section["from"]
|
|
181
181
|
to_env = section["to"]
|
|
182
182
|
|
|
183
|
-
from_account = (
|
|
184
|
-
config.get("environments", {})
|
|
185
|
-
.get(from_env, {})
|
|
186
|
-
.get("accounts", {})
|
|
187
|
-
.get("deploy", {})
|
|
188
|
-
.get("id")
|
|
189
|
-
)
|
|
190
|
-
to_account = (
|
|
191
|
-
config.get("environments", {})
|
|
192
|
-
.get(to_env, {})
|
|
193
|
-
.get("accounts", {})
|
|
194
|
-
.get("deploy", {})
|
|
195
|
-
.get("id")
|
|
196
|
-
)
|
|
197
|
-
|
|
198
183
|
if from_env == to_env:
|
|
199
184
|
errors.append(
|
|
200
185
|
f"database_copy 'to' and 'from' cannot be the same environment in extension '{extension_name}'."
|
|
@@ -215,18 +200,6 @@ class ConfigValidator:
|
|
|
215
200
|
f"database_copy 'to' parameter must be a valid environment ({all_envs_string}) but was '{to_env}' in extension '{extension_name}'."
|
|
216
201
|
)
|
|
217
202
|
|
|
218
|
-
# TODO - The from_account and to_account properties are deprecated and will be removed when terraform-platform-modules is merged with platform-tools
|
|
219
|
-
if from_account != to_account:
|
|
220
|
-
if "from_account" in section and section["from_account"] != from_account:
|
|
221
|
-
errors.append(
|
|
222
|
-
f"Incorrect value for 'from_account' for environment '{from_env}'"
|
|
223
|
-
)
|
|
224
|
-
|
|
225
|
-
if "to_account" in section and section["to_account"] != to_account:
|
|
226
|
-
errors.append(
|
|
227
|
-
f"Incorrect value for 'to_account' for environment '{to_env}'"
|
|
228
|
-
)
|
|
229
|
-
|
|
230
203
|
if errors:
|
|
231
204
|
raise ConfigValidatorError("\n".join(errors))
|
|
232
205
|
|
|
@@ -53,7 +53,7 @@ def create_addon_client_task(
|
|
|
53
53
|
# We cannot check for botocore.errorfactory.NoSuchEntityException as botocore generates that class on the fly as part of errorfactory.
|
|
54
54
|
# factory. Checking the error code is the recommended way of handling these exceptions.
|
|
55
55
|
if ex.response.get("Error", {}).get("Code", None) != "NoSuchEntity":
|
|
56
|
-
# TODO When we are refactoring this, raise an exception to be caught at the command layer
|
|
56
|
+
# TODO: DBTP-1946: When we are refactoring this, raise an exception to be caught at the command layer
|
|
57
57
|
abort_with_error(
|
|
58
58
|
f"cannot obtain Role {role_name}: {ex.response.get('Error', {}).get('Message', '')}"
|
|
59
59
|
)
|
|
@@ -132,7 +132,7 @@ def connect_to_addon_client_task(
|
|
|
132
132
|
tries = 0
|
|
133
133
|
while tries < 15 and not running:
|
|
134
134
|
tries += 1
|
|
135
|
-
#
|
|
135
|
+
# TODO: DBTP-1946: Use from ECS provider when we refactor this
|
|
136
136
|
if get_ecs_task_arns(ecs_client, cluster_arn, task_name):
|
|
137
137
|
subprocess.call(
|
|
138
138
|
"copilot task exec "
|
|
@@ -154,7 +154,7 @@ def _normalise_secret_name(addon_name: str) -> str:
|
|
|
154
154
|
|
|
155
155
|
|
|
156
156
|
def _get_secrets_provider(application: Application, env: str) -> Secrets:
|
|
157
|
-
#
|
|
157
|
+
# TODO: DBTP-1946: We instantiate the secrets provider here to avoid rabbit holing, but something better probably possible when we are refactoring this area
|
|
158
158
|
return Secrets(
|
|
159
159
|
application.environments[env].session.client("ssm"),
|
|
160
160
|
application.environments[env].session.client("secretsmanager"),
|
|
@@ -29,7 +29,7 @@ class ClickIOProvider:
|
|
|
29
29
|
click.secho(f"Error: {message}", err=True, fg="red")
|
|
30
30
|
exit(1)
|
|
31
31
|
|
|
32
|
-
# TODO messages will be a ValidationMessages class rather than a free-rein dictionary
|
|
32
|
+
# TODO: DBTP-1979: messages will be a ValidationMessages class rather than a free-rein dictionary
|
|
33
33
|
def process_messages(self, messages: dict):
|
|
34
34
|
if not messages:
|
|
35
35
|
return
|