qontract-reconcile 0.10.2.dev134__py3-none-any.whl → 0.10.2.dev135__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qontract-reconcile
3
- Version: 0.10.2.dev134
3
+ Version: 0.10.2.dev135
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
@@ -43,7 +43,7 @@ Requires-Dist: pygithub<1.59,>=1.58
43
43
  Requires-Dist: pyjwt~=2.7
44
44
  Requires-Dist: pyopenssl~=23.0
45
45
  Requires-Dist: pypd<1.2.0,>=1.1.0
46
- Requires-Dist: python-gitlab~=4.6
46
+ Requires-Dist: python-gitlab==5.6.0
47
47
  Requires-Dist: requests-oauthlib~=1.3
48
48
  Requires-Dist: requests~=2.32
49
49
  Requires-Dist: rich<14.0.0,>=13.3.0
@@ -602,14 +602,14 @@ reconcile/utils/external_resources.py,sha256=YzTb0xAcNdmKO326mGQy7BmST56CZcdru4l
602
602
  reconcile/utils/filtering.py,sha256=S4PbMHuFr3ED0P2Q_ea5CAaB7FimI62B-F5YTaKrphA,402
603
603
  reconcile/utils/git.py,sha256=o4p9m8jlzCJDcutl2HErvGLhL6sZ1NB4Aw3zGcQIzso,2427
604
604
  reconcile/utils/github_api.py,sha256=y3fxty7FKvfhdzfHgGSaIstL6A_Y2loUcMiyIK5TMDg,2750
605
- reconcile/utils/gitlab_api.py,sha256=WMTNXtldW0L9qhC0rfd3ssGeHu9khmzU1RBG6lZHpQM,29723
605
+ reconcile/utils/gitlab_api.py,sha256=SYSKm5WulWinO7P-ZYy_oerKdfNHHob2V6i7Mfr4oCU,26643
606
606
  reconcile/utils/gpg.py,sha256=EKG7_fdMv8BMlV5yUdPiqoTx-KrzmVSEAl2sLkaKwWI,1123
607
607
  reconcile/utils/gql.py,sha256=C0thIm_k9MBldfqwHzyqtYZk9sIvMdm9IbbnXLGwjD8,14158
608
608
  reconcile/utils/grouping.py,sha256=vr9SFHZ7bqmHYrvYcEZt-Er3-yQYfAAdq5sHLZVmXPY,456
609
609
  reconcile/utils/helm.py,sha256=wC1h0GylhDFeZ6hZEtYy2giAGIIQroaQhkAtURoSlI8,3893
610
610
  reconcile/utils/helpers.py,sha256=womAD2bKPUAFOjHvNPAe_2Hsb-oVTxuQiYPGeR-Thp0,1772
611
611
  reconcile/utils/imap_client.py,sha256=h8YDiCSCvroErhpH_-KGYI7Y2WU2Q2oSpuxDFbOkSbY,1989
612
- reconcile/utils/instrumented_wrappers.py,sha256=aAO4q6LMpHjJIaFdrouwCEIEl5u3thCCBPSuoEloC60,1082
612
+ reconcile/utils/instrumented_wrappers.py,sha256=VqT4s0Bdicv224-uSeSaugtHXm-xJ3oSeBiqj0QQRiU,1942
613
613
  reconcile/utils/jenkins_api.py,sha256=RaKuZmO7_lbI-hE6c_Pq2a6CQdmBVj7BcP2jR68cIbI,7081
614
614
  reconcile/utils/jira_client.py,sha256=oWi7rcAP1C59oIBTPg6kRntI25Zm4e7FyvdVYvZ9RZ8,7881
615
615
  reconcile/utils/jjb_client.py,sha256=4YqeXEkO4p6QtJE_fkaD1XuLKbe9l3g0W7AVpcjJ3yg,15187
