qontract-reconcile 0.10.1rc46__py3-none-any.whl → 0.10.1rc48__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.1rc46
3
+ Version: 0.10.1rc48
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
@@ -266,14 +266,14 @@ reconcile/prometheus_rules_tester/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeR
266
266
  reconcile/prometheus_rules_tester/integration.py,sha256=Sn6mjzC2lJQVcETS1J2Z3tOwm8M3DDW-1GVT-5ccNuA,8860
267
267
  reconcile/saas_auto_promotions_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
268
268
  reconcile/saas_auto_promotions_manager/integration.py,sha256=hmRWva3_ZEO845wMkttEt4X6Izl5p8ZKs09NXWp8mkY,5609
269
- reconcile/saas_auto_promotions_manager/publisher.py,sha256=Oi7QMlxY56NXO2W4NnB7kSeL-7Ef3oY75mIccoLWBwg,1980
269
+ reconcile/saas_auto_promotions_manager/publisher.py,sha256=8uh7YnR2IPkzJHSxMwvt_iFOnEn6JAHFz2UqLZ86qb8,2338
270
270
  reconcile/saas_auto_promotions_manager/subscriber.py,sha256=8w9q1ceA2XnuTntThg8v6mE3K28aG2Y2DwQSuTudkns,6942
271
271
  reconcile/saas_auto_promotions_manager/merge_request_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
272
272
  reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request.py,sha256=PNu7sE-tDUY61E03z5w0b93fdowZ8auCl0S4_vhYOKQ,1333
273
273
  reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager.py,sha256=SNJ9WLlaFnf_tblwC0xDBfrXi4SVadeFgV3llhTqbGM,10959
274
274
  reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py,sha256=Ye3lmfWTbuHjMoCEOpGnGRK3QU0LwB_LVfnPXFdNxf4,4702
275
275
  reconcile/saas_auto_promotions_manager/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
276
- reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py,sha256=LEK_635Vt7VPWnhVonn54JxkfUKCehX3_6bJfD8zKbI,8597
276
+ reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py,sha256=At9VXApH6n0R7DZoGxMUQ81JUzOQO3Ouf7csbBE14AA,6637
277
277
  reconcile/saas_auto_promotions_manager/utils/vcs.py,sha256=wIB3DUazVpmysKuKmHZZ_yG9d04givRBulXrUuZyOgw,5240
278
278
  reconcile/skupper_network/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
279
279
  reconcile/skupper_network/integration.py,sha256=Xps2zaD80FY_e-2vl_skybhuzQmqaC8zQQOY7K1s78o,10746
@@ -295,7 +295,7 @@ reconcile/test/conftest.py,sha256=dBWwQMkcdONERlnBJg4J6Td5Fexpbvme5y-UuoI-c9M,31
295
295
  reconcile/test/fixtures.py,sha256=VhvLXH0AWXEyu3FgPp7bcSTPmDPfMEa2v-_9cd8dCmw,572
296
296
  reconcile/test/test_aggregated_list.py,sha256=iiWitQuNYC58aimWaiBoE4NROHjr1NCgQ91MnHEG_Ro,6412
297
297
  reconcile/test/test_amtool.py,sha256=vxRhGieeydMBOb9UI2ziMHjJa8puMeGNsUhGhy-yMnk,1032
298
- reconcile/test/test_auto_promoter.py,sha256=4EtLLN0FAJGJnFoSCRsB5hHyY2-H3GMfnn5-p7kNCTg,10340
298
+ reconcile/test/test_auto_promoter.py,sha256=unvv6F7vwIB_V0FG-G9rGmVVxDLQ2m6bWSnypB5q7Ek,10864
299
299
  reconcile/test/test_aws_ami_share.py,sha256=eSITdDoXs8mMY7P2lFxAX2DA0sJ9RW6D1tG8Rek0gLE,1981
300
300
  reconcile/test/test_aws_iam_keys.py,sha256=MfE9EvItyPNPAl5QaLlJFUvvrZFiar518TM2wWNjJn4,1829
301
301
  reconcile/test/test_aws_iam_password_reset.py,sha256=fnkqB90adR7W4L4saNdrtIiwnQB9bXgqJ9R1CKxjSnk,860
@@ -340,7 +340,7 @@ reconcile/test/test_quay_repos.py,sha256=TdkcRF_a8PLp01Kti9eZZN-vGup2yPBT4Iba3k0
340
340
  reconcile/test/test_queries.py,sha256=SpH3RmNpBjEr_ne3VjAMCgKK8RE1z1zo7bypkT5uoO4,1946
341
341
  reconcile/test/test_repo_owners.py,sha256=uRYMLbMmh-9usF0TerabZTZV-Z1CS4I6ybT-LQqCLe8,1423
342
342
  reconcile/test/test_requests_sender.py,sha256=7fd9C2kEFS0-CYtlsif66N1kO9c44pzuBPAJKR9igqU,5385
