qontract-reconcile 0.10.1rc759__py3-none-any.whl → 0.10.1rc761__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.1rc759
3
+ Version: 0.10.1rc761
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
@@ -395,17 +395,19 @@ reconcile/rhidp/sso_client/base.py,sha256=EfQ2ewcOKh5idg46UKAkY6z0m_nGQfvnQKffa2
395
395
  reconcile/rhidp/sso_client/integration.py,sha256=kA8g7c38ZBSdrRtyfEqy_WgSreD1PbwY7ZIN-3tZRPc,2221
396
396
  reconcile/rhidp/sso_client/metrics.py,sha256=Tq7tSOsqL3XdcPUdozxqzSPIodUeOV87UCTqpuuqqhw,1013
397
397
  reconcile/saas_auto_promotions_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
398
- reconcile/saas_auto_promotions_manager/integration.py,sha256=h1RS-rE8_UaVoLV4c9NyfNfjzvHLQcEVwVN_2UxT7T8,6843
398
+ reconcile/saas_auto_promotions_manager/integration.py,sha256=shWQ--FWfeh_1rHJUwOWDiZWnvzKxYJYuRUIGQv22RI,6759
399
+ reconcile/saas_auto_promotions_manager/meta.py,sha256=2b44ik-qpACNtW72QlDa2YOQqxeN8FHZfLPDmKoH3Rg,161
399
400
  reconcile/saas_auto_promotions_manager/publisher.py,sha256=psrthZGgCQDUO3rwQjKSBMlwcTgfij6sxdebGuxkNv4,2739
400
401
  reconcile/saas_auto_promotions_manager/s3_exporter.py,sha256=IKlVWZmiPnvl7sKeF6JgAlhXZe5CovKTxQc0SNkNSx4,2583
401
402
  reconcile/saas_auto_promotions_manager/subscriber.py,sha256=cLhPlkT71J2LIice3SLmH1WpsqzV46gd0peMxrnqyRw,7452
402
403
  reconcile/saas_auto_promotions_manager/merge_request_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
404
+ reconcile/saas_auto_promotions_manager/merge_request_manager/desired_state.py,sha256=jgfgKv4UTYFxtDao_JwNEGEKmu4GpeMm5vbaat0289c,1225
403
405
  reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request.py,sha256=BeAJWLow7b4HQyZ9zz398sQkPeIz8chpMkCts2NU27c,1282
404
- reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager_v2.py,sha256=Z-tUicItSMWq4WoAU59WTYChtOeS2FShD_bxrhNzsgc,7069
406
+ reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager_v2.py,sha256=IRLHdz-XMn-rIb0jFddYkIuN9c7FC6InJZ61c9fVjvI,6193
405
407
  reconcile/saas_auto_promotions_manager/merge_request_manager/metrics.py,sha256=sdHp71Wl87tFM-Z_QvqvdHhyrppFLGi4ekksCi_e_bs,977
406
408
  reconcile/saas_auto_promotions_manager/merge_request_manager/mr_parser.py,sha256=x8Gg-YjEFWEeDPJH3Y8SrfcJbwhLuAqCz4kIhfEyaaA,7060
407
- reconcile/saas_auto_promotions_manager/merge_request_manager/reconciler.py,sha256=nst5ZynEQs9Hy9Z2DAjN8_ALIS_5XnrbJh7KG4YVRrE,7789
408
- reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py,sha256=Z2G4wMQB3DLTuMlH_MGURGR4uLyh-6RnksQJzdym5VQ,6960
409
+ reconcile/saas_auto_promotions_manager/merge_request_manager/reconciler.py,sha256=KZVAkFJR75Qu7-feV4mzg1S8ua-pkbuu1oC7PebSpDs,7801
410
+ reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py,sha256=iu0wMyyEvro5r5SBJVN3HGmVSIcxTyLN0Xxx3mhbYXE,7066
409
411
  reconcile/saas_auto_promotions_manager/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
410
412
  reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py,sha256=ZNxwqp9kdUSoxb3kTdM4KrtPyd3V5O4jMfjrVT2IJfs,7605
