qontract-reconcile 0.10.2.dev208__py3-none-any.whl → 0.10.2.dev213__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.2.dev208.dist-info → qontract_reconcile-0.10.2.dev213.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.2.dev208.dist-info → qontract_reconcile-0.10.2.dev213.dist-info}/RECORD +8 -8
- reconcile/openshift_resources_base.py +9 -1
- reconcile/utils/saasherder/interfaces.py +4 -0
- reconcile/utils/saasherder/models.py +26 -0
- reconcile/utils/saasherder/saasherder.py +87 -6
- {qontract_reconcile-0.10.2.dev208.dist-info → qontract_reconcile-0.10.2.dev213.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev208.dist-info → qontract_reconcile-0.10.2.dev213.dist-info}/entry_points.txt +0 -0
{qontract_reconcile-0.10.2.dev208.dist-info → qontract_reconcile-0.10.2.dev213.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: qontract-reconcile
|
3
|
-
Version: 0.10.2.
|
3
|
+
Version: 0.10.2.dev213
|
4
4
|
Summary: Collection of tools to reconcile services with their desired state as defined in the app-interface DB.
|
5
5
|
Project-URL: homepage, https://github.com/app-sre/qontract-reconcile
|
6
6
|
Project-URL: repository, https://github.com/app-sre/qontract-reconcile
|
{qontract_reconcile-0.10.2.dev208.dist-info → qontract_reconcile-0.10.2.dev213.dist-info}/RECORD
RENAMED
@@ -71,7 +71,7 @@ reconcile/openshift_network_policies.py,sha256=p81ShFK1WSEGiWHVURopDpg8YvtA3RE3O
|
|
71
71
|
reconcile/openshift_prometheus_rules.py,sha256=onowXab248zmHH8SbYDTc1W1bl7JiqRFU1xdTkZyLFg,1332
|
72
72
|
reconcile/openshift_resourcequotas.py,sha256=yUi56PiOn3inMMfq_x_FEHmaW-reGipzoorjdar372g,2415
|
73
73
|
reconcile/openshift_resources.py,sha256=I2nO_C37mG3rfyGrd4cGwN3mVseVGuTAHAyhFzLyqF4,1518
|
74
|
-
reconcile/openshift_resources_base.py,sha256=
|
74
|
+
reconcile/openshift_resources_base.py,sha256=fogdGOnAk-8xK7z9UeLs1rT2IwDs6Q7jSx_iOVAWDLk,42316
|
75
75
|
reconcile/openshift_rhcs_certs.py,sha256=lP0GwKMRl8YBzxrwdbBOxrPqIPYNmu2KkZPGzWKyRVU,9859
|
76
76
|
reconcile/openshift_rolebindings.py,sha256=9mlJ2FjWUoH-rsjtasreA_hV-K5Z_YR00qR_RR60OZM,6555
|
77
77
|
reconcile/openshift_routes.py,sha256=fXvuPSjcjVw1X3j2EQvUAdbOepmIFdKk-M3qP8QzPiw,1075
|
@@ -767,9 +767,9 @@ reconcile/utils/runtime/meta.py,sha256=dWdKS9eHVuowFkTK4lgXJ723vS1y9giOMzePUKnHn
|
|
767
767
|
reconcile/utils/runtime/runner.py,sha256=I30KRrX1UQbHc_Ir1cIZX3OfNSdoHKdnDSPAEB69Ilk,7944
|
768
768
|
reconcile/utils/runtime/sharding.py,sha256=r0ieUtNed7NvknSw6qQrCkKpVXE1shuHGnfFcnpA_k4,16142
|
769
769
|
reconcile/utils/saasherder/__init__.py,sha256=3U8plqMAPRE1kjwZ5YnIsYsggTf4_gS7flRUEuXVBAs,343
|
770
|
-
reconcile/utils/saasherder/interfaces.py,sha256=
|
771
|
-
reconcile/utils/saasherder/models.py,sha256=
|
772
|
-
reconcile/utils/saasherder/saasherder.py,sha256=
|
770
|
+
reconcile/utils/saasherder/interfaces.py,sha256=nbGVLiIXJvOtd5ZfKsP3bfrFbMpdQ02D0cTTM9rrED0,9286
|
771
|
+
reconcile/utils/saasherder/models.py,sha256=MSKaC65_bXSxKvhCibRH5K1DNppLPbw5w7_6VrjCCFU,11018
|
772
|
+
reconcile/utils/saasherder/saasherder.py,sha256=W9nmQyULr4Jx9VAMwFyhULbKo5WRP9nSieOnpO5UxKQ,90224
|
773
773
|
reconcile/utils/terraform/__init__.py,sha256=zNbiyTWo35AT1sFTElL2j_AA0jJ_yWE_bfFn-nD2xik,250
|
774
774
|
reconcile/utils/terraform/config.py,sha256=5UVrd563TMcvi4ooa5JvWVDW1I3bIWg484u79evfV_8,164
|
775
775
|
reconcile/utils/terraform/config_client.py,sha256=gRL1rQ0AqvShei_rcGqC3HDYGskOFKE1nPrJyJE9yno,4676
|
@@ -815,7 +815,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
815
815
|
tools/saas_promotion_state/saas_promotion_state.py,sha256=UfwwRLS5Ya4_Nh1w5n1dvoYtchQvYE9yj1VANt2IKqI,3925
|
816
816
|
tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
|
817
817
|
tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
|
818
|
-
qontract_reconcile-0.10.2.
|
819
|
-
qontract_reconcile-0.10.2.
|
820
|
-
qontract_reconcile-0.10.2.
|
821
|
-
qontract_reconcile-0.10.2.
|
818
|
+
qontract_reconcile-0.10.2.dev213.dist-info/METADATA,sha256=KF0B_KMRSL7FeDdMZr1P7osgPw5qyZm10v6Pe90T4oA,24555
|
819
|
+
qontract_reconcile-0.10.2.dev213.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
820
|
+
qontract_reconcile-0.10.2.dev213.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
|
821
|
+
qontract_reconcile-0.10.2.dev213.dist-info/RECORD,,
|
@@ -667,6 +667,15 @@ def fetch_current_state(
|
|
667
667
|
openshift_resource = OR(
|
668
668
|
item, QONTRACT_INTEGRATION, QONTRACT_INTEGRATION_VERSION
|
669
669
|
)
|
670
|
+
labels = openshift_resource.body.get("metadata", {}).get("labels", {})
|
671
|
+
# Skip resources managed by ArgoCD
|
672
|
+
# This uses the Kubernetes recommended label 'app.kubernetes.io/part-of=argocd'
|
673
|
+
# https://argo-cd.readthedocs.io/en/stable/user-guide/resource_tracking/
|
674
|
+
if labels.get("app.kubernetes.io/part-of") == "argocd":
|
675
|
+
_locked_info_log(
|
676
|
+
f"Skipping {openshift_resource.kind} {openshift_resource.name} in current state because it is managed by ArgoCD"
|
677
|
+
)
|
678
|
+
continue
|
670
679
|
ri.add_current(
|
671
680
|
cluster,
|
672
681
|
namespace,
|
@@ -698,7 +707,6 @@ def fetch_desired_state(
|
|
698
707
|
msg = f"[{cluster}/{namespace}] {e!s}"
|
699
708
|
_locked_error_log(msg)
|
700
709
|
return
|
701
|
-
|
702
710
|
# add to inventory
|
703
711
|
try:
|
704
712
|
ri.add_desired_resource(
|
@@ -7,6 +7,7 @@ from typing import (
|
|
7
7
|
runtime_checkable,
|
8
8
|
)
|
9
9
|
|
10
|
+
from reconcile.gql_definitions.fragments.saas_slo_document import SLODocument
|
10
11
|
from reconcile.utils import oc_connection_parameters
|
11
12
|
from reconcile.utils.secret_reader import HasSecret
|
12
13
|
|
@@ -326,6 +327,9 @@ class SaasResourceTemplateTarget(HasParameters, HasSecretParameters, Protocol):
|
|
326
327
|
@property
|
327
328
|
def images(self) -> Sequence[SaasResourceTemplateTargetImage] | None: ...
|
328
329
|
|
330
|
+
@property
|
331
|
+
def slos(self) -> list[SLODocument] | None: ...
|
332
|
+
|
329
333
|
def uid(
|
330
334
|
self, parent_saas_file_name: str, parent_resource_template_name: str
|
331
335
|
) -> str: ...
|
@@ -12,6 +12,9 @@ from pydantic import (
|
|
12
12
|
Field,
|
13
13
|
)
|
14
14
|
|
15
|
+
from reconcile.gql_definitions.fragments.saas_slo_document import (
|
16
|
+
SLODocument,
|
17
|
+
)
|
15
18
|
from reconcile.utils.oc_connection_parameters import Cluster
|
16
19
|
from reconcile.utils.saasherder.interfaces import (
|
17
20
|
HasParameters,
|
@@ -66,8 +69,18 @@ class TriggerSpecBase:
|
|
66
69
|
raise NotImplementedError("implement this function in inheriting classes")
|
67
70
|
|
68
71
|
|
72
|
+
@dataclass(frozen=True)
|
73
|
+
class SLOKey:
|
74
|
+
slo_document_name: str
|
75
|
+
namespace_name: str
|
76
|
+
cluster_name: str
|
77
|
+
|
78
|
+
|
69
79
|
@dataclass
|
70
80
|
class TriggerSpecConfig(TriggerSpecBase):
|
81
|
+
resource_template_url: str
|
82
|
+
target_ref: str
|
83
|
+
slos: list[SLODocument] | None = None
|
71
84
|
target_name: str | None = None
|
72
85
|
reason: str | None = None
|
73
86
|
|
@@ -81,6 +94,19 @@ class TriggerSpecConfig(TriggerSpecBase):
|
|
81
94
|
key += f"/{self.target_name}"
|
82
95
|
return key
|
83
96
|
|
97
|
+
def extract_slo_keys(self) -> list[SLOKey]:
|
98
|
+
return [
|
99
|
+
SLOKey(
|
100
|
+
slo_document_name=slo_document.name,
|
101
|
+
namespace_name=namespace.namespace.name,
|
102
|
+
cluster_name=namespace.namespace.cluster.name,
|
103
|
+
)
|
104
|
+
for slo_document in self.slos or []
|
105
|
+
for namespace in slo_document.namespaces
|
106
|
+
if namespace.namespace.name == self.namespace_name
|
107
|
+
and namespace.namespace.cluster.name == self.cluster_name
|
108
|
+
]
|
109
|
+
|
84
110
|
|
85
111
|
@dataclass
|
86
112
|
class TriggerSpecMovingCommit(TriggerSpecBase):
|
@@ -71,6 +71,7 @@ from reconcile.utils.saasherder.models import (
|
|
71
71
|
ImageAuth,
|
72
72
|
Namespace,
|
73
73
|
Promotion,
|
74
|
+
SLOKey,
|
74
75
|
TargetSpec,
|
75
76
|
TriggerSpecConfig,
|
76
77
|
TriggerSpecContainerImage,
|
@@ -81,6 +82,7 @@ from reconcile.utils.saasherder.models import (
|
|
81
82
|
UpstreamJob,
|
82
83
|
)
|
83
84
|
from reconcile.utils.secret_reader import SecretReaderBase
|
85
|
+
from reconcile.utils.slo_document_manager import SLODetails, SLODocumentManager
|
84
86
|
from reconcile.utils.state import State
|
85
87
|
from reconcile.utils.vcs import VCS
|
86
88
|
|
@@ -1040,19 +1042,19 @@ class SaasHerder: # pylint: disable=too-many-public-methods
|
|
1040
1042
|
return channel_map
|
1041
1043
|
|
1042
1044
|
def _collect_blocked_versions(self) -> dict[str, set[str]]:
|
1043
|
-
blocked_versions: dict[str, set[str]] =
|
1045
|
+
blocked_versions: dict[str, set[str]] = defaultdict(set[str])
|
1044
1046
|
for saas_file in self.saas_files:
|
1045
1047
|
for cc in saas_file.app.code_components or []:
|
1046
1048
|
for v in cc.blocked_versions or []:
|
1047
|
-
blocked_versions
|
1049
|
+
blocked_versions[cc.url].add(v)
|
1048
1050
|
return blocked_versions
|
1049
1051
|
|
1050
1052
|
def _collect_hotfix_versions(self) -> dict[str, set[str]]:
|
1051
|
-
hotfix_versions: dict[str, set[str]] =
|
1053
|
+
hotfix_versions: dict[str, set[str]] = defaultdict(set[str])
|
1052
1054
|
for saas_file in self.saas_files:
|
1053
1055
|
for cc in saas_file.app.code_components or []:
|
1054
1056
|
for v in cc.hotfix_versions or []:
|
1055
|
-
hotfix_versions
|
1057
|
+
hotfix_versions[cc.url].add(v)
|
1056
1058
|
return hotfix_versions
|
1057
1059
|
|
1058
1060
|
@staticmethod
|
@@ -1273,6 +1275,8 @@ class SaasHerder: # pylint: disable=too-many-public-methods
|
|
1273
1275
|
cluster_name=target.namespace.cluster.name,
|
1274
1276
|
namespace_name=target.namespace.name,
|
1275
1277
|
target_name=target.name,
|
1278
|
+
resource_template_url=rt.url,
|
1279
|
+
target_ref=target.ref,
|
1276
1280
|
state_content=None,
|
1277
1281
|
).state_key
|
1278
1282
|
digest = SaasHerder.get_target_config_hash(
|
@@ -1691,7 +1695,82 @@ class SaasHerder: # pylint: disable=too-many-public-methods
|
|
1691
1695
|
results = threaded.run(
|
1692
1696
|
self.get_configs_diff_saas_file, self.saas_files, self.thread_pool_size
|
1693
1697
|
)
|
1694
|
-
|
1698
|
+
trigger_config_spec_list = list(itertools.chain.from_iterable(results))
|
1699
|
+
return self.filter_slo_breached_triggers(trigger_config_spec_list)
|
1700
|
+
|
1701
|
+
def filter_slo_breached_triggers(
|
1702
|
+
self, trigger_config_spec_list: list[TriggerSpecConfig]
|
1703
|
+
) -> list[TriggerSpecConfig]:
|
1704
|
+
trigger_config_specs_to_validate: list[TriggerSpecConfig] = [
|
1705
|
+
trigger_config_spec
|
1706
|
+
for trigger_config_spec in trigger_config_spec_list
|
1707
|
+
if trigger_config_spec.slos
|
1708
|
+
and trigger_config_spec.target_ref
|
1709
|
+
not in self.hotfix_versions[trigger_config_spec.resource_template_url]
|
1710
|
+
]
|
1711
|
+
if not trigger_config_specs_to_validate:
|
1712
|
+
return trigger_config_spec_list
|
1713
|
+
|
1714
|
+
slo_documents = [
|
1715
|
+
slo
|
1716
|
+
for trigger_spec in trigger_config_specs_to_validate
|
1717
|
+
for slo in trigger_spec.slos or []
|
1718
|
+
]
|
1719
|
+
slo_document_manager = SLODocumentManager(
|
1720
|
+
slo_documents=slo_documents,
|
1721
|
+
thread_pool_size=self.thread_pool_size,
|
1722
|
+
secret_reader=self.secret_reader,
|
1723
|
+
)
|
1724
|
+
breached_slos = slo_document_manager.get_breached_slos()
|
1725
|
+
if not breached_slos:
|
1726
|
+
return trigger_config_spec_list
|
1727
|
+
|
1728
|
+
breached_slos_map = self.make_breached_slos_map(breached_slos)
|
1729
|
+
valid_trigger_config_specs = [
|
1730
|
+
trigger_config_spec
|
1731
|
+
for trigger_config_spec in trigger_config_spec_list
|
1732
|
+
if not self.has_breached_slos(trigger_config_spec, breached_slos_map)
|
1733
|
+
]
|
1734
|
+
return valid_trigger_config_specs
|
1735
|
+
|
1736
|
+
@staticmethod
|
1737
|
+
def make_breached_slos_map(
|
1738
|
+
breached_slos: list[SLODetails],
|
1739
|
+
) -> dict[SLOKey, list[SLODetails]]:
|
1740
|
+
breached_slos_map: dict[SLOKey, list[SLODetails]] = defaultdict(
|
1741
|
+
list[SLODetails]
|
1742
|
+
)
|
1743
|
+
for breached_slo in breached_slos:
|
1744
|
+
breached_slos_map[
|
1745
|
+
SLOKey(
|
1746
|
+
slo_document_name=breached_slo.slo_document_name,
|
1747
|
+
namespace_name=breached_slo.namespace_name,
|
1748
|
+
cluster_name=breached_slo.cluster_name,
|
1749
|
+
)
|
1750
|
+
].append(breached_slo)
|
1751
|
+
return breached_slos_map
|
1752
|
+
|
1753
|
+
@staticmethod
|
1754
|
+
def has_breached_slos(
|
1755
|
+
trigger_spec: TriggerSpecConfig,
|
1756
|
+
breached_slo_map: dict[SLOKey, list[SLODetails]],
|
1757
|
+
) -> bool:
|
1758
|
+
matching_slo_keys = [
|
1759
|
+
slo_key
|
1760
|
+
for slo_key in trigger_spec.extract_slo_keys()
|
1761
|
+
if slo_key in breached_slo_map
|
1762
|
+
]
|
1763
|
+
if not matching_slo_keys:
|
1764
|
+
return False
|
1765
|
+
logging.info(
|
1766
|
+
f"Skipping target from saas file {trigger_spec.saas_file_name} due to following breached SLOs."
|
1767
|
+
)
|
1768
|
+
for matching_key in matching_slo_keys:
|
1769
|
+
for breached_slo in breached_slo_map[matching_key]:
|
1770
|
+
logging.info(
|
1771
|
+
f"SLO: {breached_slo.slo.name} of document {breached_slo.slo_document_name} is breached. Current value: {breached_slo.current_slo_value} Expected: {breached_slo.slo.slo_target}"
|
1772
|
+
)
|
1773
|
+
return True
|
1695
1774
|
|
1696
1775
|
@staticmethod
|
1697
1776
|
def remove_none_values(d: dict[Any, Any] | None) -> dict[Any, Any]:
|
@@ -1725,7 +1804,6 @@ class SaasHerder: # pylint: disable=too-many-public-methods
|
|
1725
1804
|
dtc = SaasHerder.remove_none_values(trigger_spec.state_content)
|
1726
1805
|
if ctc == dtc:
|
1727
1806
|
continue
|
1728
|
-
|
1729
1807
|
if self.include_trigger_trace:
|
1730
1808
|
trigger_spec.reason = f"{self.repo_url}/commit/{RunningState().commit}"
|
1731
1809
|
# For now we count every saas config change as an auto-promotion
|
@@ -1820,6 +1898,9 @@ class SaasHerder: # pylint: disable=too-many-public-methods
|
|
1820
1898
|
namespace_name=target.namespace.name,
|
1821
1899
|
target_name=target.name,
|
1822
1900
|
state_content=serializable_target_config,
|
1901
|
+
resource_template_url=rt.url,
|
1902
|
+
target_ref=target.ref,
|
1903
|
+
slos=target.slos or None,
|
1823
1904
|
)
|
1824
1905
|
configs[trigger_spec.state_key] = trigger_spec
|
1825
1906
|
|
{qontract_reconcile-0.10.2.dev208.dist-info → qontract_reconcile-0.10.2.dev213.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|