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.
Files changed (30) hide show
  1. {qontract_reconcile-0.9.1rc162.dist-info → qontract_reconcile-0.9.1rc164.dist-info}/METADATA +2 -2
  2. {qontract_reconcile-0.9.1rc162.dist-info → qontract_reconcile-0.9.1rc164.dist-info}/RECORD +21 -30
  3. reconcile/glitchtip_project_dsn/integration.py +3 -0
  4. reconcile/jenkins_job_builder.py +2 -5
  5. reconcile/openshift_base.py +11 -11
  6. reconcile/openshift_saas_deploy.py +52 -57
  7. reconcile/openshift_saas_deploy_trigger_base.py +48 -55
  8. reconcile/openshift_saas_deploy_trigger_cleaner.py +2 -2
  9. reconcile/openshift_tekton_resources.py +1 -1
  10. reconcile/saas_file_validator.py +10 -23
  11. reconcile/slack_base.py +2 -5
  12. reconcile/test/conftest.py +0 -11
  13. reconcile/test/test_auto_promoter.py +42 -199
  14. reconcile/test/test_saasherder.py +463 -398
  15. reconcile/test/test_saasherder_allowed_secret_paths.py +36 -87
  16. reconcile/utils/mr/auto_promoter.py +50 -58
  17. reconcile/utils/mr/base.py +2 -6
  18. reconcile/utils/{saasherder/saasherder.py → saasherder.py} +736 -656
  19. reconcile/gql_definitions/common/app_code_component_repos.py +0 -68
  20. reconcile/gql_definitions/common/saas_files.py +0 -542
  21. reconcile/gql_definitions/common/saasherder_settings.py +0 -62
  22. reconcile/gql_definitions/fragments/oc_connection_cluster.py +0 -47
  23. reconcile/typed_queries/repos.py +0 -17
  24. reconcile/typed_queries/saas_files.py +0 -61
  25. reconcile/utils/saasherder/__init__.py +0 -17
  26. reconcile/utils/saasherder/interfaces.py +0 -404
  27. reconcile/utils/saasherder/models.py +0 -203
  28. {qontract_reconcile-0.9.1rc162.dist-info → qontract_reconcile-0.9.1rc164.dist-info}/WHEEL +0 -0
  29. {qontract_reconcile-0.9.1rc162.dist-info → qontract_reconcile-0.9.1rc164.dist-info}/entry_points.txt +0 -0
  30. {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
- gql_class_factory(
38
- SaasFileV2,
39
- {
40
- "path": "path1",
41
- "name": "a1",
42
- "managedResourceTypes": [],
43
- "allowedSecretParameterPaths": [allowed_secret_parameter_path],
44
- "app": {"name": "app1"},
45
- "pipelinesProvider": {
46
- "name": "tekton-app-sre-pipelines-appsres03ue1",
47
- "provider": "tekton",
48
- "namespace": {
49
- "name": "app-sre-pipelines",
50
- "cluster": {
51
- "name": "appsres03ue1",
52
- "serverUrl": "https://api.appsres03ue1.5nvu.p1.openshiftapps.com:6443",
53
- "consoleUrl": "https://console.appsres03ue1.5nvu.p1.openshiftapps.com:6443",
54
- "internal": True,
55
- },
56
- },
57
- "defaults": {
58
- "pipelineTemplates": {
59
- "openshiftSaasDeploy": {"name": "openshift-saas-deploy"}
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
- "parameters": "{}",
96
- "secretParameters": [
97
- {
98
- "name": "secret",
99
- "secret": {
100
- "path": referenced_secret_path,
101
- "field": "db.endpoint",
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
- hash_length=7,
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
- Iterable,
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, promotions: Union[Sequence[SaasPromotion], Sequence[dict[str, Any]]]
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
- # create an internal list with Promotion objects out of self.promotions
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(channel: str, promotion: SaasPromotion) -> dict[str, Any]:
58
+ def init_promotion_data(
59
+ channel: str, promotion: Mapping[str, Any]
60
+ ) -> dict[str, Any]:
75
61
  psc = ParentSaasConfigPromotion(
76
- parent_saas=promotion.saas_file_name,
77
- target_config_hash=promotion.target_config_hash,
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
- promotion: SaasPromotion,
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.saas_file_name,
110
- target_config_hash=promotion.target_config_hash,
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
- return modified
99
+ return modified
117
100
 
118
101
  def process_target(
119
- self, target: MutableMapping[str, Any], promotion: SaasPromotion
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 promotion.publish]
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"] != promotion.commit_sha:
138
- target["ref"] = promotion.commit_sha
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(promotion, target_promotion, channels)
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: GitLabApi) -> None:
150
- for promotion in self._promotions:
151
- if not promotion.publish:
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
- if not promotion.commit_sha:
144
+ commit_sha = item.get("commit_sha")
145
+ if not commit_sha:
154
146
  continue
155
- for saas_file_path in promotion.saas_file_paths or []:
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, promotion):
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) or ""
177
- msg = f"auto promote {promotion.commit_sha} in {saas_file_path}"
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 {promotion.commit_sha} has already been "
178
+ f"commit sha {commit_sha} has already been "
187
179
  f"promoted to all targets in {content['name']} "
188
- f"subscribing to {','.join(promotion.publish)}"
180
+ f"subscribing to {','.join(item['publish'])}"
189
181
  )
190
182
 
191
- for target_path in promotion.target_paths or []:
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, promotion):
195
+ if self.process_target(content, item, commit_sha):
204
196
  new_content = "---\n"
205
- new_content += yaml.dump(content, Dumper=yaml.RoundTripDumper) # type: ignore
206
- msg = f"auto promote {promotion.commit_sha} in {target_path}"
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 {promotion.commit_sha} has already been "
207
+ f"commit sha {commit_sha} has already been "
216
208
  f"promoted to all targets in {content['name']} "
217
- f"subscribing to {','.join(promotion.publish)}"
209
+ f"subscribing to {','.join(item['publish'])}"
218
210
  )
@@ -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) -> None:
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: MRClient):
203
+ def submit(self, cli):
208
204
  if isinstance(cli, GitLabApi):
209
205
  return self.submit_to_gitlab(gitlab_cli=cli)
210
206