411
413
  reconcile/skupper_network/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -527,6 +529,7 @@ reconcile/test/saas_auto_promotions_manager/merge_request_manager/__init__.py,sh
527
529
  reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
528
530
  reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py,sha256=7O3lbk1EmEtUofqGncfiwMYvDPXrkQNPB59zlQ_zXkM,4588
529
531
  reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/data_keys.py,sha256=Z1IV51OUuzhd-3S8W-k7ixC-fkaglCokn0eakK0Z73s,606
532
+ reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_desired_state.py,sha256=x5DDZog0SA-Z8noxwalZniGtkovaPvR0V9Pqa5QaFFY,2302
530
533
  reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_merge_request_manager.py,sha256=h8lnorFPZIxTtbaaXGLoiEsBbB4Qj-Mg9BKV62ZqEBQ,2389
531
534
  reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_mr_parser.py,sha256=dcGHzxuafKSxmswSO1qF2WlKaqsmEvtERC6Lb8kDAN0,10019
532
535
  reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_reconciler.py,sha256=_bzfJzjFJgubu--7wyXIiusUrdbmLtFbHmkbat4SX_M,17828
@@ -676,7 +679,7 @@ reconcile/utils/acs/notifiers.py,sha256=2n5blP9N1FdGLZuy3do9bpjd8NKg88kmLNNqhAGn
676
679
  reconcile/utils/acs/policies.py,sha256=_jAz6cv8KRYtDsXjGoJgNbD8_9PUa5LSwwVlpK4A_cQ,5505
677
680
  reconcile/utils/acs/rbac.py,sha256=ugsLM9Pb7FbUbdq85E3VzXGMaB9ZovXob7tdWCxwqZ8,8808
678
681
  reconcile/utils/aws_api_typed/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
679
- reconcile/utils/aws_api_typed/api.py,sha256=rGUh7-gc8AcjUFuLgQxKyPy1KGY7ffNe6zT1EDdurOM,8283
682
+ reconcile/utils/aws_api_typed/api.py,sha256=uqLNd_uNB11sQqLfcrqvXb1Z_K8GtX3K0FZ8zC_FK-A,8329
680
683
  reconcile/utils/aws_api_typed/iam.py,sha256=ka46H2-SzTCgy6EJYapKTzyZK9vR1bkfD0wF8bDdy1Q,2201
681
684
  reconcile/utils/aws_api_typed/organization.py,sha256=oXftcLVuSs9qej6efdssl38FvjeZaQC5R2Wj3NzxX4U,5529
682
685
  reconcile/utils/aws_api_typed/s3.py,sha256=J2uOTtEFgMyKT22pa4DbFnV7zfg575m2DeidQaeselM,1034
@@ -783,8 +786,8 @@ tools/test/test_app_interface_metrics_exporter.py,sha256=SX7qL3D1SIRKFo95FoQztvf
783
786
  tools/test/test_qontract_cli.py,sha256=w2l4BHB09k1d-BGJ1jBUNCqDv7zkqYrMHojQXg-21kQ,4155
784
787
  tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
785
788
  tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
786
- qontract_reconcile-0.10.1rc759.dist-info/METADATA,sha256=N17GmMBM1N_QQwB544Gd7bz5DTOnTnT4o284Cj2JVgI,2382
787
- qontract_reconcile-0.10.1rc759.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
788
- qontract_reconcile-0.10.1rc759.dist-info/entry_points.txt,sha256=rIxI5zWtHNlfpDeq1a7pZXAPoqf7HG32KMTN3MeWK_8,429
789
- qontract_reconcile-0.10.1rc759.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
790
- qontract_reconcile-0.10.1rc759.dist-info/RECORD,,
789
+ qontract_reconcile-0.10.1rc761.dist-info/METADATA,sha256=GwWf5GcPchuffOX8BPrvZrVtQiE13PieAaupZVu9ucs,2382
790
+ qontract_reconcile-0.10.1rc761.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
791
+ qontract_reconcile-0.10.1rc761.dist-info/entry_points.txt,sha256=rIxI5zWtHNlfpDeq1a7pZXAPoqf7HG32KMTN3MeWK_8,429
792
+ qontract_reconcile-0.10.1rc761.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
793
+ qontract_reconcile-0.10.1rc761.dist-info/RECORD,,
@@ -18,6 +18,7 @@ from reconcile.saas_auto_promotions_manager.merge_request_manager.reconciler imp
18
18
  from reconcile.saas_auto_promotions_manager.merge_request_manager.renderer import (
19
19
  Renderer,
20
20
  )
