qontract-reconcile 0.10.1rc867__py3-none-any.whl → 0.10.1rc869__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.1
2
2
  Name: qontract-reconcile
3
- Version: 0.10.1rc867
3
+ Version: 0.10.1rc869
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
@@ -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=YaLiMqrn9YOM5e7o2NJVg6vtILyBXTryTScA4RhTyPo,3279
38
+ reconcile/gitlab_permissions.py,sha256=1tFZws0-prcJ7vhFF3N7BxKocc16SjJuoqCkzRFESbE,3276
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
@@ -476,7 +476,7 @@ reconcile/terraform_vpc_resources/integration.py,sha256=bqEq3qHaUVQkbGt100Fa7ZwN
476
476
  reconcile/terraform_vpc_resources/merge_request.py,sha256=loRymUigCIvaaT0s_NzktZchh-DGRQnCICdBSCAcFPY,1503
477
477
  reconcile/terraform_vpc_resources/merge_request_manager.py,sha256=Vj2nuQbQyrL4q_il1My-bLxYNh_r3YXqX45P8fwtP6Q,3259
478
478
  reconcile/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
479
- reconcile/test/conftest.py,sha256=0pO4UxFeBALKbL9gwemyap0VkbPR8n5TtZbf5c9pSv0,4303
479
+ reconcile/test/conftest.py,sha256=0GXXH9DKIL9DlvY4tavLqXPaK8UXoC5tOfxkGfGy4Bs,4365
480
480
  reconcile/test/fixtures.py,sha256=9SDWAUlSd1rCx7z3GhULHcpr-I6FyCsXxaFAZIqYQsQ,591
481
481
  reconcile/test/test_acs_notifiers.py,sha256=xf3WL6q6V7KQdTVSx6YI-pa4yzOX3mkvIJomgPUc3Mw,12746
482
482
  reconcile/test/test_acs_policies.py,sha256=8pwnXpAO-0OI-6oubjf_oPPlpZjVldeZfJJ9uhsNMWM,17579
@@ -502,7 +502,7 @@ reconcile/test/test_github_repo_invites.py,sha256=UVaDlxSxi5iooyUbz8F11d7cvINHLK
502
502
  reconcile/test/test_gitlab_housekeeping.py,sha256=Sn5rERCp28sMiBx5vJaQ5yy80y37GouMClejmXocsT8,10068
503
503
  reconcile/test/test_gitlab_labeler.py,sha256=vFLUJXSIaCduj6wSqgw7Fg7FhlopaDnYI5SLzNHtLoY,4362
504
504
  reconcile/test/test_gitlab_members.py,sha256=kaCOA02eZSrSMkzHmaLwWW3LY6Af0ciLSEP4PlMLvOU,9949
505
- reconcile/test/test_gitlab_permissions.py,sha256=FAKT7UuNAjxmke90P2cA-924_CGZ7Kp3JLTb6rmTseM,1965
505
+ reconcile/test/test_gitlab_permissions.py,sha256=5QFy6InIHYM7zph5dPsDPo2hobrI5-eSGRTOzHOhF74,2005
506
506
  reconcile/test/test_instrumented_wrappers.py,sha256=CZzhnQH0c4i7-Rxjg7-0dfFMvVPegLHL46z5NHOOCwo,608
507
507
  reconcile/test/test_integrations_manager.py,sha256=l6KwSFT0NS9VSR-b_9z_ZEGXDWH3EMitUEMC_1h8Xkk,38184
508
508
  reconcile/test/test_jenkins_worker_fleets.py,sha256=o1jlT7OBBSgu0M3iI4xMdz_x6SciF7yhNBpLk5gTJfg,2361
@@ -654,7 +654,7 @@ reconcile/utils/filtering.py,sha256=zZnHH0u0SaTDyzuFXZ_mREURGLvjEqQIQy4z-7QBVlc,
654
654
  reconcile/utils/git.py,sha256=BdxXFgQ1XOZpS-4qb3qMsKTCFDG8MlE26rv1jAhvCkM,1560
655
655
  reconcile/utils/git_secrets.py,sha256=0wGNL5mvDtVPRuu3vEQgld1Am64gIDJHtmu1_ZKxMAI,1973
656
656
  reconcile/utils/github_api.py,sha256=_bttNxYKeam_tLVe27L7O4gKqSn6CeyuFnJn8tSaUVY,2488