343
- reconcile/test/test_saasherder.py,sha256=45D8_5frYn3ax-Tw96s2eBKNxY5qmZ1KpHD_iv9Ea80,37402
343
+ reconcile/test/test_saasherder.py,sha256=cZ5SN93furNduYOjdsEZdra-Vo9n9yfG23k2J7k_SZM,37609
344
344
  reconcile/test/test_saasherder_allowed_secret_paths.py,sha256=86ffYbbN0Xng8CTiXf3yR_3VD8qyqRpVTByJFycdXp0,4899
345
345
  reconcile/test/test_secret_reader.py,sha256=kz7nzcPjvA08cytnvcA_PMA98AEyqJWsESkYeRn5xCk,4994
346
346
  reconcile/test/test_slack_base.py,sha256=UqMjYt4hPmStJfog06qwJM_afbf-E9uzy-GX741KgTY,5058
@@ -401,8 +401,8 @@ reconcile/test/test_version_bump.py,sha256=q6-3Y1roriI6YWpFwaHOMN7emEP3yL33sh_0V
401
401
  reconcile/test/test_vpc_peerings_validator.py,sha256=j4MlmIoGptMJsYNfJAChHRkilSxtqBEUJBQhL6Uqfmo,3710
402
402
  reconcile/test/test_wrong_region.py,sha256=7KzL7OaICQ9Z3DW27zt_ykMN7_87owAFC-2CYjvGoyA,2138
403
403
  reconcile/test/saas_auto_promotions_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
404
- reconcile/test/saas_auto_promotions_manager/conftest.py,sha256=1QT_pdhgADtKB8VweMWMYxwXlc_aMJ0EZmA9qWC0olw,2103
405
- reconcile/test/saas_auto_promotions_manager/test_integration_test.py,sha256=lBKDeN7j9i-JxNUyo0hlWU_WkEUUskm4xkcHfPMJm1Y,4562
404
+ reconcile/test/saas_auto_promotions_manager/conftest.py,sha256=DodxMN_hjE3GU7G_k5RYjAoc4Iu1vp0WiE_ISQEG9YA,2382
405
+ reconcile/test/saas_auto_promotions_manager/test_integration_test.py,sha256=8eW0kWCgwCs1gGEkzqKoG77z0Z9HMWpALYoK0iNl5DQ,5164
406
406
  reconcile/test/saas_auto_promotions_manager/merge_request_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
407
407
  reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
408
408
  reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py,sha256=LGEsqcjs4O4i29LJ0I7g8-uBog1QKFRGA5-8rSfrks0,3302
@@ -416,7 +416,7 @@ reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_
416
416
  reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_namespace.py,sha256=w8BT3Z_M7Jz0Xn1OINWypWjmSGMBDGgjt_zY_3iOJoM,2667
417
417
  reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_target.py,sha256=cwAPrQ_v3DR_CHU7Nt2xBGutC-1XslyJ5mXM8FXW-3o,1111
418
418
  reconcile/test/saas_auto_promotions_manager/subscriber/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
419
- reconcile/test/saas_auto_promotions_manager/subscriber/conftest.py,sha256=YmuCS9fIQ6CiAM8pjjtSPe12skQrrch6mD06HTbRdIE,2531
419
+ reconcile/test/saas_auto_promotions_manager/subscriber/conftest.py,sha256=05BZqP5tapjhlcLD0teasbNO1DzBo_xoGhZdxebbWK8,2559
420
420
  reconcile/test/saas_auto_promotions_manager/subscriber/data_keys.py,sha256=xaGGbeWtq0aYlJxC-7wJvX3yWnqDSNYMeR0h5rsYAh0,410
421
421
  reconcile/test/saas_auto_promotions_manager/subscriber/test_content_hash.py,sha256=6Nkyix3Uyf7Zd9t2C6RnYlQG_y3NsZ6v6zu3G-qF4to,5186
422
422
  reconcile/test/saas_auto_promotions_manager/subscriber/test_diff.py,sha256=naArIa1AZj8iaDjzJoYwLX5PqrSNakqsBXonOHEQ0PA,4957
@@ -425,7 +425,7 @@ reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_channels_mo
425
425
  reconcile/test/saas_auto_promotions_manager/subscriber/test_single_channel_with_single_publisher.py,sha256=zIkUg-Vx-Em0-0JY_zC1N3Of_PaB-8GRSqsW5FXLkM8,10244
426
426
  reconcile/test/saas_auto_promotions_manager/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
427
427
  reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
428
- reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_multiple_publishers_for_single_channel.py,sha256=A2bw4U2jcwpQpTd8nab2Pe7QeF-__2CEJp8kWocVHVc,2414
428
+ reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_multiple_publishers_for_single_channel.py,sha256=1O1F-BVWAgcrfPJ7QDpMeQcrZRB0eWa9jCzDZ_o7QS8,2309
429
429
  reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_use_target_config_hash.py,sha256=qC_GapxJxfTEZ0o5xYuI4BA0cRcX4QLgtlW5MY691nw,2066
430
430
  reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_with_auto_promote.py,sha256=F3ZGLzNa821yUw68YH9bA1cQEV82_hQxfPjkuJ-ELWw,2707
431
431
  reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_without_auto_promote.py,sha256=6EYKmXDN9ckkMvdUBZlUiunCKuwQ9UmnPijKvXU8iZo,2170