21
+ from reconcile.saas_auto_promotions_manager.meta import QONTRACT_INTEGRATION
21
22
  from reconcile.saas_auto_promotions_manager.publisher import Publisher
22
23
  from reconcile.saas_auto_promotions_manager.s3_exporter import S3Exporter
23
24
  from reconcile.saas_auto_promotions_manager.subscriber import Subscriber
@@ -34,14 +35,10 @@ from reconcile.typed_queries.saas_files import get_saas_files
34
35
  from reconcile.utils.defer import defer
35
36
  from reconcile.utils.promotion_state import PromotionState
36
37
  from reconcile.utils.secret_reader import create_secret_reader
37
- from reconcile.utils.semver_helper import make_semver
38
38
  from reconcile.utils.state import State, init_state
39
39
  from reconcile.utils.unleash import get_feature_toggle_state
40
40
  from reconcile.utils.vcs import VCS
41
41
 
42
- QONTRACT_INTEGRATION = "saas-auto-promotions-manager"
43
- QONTRACT_INTEGRATION_VERSION = make_semver(0, 1, 0)
44
-
45
42
 
46
43
  class SaasAutoPromotionsManager:
47
44
  def __init__(
@@ -0,0 +1,28 @@
1
+ from collections import defaultdict
2
+ from collections.abc import Iterable
3
+
4
+ from reconcile.saas_auto_promotions_manager.merge_request_manager.reconciler import (
5
+ Promotion,
6
+ )
7
+ from reconcile.saas_auto_promotions_manager.subscriber import Subscriber
8
+
9
+
10
+ class DesiredState:
11
+ def __init__(self, subscribers: Iterable[Subscriber]) -> None:
12
+ self.content_hash_to_subscriber: dict[str, list[Subscriber]] = {}
13
+ subscribers_per_channel_combo: dict[str, list[Subscriber]] = defaultdict(list)
14
+ for subscriber in subscribers:
15
+ channel_combo = ",".join([c.name for c in subscriber.channels])
16
+ subscribers_per_channel_combo[channel_combo].append(subscriber)
17
+
18
+ desired_promotions: list[Promotion] = []
19
+ for channel_combo, subs in subscribers_per_channel_combo.items():
20
+ combined_content_hash = Subscriber.combined_content_hash(subscribers=subs)
21
+ self.content_hash_to_subscriber[combined_content_hash] = subs
22
+ desired_promotions.append(
23
+ Promotion(
24
+ content_hashes={combined_content_hash},
25
+ channels={channel_combo},
26
+ )
27
+ )
28
+ self.promotions = desired_promotions
@@ -1,9 +1,11 @@
1
1
  import logging
2
- from collections import defaultdict
3
2
  from collections.abc import Iterable
4
3
 
5
4
  from gitlab.exceptions import GitlabGetError
6
5
 
6
+ from reconcile.saas_auto_promotions_manager.merge_request_manager.desired_state import (
7
+ DesiredState,
8
+ )
7
9
  from reconcile.saas_auto_promotions_manager.merge_request_manager.merge_request import (
8
10
  SAPMMR,
9
11
  )
@@ -21,7 +23,6 @@ from reconcile.saas_auto_promotions_manager.merge_request_manager.mr_parser impo
21
23
  )
22
24
  from reconcile.saas_auto_promotions_manager.merge_request_manager.reconciler import (
23
25
  Addition,
24
- Promotion,
25
26
  Reconciler,
26
27
  )