657
- reconcile/utils/gitlab_api.py,sha256=kGYNyx6pbF43rd6R3a3wcIGmATiqNUFJUUHP4sELgNI,29027
657
+ reconcile/utils/gitlab_api.py,sha256=thEdQ4AX96R4F3XhpOpugWmbueIgzDc_9b56DW-6ecY,29116
658
658
  reconcile/utils/gpg.py,sha256=EKG7_fdMv8BMlV5yUdPiqoTx-KrzmVSEAl2sLkaKwWI,1123
659
659
  reconcile/utils/gql.py,sha256=o8TLe9zW_zf_vOYC4yAy7mP5UvSR4eq3JKa4rxy1KjI,14277
660
660
  reconcile/utils/grouping.py,sha256=kWKivD14eAkiDneH_VIl_XyUdcVVQgiaKA9sLsuD2dw,441
@@ -686,7 +686,7 @@ reconcile/utils/pagerduty_api.py,sha256=fcSAUez6w51woDvbm0plJW2qSw6_NXQs1Fit_KTN
686
686
  reconcile/utils/parse_dhms_duration.py,sha256=TONpLnec5gHeF7k815YNJpQyDjXhkxZIcv9s8ffbTSY,1840
687
687
  reconcile/utils/password_validator.py,sha256=XwuWg-8CPlcuG7dl_oQ1G1h2gSVSnfMym_VkuprpWVg,2183
688
688
  reconcile/utils/prometheus.py,sha256=i5aCQ_I4WOg76iEjglVxxO9-OKby2N80ScErAbDtHE8,3848
689
- reconcile/utils/promotion_state.py,sha256=Gf58uvBWqGDZtNsnGbi6-K4LC94Mm_bJDs_Ztq1FPSs,2603
689
+ reconcile/utils/promotion_state.py,sha256=RswY0iMBw92ktyoorb-PFefaTAVlxyiKduVIoPyHpgU,3647
690
690
  reconcile/utils/promtool.py,sha256=kT2rFZSBaRqW7SSHAuYzGZzQxM5Dzk8KW1NnEUYZU_s,2896
691
691
  reconcile/utils/quay_api.py,sha256=EuOegpb-7ntEjkKLFwM2Oo4Nw7SyFtmyl3sQ9aXMtrM,8152
692
692
  reconcile/utils/raw_github_api.py,sha256=ZHC-SZuAyRe1zaMoOU7Krt1-zecDxENd9c_NzQYqK9g,2968
@@ -789,7 +789,7 @@ reconcile/utils/runtime/sharding.py,sha256=roCdbnBklhTK_g34zbgQYqzpKPaNQ8J6Xd9XL
789
789
  reconcile/utils/saasherder/__init__.py,sha256=J3MBZBFa5YmhqYm08QsjBXz8mFcVOCiOCkyIcw41t7E,343
790
790
  reconcile/utils/saasherder/interfaces.py,sha256=Tte-BAJ71FZF1J_ADay1UVIxLCJZcbefq4SRua4mn5w,9141
791
791
  reconcile/utils/saasherder/models.py,sha256=XiAb9pSmTxaNFa3XqNNfe1JxlGgTqsmd1nLi17iIV_g,5566
792
- reconcile/utils/saasherder/saasherder.py,sha256=4S3Q4tb11hmBI3rux5ajk-BUs-6Lfpg47uHZJj2uNKk,86787
792
+ reconcile/utils/saasherder/saasherder.py,sha256=kPYklRU9hPcdg573QQ0OoaXYG26t_v5COAz62QVPS3c,86883
793
793
  reconcile/utils/terraform/__init__.py,sha256=zNbiyTWo35AT1sFTElL2j_AA0jJ_yWE_bfFn-nD2xik,250
794
794
  reconcile/utils/terraform/config.py,sha256=5UVrd563TMcvi4ooa5JvWVDW1I3bIWg484u79evfV_8,164
795
795
  reconcile/utils/terraform/config_client.py,sha256=py-Ree-QUYD6Hvng6bM40VgSuttteehIKNgwOSoJO1o,4706