@@ -445,7 +445,7 @@ reconcile/typed_queries/namespaces_minimal.py,sha256=rUtqNQ0ORXXUTQfnpsMURymAJ4g
445
445
  reconcile/typed_queries/ocp_release_mirror.py,sha256=jwX29Tcdvov8oEDNkE4t1j-2Hz8QJrjg9ITppP-panQ,313
446
446
  reconcile/typed_queries/pagerduty_instances.py,sha256=QCHqEAakiH6eSob0Pnnn3IBd8Ga0zpEp1Z6Qu3v2uH4,733
447
447
  reconcile/typed_queries/repos.py,sha256=RKBsf7IDS6NsXTtXxJ9Ol9G3bxG9sr3vW9QQ2bahEHo,512
448
- reconcile/typed_queries/saas_files.py,sha256=aAtAtUGP5yRWI5MxL3GmrhjKNUKOd8RhALECwRZvr3E,11443
448
+ reconcile/typed_queries/saas_files.py,sha256=XU4nzvcD3kUT4Aw-mrupWESc6RANUAwCfBf5OVhD7Lk,12689
449
449
  reconcile/typed_queries/smtp.py,sha256=aSLglYa5bHKmlGwKkxq2RZqyMWuAf0a4S_mOuhDa084,542
450
450
  reconcile/typed_queries/tekton_pipeline_providers.py,sha256=2mpHBdsNPQB94tw0H9aenGuqj8EEjYolQ03YEq1CpiY,546
451
451
  reconcile/typed_queries/terraform_namespaces.py,sha256=71ARJ-GzkU9tBM0IfJTL3NF4349SJy-Mgs_DwAgUz_g,444
@@ -504,7 +504,7 @@ reconcile/utils/output.py,sha256=htcMXMe0y2dNnwu8MW8x0JZ5YBaEJRy5w4tR8yLF0OU,173
504
504
  reconcile/utils/pagerduty_api.py,sha256=LgfiGSmg1iLfTsc1ZuHrFh_8qXLz52YWTXv5sF1BpN8,7468
505
505
  reconcile/utils/parse_dhms_duration.py,sha256=ZJGlB43MjhgckgO3OF_nacwTiKVRpxb5Yv7m-PnaQLk,1616
506
506
  reconcile/utils/password_validator.py,sha256=XwuWg-8CPlcuG7dl_oQ1G1h2gSVSnfMym_VkuprpWVg,2183
507
- reconcile/utils/promotion_state.py,sha256=xveM7-5hIVcTFpHkE9iYctXB9e-7FApUXIeWkoLFkrU,2172
507
+ reconcile/utils/promotion_state.py,sha256=n7OucbDDkK-8OAzAnTWtHXn14amqtZ7cr-h1MJ-I8hc,3176
508
508
  reconcile/utils/promtool.py,sha256=IYNCjj5xDAEdxv6Z0pLdrIcybDfHHtWE9Z6f4LSPcG4,2791
509
509
  reconcile/utils/quay_api.py,sha256=EuOegpb-7ntEjkKLFwM2Oo4Nw7SyFtmyl3sQ9aXMtrM,8152
510
510
  reconcile/utils/raw_github_api.py,sha256=ZHC-SZuAyRe1zaMoOU7Krt1-zecDxENd9c_NzQYqK9g,2968
@@ -557,9 +557,9 @@ reconcile/utils/runtime/meta.py,sha256=hQ_jHPY0zbyA08hzpfu4FzOw25NqMg_fgCr2r9gGX
557
557
  reconcile/utils/runtime/runner.py,sha256=72cc-I6yXyPov8UCLHpyERRy1eiMLpGite2roO0yUlo,7979
558
558
  reconcile/utils/runtime/sharding.py,sha256=S43RM_ycFUDVzJD69It91xHZNML_xaAlsbVPR-me5Bk,13638
559
559
  reconcile/utils/saasherder/__init__.py,sha256=J3MBZBFa5YmhqYm08QsjBXz8mFcVOCiOCkyIcw41t7E,343
560
- reconcile/utils/saasherder/interfaces.py,sha256=gj0ACYSwp21hxTjoF3Ztd4EDLZ55QxBaXYJ3yhIgF94,8691
561
- reconcile/utils/saasherder/models.py,sha256=pmHYafLyasZHeVz_HvHraIb_9ITj4j6S9K604LRtDHg,4700
562
- reconcile/utils/saasherder/saasherder.py,sha256=oxUVVMIrORWplGghVRK-29tN-JYH4Boolk20EZtu8FA,80885
560
+ reconcile/utils/saasherder/interfaces.py,sha256=MWP9gJOac0NA8mdzCqzta4RYbr680pR8orZmRftv5VU,8840
561
+ reconcile/utils/saasherder/models.py,sha256=R_6Gx71GnK_eWBG1onBbHfHwkektecKGmMTttbKe33E,4725
562
+ reconcile/utils/saasherder/saasherder.py,sha256=hYQOAG3O1w-znNld6mv8xdimh7XIh7WEjYQq-f3qzwk,81112
563
563
  reconcile/utils/terraform/__init__.py,sha256=zNbiyTWo35AT1sFTElL2j_AA0jJ_yWE_bfFn-nD2xik,250
