qontract-reconcile 0.10.2.dev56__py3-none-any.whl → 0.10.2.dev58__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.dev56.dist-info → qontract_reconcile-0.10.2.dev58.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.2.dev56.dist-info → qontract_reconcile-0.10.2.dev58.dist-info}/RECORD +8 -8
- reconcile/utils/output.py +6 -3
- tools/app_interface_reporter.py +70 -44
- tools/cli_commands/gpg_encrypt.py +2 -2
- tools/qontract_cli.py +230 -291
- {qontract_reconcile-0.10.2.dev56.dist-info → qontract_reconcile-0.10.2.dev58.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev56.dist-info → qontract_reconcile-0.10.2.dev58.dist-info}/entry_points.txt +0 -0
{qontract_reconcile-0.10.2.dev56.dist-info → qontract_reconcile-0.10.2.dev58.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.dev58
|
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.dev56.dist-info → qontract_reconcile-0.10.2.dev58.dist-info}/RECORD
RENAMED
@@ -615,7 +615,7 @@ reconcile/utils/oc_map.py,sha256=ougQ-Wlsa8ymoE_lPQ7g2LlpsUOsHVeRCLYW_6fjeWU,897
|
|
615
615
|
reconcile/utils/ocm_base_client.py,sha256=t5kxhklEqOpenXPkXiwQIk8d3D7hIUndBm5qGusS0bc,6681
|
616
616
|
reconcile/utils/openshift_resource.py,sha256=DI-e04f4NqEUFJ_9HzjY-QMhFt7o2XVauM09mzMC5Vs,24716
|
617
617
|
reconcile/utils/openssl.py,sha256=QVvhzhpChq_4Daf_5wE1qeZJr4thg3DDjJPn4bOPD4E,365
|
618
|
-
reconcile/utils/output.py,sha256=
|
618
|
+
reconcile/utils/output.py,sha256=xh2Not-Xm97KeRx_J5nc2PP5tDwpDLZBeCrWI0S-al4,2034
|
619
619
|
reconcile/utils/pagerduty_api.py,sha256=_24i9S_4X7nlvHb-7clXRE0p1BG4ODjOzKxWO-F9WgI,7627
|
620
620
|
reconcile/utils/parse_dhms_duration.py,sha256=TONpLnec5gHeF7k815YNJpQyDjXhkxZIcv9s8ffbTSY,1840
|
621
621
|
reconcile/utils/password_validator.py,sha256=XwuWg-8CPlcuG7dl_oQ1G1h2gSVSnfMym_VkuprpWVg,2183
|
@@ -745,18 +745,18 @@ reconcile/utils/unleash/client.py,sha256=YrJnauxjcy1ml7W2AHg7dzIH_fVK_GugoRu7IFm
|
|
745
745
|
reconcile/utils/unleash/server.py,sha256=907gDh9Ee8UxLqusnfpzE-7LUnttB38D4xhVJ0vMf_M,4439
|
746
746
|
tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
747
747
|
tools/app_interface_metrics_exporter.py,sha256=f1qwTmQfEcs98uBVRyBa0k7GQXdiSwd7w1hDVjhdGcQ,2303
|
748
|
-
tools/app_interface_reporter.py,sha256=
|
748
|
+
tools/app_interface_reporter.py,sha256=gR2EgHmgSIxzK5xxDW1SduFU6OkPaf2LlAQjhV3NYIg,17623
|
749
749
|
tools/app_sre_tekton_access_reporter.py,sha256=o9prLUgQpwO3msRWc2as1xT1y9OB3znkpgvLr0Ys8_M,3146
|
750
750
|
tools/app_sre_tekton_access_revalidation.py,sha256=66nHEaY-bIqxIhpcmwN8AvQZu6ZXenfkg4Fut0pVZRM,2726
|
751
751
|
tools/glitchtip_access_reporter.py,sha256=o01A6b88t3Wie6tj_tJWWVo2J01LxQ_a9giGm4UzEaU,2901
|
752
752
|
tools/glitchtip_access_revalidation.py,sha256=8kbBJk04mkq28kWoRDDkfCGIF3GRg3pJrFAh1sW0dbk,2821
|
753
|
-
tools/qontract_cli.py,sha256=
|
753
|
+
tools/qontract_cli.py,sha256=DCgIaGxZlYG5TVWUifAQGfp81aop9SLu0ezVVg4x2NM,148792
|
754
754
|
tools/sd_app_sre_alert_report.py,sha256=jQpJdXVID68bSNtJNOGDh0-ei1CfEUS4Itr4MAaBNFA,5062
|
755
755
|
tools/template_validation.py,sha256=qpKYaTgk0GOPGa2Ct5_5sKdwIHtCAKIBGzsMPuJU5fw,3371
|
756
756
|
tools/cli_commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
757
757
|
tools/cli_commands/container_images_report.py,sha256=8fG9XU-eEhJ7hKCdQzBcdPpvIJR-8WGkHOgFEulpfYQ,5213
|
758
758
|
tools/cli_commands/erv2.py,sha256=VxUlNXllo947UwmtvS-42IeI9x_t_X3MHrrSI3K_GRo,23274
|
759
|
-
tools/cli_commands/gpg_encrypt.py,sha256=
|
759
|
+
tools/cli_commands/gpg_encrypt.py,sha256=NhzwN49UN7P5_FJgTUN5A4BIwNbFokIE4lwDax2iP5k,4891
|
760
760
|
tools/cli_commands/systems_and_tools.py,sha256=EMHOF1AtUDaoSk0bbjl6oUKYAz4rTZjIBaF-6E6GspM,16816
|
761
761
|
tools/cli_commands/cost_report/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
762
762
|
tools/cli_commands/cost_report/aws.py,sha256=JtwDfhaYLfa4Uz1LR6OfSBh_3nBlb90kQq6i3MV_ims,4563
|
@@ -777,7 +777,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
777
777
|
tools/saas_promotion_state/saas_promotion_state.py,sha256=UfwwRLS5Ya4_Nh1w5n1dvoYtchQvYE9yj1VANt2IKqI,3925
|
778
778
|
tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
|
779
779
|
tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
|
780
|
-
qontract_reconcile-0.10.2.
|
781
|
-
qontract_reconcile-0.10.2.
|
782
|
-
qontract_reconcile-0.10.2.
|
783
|
-
qontract_reconcile-0.10.2.
|
780
|
+
qontract_reconcile-0.10.2.dev58.dist-info/METADATA,sha256=rQJYMzaII94AgfVybASnf6jWezt2vOg4-p1vRIuKKyc,24665
|
781
|
+
qontract_reconcile-0.10.2.dev58.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
782
|
+
qontract_reconcile-0.10.2.dev58.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
|
783
|
+
qontract_reconcile-0.10.2.dev58.dist-info/RECORD,,
|
reconcile/utils/output.py
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
import json
|
2
2
|
import re
|
3
|
-
from collections.abc import
|
3
|
+
from collections.abc import (
|
4
|
+
Iterable,
|
5
|
+
Mapping,
|
6
|
+
)
|
4
7
|
|
5
8
|
import yaml
|
6
9
|
from tabulate import tabulate
|
@@ -8,11 +11,11 @@ from tabulate import tabulate
|
|
8
11
|
|
9
12
|
def print_output(
|
10
13
|
options: Mapping[str, str | bool],
|
11
|
-
content:
|
14
|
+
content: list[dict],
|
12
15
|
columns: Iterable[str] = (),
|
13
16
|
) -> str | None:
|
14
17
|
if options["sort"]:
|
15
|
-
content
|
18
|
+
content.sort(key=lambda c: tuple(c.values()))
|
16
19
|
if options.get("to_string"):
|
17
20
|
for c in content:
|
18
21
|
for k, v in c.items():
|
tools/app_interface_reporter.py
CHANGED
@@ -2,7 +2,6 @@ import contextlib
|
|
2
2
|
import logging
|
3
3
|
import os
|
4
4
|
import textwrap
|
5
|
-
from collections.abc import Mapping, MutableMapping
|
6
5
|
from datetime import (
|
7
6
|
UTC,
|
8
7
|
datetime,
|
@@ -39,14 +38,50 @@ DASHDOTDB_SECRET = os.environ.get(
|
|
39
38
|
)
|
40
39
|
|
41
40
|
|
41
|
+
def promql(url, query, auth=None):
|
42
|
+
"""
|
43
|
+
Run an instant-query on the prometheus instance.
|
44
|
+
|
45
|
+
The returned structure is documented here:
|
46
|
+
https://prometheus.io/docs/prometheus/latest/querying/api/#instant-queries
|
47
|
+
|
48
|
+
:param url: base prometheus url (not the API endpoint).
|
49
|
+
:type url: string
|
50
|
+
:param query: this is a second value
|
51
|
+
:type query: string
|
52
|
+
:param auth: auth object
|
53
|
+
:type auth: requests.auth
|
54
|
+
:return: structure with the metrics
|
55
|
+
:rtype: dictionary
|
56
|
+
"""
|
57
|
+
|
58
|
+
url = os.path.join(url, "api/v1/query")
|
59
|
+
|
60
|
+
if auth is None:
|
61
|
+
auth = {}
|
62
|
+
|
63
|
+
params = {"query": query}
|
64
|
+
|
65
|
+
response = requests.get(url, params=params, auth=auth, timeout=60)
|
66
|
+
|
67
|
+
response.raise_for_status()
|
68
|
+
response = response.json()
|
69
|
+
|
70
|
+
# TODO ensure len response == 1
|
71
|
+
return response["data"]["result"]
|
72
|
+
|
73
|
+
|
42
74
|
class Report:
|
43
|
-
def __init__(self, app
|
75
|
+
def __init__(self, app, date):
|
44
76
|
settings = queries.get_app_interface_settings()
|
45
77
|
self.secret_reader = SecretReader(settings=settings)
|
46
|
-
self.app = app
|
47
78
|
# standard date format
|
48
|
-
|
49
|
-
|
79
|
+
if hasattr(date, "strftime"):
|
80
|
+
date = date.strftime("%Y-%m-%d")
|
81
|
+
|
82
|
+
self.app = app
|
83
|
+
self.date = date
|
84
|
+
self.report_sections = {}
|
50
85
|
|
51
86
|
# promotions
|
52
87
|
self.add_report_section("promotions", self.app.get("promotions"))
|
@@ -73,10 +108,10 @@ class Report:
|
|
73
108
|
)
|
74
109
|
|
75
110
|
@property
|
76
|
-
def path(self)
|
77
|
-
return
|
111
|
+
def path(self):
|
112
|
+
return "data/reports/{}/{}.yml".format(self.app["name"], self.date)
|
78
113
|
|
79
|
-
def content(self)
|
114
|
+
def content(self):
|
80
115
|
return {
|
81
116
|
"$schema": "/app-sre/report-1.yml",
|
82
117
|
"labels": {"app": self.app["name"]},
|
@@ -87,20 +122,21 @@ class Report:
|
|
87
122
|
"content": yaml.safe_dump(self.report_sections, sort_keys=False),
|
88
123
|
}
|
89
124
|
|
90
|
-
def to_yaml(self)
|
125
|
+
def to_yaml(self):
|
91
126
|
return yaml.safe_dump(self.content(), sort_keys=False)
|
92
127
|
|
93
|
-
def to_message(self)
|
128
|
+
def to_message(self):
|
94
129
|
return {"file_path": self.path, "content": self.to_yaml()}
|
95
130
|
|
96
|
-
def add_report_section(self, header
|
97
|
-
|
131
|
+
def add_report_section(self, header, content):
|
132
|
+
if not content:
|
133
|
+
content = None
|
134
|
+
|
135
|
+
self.report_sections[header] = content
|
98
136
|
|
99
137
|
@staticmethod
|
100
|
-
def get_vulnerability_content(
|
101
|
-
|
102
|
-
) -> list[dict]:
|
103
|
-
parsed_metrics: list[dict] = []
|
138
|
+
def get_vulnerability_content(container_vulnerabilities):
|
139
|
+
parsed_metrics = []
|
104
140
|
if not container_vulnerabilities:
|
105
141
|
return parsed_metrics
|
106
142
|
|
@@ -114,8 +150,8 @@ class Report:
|
|
114
150
|
return parsed_metrics
|
115
151
|
|
116
152
|
@staticmethod
|
117
|
-
def get_post_deploy_jobs_content(post_deploy_jobs
|
118
|
-
results
|
153
|
+
def get_post_deploy_jobs_content(post_deploy_jobs):
|
154
|
+
results = []
|
119
155
|
if not post_deploy_jobs:
|
120
156
|
return results
|
121
157
|
|
@@ -129,8 +165,8 @@ class Report:
|
|
129
165
|
return results
|
130
166
|
|
131
167
|
@staticmethod
|
132
|
-
def get_validations_content(deployment_validations
|
133
|
-
parsed_metrics
|
168
|
+
def get_validations_content(deployment_validations):
|
169
|
+
parsed_metrics = []
|
134
170
|
if not deployment_validations:
|
135
171
|
return parsed_metrics
|
136
172
|
|
@@ -144,8 +180,8 @@ class Report:
|
|
144
180
|
return parsed_metrics
|
145
181
|
|
146
182
|
@staticmethod
|
147
|
-
def get_slo_content(service_slo
|
148
|
-
parsed_metrics
|
183
|
+
def get_slo_content(service_slo):
|
184
|
+
parsed_metrics = []
|
149
185
|
if not service_slo:
|
150
186
|
return parsed_metrics
|
151
187
|
|
@@ -164,7 +200,7 @@ class Report:
|
|
164
200
|
return parsed_metrics
|
165
201
|
|
166
202
|
@staticmethod
|
167
|
-
def get_activity_content(activity
|
203
|
+
def get_activity_content(activity):
|
168
204
|
if not activity:
|
169
205
|
return []
|
170
206
|
|
@@ -178,9 +214,7 @@ class Report:
|
|
178
214
|
]
|
179
215
|
|
180
216
|
|
181
|
-
def get_apps_data(
|
182
|
-
date: datetime, month_delta: int = 1, thread_pool_size: int = 10
|
183
|
-
) -> list[dict]:
|
217
|
+
def get_apps_data(date, month_delta=1, thread_pool_size=10):
|
184
218
|
settings = queries.get_app_interface_settings()
|
185
219
|
secret_reader = SecretReader(settings)
|
186
220
|
|
@@ -263,9 +297,9 @@ def get_apps_data(
|
|
263
297
|
if namespace["app"]["name"] != app["name"]:
|
264
298
|
continue
|
265
299
|
app_namespaces.append(namespace)
|
266
|
-
vuln_mx
|
267
|
-
validt_mx
|
268
|
-
slo_mx
|
300
|
+
vuln_mx = {}
|
301
|
+
validt_mx = {}
|
302
|
+
slo_mx = {}
|
269
303
|
for family in text_string_to_metric_families(vuln_metrics):
|
270
304
|
for sample in family.samples:
|
271
305
|
if sample.name == "imagemanifestvuln_total":
|
@@ -341,7 +375,7 @@ def get_apps_data(
|
|
341
375
|
return apps
|
342
376
|
|
343
377
|
|
344
|
-
def get_build_history(job
|
378
|
+
def get_build_history(job):
|
345
379
|
try:
|
346
380
|
logging.info(f"getting build history for {job['name']}")
|
347
381
|
job["build_history"] = job["jenkins"].get_build_history(
|
@@ -352,9 +386,7 @@ def get_build_history(job: MutableMapping) -> MutableMapping:
|
|
352
386
|
return job
|
353
387
|
|
354
388
|
|
355
|
-
def get_build_history_pool(
|
356
|
-
jenkins_map: Mapping, jobs: Mapping, timestamp_limit: int, thread_pool_size: int
|
357
|
-
) -> dict:
|
389
|
+
def get_build_history_pool(jenkins_map, jobs, timestamp_limit, thread_pool_size):
|
358
390
|
history_to_get = []
|
359
391
|
for instance, _jobs in jobs.items():
|
360
392
|
jenkins = jenkins_map[instance]
|
@@ -379,7 +411,7 @@ def get_build_history_pool(
|
|
379
411
|
return history
|
380
412
|
|
381
413
|
|
382
|
-
def get_repo_url(job
|
414
|
+
def get_repo_url(job):
|
383
415
|
repo_url_raw = job["properties"][0]["github"]["url"]
|
384
416
|
return repo_url_raw.strip("/").replace(".git", "")
|
385
417
|
|
@@ -392,13 +424,8 @@ def get_repo_url(job: Mapping) -> str:
|
|
392
424
|
@gitlab_project_id
|
393
425
|
@click.option("--reports-path", help="path to write reports")
|
394
426
|
def main(
|
395
|
-
configfile
|
396
|
-
|
397
|
-
log_level: str,
|
398
|
-
gitlab_project_id: str,
|
399
|
-
reports_path: str,
|
400
|
-
thread_pool_size: int,
|
401
|
-
) -> None:
|
427
|
+
configfile, dry_run, log_level, gitlab_project_id, reports_path, thread_pool_size
|
428
|
+
):
|
402
429
|
init_env(log_level=log_level, config_file=configfile)
|
403
430
|
|
404
431
|
now = datetime.now()
|
@@ -449,9 +476,8 @@ def main(
|
|
449
476
|
gitlab_project_id=gitlab_project_id, sqs_or_gitlab="gitlab"
|
450
477
|
) as mr_cli:
|
451
478
|
result = mr.submit(cli=mr_cli)
|
452
|
-
|
453
|
-
logging.info(["created_mr", result.web_url])
|
479
|
+
logging.info(["created_mr", result.web_url])
|
454
480
|
|
455
481
|
|
456
482
|
if __name__ == "__main__":
|
457
|
-
main()
|
483
|
+
main() # pylint: disable=no-value-for-parameter
|
@@ -132,7 +132,7 @@ class GPGEncryptCommand:
|
|
132
132
|
|
133
133
|
return user["public_gpg_key"]
|
134
134
|
|
135
|
-
def _output(self, content: str)
|
135
|
+
def _output(self, content: str):
|
136
136
|
output = self._command_data.output
|
137
137
|
if not output:
|
138
138
|
print(content)
|
@@ -140,7 +140,7 @@ class GPGEncryptCommand:
|
|
140
140
|
with open(output, "w", encoding="locale") as f:
|
141
141
|
f.write(content)
|
142
142
|
|
143
|
-
def execute(self)
|
143
|
+
def execute(self):
|
144
144
|
secret = self._fetch_secret()
|
145
145
|
gpg_key = self._get_gpg_key()
|
146
146
|
encrypted_content = gpg.gpg_encrypt(
|