@@ -837,8 +837,8 @@ tools/test/test_app_interface_metrics_exporter.py,sha256=SX7qL3D1SIRKFo95FoQztvf
837
837
  tools/test/test_qontract_cli.py,sha256=_D61RFGAN5x44CY1tYbouhlGXXABwYfxKSWSQx3Jrss,4941
838
838
  tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
839
839
  tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
840
- qontract_reconcile-0.10.1rc867.dist-info/METADATA,sha256=kW9F6ZoBWCOD-GG7iiqXdukYen14M_t-HJ5FeYmfSxk,2273
841
- qontract_reconcile-0.10.1rc867.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
842
- qontract_reconcile-0.10.1rc867.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
843
- qontract_reconcile-0.10.1rc867.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
844
- qontract_reconcile-0.10.1rc867.dist-info/RECORD,,
840
+ qontract_reconcile-0.10.1rc869.dist-info/METADATA,sha256=geTr8-qfS2A6C1-lBsxjSlUZLA5SGrxsm8RgJkSCnsY,2273
841
+ qontract_reconcile-0.10.1rc869.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
842
+ qontract_reconcile-0.10.1rc869.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
843
+ qontract_reconcile-0.10.1rc869.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
844
+ qontract_reconcile-0.10.1rc869.dist-info/RECORD,,
@@ -80,7 +80,7 @@ def share_project_with_group(gl: GitLabApi, repos: list[str], dry_run: bool) ->
80
80
  # get repos not owned by app-sre
81
81
  non_app_sre_projects = {repo for repo in repos if "/app-sre/" not in repo}
82
82
  group_id, shared_projects = gl.get_group_id_and_shared_projects(APP_SRE_GROUP_NAME)
83
- shared_project_repos = {project["web_url"] for project in shared_projects}
83
+ shared_project_repos = {project.web_url for project in shared_projects}
84
84
  repos_to_share = non_app_sre_projects - shared_project_repos
85
85
  for repo in repos_to_share:
86
86
  gl.share_project_with_group(repo_url=repo, group_id=group_id, dry_run=dry_run)
@@ -10,7 +10,7 @@ from typing import (
10
10
  Any,
11
11
  Optional,
12
12
  )
13
- from unittest.mock import create_autospec
13
+ from unittest.mock import MagicMock, create_autospec
14
14
 
15
15
  import pytest
16
16
  from pydantic import BaseModel
@@ -74,7 +74,8 @@ def s3_state_builder() -> Callable[[Mapping], State]:
74
74
  return get(key)
75
75
 
76
76
  state = create_autospec(spec=State)
77
- state.get = get
77
+ mock_get = MagicMock(side_effect=get)
78
+ state.get = mock_get
78
79
  state.__getitem__ = __getitem__
79
80
  state.ls.side_effect = [data.get("ls", [])]
80
81
  return state
@@ -1,7 +1,7 @@
1
1
  from unittest.mock import MagicMock, create_autospec
2
2
 
3
3
  import pytest
4
- from gitlab.v4.objects import CurrentUser, GroupMember
4
+ from gitlab.v4.objects import CurrentUser, GroupMember, GroupProject
5
5
  from pytest_mock import MockerFixture
6
6
 
7
7
  from reconcile import gitlab_permissions
@@ -51,7 +51,7 @@ def test_run_share_with_group(
51
51
  ).return_value = True
52
52
  mocked_gl.get_group_id_and_shared_projects.return_value = (
53
53
  1234,
54
- [{"web_url": "https://test.com"}],
54
+ [create_autospec(GroupProject, web_url="https://test.com")],
55
55
  )
56
56
  gitlab_permissions.run(False, thread_pool_size=1)
57
57
  mocked_gl.share_project_with_group.assert_called_once()