564
564
  reconcile/utils/terraform/config.py,sha256=5UVrd563TMcvi4ooa5JvWVDW1I3bIWg484u79evfV_8,164
565
565
  reconcile/utils/terraform/config_client.py,sha256=t4novdX7GeYPMYms97C_BBtLmt0M8CJCmCT7QHENwxg,4687
@@ -583,8 +583,8 @@ tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y
583
583
  tools/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
584
584
  tools/test/test_qontract_cli.py,sha256=awwTHEc2DWlykuqGIYM0WOBoSL0KRnOraCLk3C7izis,1401
585
585
  tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
586
- qontract_reconcile-0.10.1rc46.dist-info/METADATA,sha256=Pyu_2PvygoodwZx6A4XAwAQYcYthtBsW_g1d_JCNbvc,2288
587
- qontract_reconcile-0.10.1rc46.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
588
- qontract_reconcile-0.10.1rc46.dist-info/entry_points.txt,sha256=Af70EWPJxsTiCNF6gA-pWdw1A0Heqn-PZF-oBc5NmiU,302
589
- qontract_reconcile-0.10.1rc46.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
590
- qontract_reconcile-0.10.1rc46.dist-info/RECORD,,
586
+ qontract_reconcile-0.10.1rc48.dist-info/METADATA,sha256=IPX-uDN-ybEdMeUiV7zrZzcLvm2X80poZF9Nv72FFYo,2288
587
+ qontract_reconcile-0.10.1rc48.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
588
+ qontract_reconcile-0.10.1rc48.dist-info/entry_points.txt,sha256=Af70EWPJxsTiCNF6gA-pWdw1A0Heqn-PZF-oBc5NmiU,302
589
+ qontract_reconcile-0.10.1rc48.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
590
+ qontract_reconcile-0.10.1rc48.dist-info/RECORD,,
@@ -28,10 +28,19 @@ class Publisher:
28
28
  def __init__(
29
29
  self,
30
30
  ref: str,
31
+ uid: str,
31
32
  repo_url: str,
32
33
  auth_code: Optional[HasSecret],
33
34
  ):
35
+ """Init.
36
+
37
+ ref: The target git ref to fetch the commit sha from.
38
+ uid: The uid of the saas publisher target.
39
+ repo_url: The git repo url of the saas publisher target.
40
+ auth_code: The auth code to use to fetch the commit sha.
41
+ """
34
42
  self._ref = ref
43
+ self._uid = uid
35
44
  self._repo_url = repo_url
36
45
  self._auth_code = auth_code
37
46
  self.channels: set[str] = set()
@@ -51,6 +60,7 @@ class Publisher:
51
60
  promotion_data = deployment_state.get_promotion_data(
52
61
  sha=self.commit_sha,
53
62
  channel=channel,
63
+ saas_target_uid=self._uid,
54
64
  )
55
65
  if not (
56
66
  promotion_data
@@ -34,25 +34,6 @@ class SaasFilesInventory:
34
34
  self._assemble_publishers()
35
35
  self._remove_unsupported()
36
36
 
37
- def _assemble_channels(self) -> None:
38
- for saas_file in self._saas_files:
39
- for resource_template in saas_file.resource_templates:
40
- for target in resource_template.targets:
41
- if not target.promotion:
42
- continue
43
- for publish_channel in target.promotion.publish or []:
44
- if publish_channel not in self._channels_by_name:
45
- self._channels_by_name[publish_channel] = Channel(
46
- name=publish_channel,
47
- publishers=[],
48
- )
49
- for subscribe_channel in target.promotion.subscribe or []:
50
- if subscribe_channel not in self._channels_by_name:
51
- self._channels_by_name[subscribe_channel] = Channel(
52
- name=subscribe_channel,
53
- publishers=[],
54
- )
55
-
56
37
  def _assemble_publishers(self) -> None:
57
38
  for saas_file in self._saas_files:
58
39
  for resource_template in saas_file.resource_templates:
@@ -66,6 +47,7 @@ class SaasFilesInventory:
66
47
  )
67
48
  publisher = Publisher(
68
49
  ref=target.ref,
50
+ uid=target.uid,
69
51
  repo_url=resource_template.url,
70
52
  auth_code=auth_code,
71
53
  )
@@ -149,13 +131,6 @@ class SaasFilesInventory:
149
131
  for subscriber in self.subscribers:
150
132
  is_supported = True
151
133
  for channel in subscriber.channels:
152
- if len(channel.publishers) > 1:
153
- logging.error(
154
- "[%s] We do not support multiple publishers for a single channel - blocked by https://issues.redhat.com/browse/APPSRE-7414",
155
- channel.name,
156
- )
157
- is_supported = False
158
- break
159
134
  if not channel.publishers:
160
135
  logging.error(
161
136
  "[%s] There must be at least one publisher per channel.",
@@ -163,18 +138,7 @@ class SaasFilesInventory:
163
138
  )
