qontract-reconcile 0.10.1rc536__py3-none-any.whl → 0.10.1rc538__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.1rc536.dist-info → qontract_reconcile-0.10.1rc538.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc536.dist-info → qontract_reconcile-0.10.1rc538.dist-info}/RECORD +19 -18
- reconcile/acs_policies.py +16 -6
- reconcile/cli.py +33 -0
- reconcile/terraform_resources.py +182 -111
- reconcile/test/test_acs_policies.py +26 -11
- reconcile/test/test_terraform_resources.py +242 -12
- reconcile/utils/acs/policies.py +10 -0
- reconcile/utils/early_exit_cache.py +5 -5
- reconcile/utils/extended_early_exit.py +177 -0
- reconcile/utils/external_resources.py +2 -1
- reconcile/utils/metrics.py +7 -0
- reconcile/utils/terraform_client.py +10 -4
- reconcile/utils/terrascript_aws_client.py +11 -3
- tools/qontract_cli.py +17 -17
- tools/test/test_qontract_cli.py +1 -1
- {qontract_reconcile-0.10.1rc536.dist-info → qontract_reconcile-0.10.1rc538.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc536.dist-info → qontract_reconcile-0.10.1rc538.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc536.dist-info → qontract_reconcile-0.10.1rc538.dist-info}/top_level.txt +0 -0
{qontract_reconcile-0.10.1rc536.dist-info → qontract_reconcile-0.10.1rc538.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.1rc538
|
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.1rc536.dist-info → qontract_reconcile-0.10.1rc538.dist-info}/RECORD
RENAMED
@@ -1,5 +1,5 @@
|
|
1
1
|
reconcile/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
reconcile/acs_policies.py,sha256=
|
2
|
+
reconcile/acs_policies.py,sha256=e_kVyP4rGm3fJzq10Anr8scZoPenlmTcoS5REK0d2T0,9144
|
3
3
|
reconcile/acs_rbac.py,sha256=YoKu5wTRTtb3EGT0PV3r279LDgvw2ECb-0_0j4suScg,23032
|
4
4
|
reconcile/aws_ami_share.py,sha256=eeu0TI3M5yyUaozyAq_aW3tir-9be4YFguOXvIvKHSo,3757
|
5
5
|
reconcile/aws_ecr_image_pull_secrets.py,sha256=TGEc_0nv8oxV2HqA8VdcM4HHP-B1YqmNOOU6FPwVFTY,2328
|
@@ -9,7 +9,7 @@ reconcile/aws_iam_password_reset.py,sha256=NwErtrqgBiXr7eGCAHdtGGOx0S7-4JnSc29Ie
|
|
9
9
|
reconcile/aws_support_cases_sos.py,sha256=Jk6_XjDeJSYxgRGqcEAOcynt9qJF2r5HPIPcSKmoBv8,2974
|
10
10
|
reconcile/blackbox_exporter_endpoint_monitoring.py,sha256=W_VJagnsJR1v5oqjlI3RJJE0_nhtJ0m81RS8zWA5u5c,3538
|
11
11
|
reconcile/checkpoint.py,sha256=R2WFXUXLTB4sWMi4GeA4eegsuf_1-Q4vH8M0Toh3Ij4,5036
|
12
|
-
reconcile/cli.py,sha256=
|
12
|
+
reconcile/cli.py,sha256=LFsNTM36MINQ_iDqIpXlJPrUcLUL7BUEE4GpPG2LmaQ,85546
|
13
13
|
reconcile/closedbox_endpoint_monitoring_base.py,sha256=SMhkcQqprWvThrIJa3U_3uh5w1h-alleW1QnCJFY4Qw,4909
|
14
14
|
reconcile/cluster_deployment_mapper.py,sha256=2Ah-nu-Mdig0pjuiZl_XLrmVAjYzFjORR3dMlCgkmw0,2352
|
15
15
|
reconcile/dashdotdb_base.py,sha256=a5aPLVxyqPSbjdB0Ty-uliOtxwvEbbEljHJKxdK3-Zk,4813
|
@@ -111,7 +111,7 @@ reconcile/terraform_cloudflare_dns.py,sha256=auU4bzeLwd4S8D8oqpqJbrCUoEdELXrgi7v
|
|
111
111
|
reconcile/terraform_cloudflare_resources.py,sha256=EbQQaoDnZ7brvRCpbFtwlD7KLk2hDVNcjhrJGaAywEk,15023
|
112
112
|
reconcile/terraform_cloudflare_users.py,sha256=1EbTHwJgiPkJpMP-Ag340QNgGK3mXn3dcC3DpLakudM,13987
|
113
113
|
reconcile/terraform_repo.py,sha256=c0GZFuY3rCm6VHjHqYbsgOHrEkRWKF_1LrMThsn2XDw,16127
|
114
|
-
reconcile/terraform_resources.py,sha256=
|
114
|
+
reconcile/terraform_resources.py,sha256=3-q0WyCzBbfgvfDjCEKGp09bNGgxtbzUs9jEeoLr6u4,19176
|
115
115
|
reconcile/terraform_tgw_attachments.py,sha256=_g7QSHM03YZzTU7O189S4HYtUn7WmwOBq67G4AieU24,15298
|
116
116
|
reconcile/terraform_users.py,sha256=kXRUxCUchKCP2dbXXOzctynqMii4oyCP6bYZHQTrlTg,10202
|
117
117
|
reconcile/terraform_vpc_peerings.py,sha256=rnDH1u93OyzrBM8Hib0HwSnlxZtx4ScRQaZAcn3mx-k,25402
|
@@ -375,7 +375,7 @@ reconcile/templates/jira-checkpoint-missinginfo.j2,sha256=c_Vvg-lEENsB3tgxm9B6Y9
|
|
375
375
|
reconcile/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
376
376
|
reconcile/test/conftest.py,sha256=rQousYrxUz-EwAIbsYO6bIwR1B4CrOz9y_zaUVo2lfI,4466
|
377
377
|
reconcile/test/fixtures.py,sha256=9SDWAUlSd1rCx7z3GhULHcpr-I6FyCsXxaFAZIqYQsQ,591
|
378
|
-
reconcile/test/test_acs_policies.py,sha256=
|
378
|
+
reconcile/test/test_acs_policies.py,sha256=hMnCX9KdLRKb53gYXK4JUR5yJwhczJRyyUPywDeLeLg,15716
|
379
379
|
reconcile/test/test_acs_rbac.py,sha256=lvNd8GY0-GHzcOdOn13QWdrqbBXXKzNT7EEDHNH7cjM,28272
|
380
380
|
reconcile/test/test_aggregated_list.py,sha256=iiWitQuNYC58aimWaiBoE4NROHjr1NCgQ91MnHEG_Ro,6412
|
381
381
|
reconcile/test/test_amtool.py,sha256=vxRhGieeydMBOb9UI2ziMHjJa8puMeGNsUhGhy-yMnk,1032
|
@@ -440,7 +440,7 @@ reconcile/test/test_terraform_cloudflare_dns.py,sha256=aQTXX8Vr4h9aWvJZTnpZEhMGY
|
|
440
440
|
reconcile/test/test_terraform_cloudflare_resources.py,sha256=NK_uktyWihkQ3gMN4bCaKerpi43CXAVYGIKTfcz05rY,13550
|
441
441
|
reconcile/test/test_terraform_cloudflare_users.py,sha256=RAFtMMdqZha3jNnNNsqbNQQUDSqUzdoM63rCw7fs4Fo,27456
|
442
442
|
reconcile/test/test_terraform_repo.py,sha256=soKFJfF8tWIimDs39RQl3Hnh-Od-bR4PfnEA2s1UprM,11552
|
443
|
-
reconcile/test/test_terraform_resources.py,sha256=
|
443
|
+
reconcile/test/test_terraform_resources.py,sha256=O8kCYxGKqILbbCP86eJ3ESjatdPa1m3wQYXxrVfc_eo,15082
|
444
444
|
reconcile/test/test_terraform_tgw_attachments.py,sha256=cAq6exc-K-jtLla1CZUZQzVnBkyDnIlL7jybnddhLKc,36861
|
445
445
|
reconcile/test/test_terraform_users.py,sha256=Xn4y6EcxnNQb6XcPoOhz_Ikxmh9Nrsu88OM1scN9hzY,5434
|
446
446
|
reconcile/test/test_terraform_vpc_peerings.py,sha256=ubcsKh0TrUIwuI1-W3ETIgzsFvzAyeoFmEJFC-IK6JY,20538
|
@@ -524,13 +524,14 @@ reconcile/utils/defer.py,sha256=SniUsbgOEs9Pa8JkecLu0F94O63yQPByKXaElDYe0FI,377
|
|
524
524
|
reconcile/utils/differ.py,sha256=kJmUp9ZffFPSUEviaAw3s9c92ErwRJeHaRexGPai7wA,7643
|
525
525
|
reconcile/utils/disabled_integrations.py,sha256=avdDsFyl_LdTsrPVzlcIhWzT_V4C4MXw1ZC__aOtluE,1126
|
526
526
|
reconcile/utils/dnsutils.py,sha256=VX4gDQXpiMYVuT0pvNbzzSgfqmsWOM2qtjNQHUyIYF8,370
|
527
|
-
reconcile/utils/early_exit_cache.py,sha256=
|
527
|
+
reconcile/utils/early_exit_cache.py,sha256=2uaiYIILA64D8mqqPj-GSvVBa80bN5XQRKz9x33iIpc,2304
|
528
528
|
reconcile/utils/elasticsearch_exceptions.py,sha256=UY5Z3y2hw7T73sPJ6dHmUybegiIophrKFdTfdsOa6UY,379
|
529
529
|
reconcile/utils/environ.py,sha256=VnW3zp6Un_UJn5BU4FU8RfhuqtZp0s-VeuuHnqC_WcQ,515
|
530
530
|
reconcile/utils/exceptions.py,sha256=DwfnWUpVOotpP79RWZ2pycmG6nKCL00RBIeZLYkQPW4,635
|
531
531
|
reconcile/utils/expiration.py,sha256=BXwKE50sNIV-Lszke97fxitNkLxYszoOLW1LBgp_yqg,1246
|
532
|
+
reconcile/utils/extended_early_exit.py,sha256=gLWRtgzRB584iX4pVfGjfZxbIDd_AQPYu8MkQkReA3U,5688
|
532
533
|
reconcile/utils/external_resource_spec.py,sha256=OGPKH3IKXgJszRTgE5U_QKgU-s4BHQnx97Lj-Krz46k,6655
|
533
|
-
reconcile/utils/external_resources.py,sha256=
|
534
|
+
reconcile/utils/external_resources.py,sha256=a2CkJ3KLociYBnc_9F2VWfZGWMhzDl6fDNhwo2U-MWU,7501
|
534
535
|
reconcile/utils/filtering.py,sha256=zZnHH0u0SaTDyzuFXZ_mREURGLvjEqQIQy4z-7QBVlc,419
|
535
536
|
reconcile/utils/git.py,sha256=Qad7mfPuS9s7eKODeWSewehwSGgJPCbQuLda1qg_6GA,1522
|
536
537
|
reconcile/utils/git_secrets.py,sha256=0wGNL5mvDtVPRuu3vEQgld1Am64gIDJHtmu1_ZKxMAI,1973
|
@@ -553,7 +554,7 @@ reconcile/utils/keycloak.py,sha256=UqOsAcHKmmIunroWB5YzC1fUZ3S3aq6L7trn6vLRmXY,3
|
|
553
554
|
reconcile/utils/ldap_client.py,sha256=ho4veSrHqQWs0YhLFyKeD-duCwY8Nc5gUIA5qLENuMY,2502
|
554
555
|
reconcile/utils/lean_terraform_client.py,sha256=zReyNPJbr2uOdrdh8Qfe-OZQBoRwxb5Za_ddeoUCYVk,4064
|
555
556
|
reconcile/utils/make.py,sha256=QaEwucrzbl8-VHS66Wfdjfo0ubmAcvt_hZGpiGsKU50,231
|
556
|
-
reconcile/utils/metrics.py,sha256=
|
557
|
+
reconcile/utils/metrics.py,sha256=7nXdctmZ0UtGMHPpS3V55sfH4xpMPqdYaJ3JKAUc_sM,18474
|
557
558
|
reconcile/utils/models.py,sha256=R3wF68yiaT0H2sQVMmHhHSTGI3JKKYEVjoizhHkySn8,4533
|
558
559
|
reconcile/utils/oc.py,sha256=iAoM7zSm72zBOmCNW19ttAvm76tUgS26vlpb8SvVYwU,64058
|
559
560
|
reconcile/utils/oc_connection_parameters.py,sha256=85slrnDigYwYmzhyceVkMElWzFArp4ge1d-fHXVqh0w,9729
|
@@ -580,8 +581,8 @@ reconcile/utils/sqs_gateway.py,sha256=gFl9DM4DmGnptuxTOe4lS3YTyE80eSAvK42ljS8h4d
|
|
580
581
|
reconcile/utils/state.py,sha256=SAa6QLHu9lr0yqLCBy2AypNx1IPCJWlrRBrvlzAKsOU,14505
|
581
582
|
reconcile/utils/structs.py,sha256=LcbLEg8WxfRqM6nW7NhcWN0YeqF7SQzxOgntmLs1SgY,352
|
582
583
|
reconcile/utils/template.py,sha256=wTvRU4AnAV_o042tD4Mwls2dwWMuk7MKnde3MaCjaYg,331
|
583
|
-
reconcile/utils/terraform_client.py,sha256=
|
584
|
-
reconcile/utils/terrascript_aws_client.py,sha256=
|
584
|
+
reconcile/utils/terraform_client.py,sha256=_jBriLBwU005bDxWlq7CRByOkVCfiH47oBzB0ArNAY8,31901
|
585
|
+
reconcile/utils/terrascript_aws_client.py,sha256=Ht2akaR4bRERLoyN_Zh2JBbN1-p-ofXICqW-oXzGcFk,265789
|
585
586
|
reconcile/utils/three_way_diff_strategy.py,sha256=nyqeQsLCoPI6e16k2CF3b9KNgQLU-rPf5RtfdUfVMwE,4468
|
586
587
|
reconcile/utils/throughput.py,sha256=iP4UWAe2LVhDo69mPPmgo9nQ7RxHD6_GS8MZe-aSiuM,344
|
587
588
|
reconcile/utils/unleash.py,sha256=1D56CsZfE3ShDtN3IErE1T2eeIwNmxhK-yYbCotJ99E,3601
|
@@ -590,7 +591,7 @@ reconcile/utils/vaultsecretref.py,sha256=3Ed2uBy36TzSvL0B-l4FoWQqB2SbBKDKEuUPIO6
|
|
590
591
|
reconcile/utils/vcs.py,sha256=o1r0n_IrU2El75CED_6sjR2GZGM-exuWsj5F7jONaMU,6779
|
591
592
|
reconcile/utils/acs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
592
593
|
reconcile/utils/acs/base.py,sha256=Qih-xZ3RBJZEE291iHHlv7lUY6ShcAvSj1PA3_aTTnM,2276
|
593
|
-
reconcile/utils/acs/policies.py,sha256=
|
594
|
+
reconcile/utils/acs/policies.py,sha256=_jAz6cv8KRYtDsXjGoJgNbD8_9PUa5LSwwVlpK4A_cQ,5505
|
594
595
|
reconcile/utils/acs/rbac.py,sha256=ugsLM9Pb7FbUbdq85E3VzXGMaB9ZovXob7tdWCxwqZ8,8808
|
595
596
|
reconcile/utils/cloud_resource_best_practice/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
596
597
|
reconcile/utils/cloud_resource_best_practice/aws_rds.py,sha256=EvE6XKLsrZ531MJptKqPht2lOETrOjySTHXk6CzMgo0,2279
|
@@ -657,7 +658,7 @@ tools/app_interface_metrics_exporter.py,sha256=zkwkxdAUAxjdc-pzx2_oJXG25fo0Fnyd5
|
|
657
658
|
tools/app_interface_reporter.py,sha256=upA-J-n-HXHKVDINRuMR7vTt-iJvQORKUVi9D3leQto,17738
|
658
659
|
tools/glitchtip_access_reporter.py,sha256=oPBnk_YoDuljU3v0FaChzOwwnk4vap1xEE67QEjzdqs,2948
|
659
660
|
tools/glitchtip_access_revalidation.py,sha256=8kbBJk04mkq28kWoRDDkfCGIF3GRg3pJrFAh1sW0dbk,2821
|
660
|
-
tools/qontract_cli.py,sha256=
|
661
|
+
tools/qontract_cli.py,sha256=mN5oXM_lmFmCGwoGU77qqO8nzlfKnNGlP6y-ILFyHIQ,103423
|
661
662
|
tools/sd_app_sre_alert_report.py,sha256=e9vAdyenUz2f5c8-z-5WY0wv-SJ9aePKDH2r4IwB6pc,5063
|
662
663
|
tools/cli_commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
663
664
|
tools/cli_commands/gpg_encrypt.py,sha256=w8hl4jIEWk5wKbEFN6fVEOwUJGmdlvOqYodW3XSN7mU,4978
|
@@ -665,11 +666,11 @@ tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOy
|
|
665
666
|
tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
|
666
667
|
tools/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
667
668
|
tools/test/test_app_interface_metrics_exporter.py,sha256=SX7qL3D1SIRKFo95FoQztvftCWEEf-g1mfXOtgCog-g,1271
|
668
|
-
tools/test/test_qontract_cli.py,sha256=
|
669
|
+
tools/test/test_qontract_cli.py,sha256=se-YG_YVCWRFrnCPvBVHDBT_59CkbIoEni-4SJa8_MU,2755
|
669
670
|
tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
|
670
671
|
tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
|
671
|
-
qontract_reconcile-0.10.
|
672
|
-
qontract_reconcile-0.10.
|
673
|
-
qontract_reconcile-0.10.
|
674
|
-
qontract_reconcile-0.10.
|
675
|
-
qontract_reconcile-0.10.
|
672
|
+
qontract_reconcile-0.10.1rc538.dist-info/METADATA,sha256=TkmlNiYqcISDkpP1_R0KR4m709lpVpeeJUAkfjVEFVc,2349
|
673
|
+
qontract_reconcile-0.10.1rc538.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
674
|
+
qontract_reconcile-0.10.1rc538.dist-info/entry_points.txt,sha256=rTjAv28I_CHLM8ID3OPqMI_suoQ9s7tFbim4aYjn9kk,376
|
675
|
+
qontract_reconcile-0.10.1rc538.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
|
676
|
+
qontract_reconcile-0.10.1rc538.dist-info/RECORD,,
|
reconcile/acs_policies.py
CHANGED
@@ -58,7 +58,10 @@ class AcsPoliciesIntegration(QontractReconcileIntegration[NoParams]):
|
|
58
58
|
return self.qontract_integration.replace("_", "-")
|
59
59
|
|
60
60
|
def _build_policy(
|
61
|
-
self,
|
61
|
+
self,
|
62
|
+
gql_policy: AcsPolicyV1,
|
63
|
+
notifier_name_to_id: dict[str, str],
|
64
|
+
cluster_name_to_id: dict[str, str],
|
62
65
|
) -> Policy:
|
63
66
|
conditions = [
|
64
67
|
pc for c in gql_policy.conditions if (pc := self._build_policy_condition(c))
|
@@ -72,7 +75,7 @@ class AcsPoliciesIntegration(QontractReconcileIntegration[NoParams]):
|
|
72
75
|
severity=f"{gql_policy.severity.upper()}_SEVERITY", # align with acs api severity value format
|
73
76
|
scope=sorted(
|
74
77
|
[
|
75
|
-
Scope(cluster=cs.name, namespace="")
|
78
|
+
Scope(cluster=cluster_name_to_id[cs.name], namespace="")
|
76
79
|
for cs in cast(
|
77
80
|
gql_acs_policies.AcsPolicyScopeClusterV1,
|
78
81
|
gql_policy.scope,
|
@@ -83,7 +86,9 @@ class AcsPoliciesIntegration(QontractReconcileIntegration[NoParams]):
|
|
83
86
|
if gql_policy.scope.level == "cluster"
|
84
87
|
else sorted(
|
85
88
|
[
|
86
|
-
Scope(
|
89
|
+
Scope(
|
90
|
+
cluster=cluster_name_to_id[ns.cluster.name], namespace=ns.name
|
91
|
+
)
|
87
92
|
for ns in cast(
|
88
93
|
gql_acs_policies.AcsPolicyScopeNamespaceV1,
|
89
94
|
gql_policy.scope,
|
@@ -158,7 +163,10 @@ class AcsPoliciesIntegration(QontractReconcileIntegration[NoParams]):
|
|
158
163
|
return None
|
159
164
|
|
160
165
|
def get_desired_state(
|
161
|
-
self,
|
166
|
+
self,
|
167
|
+
query_func: Callable,
|
168
|
+
notifiers: list[AcsPolicyApi.NotifierIdentifiers],
|
169
|
+
clusters: list[AcsPolicyApi.ClusterIdentifiers],
|
162
170
|
) -> list[Policy]:
|
163
171
|
"""
|
164
172
|
Get desired ACS security policies and convert to acs api policy object format
|
@@ -167,8 +175,9 @@ class AcsPoliciesIntegration(QontractReconcileIntegration[NoParams]):
|
|
167
175
|
:return: list of utils.acs.policies.Policy derived from acs-policy-1 definitions
|
168
176
|
"""
|
169
177
|
notifier_name_to_id = {n.name: n.id for n in notifiers}
|
178
|
+
cluster_name_to_id = {c.name: c.id for c in clusters}
|
170
179
|
return [
|
171
|
-
self._build_policy(gql_policy, notifier_name_to_id)
|
180
|
+
self._build_policy(gql_policy, notifier_name_to_id, cluster_name_to_id)
|
172
181
|
for gql_policy in gql_acs_policies.query(query_func=query_func).acs_policies
|
173
182
|
or []
|
174
183
|
]
|
@@ -225,7 +234,8 @@ class AcsPoliciesIntegration(QontractReconcileIntegration[NoParams]):
|
|
225
234
|
instance={"url": instance.url, "token": token[instance.credentials.field]}
|
226
235
|
) as acs_api:
|
227
236
|
notifiers = acs_api.list_notifiers()
|
228
|
-
|
237
|
+
clusters = acs_api.list_clusters()
|
238
|
+
desired = self.get_desired_state(gqlapi.query, notifiers, clusters)
|
229
239
|
current = acs_api.get_custom_policies()
|
230
240
|
self.reconcile(
|
231
241
|
desired=desired, current=current, acs=acs_api, dry_run=dry_run
|
reconcile/cli.py
CHANGED
@@ -507,6 +507,30 @@ def trigger_integration(function):
|
|
507
507
|
return function
|
508
508
|
|
509
509
|
|
510
|
+
def enable_extended_early_exit(function):
|
511
|
+
return click.option(
|
512
|
+
"--enable-extended-early-exit/--no-enable-extended-early-exit",
|
513
|
+
default=False,
|
514
|
+
help="enable extended early exit.",
|
515
|
+
)(function)
|
516
|
+
|
517
|
+
|
518
|
+
def extended_early_exit_cache_ttl_seconds(function):
|
519
|
+
return click.option(
|
520
|
+
"--extended-early-exit-cache-ttl-seconds",
|
521
|
+
default=3600,
|
522
|
+
help="TTL of extended early exit cache in seconds.",
|
523
|
+
)(function)
|
524
|
+
|
525
|
+
|
526
|
+
def log_cached_log_output(function):
|
527
|
+
return click.option(
|
528
|
+
"--log-cached-log-output/--no-log-cached-log-output",
|
529
|
+
default=False,
|
530
|
+
help="log the cached log output.",
|
531
|
+
)(function)
|
532
|
+
|
533
|
+
|
510
534
|
def register_faulthandler(fileobj=sys.__stderr__):
|
511
535
|
if fileobj:
|
512
536
|
if not faulthandler.is_enabled():
|
@@ -1738,6 +1762,9 @@ def terraform_repo(ctx, output_file, gitlab_project_id, gitlab_merge_request_id)
|
|
1738
1762
|
@enable_deletion(default=False)
|
1739
1763
|
@account_name_multiple
|
1740
1764
|
@exclude_aws_accounts
|
1765
|
+
@enable_extended_early_exit
|
1766
|
+
@extended_early_exit_cache_ttl_seconds
|
1767
|
+
@log_cached_log_output
|
1741
1768
|
@click.option(
|
1742
1769
|
"--light/--full",
|
1743
1770
|
default=False,
|
@@ -1755,6 +1782,9 @@ def terraform_resources(
|
|
1755
1782
|
vault_output_path,
|
1756
1783
|
account_name,
|
1757
1784
|
exclude_accounts,
|
1785
|
+
enable_extended_early_exit,
|
1786
|
+
extended_early_exit_cache_ttl_seconds,
|
1787
|
+
log_cached_log_output,
|
1758
1788
|
):
|
1759
1789
|
import reconcile.terraform_resources
|
1760
1790
|
|
@@ -1772,6 +1802,9 @@ def terraform_resources(
|
|
1772
1802
|
vault_output_path,
|
1773
1803
|
account_name=account_name,
|
1774
1804
|
exclude_accounts=exclude_accounts,
|
1805
|
+
enable_extended_early_exit=enable_extended_early_exit,
|
1806
|
+
extended_early_exit_cache_ttl_seconds=extended_early_exit_cache_ttl_seconds,
|
1807
|
+
log_cached_log_output=log_cached_log_output,
|
1775
1808
|
)
|
1776
1809
|
|
1777
1810
|
|
reconcile/terraform_resources.py
CHANGED
@@ -1,6 +1,4 @@
|
|
1
1
|
import logging
|
2
|
-
import shutil
|
3
|
-
import sys
|
4
2
|
from collections.abc import (
|
5
3
|
Callable,
|
6
4
|
Iterable,
|
@@ -11,6 +9,7 @@ from typing import (
|
|
11
9
|
Collection,
|
12
10
|
Optional,
|
13
11
|
Sequence,
|
12
|
+
TypedDict,
|
14
13
|
cast,
|
15
14
|
)
|
16
15
|
|
@@ -33,6 +32,10 @@ from reconcile.typed_queries.terraform_namespaces import get_namespaces
|
|
33
32
|
from reconcile.utils import gql
|
34
33
|
from reconcile.utils.aws_api import AWSApi
|
35
34
|
from reconcile.utils.defer import defer
|
35
|
+
from reconcile.utils.extended_early_exit import (
|
36
|
+
ExtendedEarlyExitRunnerResult,
|
37
|
+
extended_early_exit_run,
|
38
|
+
)
|
36
39
|
from reconcile.utils.external_resource_spec import (
|
37
40
|
ExternalResourceSpec,
|
38
41
|
ExternalResourceSpecInventory,
|
@@ -52,10 +55,12 @@ from reconcile.utils.ocm import OCMMap
|
|
52
55
|
from reconcile.utils.openshift_resource import OpenshiftResource as OR
|
53
56
|
from reconcile.utils.openshift_resource import ResourceInventory
|
54
57
|
from reconcile.utils.runtime.integration import DesiredStateShardConfig
|
55
|
-
from reconcile.utils.secret_reader import create_secret_reader
|
58
|
+
from reconcile.utils.secret_reader import SecretReaderBase, create_secret_reader
|
56
59
|
from reconcile.utils.semver_helper import make_semver
|
57
60
|
from reconcile.utils.terraform_client import TerraformClient as Terraform
|
61
|
+
from reconcile.utils.terrascript_aws_client import TerrascriptClient
|
58
62
|
from reconcile.utils.terrascript_aws_client import TerrascriptClient as Terrascript
|
63
|
+
from reconcile.utils.unleash import get_feature_toggle_state
|
59
64
|
from reconcile.utils.vault import (
|
60
65
|
VaultClient,
|
61
66
|
_VaultClient,
|
@@ -117,18 +122,14 @@ def populate_oc_resources(
|
|
117
122
|
|
118
123
|
|
119
124
|
def fetch_current_state(
|
120
|
-
dry_run: bool,
|
121
125
|
namespaces: Iterable[NamespaceV1],
|
122
126
|
thread_pool_size: int,
|
123
127
|
internal: Optional[bool],
|
124
128
|
use_jump_host: bool,
|
125
129
|
account_names: Optional[Iterable[str]],
|
126
|
-
|
130
|
+
secret_reader: SecretReaderBase,
|
131
|
+
) -> tuple[ResourceInventory, OCMap]:
|
127
132
|
ri = ResourceInventory()
|
128
|
-
if dry_run:
|
129
|
-
return ri, None
|
130
|
-
vault_settings = get_app_interface_vault_settings()
|
131
|
-
secret_reader = create_secret_reader(use_vault=vault_settings.vault)
|
132
133
|
oc_map = init_oc_map_from_namespaces(
|
133
134
|
namespaces=namespaces,
|
134
135
|
integration=QONTRACT_INTEGRATION,
|
@@ -172,64 +173,74 @@ def init_working_dirs(
|
|
172
173
|
|
173
174
|
|
174
175
|
def filter_accounts_by_name(
|
175
|
-
accounts: Iterable[
|
176
|
-
) ->
|
177
|
-
return [ac for ac in accounts if ac["name"] in
|
176
|
+
accounts: Iterable[dict[str, Any]], names: Iterable[str]
|
177
|
+
) -> list[dict[str, Any]]:
|
178
|
+
return [ac for ac in accounts if ac["name"] in names]
|
178
179
|
|
179
180
|
|
180
181
|
def exclude_accounts_by_name(
|
181
|
-
accounts: Iterable[
|
182
|
-
) ->
|
183
|
-
return [ac for ac in accounts if ac["name"] not in
|
182
|
+
accounts: Iterable[dict[str, Any]], names: Iterable[str]
|
183
|
+
) -> list[dict[str, Any]]:
|
184
|
+
return [ac for ac in accounts if ac["name"] not in names]
|
184
185
|
|
185
186
|
|
186
187
|
def validate_account_names(
|
187
188
|
accounts: Collection[Mapping[str, Any]], names: Collection[str]
|
188
189
|
) -> None:
|
189
|
-
if
|
190
|
-
missing_names = set(names) - {a["name"] for a in accounts}
|
190
|
+
if missing_names := set(names) - {a["name"] for a in accounts}:
|
191
191
|
raise ValueError(
|
192
192
|
f"Accounts {missing_names} were provided as arguments, but not found in app-interface. Check your input for typos or for missing AWS account definitions."
|
193
193
|
)
|
194
194
|
|
195
195
|
|
196
|
-
def
|
196
|
+
def get_aws_accounts(
|
197
197
|
dry_run: bool,
|
198
|
-
print_to_file: Optional[str],
|
199
|
-
thread_pool_size: int,
|
200
|
-
internal: Optional[bool],
|
201
|
-
use_jump_host: bool,
|
202
198
|
include_accounts: Optional[Collection[str]],
|
203
199
|
exclude_accounts: Optional[Collection[str]],
|
204
|
-
) ->
|
205
|
-
|
206
|
-
|
200
|
+
) -> list[dict[str, Any]]:
|
201
|
+
if exclude_accounts and not dry_run:
|
202
|
+
message = "--exclude-accounts is only supported in dry-run mode"
|
203
|
+
logging.error(message)
|
204
|
+
raise ExcludeAccountsAndDryRunException(message)
|
205
|
+
|
206
|
+
if exclude_accounts and include_accounts:
|
207
|
+
message = "Using --exclude-accounts and --account-name at the same time is not allowed"
|
208
|
+
logging.error(message)
|
209
|
+
raise ExcludeAccountsAndAccountNameException(message)
|
210
|
+
|
211
|
+
# If we are not running in dry run we don't want to run with more than one account
|
212
|
+
if include_accounts and len(include_accounts) > 1 and not dry_run:
|
213
|
+
message = "Running with multiple accounts is only supported in dry-run mode"
|
214
|
+
logging.error(message)
|
215
|
+
raise MultipleAccountNamesInDryRunException(message)
|
216
|
+
|
207
217
|
accounts = queries.get_aws_accounts(terraform_state=True)
|
208
|
-
|
209
|
-
|
210
|
-
validate_account_names(
|
211
|
-
|
212
|
-
if
|
218
|
+
|
219
|
+
if exclude_accounts:
|
220
|
+
validate_account_names(accounts, exclude_accounts)
|
221
|
+
filtered_accounts = exclude_accounts_by_name(accounts, exclude_accounts)
|
222
|
+
if not filtered_accounts:
|
213
223
|
raise ValueError("You have excluded all aws accounts, verify your input")
|
214
|
-
|
215
|
-
|
216
|
-
|
224
|
+
return filtered_accounts
|
225
|
+
|
226
|
+
if include_accounts:
|
217
227
|
validate_account_names(accounts, include_accounts)
|
218
|
-
|
219
|
-
settings = queries.get_app_interface_settings()
|
228
|
+
return filter_accounts_by_name(accounts, include_accounts)
|
220
229
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
)
|
230
|
+
return accounts
|
231
|
+
|
232
|
+
|
233
|
+
def setup(
|
234
|
+
accounts: list[dict[str, Any]],
|
235
|
+
account_names: set[str],
|
236
|
+
tf_namespaces: list[NamespaceV1],
|
237
|
+
print_to_file: Optional[str],
|
238
|
+
thread_pool_size: int,
|
239
|
+
) -> tuple[Terraform, TerrascriptClient, SecretReaderBase]:
|
240
|
+
vault_settings = get_app_interface_vault_settings()
|
241
|
+
secret_reader = create_secret_reader(use_vault=vault_settings.vault)
|
232
242
|
|
243
|
+
settings = queries.get_app_interface_settings()
|
233
244
|
# initialize terrascript (scripting engine to generate terraform manifests)
|
234
245
|
ts, working_dirs = init_working_dirs(accounts, thread_pool_size, settings=settings)
|
235
246
|
|
@@ -260,7 +271,7 @@ def setup(
|
|
260
271
|
ts.populate_resources(ocm_map=ocm_map)
|
261
272
|
ts.dump(print_to_file, existing_dirs=working_dirs)
|
262
273
|
|
263
|
-
return
|
274
|
+
return tf, ts, secret_reader
|
264
275
|
|
265
276
|
|
266
277
|
def filter_tf_namespaces(
|
@@ -290,21 +301,6 @@ def filter_tf_namespaces(
|
|
290
301
|
return tf_namespaces
|
291
302
|
|
292
303
|
|
293
|
-
def cleanup_and_exit(
|
294
|
-
tf: Optional[Terraform] = None,
|
295
|
-
status: bool = False,
|
296
|
-
working_dirs: Optional[Mapping[str, str]] = None,
|
297
|
-
) -> None:
|
298
|
-
if working_dirs is None:
|
299
|
-
working_dirs = {}
|
300
|
-
if tf is None:
|
301
|
-
for wd in working_dirs.values():
|
302
|
-
shutil.rmtree(wd)
|
303
|
-
else:
|
304
|
-
tf.cleanup()
|
305
|
-
sys.exit(status)
|
306
|
-
|
307
|
-
|
308
304
|
@retry()
|
309
305
|
def write_outputs_to_vault(
|
310
306
|
vault_path: str, resource_specs: ExternalResourceSpecInventory
|
@@ -366,65 +362,125 @@ def run(
|
|
366
362
|
vault_output_path: str = "",
|
367
363
|
account_name: Optional[Sequence[str]] = None,
|
368
364
|
exclude_accounts: Optional[Sequence[str]] = None,
|
365
|
+
enable_extended_early_exit: bool = False,
|
366
|
+
extended_early_exit_cache_ttl_seconds: int = 3600,
|
367
|
+
log_cached_log_output: bool = False,
|
369
368
|
defer: Optional[Callable] = None,
|
370
369
|
) -> None:
|
371
|
-
if exclude_accounts and not dry_run:
|
372
|
-
message = "--exclude-accounts is only supported in dry-run mode"
|
373
|
-
logging.error(message)
|
374
|
-
raise ExcludeAccountsAndDryRunException(message)
|
375
|
-
|
376
|
-
if exclude_accounts and account_name:
|
377
|
-
message = "Using --exclude-accounts and --account-name at the same time is not allowed"
|
378
|
-
logging.error(message)
|
379
|
-
raise ExcludeAccountsAndAccountNameException(message)
|
380
|
-
|
381
370
|
# account_name is a tuple of account names for more detail go to
|
382
371
|
# https://click.palletsprojects.com/en/8.1.x/options/#multiple-options
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
logging.error(message)
|
392
|
-
raise MultipleAccountNamesInDryRunException(message)
|
372
|
+
accounts = get_aws_accounts(dry_run, account_name, exclude_accounts)
|
373
|
+
account_names = {a["name"] for a in accounts}
|
374
|
+
tf_namespaces = get_tf_namespaces(account_names)
|
375
|
+
if not tf_namespaces:
|
376
|
+
logging.warning(
|
377
|
+
"No terraform namespaces found, consider disabling this integration, account names: "
|
378
|
+
f"{', '.join(account_names)}"
|
379
|
+
)
|
393
380
|
|
394
|
-
|
395
|
-
|
381
|
+
tf, ts, secret_reader = setup(
|
382
|
+
accounts,
|
383
|
+
account_names,
|
384
|
+
tf_namespaces,
|
396
385
|
print_to_file,
|
397
386
|
thread_pool_size,
|
398
|
-
internal,
|
399
|
-
use_jump_host,
|
400
|
-
account_names,
|
401
|
-
exclude_accounts,
|
402
387
|
)
|
403
|
-
|
388
|
+
if defer:
|
389
|
+
defer(tf.cleanup)
|
404
390
|
|
405
|
-
|
406
|
-
defer(oc_map.cleanup)
|
391
|
+
publish_metrics(ts.resource_spec_inventory, QONTRACT_INTEGRATION)
|
407
392
|
|
408
393
|
if print_to_file:
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
394
|
+
return
|
395
|
+
|
396
|
+
runner_params: RunnerParams = dict(
|
397
|
+
accounts=accounts,
|
398
|
+
account_names=account_names,
|
399
|
+
tf_namespaces=tf_namespaces,
|
400
|
+
tf=tf,
|
401
|
+
ts=ts,
|
402
|
+
secret_reader=secret_reader,
|
403
|
+
dry_run=dry_run,
|
404
|
+
enable_deletion=enable_deletion,
|
405
|
+
thread_pool_size=thread_pool_size,
|
406
|
+
internal=internal,
|
407
|
+
use_jump_host=use_jump_host,
|
408
|
+
light=light,
|
409
|
+
vault_output_path=vault_output_path,
|
410
|
+
defer=defer,
|
411
|
+
)
|
413
412
|
|
413
|
+
if enable_extended_early_exit and get_feature_toggle_state(
|
414
|
+
"terraform-resources-extended-early-exit",
|
415
|
+
default=False,
|
416
|
+
):
|
417
|
+
extended_early_exit_run(
|
418
|
+
integration=QONTRACT_INTEGRATION,
|
419
|
+
integration_version=QONTRACT_INTEGRATION_VERSION,
|
420
|
+
dry_run=dry_run,
|
421
|
+
cache_source=ts.terraform_configurations(),
|
422
|
+
ttl_seconds=extended_early_exit_cache_ttl_seconds,
|
423
|
+
logger=logging.getLogger(),
|
424
|
+
runner=runner,
|
425
|
+
runner_params=runner_params,
|
426
|
+
secret_reader=secret_reader,
|
427
|
+
log_cached_log_output=log_cached_log_output,
|
428
|
+
)
|
429
|
+
else:
|
430
|
+
runner(**runner_params)
|
431
|
+
|
432
|
+
|
433
|
+
class RunnerParams(TypedDict):
|
434
|
+
accounts: list[dict[str, Any]]
|
435
|
+
account_names: set[str]
|
436
|
+
tf_namespaces: list[NamespaceV1]
|
437
|
+
tf: Terraform
|
438
|
+
ts: Terrascript
|
439
|
+
secret_reader: SecretReaderBase
|
440
|
+
dry_run: bool
|
441
|
+
enable_deletion: bool
|
442
|
+
thread_pool_size: int
|
443
|
+
internal: Optional[bool]
|
444
|
+
use_jump_host: bool
|
445
|
+
light: bool
|
446
|
+
vault_output_path: str
|
447
|
+
defer: Optional[Callable]
|
448
|
+
|
449
|
+
|
450
|
+
def runner(
|
451
|
+
accounts: list[dict[str, Any]],
|
452
|
+
account_names: set[str],
|
453
|
+
tf_namespaces: list[NamespaceV1],
|
454
|
+
tf: Terraform,
|
455
|
+
ts: Terrascript,
|
456
|
+
secret_reader: SecretReaderBase,
|
457
|
+
dry_run: bool,
|
458
|
+
enable_deletion: bool = False,
|
459
|
+
thread_pool_size: int = 10,
|
460
|
+
internal: Optional[bool] = None,
|
461
|
+
use_jump_host: bool = True,
|
462
|
+
light: bool = False,
|
463
|
+
vault_output_path: str = "",
|
464
|
+
defer: Optional[Callable] = None,
|
465
|
+
) -> ExtendedEarlyExitRunnerResult:
|
414
466
|
if not light:
|
415
467
|
disabled_deletions_detected, err = tf.plan(enable_deletion)
|
416
468
|
if err:
|
417
|
-
|
469
|
+
raise RuntimeError("Terraform plan has errors")
|
418
470
|
if disabled_deletions_detected:
|
419
|
-
|
471
|
+
raise RuntimeError("Terraform plan has disabled deletions detected")
|
420
472
|
|
421
473
|
if dry_run:
|
422
|
-
|
474
|
+
return ExtendedEarlyExitRunnerResult(
|
475
|
+
payload=ts.terraform_configurations(),
|
476
|
+
applied_count=0,
|
477
|
+
)
|
423
478
|
|
424
|
-
if
|
479
|
+
acc_name = accounts[0]["name"] if accounts else None
|
480
|
+
if not light and tf.should_apply():
|
425
481
|
err = tf.apply()
|
426
482
|
if err:
|
427
|
-
|
483
|
+
raise RuntimeError("Terraform apply has errors")
|
428
484
|
|
429
485
|
if defer:
|
430
486
|
defer(
|
@@ -437,26 +493,41 @@ def run(
|
|
437
493
|
|
438
494
|
# refresh output data after terraform apply
|
439
495
|
tf.populate_terraform_output_secrets(
|
440
|
-
resource_specs=
|
496
|
+
resource_specs=ts.resource_spec_inventory, init_rds_replica_source=True
|
441
497
|
)
|
498
|
+
|
499
|
+
ri, oc_map = fetch_current_state(
|
500
|
+
tf_namespaces,
|
501
|
+
thread_pool_size,
|
502
|
+
internal,
|
503
|
+
use_jump_host,
|
504
|
+
account_names,
|
505
|
+
secret_reader=secret_reader,
|
506
|
+
)
|
507
|
+
if defer:
|
508
|
+
defer(oc_map.cleanup)
|
442
509
|
# populate the resource inventory with latest output data
|
443
|
-
populate_desired_state(ri,
|
510
|
+
populate_desired_state(ri, ts.resource_spec_inventory)
|
444
511
|
|
445
512
|
ob.publish_metrics(ri, QONTRACT_INTEGRATION)
|
446
|
-
actions =
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
513
|
+
actions = ob.realize_data(
|
514
|
+
dry_run,
|
515
|
+
oc_map,
|
516
|
+
ri,
|
517
|
+
thread_pool_size,
|
518
|
+
caller=acc_name,
|
519
|
+
)
|
451
520
|
|
452
521
|
if actions and vault_output_path:
|
453
|
-
write_outputs_to_vault(vault_output_path,
|
522
|
+
write_outputs_to_vault(vault_output_path, ts.resource_spec_inventory)
|
454
523
|
|
455
524
|
if ri.has_error_registered():
|
456
|
-
|
457
|
-
cleanup_and_exit(tf, err)
|
525
|
+
raise RuntimeError("Resource inventory has errors registered")
|
458
526
|
|
459
|
-
|
527
|
+
return ExtendedEarlyExitRunnerResult(
|
528
|
+
payload=ts.terraform_configurations(),
|
529
|
+
applied_count=tf.apply_count + len(actions),
|
530
|
+
)
|
460
531
|
|
461
532
|
|
462
533
|
def early_exit_desired_state(*args: Any, **kwargs: Any) -> dict[str, Any]:
|