qontract-reconcile 0.10.2.dev265__py3-none-any.whl → 0.10.2.dev267__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.dev265.dist-info → qontract_reconcile-0.10.2.dev267.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.2.dev265.dist-info → qontract_reconcile-0.10.2.dev267.dist-info}/RECORD +9 -9
- reconcile/openshift_resources_base.py +1 -0
- reconcile/prometheus_rules_tester/integration.py +11 -2
- reconcile/utils/promtool.py +16 -5
- tools/alert_report.py +16 -0
- tools/qontract_cli.py +2 -0
- {qontract_reconcile-0.10.2.dev265.dist-info → qontract_reconcile-0.10.2.dev267.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev265.dist-info → qontract_reconcile-0.10.2.dev267.dist-info}/entry_points.txt +0 -0
{qontract_reconcile-0.10.2.dev265.dist-info → qontract_reconcile-0.10.2.dev267.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.dev267
|
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.dev265.dist-info → qontract_reconcile-0.10.2.dev267.dist-info}/RECORD
RENAMED
@@ -65,7 +65,7 @@ reconcile/openshift_network_policies.py,sha256=p81ShFK1WSEGiWHVURopDpg8YvtA3RE3O
|
|
65
65
|
reconcile/openshift_prometheus_rules.py,sha256=onowXab248zmHH8SbYDTc1W1bl7JiqRFU1xdTkZyLFg,1332
|
66
66
|
reconcile/openshift_resourcequotas.py,sha256=yUi56PiOn3inMMfq_x_FEHmaW-reGipzoorjdar372g,2415
|
67
67
|
reconcile/openshift_resources.py,sha256=I2nO_C37mG3rfyGrd4cGwN3mVseVGuTAHAyhFzLyqF4,1518
|
68
|
-
reconcile/openshift_resources_base.py,sha256=
|
68
|
+
reconcile/openshift_resources_base.py,sha256=Z5l_EzH5nDuKPF1dkBiyo6oHa-jAgGU9z1OGH77o_2g,42929
|
69
69
|
reconcile/openshift_rhcs_certs.py,sha256=d-72kJwgHMtdvs1F5uv-jC2lWmOyN2Wp1pQMbQ43FbU,10240
|
70
70
|
reconcile/openshift_rolebindings.py,sha256=9mlJ2FjWUoH-rsjtasreA_hV-K5Z_YR00qR_RR60OZM,6555
|
71
71
|
reconcile/openshift_routes.py,sha256=fXvuPSjcjVw1X3j2EQvUAdbOepmIFdKk-M3qP8QzPiw,1075
|
@@ -456,7 +456,7 @@ reconcile/oum/models.py,sha256=teH0bJTCMTzbdbYD9CU4yXDuMr34ceLcM0KuoIPU8gI,1712
|
|
456
456
|
reconcile/oum/providers.py,sha256=lfG6d7YV-A4Lte45EMv1Gx4A346piJ_jAkrU5AHJZ_g,1834
|
457
457
|
reconcile/oum/standalone.py,sha256=EN5y1S-3DwUZYzSRqRMtf63mI2slvBHKiU9zOTjYvWM,7334
|
458
458
|
reconcile/prometheus_rules_tester/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
459
|
-
reconcile/prometheus_rules_tester/integration.py,sha256=
|
459
|
+
reconcile/prometheus_rules_tester/integration.py,sha256=TWsVBUeRLH3lUCf47sWWVgq4Rpkrq0i_eu2vkqQniP0,9619
|
460
460
|
reconcile/rhidp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
461
461
|
reconcile/rhidp/common.py,sha256=rqifpncnE5--sYSx7ERMGDUjNHRI-SZkpuzwepZSps4,6766
|
462
462
|
reconcile/rhidp/metrics.py,sha256=Yp0GtpjhieEdru0qkG3osBTJiKUzg6CAjwPoFTQDnCg,417
|
@@ -640,7 +640,7 @@ reconcile/utils/parse_dhms_duration.py,sha256=TONpLnec5gHeF7k815YNJpQyDjXhkxZIcv
|
|
640
640
|
reconcile/utils/password_validator.py,sha256=XwuWg-8CPlcuG7dl_oQ1G1h2gSVSnfMym_VkuprpWVg,2183
|
641
641
|
reconcile/utils/prometheus.py,sha256=Ad0rwLbxRuuYjHwkwJloHEdK0bvy42h-p-HIT1DhDhs,3832
|
642
642
|
reconcile/utils/promotion_state.py,sha256=McSgGj3oog83ThJCrMR2v8q6Xb_Pxij-HEe_RbDu8cg,3946
|
643
|
-
reconcile/utils/promtool.py,sha256=
|
643
|
+
reconcile/utils/promtool.py,sha256=YnqwMAzsQVGuBZ1j9zy3UcVPFQVJgBMLzQkxhK_KFkU,3079
|
644
644
|
reconcile/utils/quay_api.py,sha256=Z6e3oPSp8sCIYxUSDTc6r_qZmXN8Ci_gK90DSCF7BDw,7814
|
645
645
|
reconcile/utils/quay_mirror.py,sha256=dpWCNv5lITwIk6Q9RkmqaQKHNk_JPy27UQEribJ7E-U,1324
|
646
646
|
reconcile/utils/raw_github_api.py,sha256=2WKtE8ABYYB9UGOAh9N_kLkksBWL3320Z2_scteZddI,2805
|
@@ -764,14 +764,14 @@ reconcile/utils/unleash/__init__.py,sha256=2PsN3GlLU8DOyWSvv5q9uzwuFn_vYtfEo-mmV
|
|
764
764
|
reconcile/utils/unleash/client.py,sha256=YrJnauxjcy1ml7W2AHg7dzIH_fVK_GugoRu7IFmk6e0,3505
|
765
765
|
reconcile/utils/unleash/server.py,sha256=907gDh9Ee8UxLqusnfpzE-7LUnttB38D4xhVJ0vMf_M,4439
|
766
766
|
tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
767
|
-
tools/alert_report.py,sha256=
|
767
|
+
tools/alert_report.py,sha256=cyQTei8_SYOggW_6uYvzhrF7Nae-9xOz-jmh9O9V8R8,5589
|
768
768
|
tools/app_interface_metrics_exporter.py,sha256=f1qwTmQfEcs98uBVRyBa0k7GQXdiSwd7w1hDVjhdGcQ,2303
|
769
769
|
tools/app_interface_reporter.py,sha256=0_oq1-mL0UOh1x5G8CoKaEVJqK-XTKE7PX7IbRTovBc,17224
|
770
770
|
tools/app_sre_tekton_access_reporter.py,sha256=o9prLUgQpwO3msRWc2as1xT1y9OB3znkpgvLr0Ys8_M,3146
|
771
771
|
tools/app_sre_tekton_access_revalidation.py,sha256=66nHEaY-bIqxIhpcmwN8AvQZu6ZXenfkg4Fut0pVZRM,2726
|
772
772
|
tools/glitchtip_access_reporter.py,sha256=o01A6b88t3Wie6tj_tJWWVo2J01LxQ_a9giGm4UzEaU,2901
|
773
773
|
tools/glitchtip_access_revalidation.py,sha256=PXN5wxl6OX8sxddPaakDF3X79nFLvpm-lz0mWLVelw0,2806
|
774
|
-
tools/qontract_cli.py,sha256=
|
774
|
+
tools/qontract_cli.py,sha256=DkIJX7jYRycBDKySQHVB6fNIAFpF3USkZaLJbcsYnDg,159204
|
775
775
|
tools/template_validation.py,sha256=wW22pH4bJBN5CcK74RuIEwtiVmQ3zI1eSvNMAE6fbyc,3377
|
776
776
|
tools/cli_commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
777
777
|
tools/cli_commands/container_images_report.py,sha256=_8GuBsl_qYP5qfa5aa9krwyKHYu82MSh02deHEroSa4,5459
|
@@ -797,7 +797,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
797
797
|
tools/saas_promotion_state/saas_promotion_state.py,sha256=oF7C4hpIgyMTwTRm3Aun3cDCHIjVar65JoLp6NcJHlU,3909
|
798
798
|
tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
|
799
799
|
tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
|
800
|
-
qontract_reconcile-0.10.2.
|
801
|
-
qontract_reconcile-0.10.2.
|
802
|
-
qontract_reconcile-0.10.2.
|
803
|
-
qontract_reconcile-0.10.2.
|
800
|
+
qontract_reconcile-0.10.2.dev267.dist-info/METADATA,sha256=8vXQoAu6tLPI2W0bpAPmQW3RzzD_eO20K4SvoXs-560,24501
|
801
|
+
qontract_reconcile-0.10.2.dev267.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
802
|
+
qontract_reconcile-0.10.2.dev267.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
|
803
|
+
qontract_reconcile-0.10.2.dev267.dist-info/RECORD,,
|
@@ -42,6 +42,7 @@ QONTRACT_INTEGRATION_VERSION = make_semver(0, 1, 0)
|
|
42
42
|
PROVIDERS = ["prometheus-rule"]
|
43
43
|
|
44
44
|
NAMESPACE_NAME = "openshift-customer-monitoring"
|
45
|
+
DEFAULT_PROMTOOL_VERSION = "2.55.1"
|
45
46
|
|
46
47
|
|
47
48
|
class TestContent(BaseModel):
|
@@ -57,6 +58,7 @@ class Test(BaseModel):
|
|
57
58
|
rule_length: int
|
58
59
|
tests: list[TestContent] | None
|
59
60
|
result: CommandExecutionResult | None = None
|
61
|
+
promtool_version: str
|
60
62
|
|
61
63
|
|
62
64
|
class RuleToFetch(BaseModel):
|
@@ -80,6 +82,8 @@ def fetch_rule_and_tests(
|
|
80
82
|
rule_body = openshift_resource.body
|
81
83
|
rule_length = len(yaml.dump(rule_body)) # Same as prometheus-operator does it.
|
82
84
|
|
85
|
+
promtool_version = rule.resource.get("promtool_version") or DEFAULT_PROMTOOL_VERSION
|
86
|
+
|
83
87
|
if rule.resource["type"] == "resource-template-extracurlyjinja2":
|
84
88
|
variables = json.loads(rule.resource.get("variables") or "{}")
|
85
89
|
variables["resource"] = rule.resource
|
@@ -113,6 +117,7 @@ def fetch_rule_and_tests(
|
|
113
117
|
rule=rule_body,
|
114
118
|
rule_length=rule_length,
|
115
119
|
tests=tests,
|
120
|
+
promtool_version=promtool_version,
|
116
121
|
)
|
117
122
|
|
118
123
|
|
@@ -204,7 +209,9 @@ def check_rule_length(rule_length: int) -> CommandExecutionResult:
|
|
204
209
|
|
205
210
|
def run_test(test: Test, alerting_services: Iterable[str]) -> None:
|
206
211
|
"""Checks rules, run tests and stores the result in test.result"""
|
207
|
-
check_rule_result = promtool.check_rule(
|
212
|
+
check_rule_result = promtool.check_rule(
|
213
|
+
test.rule["spec"], promtool_version=test.promtool_version
|
214
|
+
)
|
208
215
|
valid_services_result = check_valid_services(test.rule, alerting_services)
|
209
216
|
rule_length_result = check_rule_length(test.rule_length)
|
210
217
|
test.result = check_rule_result and valid_services_result and rule_length_result
|
@@ -214,7 +221,9 @@ def run_test(test: Test, alerting_services: Iterable[str]) -> None:
|
|
214
221
|
|
215
222
|
rule_files = {test.rule_path: test.rule["spec"]}
|
216
223
|
for t in test.tests or []:
|
217
|
-
result = promtool.run_test(
|
224
|
+
result = promtool.run_test(
|
225
|
+
t.test, rule_files, promtool_version=test.promtool_version
|
226
|
+
)
|
218
227
|
test.result = test.result and result
|
219
228
|
|
220
229
|
|
reconcile/utils/promtool.py
CHANGED
@@ -9,17 +9,28 @@ import yaml
|
|
9
9
|
from reconcile.utils.defer import defer
|
10
10
|
from reconcile.utils.structs import CommandExecutionResult
|
11
11
|
|
12
|
-
PROMTOOL_VERSION = ["2.55.1"]
|
12
|
+
PROMTOOL_VERSION = ["2.55.1", "3.2.1"]
|
13
13
|
PROMTOOL_VERSION_REGEX = r"^promtool,\sversion\s([\d]+\.[\d]+\.[\d]+).+$"
|
14
14
|
|
15
15
|
|
16
|
-
def
|
16
|
+
def _bin(version: str | None = None) -> str:
|
17
|
+
return f"promtool-{version}" if version else "promtool"
|
18
|
+
|
19
|
+
|
20
|
+
def check_rule(
|
21
|
+
yaml_spec: Mapping,
|
22
|
+
promtool_version: str | None = None,
|
23
|
+
) -> CommandExecutionResult:
|
17
24
|
"""Run promtool check rules on the given yaml spec given as dict"""
|
18
|
-
return _run_yaml_spec_cmd(
|
25
|
+
return _run_yaml_spec_cmd(
|
26
|
+
cmd=[_bin(promtool_version), "check", "rules"], yaml_spec=yaml_spec
|
27
|
+
)
|
19
28
|
|
20
29
|
|
21
30
|
def run_test(
|
22
|
-
test_yaml_spec: MutableMapping,
|
31
|
+
test_yaml_spec: MutableMapping,
|
32
|
+
rule_files: Mapping[str, Mapping],
|
33
|
+
promtool_version: str | None = None,
|
23
34
|
) -> CommandExecutionResult:
|
24
35
|
"""Run promtool test rules
|
25
36
|
|
@@ -52,7 +63,7 @@ def run_test(
|
|
52
63
|
defer(lambda: _cleanup(temp_rule_files.values()))
|
53
64
|
|
54
65
|
return _run_yaml_spec_cmd(
|
55
|
-
cmd=[
|
66
|
+
cmd=[_bin(promtool_version), "test", "rules"], yaml_spec=temp_test_yaml_spec
|
56
67
|
)
|
57
68
|
|
58
69
|
|
tools/alert_report.py
CHANGED
@@ -12,17 +12,22 @@ class Alert:
|
|
12
12
|
message: str
|
13
13
|
timestamp: float
|
14
14
|
username: str
|
15
|
+
responsed: bool
|
15
16
|
|
16
17
|
|
17
18
|
class AlertStat:
|
18
19
|
def __init__(self) -> None:
|
19
20
|
self._triggered_alerts = 0
|
20
21
|
self._resolved_alerts = 0
|
22
|
+
self._responsed_alerts = 0
|
21
23
|
self._elapsed_times: list[float] = []
|
22
24
|
|
23
25
|
def add_triggered(self) -> None:
|
24
26
|
self._triggered_alerts += 1
|
25
27
|
|
28
|
+
def add_responsed(self) -> None:
|
29
|
+
self._responsed_alerts += 1
|
30
|
+
|
26
31
|
def add_resolved(self) -> None:
|
27
32
|
self._resolved_alerts += 1
|
28
33
|
|
@@ -37,6 +42,10 @@ class AlertStat:
|
|
37
42
|
def resolved_alerts(self) -> int:
|
38
43
|
return self._resolved_alerts
|
39
44
|
|
45
|
+
@property
|
46
|
+
def responsed_alerts(self) -> int:
|
47
|
+
return self._responsed_alerts
|
48
|
+
|
40
49
|
@property
|
41
50
|
def elapsed_times(self) -> list[float]:
|
42
51
|
return self._elapsed_times
|
@@ -53,6 +62,8 @@ def group_alerts(messages: list[dict]) -> dict[str, list[Alert]]:
|
|
53
62
|
continue
|
54
63
|
|
55
64
|
timestamp = float(m["ts"])
|
65
|
+
responsed = bool(m.get("reply_count", 0) or m.get("reactions", []))
|
66
|
+
|
56
67
|
for at in m.get("attachments", []):
|
57
68
|
if "title" not in at:
|
58
69
|
continue
|
@@ -79,6 +90,7 @@ def group_alerts(messages: list[dict]) -> dict[str, list[Alert]]:
|
|
79
90
|
message=alert_message,
|
80
91
|
timestamp=timestamp,
|
81
92
|
username=m["username"],
|
93
|
+
responsed=responsed,
|
82
94
|
)
|
83
95
|
)
|
84
96
|
else:
|
@@ -93,6 +105,7 @@ def group_alerts(messages: list[dict]) -> dict[str, list[Alert]]:
|
|
93
105
|
message="placeholder",
|
94
106
|
timestamp=timestamp,
|
95
107
|
username=m["username"],
|
108
|
+
responsed=responsed,
|
96
109
|
)
|
97
110
|
)
|
98
111
|
continue
|
@@ -114,6 +127,7 @@ def group_alerts(messages: list[dict]) -> dict[str, list[Alert]]:
|
|
114
127
|
message=alert_message,
|
115
128
|
timestamp=timestamp,
|
116
129
|
username=m["username"],
|
130
|
+
responsed=responsed,
|
117
131
|
)
|
118
132
|
)
|
119
133
|
|
@@ -135,6 +149,8 @@ def gen_alert_stats(alerts: dict[str, list[Alert]]) -> dict[str, AlertStat]:
|
|
135
149
|
if al.state == "FIRING":
|
136
150
|
alert_stats[alert_name].add_triggered()
|
137
151
|
temp[key] = al
|
152
|
+
if al.responsed:
|
153
|
+
alert_stats[alert_name].add_responsed()
|
138
154
|
|
139
155
|
if al.state == "RESOLVED":
|
140
156
|
alert_stats[alert_name].add_resolved()
|
tools/qontract_cli.py
CHANGED
@@ -869,6 +869,7 @@ def alert_report(
|
|
869
869
|
"Triggered",
|
870
870
|
"Resolved",
|
871
871
|
"Median time to resolve (h:mm:ss)",
|
872
|
+
"Response Rate",
|
872
873
|
]
|
873
874
|
table_data: list[dict[str, str]] = []
|
874
875
|
for alert_name, data in sorted(
|
@@ -884,6 +885,7 @@ def alert_report(
|
|
884
885
|
"Triggered": str(data.triggered_alerts),
|
885
886
|
"Resolved": str(data.resolved_alerts),
|
886
887
|
"Median time to resolve (h:mm:ss)": median_elapsed,
|
888
|
+
"Response Rate": f"{data.responsed_alerts / data.triggered_alerts * 100:.2f}%",
|
887
889
|
})
|
888
890
|
|
889
891
|
# TODO(mafriedm, rporres): Fix this
|
{qontract_reconcile-0.10.2.dev265.dist-info → qontract_reconcile-0.10.2.dev267.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|