164
139
  is_supported = False
165
140
  break
166
- if (
167
- len(subscriber.config_hashes_by_channel_name.get(channel.name, []))
168
- > 1
169
- ):
170
- logging.error(
171
- "[%s] We do not support multiple publishers for a single channel - blocked by https://issues.redhat.com/browse/APPSRE-7414",
172
- channel.name,
173
- )
174
- is_supported = False
175
- break
141
+
176
142
  if is_supported:
177
143
  supported_subscribers.append(subscriber)
178
144
  self.subscribers = supported_subscribers
179
- # Ideally we also remove the publishers that are left w/o subscriber.
180
- # But lets solve APPSRE-7414 - then it wont be necessary in the first place.
@@ -32,6 +32,11 @@ def saas_files_builder(
32
32
  d["imagePatterns"] = []
33
33
  for rt in d.get("resourceTemplates", []):
34
34
  for t in rt.get("targets", []):
35
+ if "parent_saas_file_name" not in t:
36
+ t["parent_saas_file_name"] = "saas-file-name"
37
+ if "parent_resource_template_name" not in t:
38
+ t["parent_resource_template_name"] = "resource-template-name"
39
+
35
40
  ns = t["namespace"]
36
41
  if "name" not in ns:
37
42
  ns["name"] = "some_name"
@@ -41,6 +41,7 @@ def subscriber_builder() -> Callable[[Mapping[str, Any]], Subscriber]:
41
41
  for publisher_name, publisher_data in channel_data.items():
42
42
  publisher = Publisher(
43
43
  ref="",
44
+ uid="",
44
45
  repo_url="",
45
46
  auth_code=None,
46
47
  )
@@ -92,6 +92,8 @@ def test_integration_test(
92
92
  "ls": [
93
93
  "/promotions/channel-1/new_sha",
94
94
  "/promotions/channel-2/new_sha",
95
+ "/deployments/channel-3/target-uid/new_sha",
96
+ "/deployments/channel-4/target-uid/new_sha",
95
97
  ],
96
98
  "get": {
97
99
  "promotions/channel-1/new_sha": {
@@ -104,6 +106,16 @@ def test_integration_test(
104
106
  "target_config_hash": "new_hash",
105
107
  "saas_file": "saas_1",
106
108
  },
109
+ "/deployments/channel-3/target-uid/new_sha": {
110
+ "success": True,
111
+ "target_config_hash": "new_hash",
112
+ "saas_file": "saas_1",
113
+ },
114
+ "/deployments/channel-4/target-uid/new_sha": {
115
+ "success": True,
116
+ "target_config_hash": "new_hash",
117
+ "saas_file": "saas_1",
118
+ },
107
119
  },
108
120
  }
109
121
  )
@@ -65,6 +65,4 @@ def test_multiple_publishers_for_single_channel(
65
65
  )
66
66
  inventory = SaasFilesInventory(saas_files=saas_files)
67
67
  assert len(inventory.publishers) == 2
68
- # As of now we do not support this, i.e., all
69
- # subscribers should be removed from the inventory
70
- assert len(inventory.subscribers) == 0
68
+ assert len(inventory.subscribers) == 1
@@ -15,6 +15,7 @@ class TestPromotions(TestCase):
15
15
  commit_sha="ahash",
16
16
  saas_file="saas_file",
17
17
  target_config_hash="123123123",
18
+ saas_target_uid="saas_target_uid",
18
19
  )
19
20
 
20
21
  expected = {
@@ -50,6 +51,7 @@ class TestPromotions(TestCase):
50
51
  publish=["test-channel"],
51
52
  commit_sha="ahash",
52
53
  target_config_hash="111111111",
54
+ saas_target_uid="saas_target_uid",
53
55
  )
54
56
 
55
57
  target_promotion = {
@@ -74,6 +76,7 @@ class TestPromotions(TestCase):
74
76
  commit_sha="ahash",
75
77
  saas_file="saas_file",
76
78
  target_config_hash="111111111",
79
+ saas_target_uid="saas_target_uid",
77
80
  )
78
81
 
79
82
  target_promotion = {
@@ -110,6 +113,7 @@ class TestPromotions(TestCase):
110
113
  commit_sha="ahash",
111
114
  saas_file="saas_file",
112
115
  target_config_hash="111111111",
116
+ saas_target_uid="saas_target_uid",
113
117
  )
114
118
 
115
119
  target_promotion = {
@@ -142,11 +146,12 @@ class TestPromotions(TestCase):
142
146
  commit_sha="ahash",
143
147
  saas_file="saas_file",
144
148
  target_config_hash="111111111",
149
+ saas_target_uid="saas_target_uid",
145
150
  )
146
151
 
147
152
  ap = AutoPromoter([promotion])
148
153
  self.assertEqual(
149
- ap.title, "[auto_promoter] openshift-saas-deploy automated promotion 4af7b1"
154
+ ap.title, "[auto_promoter] openshift-saas-deploy automated promotion 0a3d57"
150
155
  )
151
156
 
152
157
  def test_description_property(self) -> None:
