qontract-reconcile 0.9.1rc162__py3-none-any.whl → 0.9.1rc164__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.
- {qontract_reconcile-0.9.1rc162.dist-info → qontract_reconcile-0.9.1rc164.dist-info}/METADATA +2 -2
- {qontract_reconcile-0.9.1rc162.dist-info → qontract_reconcile-0.9.1rc164.dist-info}/RECORD +21 -30
- reconcile/glitchtip_project_dsn/integration.py +3 -0
- reconcile/jenkins_job_builder.py +2 -5
- reconcile/openshift_base.py +11 -11
- reconcile/openshift_saas_deploy.py +52 -57
- reconcile/openshift_saas_deploy_trigger_base.py +48 -55
- reconcile/openshift_saas_deploy_trigger_cleaner.py +2 -2
- reconcile/openshift_tekton_resources.py +1 -1
- reconcile/saas_file_validator.py +10 -23
- reconcile/slack_base.py +2 -5
- reconcile/test/conftest.py +0 -11
- reconcile/test/test_auto_promoter.py +42 -199
- reconcile/test/test_saasherder.py +463 -398
- reconcile/test/test_saasherder_allowed_secret_paths.py +36 -87
- reconcile/utils/mr/auto_promoter.py +50 -58
- reconcile/utils/mr/base.py +2 -6
- reconcile/utils/{saasherder/saasherder.py → saasherder.py} +736 -656
- reconcile/gql_definitions/common/app_code_component_repos.py +0 -68
- reconcile/gql_definitions/common/saas_files.py +0 -542
- reconcile/gql_definitions/common/saasherder_settings.py +0 -62
- reconcile/gql_definitions/fragments/oc_connection_cluster.py +0 -47
- reconcile/typed_queries/repos.py +0 -17
- reconcile/typed_queries/saas_files.py +0 -61
- reconcile/utils/saasherder/__init__.py +0 -17
- reconcile/utils/saasherder/interfaces.py +0 -404
- reconcile/utils/saasherder/models.py +0 -203
- {qontract_reconcile-0.9.1rc162.dist-info → qontract_reconcile-0.9.1rc164.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.9.1rc162.dist-info → qontract_reconcile-0.9.1rc164.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.9.1rc162.dist-info → qontract_reconcile-0.9.1rc164.dist-info}/top_level.txt +0 -0
@@ -1,10 +1,6 @@
|
|
1
|
-
from collections.abc import Callable
|
2
|
-
|
3
1
|
import pytest
|
4
2
|
|
5
|
-
from reconcile.gql_definitions.common.saas_files import SaasFileV2
|
6
3
|
from reconcile.utils.saasherder import SaasHerder
|
7
|
-
from reconcile.utils.secret_reader import SecretReader
|
8
4
|
|
9
5
|
|
10
6
|
@pytest.mark.parametrize(
|
@@ -24,103 +20,56 @@ def test_saasherder_allowed_secret_paths(
|
|
24
20
|
allowed_secret_parameter_path: str,
|
25
21
|
referenced_secret_path: str,
|
26
22
|
expected_valid: bool,
|
27
|
-
secret_reader: SecretReader,
|
28
|
-
gql_class_factory: Callable[
|
29
|
-
...,
|
30
|
-
SaasFileV2,
|
31
|
-
],
|
32
23
|
):
|
33
24
|
"""
|
34
25
|
ensure a parent directory in allowed_secret_parameter_paths matches correctly
|
35
26
|
"""
|
36
27
|
saas_files = [
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
"
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
"
|
54
|
-
"
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
"pipelineTemplates": {
|
63
|
-
"openshiftSaasDeploy": {"name": "openshift-saas-deploy"}
|
64
|
-
},
|
65
|
-
},
|
66
|
-
"imagePatterns": [],
|
67
|
-
"resourceTemplates": [
|
68
|
-
{
|
69
|
-
"path": "path1",
|
70
|
-
"name": "test",
|
71
|
-
"url": "url",
|
72
|
-
"targets": [
|
73
|
-
{
|
74
|
-
"namespace": {
|
75
|
-
"name": "test-ns-subscriber",
|
76
|
-
"environment": {
|
77
|
-
"name": "App-SRE",
|
78
|
-
"parameters": "{}",
|
79
|
-
},
|
80
|
-
"app": {"name": "test-saas-deployments"},
|
81
|
-
"cluster": {
|
82
|
-
"name": "appsres03ue1",
|
83
|
-
"serverUrl": "https://api.appsres03ue1.5nvu.p1.openshiftapps.com:6443",
|
84
|
-
"internal": True,
|
85
|
-
},
|
86
|
-
},
|
87
|
-
"ref": "main",
|
88
|
-
"upstream": {
|
89
|
-
"instance": {
|
90
|
-
"name": "ci",
|
91
|
-
"serverUrl": "https://jenkins.com",
|
28
|
+
{
|
29
|
+
"path": "path1",
|
30
|
+
"name": "a1",
|
31
|
+
"managedResourceTypes": [],
|
32
|
+
"allowedSecretParameterPaths": [allowed_secret_parameter_path],
|
33
|
+
"resourceTemplates": [
|
34
|
+
{
|
35
|
+
"name": "test",
|
36
|
+
"url": "url",
|
37
|
+
"targets": [
|
38
|
+
{
|
39
|
+
"namespace": {
|
40
|
+
"name": "ns",
|
41
|
+
"environment": {"name": "env1", "parameters": "{}"},
|
42
|
+
"cluster": {"name": "cluster"},
|
43
|
+
},
|
44
|
+
"ref": "main",
|
45
|
+
"upstream": {"instance": {"name": "ci"}, "name": "job"},
|
46
|
+
"parameters": {},
|
47
|
+
"secretParameters": [
|
48
|
+
{
|
49
|
+
"name": "secret",
|
50
|
+
"secret": {
|
51
|
+
"path": referenced_secret_path,
|
52
|
+
"field": "db.endpoint",
|
92
53
|
},
|
93
|
-
"name": "job",
|
94
54
|
},
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
],
|
105
|
-
},
|
106
|
-
],
|
107
|
-
},
|
108
|
-
],
|
109
|
-
"selfServiceRoles": [
|
110
|
-
{"users": [{"org_username": "theirname"}], "bots": []}
|
111
|
-
],
|
112
|
-
},
|
113
|
-
)
|
55
|
+
],
|
56
|
+
},
|
57
|
+
],
|
58
|
+
},
|
59
|
+
],
|
60
|
+
"selfServiceRoles": [
|
61
|
+
{"users": [{"org_username": "theirname"}], "bots": []}
|
62
|
+
],
|
63
|
+
},
|
114
64
|
]
|
115
65
|
|
116
66
|
saasherder = SaasHerder(
|
117
67
|
saas_files,
|
118
|
-
secret_reader=secret_reader,
|
119
68
|
thread_pool_size=1,
|
69
|
+
gitlab=None,
|
120
70
|
integration="",
|
121
71
|
integration_version="",
|
122
|
-
|
123
|
-
repo_url="https://repo-url.com",
|
72
|
+
settings={},
|
124
73
|
validate=True,
|
125
74
|
)
|
126
75
|
|
@@ -2,29 +2,24 @@ import hashlib
|
|
2
2
|
import json
|
3
3
|
import logging
|
4
4
|
from collections.abc import (
|
5
|
-
|
5
|
+
Mapping,
|
6
6
|
MutableMapping,
|
7
7
|
)
|
8
8
|
from dataclasses import (
|
9
9
|
asdict,
|
10
10
|
dataclass,
|
11
11
|
)
|
12
|
-
from typing import
|
13
|
-
Any,
|
14
|
-
Sequence,
|
15
|
-
Union,
|
16
|
-
)
|
12
|
+
from typing import Any
|
17
13
|
|
18
14
|
from ruamel import yaml
|
19
15
|
|
20
|
-
from reconcile.utils.gitlab_api import GitLabApi
|
21
16
|
from reconcile.utils.mr.base import MergeRequestBase
|
22
17
|
from reconcile.utils.mr.labels import AUTO_MERGE
|
23
|
-
from reconcile.utils.saasherder.interfaces import SaasPromotion
|
24
|
-
from reconcile.utils.saasherder.models import Promotion
|
25
18
|
|
26
19
|
LOG = logging.getLogger(__name__)
|
27
20
|
|
21
|
+
TARGET_CONFIG_HASH = "target_config_hash"
|
22
|
+
|
28
23
|
|
29
24
|
@dataclass
|
30
25
|
class ParentSaasConfigPromotion:
|
@@ -37,21 +32,10 @@ class ParentSaasConfigPromotion:
|
|
37
32
|
class AutoPromoter(MergeRequestBase):
|
38
33
|
name = "auto_promoter"
|
39
34
|
|
40
|
-
def __init__(
|
41
|
-
self
|
42
|
-
):
|
43
|
-
# !!! Attention !!!
|
44
|
-
# AutoPromoter is also initialized with promitions as dict by 'gitlab_mr_sqs_consumer'
|
45
|
-
# loaded from SQS message body, therefore self.promotions must be json serializable
|
46
|
-
self.promotions = [
|
47
|
-
p.dict(by_alias=True) if isinstance(p, SaasPromotion) else p
|
48
|
-
for p in promotions
|
49
|
-
]
|
50
|
-
|
51
|
-
# the parent class stores self.promotions (the json serializable one) in self.sqs_msg_data
|
35
|
+
def __init__(self, promotions):
|
36
|
+
self.promotions = [p for p in promotions if p]
|
52
37
|
super().__init__()
|
53
|
-
|
54
|
-
self._promotions = [Promotion(**p) for p in self.promotions]
|
38
|
+
|
55
39
|
self.labels = [AUTO_MERGE]
|
56
40
|
|
57
41
|
@property
|
@@ -71,19 +55,18 @@ class AutoPromoter(MergeRequestBase):
|
|
71
55
|
return "openshift-saas-deploy automated promotion"
|
72
56
|
|
73
57
|
@staticmethod
|
74
|
-
def init_promotion_data(
|
58
|
+
def init_promotion_data(
|
59
|
+
channel: str, promotion: Mapping[str, Any]
|
60
|
+
) -> dict[str, Any]:
|
75
61
|
psc = ParentSaasConfigPromotion(
|
76
|
-
parent_saas=promotion
|
77
|
-
target_config_hash=promotion
|
62
|
+
parent_saas=promotion["saas_file"],
|
63
|
+
target_config_hash=promotion[TARGET_CONFIG_HASH],
|
78
64
|
)
|
79
65
|
return {"channel": channel, "data": [asdict(psc)]}
|
80
66
|
|
81
67
|
@staticmethod
|
82
|
-
def process_promotion(
|
83
|
-
|
84
|
-
target_promotion: MutableMapping[str, Any],
|
85
|
-
target_channels: Iterable[str],
|
86
|
-
) -> bool:
|
68
|
+
def process_promotion(promotion, target_promotion, target_channels):
|
69
|
+
|
87
70
|
# Existent subscribe data channel data
|
88
71
|
promotion_data = {
|
89
72
|
v["channel"]: v["data"]
|
@@ -106,17 +89,20 @@ class AutoPromoter(MergeRequestBase):
|
|
106
89
|
if item["type"] == ParentSaasConfigPromotion.TYPE:
|
107
90
|
target_psc = ParentSaasConfigPromotion(**item)
|
108
91
|
promotion_psc = ParentSaasConfigPromotion(
|
109
|
-
parent_saas=promotion
|
110
|
-
target_config_hash=promotion
|
92
|
+
parent_saas=promotion["saas_file"],
|
93
|
+
target_config_hash=promotion[TARGET_CONFIG_HASH],
|
111
94
|
)
|
112
95
|
if target_psc != promotion_psc:
|
113
96
|
channel_data[i] = asdict(promotion_psc)
|
114
97
|
modified = True
|
115
98
|
|
116
|
-
|
99
|
+
return modified
|
117
100
|
|
118
101
|
def process_target(
|
119
|
-
self,
|
102
|
+
self,
|
103
|
+
target: MutableMapping[str, Any],
|
104
|
+
promotion_item: Mapping[str, Any],
|
105
|
+
commit_sha: str,
|
120
106
|
) -> bool:
|
121
107
|
target_updated = False
|
122
108
|
target_promotion = target.get("promotion")
|
@@ -128,31 +114,37 @@ class AutoPromoter(MergeRequestBase):
|
|
128
114
|
subscribe = target_promotion.get("subscribe")
|
129
115
|
if not subscribe:
|
130
116
|
return target_updated
|
131
|
-
if not promotion.publish:
|
132
|
-
return target_updated
|
133
117
|
|
134
|
-
channels = [c for c in subscribe if c in
|
135
|
-
if channels:
|
118
|
+
channels = [c for c in subscribe if c in promotion_item["publish"]]
|
119
|
+
if len(channels) > 0:
|
136
120
|
# Update REF on target if differs.
|
137
|
-
if target["ref"] !=
|
138
|
-
target["ref"] =
|
121
|
+
if target["ref"] != commit_sha:
|
122
|
+
target["ref"] = commit_sha
|
139
123
|
target_updated = True
|
140
124
|
|
141
125
|
# Update Promotion data
|
142
|
-
modified = self.process_promotion(
|
126
|
+
modified = self.process_promotion(
|
127
|
+
promotion_item, target_promotion, channels
|
128
|
+
)
|
143
129
|
|
144
130
|
if modified:
|
145
131
|
target_updated = True
|
146
132
|
|
147
133
|
return target_updated
|
148
134
|
|
149
|
-
def process(self, gitlab_cli
|
150
|
-
for
|
151
|
-
|
135
|
+
def process(self, gitlab_cli):
|
136
|
+
for item in self.promotions:
|
137
|
+
saas_file_paths = item.get("saas_file_paths") or []
|
138
|
+
target_paths = item.get("target_paths") or []
|
139
|
+
if not (saas_file_paths or target_paths):
|
140
|
+
continue
|
141
|
+
publish = item.get("publish")
|
142
|
+
if not publish:
|
152
143
|
continue
|
153
|
-
|
144
|
+
commit_sha = item.get("commit_sha")
|
145
|
+
if not commit_sha:
|
154
146
|
continue
|
155
|
-
for saas_file_path in
|
147
|
+
for saas_file_path in saas_file_paths:
|
156
148
|
saas_file_updated = False
|
157
149
|
try:
|
158
150
|
# This will only work with gitlab cli, not with SQS
|
@@ -168,13 +160,13 @@ class AutoPromoter(MergeRequestBase):
|
|
168
160
|
|
169
161
|
for rt in content["resourceTemplates"]:
|
170
162
|
for target in rt["targets"]:
|
171
|
-
if self.process_target(target,
|
163
|
+
if self.process_target(target, item, commit_sha):
|
172
164
|
saas_file_updated = True
|
173
165
|
|
174
166
|
if saas_file_updated:
|
175
167
|
new_content = "---\n"
|
176
|
-
new_content += yaml.dump(content, Dumper=yaml.RoundTripDumper)
|
177
|
-
msg = f"auto promote {
|
168
|
+
new_content += yaml.dump(content, Dumper=yaml.RoundTripDumper)
|
169
|
+
msg = f"auto promote {commit_sha} in {saas_file_path}"
|
178
170
|
gitlab_cli.update_file(
|
179
171
|
branch_name=self.branch,
|
180
172
|
file_path=saas_file_path,
|
@@ -183,12 +175,12 @@ class AutoPromoter(MergeRequestBase):
|
|
183
175
|
)
|
184
176
|
else:
|
185
177
|
LOG.info(
|
186
|
-
f"commit sha {
|
178
|
+
f"commit sha {commit_sha} has already been "
|
187
179
|
f"promoted to all targets in {content['name']} "
|
188
|
-
f"subscribing to {','.join(
|
180
|
+
f"subscribing to {','.join(item['publish'])}"
|
189
181
|
)
|
190
182
|
|
191
|
-
for target_path in
|
183
|
+
for target_path in target_paths:
|
192
184
|
try:
|
193
185
|
# This will only work with gitlab cli, not with SQS
|
194
186
|
# this method is only triggered by gitlab_sqs_consumer
|
@@ -200,10 +192,10 @@ class AutoPromoter(MergeRequestBase):
|
|
200
192
|
logging.error(e)
|
201
193
|
|
202
194
|
content = yaml.load(raw_file.decode(), Loader=yaml.RoundTripLoader)
|
203
|
-
if self.process_target(content,
|
195
|
+
if self.process_target(content, item, commit_sha):
|
204
196
|
new_content = "---\n"
|
205
|
-
new_content += yaml.dump(content, Dumper=yaml.RoundTripDumper)
|
206
|
-
msg = f"auto promote {
|
197
|
+
new_content += yaml.dump(content, Dumper=yaml.RoundTripDumper)
|
198
|
+
msg = f"auto promote {commit_sha} in {target_path}"
|
207
199
|
gitlab_cli.update_file(
|
208
200
|
branch_name=self.branch,
|
209
201
|
file_path=target_path,
|
@@ -212,7 +204,7 @@ class AutoPromoter(MergeRequestBase):
|
|
212
204
|
)
|
213
205
|
else:
|
214
206
|
LOG.info(
|
215
|
-
f"commit sha {
|
207
|
+
f"commit sha {commit_sha} has already been "
|
216
208
|
f"promoted to all targets in {content['name']} "
|
217
|
-
f"subscribing to {','.join(
|
209
|
+
f"subscribing to {','.join(item['publish'])}"
|
218
210
|
)
|
reconcile/utils/mr/base.py
CHANGED
@@ -4,7 +4,6 @@ from abc import (
|
|
4
4
|
ABCMeta,
|
5
5
|
abstractmethod,
|
6
6
|
)
|
7
|
-
from typing import Union
|
8
7
|
from uuid import uuid4
|
9
8
|
|
10
9
|
from gitlab.exceptions import GitlabError
|
@@ -28,9 +27,6 @@ class MergeRequestProcessingError(Exception):
|
|
28
27
|
"""
|
29
28
|
|
30
29
|
|
31
|
-
MRClient = Union[GitLabApi, SQSGateway]
|
32
|
-
|
33
|
-
|
34
30
|
class MergeRequestBase(metaclass=ABCMeta):
|
35
31
|
"""
|
36
32
|
Base abstract class for all merge request types.
|
@@ -106,7 +102,7 @@ class MergeRequestBase(metaclass=ABCMeta):
|
|
106
102
|
**self.sqs_msg_data,
|
107
103
|
}
|
108
104
|
|
109
|
-
def submit_to_sqs(self, sqs_cli)
|
105
|
+
def submit_to_sqs(self, sqs_cli):
|
110
106
|
"""
|
111
107
|
Sends the MR message to SQS.
|
112
108
|
|
@@ -204,7 +200,7 @@ class MergeRequestBase(metaclass=ABCMeta):
|
|
204
200
|
from_=self.main_branch, to=self.branch
|
205
201
|
)["diffs"]
|
206
202
|
|
207
|
-
def submit(self, cli
|
203
|
+
def submit(self, cli):
|
208
204
|
if isinstance(cli, GitLabApi):
|
209
205
|
return self.submit_to_gitlab(gitlab_cli=cli)
|
210
206
|
|