@@ -791,7 +791,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
791
791
  tools/saas_promotion_state/saas_promotion_state.py,sha256=UfwwRLS5Ya4_Nh1w5n1dvoYtchQvYE9yj1VANt2IKqI,3925
792
792
  tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
793
793
  tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
794
- qontract_reconcile-0.10.2.dev134.dist-info/METADATA,sha256=ZwWSIqfFCLGRV3nVjvaMU8JI-acP431ZIzUOA9ze7D8,24566
795
- qontract_reconcile-0.10.2.dev134.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
796
- qontract_reconcile-0.10.2.dev134.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
797
- qontract_reconcile-0.10.2.dev134.dist-info/RECORD,,
794
+ qontract_reconcile-0.10.2.dev135.dist-info/METADATA,sha256=OmObsM9l7n-M8XKiFzj-KByzt8R4NLvzOLm22SNnumM,24568
795
+ qontract_reconcile-0.10.2.dev135.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
796
+ qontract_reconcile-0.10.2.dev135.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
797
+ qontract_reconcile-0.10.2.dev135.dist-info/RECORD,,
@@ -21,8 +21,12 @@ from typing import (
21
21
  )
22
22
  from urllib.parse import urlparse
23
23
 
24
- import gitlab
25
24
  import urllib3
25
+ from gitlab import (
26
+ Gitlab,
27
+ GitlabCreateError,
28
+ GitlabGetError,
29
+ )
26
30
  from gitlab.const import (
27
31
  DEVELOPER_ACCESS,
28
32
  GUEST_ACCESS,
@@ -47,8 +51,10 @@ from gitlab.v4.objects import (
47
51
  ProjectMergeRequestResourceLabelEvent,
48
52
  User,
49
53
  )
54
+ from requests import Session
50
55
  from sretoolbox.utils import retry
51
56
 
57
+ from reconcile.utils.instrumented_wrappers import InstrumentedSession
52
58
  from reconcile.utils.metrics import gitlab_request
53
59
  from reconcile.utils.secret_reader import SecretReader, SecretReaderBase
54
60
 
@@ -59,8 +65,6 @@ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
59
65
 
60
66
  MR_DESCRIPTION_COMMENT_ID = 0
61
67
 
62
- # The default value is there for unit test
63
- INTEGRATION_NAME = os.getenv("INTEGRATION_NAME", "")
64
68
  DEFAULT_MAIN_BRANCH = "master"
65
69
 
66
70
 
@@ -113,19 +117,24 @@ class GitLabApi:
113
117
  secret_reader: SecretReaderBase | None = None,
114
118
  project_url: str | None = None,
115
119
  timeout: float = 30,
120
+ session: Session | None = None,
116
121
  ):
117
122
  self.server = instance["url"]
118
123
  if not secret_reader:
119
124
  secret_reader = SecretReader(settings=settings)
120
125
  token = secret_reader.read(instance["token"])