@@ -157,6 +162,7 @@ class TestPromotions(TestCase):
157
162
  commit_sha="ahash",
158
163
  saas_file="saas_file",
159
164
  target_config_hash="111111111",
165
+ saas_target_uid="saas_target_uid",
160
166
  )
161
167
 
162
168
  ap = AutoPromoter([promotion])
@@ -170,15 +176,13 @@ class TestPromotions(TestCase):
170
176
  commit_sha="ahash",
171
177
  saas_file="saas_file",
172
178
  target_config_hash="111111111",
179
+ saas_target_uid="saas_target_uid",
173
180
  )
174
181
 
175
182
  ap = AutoPromoter([promotion])
176
183
  self.assertTrue(ap.gitlab_data["source_branch"].startswith("auto_promoter-"))
177
184
  self.assertEqual(ap.gitlab_data["target_branch"], "master")
178
- self.assertEqual(
179
- ap.gitlab_data["title"],
180
- "[auto_promoter] openshift-saas-deploy automated promotion 4af7b1",
181
- )
185
+ self.assertEqual(ap.gitlab_data["title"], ap.title)
182
186
  self.assertEqual(
183
187
  ap.gitlab_data["description"], "openshift-saas-deploy automated promotion"
184
188
  )
@@ -193,6 +197,7 @@ class TestPromotions(TestCase):
193
197
  commit_sha="ahash",
194
198
  saas_file="saas_file",
195
199
  target_config_hash="111111111",
200
+ saas_target_uid="saas_target_uid",
196
201
  )
197
202
 
198
203
  ap = AutoPromoter([promotion])
@@ -210,6 +215,7 @@ class TestPromotions(TestCase):
210
215
  "subscribe": None,
211
216
  "promotion_data": None,
212
217
  "saas_file_paths": ["destination-saas-file"],
218
+ "saas_target_uid": "saas_target_uid",
213
219
  "target_paths": None,
214
220
  }
215
221
  ],
@@ -224,6 +230,7 @@ class TestPromotions(TestCase):
224
230
  commit_sha="ahash",
225
231
  saas_file="saas_file",
226
232
  target_config_hash="111111111",
