qontract-reconcile 0.10.2.dev50__py3-none-any.whl → 0.10.2.dev52__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.
Potentially problematic release.
This version of qontract-reconcile might be problematic. Click here for more details.
- {qontract_reconcile-0.10.2.dev50.dist-info → qontract_reconcile-0.10.2.dev52.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.2.dev50.dist-info → qontract_reconcile-0.10.2.dev52.dist-info}/RECORD +28 -29
- reconcile/aws_cloudwatch_log_retention/integration.py +10 -17
- reconcile/dashdotdb_dora.py +5 -4
- reconcile/gitlab_housekeeping.py +10 -6
- reconcile/terraform_tgw_attachments.py +5 -5
- reconcile/terraform_vpc_peerings.py +1 -1
- reconcile/utils/aggregated_list.py +30 -20
- reconcile/utils/aws_api.py +596 -169
- reconcile/utils/aws_helper.py +7 -7
- reconcile/utils/binary.py +14 -7
- reconcile/utils/config.py +9 -6
- reconcile/utils/defer.py +4 -2
- reconcile/utils/elasticsearch_exceptions.py +7 -4
- reconcile/utils/environ.py +5 -3
- reconcile/utils/exceptions.py +5 -2
- reconcile/utils/git.py +6 -4
- reconcile/utils/gitlab_api.py +103 -82
- reconcile/utils/mr/base.py +6 -3
- reconcile/utils/mr/update_access_report_base.py +2 -2
- reconcile/utils/output.py +3 -6
- reconcile/utils/vcs.py +5 -3
- reconcile/vpc_peerings_validator.py +21 -15
- tools/app_interface_reporter.py +44 -70
- tools/cli_commands/gpg_encrypt.py +2 -2
- tools/qontract_cli.py +317 -246
- reconcile/utils/data_structures.py +0 -13
- {qontract_reconcile-0.10.2.dev50.dist-info → qontract_reconcile-0.10.2.dev52.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev50.dist-info → qontract_reconcile-0.10.2.dev52.dist-info}/entry_points.txt +0 -0
reconcile/utils/gitlab_api.py
CHANGED
@@ -2,7 +2,9 @@ import logging
|
|
2
2
|
import os
|
3
3
|
import re
|
4
4
|
from collections.abc import (
|
5
|
+
Callable,
|
5
6
|
Iterable,
|
7
|
+
Mapping,
|
6
8
|
Set,
|
7
9
|
)
|
8
10
|
from functools import cached_property
|
@@ -12,6 +14,8 @@ from operator import (
|
|
12
14
|
)
|
13
15
|
from typing import (
|
14
16
|
Any,
|
17
|
+
Protocol,
|
18
|
+
Self,
|
15
19
|
TypedDict,
|
16
20
|
cast,
|
17
21
|
)
|
@@ -25,6 +29,7 @@ from gitlab.const import (
|
|
25
29
|
MAINTAINER_ACCESS,
|
26
30
|
OWNER_ACCESS,
|
27
31
|
REPORTER_ACCESS,
|
32
|
+
AccessLevel,
|
28
33
|
)
|
29
34
|
from gitlab.v4.objects import (
|
30
35
|
CurrentUser,
|
@@ -32,16 +37,20 @@ from gitlab.v4.objects import (
|
|
32
37
|
GroupMember,
|
33
38
|
PersonalAccessToken,
|
34
39
|
Project,
|
40
|
+
ProjectFile,
|
41
|
+
ProjectHook,
|
35
42
|
ProjectIssue,
|
36
43
|
ProjectIssueManager,
|
37
44
|
ProjectMergeRequest,
|
38
45
|
ProjectMergeRequestManager,
|
39
46
|
ProjectMergeRequestNote,
|
47
|
+
ProjectMergeRequestResourceLabelEvent,
|
48
|
+
User,
|
40
49
|
)
|
41
50
|
from sretoolbox.utils import retry
|
42
51
|
|
43
52
|
from reconcile.utils.metrics import gitlab_request
|
44
|
-
from reconcile.utils.secret_reader import SecretReader
|
53
|
+
from reconcile.utils.secret_reader import SecretReader, SecretReaderBase
|
45
54
|
|
46
55
|
# The following line will suppress
|
47
56
|
# `InsecureRequestWarning: Unverified HTTPS request is being made`
|
@@ -90,16 +99,20 @@ class GLGroupMember(TypedDict):
|
|
90
99
|
access_level: str
|
91
100
|
|
92
101
|
|
93
|
-
class
|
102
|
+
class GitlabUser(Protocol):
|
103
|
+
user: str
|
104
|
+
access_level: int
|
105
|
+
|
106
|
+
|
107
|
+
class GitLabApi:
|
94
108
|
def __init__(
|
95
109
|
self,
|
96
|
-
instance,
|
97
|
-
project_id=None,
|
98
|
-
settings=None,
|
99
|
-
secret_reader=None,
|
100
|
-
project_url=None,
|
101
|
-
|
102
|
-
timeout=30,
|
110
|
+
instance: Mapping,
|
111
|
+
project_id: str | int | None = None,
|
112
|
+
settings: Mapping | None = None,
|
113
|
+
secret_reader: SecretReaderBase | None = None,
|
114
|
+
project_url: str | None = None,
|
115
|
+
timeout: float = 30,
|
103
116
|
):
|
104
117
|
self.server = instance["url"]
|
105
118
|
if not secret_reader:
|
@@ -115,6 +128,7 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
115
128
|
timeout=timeout,
|
116
129
|
)
|
117
130
|
self._auth()
|
131
|
+
assert self.gl.user
|
118
132
|
self.user: CurrentUser = self.gl.user
|
119
133
|
if project_id is None:
|
120
134
|
# When project_id is not provide, we try to get the project
|
@@ -127,7 +141,6 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
127
141
|
else:
|
128
142
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
129
143
|
self.project = self.gl.projects.get(project_id)
|
130
|
-
self.saas_files = saas_files
|
131
144
|
|
132
145
|
@cached_property
|
133
146
|
def project_main_branch(self) -> str:
|
@@ -138,38 +151,40 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
138
151
|
|
139
152
|
@property
|
140
153
|
def main_branch(self) -> str:
|
141
|
-
return self.project_main_branch
|
154
|
+
return self.project_main_branch
|
142
155
|
|
143
|
-
def __enter__(self):
|
156
|
+
def __enter__(self) -> Self:
|
144
157
|
return self
|
145
158
|
|
146
|
-
def __exit__(self, *exc):
|
159
|
+
def __exit__(self, *exc: Any) -> None:
|
147
160
|
self.cleanup()
|
148
161
|
|
149
|
-
def __str__(self):
|
162
|
+
def __str__(self) -> str:
|
150
163
|
return self.project.web_url
|
151
164
|
|
152
|
-
def cleanup(self):
|
165
|
+
def cleanup(self) -> None:
|
153
166
|
"""
|
154
167
|
Close gl session.
|
155
168
|
"""
|
156
169
|
self.gl.session.close()
|
157
170
|
|
158
171
|
@retry()
|
159
|
-
def _auth(self):
|
172
|
+
def _auth(self) -> None:
|
160
173
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
161
174
|
self.gl.auth()
|
162
175
|
|
163
|
-
def create_branch(self, new_branch, source_branch):
|
176
|
+
def create_branch(self, new_branch: str, source_branch: str) -> None:
|
164
177
|
data = {"branch": new_branch, "ref": source_branch}
|
165
178
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
166
179
|
self.project.branches.create(data)
|
167
180
|
|
168
|
-
def delete_branch(self, branch):
|
181
|
+
def delete_branch(self, branch: str) -> None:
|
169
182
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
170
183
|
self.project.branches.delete(branch)
|
171
184
|
|
172
|
-
def create_commit(
|
185
|
+
def create_commit(
|
186
|
+
self, branch_name: str, commit_message: str, actions: Iterable[Mapping]
|
187
|
+
) -> None:
|
173
188
|
"""
|
174
189
|
actions is a list of 'action' dictionaries. The 'action' dict is
|
175
190
|
documented here: https://docs.gitlab.com/ee/api/commits.html
|
@@ -183,7 +198,9 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
183
198
|
"actions": actions,
|
184
199
|
})
|
185
200
|
|
186
|
-
def create_file(
|
201
|
+
def create_file(
|
202
|
+
self, branch_name: str, file_path: str, commit_message: str, content: str
|
203
|
+
) -> None:
|
187
204
|
data = {
|
188
205
|
"branch": branch_name,
|
189
206
|
"commit_message": commit_message,
|
@@ -194,7 +211,9 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
194
211
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
195
212
|
self.project.commits.create(data)
|
196
213
|
|
197
|
-
def delete_file(
|
214
|
+
def delete_file(
|
215
|
+
self, branch_name: str, file_path: str, commit_message: str
|
216
|
+
) -> None:
|
198
217
|
data = {
|
199
218
|
"branch": branch_name,
|
200
219
|
"commit_message": commit_message,
|
@@ -203,7 +222,9 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
203
222
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
204
223
|
self.project.commits.create(data)
|
205
224
|
|
206
|
-
def update_file(
|
225
|
+
def update_file(
|
226
|
+
self, branch_name: str, file_path: str, commit_message: str, content: str
|
227
|
+
) -> None:
|
207
228
|
data = {
|
208
229
|
"branch": branch_name,
|
209
230
|
"commit_message": commit_message,
|
@@ -216,12 +237,12 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
216
237
|
|
217
238
|
def create_mr(
|
218
239
|
self,
|
219
|
-
source_branch,
|
220
|
-
target_branch,
|
221
|
-
title,
|
222
|
-
remove_source_branch=True,
|
223
|
-
labels=None,
|
224
|
-
):
|
240
|
+
source_branch: str,
|
241
|
+
target_branch: str,
|
242
|
+
title: str,
|
243
|
+
remove_source_branch: bool = True,
|
244
|
+
labels: Iterable[str] | None = None,
|
245
|
+
) -> ProjectMergeRequest:
|
225
246
|
if labels is None:
|
226
247
|
labels = []
|
227
248
|
data = {
|
@@ -232,7 +253,7 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
232
253
|
"labels": labels,
|
233
254
|
}
|
234
255
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
235
|
-
return self.project.mergerequests.create(data)
|
256
|
+
return cast(ProjectMergeRequest, self.project.mergerequests.create(data))
|
236
257
|
|
237
258
|
def mr_exists(self, title: str) -> bool:
|
238
259
|
mrs = self.get_merge_requests(state=MRState.OPENED)
|
@@ -253,7 +274,7 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
253
274
|
members = self.get_items(project.members_all.list)
|
254
275
|
return [m.username for m in members if m.access_level >= 40]
|
255
276
|
|
256
|
-
def get_app_sre_group_users(self):
|
277
|
+
def get_app_sre_group_users(self) -> list[GroupMember]:
|
257
278
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
258
279
|
app_sre_group = self.gl.groups.get("app-sre")
|
259
280
|
return self.get_items(app_sre_group.members.list)
|
@@ -304,7 +325,9 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
304
325
|
if not self._is_bot_username(m.username)
|
305
326
|
]
|
306
327
|
|
307
|
-
def add_project_member(
|
328
|
+
def add_project_member(
|
329
|
+
self, repo_url: str, user: GroupMember, access: str = "maintainer"
|
330
|
+
) -> None:
|
308
331
|
project = self.get_project(repo_url)
|
309
332
|
if project is None:
|
310
333
|
return
|
@@ -316,7 +339,7 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
316
339
|
member.access_level = access_level
|
317
340
|
member.save()
|
318
341
|
|
319
|
-
def add_group_member(self, group, user):
|
342
|
+
def add_group_member(self, group: Group, user: GitlabUser) -> None:
|
320
343
|
gitlab_user = self.get_user(user.user)
|
321
344
|
if gitlab_user is not None:
|
322
345
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
@@ -331,41 +354,34 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
331
354
|
member.access_level = user.access_level
|
332
355
|
member.save()
|
333
356
|
|
334
|
-
def remove_group_member(self, group, user_id):
|
357
|
+
def remove_group_member(self, group: Group, user_id: str) -> None:
|
335
358
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
336
359
|
group.members.delete(user_id)
|
337
360
|
|
338
|
-
def change_access(self, member, access_level):
|
361
|
+
def change_access(self, member: GroupMember, access_level: int) -> None:
|
339
362
|
member.access_level = access_level
|
340
363
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
341
364
|
member.save()
|
342
365
|
|
343
366
|
@staticmethod
|
344
|
-
def get_access_level_string(access_level):
|
345
|
-
|
346
|
-
return "owner"
|
347
|
-
if access_level == MAINTAINER_ACCESS:
|
348
|
-
return "maintainer"
|
349
|
-
if access_level == DEVELOPER_ACCESS:
|
350
|
-
return "developer"
|
351
|
-
if access_level == REPORTER_ACCESS:
|
352
|
-
return "reporter"
|
353
|
-
if access_level == GUEST_ACCESS:
|
354
|
-
return "guest"
|
367
|
+
def get_access_level_string(access_level: int) -> str:
|
368
|
+
return AccessLevel(access_level).name.lower()
|
355
369
|
|
356
370
|
@staticmethod
|
357
|
-
def get_access_level(access):
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
371
|
+
def get_access_level(access: str) -> int:
|
372
|
+
match access.lower():
|
373
|
+
case "owner":
|
374
|
+
return OWNER_ACCESS
|
375
|
+
case "maintainer":
|
376
|
+
return MAINTAINER_ACCESS
|
377
|
+
case "developer":
|
378
|
+
return DEVELOPER_ACCESS
|
379
|
+
case "reporter":
|
380
|
+
return REPORTER_ACCESS
|
381
|
+
case "guest":
|
382
|
+
return GUEST_ACCESS
|
383
|
+
case _:
|
384
|
+
raise ValueError(f"Invalid access level: {access}")
|
369
385
|
|
370
386
|
def get_group_id_and_projects(self, group_name: str) -> tuple[str, list[str]]:
|
371
387
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
@@ -376,11 +392,11 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
376
392
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
377
393
|
return self.gl.groups.get(group_name)
|
378
394
|
|
379
|
-
def create_project(self, group_id, project):
|
395
|
+
def create_project(self, group_id: str, project: str) -> None:
|
380
396
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
381
397
|
self.gl.projects.create({"name": project, "namespace_id": group_id})
|
382
398
|
|
383
|
-
def get_project_url(self, group, project):
|
399
|
+
def get_project_url(self, group: str, project: str) -> str:
|
384
400
|
return f"{self.server}/{group}/{project}"
|
385
401
|
|
386
402
|
@retry()
|
@@ -398,17 +414,19 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
398
414
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
399
415
|
return self.gl.projects.get(project_id)
|
400
416
|
|
401
|
-
def get_issues(self, state):
|
417
|
+
def get_issues(self, state: str) -> list[ProjectIssue]:
|
402
418
|
return self.get_items(self.project.issues.list, state=state)
|
403
419
|
|
404
|
-
def get_merge_request(self, mr_id):
|
420
|
+
def get_merge_request(self, mr_id: str | int) -> ProjectMergeRequest:
|
405
421
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
406
422
|
return self.project.mergerequests.get(mr_id)
|
407
423
|
|
408
|
-
def get_merge_requests(self, state):
|
424
|
+
def get_merge_requests(self, state: str) -> list[ProjectMergeRequest]:
|
409
425
|
return self.get_items(self.project.mergerequests.list, state=state)
|
410
426
|
|
411
|
-
def get_merge_request_label_events(
|
427
|
+
def get_merge_request_label_events(
|
428
|
+
self, mr: ProjectMergeRequest
|
429
|
+
) -> list[ProjectMergeRequestResourceLabelEvent]:
|
412
430
|
return self.get_items(mr.resourcelabelevents.list)
|
413
431
|
|
414
432
|
def get_merge_request_pipelines(self, mr: ProjectMergeRequest) -> list[dict]:
|
@@ -506,7 +524,7 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
506
524
|
def add_labels_to_merge_request(
|
507
525
|
merge_request: ProjectMergeRequest,
|
508
526
|
labels: Iterable[str],
|
509
|
-
):
|
527
|
+
) -> None:
|
510
528
|
"""Adds labels to a Merge Request"""
|
511
529
|
# merge_request maybe stale, refresh it to reduce the possibility of labels overwriting
|
512
530
|
GitLabApi.refresh_labels(merge_request)
|
@@ -557,7 +575,7 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
557
575
|
|
558
576
|
# TODO: deprecated this method as new support of list(get_all=True), and figure out request counter metrics
|
559
577
|
@staticmethod
|
560
|
-
def get_items(method, **kwargs):
|
578
|
+
def get_items(method: Callable, **kwargs: Any) -> list:
|
561
579
|
all_items = []
|
562
580
|
page = 1
|
563
581
|
while True:
|
@@ -575,7 +593,7 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
575
593
|
self.project.labels.create({"name": label_text, "color": label_color})
|
576
594
|
|
577
595
|
@staticmethod
|
578
|
-
def refresh_labels(item: ProjectMergeRequest | ProjectIssue):
|
596
|
+
def refresh_labels(item: ProjectMergeRequest | ProjectIssue) -> None:
|
579
597
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
580
598
|
manager: ProjectMergeRequestManager | ProjectIssueManager
|
581
599
|
match item:
|
@@ -613,7 +631,7 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
613
631
|
def remove_label(
|
614
632
|
item: ProjectMergeRequest | ProjectIssue,
|
615
633
|
label: str,
|
616
|
-
):
|
634
|
+
) -> None:
|
617
635
|
# item maybe stale, refresh it to reduce the possibility of labels overwriting
|
618
636
|
GitLabApi.refresh_labels(item)
|
619
637
|
|
@@ -628,7 +646,7 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
628
646
|
def remove_labels(
|
629
647
|
item: ProjectMergeRequest | ProjectIssue,
|
630
648
|
labels: Iterable[str],
|
631
|
-
):
|
649
|
+
) -> None:
|
632
650
|
# item maybe stale, refresh it to reduce the possibility of labels overwriting
|
633
651
|
GitLabApi.refresh_labels(item)
|
634
652
|
|
@@ -643,21 +661,21 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
643
661
|
item.save()
|
644
662
|
|
645
663
|
@staticmethod
|
646
|
-
def close(item):
|
664
|
+
def close(item: ProjectIssue | ProjectMergeRequest) -> None:
|
647
665
|
item.state_event = "close"
|
648
666
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
649
667
|
item.save()
|
650
668
|
|
651
|
-
def get_user(self, username):
|
669
|
+
def get_user(self, username: str) -> User | None:
|
652
670
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
653
|
-
user = self.gl.users.list(search=username, page=1, per_page=1)
|
654
|
-
if
|
655
|
-
logging.error(username
|
656
|
-
return
|
671
|
+
user = cast(list[User], self.gl.users.list(search=username, page=1, per_page=1))
|
672
|
+
if not user:
|
673
|
+
logging.error(f"{username} user not found")
|
674
|
+
return None
|
657
675
|
return user[0]
|
658
676
|
|
659
677
|
@retry()
|
660
|
-
def get_project_hooks(self, repo_url):
|
678
|
+
def get_project_hooks(self, repo_url: str) -> list[ProjectHook]:
|
661
679
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
662
680
|
p = self.get_project(repo_url)
|
663
681
|
if p is None:
|
@@ -666,7 +684,7 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
666
684
|
# TODO: get_all may send multiple requests, update metrics accordingly
|
667
685
|
return p.hooks.list(per_page=100, get_all=True)
|
668
686
|
|
669
|
-
def create_project_hook(self, repo_url, data):
|
687
|
+
def create_project_hook(self, repo_url: str, data: Mapping) -> None:
|
670
688
|
p = self.get_project(repo_url)
|
671
689
|
if p is None:
|
672
690
|
return
|
@@ -682,13 +700,13 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
682
700
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
683
701
|
p.hooks.create(hook)
|
684
702
|
|
685
|
-
def get_repository_tree(self, ref="master"):
|
703
|
+
def get_repository_tree(self, ref: str = "master") -> list[dict]:
|
686
704
|
"""
|
687
705
|
Wrapper around Gitlab.repository_tree() with pagination enabled.
|
688
706
|
"""
|
689
707
|
return self.get_items(self.project.repository_tree, ref=ref, recursive=True)
|
690
708
|
|
691
|
-
def get_file(self, path, ref="master"):
|
709
|
+
def get_file(self, path: str, ref: str = "master") -> ProjectFile | None:
|
692
710
|
"""
|
693
711
|
Wrapper around Gitlab.files.get() with exception handling.
|
694
712
|
"""
|
@@ -699,7 +717,7 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
699
717
|
except gitlab.exceptions.GitlabGetError:
|
700
718
|
return None
|
701
719
|
|
702
|
-
def initiate_saas_bundle_repo(self, repo_url):
|
720
|
+
def initiate_saas_bundle_repo(self, repo_url: str) -> None:
|
703
721
|
project = self.get_project(repo_url)
|
704
722
|
if project is None:
|
705
723
|
return
|
@@ -714,7 +732,7 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
714
732
|
self.create_branch("production", "master")
|
715
733
|
|
716
734
|
def is_last_action_by_team(
|
717
|
-
self, mr, team_usernames: list[str], hold_labels: list[str]
|
735
|
+
self, mr: ProjectMergeRequest, team_usernames: list[str], hold_labels: list[str]
|
718
736
|
) -> bool:
|
719
737
|
# what is the time of the last app-sre response?
|
720
738
|
last_action_by_team = None
|
@@ -731,7 +749,10 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
731
749
|
# labels
|
732
750
|
gitlab_request.labels(integration=INTEGRATION_NAME).inc()
|
733
751
|
# TODO: this may send multiple requests, update metrics accordingly
|
734
|
-
label_events =
|
752
|
+
label_events = cast(
|
753
|
+
list[ProjectMergeRequestResourceLabelEvent],
|
754
|
+
mr.resourcelabelevents.list(get_all=True),
|
755
|
+
)
|
735
756
|
for label in reversed(label_events):
|
736
757
|
if label.action == "add" and label.label["name"] in hold_labels:
|
737
758
|
username = label.user["username"]
|
@@ -798,7 +819,7 @@ class GitLabApi: # pylint: disable=too-many-public-methods
|
|
798
819
|
return None
|
799
820
|
|
800
821
|
def last_comment(
|
801
|
-
self, mr: ProjectMergeRequest, exclude_bot=True
|
822
|
+
self, mr: ProjectMergeRequest, exclude_bot: bool = True
|
802
823
|
) -> dict[str, Any] | None:
|
803
824
|
comments = self.get_merge_request_comments(mr)
|
804
825
|
comments.sort(key=itemgetter("created_at"), reverse=True)
|
reconcile/utils/mr/base.py
CHANGED
@@ -5,7 +5,7 @@ from abc import (
|
|
5
5
|
abstractmethod,
|
6
6
|
)
|
7
7
|
from collections.abc import Iterable
|
8
|
-
from typing import Any
|
8
|
+
from typing import Any, cast
|
9
9
|
from uuid import uuid4
|
10
10
|
|
11
11
|
from gitlab.exceptions import GitlabError
|
@@ -224,8 +224,11 @@ class MergeRequestBase(ABC):
|
|
224
224
|
)
|
225
225
|
|
226
226
|
def diffs(self, gitlab_cli: GitLabApi) -> Any:
|
227
|
-
return
|
228
|
-
|
227
|
+
return cast(
|
228
|
+
dict,
|
229
|
+
gitlab_cli.project.repository_compare(
|
230
|
+
from_=gitlab_cli.main_branch, to=self.branch
|
231
|
+
),
|
229
232
|
)["diffs"]
|
230
233
|
|
231
234
|
def submit(self, cli: MRClient) -> Any | None:
|
@@ -100,10 +100,10 @@ class UpdateAccessReportBase(MergeRequestBase):
|
|
100
100
|
return new_workbook_md
|
101
101
|
|
102
102
|
def process(self, gitlab_cli: GitLabApi) -> None:
|
103
|
-
|
103
|
+
workbook_file = gitlab_cli.project.files.get(
|
104
104
|
file_path=self._workbook_file_name, ref=self.branch
|
105
105
|
)
|
106
|
-
workbook_md = self._update_workbook(
|
106
|
+
workbook_md = self._update_workbook(workbook_file.decode().decode("utf-8"))
|
107
107
|
|
108
108
|
if not self._dry_run:
|
109
109
|
logging.info(
|
reconcile/utils/output.py
CHANGED
@@ -1,9 +1,6 @@
|
|
1
1
|
import json
|
2
2
|
import re
|
3
|
-
from collections.abc import
|
4
|
-
Iterable,
|
5
|
-
Mapping,
|
6
|
-
)
|
3
|
+
from collections.abc import Iterable, Mapping
|
7
4
|
|
8
5
|
import yaml
|
9
6
|
from tabulate import tabulate
|
@@ -11,11 +8,11 @@ from tabulate import tabulate
|
|
11
8
|
|
12
9
|
def print_output(
|
13
10
|
options: Mapping[str, str | bool],
|
14
|
-
content:
|
11
|
+
content: Iterable[dict],
|
15
12
|
columns: Iterable[str] = (),
|
16
13
|
) -> str | None:
|
17
14
|
if options["sort"]:
|
18
|
-
content
|
15
|
+
content = sorted(content, key=lambda c: tuple(c.values()))
|
19
16
|
if options.get("to_string"):
|
20
17
|
for c in content:
|
21
18
|
for k, v in c.items():
|
reconcile/utils/vcs.py
CHANGED
@@ -222,9 +222,11 @@ class VCS:
|
|
222
222
|
if not file_path.startswith("data")
|
223
223
|
else file_path
|
224
224
|
)
|
225
|
-
return
|
226
|
-
file_path=file_path, ref="master"
|
227
|
-
|
225
|
+
return (
|
226
|
+
self._app_interface_api.project.files.get(file_path=file_path, ref="master")
|
227
|
+
.decode()
|
228
|
+
.decode("utf-8")
|
229
|
+
)
|
228
230
|
|
229
231
|
def get_open_app_interface_merge_requests(self) -> list[ProjectMergeRequest]:
|
230
232
|
return self._app_interface_api.get_merge_requests(state=MRState.OPENED)
|
@@ -8,6 +8,8 @@ from typing import (
|
|
8
8
|
from reconcile import queries
|
9
9
|
from reconcile.gql_definitions.vpc_peerings_validator import vpc_peerings_validator
|
10
10
|
from reconcile.gql_definitions.vpc_peerings_validator.vpc_peerings_validator import (
|
11
|
+
ClusterPeeringConnectionAccountV1,
|
12
|
+
ClusterPeeringConnectionAccountVPCMeshV1,
|
11
13
|
ClusterPeeringConnectionClusterAccepterV1,
|
12
14
|
ClusterPeeringConnectionClusterRequesterV1,
|
13
15
|
ClusterV1,
|
@@ -27,21 +29,23 @@ def validate_no_cidr_overlap(
|
|
27
29
|
|
28
30
|
for cluster in clusters:
|
29
31
|
if cluster.peering:
|
32
|
+
assert cluster.network
|
30
33
|
peerings_entries = [
|
31
34
|
{
|
32
35
|
"provider": "cluster-self-vpc",
|
33
36
|
"vpc_name": cluster.name,
|
34
|
-
"cidr_block": cluster.network.vpc,
|
37
|
+
"cidr_block": cluster.network.vpc,
|
35
38
|
},
|
36
39
|
]
|
37
40
|
for peering in cluster.peering.connections:
|
38
|
-
if peering
|
39
|
-
aws_account_uid = peering.account.uid
|
41
|
+
if isinstance(peering, ClusterPeeringConnectionAccountVPCMeshV1):
|
42
|
+
aws_account_uid = peering.account.uid
|
40
43
|
settings = queries.get_secret_reader_settings()
|
41
44
|
accounts = queries.get_aws_accounts(uid=aws_account_uid)
|
42
45
|
awsapi = AWSApi(1, accounts, settings=settings, init_users=False)
|
43
|
-
|
44
|
-
|
46
|
+
mesh_results = awsapi.get_vpcs_details(
|
47
|
+
accounts[0], peering.tags or {}
|
48
|
+
)
|
45
49
|
for mesh_result in mesh_results:
|
46
50
|
vpc_peering_info = {
|
47
51
|
"provider": peering.provider,
|
@@ -49,22 +53,24 @@ def validate_no_cidr_overlap(
|
|
49
53
|
"cidr_block": mesh_result["cidr_block"],
|
50
54
|
}
|
51
55
|
peerings_entries.append(vpc_peering_info)
|
52
|
-
if peering
|
53
|
-
cidr_block = str(peering.vpc.cidr_block)
|
56
|
+
if isinstance(peering, ClusterPeeringConnectionAccountV1):
|
57
|
+
cidr_block = str(peering.vpc.cidr_block)
|
54
58
|
vpc_peering_info = {
|
55
59
|
"provider": peering.provider,
|
56
|
-
"vpc_name": peering.vpc.name,
|
60
|
+
"vpc_name": peering.vpc.name,
|
57
61
|
"cidr_block": cidr_block,
|
58
62
|
}
|
59
63
|
peerings_entries.append(vpc_peering_info)
|
60
|
-
if
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
+
if isinstance(
|
65
|
+
peering,
|
66
|
+
ClusterPeeringConnectionClusterRequesterV1
|
67
|
+
| ClusterPeeringConnectionClusterAccepterV1,
|
68
|
+
):
|
69
|
+
assert peering.cluster.network
|
64
70
|
vpc_peering_info = {
|
65
71
|
"provider": peering.provider,
|
66
|
-
"vpc_name": peering.cluster.name,
|
67
|
-
"cidr_block": peering.cluster.network.vpc,
|
72
|
+
"vpc_name": peering.cluster.name,
|
73
|
+
"cidr_block": peering.cluster.network.vpc,
|
68
74
|
}
|
69
75
|
peerings_entries.append(vpc_peering_info)
|
70
76
|
find_overlap = find_cidr_overlap(cluster.name, peerings_entries)
|
@@ -74,7 +80,7 @@ def validate_no_cidr_overlap(
|
|
74
80
|
|
75
81
|
|
76
82
|
def find_cidr_overlap(cluster_name: str, input_list: list):
|
77
|
-
for i in range(len(input_list)):
|
83
|
+
for i in range(len(input_list)):
|
78
84
|
compared_vpc = input_list[i]
|
79
85
|
for j in range(i + 1, len(input_list)):
|
80
86
|
comparing_vpc = input_list[j]
|