@@ -29,6 +29,7 @@ from gitlab.const import (
29
29
  from gitlab.v4.objects import (
30
30
  CurrentUser,
31
31
  Group,
32
+ GroupProject,
32
33
  Project,
33
34
  ProjectIssue,
34
35
  ProjectMergeRequest,
@@ -286,13 +287,14 @@ class GitLabApi: # pylint: disable=too-many-public-methods
286
287
 
287
288
  def get_group_id_and_shared_projects(
288
289
  self, group_name: str
289
- ) -> tuple[int, list[dict]]:
290
+ ) -> tuple[int, list[GroupProject]]:
290
291
  gitlab_request.labels(integration=INTEGRATION_NAME).inc()
291
292
  group = self.gl.groups.get(group_name)
293
+ shared_projects = self.get_items(group.projects.list, all=True)
292
294
  return group.id, [
293
295
  project
294
- for project in group.shared_projects
295
- for shared_group in project["shared_with_groups"]
296
+ for project in shared_projects
297
+ for shared_group in project.shared_with_groups
296
298
  if shared_group["group_id"] == group.id
297
299
  and shared_group["group_access_level"] >= MAINTAINER_ACCESS
298
300
  ]
@@ -34,11 +34,17 @@ class PromotionState:
34
34
  A wrapper around a reconcile.utils.state.State object.
35
35
  This is dedicated to storing and retrieving information
36
36
  about promotions on S3.
37
+
38
+ Note, that PromotionsState holds 2 caches.
39
+ One cache for the promotion data that has already been fetched.
40
+ Another cache for commit sha lookup, i.e., checking if a commit sha
41
+ exists in S3 before making any API calls to it.
37
42
  """
38
43
 
39
44
  def __init__(self, state: State):
40
45
  self._state = state
41
46
  self._commits_by_channel: dict[str, set[str]] = defaultdict(set)
47
+ self._promotion_data_cache: dict[str, PromotionData | None] = {}
42
48
 
43
49
  def _target_key(self, channel: str, target_uid: str) -> str:
44
50
  return f"{channel}/{target_uid}"
@@ -59,19 +65,36 @@ class PromotionState:
59
65
  self._commits_by_channel[key].add(commit_sha)
60
66
 
61
67
  def get_promotion_data(
62
- self, sha: str, channel: str, target_uid: str = "", local_lookup: bool = True
68
+ self,
69
+ sha: str,
70
+ channel: str,
71
+ target_uid: str = "",
72
+ pre_check_sha_exists: bool = True,
73
+ use_cache: bool = False,
63
74
  ) -> Optional[PromotionData]:
75
+ """
76
+ Fetch promotion data from S3.
77
+
78
+ @param use_cache: Each fetched promotion data is cached locally. Setting this
79
+ flag to True will use the cache if the data is already fetched.
80
+
81
+ @param pre_check_sha_exists: If set to True, we will check if the commit sha exists
82
+ in local cache and if not will exit before making any API calls. Note, that this requires
83
+ a prior call to cache_commit_shas_from_s3 to populate the local commit cache.
84
+ """
64
85
  cache_key_v2 = self._target_key(channel=channel, target_uid=target_uid)
65
- if local_lookup and sha not in self._commits_by_channel[cache_key_v2]:
86
+ if pre_check_sha_exists and sha not in self._commits_by_channel[cache_key_v2]:
66
87
  # Lets reduce unecessary calls to S3
67
88
  return None
68
89
 
69
90
  path_v2 = f"promotions_v2/{channel}/{target_uid}/{sha}"
70
- try:
71
- data = self._state.get(path_v2)
72
- return PromotionData(**data)
73
- except KeyError:
74
- return None
91
+ if use_cache and path_v2 in self._promotion_data_cache:
92
+ return self._promotion_data_cache[path_v2]
93
+
94
+ data = self._state.get(path_v2)
95
+ promotion_data = PromotionData(**data)
96
+ self._promotion_data_cache[path_v2] = promotion_data
97
+ return promotion_data
75
98
 
76
99
  def publish_promotion_data(
77
100
  self, sha: str, channel: str, target_uid: str, data: PromotionData
@@ -1899,7 +1899,7 @@ class SaasHerder: # pylint: disable=too-many-public-methods
1899
1899
  sha=promotion.commit_sha,
1900
1900
  channel=channel.name,
1901
1901
  target_uid=target_uid,
1902
- local_lookup=False,
1902
+ pre_check_sha_exists=False,
1903
1903
  )
1904
1904
  if not (deployment and deployment.success):
1905
1905
  logging.error(
@@ -2007,6 +2007,7 @@ class SaasHerder: # pylint: disable=too-many-public-methods
2007
2007
  saas_file=promotion.saas_file,
2008
2008
  success=success,
2009
2009
  target_config_hash=promotion.target_config_hash,
2010
+ # TODO: do not override - check if timestamp already exists
2010
2011
  check_in=str(now),
2011
2012
  ),
2012
2013
  )