qontract-reconcile 0.10.1rc764__py3-none-any.whl → 0.10.1rc766__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.
- {qontract_reconcile-0.10.1rc764.dist-info → qontract_reconcile-0.10.1rc766.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc764.dist-info → qontract_reconcile-0.10.1rc766.dist-info}/RECORD +19 -34
- reconcile/gql_definitions/ldap_groups/roles.py +12 -2
- reconcile/ldap_groups/integration.py +36 -23
- reconcile/saas_auto_promotions_manager/meta.py +1 -1
- reconcile/saas_auto_promotions_manager/subscriber.py +52 -2
- reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py +4 -0
- reconcile/test/saas_auto_promotions_manager/conftest.py +63 -0
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py +0 -37
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_desired_state.py +20 -14
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py +0 -43
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_multiple_namespaces.py +4 -11
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_namespace.py +12 -19
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_target.py +6 -12
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_json_path_selector.py +8 -15
- reconcile/utils/internal_groups/models.py +1 -1
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/data_keys.py +0 -4
- reconcile/test/saas_auto_promotions_manager/subscriber/__init__.py +0 -0
- reconcile/test/saas_auto_promotions_manager/subscriber/conftest.py +0 -89
- reconcile/test/saas_auto_promotions_manager/subscriber/data_keys.py +0 -11
- reconcile/test/saas_auto_promotions_manager/subscriber/test_content_hash.py +0 -130
- reconcile/test/saas_auto_promotions_manager/subscriber/test_diff.py +0 -161
- reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_channels_config_hash.py +0 -218
- reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_channels_moving_ref.py +0 -216
- reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_publishers_moving_ref.py +0 -129
- reconcile/test/saas_auto_promotions_manager/subscriber/test_single_channel_with_single_publisher.py +0 -330
- reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/__init__.py +0 -0
- reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_multiple_publishers_for_single_channel.py +0 -68
- reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_use_target_config_hash.py +0 -62
- reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_with_auto_promote.py +0 -73
- reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_without_auto_promote.py +0 -64
- {qontract_reconcile-0.10.1rc764.dist-info → qontract_reconcile-0.10.1rc766.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc764.dist-info → qontract_reconcile-0.10.1rc766.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc764.dist-info → qontract_reconcile-0.10.1rc766.dist-info}/top_level.txt +0 -0
{qontract_reconcile-0.10.1rc764.dist-info → qontract_reconcile-0.10.1rc766.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: qontract-reconcile
|
3
|
-
Version: 0.10.
|
3
|
+
Version: 0.10.1rc766
|
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
|
{qontract_reconcile-0.10.1rc764.dist-info → qontract_reconcile-0.10.1rc766.dist-info}/RECORD
RENAMED
@@ -308,7 +308,7 @@ reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions
|
|
308
308
|
reconcile/gql_definitions/jumphosts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
309
309
|
reconcile/gql_definitions/jumphosts/jumphosts.py,sha256=gN595lx7K1XsB2AfxDQ911TBVBbCoxibVeujnsGue_Q,2371
|
310
310
|
reconcile/gql_definitions/ldap_groups/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
311
|
-
reconcile/gql_definitions/ldap_groups/roles.py,sha256=
|
311
|
+
reconcile/gql_definitions/ldap_groups/roles.py,sha256=goGDnkBBFy0mdLsXqL9qlSLPCFd9rwiD1rrsIH-6nZQ,2888
|
312
312
|
reconcile/gql_definitions/ldap_groups/settings.py,sha256=KR6eKqXQWVYZAUEdatL1RCARaTOWl9X-QmxEMVjVNDE,2227
|
313
313
|
reconcile/gql_definitions/membershipsources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
314
314
|
reconcile/gql_definitions/membershipsources/roles.py,sha256=d3nv3GLsj_eKgwB1glsiK6smpC4i16WO3dU5rIdRg94,3678
|
@@ -377,7 +377,7 @@ reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_c
|
|
377
377
|
reconcile/jenkins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
378
378
|
reconcile/jenkins/types.py,sha256=0UlyJxv3KY1WXHkfI_ghUI6FAwRJTL4EwvLg-62tNcg,3001
|
379
379
|
reconcile/ldap_groups/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
380
|
-
reconcile/ldap_groups/integration.py,sha256=
|
380
|
+
reconcile/ldap_groups/integration.py,sha256=Jj4jWp1aypkoweVNQj7QzMtFKQIWeaunLtXZ8KyKOHE,10670
|
381
381
|
reconcile/ocm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
382
382
|
reconcile/ocm/types.py,sha256=ibJYvzfAZyyMFkcF1bP8u3rkXciYJRplt_7Z1pKHFh0,2484
|
383
383
|
reconcile/ocm_internal_notifications/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -407,10 +407,10 @@ reconcile/rhidp/sso_client/integration.py,sha256=kA8g7c38ZBSdrRtyfEqy_WgSreD1Pbw
|
|
407
407
|
reconcile/rhidp/sso_client/metrics.py,sha256=Tq7tSOsqL3XdcPUdozxqzSPIodUeOV87UCTqpuuqqhw,1013
|
408
408
|
reconcile/saas_auto_promotions_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
409
409
|
reconcile/saas_auto_promotions_manager/integration.py,sha256=shWQ--FWfeh_1rHJUwOWDiZWnvzKxYJYuRUIGQv22RI,6759
|
410
|
-
reconcile/saas_auto_promotions_manager/meta.py,sha256=
|
410
|
+
reconcile/saas_auto_promotions_manager/meta.py,sha256=jzqK6qM2JDdCE5kzkcj1e1TBMAL9f6lM2Hse8yFb8W8,161
|
411
411
|
reconcile/saas_auto_promotions_manager/publisher.py,sha256=psrthZGgCQDUO3rwQjKSBMlwcTgfij6sxdebGuxkNv4,2739
|
412
412
|
reconcile/saas_auto_promotions_manager/s3_exporter.py,sha256=IKlVWZmiPnvl7sKeF6JgAlhXZe5CovKTxQc0SNkNSx4,2583
|
413
|
-
reconcile/saas_auto_promotions_manager/subscriber.py,sha256=
|
413
|
+
reconcile/saas_auto_promotions_manager/subscriber.py,sha256=NPhlagNF8om7ikrjRlYNSQ2Ra7wgW_3-OlEWapnjtW0,9405
|
414
414
|
reconcile/saas_auto_promotions_manager/merge_request_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
415
415
|
reconcile/saas_auto_promotions_manager/merge_request_manager/desired_state.py,sha256=jgfgKv4UTYFxtDao_JwNEGEKmu4GpeMm5vbaat0289c,1225
|
416
416
|
reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request.py,sha256=BeAJWLow7b4HQyZ9zz398sQkPeIz8chpMkCts2NU27c,1282
|
@@ -420,7 +420,7 @@ reconcile/saas_auto_promotions_manager/merge_request_manager/mr_parser.py,sha256
|
|
420
420
|
reconcile/saas_auto_promotions_manager/merge_request_manager/reconciler.py,sha256=KZVAkFJR75Qu7-feV4mzg1S8ua-pkbuu1oC7PebSpDs,7801
|
421
421
|
reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py,sha256=iu0wMyyEvro5r5SBJVN3HGmVSIcxTyLN0Xxx3mhbYXE,7066
|
422
422
|
reconcile/saas_auto_promotions_manager/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
423
|
-
reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py,sha256=
|
423
|
+
reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py,sha256=7LlTQCzYotWCbtYBaNQP81CFlLUOvsyGMBQE-Ha0cKY,7820
|
424
424
|
reconcile/skupper_network/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
425
425
|
reconcile/skupper_network/integration.py,sha256=178Q9RSYuZ9NmrCK4jRMLMekrewUaaRdclccI6zBsQ8,10786
|
426
426
|
reconcile/skupper_network/models.py,sha256=DNTI7HZv-rqY42GIIxyRuvroHLvdH6rJerjIq9lj3RU,6663
|
@@ -534,38 +534,23 @@ reconcile/test/test_version_bump.py,sha256=q6-3Y1roriI6YWpFwaHOMN7emEP3yL33sh_0V
|
|
534
534
|
reconcile/test/test_vpc_peerings_validator.py,sha256=dFSmjc_dMN2GqMbntCFpa7PUZmyYuQ9DKffh-T5wmxM,6639
|
535
535
|
reconcile/test/test_wrong_region.py,sha256=7KzL7OaICQ9Z3DW27zt_ykMN7_87owAFC-2CYjvGoyA,2138
|
536
536
|
reconcile/test/saas_auto_promotions_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
537
|
-
reconcile/test/saas_auto_promotions_manager/conftest.py,sha256=
|
537
|
+
reconcile/test/saas_auto_promotions_manager/conftest.py,sha256=4BtuxVZ0Lsmdp6AhG8kbtowkwG7e-pSjIKv35Wm1hI0,5803
|
538
538
|
reconcile/test/saas_auto_promotions_manager/test_integration_test.py,sha256=x7QgHDMKIoPRY8k2SRSWa7qY3Z5Vabsyh9xWCtMXtfY,1857
|
539
539
|
reconcile/test/saas_auto_promotions_manager/merge_request_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
540
540
|
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
541
|
-
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py,sha256=
|
541
|
+
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py,sha256=HikuDsdDxJ6HW48WY50s_7fmeGr07kcRdBZxgHzwc-0,3514
|
542
542
|
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/data_keys.py,sha256=Z1IV51OUuzhd-3S8W-k7ixC-fkaglCokn0eakK0Z73s,606
|
543
|
-
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_desired_state.py,sha256=
|
543
|
+
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_desired_state.py,sha256=OLtJ11SsznoT39_tudsozcksK0N3TVNv-JWhIrCVaQk,2356
|
544
544
|
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_merge_request_manager.py,sha256=h8lnorFPZIxTtbaaXGLoiEsBbB4Qj-Mg9BKV62ZqEBQ,2389
|
545
545
|
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_mr_parser.py,sha256=dcGHzxuafKSxmswSO1qF2WlKaqsmEvtERC6Lb8kDAN0,10019
|
546
546
|
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_reconciler.py,sha256=_bzfJzjFJgubu--7wyXIiusUrdbmLtFbHmkbat4SX_M,17828
|
547
547
|
reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
548
|
-
reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py,sha256=
|
549
|
-
reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/
|
550
|
-
reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/
|
551
|
-
reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/
|
552
|
-
reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/
|
553
|
-
reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_json_path_selector.py,sha256=k_jA4x_9fRGGAT1T0aeAFiZwZ7zlDZpPPgqMDeuR7y8,2189
|
554
|
-
reconcile/test/saas_auto_promotions_manager/subscriber/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
555
|
-
reconcile/test/saas_auto_promotions_manager/subscriber/conftest.py,sha256=5hMe91UEp_GQm49OeTee4ALv_xq2KhWwF6NfzzQwpnc,3101
|
556
|
-
reconcile/test/saas_auto_promotions_manager/subscriber/data_keys.py,sha256=2j4Ue-njmK53Xm4vJScT2MJJeKV7wk9xf_95pmNfLWE,402
|
557
|
-
reconcile/test/saas_auto_promotions_manager/subscriber/test_content_hash.py,sha256=viw-p42vDOC2telE5lelssRBL7V35aNJ1qUg6D-QGWw,4546
|
558
|
-
reconcile/test/saas_auto_promotions_manager/subscriber/test_diff.py,sha256=BkxCoWBlUahY5Vq36FX_t_UyIdzIc64CumzAd3imUAQ,4529
|
559
|
-
reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_channels_config_hash.py,sha256=0MeFuJnKUHdMXGe8v2Fzge1mhihTcKqr2OAMLEAyHP4,6439
|
560
|
-
reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_channels_moving_ref.py,sha256=rcF2tHltCsZiPQo23b-xjBuEqBHzVn4TMzHv_x0778o,6209
|
561
|
-
reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_publishers_moving_ref.py,sha256=tGAjetYspWeevuuUCfbeU33noM-dP4lsb96UUAHkxWw,3588
|
562
|
-
reconcile/test/saas_auto_promotions_manager/subscriber/test_single_channel_with_single_publisher.py,sha256=YDXCzrclRyKRW7qRBg9GB2HinJP_HPqzTcWMGD1rbFI,9452
|
548
|
+
reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py,sha256=MjTLg7KwvdIYvxkCzgJG-gByD1fZxaq6c4SI6rWWUu8,552
|
549
|
+
reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_multiple_namespaces.py,sha256=6LMsnbPx5svTF1nL6oQGLTp1NgjLG_tO56c0hbA2Di4,1059
|
550
|
+
reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_namespace.py,sha256=dc7vMOiVLl5yRUEfjF4eE7HfMZTbtT2dz1CMGJVLUZA,2526
|
551
|
+
reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_target.py,sha256=FY9pzmvE8uXvvt_P_G3M7_br8Zt1s428H23FlAj9nuY,1881
|
552
|
+
reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_json_path_selector.py,sha256=jCtG0hVCqJ-A4XBjwexDww5LQUXJFRc44O5rEMA7_7E,2160
|
563
553
|
reconcile/test/saas_auto_promotions_manager/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
564
|
-
reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
565
|
-
reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_multiple_publishers_for_single_channel.py,sha256=jX8ade2615gRYiJ_Bui4F2kvv3rUyod5sdiMFhzcnsw,2168
|
566
|
-
reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_use_target_config_hash.py,sha256=TThr7UeF8k7lNBeknknEcE4H9z-_K4jKdzNA_SqFKoY,1948
|
567
|
-
reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_with_auto_promote.py,sha256=OSSdVEQ72npDRrbkx5JHhXus-0ku699wG7ecsco4axM,2545
|
568
|
-
reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_without_auto_promote.py,sha256=6GoZ6ogpXBVYlRwag2wu9Z-1ES9LzyPxMqZkcX7oTA0,2040
|
569
554
|
reconcile/typed_queries/__init__.py,sha256=rRk4CyslLsBr4vAh1pIPgt6s3P4R1M9NSEPLnyQgBpk,61
|
570
555
|
reconcile/typed_queries/alerting_services_settings.py,sha256=sX6s8GY-BB0UHogMC1ICeREVab-IYrNm1c-hqMGEdYQ,864
|
571
556
|
reconcile/typed_queries/app_interface_custom_messages.py,sha256=5HWr68_kb4bEL8pDCIH0ez6GOrdwdbGF6w88xV0_Ccs,718
|
@@ -707,7 +692,7 @@ reconcile/utils/glitchtip/client.py,sha256=KHUNjN8r2J67RxROIpjzs5cKsqbwjzsM_I1TA
|
|
707
692
|
reconcile/utils/glitchtip/models.py,sha256=_oqZXNkyRTsAnx6tF4WUURSBj0cc9UNS4okOQYfAfB4,6435
|
708
693
|
reconcile/utils/internal_groups/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
709
694
|
reconcile/utils/internal_groups/client.py,sha256=abREA8RwXKybXFjCK8CAcCr-iUp2r0tAbIEJ-c-PXws,4538
|
710
|
-
reconcile/utils/internal_groups/models.py,sha256=
|
695
|
+
reconcile/utils/internal_groups/models.py,sha256=GSkF6fVcdbl774q51ZFUmNfSJPta03OcV67MgsuBR2E,2326
|
711
696
|
reconcile/utils/jinja2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
712
697
|
reconcile/utils/jinja2/extensions.py,sha256=zV_x8MhSHAynKhFnG3fULXrwsm5fUG_88IygZHSnN0o,1284
|
713
698
|
reconcile/utils/jinja2/filters.py,sha256=_kJjdMsY3lGS5PUn4NnpXUQDNrL1IwiKsB-0MhTMGYM,4521
|
@@ -797,8 +782,8 @@ tools/test/test_app_interface_metrics_exporter.py,sha256=SX7qL3D1SIRKFo95FoQztvf
|
|
797
782
|
tools/test/test_qontract_cli.py,sha256=w2l4BHB09k1d-BGJ1jBUNCqDv7zkqYrMHojQXg-21kQ,4155
|
798
783
|
tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
|
799
784
|
tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
|
800
|
-
qontract_reconcile-0.10.
|
801
|
-
qontract_reconcile-0.10.
|
802
|
-
qontract_reconcile-0.10.
|
803
|
-
qontract_reconcile-0.10.
|
804
|
-
qontract_reconcile-0.10.
|
785
|
+
qontract_reconcile-0.10.1rc766.dist-info/METADATA,sha256=tFpqi2YNRp9SyjmZicHUP7W6onmCER5zHM7Y-fD6qa0,2382
|
786
|
+
qontract_reconcile-0.10.1rc766.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
787
|
+
qontract_reconcile-0.10.1rc766.dist-info/entry_points.txt,sha256=rIxI5zWtHNlfpDeq1a7pZXAPoqf7HG32KMTN3MeWK_8,429
|
788
|
+
qontract_reconcile-0.10.1rc766.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
|
789
|
+
qontract_reconcile-0.10.1rc766.dist-info/RECORD,,
|
@@ -33,7 +33,11 @@ fragment AWSAccountSSO on AWSAccount_v1 {
|
|
33
33
|
query LdapGroupsRolesQuery {
|
34
34
|
roles: roles_v1 {
|
35
35
|
name
|
36
|
-
ldapGroup
|
36
|
+
ldapGroup {
|
37
|
+
name
|
38
|
+
notes
|
39
|
+
membersAreOwners
|
40
|
+
}
|
37
41
|
users {
|
38
42
|
org_username
|
39
43
|
}
|
@@ -58,6 +62,12 @@ class ConfiguredBaseModel(BaseModel):
|
|
58
62
|
extra=Extra.forbid
|
59
63
|
|
60
64
|
|
65
|
+
class LdapGroupV1(ConfiguredBaseModel):
|
66
|
+
name: str = Field(..., alias="name")
|
67
|
+
notes: Optional[str] = Field(..., alias="notes")
|
68
|
+
members_are_owners: Optional[bool] = Field(..., alias="membersAreOwners")
|
69
|
+
|
70
|
+
|
61
71
|
class UserV1(ConfiguredBaseModel):
|
62
72
|
org_username: str = Field(..., alias="org_username")
|
63
73
|
|
@@ -72,7 +82,7 @@ class AWSGroupV1(ConfiguredBaseModel):
|
|
72
82
|
|
73
83
|
class RoleV1(ConfiguredBaseModel):
|
74
84
|
name: str = Field(..., alias="name")
|
75
|
-
ldap_group: Optional[
|
85
|
+
ldap_group: Optional[LdapGroupV1] = Field(..., alias="ldapGroup")
|
76
86
|
users: list[UserV1] = Field(..., alias="users")
|
77
87
|
user_policies: Optional[list[AWSUserPolicyV1]] = Field(..., alias="user_policies")
|
78
88
|
aws_groups: Optional[list[AWSGroupV1]] = Field(..., alias="aws_groups")
|
@@ -93,12 +93,12 @@ class LdapGroupsIntegration(QontractReconcileIntegration[LdapGroupsIntegrationPa
|
|
93
93
|
desired_groups_for_roles = self.get_desired_groups_for_roles(
|
94
94
|
roles,
|
95
95
|
contact_list=self.settings.contact_list,
|
96
|
-
|
96
|
+
default_owners=[owner],
|
97
97
|
)
|
98
98
|
desired_groups_for_aws_roles = self.get_desired_groups_for_aws_roles(
|
99
99
|
roles,
|
100
100
|
contact_list=self.settings.contact_list,
|
101
|
-
|
101
|
+
default_owners=[owner],
|
102
102
|
)
|
103
103
|
desired_groups = desired_groups_for_roles + desired_groups_for_aws_roles
|
104
104
|
|
@@ -147,7 +147,7 @@ class LdapGroupsIntegration(QontractReconcileIntegration[LdapGroupsIntegrationPa
|
|
147
147
|
data = roles_query(query_func, variables={})
|
148
148
|
roles = [role for role in data.roles or []]
|
149
149
|
if duplicates := find_duplicates(
|
150
|
-
role.ldap_group for role in roles if role.ldap_group
|
150
|
+
role.ldap_group.name for role in roles if role.ldap_group
|
151
151
|
):
|
152
152
|
for dup in duplicates:
|
153
153
|
logging.error(f"{dup} is already in use by another role.")
|
@@ -155,30 +155,39 @@ class LdapGroupsIntegration(QontractReconcileIntegration[LdapGroupsIntegrationPa
|
|
155
155
|
return roles
|
156
156
|
|
157
157
|
def get_desired_groups_for_roles(
|
158
|
-
self,
|
158
|
+
self,
|
159
|
+
roles: Iterable[RoleV1],
|
160
|
+
default_owners: list[Entity],
|
161
|
+
contact_list: str,
|
159
162
|
) -> list[Group]:
|
160
163
|
"""Return the desired rover groups for the given roles."""
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
164
|
+
groups = []
|
165
|
+
for role in roles:
|
166
|
+
if not role.ldap_group:
|
167
|
+
continue
|
168
|
+
members = [
|
169
|
+
Entity(type=EntityType.USER, id=user.org_username)
|
170
|
+
for user in role.users
|
171
|
+
]
|
172
|
+
groups.append(
|
173
|
+
Group(
|
174
|
+
name=role.ldap_group.name,
|
175
|
+
description="Persisted App-Interface role. Managed by qontract-reconcile",
|
176
|
+
notes=role.ldap_group.notes,
|
177
|
+
display_name=f"{role.ldap_group.name} (App-Interface))",
|
178
|
+
members=members,
|
179
|
+
owners=default_owners
|
180
|
+
if not role.ldap_group.members_are_owners
|
181
|
+
else default_owners + members,
|
182
|
+
contact_list=contact_list,
|
183
|
+
)
|
173
184
|
)
|
174
|
-
|
175
|
-
if role.ldap_group
|
176
|
-
]
|
185
|
+
return groups
|
177
186
|
|
178
187
|
def get_desired_groups_for_aws_roles(
|
179
188
|
self,
|
180
189
|
roles: Iterable[RoleV1],
|
181
|
-
|
190
|
+
default_owners: Iterable[Entity],
|
182
191
|
contact_list: str,
|
183
192
|
) -> list[Group]:
|
184
193
|
"""Return the desired rover groups for all AWS roles."""
|
@@ -205,7 +214,7 @@ class LdapGroupsIntegration(QontractReconcileIntegration[LdapGroupsIntegrationPa
|
|
205
214
|
for user in role.users
|
206
215
|
],
|
207
216
|
# only owners can modify the group (e.g. add/remove members)
|
208
|
-
owners=
|
217
|
+
owners=default_owners,
|
209
218
|
contact_list=contact_list,
|
210
219
|
)
|
211
220
|
)
|
@@ -246,7 +255,9 @@ class LdapGroupsIntegration(QontractReconcileIntegration[LdapGroupsIntegrationPa
|
|
246
255
|
logging.info([
|
247
256
|
"create_ldap_group",
|
248
257
|
group_to_add.name,
|
249
|
-
f"
|
258
|
+
f"members={', '.join(u.id for u in group_to_add.members)}",
|
259
|
+
f"owners={', '.join(u.id for u in group_to_add.owners)}",
|
260
|
+
f"notes={group_to_add.notes}",
|
250
261
|
])
|
251
262
|
if not dry_run:
|
252
263
|
internal_groups_client.create_group(group_to_add)
|
@@ -266,7 +277,9 @@ class LdapGroupsIntegration(QontractReconcileIntegration[LdapGroupsIntegrationPa
|
|
266
277
|
logging.info([
|
267
278
|
"update_ldap_group",
|
268
279
|
group_to_update.name,
|
269
|
-
f"
|
280
|
+
f"members={', '.join(u.id for u in group_to_update.members)}",
|
281
|
+
f"owners={', '.join(u.id for u in group_to_update.owners)}",
|
282
|
+
f"notes={group_to_update.notes}",
|
270
283
|
])
|
271
284
|
if not dry_run:
|
272
285
|
internal_groups_client.update_group(group_to_update)
|
@@ -1,8 +1,8 @@
|
|
1
1
|
import hashlib
|
2
2
|
import logging
|
3
|
-
from collections.abc import Iterable
|
3
|
+
from collections.abc import Iterable, Mapping
|
4
4
|
from dataclasses import dataclass
|
5
|
-
from typing import Optional
|
5
|
+
from typing import Any, Optional
|
6
6
|
|
7
7
|
from reconcile.gql_definitions.fragments.saas_target_namespace import (
|
8
8
|
SaasTargetNamespace,
|
@@ -42,6 +42,7 @@ class Subscriber:
|
|
42
42
|
target_file_path: str,
|
43
43
|
target_namespace: SaasTargetNamespace,
|
44
44
|
use_target_config_hash: bool,
|
45
|
+
uid: str,
|
45
46
|
):
|
46
47
|
self.saas_name = saas_name
|
47
48
|
self.template_name = template_name
|
@@ -52,6 +53,7 @@ class Subscriber:
|
|
52
53
|
self.desired_ref = ""
|
53
54
|
self.desired_hashes: list[ConfigHash] = []
|
54
55
|
self.target_namespace = target_namespace
|
56
|
+
self.uid = uid
|
55
57
|
self._content_hash = ""
|
56
58
|
self._use_target_config_hash = use_target_config_hash
|
57
59
|
|
@@ -73,6 +75,54 @@ class Subscriber:
|
|
73
75
|
self._compute_desired_ref()
|
74
76
|
self._compute_desired_config_hashes()
|
75
77
|
|
78
|
+
@staticmethod
|
79
|
+
def from_exported_dict(data: Mapping[str, Any]) -> "Subscriber":
|
80
|
+
subscriber = Subscriber(
|
81
|
+
saas_name=data["1"],
|
82
|
+
template_name=data["2"],
|
83
|
+
ref=data["3"],
|
84
|
+
target_file_path=data["4"],
|
85
|
+
use_target_config_hash=data["5"],
|
86
|
+
target_namespace=SaasTargetNamespace(**data["6"]),
|
87
|
+
uid=data["7"],
|
88
|
+
)
|
89
|
+
subscriber.desired_hashes = data["8"]
|
90
|
+
subscriber.desired_ref = data["9"]
|
91
|
+
return subscriber
|
92
|
+
|
93
|
+
def to_exportable_dict(self) -> dict[str, Any]:
|
94
|
+
"""
|
95
|
+
We will later persist subscriber data as json in MRs. We keep key size small to use less space.
|
96
|
+
Note, the data will be encoded and encrypted in another component.
|
97
|
+
"""
|
98
|
+
data: dict[str, Any] = {}
|
99
|
+
data["1"] = self.saas_name
|
100
|
+
data["2"] = self.template_name
|
101
|
+
data["3"] = self.ref
|
102
|
+
data["4"] = self.target_file_path
|
103
|
+
data["5"] = self._use_target_config_hash
|
104
|
+
data["6"] = self.target_namespace.dict(by_alias=True)
|
105
|
+
data["7"] = self.uid
|
106
|
+
data["8"] = self.desired_hashes
|
107
|
+
data["9"] = self.desired_ref
|
108
|
+
return data
|
109
|
+
|
110
|
+
def __eq__(self, other: object) -> bool:
|
111
|
+
if not isinstance(other, Subscriber):
|
112
|
+
# don't attempt to compare against unrelated types
|
113
|
+
return False
|
114
|
+
return (
|
115
|
+
self.saas_name == other.saas_name
|
116
|
+
and self.template_name == other.template_name
|
117
|
+
and self.ref == other.ref
|
118
|
+
and self.target_file_path == other.target_file_path
|
119
|
+
and self._use_target_config_hash == other._use_target_config_hash
|
120
|
+
and self.desired_ref == other.desired_ref
|
121
|
+
and self.desired_hashes == other.desired_hashes
|
122
|
+
and self.target_namespace == other.target_namespace
|
123
|
+
and self.uid == other.uid
|
124
|
+
)
|
125
|
+
|
76
126
|
def _validate_deployment(
|
77
127
|
self, publisher: Publisher, channel: Channel
|
78
128
|
) -> Optional[DeploymentInfo]:
|
@@ -92,6 +92,10 @@ class SaasFilesInventory:
|
|
92
92
|
if not target.promotion.auto:
|
93
93
|
continue
|
94
94
|
subscriber = Subscriber(
|
95
|
+
uid=target.uid(
|
96
|
+
parent_saas_file_name=saas_file.name,
|
97
|
+
parent_resource_template_name=resource_template.name,
|
98
|
+
),
|
95
99
|
saas_name=saas_file.name,
|
96
100
|
template_name=resource_template.name,
|
97
101
|
target_file_path=file_path,
|
@@ -1,9 +1,11 @@
|
|
1
|
+
from collections import defaultdict
|
1
2
|
from collections.abc import (
|
2
3
|
Callable,
|
3
4
|
Iterable,
|
4
5
|
Mapping,
|
5
6
|
MutableMapping,
|
6
7
|
)
|
8
|
+
from typing import Any
|
7
9
|
from unittest.mock import (
|
8
10
|
MagicMock,
|
9
11
|
create_autospec,
|
@@ -14,6 +16,12 @@ import pytest
|
|
14
16
|
from reconcile.gql_definitions.fragments.saas_target_namespace import (
|
15
17
|
SaasTargetNamespace,
|
16
18
|
)
|
19
|
+
from reconcile.saas_auto_promotions_manager.publisher import DeploymentInfo, Publisher
|
20
|
+
from reconcile.saas_auto_promotions_manager.subscriber import (
|
21
|
+
Channel,
|
22
|
+
ConfigHash,
|
23
|
+
Subscriber,
|
24
|
+
)
|
17
25
|
from reconcile.typed_queries.saas_files import SaasFile
|
18
26
|
from reconcile.utils.gitlab_api import GitLabApi
|
19
27
|
from reconcile.utils.promotion_state import (
|
@@ -100,3 +108,58 @@ def promotion_state_builder() -> Callable[..., PromotionState]:
|
|
100
108
|
return promotion_state
|
101
109
|
|
102
110
|
return builder
|
111
|
+
|
112
|
+
|
113
|
+
@pytest.fixture
|
114
|
+
def subscriber_builder(
|
115
|
+
saas_target_namespace_builder: Callable[..., SaasTargetNamespace],
|
116
|
+
) -> Callable[[Mapping[str, Any]], Subscriber]:
|
117
|
+
def builder(data: Mapping[str, Any]) -> Subscriber:
|
118
|
+
channels: list[Channel] = []
|
119
|
+
for channel_name, channel_data in data.get("CHANNELS", {}).items():
|
120
|
+
channel = Channel(name=channel_name, publishers=[])
|
121
|
+
for publisher_name, publisher_data in channel_data.items():
|
122
|
+
publisher = Publisher(
|
123
|
+
ref="",
|
124
|
+
uid="",
|
125
|
+
repo_url="",
|
126
|
+
cluster_name="",
|
127
|
+
namespace_name="",
|
128
|
+
saas_name="",
|
129
|
+
saas_file_path="",
|
130
|
+
app_name="",
|
131
|
+
resource_template_name="",
|
132
|
+
target_name=None,
|
133
|
+
publish_job_logs=True,
|
134
|
+
has_subscriber=True,
|
135
|
+
auth_code=None,
|
136
|
+
)
|
137
|
+
publisher.commit_sha = publisher_data["REAL_WORLD_SHA"]
|
138
|
+
publisher.deployment_info_by_channel[channel_name] = DeploymentInfo(
|
139
|
+
success=publisher_data.get("SUCCESSFUL_DEPLOYMENT", True),
|
140
|
+
target_config_hash=publisher_data.get("CONFIG_HASH", ""),
|
141
|
+
saas_file=publisher_name,
|
142
|
+
)
|
143
|
+
channel.publishers.append(publisher)
|
144
|
+
channels.append(channel)
|
145
|
+
cur_config_hashes_by_channel: dict[str, list[ConfigHash]] = defaultdict(list)
|
146
|
+
for cur_config_hash in data.get("CUR_CONFIG_HASHES", []):
|
147
|
+
cur_config_hashes_by_channel[cur_config_hash.channel].append(
|
148
|
+
cur_config_hash
|
149
|
+
)
|
150
|
+
subscriber = Subscriber(
|
151
|
+
uid=data.get("SUB_UID", "default"),
|
152
|
+
target_namespace=saas_target_namespace_builder(data.get("NAMESPACE", {})),
|
153
|
+
ref=data.get("CUR_SUBSCRIBER_REF", ""),
|
154
|
+
saas_name="",
|
155
|
+
target_file_path=data.get("TARGET_FILE_PATH", ""),
|
156
|
+
template_name="",
|
157
|
+
use_target_config_hash=data.get("USE_TARGET_CONFIG_HASH", True),
|
158
|
+
)
|
159
|
+
subscriber.channels = channels
|
160
|
+
subscriber.config_hashes_by_channel_name = cur_config_hashes_by_channel
|
161
|
+
subscriber.desired_ref = data.get("DESIRED_REF", "")
|
162
|
+
subscriber.desired_hashes = data.get("DESIRED_TARGET_HASHES", [])
|
163
|
+
return subscriber
|
164
|
+
|
165
|
+
return builder
|
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py
CHANGED
@@ -8,9 +8,6 @@ from unittest.mock import create_autospec
|
|
8
8
|
import pytest
|
9
9
|
from gitlab.v4.objects import ProjectMergeRequest
|
10
10
|
|
11
|
-
from reconcile.gql_definitions.fragments.saas_target_namespace import (
|
12
|
-
SaasTargetNamespace,
|
13
|
-
)
|
14
11
|
from reconcile.saas_auto_promotions_manager.merge_request_manager.merge_request_manager_v2 import (
|
15
12
|
SAPM_LABEL,
|
16
13
|
)
|
@@ -31,24 +28,17 @@ from reconcile.saas_auto_promotions_manager.merge_request_manager.renderer impor
|
|
31
28
|
VERSION_REF,
|
32
29
|
Renderer,
|
33
30
|
)
|
34
|
-
from reconcile.saas_auto_promotions_manager.subscriber import (
|
35
|
-
Channel,
|
36
|
-
Subscriber,
|
37
|
-
)
|
38
31
|
from reconcile.utils.vcs import VCS, MRCheckStatus
|
39
32
|
|
40
33
|
from .data_keys import (
|
41
|
-
CHANNEL,
|
42
34
|
DESCRIPTION,
|
43
35
|
HAS_CONFLICTS,
|
44
36
|
LABELS,
|
45
37
|
OPEN_MERGE_REQUESTS,
|
46
38
|
PIPELINE_RESULTS,
|
47
|
-
REF,
|
48
39
|
SUBSCRIBER_BATCHABLE,
|
49
40
|
SUBSCRIBER_CHANNELS,
|
50
41
|
SUBSCRIBER_CONTENT_HASH,
|
51
|
-
SUBSCRIBER_TARGET_PATH,
|
52
42
|
)
|
53
43
|
|
54
44
|
|
@@ -120,33 +110,6 @@ def reconciler_builder() -> Callable[[Diff], Reconciler]:
|
|
120
110
|
return builder
|
121
111
|
|
122
112
|
|
123
|
-
@pytest.fixture
|
124
|
-
def subscriber_builder(
|
125
|
-
saas_target_namespace_builder: Callable[..., SaasTargetNamespace],
|
126
|
-
) -> Callable[..., Subscriber]:
|
127
|
-
def builder(data: Mapping) -> Subscriber:
|
128
|
-
subscriber = Subscriber(
|
129
|
-
saas_name="",
|
130
|
-
template_name="",
|
131
|
-
target_namespace=saas_target_namespace_builder({}),
|
132
|
-
ref="",
|
133
|
-
target_file_path=data.get(SUBSCRIBER_TARGET_PATH, ""),
|
134
|
-
use_target_config_hash=True,
|
135
|
-
)
|
136
|
-
subscriber.desired_hashes = []
|
137
|
-
subscriber.desired_ref = data.get(REF, "")
|
138
|
-
for channel in data.get(CHANNEL, []):
|
139
|
-
subscriber.channels.append(
|
140
|
-
Channel(
|
141
|
-
name=channel,
|
142
|
-
publishers=[],
|
143
|
-
)
|
144
|
-
)
|
145
|
-
return subscriber
|
146
|
-
|
147
|
-
return builder
|
148
|
-
|
149
|
-
|
150
113
|
@pytest.fixture
|
151
114
|
def renderer() -> Renderer:
|
152
115
|
return create_autospec(spec=Renderer)
|
@@ -5,10 +5,6 @@ from reconcile.saas_auto_promotions_manager.merge_request_manager.desired_state
|
|
5
5
|
)
|
6
6
|
from reconcile.saas_auto_promotions_manager.subscriber import Subscriber
|
7
7
|
|
8
|
-
from .data_keys import (
|
9
|
-
CHANNEL,
|
10
|
-
)
|
11
|
-
|
12
8
|
|
13
9
|
def test_desired_state_empty() -> None:
|
14
10
|
desired_state = DesiredState(subscribers=[])
|
@@ -29,10 +25,14 @@ def test_desired_state_single_subscriber(
|
|
29
25
|
def test_desired_state_multiple_subscribers_same_channel_combo(
|
30
26
|
subscriber_builder: Callable[..., Subscriber],
|
31
27
|
) -> None:
|
32
|
-
subscriber_a = subscriber_builder({
|
33
|
-
|
34
|
-
|
35
|
-
|
28
|
+
subscriber_a = subscriber_builder({
|
29
|
+
"CHANNELS": {"channel-a": {}, "channel-b": {}},
|
30
|
+
"DESIRED_REF": "ref-a",
|
31
|
+
})
|
32
|
+
subscriber_b = subscriber_builder({
|
33
|
+
"CHANNELS": {"channel-a": {}, "channel-b": {}},
|
34
|
+
"DESIRED_REF": "ref-b",
|
35
|
+
})
|
36
36
|
desired_state = DesiredState(subscribers=[subscriber_a, subscriber_b])
|
37
37
|
assert len(desired_state.promotions) == 1
|
38
38
|
assert desired_state.promotions[0].content_hashes == {
|
@@ -43,12 +43,18 @@ def test_desired_state_multiple_subscribers_same_channel_combo(
|
|
43
43
|
def test_desired_state_multiple_subscribers_different_channel_combo(
|
44
44
|
subscriber_builder: Callable[..., Subscriber],
|
45
45
|
) -> None:
|
46
|
-
subscriber_a = subscriber_builder({
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
46
|
+
subscriber_a = subscriber_builder({
|
47
|
+
"CHANNELS": {"channel-a": {}, "channel-b": {}},
|
48
|
+
"DESIRED_REF": "ref-a",
|
49
|
+
})
|
50
|
+
subscriber_b = subscriber_builder({
|
51
|
+
"CHANNELS": {"channel-a": {}, "channel-b": {}},
|
52
|
+
"DESIRED_REF": "ref-b",
|
53
|
+
})
|
54
|
+
subscriber_c = subscriber_builder({
|
55
|
+
"CHANNELS": {"channel-b": {}, "channel-c": {}},
|
56
|
+
"DESIRED_REF": "ref-c",
|
57
|
+
})
|
52
58
|
desired_state = DesiredState(subscribers=[subscriber_a, subscriber_b, subscriber_c])
|
53
59
|
sorted_promotions = sorted(desired_state.promotions)
|
54
60
|
assert len(desired_state.promotions) == 2
|
@@ -1,26 +1,10 @@
|
|
1
1
|
import os
|
2
2
|
from collections.abc import (
|
3
3
|
Callable,
|
4
|
-
Mapping,
|
5
4
|
)
|
6
5
|
|
7
6
|
import pytest
|
8
7
|
|
9
|
-
from reconcile.gql_definitions.fragments.saas_target_namespace import (
|
10
|
-
SaasTargetNamespace,
|
11
|
-
)
|
12
|
-
from reconcile.saas_auto_promotions_manager.subscriber import (
|
13
|
-
Channel,
|
14
|
-
Subscriber,
|
15
|
-
)
|
16
|
-
|
17
|
-
from .data_keys import (
|
18
|
-
CHANNELS,
|
19
|
-
CONFIG_HASHES,
|
20
|
-
NAMESPACE,
|
21
|
-
REF,
|
22
|
-
)
|
23
|
-
|
24
8
|
|
25
9
|
@pytest.fixture
|
26
10
|
def file_contents() -> Callable[[str], tuple[str, str]]:
|
@@ -39,30 +23,3 @@ def file_contents() -> Callable[[str], tuple[str, str]]:
|
|
39
23
|
return (a, b)
|
40
24
|
|
41
25
|
return contents
|
42
|
-
|
43
|
-
|
44
|
-
@pytest.fixture
|
45
|
-
def subscriber_builder(
|
46
|
-
saas_target_namespace_builder: Callable[..., SaasTargetNamespace],
|
47
|
-
) -> Callable[[Mapping], Subscriber]:
|
48
|
-
def builder(data: Mapping) -> Subscriber:
|
49
|
-
subscriber = Subscriber(
|
50
|
-
target_namespace=saas_target_namespace_builder(data.get(NAMESPACE, {})),
|
51
|
-
ref="",
|
52
|
-
saas_name="",
|
53
|
-
target_file_path="",
|
54
|
-
template_name="",
|
55
|
-
use_target_config_hash=True,
|
56
|
-
)
|
57
|
-
subscriber.desired_ref = data[REF]
|
58
|
-
subscriber.desired_hashes = data[CONFIG_HASHES]
|
59
|
-
for channel in data.get(CHANNELS, []):
|
60
|
-
subscriber.channels.append(
|
61
|
-
Channel(
|
62
|
-
name=channel,
|
63
|
-
publishers=[],
|
64
|
-
)
|
65
|
-
)
|
66
|
-
return subscriber
|
67
|
-
|
68
|
-
return builder
|