233
+ saas_target_uid="saas_target_uid",
227
234
  promotion_data=[
228
235
  {
229
236
  "channel": "test-channel",
@@ -239,7 +246,7 @@ class TestPromotions(TestCase):
239
246
  )
240
247
 
241
248
  ap = AutoPromoter([promotion])
242
- sqs_json = '{"pr_type": "auto_promoter", "promotions": [{"commit_sha": "ahash", "saas_file": "saas_file", "target_config_hash": "111111111", "auto": true, "publish": ["test-channel"], "subscribe": null, "promotion_data": [{"channel": "test-channel", "data": [{"type": "parent_saas_config", "parent_saas": "saas_file", "target_config_hash": "111111111"}]}], "saas_file_paths": ["destination-saas-file"], "target_paths": null}]}'
249
+ sqs_json = '{"pr_type": "auto_promoter", "promotions": [{"commit_sha": "ahash", "saas_file": "saas_file", "target_config_hash": "111111111", "saas_target_uid": "saas_target_uid", "auto": true, "publish": ["test-channel"], "subscribe": null, "promotion_data": [{"channel": "test-channel", "data": [{"type": "parent_saas_config", "parent_saas": "saas_file", "target_config_hash": "111111111"}]}], "saas_file_paths": ["destination-saas-file"], "target_paths": null}]}'
243
250
  self.assertEqual(json.dumps(ap.sqs_data), sqs_json)
244
251
 
245
252
  def test_init_with_promotion_object(self) -> None:
@@ -250,6 +257,7 @@ class TestPromotions(TestCase):
250
257
  commit_sha="ahash",
251
258
  saas_file="saas_file",
252
259
  target_config_hash="111111111",
260
+ saas_target_uid="saas_target_uid",
253
261
  promotion_data=[
254
262
  {
255
263
  "channel": "test-channel",
@@ -276,6 +284,7 @@ class TestPromotions(TestCase):
276
284
  commit_sha="ahash",
277
285
  saas_file="saas_file",
278
286
  target_config_hash="111111111",
287
+ saas_target_uid="saas_target_uid",
279
288
  promotion_data=[
280
289
  {
281
290
  "channel": "test-channel",
@@ -28,10 +28,14 @@ from reconcile.gql_definitions.common.saas_files import (
28
28
  SaasResourceTemplateTargetV2_SaasSecretParametersV1,
29
29
  SaasResourceTemplateV2,
30
30
  )
31
+ from reconcile.typed_queries.saas_files import (
32
+ SaasFile,
33
+ convert_saas_file_v2_to_saas_file,
34
+ )
31
35
  from reconcile.utils.jjb_client import JJB
32
36
  from reconcile.utils.openshift_resource import ResourceInventory
33
37
  from reconcile.utils.saasherder import SaasHerder
34
- from reconcile.utils.saasherder.interfaces import SaasFile
38
+ from reconcile.utils.saasherder.interfaces import SaasFile as SaasFileInterface
35
39
  from reconcile.utils.saasherder.models import TriggerSpecMovingCommit
36
40
  from reconcile.utils.secret_reader import SecretReaderBase
37
41
 
@@ -607,7 +611,7 @@ class TestPopulateDesiredState(TestCase):
607
611
  self.saasherder.populate_desired_state(ri)
608
612
 
609
613
  cnt = 0
610
- for (cluster, namespace, resource_type, data) in ri:
614
+ for cluster, namespace, resource_type, data in ri:
611
615
  for _, d_item in data["desired"].items():
612
616
  expected = yaml.safe_load(
613
617
  self.fxts.get(
@@ -763,6 +767,7 @@ class TestConfigHashPromotionsValidation(TestCase):
763
767
  self.saas_file = self.gql_class_factory( # type: ignore[attr-defined] # it's set in the fixture
764
768
  SaasFileV2, Fixtures("saasherder").get_anymarkup("saas.gql.yml")
765
769
  )
770
+ self.saas_file = convert_saas_file_v2_to_saas_file(self.saas_file)
766
771
  self.all_saas_files = [self.saas_file]
767
772
 
768
773
  self.state_patcher = patch("reconcile.utils.state.State", autospec=True)
@@ -959,7 +964,7 @@ class TestRemoveNoneAttributes(TestCase):
959
964
 
960
965
 
961
966
  def test_render_templated_parameters(
962
- gql_class_factory: Callable[..., SaasFile]
967
+ gql_class_factory: Callable[..., SaasFileInterface]
963
968
  ) -> None:
964
969
  saas_file = gql_class_factory(
965
970
  SaasFileV2,
@@ -1,3 +1,4 @@
1
+ import hashlib
1
2
  import json
2
3
  from collections.abc import Callable
3
4
  from typing import (
@@ -23,6 +24,7 @@ from reconcile.gql_definitions.common.saas_files import (
23
24
  PipelinesProviderV1,
24
25
  RoleV1,
25
26
  SaasFileAuthenticationV1,
27
+ SaasFileV2,
26
28
  SaasResourceTemplateTargetImageV1,
27
29
  SaasResourceTemplateTargetNamespaceSelectorV1,
28
30
  SaasResourceTemplateTargetPromotionV1,
@@ -70,11 +72,27 @@ class SaasResourceTemplateTarget(ConfiguredBaseModel):
70
72
  image: Optional[SaasResourceTemplateTargetImageV1] = Field(..., alias="image")
71
73
  disable: Optional[bool] = Field(..., alias="disable")
72
74
  delete: Optional[bool] = Field(..., alias="delete")
75
+ parent_saas_file_name: Optional[str] = None
76
+ parent_resource_template_name: Optional[str] = None
73
77
 
74
78
  class Config:
75
79
  # ignore `namespaceSelector` and 'provider' fields from the GQL schema
76
80
  extra = Extra.ignore
77
81
 
82
+ @property
83
+ def uid(self) -> str:
84
+ """Returns a unique identifier for a target."""
85
+ if not self.parent_resource_template_name:
86
+ raise ValueError(
87
+ "parent_resource_template_name must be set before calling uid()"
88
+ )
89
+ if not self.parent_saas_file_name:
90
+ raise ValueError("parent_saas_file_name must be set before calling uid()")
91
+ return hashlib.blake2s(
92
+ f"{self.parent_saas_file_name}:{self.parent_resource_template_name}:{self.name if self.name else 'default'}:{self.namespace.cluster.name}:{self.namespace.name}".encode(),
93
+ digest_size=20,
94
+ ).hexdigest()
95
+
78
96
 
79
97
  class SaasResourceTemplate(ConfiguredBaseModel):
80
98
  name: str = Field(..., alias="name")
@@ -205,6 +223,16 @@ def create_targets_for_namespace_selector(
205
223
  return targets
206
224
 
207
225
 
226
+ def convert_saas_file_v2_to_saas_file(saas_file_gql: SaasFileV2) -> SaasFile:
227
+ """Convert a SaasFileV2 to a SaasFile and inject the parent objects."""
228
+ saas_file = SaasFile(**export_model(saas_file_gql))
229
+ for tmpl in saas_file.resource_templates:
230
+ for target in tmpl.targets:
231
+ target.parent_saas_file_name = saas_file.name
232
+ target.parent_resource_template_name = tmpl.name
233
+ return saas_file
234
+
235
+
208
236
  def get_saas_files(
209
237
  name: Optional[str] = None,
210
238
  env_name: Optional[str] = None,
@@ -245,7 +273,7 @@ def get_saas_files(
245
273
  )
246
274
  # convert SaasFileV2 (with optional resource_templates.targets.namespace field)
247
275
  # to SaasFile (with required resource_templates.targets.namespace field)
248
- saas_files.append(SaasFile(**export_model(saas_file_gql)))
276
+ saas_files.append(convert_saas_file_v2_to_saas_file(saas_file_gql))
249
277
 
250
278
  if name is None and env_name is None and app_name is None:
251
279
  return saas_files
@@ -47,28 +47,51 @@ class PromotionState:
47
47
  """
48
48
  all_keys = self._state.ls()
49
49
  for commit in all_keys:
50
- # Format: /promotions/{channel}/{commit-sha}
51
- if not commit.startswith("/promotions/"):
50
+ # for backwards compatibility - remove this after a while
51
+ if commit.startswith("/promotions/"):
52
+ # Format: /promotions/{channel}/{commit-sha}
53
+ _, _, channel_name, commit_sha = commit.split("/")
54
+ self._commits_by_channel[channel_name].add(commit_sha)
55
+ # / for backwards compatibility - remove this after a while
56
+
57
+ # Format: /deployments/{channel}/{saas-target-uid}/{commit-sha}
58
+ if not commit.startswith("/deployments/"):
52
59
  continue
53
- _, _, channel_name, commit_sha = commit.split("/")
54
- self._commits_by_channel[channel_name].add(commit_sha)
60
+ _, _, channel_name, saas_target_uid, commit_sha = commit.split("/")
61
+ self._commits_by_channel[f"{channel_name}/{saas_target_uid}"].add(
62
+ commit_sha
63
+ )
55
64
 
56
65
  def get_promotion_data(
57
- self, sha: str, channel: str, local_lookup: bool = True
66
+ self, sha: str, channel: str, saas_target_uid: str, local_lookup: bool = True
58
67
  ) -> Optional[PromotionData]:
59
- if local_lookup and sha not in self._commits_by_channel[channel]:
68
+ if (
69
+ local_lookup
70
+ and sha not in self._commits_by_channel[channel]
71
+ and sha not in self._commits_by_channel[f"{channel}/{saas_target_uid}"]
72
+ ):
60
73
  # Lets reduce unecessary calls to S3
61
74
  return None
75
+
76
+ # for backwards compatibility - remove this after a while
62
77
  key = f"promotions/{channel}/{sha}"
63
78
  try:
64
79
  data = self._state.get(key)
80
+ return PromotionData(**data)
81
+ except KeyError:
82
+ pass
83
+ # / for backwards compatibility - remove this after a while
84
+
85
+ key = f"deployments/{channel}/{saas_target_uid}/{sha}"
86
+ try:
87
+ data = self._state.get(key)
88
+ return PromotionData(**data)
65
89
  except KeyError:
66
90
  return None
67
- return PromotionData(**data)
68
91
 
69
92
  def publish_promotion_data(
70
- self, sha: str, channel: str, data: PromotionData
93
+ self, sha: str, channel: str, saas_target_uid: str, data: PromotionData
71
94
  ) -> None:
72
- state_key = f"promotions/{channel}/{sha}"
95
+ state_key = f"deployments/{channel}/{saas_target_uid}/{sha}"
73
96
  self._state.add(state_key, data.dict(), force=True)
74
97
  logging.info("Uploaded %s to %s", data, state_key)
@@ -332,7 +332,11 @@ class SaasResourceTemplateTarget(HasParameters, HasSecretParameters, Protocol):
332
332
  ...
333
333
 
334
334
  def dict(self, *, by_alias: bool = False) -> dict[str, Any]:
335
- ...
335
+ """Return a dictionary representation of the model."""
336
+
337
+ @property
338
+ def uid(self) -> str:
339
+ """Return a unique identifier for the target."""
336
340
 
337
341
 
338
342
  class SaasResourceTemplate(HasParameters, HasSecretParameters, Protocol):
@@ -167,6 +167,7 @@ class Promotion(BaseModel):
167
167
  commit_sha: str
168
168
  saas_file: str
169
169
  target_config_hash: str
170
+ saas_target_uid: str
170
171
  auto: Optional[bool] = None
171
172
  publish: Optional[list[str]] = None
172
173
  subscribe: Optional[list[str]] = None
@@ -996,6 +996,7 @@ class SaasHerder: # pylint: disable=too-many-public-methods
996
996
  commit_sha=commit_sha,
997
997
  saas_file=saas_file_name,
998
998
  target_config_hash=target_config_hash,
999
+ saas_target_uid=target.uid,
999
1000
  )
1000
1001
  return resources, html_url, target_promotion
1001
1002
 
@@ -1768,7 +1769,10 @@ class SaasHerder: # pylint: disable=too-many-public-methods
1768
1769
  if promotion.subscribe:
1769
1770
  for channel in promotion.subscribe:
1770
1771
  info = self._promotion_state.get_promotion_data(
1771
- sha=promotion.commit_sha, channel=channel, local_lookup=False
1772
+ sha=promotion.commit_sha,
1773
+ channel=channel,
1774
+ saas_target_uid=promotion.saas_target_uid,
1775
+ local_lookup=False,
1772
1776
  )
1773
1777
  if not (info and info.success):
1774
1778
  logging.error(
@@ -1860,6 +1864,7 @@ class SaasHerder: # pylint: disable=too-many-public-methods
1860
1864
  self._promotion_state.publish_promotion_data(
1861
1865
  sha=promotion.commit_sha,
1862
1866
  channel=channel,
1867
+ saas_target_uid=promotion.saas_target_uid,
1863
1868
  data=PromotionData(
1864
1869
  saas_file=promotion.saas_file,
1865
1870
  success=success,