qontract-reconcile 0.10.2.dev317__py3-none-any.whl → 0.10.2.dev319__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.2.dev317.dist-info → qontract_reconcile-0.10.2.dev319.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.2.dev317.dist-info → qontract_reconcile-0.10.2.dev319.dist-info}/RECORD +17 -19
- reconcile/jenkins_job_builder.py +1 -1
- reconcile/jenkins_worker_fleets.py +75 -8
- reconcile/oum/providers.py +1 -1
- reconcile/terraform_vpc_peerings.py +1 -0
- reconcile/utils/gpg.py +5 -3
- reconcile/utils/imap_client.py +1 -1
- reconcile/utils/jjb_client.py +50 -31
- reconcile/utils/ldap_client.py +4 -3
- reconcile/utils/lean_terraform_client.py +3 -1
- reconcile/utils/ocm/ocm.py +81 -71
- reconcile/utils/ocm_base_client.py +4 -4
- reconcile/utils/raw_github_api.py +11 -8
- tools/cli_commands/gpg_encrypt.py +1 -1
- reconcile/jenkins/__init__.py +0 -0
- reconcile/jenkins/types.py +0 -77
- {qontract_reconcile-0.10.2.dev317.dist-info → qontract_reconcile-0.10.2.dev319.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev317.dist-info → qontract_reconcile-0.10.2.dev319.dist-info}/entry_points.txt +0 -0
{qontract_reconcile-0.10.2.dev317.dist-info → qontract_reconcile-0.10.2.dev319.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: qontract-reconcile
|
3
|
-
Version: 0.10.2.
|
3
|
+
Version: 0.10.2.dev319
|
4
4
|
Summary: Collection of tools to reconcile services with their desired state as defined in the app-interface DB.
|
5
5
|
Project-URL: homepage, https://github.com/app-sre/qontract-reconcile
|
6
6
|
Project-URL: repository, https://github.com/app-sre/qontract-reconcile
|
{qontract_reconcile-0.10.2.dev317.dist-info → qontract_reconcile-0.10.2.dev319.dist-info}/RECORD
RENAMED
@@ -35,12 +35,12 @@ reconcile/gitlab_permissions.py,sha256=LkufO5HDeti8N6QSZoGfoJG51_v8aVZYd-5MkK9Du
|
|
35
35
|
reconcile/gitlab_projects.py,sha256=JIB1UP8CnwSkngEMZE7DFQETMX6sJMp4DXaKoS-Pdkc,1879
|
36
36
|
reconcile/integrations_manager.py,sha256=g6QJOu_hJp_6tUpjpqc9HC_8FNWjvtoYat20TX-bJhg,9398
|
37
37
|
reconcile/jenkins_base.py,sha256=0Gocu3fU2YTltaxBlbDQOUvP-7CP2OSQV1ZRwtWeVXw,875
|
38
|
-
reconcile/jenkins_job_builder.py,sha256=
|
38
|
+
reconcile/jenkins_job_builder.py,sha256=eRR3AL3RN7U_8A4hceUlj_k_jWf-qHMyLr9gqxcj3kQ,3469
|
39
39
|
reconcile/jenkins_job_builds_cleaner.py,sha256=l9eLyvdgv1sN2tAlkGx3T8g6Db9kIfWW3LJh5H6dV9A,4080
|
40
40
|
reconcile/jenkins_roles.py,sha256=zdGavYJJNmbOdu_pr-NrNPl_Tj3j8oin14qvydKxXZw,4916
|
41
41
|
reconcile/jenkins_webhooks.py,sha256=8BDPsCJdvuYDl0D3qJc0l6pUtceBh9WiNGpfy-LE4S8,2351
|
42
42
|
reconcile/jenkins_webhooks_cleaner.py,sha256=tFbAzsFGvJ6UrHRZFdIuLdqG-Ocd5_OknfsbtN-eyFY,1619
|
43
|
-
reconcile/jenkins_worker_fleets.py,sha256=
|
43
|
+
reconcile/jenkins_worker_fleets.py,sha256=CqYekCjYv75NvtcegOjxMC-LvKpMYPChxI_9NQVu_VY,8236
|
44
44
|
reconcile/jira_permissions_validator.py,sha256=nVHZg7kNn04Q-ryNM20wthMrhXos28g3O9b0ahzxAKc,14690
|
45
45
|
reconcile/ldap_users.py,sha256=oP1CAxmgSi3zDJ3vKTPySjap6WmEX1U469FmFrov5l4,4599
|
46
46
|
reconcile/mr_client_gateway.py,sha256=3L21YncbetuUI3HYvDAEb5JX5HO5KG2CfUyjapX3w8E,2063
|
@@ -111,7 +111,7 @@ reconcile/terraform_repo.py,sha256=vVJfaCV9775FGMMTHfoobaPetSlJMiQ4arNudL2pvh8,1
|
|
111
111
|
reconcile/terraform_resources.py,sha256=AXO3_Ehcg3I6ao7qiKzXC4Mk6BqwMoNooXU50c2zSTA,19555
|
112
112
|
reconcile/terraform_tgw_attachments.py,sha256=P2HivCjT5AlyODy-fu1qAK5355nDEArE8E4NQlIlF7U,18933
|
113
113
|
reconcile/terraform_users.py,sha256=xa-UK2iTy0HRFAGfFQvxTbBaypsqx3O0XGVWIU9yIxI,10659
|
114
|
-
reconcile/terraform_vpc_peerings.py,sha256=
|
114
|
+
reconcile/terraform_vpc_peerings.py,sha256=OMin9ica4_tpZxoDNUX72aO6IC_YgD3rfowJQeinaJY,27822
|
115
115
|
reconcile/vault_replication.py,sha256=trtbB-jDwca822J5I_s0zlwFtlyaiAtqgbPeqp7Cggc,17714
|
116
116
|
reconcile/vpc_peerings_validator.py,sha256=_77eu6DSy6VjTE5mhV-sOIVOGIiBvDEEDCdwwRdrgVQ,7101
|
117
117
|
reconcile/aus/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -438,8 +438,6 @@ reconcile/gql_definitions/vault_policies/vault_policies.py,sha256=hfKhUXTqz22aBi
|
|
438
438
|
reconcile/gql_definitions/vpc_peerings_validator/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
439
439
|
reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py,sha256=8eN4p6csq79qwIsnMzbnWRqvxRHv6AqOZJY6lsx6fFE,4451
|
440
440
|
reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py,sha256=Hez1Oi2t2ow-G8vCQiZpi0WmSEwDFKf8RC-9uC9JcUM,1067
|
441
|
-
reconcile/jenkins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
442
|
-
reconcile/jenkins/types.py,sha256=8YJVwnwilTbBKcB46mlMztudDwd0x7rzNOI4D_lV4Fc,2958
|
443
441
|
reconcile/ldap_groups/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
444
442
|
reconcile/ldap_groups/integration.py,sha256=hx-JX9TgUJMIZoQRWO3nmQLjAPnJaQ-tNud4ky8JQdA,10622
|
445
443
|
reconcile/ocm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -453,7 +451,7 @@ reconcile/oum/base.py,sha256=WCFdHOHXLPrJcvxVqw6HjaJthT7olC5BQqqXlD4DM6c,13552
|
|
453
451
|
reconcile/oum/labelset.py,sha256=f5kDndbaIT4iNYxTRPSELTUgj_aMlzEJDPzooAkG2mE,2154
|
454
452
|
reconcile/oum/metrics.py,sha256=S_0C-hIW4jHVl9Lltgis9q-p33fdBjADWBouQ9Emeao,1575
|
455
453
|
reconcile/oum/models.py,sha256=teH0bJTCMTzbdbYD9CU4yXDuMr34ceLcM0KuoIPU8gI,1712
|
456
|
-
reconcile/oum/providers.py,sha256=
|
454
|
+
reconcile/oum/providers.py,sha256=M2kfN5gxOgIGJN2Hpprc-oQkMNhCcPPqy9ABETwLABk,1839
|
457
455
|
reconcile/oum/standalone.py,sha256=EN5y1S-3DwUZYzSRqRMtf63mI2slvBHKiU9zOTjYvWM,7334
|
458
456
|
reconcile/prometheus_rules_tester/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
459
457
|
reconcile/prometheus_rules_tester/integration.py,sha256=qa1OrD1gCR1PUrHNFc2AL3J01SdBYfMOX8fHcOUh1T8,9618
|
@@ -608,21 +606,21 @@ reconcile/utils/filtering.py,sha256=S4PbMHuFr3ED0P2Q_ea5CAaB7FimI62B-F5YTaKrphA,
|
|
608
606
|
reconcile/utils/git.py,sha256=o4p9m8jlzCJDcutl2HErvGLhL6sZ1NB4Aw3zGcQIzso,2427
|
609
607
|
reconcile/utils/github_api.py,sha256=S1vO-hvYPzm5BIychVIHSYibMns0HBmLgS78MkPfunE,3402
|
610
608
|
reconcile/utils/gitlab_api.py,sha256=okuBtZA3dRvIDuZOL-zAmiQqugebdA_H_AOV7luPnDk,28343
|
611
|
-
reconcile/utils/gpg.py,sha256=
|
609
|
+
reconcile/utils/gpg.py,sha256=VCNERVnIFZtIu62VbBtM_MtokTPVQ0bsCWs2evGKLeo,1254
|
612
610
|
reconcile/utils/gql.py,sha256=_GtzCoYIvDSS7PHXIImShs_g3k85MLlGNTJqqwhYFLQ,14703
|
613
611
|
reconcile/utils/grouping.py,sha256=vr9SFHZ7bqmHYrvYcEZt-Er3-yQYfAAdq5sHLZVmXPY,456
|
614
612
|
reconcile/utils/helm.py,sha256=wC1h0GylhDFeZ6hZEtYy2giAGIIQroaQhkAtURoSlI8,3893
|
615
613
|
reconcile/utils/helpers.py,sha256=koyAtYnxsUVx-HIn6GpedcUE-ekz_VtoYDkiZ0iv8ik,1795
|
616
|
-
reconcile/utils/imap_client.py,sha256=
|
614
|
+
reconcile/utils/imap_client.py,sha256=sJSBBCObR34JTk70raIkJYXZbmEOOyc8IDQ1CrcSO1Q,2019
|
617
615
|
reconcile/utils/instrumented_wrappers.py,sha256=VqT4s0Bdicv224-uSeSaugtHXm-xJ3oSeBiqj0QQRiU,1942
|
618
616
|
reconcile/utils/jenkins_api.py,sha256=jNwdtBtO8DgMW_H8XfqkQs2r4JsLovHe03t5_F3M1xg,7961
|
619
617
|
reconcile/utils/jira_client.py,sha256=qC1mE47_WCp3pgbMn9YqBH6LJFeQKn93biH4oG0P1bc,10574
|
620
|
-
reconcile/utils/jjb_client.py,sha256=
|
618
|
+
reconcile/utils/jjb_client.py,sha256=ZwoQvrufRxyMGXo2rg2-_b5U0rJASLG398MDBQI3K20,16416
|
621
619
|
reconcile/utils/jsonpath.py,sha256=wdxOMqR-GMpQf5vRPWRMqAF7bCiXDBkkcFfY2U4j_tk,5536
|
622
620
|
reconcile/utils/jump_host.py,sha256=gi8vGUDgdTVwJvROvRVauFxtL0YAramhbWvG70L7AY8,5137
|
623
621
|
reconcile/utils/keycloak.py,sha256=YWSEUGrOVqFaJUk055dKUWpLDPdDRvhcmvR-lfbmxdE,3388
|
624
|
-
reconcile/utils/ldap_client.py,sha256=
|
625
|
-
reconcile/utils/lean_terraform_client.py,sha256=
|
622
|
+
reconcile/utils/ldap_client.py,sha256=EIq2A19LzEQNcNCUeJQxp161tkWV1qpj9ufU15uBefE,2216
|
623
|
+
reconcile/utils/lean_terraform_client.py,sha256=cVxx0jR3-Jiuirub_gJDf-G0FC8lNoFHdI5H6xc5TyA,4047
|
626
624
|
reconcile/utils/make.py,sha256=QaEwucrzbl8-VHS66Wfdjfo0ubmAcvt_hZGpiGsKU50,231
|
627
625
|
reconcile/utils/metrics.py,sha256=kiOoWO0b0mO-MDZWxyClYz9SeohQ0QU-xji0p-cSiLo,18462
|
628
626
|
reconcile/utils/models.py,sha256=N-cOLsLbZAzVazFImue4d1pllCGd_vVcIrFKykYZXZo,4682
|
@@ -631,7 +629,7 @@ reconcile/utils/oc.py,sha256=c1O-qqKUNCgPrFNFCzVkgA0TCLY_vKpsaSY3XGMHpRg,65531
|
|
631
629
|
reconcile/utils/oc_connection_parameters.py,sha256=-H2crz0UOVKWlNrexf04ip8Vu57rE2QZLJuurvin1_c,9705
|
632
630
|
reconcile/utils/oc_filters.py,sha256=Tz3OwtbUaYKmxENFls5CtPVzkZDeFXknw53dJe-wbT8,1382
|
633
631
|
reconcile/utils/oc_map.py,sha256=ougQ-Wlsa8ymoE_lPQ7g2LlpsUOsHVeRCLYW_6fjeWU,8976
|
634
|
-
reconcile/utils/ocm_base_client.py,sha256=
|
632
|
+
reconcile/utils/ocm_base_client.py,sha256=niBN-yHiML5ljqKMOabFTaYW9iQ8JAway37BQF2NvtM,6713
|
635
633
|
reconcile/utils/openshift_resource.py,sha256=Nbte4oCzxL27Hrt2vNs2ybV3X3pV4vGJEnErEsiA6UY,24810
|
636
634
|
reconcile/utils/openssl.py,sha256=qdEdSmNXDgx_hhj2psEea6O12cmn3pb4GNhQJtI5l_E,399
|
637
635
|
reconcile/utils/output.py,sha256=wvsyf8NsFTaFHNkc8to75ta8f474Y4TMO4cHyAHEePk,2209
|
@@ -643,7 +641,7 @@ reconcile/utils/promotion_state.py,sha256=McSgGj3oog83ThJCrMR2v8q6Xb_Pxij-HEe_Rb
|
|
643
641
|
reconcile/utils/promtool.py,sha256=YnqwMAzsQVGuBZ1j9zy3UcVPFQVJgBMLzQkxhK_KFkU,3079
|
644
642
|
reconcile/utils/quay_api.py,sha256=ZWjfjzFnIsbKRDcdAnP9tWQezclf53I7VWZJ0gbF2kE,8260
|
645
643
|
reconcile/utils/quay_mirror.py,sha256=dpWCNv5lITwIk6Q9RkmqaQKHNk_JPy27UQEribJ7E-U,1324
|
646
|
-
reconcile/utils/raw_github_api.py,sha256=
|
644
|
+
reconcile/utils/raw_github_api.py,sha256=TlGfpitmqh_aX0V5b231TRQjuY2bAD6_FLvIA5P5a_o,3045
|
647
645
|
reconcile/utils/repo_owners.py,sha256=c6Z-U5TkiRPvuhr_zYWvZG9HZGzoT-l-d2PJ33lGflE,6507
|
648
646
|
reconcile/utils/rest_api_base.py,sha256=MT7tp6CQO2S5aKfVOzw_hipWg7wAGoOqkm4qurI1hEU,4342
|
649
647
|
reconcile/utils/rhcsv2_certs.py,sha256=ZnlUlEI2k6UrljGarkm1ey0znMlQtjeZB7VEfCH1A64,2545
|
@@ -728,7 +726,7 @@ reconcile/utils/ocm/identity_providers.py,sha256=dKed09N8iWmn39tI_MpwgVe47x23eLs
|
|
728
726
|
reconcile/utils/ocm/label_sources.py,sha256=ES_5VP4X6gsRxMFZ95WgbwE_HqqIUo_JRjHjdGYw6Ss,1846
|
729
727
|
reconcile/utils/ocm/labels.py,sha256=CmAgaOEPiaUb4gLtKab9vNkSDJceuREPd4ApgGcIA1U,6240
|
730
728
|
reconcile/utils/ocm/manifests.py,sha256=Q6kgOeiAwLbJY_vO_BEW2oePvbLDZcMZk20YpJJGpOA,1195
|
731
|
-
reconcile/utils/ocm/ocm.py,sha256=
|
729
|
+
reconcile/utils/ocm/ocm.py,sha256=1nBhA_h1SjTwCFF6aMMVRSDw0geg9vs0ul3WfnN2F_M,32748
|
732
730
|
reconcile/utils/ocm/products.py,sha256=UtWpkAvSMCxPOulEB7aV5ZY8ej_rmErlE_HVdm9Gnjk,26021
|
733
731
|
reconcile/utils/ocm/search_filters.py,sha256=09p4Wq1d1HGrDiinf1dmLJ46VtFhkkRCOL4V-N-zwjY,14808
|
734
732
|
reconcile/utils/ocm/service_log.py,sha256=RG1f0MMn6joKaRCAm2xveSJCavdOPP1BVo9FXecDxaI,2018
|
@@ -775,7 +773,7 @@ tools/template_validation.py,sha256=Xn9X4sGFznx-rvBDnq9Kq16rfET8V3bqH1EwavsGBac,
|
|
775
773
|
tools/cli_commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
776
774
|
tools/cli_commands/container_images_report.py,sha256=8mAjCS6XR0yD7k0mfiVBlt6xbYU47q_ftdYNi5o5VKE,5566
|
777
775
|
tools/cli_commands/erv2.py,sha256=H5RKytXP2BRYxixd-6Z3qfRJRfs2cOhtmXTgEOsn9_s,26079
|
778
|
-
tools/cli_commands/gpg_encrypt.py,sha256=
|
776
|
+
tools/cli_commands/gpg_encrypt.py,sha256=C6y0KnZxnycYOxgpDvCfAUZYGhDZjIYfZ7tnlyg3a7M,4920
|
779
777
|
tools/cli_commands/systems_and_tools.py,sha256=n6IFdPPLpueGP8Eh3dqv2errk0ZqHWUDcan_Nrhnt9I,16747
|
780
778
|
tools/cli_commands/cost_report/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
781
779
|
tools/cli_commands/cost_report/aws.py,sha256=JtwDfhaYLfa4Uz1LR6OfSBh_3nBlb90kQq6i3MV_ims,4563
|
@@ -796,7 +794,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
796
794
|
tools/saas_promotion_state/saas_promotion_state.py,sha256=uQv2QJAmUXP1g2GPIH30WTlvL9soY6m9lefpZEVDM5w,3965
|
797
795
|
tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
|
798
796
|
tools/sre_checkpoints/util.py,sha256=KcYVfa3UmJHVP_ocgrKe8NkrO5IDB9aWEDydSokPcRk,975
|
799
|
-
qontract_reconcile-0.10.2.
|
800
|
-
qontract_reconcile-0.10.2.
|
801
|
-
qontract_reconcile-0.10.2.
|
802
|
-
qontract_reconcile-0.10.2.
|
797
|
+
qontract_reconcile-0.10.2.dev319.dist-info/METADATA,sha256=FNa6A7BaR7ZXxqf7JG1YpJbOmrGsQFwzlwruMjRnGys,24916
|
798
|
+
qontract_reconcile-0.10.2.dev319.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
799
|
+
qontract_reconcile-0.10.2.dev319.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
|
800
|
+
qontract_reconcile-0.10.2.dev319.dist-info/RECORD,,
|
reconcile/jenkins_job_builder.py
CHANGED
@@ -81,7 +81,7 @@ def run(
|
|
81
81
|
if not print_only and config_name is not None:
|
82
82
|
raise Exception("--config-name must works with --print-only mode")
|
83
83
|
secret_reader = SecretReader(queries.get_secret_reader_settings())
|
84
|
-
jjb
|
84
|
+
jjb = init_jjb(secret_reader, instance_name, config_name, print_only)
|
85
85
|
if defer:
|
86
86
|
defer(jjb.cleanup)
|
87
87
|
|
@@ -1,14 +1,12 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import logging
|
2
|
-
from
|
3
|
-
|
4
|
-
|
5
|
-
|
4
|
+
from enum import Enum
|
5
|
+
from typing import Any, cast
|
6
|
+
|
7
|
+
from pydantic import BaseModel, Field
|
6
8
|
|
7
9
|
from reconcile import queries
|
8
|
-
from reconcile.jenkins.types import (
|
9
|
-
JenkinsWorkerFleet,
|
10
|
-
SSHConnector,
|
11
|
-
)
|
12
10
|
from reconcile.utils.external_resources import get_external_resource_specs
|
13
11
|
from reconcile.utils.jenkins_api import JenkinsApi
|
14
12
|
from reconcile.utils.secret_reader import SecretReader
|
@@ -17,6 +15,75 @@ from reconcile.utils.terrascript_aws_client import TerrascriptClient as Terrascr
|
|
17
15
|
QONTRACT_INTEGRATION = "jenkins-worker-fleets"
|
18
16
|
|
19
17
|
|
18
|
+
class SSHHostKeyVerificationStrategy(Enum):
|
19
|
+
MANUALLY_TRUSTED_KEY_VERIFICATION_STRATEGY = (
|
20
|
+
"manuallyTrustedKeyVerificationStrategy"
|
21
|
+
)
|
22
|
+
MANUALLY_PROVIDED_KEY_VERIFICATION_STRATEGY = (
|
23
|
+
"manuallyProvidedKeyVerificationStrategy"
|
24
|
+
)
|
25
|
+
NON_VERIFYING_KEY_VERIFICATION_STRATEGY = "nonVerifyingKeyVerificationStrategy"
|
26
|
+
KNOWN_HOSTS_FILE_KEY_VERIFICATION_STRATEGY = "knownHostsFileKeyVerificationStrategy"
|
27
|
+
|
28
|
+
|
29
|
+
class SSHConnector(BaseModel):
|
30
|
+
credentials_id: str = Field(..., alias="credentialsId")
|
31
|
+
launch_timeout_seconds: int | None = Field(None, alias="launchTimeoutSeconds")
|
32
|
+
max_num_retries: int | None = Field(None, alias="maxNumRetries")
|
33
|
+
retry_wait_time: int | None = Field(None, alias="retryWaitTime")
|
34
|
+
port: int | None = 22
|
35
|
+
jvm_options: str | None = Field(None, alias="jvmOptions")
|
36
|
+
ssh_host_key_verification_strategy: SSHHostKeyVerificationStrategy = Field(
|
37
|
+
SSHHostKeyVerificationStrategy.NON_VERIFYING_KEY_VERIFICATION_STRATEGY,
|
38
|
+
alias="sshHostKeyVerificationStrategy",
|
39
|
+
)
|
40
|
+
|
41
|
+
class Config:
|
42
|
+
use_enum_values = True
|
43
|
+
|
44
|
+
|
45
|
+
class ComputerConnector(BaseModel):
|
46
|
+
# alias name is defined by jcasc schema
|
47
|
+
ssh_connector: SSHConnector = Field(..., alias="sSHConnector")
|
48
|
+
|
49
|
+
|
50
|
+
class JenkinsWorkerFleet(BaseModel):
|
51
|
+
# following options comes form https://github.com/jenkinsci/ec2-fleet-plugin/blob/master/docs/
|
52
|
+
name: str
|
53
|
+
fleet: str
|
54
|
+
region: str
|
55
|
+
min_size: int = Field(..., alias="minSize")
|
56
|
+
max_size: int = Field(..., alias="maxSize")
|
57
|
+
computer_connector: ComputerConnector = Field(..., alias="computerConnector")
|
58
|
+
fs_root: str = Field(..., alias="fsRoot")
|
59
|
+
label_string: str = Field(..., alias="labelString")
|
60
|
+
num_executors: int = Field(2, alias="numExecutors")
|
61
|
+
idle_minutes: int = Field(30, alias="idleMinutes")
|
62
|
+
min_spare_size: int = Field(0, alias="minSpareSize")
|
63
|
+
max_total_uses: int = Field(-1, alias="maxTotalUses")
|
64
|
+
no_delay_provision: bool = Field(False, alias="noDelayProvision")
|
65
|
+
add_node_only_if_running: bool = Field(True, alias="addNodeOnlyIfRunning")
|
66
|
+
always_reconnect: bool = Field(True, alias="alwaysReconnect")
|
67
|
+
private_ip_used: bool = Field(True, alias="privateIpUsed")
|
68
|
+
restrict_usage: bool = Field(True, alias="restrictUsage")
|
69
|
+
|
70
|
+
def __lt__(self, other: JenkinsWorkerFleet) -> bool:
|
71
|
+
return self.fleet < other.fleet
|
72
|
+
|
73
|
+
def __eq__(self, other: object) -> bool:
|
74
|
+
if not isinstance(other, JenkinsWorkerFleet):
|
75
|
+
raise NotImplementedError(
|
76
|
+
"Cannot compare to non JenkinsWorkerFleet objects."
|
77
|
+
)
|
78
|
+
return self.fleet == other.fleet and self.region == other.region
|
79
|
+
|
80
|
+
def __hash__(self) -> int:
|
81
|
+
return hash(self.fleet + self.region)
|
82
|
+
|
83
|
+
def differ(self, other: JenkinsWorkerFleet) -> bool:
|
84
|
+
return self.dict() != other.dict()
|
85
|
+
|
86
|
+
|
20
87
|
def get_current_state(jenkins: JenkinsApi) -> list[JenkinsWorkerFleet]:
|
21
88
|
current_state = []
|
22
89
|
|
reconcile/oum/providers.py
CHANGED
@@ -33,7 +33,7 @@ class LdapGroupMemberProvider(GroupMemberProvider):
|
|
33
33
|
if len(group_ids) == 0:
|
34
34
|
return {}
|
35
35
|
with self.ldap_client as lc:
|
36
|
-
groups_members_by_dn = lc.get_group_members(group_dn_mapping.keys())
|
36
|
+
groups_members_by_dn = lc.get_group_members(set(group_dn_mapping.keys()))
|
37
37
|
return {
|
38
38
|
group_dn_mapping[dn]: members
|
39
39
|
for dn, members in groups_members_by_dn.items()
|
@@ -73,6 +73,7 @@ def _build_infrastructure_assume_role(
|
|
73
73
|
ocm: OCM | None,
|
74
74
|
provided_assume_role: str | None,
|
75
75
|
) -> dict[str, Any] | None:
|
76
|
+
assume_role: str | None = None
|
76
77
|
if provided_assume_role:
|
77
78
|
assume_role = provided_assume_role
|
78
79
|
elif cluster["spec"].get("account"):
|
reconcile/utils/gpg.py
CHANGED
@@ -8,7 +8,7 @@ from subprocess import (
|
|
8
8
|
)
|
9
9
|
|
10
10
|
|
11
|
-
def gpg_encrypt(content, public_gpg_key):
|
11
|
+
def gpg_encrypt(content: str, public_gpg_key: str) -> str:
|
12
12
|
public_gpg_key_dec = base64.b64decode(public_gpg_key)
|
13
13
|
|
14
14
|
with tempfile.TemporaryDirectory() as gnupg_home_dir:
|
@@ -22,6 +22,8 @@ def gpg_encrypt(content, public_gpg_key):
|
|
22
22
|
)
|
23
23
|
out = proc.stdout.decode("utf-8")
|
24
24
|
match = re.search(r"<\S+>", out)
|
25
|
+
if not match:
|
26
|
+
raise ValueError("No recipient found in GPG import output")
|
25
27
|
recipient = match.group(0)[1:-1]
|
26
28
|
# encrypt content
|
27
29
|
proc = run(
|
@@ -41,5 +43,5 @@ def gpg_encrypt(content, public_gpg_key):
|
|
41
43
|
stderr=STDOUT,
|
42
44
|
check=True,
|
43
45
|
)
|
44
|
-
|
45
|
-
return
|
46
|
+
encrypted_out = proc.stdout
|
47
|
+
return encrypted_out.decode("utf-8")
|
reconcile/utils/imap_client.py
CHANGED
reconcile/utils/jjb_client.py
CHANGED
@@ -8,6 +8,7 @@ import shutil
|
|
8
8
|
import subprocess
|
9
9
|
import tempfile
|
10
10
|
import xml.etree.ElementTree as ET
|
11
|
+
from collections.abc import Iterable, Mapping
|
11
12
|
from os import path
|
12
13
|
from subprocess import (
|
13
14
|
PIPE,
|
@@ -25,6 +26,8 @@ from sretoolbox.utils import retry
|
|
25
26
|
|
26
27
|
from reconcile.utils import throughput
|
27
28
|
from reconcile.utils.helpers import toggle_logger
|
29
|
+
from reconcile.utils.secret_reader import SecretReaderBase
|
30
|
+
from reconcile.utils.state import State
|
28
31
|
from reconcile.utils.vcs import GITHUB_BASE_URL
|
29
32
|
|
30
33
|
JJB_INI = "[jenkins]\nurl = https://JENKINS_URL"
|
@@ -33,14 +36,22 @@ JJB_INI = "[jenkins]\nurl = https://JENKINS_URL"
|
|
33
36
|
class JJB:
|
34
37
|
"""Wrapper around Jenkins Jobs"""
|
35
38
|
|
36
|
-
def __init__(
|
39
|
+
def __init__(
|
40
|
+
self,
|
41
|
+
configs: list[dict[str, Any]],
|
42
|
+
ssl_verify: bool = True,
|
43
|
+
secret_reader: SecretReaderBase | None = None,
|
44
|
+
print_only: bool = False,
|
45
|
+
) -> None:
|
37
46
|
self.print_only = print_only
|
38
47
|
self.secret_reader = secret_reader
|
48
|
+
if not self.print_only and self.secret_reader is None:
|
49
|
+
raise ValueError("secret_reader must be provided if print_only is False")
|
39
50
|
self.collect_configs(configs)
|
40
51
|
self.modify_logger()
|
41
52
|
self.python_https_verify = str(int(ssl_verify))
|
42
53
|
|
43
|
-
def collect_configs(self, configs):
|
54
|
+
def collect_configs(self, configs: list[dict[str, Any]]) -> None:
|
44
55
|
instances = {
|
45
56
|
c["instance"]["name"]: {
|
46
57
|
"serverUrl": c["instance"]["serverUrl"],
|
@@ -57,7 +68,7 @@ class JJB:
|
|
57
68
|
server_url = data["serverUrl"]
|
58
69
|
wd = tempfile.mkdtemp()
|
59
70
|
ini = JJB_INI
|
60
|
-
if not self.print_only:
|
71
|
+
if not self.print_only and self.secret_reader:
|
61
72
|
ini = self.secret_reader.read(token)
|
62
73
|
ini = ini.replace('"', "")
|
63
74
|
ini = ini.replace("false", "False")
|
@@ -92,7 +103,7 @@ class JJB:
|
|
92
103
|
self.instance_urls = instance_urls
|
93
104
|
self.working_dirs = working_dirs
|
94
105
|
|
95
|
-
def overwrite_configs(self, configs):
|
106
|
+
def overwrite_configs(self, configs: Mapping[str, str] | State) -> None:
|
96
107
|
"""This function will override the existing
|
97
108
|
config files in the working directories with
|
98
109
|
the supplied configs"""
|
@@ -101,12 +112,12 @@ class JJB:
|
|
101
112
|
with open(config_path, "w", encoding="locale") as f:
|
102
113
|
f.write(configs[name])
|
103
114
|
|
104
|
-
def sort(self, configs):
|
115
|
+
def sort(self, configs: list[dict[str, Any]]) -> None:
|
105
116
|
configs.sort(key=self.sort_by_name)
|
106
|
-
configs.sort(key=self.sort_by_type)
|
117
|
+
configs.sort(key=lambda x: self.sort_by_type(x) or 0)
|
107
118
|
|
108
119
|
@staticmethod
|
109
|
-
def sort_by_type(config):
|
120
|
+
def sort_by_type(config: Mapping[str, Any]) -> int:
|
110
121
|
if config["type"] == "defaults":
|
111
122
|
return 0
|
112
123
|
if config["type"] == "global-defaults":
|
@@ -123,12 +134,13 @@ class JJB:
|
|
123
134
|
return 40
|
124
135
|
if config["type"] == "jobs":
|
125
136
|
return 50
|
137
|
+
return 100
|
126
138
|
|
127
139
|
@staticmethod
|
128
|
-
def sort_by_name(config):
|
140
|
+
def sort_by_name(config: Mapping[str, Any]) -> str:
|
129
141
|
return config["name"]
|
130
142
|
|
131
|
-
def get_configs(self):
|
143
|
+
def get_configs(self) -> dict[str, str]:
|
132
144
|
"""This function gets the configs from the
|
133
145
|
working directories"""
|
134
146
|
configs = {}
|
@@ -139,7 +151,7 @@ class JJB:
|
|
139
151
|
|
140
152
|
return configs
|
141
153
|
|
142
|
-
def generate(self, io_dir, fetch_state):
|
154
|
+
def generate(self, io_dir: str, fetch_state: str) -> None:
|
143
155
|
"""
|
144
156
|
Generates job definitions from JJB configs
|
145
157
|
|
@@ -163,7 +175,7 @@ class JJB:
|
|
163
175
|
self.execute(args)
|
164
176
|
throughput.change_files_ownership(io_dir)
|
165
177
|
|
166
|
-
def print_diffs(self, io_dir, instance_name=None):
|
178
|
+
def print_diffs(self, io_dir: str, instance_name: str | None = None) -> None:
|
167
179
|
"""Print the diffs between the current and
|
168
180
|
the desired job definitions"""
|
169
181
|
current_path = path.join(io_dir, "jjb", "current")
|
@@ -179,7 +191,7 @@ class JJB:
|
|
179
191
|
self.print_diff(delete, current_path, "delete")
|
180
192
|
self.print_diff(common, desired_path, "update")
|
181
193
|
|
182
|
-
def print_diff(self, files, replace_path, action):
|
194
|
+
def print_diff(self, files: Iterable[str], replace_path: str, action: str) -> None:
|
183
195
|
for f in files:
|
184
196
|
if action == "update":
|
185
197
|
ft = self.toggle_cd(f)
|
@@ -210,11 +222,16 @@ class JJB:
|
|
210
222
|
]
|
211
223
|
logging.debug("DIFF:\n" + "".join(diff))
|
212
224
|
|
213
|
-
def compare_files(
|
225
|
+
def compare_files(
|
226
|
+
self,
|
227
|
+
from_files: Iterable[str],
|
228
|
+
subtract_files: Iterable[str],
|
229
|
+
in_op: bool = False,
|
230
|
+
) -> list[str]:
|
214
231
|
return [f for f in from_files if (self.toggle_cd(f) in subtract_files) is in_op]
|
215
232
|
|
216
233
|
@staticmethod
|
217
|
-
def get_files(search_path, instance_name=None):
|
234
|
+
def get_files(search_path: str, instance_name: str | None = None) -> list[str]:
|
218
235
|
if instance_name is not None:
|
219
236
|
search_path = path.join(search_path, instance_name)
|
220
237
|
return [
|
@@ -222,7 +239,7 @@ class JJB:
|
|
222
239
|
]
|
223
240
|
|
224
241
|
@staticmethod
|
225
|
-
def toggle_cd(file_name):
|
242
|
+
def toggle_cd(file_name: str) -> str:
|
226
243
|
if "desired" in file_name:
|
227
244
|
return file_name.replace("desired", "current")
|
228
245
|
return file_name.replace("current", "desired")
|
@@ -248,28 +265,28 @@ class JJB:
|
|
248
265
|
raise
|
249
266
|
|
250
267
|
@staticmethod
|
251
|
-
def get_jjb(args):
|
268
|
+
def get_jjb(args: Iterable[str]) -> Any:
|
252
269
|
from jenkins_jobs.cli.entry import JenkinsJobs # noqa: PLC0415
|
253
270
|
|
254
271
|
return JenkinsJobs(args)
|
255
272
|
|
256
|
-
def execute(self, args):
|
273
|
+
def execute(self, args: Iterable[str]) -> None:
|
257
274
|
jjb = self.get_jjb(args)
|
258
275
|
with toggle_logger():
|
259
276
|
jjb.execute()
|
260
277
|
|
261
|
-
def modify_logger(self):
|
278
|
+
def modify_logger(self) -> None:
|
262
279
|
yaml.warnings({"YAMLLoadWarning": False})
|
263
280
|
formatter = logging.Formatter("%(levelname)s: %(message)s")
|
264
281
|
logger = logging.getLogger()
|
265
282
|
logger.handlers[0].setFormatter(formatter)
|
266
283
|
|
267
|
-
def cleanup(self):
|
284
|
+
def cleanup(self) -> None:
|
268
285
|
for wd in self.working_dirs.values():
|
269
286
|
shutil.rmtree(wd)
|
270
287
|
|
271
288
|
@retry(exceptions=(JenkinsJobsException))
|
272
|
-
def get_jobs(self, wd, name):
|
289
|
+
def get_jobs(self, wd: str, name: str) -> list[dict[str, Any]]:
|
273
290
|
ini_path = f"{wd}/{name}.ini"
|
274
291
|
config_path = f"{wd}/config.yaml"
|
275
292
|
|
@@ -283,8 +300,8 @@ class JJB:
|
|
283
300
|
|
284
301
|
return jobs
|
285
302
|
|
286
|
-
def get_job_webhooks_data(self):
|
287
|
-
job_webhooks_data = {}
|
303
|
+
def get_job_webhooks_data(self) -> dict[str, list[dict[str, Any]]]:
|
304
|
+
job_webhooks_data: dict[str, list[dict[str, Any]]] = {}
|
288
305
|
for name, wd in self.working_dirs.items():
|
289
306
|
jobs = self.get_jobs(wd, name)
|
290
307
|
|
@@ -313,7 +330,7 @@ class JJB:
|
|
313
330
|
|
314
331
|
return job_webhooks_data
|
315
332
|
|
316
|
-
def get_repos(self):
|
333
|
+
def get_repos(self) -> set[str]:
|
317
334
|
repos = set()
|
318
335
|
for name, wd in self.working_dirs.items():
|
319
336
|
jobs = self.get_jobs(wd, name)
|
@@ -325,7 +342,7 @@ class JJB:
|
|
325
342
|
logging.debug(f"missing github url: {job_name}")
|
326
343
|
return repos
|
327
344
|
|
328
|
-
def get_admins(self):
|
345
|
+
def get_admins(self) -> set[str]:
|
329
346
|
admins = set()
|
330
347
|
for name, wd in self.working_dirs.items():
|
331
348
|
jobs = self.get_jobs(wd, name)
|
@@ -340,15 +357,17 @@ class JJB:
|
|
340
357
|
return admins
|
341
358
|
|
342
359
|
@staticmethod
|
343
|
-
def get_repo_url(job):
|
360
|
+
def get_repo_url(job: Mapping[str, Any]) -> str:
|
344
361
|
repo_url_raw = job["properties"][0]["github"]["url"]
|
345
362
|
return repo_url_raw.strip("/").replace(".git", "")
|
346
363
|
|
347
364
|
@staticmethod
|
348
|
-
def get_ref(job:
|
365
|
+
def get_ref(job: Mapping[str, Any]) -> str:
|
349
366
|
return job["scm"][0]["git"]["branches"][0]
|
350
367
|
|
351
|
-
def get_all_jobs(
|
368
|
+
def get_all_jobs(
|
369
|
+
self, job_types: Iterable[str] | None = None, instance_name: str | None = None
|
370
|
+
) -> dict[str, list[dict[str, Any]]]:
|
352
371
|
if job_types is None:
|
353
372
|
job_types = []
|
354
373
|
all_jobs: dict[str, list[dict]] = {}
|
@@ -366,8 +385,8 @@ class JJB:
|
|
366
385
|
|
367
386
|
return all_jobs
|
368
387
|
|
369
|
-
def print_jobs(self, job_name=None):
|
370
|
-
all_jobs = {}
|
388
|
+
def print_jobs(self, job_name: str | None = None) -> None:
|
389
|
+
all_jobs: dict[str, list[dict[str, Any]]] = {}
|
371
390
|
found = False
|
372
391
|
for name, wd in self.working_dirs.items():
|
373
392
|
logging.debug(f"getting jobs from {name}")
|
@@ -394,7 +413,7 @@ class JJB:
|
|
394
413
|
raise ValueError(f"job with {job_type=} and {repo_url=} not found")
|
395
414
|
|
396
415
|
@staticmethod
|
397
|
-
def get_trigger_phrases_regex(job:
|
416
|
+
def get_trigger_phrases_regex(job: Mapping[str, Any]) -> str | None:
|
398
417
|
for trigger in job["triggers"]:
|
399
418
|
if "gitlab" in trigger:
|
400
419
|
return trigger["gitlab"].get("note-regex")
|
@@ -403,7 +422,7 @@ class JJB:
|
|
403
422
|
return None
|
404
423
|
|
405
424
|
@staticmethod
|
406
|
-
def get_gitlab_webhook_trigger(job:
|
425
|
+
def get_gitlab_webhook_trigger(job: Mapping[str, Any]) -> list[str]:
|
407
426
|
gitlab_triggers = job["triggers"][0]["gitlab"]
|
408
427
|
# pr-check job should be triggered by merge request events
|
409
428
|
# and certain comments: [test]|/retest|/lgtm|/lgtm cancel|/hold|/hold cancel
|
reconcile/utils/ldap_client.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
from collections import defaultdict
|
2
2
|
from collections.abc import Iterable
|
3
|
+
from typing import Any, Self
|
3
4
|
|
4
5
|
from ldap3 import (
|
5
6
|
ALL,
|
@@ -17,15 +18,15 @@ class LdapClient:
|
|
17
18
|
appropriately.
|
18
19
|
"""
|
19
20
|
|
20
|
-
def __init__(self, base_dn: str, connection: Connection):
|
21
|
+
def __init__(self, base_dn: str, connection: Connection) -> None:
|
21
22
|
self.base_dn = base_dn
|
22
23
|
self.connection = connection
|
23
24
|
|
24
|
-
def __enter__(self):
|
25
|
+
def __enter__(self) -> Self:
|
25
26
|
self.connection.bind()
|
26
27
|
return self
|
27
28
|
|
28
|
-
def __exit__(self, exc_type, exc_val, exc_tb):
|
29
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
29
30
|
self.connection.unbind()
|
30
31
|
|
31
32
|
def get_users(self, uids: Iterable[str]) -> set[str]:
|
@@ -6,7 +6,9 @@ from collections.abc import Mapping
|
|
6
6
|
from typing import Any
|
7
7
|
|
8
8
|
|
9
|
-
def state_rm_access_key(
|
9
|
+
def state_rm_access_key(
|
10
|
+
working_dirs: Mapping[str, str], account: str, user: str
|
11
|
+
) -> bool:
|
10
12
|
wd = working_dirs[account]
|
11
13
|
init_result = subprocess.run(["terraform", "init"], check=False, cwd=wd)
|
12
14
|
if init_result.returncode != 0:
|
reconcile/utils/ocm/ocm.py
CHANGED
@@ -21,7 +21,7 @@ from reconcile.utils.ocm_base_client import (
|
|
21
21
|
from reconcile.utils.secret_reader import SecretReader
|
22
22
|
|
23
23
|
if TYPE_CHECKING:
|
24
|
-
from collections.abc import Mapping
|
24
|
+
from collections.abc import Iterable, Mapping, MutableMapping
|
25
25
|
|
26
26
|
from reconcile.ocm.types import OCMSpec
|
27
27
|
|
@@ -83,13 +83,13 @@ class OCM:
|
|
83
83
|
|
84
84
|
def __init__(
|
85
85
|
self,
|
86
|
-
name,
|
87
|
-
org_id,
|
86
|
+
name: str,
|
87
|
+
org_id: str,
|
88
88
|
ocm_env: str,
|
89
89
|
ocm_client: OCMBaseClient,
|
90
|
-
init_provision_shards=False,
|
91
|
-
init_addons=False,
|
92
|
-
init_version_gates=False,
|
90
|
+
init_provision_shards: bool = False,
|
91
|
+
init_addons: bool = False,
|
92
|
+
init_version_gates: bool = False,
|
93
93
|
product_portfolio: OCMProductPortfolio | None = None,
|
94
94
|
):
|
95
95
|
"""Initiates access token and gets clusters information."""
|
@@ -130,7 +130,7 @@ class OCM:
|
|
130
130
|
and cluster["product"]["id"] in self.product_portfolio.product_names
|
131
131
|
)
|
132
132
|
|
133
|
-
def _init_clusters(self, init_provision_shards: bool):
|
133
|
+
def _init_clusters(self, init_provision_shards: bool) -> None:
|
134
134
|
api = f"{CS_API_BASE}/v1/clusters"
|
135
135
|
product_csv = ",".join([f"'{p}'" for p in self.product_portfolio.product_names])
|
136
136
|
params = {
|
@@ -168,19 +168,19 @@ class OCM:
|
|
168
168
|
spec = impl.get_ocm_spec(self.ocm_api, cluster, init_provision_shards)
|
169
169
|
return spec
|
170
170
|
|
171
|
-
def create_cluster(self, name: str, cluster: OCMSpec, dry_run: bool):
|
171
|
+
def create_cluster(self, name: str, cluster: OCMSpec, dry_run: bool) -> None:
|
172
172
|
impl = self.get_product_impl(cluster.spec.product, cluster.spec.hypershift)
|
173
173
|
impl.create_cluster(self.ocm_api, self.org_id, name, cluster, dry_run)
|
174
174
|
|
175
175
|
def update_cluster(
|
176
|
-
self, cluster_name: str, update_spec: Mapping[str, Any], dry_run=False
|
177
|
-
):
|
176
|
+
self, cluster_name: str, update_spec: Mapping[str, Any], dry_run: bool = False
|
177
|
+
) -> None:
|
178
178
|
cluster = self.clusters[cluster_name]
|
179
179
|
cluster_id = self.cluster_ids[cluster_name]
|
180
180
|
impl = self.get_product_impl(cluster.spec.product, cluster.spec.hypershift)
|
181
181
|
impl.update_cluster(self.ocm_api, cluster_id, update_spec, dry_run)
|
182
182
|
|
183
|
-
def get_group_if_exists(self, cluster, group_id):
|
183
|
+
def get_group_if_exists(self, cluster: str, group_id: str) -> dict[str, Any] | None:
|
184
184
|
"""Returns a list of users in a group in a cluster.
|
185
185
|
If the group does not exist, None will be returned.
|
186
186
|
|
@@ -202,7 +202,7 @@ class OCM:
|
|
202
202
|
users = self._get_json(api).get("items", [])
|
203
203
|
return {"users": [u["id"] for u in users]}
|
204
204
|
|
205
|
-
def add_user_to_group(self, cluster, group_id, user):
|
205
|
+
def add_user_to_group(self, cluster: str, group_id: str, user: str) -> None:
|
206
206
|
"""
|
207
207
|
Adds a user to a group in a cluster.
|
208
208
|
|
@@ -218,7 +218,7 @@ class OCM:
|
|
218
218
|
api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/" + f"groups/{group_id}/users"
|
219
219
|
self._post(api, {"id": user})
|
220
220
|
|
221
|
-
def del_user_from_group(self, cluster, group_id, user_id):
|
221
|
+
def del_user_from_group(self, cluster: str, group_id: str, user_id: str) -> None:
|
222
222
|
"""Deletes a user from a group in a cluster.
|
223
223
|
|
224
224
|
:param cluster: cluster name
|
@@ -250,7 +250,9 @@ class OCM:
|
|
250
250
|
switch_role_link = role_grants[0][-1]
|
251
251
|
return awsh.get_account_uid_from_role_link(switch_role_link)
|
252
252
|
|
253
|
-
def get_aws_infrastructure_access_role_grants(
|
253
|
+
def get_aws_infrastructure_access_role_grants(
|
254
|
+
self, cluster: str
|
255
|
+
) -> list[tuple[str, str, str, str]]:
|
254
256
|
"""Returns a list of AWS users (ARN, access level)
|
255
257
|
who have AWS infrastructure access in a cluster.
|
256
258
|
|
@@ -272,8 +274,8 @@ class OCM:
|
|
272
274
|
]
|
273
275
|
|
274
276
|
def get_aws_infrastructure_access_terraform_assume_role(
|
275
|
-
self, cluster, tf_account_id, tf_user
|
276
|
-
):
|
277
|
+
self, cluster: str, tf_account_id: str, tf_user: str | None
|
278
|
+
) -> str | None:
|
277
279
|
role_grants = self.get_aws_infrastructure_access_role_grants(cluster)
|
278
280
|
user_arn = f"arn:aws:iam::{tf_account_id}:user/{tf_user}"
|
279
281
|
for arn, role_id, _, console_url in role_grants:
|
@@ -288,9 +290,11 @@ class OCM:
|
|
288
290
|
role_name = role.replace("roleName=", "")
|
289
291
|
return f"arn:aws:iam::{role_account_id}:role/{role_name}"
|
290
292
|
|
293
|
+
return None
|
294
|
+
|
291
295
|
def add_user_to_aws_infrastructure_access_role_grants(
|
292
|
-
self, cluster, user_arn, access_level
|
293
|
-
):
|
296
|
+
self, cluster: str, user_arn: str, access_level: str
|
297
|
+
) -> None:
|
294
298
|
"""
|
295
299
|
Adds a user to AWS infrastructure access in a cluster.
|
296
300
|
|
@@ -310,8 +314,8 @@ class OCM:
|
|
310
314
|
self._post(api, {"user_arn": user_arn, "role": {"id": access_level}})
|
311
315
|
|
312
316
|
def del_user_from_aws_infrastructure_access_role_grants(
|
313
|
-
self, cluster, user_arn, access_level
|
314
|
-
):
|
317
|
+
self, cluster: str, user_arn: str, access_level: str
|
318
|
+
) -> None:
|
315
319
|
"""
|
316
320
|
Deletes a user from AWS infrastructure access in a cluster.
|
317
321
|
|
@@ -375,7 +379,9 @@ class OCM:
|
|
375
379
|
|
376
380
|
return results
|
377
381
|
|
378
|
-
def create_external_configuration_label(
|
382
|
+
def create_external_configuration_label(
|
383
|
+
self, cluster: str, label: dict[str, str]
|
384
|
+
) -> None:
|
379
385
|
"""Creates a new External Configuration label
|
380
386
|
|
381
387
|
:param cluster: cluster name
|
@@ -390,7 +396,9 @@ class OCM:
|
|
390
396
|
)
|
391
397
|
self._post(api, label)
|
392
398
|
|
393
|
-
def delete_external_configuration_label(
|
399
|
+
def delete_external_configuration_label(
|
400
|
+
self, cluster: str, label: Mapping[str, str]
|
401
|
+
) -> None:
|
394
402
|
"""Deletes an existing External Configuration label
|
395
403
|
|
396
404
|
:param cluster: cluster name
|
@@ -414,14 +422,9 @@ class OCM:
|
|
414
422
|
)
|
415
423
|
self._delete(api)
|
416
424
|
|
417
|
-
def get_machine_pools(self, cluster):
|
418
|
-
"""Returns a list of details of Machine Pools
|
419
|
-
|
420
|
-
:param cluster: cluster name
|
421
|
-
|
422
|
-
:type cluster: string
|
423
|
-
"""
|
424
|
-
results = []
|
425
|
+
def get_machine_pools(self, cluster: str) -> list[dict[str, Any]]:
|
426
|
+
"""Returns a list of details of Machine Pools"""
|
427
|
+
results: list[dict[str, Any]] = []
|
425
428
|
cluster_id = self.cluster_ids.get(cluster)
|
426
429
|
if not cluster_id:
|
427
430
|
return results
|
@@ -436,7 +439,7 @@ class OCM:
|
|
436
439
|
|
437
440
|
return results
|
438
441
|
|
439
|
-
def create_machine_pool(self, cluster, spec):
|
442
|
+
def create_machine_pool(self, cluster: str, spec: Mapping[str, Any]) -> None:
|
440
443
|
"""Creates a new Machine Pool
|
441
444
|
|
442
445
|
:param cluster: cluster name
|
@@ -449,7 +452,7 @@ class OCM:
|
|
449
452
|
api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/machine_pools"
|
450
453
|
self._post(api, spec)
|
451
454
|
|
452
|
-
def update_machine_pool(self, cluster, spec):
|
455
|
+
def update_machine_pool(self, cluster: str, spec: MutableMapping[str, Any]) -> None:
|
453
456
|
"""Updates an existing Machine Pool
|
454
457
|
|
455
458
|
:param cluster: cluster name
|
@@ -460,7 +463,7 @@ class OCM:
|
|
460
463
|
"""
|
461
464
|
cluster_id = self.cluster_ids[cluster]
|
462
465
|
machine_pool_id = spec["id"]
|
463
|
-
labels = spec.get("labels", {})
|
466
|
+
labels: dict[str, str] = spec.get("labels", {})
|
464
467
|
spec["labels"] = labels
|
465
468
|
api = (
|
466
469
|
f"{CS_API_BASE}/v1/clusters/{cluster_id}/machine_pools/"
|
@@ -468,7 +471,7 @@ class OCM:
|
|
468
471
|
)
|
469
472
|
self._patch(api, spec)
|
470
473
|
|
471
|
-
def delete_machine_pool(self, cluster, spec):
|
474
|
+
def delete_machine_pool(self, cluster: str, spec: Mapping[str, Any]) -> None:
|
472
475
|
"""Deletes an existing Machine Pool
|
473
476
|
|
474
477
|
:param cluster: cluster name
|
@@ -485,21 +488,21 @@ class OCM:
|
|
485
488
|
)
|
486
489
|
self._delete(api)
|
487
490
|
|
488
|
-
def get_node_pools(self, cluster):
|
491
|
+
def get_node_pools(self, cluster: str) -> list[dict[str, Any]]:
|
489
492
|
"""Returns a list of details of Node Pools
|
490
493
|
|
491
494
|
:param cluster: cluster name
|
492
495
|
|
493
496
|
:type cluster: string
|
494
497
|
"""
|
495
|
-
results = []
|
498
|
+
results: list[dict[str, Any]] = []
|
496
499
|
cluster_id = self.cluster_ids.get(cluster)
|
497
500
|
if not cluster_id:
|
498
501
|
return results
|
499
502
|
|
500
503
|
return get_node_pools(self._ocm_client, cluster_id)
|
501
504
|
|
502
|
-
def delete_node_pool(self, cluster, spec):
|
505
|
+
def delete_node_pool(self, cluster: str, spec: Mapping[str, Any]) -> None:
|
503
506
|
"""Deletes an existing Node Pool
|
504
507
|
|
505
508
|
:param cluster: cluster name
|
@@ -513,7 +516,7 @@ class OCM:
|
|
513
516
|
api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/node_pools/" + f"{node_pool_id}"
|
514
517
|
self._delete(api)
|
515
518
|
|
516
|
-
def create_node_pool(self, cluster, spec):
|
519
|
+
def create_node_pool(self, cluster: str, spec: Mapping[str, Any]) -> None:
|
517
520
|
"""Creates a new Node Pool
|
518
521
|
|
519
522
|
:param cluster: cluster name
|
@@ -526,7 +529,7 @@ class OCM:
|
|
526
529
|
api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/node_pools"
|
527
530
|
self._post(api, spec)
|
528
531
|
|
529
|
-
def update_node_pool(self, cluster, spec):
|
532
|
+
def update_node_pool(self, cluster: str, spec: MutableMapping[str, Any]) -> None:
|
530
533
|
"""Updates an existing Node Pool
|
531
534
|
|
532
535
|
:param cluster: cluster name
|
@@ -537,19 +540,19 @@ class OCM:
|
|
537
540
|
"""
|
538
541
|
cluster_id = self.cluster_ids[cluster]
|
539
542
|
node_pool_id = spec["id"]
|
540
|
-
labels = spec.get("labels", {})
|
543
|
+
labels: dict[str, str] = spec.get("labels", {})
|
541
544
|
spec["labels"] = labels
|
542
545
|
api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/node_pools/" + f"{node_pool_id}"
|
543
546
|
self._patch(api, spec)
|
544
547
|
|
545
|
-
def get_additional_routers(self, cluster):
|
548
|
+
def get_additional_routers(self, cluster: str) -> list[dict[str, Any]]:
|
546
549
|
"""Returns a list of Additional Application Routers
|
547
550
|
|
548
551
|
:param cluster: cluster name
|
549
552
|
|
550
553
|
:type cluster: string
|
551
554
|
"""
|
552
|
-
results = []
|
555
|
+
results: list[dict[str, Any]] = []
|
553
556
|
cluster_id = self.cluster_ids.get(cluster)
|
554
557
|
if not cluster_id:
|
555
558
|
return results
|
@@ -567,7 +570,7 @@ class OCM:
|
|
567
570
|
|
568
571
|
return results
|
569
572
|
|
570
|
-
def create_additional_router(self, cluster, spec):
|
573
|
+
def create_additional_router(self, cluster: str, spec: Mapping[str, Any]) -> None:
|
571
574
|
"""Creates a new Additional Application Router
|
572
575
|
|
573
576
|
:param cluster: cluster name
|
@@ -580,7 +583,7 @@ class OCM:
|
|
580
583
|
api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/ingresses"
|
581
584
|
self._post(api, spec)
|
582
585
|
|
583
|
-
def delete_additional_router(self, cluster, spec):
|
586
|
+
def delete_additional_router(self, cluster: str, spec: Mapping[str, Any]) -> None:
|
584
587
|
"""Deletes an existing Additional Application Router
|
585
588
|
|
586
589
|
:param cluster: cluster name
|
@@ -594,19 +597,19 @@ class OCM:
|
|
594
597
|
api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/" + f"ingresses/{router_id}"
|
595
598
|
self._delete(api)
|
596
599
|
|
597
|
-
def _init_addons(self):
|
600
|
+
def _init_addons(self) -> None:
|
598
601
|
"""Returns a list of Addons"""
|
599
602
|
api = f"{CS_API_BASE}/v1/addons"
|
600
603
|
self.addons = self._get_json(api).get("items", [])
|
601
604
|
|
602
|
-
def _init_version_gates(self):
|
605
|
+
def _init_version_gates(self) -> None:
|
603
606
|
"""Returns a list of version gates"""
|
604
607
|
if self.version_gates:
|
605
608
|
return
|
606
609
|
api = f"{CS_API_BASE}/v1/version_gates"
|
607
610
|
self.version_gates = self._get_json(api).get("items", [])
|
608
611
|
|
609
|
-
def get_addon(self, id):
|
612
|
+
def get_addon(self, id: str) -> dict[str, Any] | None:
|
610
613
|
for addon in self.addons:
|
611
614
|
addon_id = addon["id"]
|
612
615
|
if id == addon_id:
|
@@ -652,7 +655,7 @@ class OCM:
|
|
652
655
|
|
653
656
|
return results
|
654
657
|
|
655
|
-
def install_addon(self, cluster, spec):
|
658
|
+
def install_addon(self, cluster: str, spec: MutableMapping[str, Any]) -> None:
|
656
659
|
"""Installs an addon on a cluster
|
657
660
|
|
658
661
|
:param cluster: cluster name
|
@@ -714,21 +717,28 @@ class OCM:
|
|
714
717
|
return ret_items
|
715
718
|
return responses[0]
|
716
719
|
|
717
|
-
def _post(
|
720
|
+
def _post(
|
721
|
+
self,
|
722
|
+
api: str,
|
723
|
+
data: Mapping[str, Any] | None = None,
|
724
|
+
params: Mapping[str, str] | None = None,
|
725
|
+
) -> Any:
|
718
726
|
return self._ocm_client.post(
|
719
727
|
api_path=api,
|
720
728
|
data=data,
|
721
729
|
params=params,
|
722
730
|
)
|
723
731
|
|
724
|
-
def _patch(
|
732
|
+
def _patch(
|
733
|
+
self, api: str, data: Mapping[str, Any], params: Mapping[str, str] | None = None
|
734
|
+
) -> None:
|
725
735
|
return self._ocm_client.patch(
|
726
736
|
api_path=api,
|
727
737
|
data=data,
|
728
738
|
params=params,
|
729
739
|
)
|
730
740
|
|
731
|
-
def _delete(self, api):
|
741
|
+
def _delete(self, api: str) -> None:
|
732
742
|
return self._ocm_client.delete(
|
733
743
|
api_path=api,
|
734
744
|
)
|
@@ -762,14 +772,14 @@ class OCMMap:
|
|
762
772
|
|
763
773
|
def __init__(
|
764
774
|
self,
|
765
|
-
clusters=None,
|
766
|
-
namespaces=None,
|
767
|
-
ocms=None,
|
768
|
-
integration="",
|
769
|
-
settings=None,
|
770
|
-
init_provision_shards=False,
|
771
|
-
init_addons=False,
|
772
|
-
init_version_gates=False,
|
775
|
+
clusters: Iterable[Mapping[str, Any]] | None = None,
|
776
|
+
namespaces: Iterable[Mapping[str, Any]] | None = None,
|
777
|
+
ocms: Iterable[Mapping[str, Any]] | None = None,
|
778
|
+
integration: str = "",
|
779
|
+
settings: Mapping[str, Any] | None = None,
|
780
|
+
init_provision_shards: bool = False,
|
781
|
+
init_addons: bool = False,
|
782
|
+
init_version_gates: bool = False,
|
773
783
|
product_portfolio: OCMProductPortfolio | None = None,
|
774
784
|
) -> None:
|
775
785
|
"""Initiates OCM instances for each OCM referenced in a cluster."""
|
@@ -817,12 +827,12 @@ class OCMMap:
|
|
817
827
|
|
818
828
|
def init_ocm_client_from_cluster(
|
819
829
|
self,
|
820
|
-
cluster_info,
|
821
|
-
init_provision_shards,
|
822
|
-
init_addons,
|
823
|
-
init_version_gates,
|
830
|
+
cluster_info: Mapping[str, Any],
|
831
|
+
init_provision_shards: bool,
|
832
|
+
init_addons: bool,
|
833
|
+
init_version_gates: bool,
|
824
834
|
product_portfolio: OCMProductPortfolio | None = None,
|
825
|
-
):
|
835
|
+
) -> None:
|
826
836
|
if self.cluster_disabled(cluster_info):
|
827
837
|
return
|
828
838
|
cluster_name = cluster_info["name"]
|
@@ -842,12 +852,12 @@ class OCMMap:
|
|
842
852
|
|
843
853
|
def init_ocm_client(
|
844
854
|
self,
|
845
|
-
ocm_info,
|
846
|
-
init_provision_shards,
|
847
|
-
init_addons,
|
848
|
-
init_version_gates,
|
855
|
+
ocm_info: Mapping[str, Any],
|
856
|
+
init_provision_shards: bool,
|
857
|
+
init_addons: bool,
|
858
|
+
init_version_gates: bool,
|
849
859
|
product_portfolio: OCMProductPortfolio | None = None,
|
850
|
-
):
|
860
|
+
) -> None:
|
851
861
|
"""
|
852
862
|
Initiate OCM client.
|
853
863
|
Gets the OCM information and initiates an OCM client.
|
@@ -901,7 +911,7 @@ class OCMMap:
|
|
901
911
|
"""Get list of OCM instance names initiated in the OCM map."""
|
902
912
|
return list(self.ocm_map.keys())
|
903
913
|
|
904
|
-
def cluster_disabled(self, cluster_info):
|
914
|
+
def cluster_disabled(self, cluster_info: Mapping[str, Any]) -> bool:
|
905
915
|
"""
|
906
916
|
Checks if the calling integration is disabled in this cluster.
|
907
917
|
|
@@ -918,7 +928,7 @@ class OCMMap:
|
|
918
928
|
|
919
929
|
return False
|
920
930
|
|
921
|
-
def get(self, cluster) -> OCM:
|
931
|
+
def get(self, cluster: str) -> OCM:
|
922
932
|
"""
|
923
933
|
Gets an OCM instance by cluster.
|
924
934
|
|
@@ -49,7 +49,7 @@ class OCMBaseClient:
|
|
49
49
|
self._init_request_headers()
|
50
50
|
|
51
51
|
@retry()
|
52
|
-
def _init_access_token(self):
|
52
|
+
def _init_access_token(self) -> None:
|
53
53
|
data = {
|
54
54
|
"grant_type": "client_credentials",
|
55
55
|
"client_id": self._access_token_client_id,
|
@@ -61,7 +61,7 @@ class OCMBaseClient:
|
|
61
61
|
r.raise_for_status()
|
62
62
|
self._access_token = r.json().get("access_token")
|
63
63
|
|
64
|
-
def _init_request_headers(self):
|
64
|
+
def _init_request_headers(self) -> None:
|
65
65
|
self._session.headers.update({
|
66
66
|
"Authorization": f"Bearer {self._access_token}",
|
67
67
|
"accept": "application/json",
|
@@ -130,7 +130,7 @@ class OCMBaseClient:
|
|
130
130
|
api_path: str,
|
131
131
|
data: Mapping[str, Any],
|
132
132
|
params: Mapping[str, str] | None = None,
|
133
|
-
):
|
133
|
+
) -> None:
|
134
134
|
ocm_request.labels(verb="PATCH", client_id=self._access_token_client_id).inc()
|
135
135
|
r = self._session.patch(
|
136
136
|
f"{self._url}{api_path}",
|
@@ -144,7 +144,7 @@ class OCMBaseClient:
|
|
144
144
|
logging.error(r.text)
|
145
145
|
raise e
|
146
146
|
|
147
|
-
def delete(self, api_path: str):
|
147
|
+
def delete(self, api_path: str) -> None:
|
148
148
|
ocm_request.labels(verb="DELETE", client_id=self._access_token_client_id).inc()
|
149
149
|
r = self._session.delete(f"{self._url}{api_path}", timeout=REQUEST_TIMEOUT_SEC)
|
150
150
|
try:
|
@@ -1,8 +1,11 @@
|
|
1
1
|
import os
|
2
|
+
from typing import Any
|
2
3
|
|
3
4
|
import requests
|
4
5
|
from sretoolbox.utils import retry
|
5
6
|
|
7
|
+
Headers = dict[str, str | bytes | None]
|
8
|
+
|
6
9
|
|
7
10
|
class RawGithubApi:
|
8
11
|
"""
|
@@ -18,10 +21,10 @@ class RawGithubApi:
|
|
18
21
|
"application/vnd.github.dazzler-preview+json"
|
19
22
|
}
|
20
23
|
|
21
|
-
def __init__(self, password):
|
24
|
+
def __init__(self, password: str) -> None:
|
22
25
|
self.password = password
|
23
26
|
|
24
|
-
def headers(self, headers=None):
|
27
|
+
def headers(self, headers: Headers | None = None) -> Headers:
|
25
28
|
if headers is None:
|
26
29
|
headers = {}
|
27
30
|
new_headers = headers.copy()
|
@@ -29,13 +32,13 @@ class RawGithubApi:
|
|
29
32
|
new_headers["Authorization"] = "token %s" % (self.password,)
|
30
33
|
return new_headers
|
31
34
|
|
32
|
-
def patch(self, url):
|
35
|
+
def patch(self, url: str) -> requests.Response:
|
33
36
|
res = requests.patch(url, headers=self.headers(), timeout=60)
|
34
37
|
res.raise_for_status()
|
35
38
|
return res
|
36
39
|
|
37
40
|
@retry()
|
38
|
-
def query(self, url, headers=None):
|
41
|
+
def query(self, url: str, headers: Headers | None = None) -> Any:
|
39
42
|
if headers is None:
|
40
43
|
headers = {}
|
41
44
|
h = self.headers(headers)
|
@@ -64,7 +67,7 @@ class RawGithubApi:
|
|
64
67
|
|
65
68
|
return result
|
66
69
|
|
67
|
-
def org_invitations(self, org):
|
70
|
+
def org_invitations(self, org: str) -> list[str]:
|
68
71
|
invitations = self.query(f"/orgs/{org}/invitations")
|
69
72
|
|
70
73
|
return [
|
@@ -73,7 +76,7 @@ class RawGithubApi:
|
|
73
76
|
if login is not None
|
74
77
|
]
|
75
78
|
|
76
|
-
def team_invitations(self, org_id, team_id):
|
79
|
+
def team_invitations(self, org_id: str, team_id: str) -> list[str]:
|
77
80
|
invitations = self.query(f"/organizations/{org_id}/team/{team_id}/invitations")
|
78
81
|
|
79
82
|
return [
|
@@ -82,10 +85,10 @@ class RawGithubApi:
|
|
82
85
|
if login is not None
|
83
86
|
]
|
84
87
|
|
85
|
-
def repo_invitations(self):
|
88
|
+
def repo_invitations(self) -> list[dict[str, Any]]:
|
86
89
|
return self.query("/user/repository_invitations")
|
87
90
|
|
88
|
-
def accept_repo_invitation(self, invitation_id):
|
91
|
+
def accept_repo_invitation(self, invitation_id: int) -> None:
|
89
92
|
url = self.BASE_URL + f"/user/repository_invitations/{invitation_id}"
|
90
93
|
res = self.patch(url)
|
91
94
|
res.raise_for_status()
|
@@ -114,7 +114,7 @@ class GPGEncryptCommand:
|
|
114
114
|
f"No argument given which defines how to fetch the secret {self._command_data}"
|
115
115
|
)
|
116
116
|
|
117
|
-
def _get_gpg_key(self) -> str
|
117
|
+
def _get_gpg_key(self) -> str:
|
118
118
|
target_user = self._command_data.target_user
|
119
119
|
users = queries.get_users_by(
|
120
120
|
refs=False,
|
reconcile/jenkins/__init__.py
DELETED
File without changes
|
reconcile/jenkins/types.py
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
from enum import Enum
|
4
|
-
|
5
|
-
from pydantic import (
|
6
|
-
BaseModel,
|
7
|
-
Field,
|
8
|
-
)
|
9
|
-
|
10
|
-
|
11
|
-
class SSHHostKeyVerificationStrategy(Enum):
|
12
|
-
MANUALLY_TRUSTED_KEY_VERIFICATION_STRATEGY = (
|
13
|
-
"manuallyTrustedKeyVerificationStrategy"
|
14
|
-
)
|
15
|
-
MANUALLY_PROVIDED_KEY_VERIFICATION_STRATEGY = (
|
16
|
-
"manuallyProvidedKeyVerificationStrategy"
|
17
|
-
)
|
18
|
-
NON_VERIFYING_KEY_VERIFICATION_STRATEGY = "nonVerifyingKeyVerificationStrategy"
|
19
|
-
KNOWN_HOSTS_FILE_KEY_VERIFICATION_STRATEGY = "knownHostsFileKeyVerificationStrategy"
|
20
|
-
|
21
|
-
|
22
|
-
class SSHConnector(BaseModel):
|
23
|
-
credentials_id: str = Field(..., alias="credentialsId")
|
24
|
-
launch_timeout_seconds: int | None = Field(None, alias="launchTimeoutSeconds")
|
25
|
-
max_num_retries: int | None = Field(None, alias="maxNumRetries")
|
26
|
-
retry_wait_time: int | None = Field(None, alias="retryWaitTime")
|
27
|
-
port: int | None = 22
|
28
|
-
jvm_options: str | None = Field(None, alias="jvmOptions")
|
29
|
-
ssh_host_key_verification_strategy: SSHHostKeyVerificationStrategy = Field(
|
30
|
-
SSHHostKeyVerificationStrategy.NON_VERIFYING_KEY_VERIFICATION_STRATEGY,
|
31
|
-
alias="sshHostKeyVerificationStrategy",
|
32
|
-
)
|
33
|
-
|
34
|
-
class Config:
|
35
|
-
use_enum_values = True
|
36
|
-
|
37
|
-
|
38
|
-
class ComputerConnector(BaseModel):
|
39
|
-
# alias name is defined by jcasc schema
|
40
|
-
ssh_connector: SSHConnector = Field(..., alias="sSHConnector")
|
41
|
-
|
42
|
-
|
43
|
-
class JenkinsWorkerFleet(BaseModel):
|
44
|
-
# following options comes form https://github.com/jenkinsci/ec2-fleet-plugin/blob/master/docs/
|
45
|
-
name: str
|
46
|
-
fleet: str
|
47
|
-
region: str
|
48
|
-
min_size: int = Field(..., alias="minSize")
|
49
|
-
max_size: int = Field(..., alias="maxSize")
|
50
|
-
computer_connector: ComputerConnector = Field(..., alias="computerConnector")
|
51
|
-
fs_root: str = Field(..., alias="fsRoot")
|
52
|
-
label_string: str = Field(..., alias="labelString")
|
53
|
-
num_executors: int = Field(2, alias="numExecutors")
|
54
|
-
idle_minutes: int = Field(30, alias="idleMinutes")
|
55
|
-
min_spare_size: int = Field(0, alias="minSpareSize")
|
56
|
-
max_total_uses: int = Field(-1, alias="maxTotalUses")
|
57
|
-
no_delay_provision: bool = Field(False, alias="noDelayProvision")
|
58
|
-
add_node_only_if_running: bool = Field(True, alias="addNodeOnlyIfRunning")
|
59
|
-
always_reconnect: bool = Field(True, alias="alwaysReconnect")
|
60
|
-
private_ip_used: bool = Field(True, alias="privateIpUsed")
|
61
|
-
restrict_usage: bool = Field(True, alias="restrictUsage")
|
62
|
-
|
63
|
-
def __lt__(self, other: JenkinsWorkerFleet) -> bool:
|
64
|
-
return self.fleet < other.fleet
|
65
|
-
|
66
|
-
def __eq__(self, other: object) -> bool:
|
67
|
-
if not isinstance(other, JenkinsWorkerFleet):
|
68
|
-
raise NotImplementedError(
|
69
|
-
"Cannot compare to non JenkinsWorkerFleet objects."
|
70
|
-
)
|
71
|
-
return self.fleet == other.fleet and self.region == other.region
|
72
|
-
|
73
|
-
def __hash__(self) -> int:
|
74
|
-
return hash(self.fleet + self.region)
|
75
|
-
|
76
|
-
def differ(self, other: JenkinsWorkerFleet) -> bool:
|
77
|
-
return self.dict() != other.dict()
|
{qontract_reconcile-0.10.2.dev317.dist-info → qontract_reconcile-0.10.2.dev319.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|