qontract-reconcile 0.10.1rc825__py3-none-any.whl → 0.10.1rc827__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.1rc825.dist-info → qontract_reconcile-0.10.1rc827.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc825.dist-info → qontract_reconcile-0.10.1rc827.dist-info}/RECORD +9 -8
- reconcile/gitlab_permissions.py +17 -2
- reconcile/statuspage/integrations/maintenances.py +27 -1
- reconcile/utils/batches.py +11 -0
- reconcile/utils/gitlab_api.py +7 -2
- {qontract_reconcile-0.10.1rc825.dist-info → qontract_reconcile-0.10.1rc827.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc825.dist-info → qontract_reconcile-0.10.1rc827.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc825.dist-info → qontract_reconcile-0.10.1rc827.dist-info}/top_level.txt +0 -0
{qontract_reconcile-0.10.1rc825.dist-info → qontract_reconcile-0.10.1rc827.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.1rc827
|
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.1rc825.dist-info → qontract_reconcile-0.10.1rc827.dist-info}/RECORD
RENAMED
@@ -35,7 +35,7 @@ reconcile/gitlab_labeler.py,sha256=IxE1XM5o4rDOFuR4cM2yAHTy4Uzdg3Nyz2mp7b8Fx1g,4
|
|
35
35
|
reconcile/gitlab_members.py,sha256=M6LwFOrwgvl1NNdOJa1mrQFUon-bEVv1AyhGeLed454,8443
|
36
36
|
reconcile/gitlab_mr_sqs_consumer.py,sha256=O46mdziPgGOndbU-0_UJKJVUaiEoVzJPEgKm4_UvYoI,2571
|
37
37
|
reconcile/gitlab_owners.py,sha256=sn9njaKOtqcvnhi2qtm-faAfAR4zNqflbSuusA9RUuI,13456
|
38
|
-
reconcile/gitlab_permissions.py,sha256=
|
38
|
+
reconcile/gitlab_permissions.py,sha256=Q_vGh8F_7-fUIDWZFigZpwkY4fvjxS7Tmq4jQCS56zw,2166
|
39
39
|
reconcile/gitlab_projects.py,sha256=K3tFf_aD1W4Ijp5q-9Qek3kwFGEWPcZ1kd7tzFJ4GyQ,1781
|
40
40
|
reconcile/integrations_manager.py,sha256=J_VV-HINI7YNav2NPIolePZkll-7VBuBXWAyMNhsM_Q,9535
|
41
41
|
reconcile/jenkins_base.py,sha256=0Gocu3fU2YTltaxBlbDQOUvP-7CP2OSQV1ZRwtWeVXw,875
|
@@ -445,7 +445,7 @@ reconcile/statuspage/state.py,sha256=HD9EOoKm_nEqCMLIwW809En3cq5VhyzKJPUbsh-bae8
|
|
445
445
|
reconcile/statuspage/status.py,sha256=mfRJ_tW7jM4_Vy_1cc8C0fKJEoA2GwrA3gJeV1KImAw,2834
|
446
446
|
reconcile/statuspage/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
447
447
|
reconcile/statuspage/integrations/components.py,sha256=49KHd_E9AdRvcEA6n75q1McZv2LfN-hRsW-WA7dgw9g,2651
|
448
|
-
reconcile/statuspage/integrations/maintenances.py,sha256=
|
448
|
+
reconcile/statuspage/integrations/maintenances.py,sha256=nG45b8A_ir9Ivtr4zH_VpHMahq8wev_M5igqK6T0hP0,4225
|
449
449
|
reconcile/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
450
450
|
reconcile/templates/aws_access_key_email.j2,sha256=2MUr1ERmyISzKgHqsWYLd-1Wbl-peUa-FsGUS-JLUFc,238
|
451
451
|
reconcile/templates/email.yml.j2,sha256=OZgczNRgXPj2gVYTgwQyHAQrMGu7xp-e4W1rX19GcrU,690
|
@@ -608,6 +608,7 @@ reconcile/utils/aggregated_list.py,sha256=pkYoBj7WwmaNgEefETqEOFTnQMcUzHE3mdsVdz
|
|
608
608
|
reconcile/utils/amtool.py,sha256=Rg6_TTvuS7M2QbOkIjy2sRetvf6aNVdv_DA9ugSgMi4,2303
|
609
609
|
reconcile/utils/aws_api.py,sha256=3VLg_MBih9SY9u43ZFbsaFNbDr086CJ7qQdTCfA-Rjo,66258
|
610
610
|
reconcile/utils/aws_helper.py,sha256=MDbv5jrNdqqJ5pfBxniGdJXBBO_EYc2_Uf2w9ZzeMNs,2854
|
611
|
+
reconcile/utils/batches.py,sha256=TtEm64a8lWhFuNbUVpFEmXVdU2Q0sTBrP_I0Cjbgh7g,320
|
611
612
|
reconcile/utils/binary.py,sha256=EsOGg82Y2QJh91SGJE0tYpBKqU0iaaagQVoYONBtQn8,2359
|
612
613
|
reconcile/utils/config.py,sha256=aId5zrPjM_84u_T4yTRE_Psu3zo5-5_JCR6_7Wgv5UQ,990
|
613
614
|
reconcile/utils/constants.py,sha256=pOUd97bqZdsAu5RWJ8NUs9cwCY7K9y0eW9VVeJ4fZIU,138
|
@@ -629,7 +630,7 @@ reconcile/utils/filtering.py,sha256=zZnHH0u0SaTDyzuFXZ_mREURGLvjEqQIQy4z-7QBVlc,
|
|
629
630
|
reconcile/utils/git.py,sha256=BdxXFgQ1XOZpS-4qb3qMsKTCFDG8MlE26rv1jAhvCkM,1560
|
630
631
|
reconcile/utils/git_secrets.py,sha256=0wGNL5mvDtVPRuu3vEQgld1Am64gIDJHtmu1_ZKxMAI,1973
|
631
632
|
reconcile/utils/github_api.py,sha256=_bttNxYKeam_tLVe27L7O4gKqSn6CeyuFnJn8tSaUVY,2488
|
632
|
-
reconcile/utils/gitlab_api.py,sha256=
|
633
|
+
reconcile/utils/gitlab_api.py,sha256=9C6oS98w1z-pDAAz5k9kgEvRO6r7hduHoOl7cufFr5s,27400
|
633
634
|
reconcile/utils/gpg.py,sha256=EKG7_fdMv8BMlV5yUdPiqoTx-KrzmVSEAl2sLkaKwWI,1123
|
634
635
|
reconcile/utils/gql.py,sha256=bzIYYYYGIO_4Db4sA-mnZUOPVNBELZD5EcIUSTbYG1o,13604
|
635
636
|
reconcile/utils/grouping.py,sha256=kWKivD14eAkiDneH_VIl_XyUdcVVQgiaKA9sLsuD2dw,441
|
@@ -811,8 +812,8 @@ tools/test/test_app_interface_metrics_exporter.py,sha256=SX7qL3D1SIRKFo95FoQztvf
|
|
811
812
|
tools/test/test_qontract_cli.py,sha256=_D61RFGAN5x44CY1tYbouhlGXXABwYfxKSWSQx3Jrss,4941
|
812
813
|
tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
|
813
814
|
tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
|
814
|
-
qontract_reconcile-0.10.
|
815
|
-
qontract_reconcile-0.10.
|
816
|
-
qontract_reconcile-0.10.
|
817
|
-
qontract_reconcile-0.10.
|
818
|
-
qontract_reconcile-0.10.
|
815
|
+
qontract_reconcile-0.10.1rc827.dist-info/METADATA,sha256=u5Eopi8oHyBimPZUq-Bc7QvHZttOUWrLGXF2f7raVV4,2314
|
816
|
+
qontract_reconcile-0.10.1rc827.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
817
|
+
qontract_reconcile-0.10.1rc827.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
|
818
|
+
qontract_reconcile-0.10.1rc827.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
|
819
|
+
qontract_reconcile-0.10.1rc827.dist-info/RECORD,,
|
reconcile/gitlab_permissions.py
CHANGED
@@ -5,14 +5,16 @@ from typing import Any
|
|
5
5
|
from sretoolbox.utils import threaded
|
6
6
|
|
7
7
|
from reconcile import queries
|
8
|
+
from reconcile.utils import batches
|
8
9
|
from reconcile.utils.defer import defer
|
9
10
|
from reconcile.utils.gitlab_api import GitLabApi
|
10
11
|
|
11
12
|
QONTRACT_INTEGRATION = "gitlab-permissions"
|
13
|
+
PAGE_SIZE = 100
|
12
14
|
|
13
15
|
|
14
16
|
def get_members_to_add(repo, gl, app_sre):
|
15
|
-
maintainers =
|
17
|
+
maintainers = get_all_app_sre_maintainers(repo, gl, app_sre)
|
16
18
|
if maintainers is None:
|
17
19
|
return []
|
18
20
|
if gl.user.username not in maintainers:
|
@@ -26,6 +28,20 @@ def get_members_to_add(repo, gl, app_sre):
|
|
26
28
|
return members_to_add
|
27
29
|
|
28
30
|
|
31
|
+
def get_all_app_sre_maintainers(repo, gl, app_sre):
|
32
|
+
app_sre_user_ids = [user.id for user in app_sre]
|
33
|
+
chunks = batches.batched(app_sre_user_ids, PAGE_SIZE)
|
34
|
+
app_sre_maintainers = (
|
35
|
+
gl.get_project_maintainers(repo, query=create_user_ids_query(chunk))
|
36
|
+
for chunk in chunks
|
37
|
+
)
|
38
|
+
return list(itertools.chain.from_iterable(app_sre_maintainers))
|
39
|
+
|
40
|
+
|
41
|
+
def create_user_ids_query(ids):
|
42
|
+
return {"user_ids": ",".join(str(id) for id in ids)}
|
43
|
+
|
44
|
+
|
29
45
|
@defer
|
30
46
|
def run(dry_run, thread_pool_size=10, defer=None):
|
31
47
|
instance = queries.get_gitlab_instance()
|
@@ -38,7 +54,6 @@ def run(dry_run, thread_pool_size=10, defer=None):
|
|
38
54
|
results = threaded.run(
|
39
55
|
get_members_to_add, repos, thread_pool_size, gl=gl, app_sre=app_sre
|
40
56
|
)
|
41
|
-
|
42
57
|
members_to_add = list(itertools.chain.from_iterable(results))
|
43
58
|
for m in members_to_add:
|
44
59
|
logging.info(["add_maintainer", m["repo"], m["user"].username])
|
@@ -1,10 +1,12 @@
|
|
1
1
|
import logging
|
2
2
|
import sys
|
3
|
-
from datetime import datetime, timezone
|
3
|
+
from datetime import datetime, timedelta, timezone
|
4
4
|
|
5
|
+
from reconcile.slack_base import slackapi_from_queries
|
5
6
|
from reconcile.statuspage.atlassian import AtlassianStatusPageProvider
|
6
7
|
from reconcile.statuspage.integration import get_binding_state, get_status_pages
|
7
8
|
from reconcile.statuspage.page import StatusMaintenance
|
9
|
+
from reconcile.statuspage.state import S3ComponentBindingState
|
8
10
|
from reconcile.utils.differ import diff_iterables
|
9
11
|
from reconcile.utils.runtime.integration import (
|
10
12
|
NoParams,
|
@@ -44,6 +46,25 @@ class StatusPageMaintenancesIntegration(QontractReconcileIntegration[NoParams]):
|
|
44
46
|
f"Delete StatusPage Maintenance is not supported at this time: {d.name}"
|
45
47
|
)
|
46
48
|
|
49
|
+
def notify(
|
50
|
+
self,
|
51
|
+
dry_run: bool,
|
52
|
+
desired_state: list[StatusMaintenance],
|
53
|
+
binding_state: S3ComponentBindingState,
|
54
|
+
) -> None:
|
55
|
+
now = datetime.now(timezone.utc)
|
56
|
+
slack = slackapi_from_queries(QONTRACT_INTEGRATION, init_usergroups=False)
|
57
|
+
for m in desired_state:
|
58
|
+
scheduled_start = datetime.fromisoformat(m.schedule_start)
|
59
|
+
if now <= scheduled_start <= now + timedelta(hours=1):
|
60
|
+
state_key = f"notifications/{m.name}"
|
61
|
+
if binding_state.state.exists(state_key):
|
62
|
+
continue
|
63
|
+
logging.info(f"Notify StatusPage Maintenance: {m.name}")
|
64
|
+
if not dry_run:
|
65
|
+
slack.chat_post_message(m.message)
|
66
|
+
binding_state.state.add(f"notifications/{m.name}")
|
67
|
+
|
47
68
|
def run(self, dry_run: bool = False) -> None:
|
48
69
|
binding_state = get_binding_state(self.name, self.secret_reader)
|
49
70
|
pages = get_status_pages()
|
@@ -75,6 +96,11 @@ class StatusPageMaintenancesIntegration(QontractReconcileIntegration[NoParams]):
|
|
75
96
|
current_state=current_state,
|
76
97
|
provider=page_provider,
|
77
98
|
)
|
99
|
+
self.notify(
|
100
|
+
dry_run=dry_run,
|
101
|
+
desired_state=desired_state,
|
102
|
+
binding_state=binding_state,
|
103
|
+
)
|
78
104
|
except Exception:
|
79
105
|
logging.exception(f"failed to reconcile statuspage {p.name}")
|
80
106
|
error = True
|
@@ -0,0 +1,11 @@
|
|
1
|
+
from collections.abc import Generator, Iterable
|
2
|
+
from itertools import islice
|
3
|
+
from typing import Any
|
4
|
+
|
5
|
+
|
6
|
+
def batched(iterable: Iterable[Any], size: int) -> Generator:
|
7
|
+
if size < 1:
|
8
|
+
raise ValueError("n must be at least one")
|
9
|
+
it = iter(iterable)
|
10
|
+
while batch := tuple(islice(it, size)):
|
11
|
+
yield batch
|
reconcile/utils/gitlab_api.py
CHANGED
@@ -223,14 +223,19 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
223
223
|
return any(mr.title == title for mr in mrs)
|
224
224
|
|
225
225
|
@retry()
|
226
|
-
def get_project_maintainers(
|
226
|
+
def get_project_maintainers(
|
227
|
+
self, repo_url: str | None = None, query: dict | None = None
|
228
|
+
) -> list[str] | None:
|
227
229
|
if repo_url is None:
|
228
230
|
project = self.project
|
229
231
|
else:
|
230
232
|
project = self.get_project(repo_url)
|
231
233
|
if project is None:
|
232
234
|
return None
|
233
|
-
|
235
|
+
if query:
|
236
|
+
members = self.get_items(project.members.all, query_parameters=query)
|
237
|
+
else:
|
238
|
+
members = self.get_items(project.members.all)
|
234
239
|
return [m.username for m in members if m.access_level >= 40]
|
235
240
|
|
236
241
|
def get_app_sre_group_users(self):
|
File without changes
|
File without changes
|
{qontract_reconcile-0.10.1rc825.dist-info → qontract_reconcile-0.10.1rc827.dist-info}/top_level.txt
RENAMED
File without changes
|