121
- self.ssl_verify = instance["sslVerify"]
122
- if self.ssl_verify is None:
123
- self.ssl_verify = True
124
- self.gl = gitlab.Gitlab(
126
+ self.ssl_verify = (
127
+ instance["sslVerify"] if instance["sslVerify"] is not None else True
128
+ )
129
+ self.session = session or InstrumentedSession(
130
+ gitlab_request.labels(integration=os.getenv("INTEGRATION_NAME", ""))
131
+ )
132
+ self.gl = Gitlab(
125
133
  self.server,
126
134
  private_token=token,
127
135
  ssl_verify=self.ssl_verify,
128
136
  timeout=timeout,
137
+ session=self.session,
129
138
  )
130
139
  self._auth()
131
140
  assert self.gl.user
@@ -136,10 +145,8 @@ class GitLabApi:
136
145
  if project_url is not None:
137
146
  parsed_project_url = urlparse(project_url)
138
147
  name_with_namespace = parsed_project_url.path.strip("/")
139
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
140
148
  self.project = self.gl.projects.get(name_with_namespace)
141
149
  else:
142
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
143
150
  self.project = self.gl.projects.get(project_id)
144
151
 
145
152
  @cached_property
@@ -164,22 +171,19 @@ class GitLabApi:
164
171
 
165
172
  def cleanup(self) -> None:
166
173
  """
167
- Close gl session.
174
+ Close session.
168
175
  """
169
- self.gl.session.close()
176
+ self.session.close()
170
177
 
171
178
  @retry()
172
179
  def _auth(self) -> None:
173
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
174
180
  self.gl.auth()
175
181
 
176
182
  def create_branch(self, new_branch: str, source_branch: str) -> None:
177
183
  data = {"branch": new_branch, "ref": source_branch}
178
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
179
184
  self.project.branches.create(data)
180
185
 
181
186
  def delete_branch(self, branch: str) -> None:
182
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
183
187
  self.project.branches.delete(branch)
184
188
 
185
189
  def create_commit(
@@ -191,7 +195,6 @@ class GitLabApi:
191
195
  #create-a-commit-with-multiple-files-and-actions
192
196
  """
193
197
 
194
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
195
198
  self.project.commits.create({
196
199
  "branch": branch_name,
197
200
  "commit_message": commit_message,
@@ -208,7 +211,6 @@ class GitLabApi:
208
211
  {"action": "create", "file_path": file_path, "content": content}
209
212
  ],
210
213
  }
211
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
212
214
  self.project.commits.create(data)
213
215
 
214
216
  def delete_file(
@@ -219,7 +221,6 @@ class GitLabApi:
219
221
  "commit_message": commit_message,
220
222
  "actions": [{"action": "delete", "file_path": file_path}],
221
223
  }
222
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
223
224
  self.project.commits.create(data)
224
225
 
225
226
  def update_file(
@@ -232,7 +233,6 @@ class GitLabApi:
232
233
  {"action": "update", "file_path": file_path, "content": content}
233
234
  ],
234
235
  }
235
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
236
236
  self.project.commits.create(data)
237
237
 
238
238
  def create_mr(
@@ -252,7 +252,6 @@ class GitLabApi:
252
252
  "remove_source_branch": str(remove_source_branch),
253
253
  "labels": labels,
254
254
  }
255
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
256
255
  return cast(ProjectMergeRequest, self.project.mergerequests.create(data))
257
256
 
258
257
  def mr_exists(self, title: str) -> bool:
@@ -275,15 +274,13 @@ class GitLabApi:
275
274
  return [m.username for m in members if m.access_level >= 40]
276
275
 
277
276
  def get_app_sre_group_users(self) -> list[GroupMember]:
278
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
279
277
  app_sre_group = self.gl.groups.get("app-sre")
280
278
  return self.get_items(app_sre_group.members.list)
281
279
 
282
280
  def get_group_if_exists(self, group_name: str) -> Group | None:
283
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
284
281
  try:
285
282
  return self.gl.groups.get(group_name)
286
- except gitlab.exceptions.GitlabGetError:
283
+ except GitlabGetError:
287
284
  return None
288
285
 
289
286
  def share_project_with_group(
@@ -294,9 +291,7 @@ class GitLabApi:
294
291
  reshare: bool = False,
295
292
  ) -> None:
296
293
  if reshare:
297
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
298
294
  project.unshare(group_id)
299
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
300
295
  project.share(group_id, access_level)
301
296
 
302
297
  @staticmethod
@@ -334,7 +329,7 @@ class GitLabApi:
334
329
  access_level = self.get_access_level(access)
335
330
  try:
336
331
  project.members.create({"user_id": user.id, "access_level": access_level})
337
- except gitlab.exceptions.GitlabCreateError:
332
+ except GitlabCreateError:
338
333
  member = project.members.get(user.id)
339
334
  member.access_level = access_level
340
335
  member.save()
@@ -342,25 +337,21 @@ class GitLabApi:
342
337
  def add_group_member(self, group: Group, user: GitlabUser) -> None:
343
338
  gitlab_user = self.get_user(user.user)
344
339
  if gitlab_user is not None:
345
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
346
340
  try:
347
341
  group.members.create({
348
342
  "user_id": gitlab_user.id,
349
343
  "access_level": user.access_level,
350
344
  })
351
- except gitlab.exceptions.GitlabCreateError:
352
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
345
+ except GitlabCreateError:
353
346
  member = group.members.get(user.user)
354
347
  member.access_level = user.access_level
355
348
  member.save()
356
349
 
357
350
  def remove_group_member(self, group: Group, user_id: str) -> None:
358
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
359
351
  group.members.delete(user_id)
360
352
 
361
353
  def change_access(self, member: GroupMember, access_level: int) -> None:
362
354
  member.access_level = access_level
363
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
364
355
  member.save()
365
356
 
366
357
  @staticmethod
@@ -384,16 +375,13 @@ class GitLabApi:
384
375
  raise ValueError(f"Invalid access level: {access}")
385
376
 
386
377
  def get_group_id_and_projects(self, group_name: str) -> tuple[str, list[str]]:
387
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
388
378
  group = self.gl.groups.get(group_name)
389
379
  return group.id, [p.name for p in self.get_items(group.projects.list)]
390
380
 
391
381
  def get_group(self, group_name: str) -> Group:
392
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
393
382
  return self.gl.groups.get(group_name)
394
383
 
395
384
  def create_project(self, group_id: str, project: str) -> None:
396
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
397
385
  self.gl.projects.create({"name": project, "namespace_id": group_id})
398
386
 
399
387
  def get_project_url(self, group: str, project: str) -> str:
@@ -402,23 +390,20 @@ class GitLabApi:
402
390
  @retry()
403
391
  def get_project(self, repo_url: str) -> Project | None:
404
392
  repo = repo_url.replace(self.server + "/", "")
405
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
406
393
  try:
407
394
  project = self.gl.projects.get(repo)
408
- except gitlab.exceptions.GitlabGetError:
395
+ except GitlabGetError:
409
396
  logging.warning(f"{repo_url} not found")
410
397
  project = None
411
398
  return project
412
399
 
413
400
  def get_project_by_id(self, project_id: int) -> Project:
414
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
415
401
  return self.gl.projects.get(project_id)
416
402
 
417
403
  def get_issues(self, state: str) -> list[ProjectIssue]:
418
404
  return self.get_items(self.project.issues.list, state=state)
419
405
 
420
406
  def get_merge_request(self, mr_id: str | int) -> ProjectMergeRequest:
421
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
422
407
  return self.project.mergerequests.get(mr_id)
423
408
 
424
409
  def get_merge_requests(self, state: str) -> list[ProjectMergeRequest]:
@@ -443,7 +428,6 @@ class GitLabApi:
443
428
  def get_merge_request_changed_paths(
444
429
  merge_request: ProjectMergeRequest,
445
430
  ) -> list[str]:
446
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
447
431
  result = merge_request.changes()
448
432
  changes = cast(dict, result)["changes"]
449
433
  changed_paths = set()
@@ -487,7 +471,6 @@ class GitLabApi:
487
471
 
488
472
  @staticmethod
489
473
  def delete_comment(note: ProjectMergeRequestNote) -> None:
490
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
491
474
  note.delete()
492
475
 
493
476
  def delete_merge_request_comments(
@@ -517,7 +500,6 @@ class GitLabApi:
517
500
  if label in labels:
518
501
  return
519
502
  labels.append(label)
520
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
521
503
  merge_request.save()
522
504
 
523
505
  @staticmethod
@@ -533,7 +515,6 @@ class GitLabApi:
533
515
  if not new_labels:
534
516
  return
535
517
  merge_request.labels.extend(new_labels)
536
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
537
518
  merge_request.save()
538
519
 
539
520
  @staticmethod
@@ -562,7 +543,6 @@ class GitLabApi:
562
543
  return
563
544
 
564
545
  merge_request.labels = list(new_desired_labels)
565
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
566
546
  merge_request.save()
567
547
 
568
548
  @staticmethod
@@ -570,16 +550,14 @@ class GitLabApi:
570
550
  merge_request: ProjectMergeRequest,
571
551
  body: str,
572
552
  ) -> None:
573
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
574
553
  merge_request.notes.create({"body": body})
575
554
 
576
- # TODO: deprecated this method as new support of list(get_all=True), and figure out request counter metrics
555
+ # TODO: deprecated this method as new support of list(get_all=True)
577
556
  @staticmethod
578
557
  def get_items(method: Callable, **kwargs: Any) -> list:
579
558
  all_items = []
580
559
  page = 1
581
560
  while True:
582
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
583
561
  items = method(page=page, per_page=100, **kwargs)
584
562
  all_items.extend(items)
585
563
  if len(items) < 100:
@@ -589,12 +567,10 @@ class GitLabApi:
589
567
  return all_items
590
568
 
591
569
  def create_label(self, label_text: str, label_color: str) -> None:
592
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
593
570
  self.project.labels.create({"name": label_text, "color": label_color})
594
571
 
595
572
  @staticmethod
596
573
  def refresh_labels(item: ProjectMergeRequest | ProjectIssue) -> None:
597
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
598
574
  manager: ProjectMergeRequestManager | ProjectIssueManager
599
575
  match item:
600
576
  case ProjectMergeRequest():
@@ -622,9 +598,7 @@ class GitLabApi:
622
598
  return
623
599
  labels.append(label)
624
600
  note_body = f"item has been marked as {label}. to remove say `/{label} cancel`"
625
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
626
601
  item.notes.create({"body": note_body})
627
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
628
602
  item.save()
629
603
 
630
604
  @staticmethod
@@ -639,7 +613,6 @@ class GitLabApi:
639
613
  if label not in labels:
640
614
  return
641
615
  labels.remove(label)
642
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
643
616
  item.save()
644
617
 
645
618
  @staticmethod
@@ -656,18 +629,14 @@ class GitLabApi:
656
629
  if not to_be_removed:
657
630
  return
658
631
  item.labels = list(current_labels - to_be_removed)
659
-
660
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
661
632
  item.save()
662
633
 
663
634
  @staticmethod
664
635
  def close(item: ProjectIssue | ProjectMergeRequest) -> None:
665
636
  item.state_event = "close"
666
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
667
637
  item.save()
668
638
 
669
639
  def get_user(self, username: str) -> User | None:
670
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
671
640
  user = cast(list[User], self.gl.users.list(search=username, page=1, per_page=1))
672
641
  if not user:
673
642
  logging.error(f"{username} user not found")
@@ -676,12 +645,9 @@ class GitLabApi:
676
645
 
677
646
  @retry()
678
647
  def get_project_hooks(self, repo_url: str) -> list[ProjectHook]:
679
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
680
648
  p = self.get_project(repo_url)
681
649
  if p is None:
682
650
  return []
683
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
684
- # TODO: get_all may send multiple requests, update metrics accordingly
685
651
  return p.hooks.list(per_page=100, get_all=True)
686
652
 
687
653
  def create_project_hook(self, repo_url: str, data: Mapping) -> None:
@@ -697,7 +663,6 @@ class GitLabApi:
697
663
  "push_events": int("push" in trigger),
698
664
  "merge_requests_events": int("mr" in trigger),
699
665
  }
700
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
701
666
  p.hooks.create(hook)
702
667
 
703
668
  def get_repository_tree(self, ref: str = "master") -> list[dict]:
@@ -710,11 +675,10 @@ class GitLabApi:
710
675
  """
711
676
  Wrapper around Gitlab.files.get() with exception handling.
712
677
  """
713
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
714
678
  try:
715
679
  path = path.lstrip("/")
716
680
  return self.project.files.get(file_path=path, ref=ref)
717
- except gitlab.exceptions.GitlabGetError:
681
+ except GitlabGetError:
718
682
  return None
719
683
 
720
684
  def initiate_saas_bundle_repo(self, repo_url: str) -> None:
@@ -747,8 +711,6 @@ class GitLabApi:
747
711
  last_action_by_team = comment["created_at"]
748
712
  break
749
713
  # labels
750
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
751
- # TODO: this may send multiple requests, update metrics accordingly
752
714
  label_events = cast(
753
715
  list[ProjectMergeRequestResourceLabelEvent],
754
716
  mr.resourcelabelevents.list(get_all=True),
@@ -769,7 +731,6 @@ class GitLabApi:
769
731
  # possible responses from tenants (ignore the bot)
770
732
  last_action_not_by_team = None
771
733
  # commits
772
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
773
734
  commits = list(mr.commits())
774
735
  commits.sort(key=attrgetter("created_at"), reverse=True)
775
736
  for commit in commits:
@@ -831,7 +792,6 @@ class GitLabApi:
831
792
  return None
832
793
 
833
794
  def get_commit_sha(self, ref: str, repo_url: str) -> str:
834
- gitlab_request.labels(integration=INTEGRATION_NAME).inc()
835
795
  project = self.get_project(repo_url)
836
796
  commits = project.commits.list(ref_name=ref, per_page=1, page=1)
837
797
  return commits[0].id
@@ -1,5 +1,11 @@
1
1
  import os
2
+ from typing import Any
2
3
 
4
+ from prometheus_client.core import Counter
5
+ from requests import (
6
+ Response,
7
+ Session,
8
+ )
3
9
  from sretoolbox.container import (
4
10
  Image,
5
11
  Skopeo,
@@ -23,20 +29,42 @@ class InstrumentedImage(Image):
23
29
 
24
30
  """
25
31
 
26
- def _get_manifest(self):
32
+ def _get_manifest(self) -> Response:
27
33
  metrics.registry_reachouts.labels(
28
34
  integration=INTEGRATION_NAME,
29
35
  shard=SHARDS,
30
36
  shard_id=SHARD_ID,
31
37
  registry=self.registry,
32
38
  ).inc()
33
- super()._get_manifest()
39
+ return super()._get_manifest()
34
40
 
35
41
 
36
42
  class InstrumentedSkopeo(Skopeo):
37
- def copy(self, *args, **kwargs):
38
- # pylint: disable=signature-differs
43
+ def copy(self, *args: Any, **kwargs: Any) -> bytes | str:
39
44
  metrics.copy_count.labels(
40
45
  integration=INTEGRATION_NAME, shard=SHARDS, shard_id=SHARD_ID
41
46
  ).inc()
42
47
  return super().copy(*args, **kwargs)
48
+
49
+
50
+ class InstrumentedSession(Session):
51
+ """
52
+ Instrumented requests.Session that auto increments Prometheus Counter on request.
53
+
54
+ Usage:
55
+ from prometheus_client import Counter
56
+ gitlab_request = Counter(
57
+ name="qontract_reconcile_gitlab_request_total",
58
+ documentation="Number of calls made to Gitlab API",
59
+ labelnames=["integration"],
60
+ )
61
+ session = InstrumentedSession(counter.labels(integration="gitlab-housekeeping"))
62
+ """
63
+
64
+ def __init__(self, counter: Counter) -> None:
65
+ self.counter = counter
66
+ super().__init__()
67
+
68
+ def request(self, *args: Any, **kwargs: Any) -> Response:
69
+ self.counter.inc()
70
+ return super().request(*args, **kwargs)