qontract-reconcile 0.10.1rc885__py3-none-any.whl → 0.10.1rc887__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.10.1rc885.dist-info → qontract_reconcile-0.10.1rc887.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc885.dist-info → qontract_reconcile-0.10.1rc887.dist-info}/RECORD +13 -10
- reconcile/saas_auto_promotions_manager/subscriber.py +33 -11
- reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py +8 -0
- reconcile/test/saas_auto_promotions_manager/conftest.py +1 -0
- tools/qontract_cli.py +19 -0
- tools/saas_promotion_state/__init__.py +0 -0
- tools/saas_promotion_state/saas_promotion_state.py +72 -0
- tools/test/conftest.py +42 -0
- tools/test/test_saas_promotion_state.py +86 -0
- {qontract_reconcile-0.10.1rc885.dist-info → qontract_reconcile-0.10.1rc887.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc885.dist-info → qontract_reconcile-0.10.1rc887.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc885.dist-info → qontract_reconcile-0.10.1rc887.dist-info}/top_level.txt +0 -0
{qontract_reconcile-0.10.1rc885.dist-info → qontract_reconcile-0.10.1rc887.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: qontract-reconcile
|
3
|
-
Version: 0.10.
|
3
|
+
Version: 0.10.1rc887
|
4
4
|
Summary: Collection of tools to reconcile services with their desired state as defined in the app-interface DB.
|
5
5
|
Home-page: https://github.com/app-sre/qontract-reconcile
|
6
6
|
Author: Red Hat App-SRE Team
|
{qontract_reconcile-0.10.1rc885.dist-info → qontract_reconcile-0.10.1rc887.dist-info}/RECORD
RENAMED
@@ -428,7 +428,7 @@ reconcile/saas_auto_promotions_manager/integration.py,sha256=haXTpwi0rEQtN9-MadB
|
|
428
428
|
reconcile/saas_auto_promotions_manager/meta.py,sha256=76Jp50r6Y_KyJoXFfSjrt5YrCtXyg_A4FXXxHYiS3TE,161
|
429
429
|
reconcile/saas_auto_promotions_manager/publisher.py,sha256=IZGu-PMffyk3fNL8QcZ2VBmYTZ5zigoCwNJ4_Ak6-C8,2966
|
430
430
|
reconcile/saas_auto_promotions_manager/s3_exporter.py,sha256=IKlVWZmiPnvl7sKeF6JgAlhXZe5CovKTxQc0SNkNSx4,2583
|
431
|
-
reconcile/saas_auto_promotions_manager/subscriber.py,sha256=
|
431
|
+
reconcile/saas_auto_promotions_manager/subscriber.py,sha256=A-d_qIUo5jbseEaAN3YlVU46MQAVCw28j5HvORgaGtw,9149
|
432
432
|
reconcile/saas_auto_promotions_manager/merge_request_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
433
433
|
reconcile/saas_auto_promotions_manager/merge_request_manager/batcher.py,sha256=CP392gq0yntzEkqpMJl2j-N4CGfFDFbBfK77J7Oo5Pg,7817
|
434
434
|
reconcile/saas_auto_promotions_manager/merge_request_manager/desired_state.py,sha256=isY8frVsL3PlcdZmdZ4O0qyp76oczl4DUMX9uMArs5Y,1222
|
@@ -439,7 +439,7 @@ reconcile/saas_auto_promotions_manager/merge_request_manager/mr_parser.py,sha256
|
|
439
439
|
reconcile/saas_auto_promotions_manager/merge_request_manager/open_merge_requests.py,sha256=-qGQOh6Jdp4lomNDij3zWVC0pl6uPHFWS5Woqcp5HQk,410
|
440
440
|
reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py,sha256=IZ7cuH6uOi7f0aIPVi1irBmP0CIK5vmEuhKBJz4YA1s,7235
|
441
441
|
reconcile/saas_auto_promotions_manager/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
442
|
-
reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py,sha256=
|
442
|
+
reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py,sha256=rGvBWGcpryM-W3nasBET-PHAXY2ZZL9ihcTe70qoQEA,8660
|
443
443
|
reconcile/skupper_network/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
444
444
|
reconcile/skupper_network/integration.py,sha256=GEFlQTjK4DYXnvrQtsvFdZlYsbiFabM7IdBX69ZXWcY,10757
|
445
445
|
reconcile/skupper_network/models.py,sha256=HEwlVKsbmMaKaaBGvITIiSYNEVdjwXVhLaOJgLSZ2xQ,6604
|
@@ -560,7 +560,7 @@ reconcile/test/test_version_bump.py,sha256=q6-3Y1roriI6YWpFwaHOMN7emEP3yL33sh_0V
|
|
560
560
|
reconcile/test/test_vpc_peerings_validator.py,sha256=dFSmjc_dMN2GqMbntCFpa7PUZmyYuQ9DKffh-T5wmxM,6639
|
561
561
|
reconcile/test/test_wrong_region.py,sha256=7KzL7OaICQ9Z3DW27zt_ykMN7_87owAFC-2CYjvGoyA,2138
|
562
562
|
reconcile/test/saas_auto_promotions_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
563
|
-
reconcile/test/saas_auto_promotions_manager/conftest.py,sha256=
|
563
|
+
reconcile/test/saas_auto_promotions_manager/conftest.py,sha256=tF6YMgeh9PHxlKsihL8qdLEgixk_k6mOGV1qS7ukHYI,6029
|
564
564
|
reconcile/test/saas_auto_promotions_manager/test_integration_test.py,sha256=S30eXJSy2Vc3YLbCP7AfLkOiFGUVoKhEvEBL5vwnbfg,1848
|
565
565
|
reconcile/test/saas_auto_promotions_manager/merge_request_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
566
566
|
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -810,7 +810,7 @@ tools/app_interface_metrics_exporter.py,sha256=zkwkxdAUAxjdc-pzx2_oJXG25fo0Fnyd5
|
|
810
810
|
tools/app_interface_reporter.py,sha256=uy9eRHf6EdvD8ZY2WYdroGXm18DOdnqVZyxaWN3Bm_0,17724
|
811
811
|
tools/glitchtip_access_reporter.py,sha256=oPBnk_YoDuljU3v0FaChzOwwnk4vap1xEE67QEjzdqs,2948
|
812
812
|
tools/glitchtip_access_revalidation.py,sha256=8kbBJk04mkq28kWoRDDkfCGIF3GRg3pJrFAh1sW0dbk,2821
|
813
|
-
tools/qontract_cli.py,sha256=
|
813
|
+
tools/qontract_cli.py,sha256=PYFiVIc37qFOl3UxXt04o-V50Leu37pAFndTRMu_WBs,121059
|
814
814
|
tools/sd_app_sre_alert_report.py,sha256=e9vAdyenUz2f5c8-z-5WY0wv-SJ9aePKDH2r4IwB6pc,5063
|
815
815
|
tools/template_validation.py,sha256=qpKYaTgk0GOPGa2Ct5_5sKdwIHtCAKIBGzsMPuJU5fw,3371
|
816
816
|
tools/cli_commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -830,16 +830,19 @@ tools/saas_metrics_exporter/commit_distance/__init__.py,sha256=47DEQpj8HBSa-_TIm
|
|
830
830
|
tools/saas_metrics_exporter/commit_distance/channel.py,sha256=XEAh3eL8TmgMe7V2BsyxuXYWgvBBVdSJETd6Ec7cI04,2171
|
831
831
|
tools/saas_metrics_exporter/commit_distance/commit_distance.py,sha256=pUWaZfZf0TYOwAW0gDdU8cYgTR586J_8S_DWxqHMWNA,3116
|
832
832
|
tools/saas_metrics_exporter/commit_distance/metrics.py,sha256=5-y6n-sGACAS3eJ5ndY-2BFxcd0fxLfhvZmmBHu4JuA,426
|
833
|
+
tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
834
|
+
tools/saas_promotion_state/saas_promotion_state.py,sha256=_jP9E8-VcWho6FIOGdcjNN6uvMVhpdXOMHw59qNnEmE,2855
|
833
835
|
tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
|
834
836
|
tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
|
835
837
|
tools/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
836
|
-
tools/test/conftest.py,sha256=
|
838
|
+
tools/test/conftest.py,sha256=YLtiauk_StNFE-lirLnfG_BpJmlB2NGMZISE9A4zwvk,2421
|
837
839
|
tools/test/test_app_interface_metrics_exporter.py,sha256=SX7qL3D1SIRKFo95FoQztvftCWEEf-g1mfXOtgCog-g,1271
|
838
840
|
tools/test/test_qontract_cli.py,sha256=_D61RFGAN5x44CY1tYbouhlGXXABwYfxKSWSQx3Jrss,4941
|
841
|
+
tools/test/test_saas_promotion_state.py,sha256=48Qe5UA5WTI5NVgL7Nz0TSS77osetcijfHNCNdsHfSI,2726
|
839
842
|
tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
|
840
843
|
tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
|
841
|
-
qontract_reconcile-0.10.
|
842
|
-
qontract_reconcile-0.10.
|
843
|
-
qontract_reconcile-0.10.
|
844
|
-
qontract_reconcile-0.10.
|
845
|
-
qontract_reconcile-0.10.
|
844
|
+
qontract_reconcile-0.10.1rc887.dist-info/METADATA,sha256=hsI7-7-pLKcnuPvfEEaiX0kI_9dg2RVn3ADXezJXa1Q,2273
|
845
|
+
qontract_reconcile-0.10.1rc887.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
846
|
+
qontract_reconcile-0.10.1rc887.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
|
847
|
+
qontract_reconcile-0.10.1rc887.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
|
848
|
+
qontract_reconcile-0.10.1rc887.dist-info/RECORD,,
|
@@ -44,6 +44,7 @@ class Subscriber:
|
|
44
44
|
use_target_config_hash: bool,
|
45
45
|
uid: str,
|
46
46
|
soak_days: int,
|
47
|
+
blocked_versions: set[str],
|
47
48
|
):
|
48
49
|
self.saas_name = saas_name
|
49
50
|
self.template_name = template_name
|
@@ -58,6 +59,7 @@ class Subscriber:
|
|
58
59
|
self.soak_days = soak_days
|
59
60
|
self._content_hash = ""
|
60
61
|
self._use_target_config_hash = use_target_config_hash
|
62
|
+
self._blocked_versions = blocked_versions
|
61
63
|
|
62
64
|
def has_diff(self) -> bool:
|
63
65
|
current_hashes = {
|
@@ -141,22 +143,42 @@ class Subscriber:
|
|
141
143
|
break
|
142
144
|
publisher_refs.add(publisher.commit_sha)
|
143
145
|
|
144
|
-
|
146
|
+
# By default we keep current state
|
147
|
+
self.desired_ref = self.ref
|
148
|
+
|
149
|
+
if any_bad_deployment:
|
150
|
+
logging.info(
|
151
|
+
"Subscriber at path %s promotion stopped because of bad publisher deployment",
|
152
|
+
self.target_file_path,
|
153
|
+
)
|
154
|
+
return
|
155
|
+
|
156
|
+
if len(publisher_refs) != 1:
|
145
157
|
logging.info(
|
146
158
|
"Publishers for subscriber at path %s have mismatching refs: %s",
|
147
159
|
self.target_file_path,
|
148
160
|
publisher_refs,
|
149
161
|
)
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
162
|
+
return
|
163
|
+
|
164
|
+
if not self._passed_accumulated_soak_days():
|
165
|
+
logging.debug(
|
166
|
+
"Subscriber at path %s promotion stopped because of soak days",
|
167
|
+
self.target_file_path,
|
168
|
+
)
|
169
|
+
return
|
170
|
+
|
171
|
+
desired_ref = next(iter(publisher_refs))
|
172
|
+
if desired_ref in self._blocked_versions:
|
173
|
+
logging.info(
|
174
|
+
"Subscriber at path %s promotion stopped because of blocked ref: %s",
|
175
|
+
self.target_file_path,
|
176
|
+
desired_ref,
|
177
|
+
)
|
178
|
+
return
|
179
|
+
|
180
|
+
# Passed all gates -> lets promote desired ref
|
181
|
+
self.desired_ref = desired_ref
|
160
182
|
|
161
183
|
def _compute_desired_config_hashes(self) -> None:
|
162
184
|
"""
|
@@ -86,6 +86,10 @@ class SaasFilesInventory:
|
|
86
86
|
|
87
87
|
def _assemble_subscribers_with_auto_promotions(self) -> None:
|
88
88
|
for saas_file in self._saas_files:
|
89
|
+
blocked_versions: dict[str, set[str]] = {}
|
90
|
+
for code_component in saas_file.app.code_components or []:
|
91
|
+
for version in code_component.blocked_versions or []:
|
92
|
+
blocked_versions.setdefault(code_component.url, set()).add(version)
|
89
93
|
for resource_template in saas_file.resource_templates:
|
90
94
|
for target in resource_template.targets:
|
91
95
|
file_path = target.path if target.path else saas_file.path
|
@@ -98,6 +102,7 @@ class SaasFilesInventory:
|
|
98
102
|
soak_days = (
|
99
103
|
target.promotion.soak_days if target.promotion.soak_days else 0
|
100
104
|
)
|
105
|
+
resource_template.url
|
101
106
|
subscriber = Subscriber(
|
102
107
|
uid=target.uid(
|
103
108
|
parent_saas_file_name=saas_file.name,
|
@@ -109,6 +114,9 @@ class SaasFilesInventory:
|
|
109
114
|
ref=target.ref,
|
110
115
|
target_namespace=target.namespace,
|
111
116
|
soak_days=soak_days,
|
117
|
+
blocked_versions=blocked_versions.get(
|
118
|
+
resource_template.url, set()
|
119
|
+
),
|
112
120
|
# Note: this will be refactored at a later point.
|
113
121
|
# https://issues.redhat.com/browse/APPSRE-7516
|
114
122
|
use_target_config_hash=bool(saas_file.publish_job_logs),
|
@@ -158,6 +158,7 @@ def subscriber_builder(
|
|
158
158
|
template_name="",
|
159
159
|
use_target_config_hash=data.get("USE_TARGET_CONFIG_HASH", True),
|
160
160
|
soak_days=data.get("SOAK_DAYS", 0),
|
161
|
+
blocked_versions=data.get("BLOCKED_VERSIONS", {}),
|
161
162
|
)
|
162
163
|
subscriber.channels = channels
|
163
164
|
subscriber.config_hashes_by_channel_name = cur_config_hashes_by_channel
|
tools/qontract_cli.py
CHANGED
@@ -3658,6 +3658,25 @@ def gpg_encrypt(
|
|
3658
3658
|
).execute()
|
3659
3659
|
|
3660
3660
|
|
3661
|
+
@root.command()
|
3662
|
+
@click.option("--channel", help="the channel that state is part of")
|
3663
|
+
@click.option("--sha", help="the commit sha we want state for")
|
3664
|
+
@environ(["APP_INTERFACE_STATE_BUCKET"])
|
3665
|
+
def get_promotion_state(channel: str, sha: str):
|
3666
|
+
from tools.saas_promotion_state.saas_promotion_state import (
|
3667
|
+
SaasPromotionState,
|
3668
|
+
)
|
3669
|
+
|
3670
|
+
promotion_state = SaasPromotionState.create(promotion_state=None, saas_files=None)
|
3671
|
+
for publisher_id, state in promotion_state.get(channel=channel, sha=sha).items():
|
3672
|
+
print()
|
3673
|
+
if not state:
|
3674
|
+
print(f"No state found for {publisher_id=}")
|
3675
|
+
else:
|
3676
|
+
print(f"State for {publisher_id=}:")
|
3677
|
+
print(state)
|
3678
|
+
|
3679
|
+
|
3661
3680
|
@root.command()
|
3662
3681
|
@click.option("--change-type-name")
|
3663
3682
|
@click.option("--role-name")
|
File without changes
|
@@ -0,0 +1,72 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from collections.abc import Iterable
|
4
|
+
|
5
|
+
from reconcile.openshift_saas_deploy import (
|
6
|
+
QONTRACT_INTEGRATION as OPENSHIFT_SAAS_DEPLOY,
|
7
|
+
)
|
8
|
+
from reconcile.typed_queries.app_interface_vault_settings import (
|
9
|
+
get_app_interface_vault_settings,
|
10
|
+
)
|
11
|
+
from reconcile.typed_queries.saas_files import SaasFile, get_saas_files
|
12
|
+
from reconcile.utils.promotion_state import PromotionData, PromotionState
|
13
|
+
from reconcile.utils.secret_reader import create_secret_reader
|
14
|
+
from reconcile.utils.state import init_state
|
15
|
+
|
16
|
+
|
17
|
+
class SaasPromotionState:
|
18
|
+
def __init__(
|
19
|
+
self, promotion_state: PromotionState, saas_files: Iterable[SaasFile]
|
20
|
+
) -> None:
|
21
|
+
self._promotion_state = promotion_state
|
22
|
+
self._saas_files = saas_files
|
23
|
+
|
24
|
+
def _publisher_ids_for_channel(
|
25
|
+
self, channel: str, saas_files: Iterable[SaasFile]
|
26
|
+
) -> list[str]:
|
27
|
+
publisher_uids: list[str] = []
|
28
|
+
for saas_file in saas_files:
|
29
|
+
for resource_template in saas_file.resource_templates:
|
30
|
+
for target in resource_template.targets:
|
31
|
+
if not target.promotion:
|
32
|
+
continue
|
33
|
+
for publish_channel in target.promotion.publish or []:
|
34
|
+
if publish_channel == channel:
|
35
|
+
publisher_uids.append(
|
36
|
+
target.uid(
|
37
|
+
parent_saas_file_name=saas_file.name,
|
38
|
+
parent_resource_template_name=resource_template.name,
|
39
|
+
)
|
40
|
+
)
|
41
|
+
return publisher_uids
|
42
|
+
|
43
|
+
def get(self, channel: str, sha: str) -> dict[str, PromotionData | None]:
|
44
|
+
return {
|
45
|
+
publisher_id: self._promotion_state.get_promotion_data(
|
46
|
+
sha=sha,
|
47
|
+
channel=channel,
|
48
|
+
use_cache=False,
|
49
|
+
target_uid=publisher_id,
|
50
|
+
pre_check_sha_exists=False,
|
51
|
+
)
|
52
|
+
for publisher_id in self._publisher_ids_for_channel(
|
53
|
+
channel=channel, saas_files=self._saas_files
|
54
|
+
)
|
55
|
+
}
|
56
|
+
|
57
|
+
@staticmethod
|
58
|
+
def create(
|
59
|
+
promotion_state: PromotionState | None, saas_files: Iterable[SaasFile] | None
|
60
|
+
) -> SaasPromotionState:
|
61
|
+
if not promotion_state:
|
62
|
+
vault_settings = get_app_interface_vault_settings()
|
63
|
+
secret_reader = create_secret_reader(use_vault=vault_settings.vault)
|
64
|
+
saas_deploy_state = init_state(
|
65
|
+
integration=OPENSHIFT_SAAS_DEPLOY, secret_reader=secret_reader
|
66
|
+
)
|
67
|
+
promotion_state = PromotionState(state=saas_deploy_state)
|
68
|
+
if not saas_files:
|
69
|
+
saas_files = get_saas_files()
|
70
|
+
return SaasPromotionState(
|
71
|
+
promotion_state=promotion_state, saas_files=saas_files
|
72
|
+
)
|
tools/test/conftest.py
CHANGED
@@ -1,13 +1,17 @@
|
|
1
1
|
from collections.abc import (
|
2
2
|
Callable,
|
3
|
+
Iterable,
|
4
|
+
Mapping,
|
3
5
|
MutableMapping,
|
4
6
|
)
|
7
|
+
from pathlib import Path
|
5
8
|
from typing import Any
|
6
9
|
|
7
10
|
import pytest
|
8
11
|
from pydantic import BaseModel
|
9
12
|
from pydantic.error_wrappers import ValidationError
|
10
13
|
|
14
|
+
from reconcile.typed_queries.saas_files import SaasFile
|
11
15
|
from reconcile.utils.models import data_default_none
|
12
16
|
|
13
17
|
|
@@ -15,6 +19,44 @@ class GQLClassFactoryError(Exception):
|
|
15
19
|
pass
|
16
20
|
|
17
21
|
|
22
|
+
@pytest.fixture
|
23
|
+
def saas_files_builder(
|
24
|
+
gql_class_factory: Callable[[type[SaasFile], Mapping], SaasFile],
|
25
|
+
) -> Callable[[Iterable[MutableMapping]], list[SaasFile]]:
|
26
|
+
def builder(data: Iterable[MutableMapping]) -> list[SaasFile]:
|
27
|
+
for d in data:
|
28
|
+
if "app" not in d:
|
29
|
+
d["app"] = {}
|
30
|
+
if "pipelinesProvider" not in d:
|
31
|
+
d["pipelinesProvider"] = {}
|
32
|
+
if "managedResourceTypes" not in d:
|
33
|
+
d["managedResourceTypes"] = []
|
34
|
+
if "imagePatterns" not in d:
|
35
|
+
d["imagePatterns"] = []
|
36
|
+
for rt in d.get("resourceTemplates", []):
|
37
|
+
for t in rt.get("targets", []):
|
38
|
+
ns = t["namespace"]
|
39
|
+
if "name" not in ns:
|
40
|
+
ns["name"] = "some_name"
|
41
|
+
if "environment" not in ns:
|
42
|
+
ns["environment"] = {}
|
43
|
+
if "app" not in ns:
|
44
|
+
ns["app"] = {}
|
45
|
+
if "cluster" not in ns:
|
46
|
+
ns["cluster"] = {}
|
47
|
+
return [gql_class_factory(SaasFile, d) for d in data]
|
48
|
+
|
49
|
+
return builder
|
50
|
+
|
51
|
+
|
52
|
+
@pytest.fixture
|
53
|
+
def fx() -> Callable:
|
54
|
+
def _fx(name: str) -> str:
|
55
|
+
return (Path(__file__).parent / "fixtures" / name).read_text()
|
56
|
+
|
57
|
+
return _fx
|
58
|
+
|
59
|
+
|
18
60
|
@pytest.fixture
|
19
61
|
def gql_class_factory() -> (
|
20
62
|
Callable[
|
@@ -0,0 +1,86 @@
|
|
1
|
+
from collections.abc import (
|
2
|
+
Callable,
|
3
|
+
Iterable,
|
4
|
+
Mapping,
|
5
|
+
)
|
6
|
+
from unittest.mock import (
|
7
|
+
create_autospec,
|
8
|
+
)
|
9
|
+
|
10
|
+
from reconcile.typed_queries.saas_files import SaasFile
|
11
|
+
from reconcile.utils.promotion_state import PromotionData, PromotionState
|
12
|
+
from tools.saas_promotion_state.saas_promotion_state import (
|
13
|
+
SaasPromotionState,
|
14
|
+
)
|
15
|
+
|
16
|
+
|
17
|
+
def test_saas_promotion_state(
|
18
|
+
saas_files_builder: Callable[[Iterable[Mapping]], list[SaasFile]],
|
19
|
+
) -> None:
|
20
|
+
saas_files = saas_files_builder([
|
21
|
+
{
|
22
|
+
"path": "/saas1.yml",
|
23
|
+
"name": "saas_1",
|
24
|
+
"resourceTemplates": [
|
25
|
+
{
|
26
|
+
"name": "template_1",
|
27
|
+
"url": "repo1/url",
|
28
|
+
"targets": [
|
29
|
+
{
|
30
|
+
"ref": "main",
|
31
|
+
"namespace": {"path": "/namespace1.yml"},
|
32
|
+
"promotion": {
|
33
|
+
"publish": ["channel-a"],
|
34
|
+
},
|
35
|
+
}
|
36
|
+
],
|
37
|
+
}
|
38
|
+
],
|
39
|
+
},
|
40
|
+
{
|
41
|
+
"path": "/saas2.yml",
|
42
|
+
"name": "saas_2",
|
43
|
+
"resourceTemplates": [
|
44
|
+
{
|
45
|
+
"name": "template_2",
|
46
|
+
"url": "repo2/url",
|
47
|
+
"targets": [
|
48
|
+
{
|
49
|
+
"ref": "main",
|
50
|
+
"namespace": {"path": "/namespace2.yml"},
|
51
|
+
"promotion": {
|
52
|
+
"publish": ["channel-b"],
|
53
|
+
"subscribe": ["channel-a"],
|
54
|
+
},
|
55
|
+
},
|
56
|
+
{
|
57
|
+
"ref": "main",
|
58
|
+
"namespace": {"path": "/namespace3.yml"},
|
59
|
+
},
|
60
|
+
],
|
61
|
+
}
|
62
|
+
],
|
63
|
+
},
|
64
|
+
])
|
65
|
+
|
66
|
+
expected = PromotionData(
|
67
|
+
check_in="test1",
|
68
|
+
saas_file="test2",
|
69
|
+
success=True,
|
70
|
+
target_config_hash="test3",
|
71
|
+
)
|
72
|
+
promotion_state = create_autospec(spec=PromotionState)
|
73
|
+
promotion_state.get_promotion_data.return_value = expected
|
74
|
+
saas_promotion_state = SaasPromotionState.create(
|
75
|
+
promotion_state=promotion_state, saas_files=saas_files
|
76
|
+
)
|
77
|
+
result = saas_promotion_state.get(channel="channel-a", sha="main")
|
78
|
+
|
79
|
+
assert result == {"616af45d7fad7f4eea8d52b8b5e8a058cef82ab0": expected}
|
80
|
+
promotion_state.get_promotion_data.assert_called_once_with(
|
81
|
+
sha="main",
|
82
|
+
channel="channel-a",
|
83
|
+
use_cache=False,
|
84
|
+
target_uid="616af45d7fad7f4eea8d52b8b5e8a058cef82ab0",
|
85
|
+
pre_check_sha_exists=False,
|
86
|
+
)
|
File without changes
|
File without changes
|
{qontract_reconcile-0.10.1rc885.dist-info → qontract_reconcile-0.10.1rc887.dist-info}/top_level.txt
RENAMED
File without changes
|