27
28
  from reconcile.saas_auto_promotions_manager.merge_request_manager.renderer import (
@@ -66,33 +67,12 @@ class MergeRequestManagerV2:
66
67
  self._mr_parser = mr_parser
67
68
  self._renderer = renderer
68
69
  self._reconciler = reconciler
69
- self._content_hash_to_subscriber: dict[str, list[Subscriber]] = {}
70
70
  self._sapm_mrs: list[SAPMMR] = []
71
71
 
72
- def _aggregate_desired_state(
73
- self, subscribers: Iterable[Subscriber]
74
- ) -> list[Promotion]:
75
- subscribers_per_channel_combo: dict[str, list[Subscriber]] = defaultdict(list)
76
- for subscriber in subscribers:
77
- channel_combo = ",".join([c.name for c in subscriber.channels])
78
- subscribers_per_channel_combo[channel_combo].append(subscriber)
79
-
80
- desired_promotions: list[Promotion] = []
81
- for channel_combo, subs in subscribers_per_channel_combo.items():
82
- combined_content_hash = Subscriber.combined_content_hash(subscribers=subs)
83
- self._content_hash_to_subscriber[combined_content_hash] = subs
84
- desired_promotions.append(
85
- Promotion(
86
- content_hashes={combined_content_hash},
87
- channels={channel_combo},
88
- )
89
- )
90
- return desired_promotions
91
-
92
72
  def _render_mr(self, addition: Addition) -> None:
93
73
  subs: list[Subscriber] = []
94
74
  for content_hash in addition.content_hashes:
95
- subs.extend(self._content_hash_to_subscriber[content_hash])
75
+ subs.extend(self._desired_state.content_hash_to_subscriber[content_hash])
96
76
  content_by_path: dict[str, str] = {}
97
77
  has_error = False
98
78
  for sub in subs:
@@ -151,11 +131,12 @@ class MergeRequestManagerV2:
151
131
 
152
132
  def reconcile(self, subscribers: Iterable[Subscriber]) -> None:
153
133
  current_state = self._mr_parser.retrieve_open_mrs(label=SAPM_LABEL)
154
- desired_state = self._aggregate_desired_state(subscribers=subscribers)
134
+ desired_state = DesiredState(subscribers=subscribers)
135
+ self._desired_state = desired_state
155
136
 
156
137
  diff = self._reconciler.reconcile(
157
138
  batch_limit=BATCH_SIZE_LIMIT,
158
- desired_promotions=desired_state,
139
+ desired_promotions=desired_state.promotions,
159
140
  open_mrs=current_state,
160
141
  )
161
142
  parallel_open_mrs = (
@@ -14,7 +14,7 @@ class Reason(Enum):
14
14
  NEW_BATCH = "Closing this MR in favor of a new batch MR."
15
15
 
16
16
 
17
- @dataclass
17
+ @dataclass(order=True)
18
18
  class Promotion:
19
19
  content_hashes: set[str]
20
20
  channels: set[str]
@@ -13,13 +13,14 @@ from reconcile.gql_definitions.common.saas_files import (
13
13
  from reconcile.gql_definitions.fragments.saas_target_namespace import (
14
14
  SaasTargetNamespace,
15
15
  )
16
+ from reconcile.saas_auto_promotions_manager.meta import QONTRACT_INTEGRATION_VERSION
16
17
  from reconcile.saas_auto_promotions_manager.subscriber import Subscriber
17
18
  from reconcile.utils.ruamel import create_ruamel_instance
18
19
 
19
20
  PROMOTION_DATA_SEPARATOR = (
20
21
  "**SAPM Data - DO NOT MANUALLY CHANGE ANYTHING BELOW THIS LINE**"
21
22
  )
22
- SAPM_VERSION = "2.1.3"
23
+ SAPM_VERSION = QONTRACT_INTEGRATION_VERSION
23
24
  CONTENT_HASHES = "content_hashes"
24
25
  CHANNELS_REF = "channels"
25
26
  IS_BATCHABLE = "is_batchable"
@@ -0,0 +1,4 @@
1
+ from reconcile.utils.semver_helper import make_semver
2
+
3
+ QONTRACT_INTEGRATION = "saas-auto-promotions-manager"
4
+ QONTRACT_INTEGRATION_VERSION = make_semver(2, 1, 4)
@@ -0,0 +1,60 @@
1
+ from collections.abc import Callable
2
+
3
+ from reconcile.saas_auto_promotions_manager.merge_request_manager.desired_state import (
4
+ DesiredState,
5
+ )
6
+ from reconcile.saas_auto_promotions_manager.subscriber import Subscriber
7
+
8
+ from .data_keys import (
9
+ CHANNEL,
10
+ )
11
+
12
+
13
+ def test_desired_state_empty() -> None:
14
+ desired_state = DesiredState(subscribers=[])
15
+ assert desired_state.promotions == []
16
+
17
+
18
+ def test_desired_state_single_subscriber(
19
+ subscriber_builder: Callable[..., Subscriber],
20
+ ) -> None:
21
+ subscriber = subscriber_builder({})
22
+ desired_state = DesiredState(subscribers=[subscriber])
23
+ assert len(desired_state.promotions) == 1
24
+ assert desired_state.promotions[0].content_hashes == {
25
+ Subscriber.combined_content_hash([subscriber])
26
+ }
27
+
28
+
29
+ def test_desired_state_multiple_subscribers_same_channel_combo(
30
+ subscriber_builder: Callable[..., Subscriber],
31
+ ) -> None:
32
+ subscriber_a = subscriber_builder({CHANNEL: ["channel-a", "channel-b"]})
33
+ subscriber_a.desired_ref = "ref-a"
34
+ subscriber_b = subscriber_builder({CHANNEL: ["channel-a", "channel-b"]})
35
+ subscriber_b.desired_ref = "ref-b"
36
+ desired_state = DesiredState(subscribers=[subscriber_a, subscriber_b])
37
+ assert len(desired_state.promotions) == 1
38
+ assert desired_state.promotions[0].content_hashes == {
39
+ Subscriber.combined_content_hash([subscriber_a, subscriber_b]),
40
+ }
41
+
42
+
43
+ def test_desired_state_multiple_subscribers_different_channel_combo(
44
+ subscriber_builder: Callable[..., Subscriber],
45
+ ) -> None:
46
+ subscriber_a = subscriber_builder({CHANNEL: ["channel-a", "channel-b"]})
47
+ subscriber_a.desired_ref = "ref-a"
48
+ subscriber_b = subscriber_builder({CHANNEL: ["channel-a", "channel-b"]})
49
+ subscriber_b.desired_ref = "ref-b"
50
+ subscriber_c = subscriber_builder({CHANNEL: ["channel-b", "channel-c"]})
51
+ subscriber_c.desired_ref = "ref-c"
52
+ desired_state = DesiredState(subscribers=[subscriber_a, subscriber_b, subscriber_c])
53
+ sorted_promotions = sorted(desired_state.promotions)
54
+ assert len(desired_state.promotions) == 2
55
+ assert sorted_promotions[0].content_hashes == {
56
+ Subscriber.combined_content_hash([subscriber_a, subscriber_b]),
57
+ }
58
+ assert sorted_promotions[1].content_hashes == {
59
+ Subscriber.combined_content_hash([subscriber_c]),
60
+ }
@@ -22,7 +22,15 @@ from reconcile.utils.aws_api_typed.service_quotas import AWSApiServiceQuotas
22
22
  from reconcile.utils.aws_api_typed.sts import AWSApiSts
23
23
  from reconcile.utils.aws_api_typed.support import AWSApiSupport
24
24
 
25
- SubApi = TypeVar("SubApi")
25
+ SubApi = TypeVar(
26
+ "SubApi",
27
+ AWSApiIam,
28
+ AWSApiOrganizations,
29
+ AWSApiS3,
30
+ AWSApiServiceQuotas,
31
+ AWSApiSts,
32
+ AWSApiSupport,
33
+ )
26
34
 
27
35
 
28
36
  class AWSCredentials(ABC):
@@ -159,7 +167,7 @@ class AWSApi:
159
167
  match api_cls:
160
168
  case reconcile.utils.aws_api_typed.iam.AWSApiIam:
161
169
  client = self.session.client("iam")
162
- api = api_cls(client) # type: ignore # mypy bug, it doesn't recognize that api_cls is callable
170
+ api = api_cls(client)
163
171
  case reconcile.utils.aws_api_typed.organization.AWSApiOrganizations:
164
172
  client = self.session.client("organizations")
165
173
  api = api_cls(client)