qontract-reconcile 0.10.2.dev456__py3-none-any.whl → 0.10.2.dev473__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.

Potentially problematic release.


This version of qontract-reconcile might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qontract-reconcile
3
- Version: 0.10.2.dev456
3
+ Version: 0.10.2.dev473
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
@@ -18,7 +18,7 @@ Requires-Dist: botocore==1.34.94
18
18
  Requires-Dist: click<9.0,>=7.0
19
19
  Requires-Dist: croniter<1.1.0,>=1.0.15
20
20
  Requires-Dist: dateparser~=1.1.7
21
- Requires-Dist: deepdiff==6.7.1
21
+ Requires-Dist: deepdiff==8.6.1
22
22
  Requires-Dist: dnspython~=2.1
23
23
  Requires-Dist: dt==1.1.73
24
24
  Requires-Dist: filetype~=1.2.0
@@ -82,13 +82,13 @@ reconcile/openshift_tekton_resources.py,sha256=5mUWEQqU9RpMLQZxHOb6IkbbZzx4iJnaV
82
82
  reconcile/openshift_upgrade_watcher.py,sha256=93l8X1-RHNtL89GzPg1XWivWart49l_hpAVFChvT6Wg,6643
83
83
  reconcile/openshift_users.py,sha256=lxHYrOhKntLnRy5mVZfh_8XWvwZaUgzrDNqkoon905U,5508
84
84
  reconcile/openshift_vault_secrets.py,sha256=Ax-_EBWWU1VRHYyKaUkGJkIjHGwWM3bZgjXL5CkPW8k,1883
85
- reconcile/quay_base.py,sha256=hfHv8ET6iw0GqPyncYJMRH7YFwJc5E1C9z7zET5MCjo,2327
86
- reconcile/quay_membership.py,sha256=No2sgEyTVj-hr5VPLy_xdrYAPvt-xo-CPpOt0X3x_6o,6623
85
+ reconcile/quay_base.py,sha256=4gNca076ICJ2fDoTwCgcA3L-DqmVmBgHWLCubTk78uc,2832
86
+ reconcile/quay_membership.py,sha256=ul4KcEdarri0WzH3ZBHzXup7oF9MhGLDpCyHtfxuuZ0,6844
87
87
  reconcile/quay_mirror.py,sha256=vhPL44TMEsritkiJhNQLf2Ir45RLApdO_mh3aZV0OuI,14334
88
- reconcile/quay_mirror_org.py,sha256=ltPbHuWUI8Wnl8gV4aeYmvoYFA1uXLWqlXqEPpw7Hi0,11065
89
- reconcile/quay_permissions.py,sha256=BF539lRxjpgwm88WzazklzgaCF_ipRALwbO2AdpqUqE,4388
90
- reconcile/quay_repos.py,sha256=fBleLzMtfDmTidpzbrTt8kGCy-Bk3J06EO4hhyghGnQ,7570
91
- reconcile/queries.py,sha256=L0NbIr6-M12P7xqU2s_2-tgi5BOC5QEo6Otu33WG5tI,56598
88
+ reconcile/quay_mirror_org.py,sha256=9YeOpRsuTOWxnql1oj-rbUAkb_aGSlzmHVbMyLhSalM,11092
89
+ reconcile/quay_permissions.py,sha256=wsQZ5wi2jrlTlV3Aq3dn_mJpjMlcjnjVvFNflBFBdGk,4706
90
+ reconcile/quay_repos.py,sha256=JpR9vyvDIdKfP4EwLw1c2X53LOjLZY35pJ8AvNxZIGo,7674
91
+ reconcile/queries.py,sha256=nEko5_luE4Xoj-nBI1XEX3YRcxfAObtvqZbN7LSlJVY,56597
92
92
  reconcile/query_validator.py,sha256=csOSkKxcf6ZlpchJu4ck2jLYKUN6y1l-UmSQUFHgssY,1618
93
93
  reconcile/requests_sender.py,sha256=g-tlrudvIqhneQPDMrfYF0Xsq7BSW2QcBPirl7hFM6I,4058
94
94
  reconcile/resource_scraper.py,sha256=TcMhXga7konX9x97NhpoijnDGWA-ZjdpiiXjm5qCmPk,2249
@@ -118,7 +118,7 @@ reconcile/aus/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
118
118
  reconcile/aus/advanced_upgrade_service.py,sha256=byOl5wtDRG_VJiN50IM3dwA9vQz39ibSEh9uY5HI9jE,24201
119
119
  reconcile/aus/aus_label_source.py,sha256=o0S2f0qwcII_8nzhHZhRQ83gEZ1DrSXyO4xzSwLebuU,4382
120
120
  reconcile/aus/aus_sts_gate_handler.py,sha256=7MDHtd4G_t3_ItcnpfpqN7sI6QbFNJEFGJOibfALI-o,2075
121
- reconcile/aus/base.py,sha256=ph9gxWQ5JcusY9S8gAa1Lz1Z_1rd_0W6w_aZYO9Ypzc,54136
121
+ reconcile/aus/base.py,sha256=NXknPntO9EwLTuQMyFxPVtw8r7d9IbwUg-GadDNOU5w,54078
122
122
  reconcile/aus/cluster_version_data.py,sha256=rrMYtS-gSWwV4vibf3HKP06Hh3FHO4cBzhZzEInMRlo,7506
123
123
  reconcile/aus/healthchecks.py,sha256=jR9c-syh9impnkV0fd6XW3Bnk7iRN5zv8oCRYM-yIRY,2700
124
124
  reconcile/aus/metrics.py,sha256=BhIvZVTn25fIzijz3xFynJngS2sXDBTxxprUUVWJcFo,4246
@@ -139,11 +139,11 @@ reconcile/automated_actions/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQe
139
139
  reconcile/automated_actions/config/integration.py,sha256=uvaZbLp4FQz3DHfr9dA77FyHaRJHTvJDgdqGp7wdCNg,15303
140
140
  reconcile/aws_account_manager/README.md,sha256=_XFM3GZNHUzv--e_navqJuaUWpjC6QrHfulreHynFf0,262
141
141
  reconcile/aws_account_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
142
- reconcile/aws_account_manager/integration.py,sha256=kVh8BgIOYDo482ExldGhuqmj1KN8qtlO15YVRvLxMDU,15397
142
+ reconcile/aws_account_manager/integration.py,sha256=qpqefqnq4sPtXW13LBL0D2a5wXdq44mZzi3JxJtM7P0,16042
143
143
  reconcile/aws_account_manager/merge_request_manager.py,sha256=ePdn3c5MHZEW9iawgQWg7L5ydPLh0YZzfmRYV-rBCD8,3987
144
144
  reconcile/aws_account_manager/metrics.py,sha256=YB10ea4kIGwJfs5N14RF-RoXPb-QQWaDBz1jLZ3YWE0,917
145
145
  reconcile/aws_account_manager/reconciler.py,sha256=xbCih3aOFk_98Nxly7-W8QMrT67loTH2-HVyQudjH00,17162
146
- reconcile/aws_account_manager/utils.py,sha256=iYPPOtbZ7FiKkz9v5f1YXRIHw5YFOtSavUkF8oMwfJY,1439
146
+ reconcile/aws_account_manager/utils.py,sha256=m40ntjpxREpVPuzJv4pCG3LWtojAeqEoPOfbeIbmQUU,1443
147
147
  reconcile/aws_ami_cleanup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
148
148
  reconcile/aws_ami_cleanup/integration.py,sha256=NJhGzl9lMOG4VgYf8IsoZFJeYTRS1e5ORpHfIUEl3tA,9264
149
149
  reconcile/aws_cloudwatch_log_retention/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -158,15 +158,15 @@ reconcile/aws_version_sync/utils.py,sha256=x-45QT7zAwdNvCg7w_qJNwLaksFcfz1_6KQoD
158
158
  reconcile/aws_version_sync/merge_request_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
159
159
  reconcile/aws_version_sync/merge_request_manager/merge_request.py,sha256=2FbqLLdqxycWNvX1eNbwMjWSVBb7q0p-8t5Db0m7b4Q,4842
160
160
  reconcile/aws_version_sync/merge_request_manager/merge_request_manager.py,sha256=7EwpSMsAYk41yEqb3uB_EjU73qqWeF28c7UTuQaNjUQ,5522
161
- reconcile/change_owners/README.md,sha256=NEXVw4SioTWTGo9elSQUjqY10RIUoisl4zkzEBvly8s,3946
161
+ reconcile/change_owners/README.md,sha256=ETmGkj1hRklv0EFoHTZ89NsM3yjta0ikoIPvjn96BZo,3944
162
162
  reconcile/change_owners/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
163
163
  reconcile/change_owners/approver.py,sha256=Z3_11vnK2WNOxjEEXVDh0224-_-qbt9d6mBeVE-7fsc,2259
164
164
  reconcile/change_owners/bundle.py,sha256=6a51hi8yn2QwxQLQ4xc9zwlL5IT2sCbHriFuVJVeqzQ,5376
165
165
  reconcile/change_owners/change_log_tracking.py,sha256=njIBC6pRb6U2GmeXxAAc_CruIfnDpEUhOp05DrPFsuk,9531
166
- reconcile/change_owners/change_owners.py,sha256=9M0_D52xiRiN7UQe-q22C0FZZCdWmCAWXajieGYjJRk,18418
166
+ reconcile/change_owners/change_owners.py,sha256=Ay3KdLJBKH59xMdNYbiNTr2ow71bKPm0URiv4DjcB2M,18400
167
167
  reconcile/change_owners/change_types.py,sha256=5eSvS2_npUriq9RN4LdAWdYUiNzF91K1pDUEVYDIQ4k,32023
168
168
  reconcile/change_owners/changes.py,sha256=YTqwUYutQ6JVSSYmC2Ph5ROCiVix42Vnzy47-i57z4Q,18119
169
- reconcile/change_owners/decision.py,sha256=755rHmrnhfM_xVKnCPlLPOVm_TCJVb3lSkkUvxFM61Q,7491
169
+ reconcile/change_owners/decision.py,sha256=WaT7ehJFYofsgSbbpabj3a5jniomxy8R4wQpb3xsdsw,7487
170
170
  reconcile/change_owners/diff.py,sha256=xuyvnHcdRuQ8Twl0QST3rbbPo-hiH1uTycTet_AoT8k,8944
171
171
  reconcile/change_owners/implicit_ownership.py,sha256=6BehZvx4IjrphmOt_LLLk9_02Fl5BY5jd00Wuz_PBZk,4234
172
172
  reconcile/change_owners/self_service_roles.py,sha256=xSe5AKZxXAIo0vWOMM5hImQ_rd-dQ38y_5dG5L6X0so,9655
@@ -214,7 +214,7 @@ reconcile/glitchtip_project_alerts/integration.py,sha256=prje61EOuLEIZLLxlJS_YN0
214
214
  reconcile/glitchtip_project_dsn/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
215
215
  reconcile/glitchtip_project_dsn/integration.py,sha256=3GgcqUM6hWhLpo9Yx5Xr9vrdexF-WNevVCNL9bJ0Upc,8162
216
216
  reconcile/gql_definitions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
217
- reconcile/gql_definitions/introspection.json,sha256=RA-nGyii90zEWBMoF1mBiv2ue-d0mV5ofxwAJHOVj-M,2429636
217
+ reconcile/gql_definitions/introspection.json,sha256=liDjRAOJ0_ZN7bagOacrd1yGlybaxK8V9rQTflnecxo,2429961
218
218
  reconcile/gql_definitions/acs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
219
219
  reconcile/gql_definitions/acs/acs_instances.py,sha256=VySMcnWddg-jXj-bj_ddLIwLX3u1GSFUm02H8rJDBYU,2167
220
220
  reconcile/gql_definitions/acs/acs_policies.py,sha256=jEV1U8j4VYL9ih17JSK1tiz2s_1CegVECmXU-NVEQvA,4333
@@ -230,7 +230,7 @@ reconcile/gql_definitions/app_sre_tekton_access_revalidation/users.py,sha256=9x3
230
230
  reconcile/gql_definitions/automated_actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
231
231
  reconcile/gql_definitions/automated_actions/instance.py,sha256=w-68URz5Q5DVR_dAn13r5mP5YgtutdVHOv3LGQmfxxM,15810
232
232
  reconcile/gql_definitions/aws_account_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
233
- reconcile/gql_definitions/aws_account_manager/aws_accounts.py,sha256=p-ojQL0zeY_u694irRGG2HT6XaWkksoOtzCkPrdkXJo,5133
233
+ reconcile/gql_definitions/aws_account_manager/aws_accounts.py,sha256=dc3zbFPHW3eUcG3PPSKK498p_Q3a3DuJmyfVOPkfWIk,5401
234
234
  reconcile/gql_definitions/aws_ami_cleanup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
235
235
  reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py,sha256=XmJ-8_77QnATbeDmXzFiaLkWsxdlkbMWHlTlP9nTqfY,4226
236
236
  reconcile/gql_definitions/aws_cloudwatch_log_retention/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -307,7 +307,7 @@ reconcile/gql_definitions/endpoints_discovery/apps.py,sha256=p3hvzvrtkCCQfQoJ3mi
307
307
  reconcile/gql_definitions/external_resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
308
308
  reconcile/gql_definitions/external_resources/aws_accounts.py,sha256=bRzfuPDLJvVJRx7IzqAJKnqpd7SBWdj3trI1rNPeYnU,2033
309
309
  reconcile/gql_definitions/external_resources/external_resources_modules.py,sha256=w07PFh526GaYnZRe-SH92MaxA-aeD2TDT2kG_3Da_HE,3241
310
- reconcile/gql_definitions/external_resources/external_resources_namespaces.py,sha256=XRqi539Xu_lFwmK_pyb_5VvwDjIlcUrRwX1Ht9WiRG0,46525
310
+ reconcile/gql_definitions/external_resources/external_resources_namespaces.py,sha256=DGKKoJK7rOng2FBan8vxunLdlysX9Hb9_GTPsm2wyf8,46616
311
311
  reconcile/gql_definitions/external_resources/external_resources_settings.py,sha256=RvAMgipgH3MoLfWaqCPaYUy8GS3v0Dr4Cod17OsaNx0,3567
312
312
  reconcile/gql_definitions/external_resources/fragments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
313
313
  reconcile/gql_definitions/external_resources/fragments/external_resources_module_overrides.py,sha256=jjABgAhVx7LO3NJd9l90JH8s-_TJFvduBZRbdVquLfY,1313
@@ -427,7 +427,7 @@ reconcile/gql_definitions/terraform_repo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5
427
427
  reconcile/gql_definitions/terraform_repo/terraform_repo.py,sha256=vocF7fpLk4Rdz1maZ2Hi_d5l4bt3kuL2HyDGvFIUu8M,3868
428
428
  reconcile/gql_definitions/terraform_resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
429
429
  reconcile/gql_definitions/terraform_resources/database_access_manager.py,sha256=17CC1Wk65HtBn45Bo6iGsFNaLOnKD03MV3QQtixFtPw,4808
430
- reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py,sha256=wO8dycnslrO5THKDma8VSRboO5bSiBDUiYbJqMhr_6s,44673
430
+ reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py,sha256=oaLnYx6FtG33zDtE2TN8_iPXFfP8mRvPivYtoPo_8M8,44764
431
431
  reconcile/gql_definitions/terraform_tgw_attachments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
432
432
  reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py,sha256=VVWXcTGrHlZ8xqAf7p9Ygocwkm7dWZRaO_B6d_SamCc,2719
433
433
  reconcile/gql_definitions/unleash_feature_toggles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -507,7 +507,7 @@ reconcile/templates/rosa-classic-cluster-creation.sh.j2,sha256=7VlxlKpqIA9Pq7SMn
507
507
  reconcile/templates/rosa-hcp-cluster-creation.sh.j2,sha256=UbLexFWBsDbSUUe3-5S5aLaH1u_t8ikZnoKd5QTk_ro,2376
508
508
  reconcile/templating/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
509
509
  reconcile/templating/renderer.py,sha256=nR1CM3DDOoLOH7UOxO0PMDkOmhiYFbGriKcjDA-Z8j8,14810
510
- reconcile/templating/validator.py,sha256=5f9f35PCHOOdjb7KZquL2YdabyuAUokPDa4xutSEHIQ,5360
510
+ reconcile/templating/validator.py,sha256=cyvSNsQqheIBl78HHDu4u_H82rt0zC8_YZL5BtT_Y1w,5266
511
511
  reconcile/templating/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
512
512
  reconcile/templating/lib/merge_request_manager.py,sha256=MaEI9Vrtblb5LIpaa394ACut0Rq_gzxJTfNVSgG113o,5234
513
513
  reconcile/templating/lib/model.py,sha256=YVUIXuPny3_kpFgBMSud8q_ndY5o882wKiX0l0A14L4,481
@@ -518,8 +518,8 @@ reconcile/terraform_init/merge_request.py,sha256=3CYtgSd7Q9zjKg4wsDz437EPCRfGeZZ
518
518
  reconcile/terraform_init/merge_request_manager.py,sha256=TQmtHq4DH-xgyYvuRyGu7VEgjPU2Yjj-uexIy-L7i88,3098
519
519
  reconcile/terraform_vpc_resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
520
520
  reconcile/terraform_vpc_resources/integration.py,sha256=q5il4l4Bd9fmCQePy4XSy5R3nokVvcz1v2znwadelhU,9703
521
- reconcile/terraform_vpc_resources/merge_request.py,sha256=loRymUigCIvaaT0s_NzktZchh-DGRQnCICdBSCAcFPY,1503
522
- reconcile/terraform_vpc_resources/merge_request_manager.py,sha256=6jfwgbqXEFQlgLM6zmModpOkQX8wqddpoE0pZJL1Acc,3256
521
+ reconcile/terraform_vpc_resources/merge_request.py,sha256=MFRG7JQojmCTgr-9rLXVotcjH9mMIZZ0-kPai9UDJWA,1732
522
+ reconcile/terraform_vpc_resources/merge_request_manager.py,sha256=erCC9aY-gWMCVeLrFxG5_q3G2p3iVBS8eeYIUZR_6_o,4123
523
523
  reconcile/typed_queries/__init__.py,sha256=rRk4CyslLsBr4vAh1pIPgt6s3P4R1M9NSEPLnyQgBpk,61
524
524
  reconcile/typed_queries/alerting_services_settings.py,sha256=YKQd60O_2C_H103nLrYgcUInndM2vFypqW_NO706L2E,833
525
525
  reconcile/typed_queries/app_interface_custom_messages.py,sha256=bgSAJEzqee8aiPVCj_bIIqb4VTkrF0-vti1dos7ebEg,684
@@ -560,7 +560,7 @@ reconcile/typed_queries/quay.py,sha256=3IMy9jjHF2f9t47EXZOQVA3p0nFkWFhaFhxhvib-7
560
560
  reconcile/typed_queries/repos.py,sha256=8A93dKDt6igT4ClqMjt7YUTsoP4qh1Wnm0W3xsMgj48,824
561
561
  reconcile/typed_queries/reserved_networks.py,sha256=XY9y3amtIQT0n06O0Toubqr_UmylJ2ELAv9-BJCK890,345
562
562
  reconcile/typed_queries/rhcs_provider_settings.py,sha256=fxD84CPCiH25_qc02p48LOIJHv39Wlc1VwOhs9ZVsKk,743
563
- reconcile/typed_queries/saas_files.py,sha256=F6F59Uo1fkap3mpNjV7YoVfcSf2tN_ixowBaMpxaLyc,14667
563
+ reconcile/typed_queries/saas_files.py,sha256=yVJiba_kIKYaRqSxXovNC2Zupf-KfWoVWQdOmeD1ccY,14666
564
564
  reconcile/typed_queries/slack.py,sha256=r30lspctHloyygPn8_DVybxPwUWwiBpvBRRXiTVcQYk,251
565
565
  reconcile/typed_queries/slo_documents.py,sha256=YMdox_-lBRqrdxamPhdnUlRTY_Ro35ptsupq7OaynUQ,362
566
566
  reconcile/typed_queries/smtp.py,sha256=aSLglYa5bHKmlGwKkxq2RZqyMWuAf0a4S_mOuhDa084,542
@@ -604,7 +604,7 @@ reconcile/utils/environ.py,sha256=UOYbV7K1MpU7lwcjslKB7oJ7Ek8pOAwf12fA2lV9LM4,81
604
604
  reconcile/utils/exceptions.py,sha256=2cKJD01d_uZM_j0CTcvDoo-WDisZJVYaeY2KUbfUHCc,686
605
605
  reconcile/utils/expiration.py,sha256=6GrQp-sYDKf6scuzzUPxSS8_q_6IiQyjcdvZEVQZzGc,1353
606
606
  reconcile/utils/extended_early_exit.py,sha256=QSktrmfw37zSRMNk930tDbQsVeKxaPPPD43e79DGwZw,6754
607
- reconcile/utils/external_resource_spec.py,sha256=y-jZvio-kPIqQ07ApWegbx5DWUnlkL8cXTg586mHBqc,8188
607
+ reconcile/utils/external_resource_spec.py,sha256=itiV8s87pD5LZ7Xx_rMTf3P-VsEdR7F5Sh7EDXJIGdE,8309
608
608
  reconcile/utils/external_resources.py,sha256=YzTb0xAcNdmKO326mGQy7BmST56CZcdru4lX7ai_7kw,7579
609
609
  reconcile/utils/filtering.py,sha256=rvCr0drVeD9x4yVox-kvbHEufBktlz3yyQjM-y3IJsM,422
610
610
  reconcile/utils/git.py,sha256=o4p9m8jlzCJDcutl2HErvGLhL6sZ1NB4Aw3zGcQIzso,2427
@@ -644,7 +644,7 @@ reconcile/utils/password_validator.py,sha256=knR6jJGc-v44v-hhQFvpYrEubuFfCCc3Qly
644
644
  reconcile/utils/prometheus.py,sha256=Ad0rwLbxRuuYjHwkwJloHEdK0bvy42h-p-HIT1DhDhs,3832
645
645
  reconcile/utils/promotion_state.py,sha256=4NTBswYkzxlJIIkMz4j92dOj-jn0m36DKQg8CqZEyo8,3910
646
646
  reconcile/utils/promtool.py,sha256=YnqwMAzsQVGuBZ1j9zy3UcVPFQVJgBMLzQkxhK_KFkU,3079
647
- reconcile/utils/quay_api.py,sha256=ZWjfjzFnIsbKRDcdAnP9tWQezclf53I7VWZJ0gbF2kE,8260
647
+ reconcile/utils/quay_api.py,sha256=zlzM-1_GsVSQVd2z0SMwx3uv5wqzZ7JUKE5ZOqQPKXc,7728
648
648
  reconcile/utils/quay_mirror.py,sha256=dpWCNv5lITwIk6Q9RkmqaQKHNk_JPy27UQEribJ7E-U,1324
649
649
  reconcile/utils/raw_github_api.py,sha256=ZUDtOxdMSMs-Z0noKi0pyMtXHi5V2nCMFDB5JIM_oQ0,3057
650
650
  reconcile/utils/repo_owners.py,sha256=c6Z-U5TkiRPvuhr_zYWvZG9HZGzoT-l-d2PJ33lGflE,6507
@@ -802,7 +802,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
802
802
  tools/saas_promotion_state/saas_promotion_state.py,sha256=uQv2QJAmUXP1g2GPIH30WTlvL9soY6m9lefpZEVDM5w,3965
803
803
  tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
804
804
  tools/sre_checkpoints/util.py,sha256=KcYVfa3UmJHVP_ocgrKe8NkrO5IDB9aWEDydSokPcRk,975
805
- qontract_reconcile-0.10.2.dev456.dist-info/METADATA,sha256=s_WqWgoFL4Yacm8I8TJYk6b3-Q_Wn9ONhB7GxO9tsN8,24948
806
- qontract_reconcile-0.10.2.dev456.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
807
- qontract_reconcile-0.10.2.dev456.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
808
- qontract_reconcile-0.10.2.dev456.dist-info/RECORD,,
805
+ qontract_reconcile-0.10.2.dev473.dist-info/METADATA,sha256=cqVPSqOjgcxHnzId0KJ1x9lHen_cPLUwfkBQjZe6ULI,24948
806
+ qontract_reconcile-0.10.2.dev473.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
807
+ qontract_reconcile-0.10.2.dev473.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
808
+ qontract_reconcile-0.10.2.dev473.dist-info/RECORD,,
reconcile/aus/base.py CHANGED
@@ -460,9 +460,6 @@ class AddonUpgradePolicy(AbstractUpgradePolicy, arbitrary_types_allowed=True):
460
460
  addon_id: str
461
461
  addon_service: AddonService
462
462
 
463
- class Config:
464
- arbitrary_types_allowed = True
465
-
466
463
  def create(
467
464
  self,
468
465
  ocm_api: OCMBaseClient,
@@ -128,12 +128,24 @@ class AwsAccountMgmtIntegration(
128
128
  for payer_account in payer_accounts
129
129
  for org_account in payer_account.organization_accounts or []
130
130
  }
131
-
132
131
  non_organization_accounts = [
133
132
  account
134
133
  for account in all_aws_accounts
135
134
  if account.name not in all_organization_account_names
136
135
  ]
136
+
137
+ # check account requests for invalid emails
138
+ used_emails: set[str] = {
139
+ owner.email
140
+ for account in all_aws_accounts
141
+ for owner in account.account_owners
142
+ }
143
+ for payer_account in payer_accounts:
144
+ for account_request in payer_account.account_requests or []:
145
+ if account_request.account_owner.email in used_emails:
146
+ raise ValueError(
147
+ f"Invalid email for account request {account_request.name} in payer account {payer_account.name}. Email {account_request.account_owner.email} is already used."
148
+ )
137
149
  return payer_accounts, non_organization_accounts
138
150
 
139
151
  def save_access_key(self, account: str, access_key: AWSAccessKey) -> None:
@@ -24,7 +24,7 @@ def validate(account: AWSAccountV1) -> bool:
24
24
  raise ExceptionGroup("Multiple quotas are referenced in the account", errors)
25
25
 
26
26
  if account.organization_accounts or account.account_requests:
27
- # it's payer account
27
+ # it's a "payer account"
28
28
  if not account.premium_support:
29
29
  raise ValueError(
30
30
  f"Premium support is required for payer account {account.name}"
@@ -15,7 +15,7 @@
15
15
 
16
16
  `change_owners` uses the `qontract-server` diff endpoint to get a highlevel overview what changed in an MR. It leverages `change_types` to find fine grained differences in datafiles and resourcefiles and build `BundleFileChange` objects that hold the state of diffs and diff coverage.
17
17
 
18
- `change_owners` checks `BundleFileChange` objects for `change-types` that are `restrictive`. If the MR was created by a user, that has this `change-type` not assigned, the integration will fail. A user with this role assigned could issue an `/good-to-test` command to override this restriction.
18
+ `change_owners` checks `BundleFileChange` objects for `change-types` that are `restrictive`. If the MR was created by a user, that has this `change-type` not assigned, the integration will fail. A user with this role assigned could issue an `/ok-to-test` command to override this restriction.
19
19
 
20
20
  `change_owners` reachs out to pluggable functionality to find out which `change-types` can be applied to which changes with a set of approvers. Currently, the only module to provide such `ChangeTypeContext` is `self_service_roles` which looks for explicitly bound `change-types` and files in the context of a `Role` with users and bots will can act as approvers.
21
21
 
@@ -131,7 +131,7 @@ def build_status_message(
131
131
  # Check if changes are not admitted (security gate - takes priority)
132
132
  if not change_admitted:
133
133
  return f"""## ⏸️ Approval Required
134
- Your changes need `/good-to-test` approval from a listed approver before review can begin.
134
+ Your changes need `/ok-to-test` approval from a listed approver before review can begin.
135
135
 
136
136
  {approver_section}"""
137
137
 
@@ -322,22 +322,22 @@ def init_gitlab(gitlab_project_id: str) -> GitLabApi:
322
322
 
323
323
 
324
324
  def is_coverage_admitted(
325
- coverage: ChangeTypeContext, mr_author: str, good_to_test_approvers: set[str]
325
+ coverage: ChangeTypeContext, mr_author: str, ok_to_test_approvers: set[str]
326
326
  ) -> bool:
327
327
  return any(
328
- a.org_username == mr_author or a.org_username in good_to_test_approvers
328
+ a.org_username == mr_author or a.org_username in ok_to_test_approvers
329
329
  for a in coverage.approvers
330
330
  )
331
331
 
332
332
 
333
333
  def is_change_admitted(
334
- changes: list[BundleFileChange], mr_author: str, good_to_test_approvers: set[str]
334
+ changes: list[BundleFileChange], mr_author: str, ok_to_test_approvers: set[str]
335
335
  ) -> bool:
336
336
  # Checks if mr authors are allowed to do the changes in the merge request.
337
337
  # If a change type is restrictive and the author is not an approver,
338
338
  # this is not admitted.
339
339
  # A change might be admitted if a user that has the restrictive change
340
- # type is an approver or an approver adds an /good-to-test comment.
340
+ # type is an approver or an approver adds an /ok-to-test comment.
341
341
 
342
342
  restrictive_coverages = [
343
343
  c
@@ -351,7 +351,7 @@ def is_change_admitted(
351
351
  change_types_approved = {
352
352
  c.origin
353
353
  for c in restrictive_coverages
354
- if is_coverage_admitted(c, mr_author, good_to_test_approvers)
354
+ if is_coverage_admitted(c, mr_author, ok_to_test_approvers)
355
355
  }
356
356
  return change_types_to_approve == change_types_approved
357
357
 
@@ -442,14 +442,14 @@ def run(
442
442
  merge_request = gl.get_merge_request(gitlab_merge_request_id)
443
443
 
444
444
  comments = gl.get_merge_request_comments(merge_request)
445
- good_to_test_approvers = {
446
- c.username for c in comments if c.body.strip() == "/good-to-test"
445
+ ok_to_test_approvers = {
446
+ c.username for c in comments if c.body.strip() == "/ok-to-test"
447
447
  }
448
448
 
449
449
  change_admitted = is_change_admitted(
450
450
  changes,
451
451
  gl.get_merge_request_author_username(merge_request),
452
- good_to_test_approvers,
452
+ ok_to_test_approvers,
453
453
  )
454
454
  approver_decisions = get_approver_decisions_from_mr_comments(
455
455
  gl.get_merge_request_comments(
@@ -20,7 +20,7 @@ class DecisionCommand(Enum):
20
20
  CANCEL_APPROVED = "/lgtm cancel"
21
21
  HOLD = "/hold"
22
22
  CANCEL_HOLD = "/hold cancel"
23
- GOOD_TO_TEST = "/good-to-test"
23
+ OK_TO_TEST = "/ok-to-test"
24
24
 
25
25
 
26
26
  @dataclass
@@ -97,6 +97,10 @@ query AWSAccountManagerAccounts {
97
97
  ...AWSAccountManaged
98
98
  }
99
99
  organizationAccountTags
100
+ # for account request email address verification
101
+ accountOwners {
102
+ email
103
+ }
100
104
  }
101
105
  }
102
106
  """
@@ -149,6 +153,10 @@ class AWSAccountRequestV1(ConfiguredBaseModel):
149
153
  account_file_target_path: Optional[str] = Field(..., alias="accountFileTargetPath")
150
154
 
151
155
 
156
+ class AWSAccountV1_OwnerV1(ConfiguredBaseModel):
157
+ email: str = Field(..., alias="email")
158
+
159
+
152
160
  class AWSAccountV1(AWSAccountManaged):
153
161
  resources_default_region: str = Field(..., alias="resourcesDefaultRegion")
154
162
  automation_token: VaultSecret = Field(..., alias="automationToken")
@@ -157,6 +165,7 @@ class AWSAccountV1(AWSAccountManaged):
157
165
  account_requests: Optional[list[AWSAccountRequestV1]] = Field(..., alias="account_requests")
158
166
  organization_accounts: Optional[list[AWSAccountManaged]] = Field(..., alias="organization_accounts")
159
167
  organization_account_tags: Optional[Json] = Field(..., alias="organizationAccountTags")
168
+ account_owners: list[AWSAccountV1_OwnerV1] = Field(..., alias="accountOwners")
160
169
 
161
170
 
162
171
  class AWSAccountManagerAccountsQueryData(ConfiguredBaseModel):
@@ -575,6 +575,7 @@ query ExternalResourcesNamespaces {
575
575
  name
576
576
  labels
577
577
  servicePhase
578
+ costCenter
578
579
  }
579
580
  app {
580
581
  path
@@ -1176,13 +1177,14 @@ class EnvironmentV1(ConfiguredBaseModel):
1176
1177
  name: str = Field(..., alias="name")
1177
1178
  labels: str = Field(..., alias="labels")
1178
1179
  service_phase: str = Field(..., alias="servicePhase")
1180
+ cost_center: Optional[str] = Field(..., alias="costCenter")
1179
1181
 
1180
1182
 
1181
1183
  class AppV1(ConfiguredBaseModel):
1182
1184
  path: str = Field(..., alias="path")
1183
1185
  name: str = Field(..., alias="name")
1184
1186
  app_code: str = Field(..., alias="appCode")
1185
- cost_center: str = Field(..., alias="costCenter")
1187
+ cost_center: Optional[str] = Field(..., alias="costCenter")
1186
1188
 
1187
1189
 
1188
1190
  class ClusterSpecV1(ConfiguredBaseModel):
@@ -16708,13 +16708,9 @@
16708
16708
  "description": null,
16709
16709
  "args": [],
16710
16710
  "type": {
16711
- "kind": "NON_NULL",
16712
- "name": null,
16713
- "ofType": {
16714
- "kind": "SCALAR",
16715
- "name": "String",
16716
- "ofType": null
16717
- }
16711
+ "kind": "SCALAR",
16712
+ "name": "String",
16713
+ "ofType": null
16718
16714
  },
16719
16715
  "isDeprecated": false,
16720
16716
  "deprecationReason": null
@@ -17229,6 +17225,18 @@
17229
17225
  "isDeprecated": false,
17230
17226
  "deprecationReason": null
17231
17227
  },
17228
+ {
17229
+ "name": "costCenter",
17230
+ "description": null,
17231
+ "args": [],
17232
+ "type": {
17233
+ "kind": "SCALAR",
17234
+ "name": "String",
17235
+ "ofType": null
17236
+ },
17237
+ "isDeprecated": false,
17238
+ "deprecationReason": null
17239
+ },
17232
17240
  {
17233
17241
  "name": "namespaces",
17234
17242
  "description": null,
@@ -521,6 +521,7 @@ query TerraformResourcesNamespaces {
521
521
  environment {
522
522
  name
523
523
  servicePhase
524
+ costCenter
524
525
  }
525
526
  app {
526
527
  name
@@ -1110,12 +1111,13 @@ class NamespaceTerraformProviderResourceAWSV1(NamespaceExternalResourceV1):
1110
1111
  class EnvironmentV1(ConfiguredBaseModel):
1111
1112
  name: str = Field(..., alias="name")
1112
1113
  service_phase: str = Field(..., alias="servicePhase")
1114
+ cost_center: Optional[str] = Field(..., alias="costCenter")
1113
1115
 
1114
1116
 
1115
1117
  class AppV1(ConfiguredBaseModel):
1116
1118
  name: str = Field(..., alias="name")
1117
1119
  app_code: str = Field(..., alias="appCode")
1118
- cost_center: str = Field(..., alias="costCenter")
1120
+ cost_center: Optional[str] = Field(..., alias="costCenter")
1119
1121
 
1120
1122
 
1121
1123
  class ClusterSpecV1(ConfiguredBaseModel):
reconcile/quay_base.py CHANGED
@@ -1,4 +1,4 @@
1
- from collections import namedtuple
1
+ from collections import UserDict, namedtuple
2
2
  from typing import Any, TypedDict
3
3
 
4
4
  from reconcile import queries
@@ -10,22 +10,34 @@ OrgKey = namedtuple("OrgKey", ["instance", "org_name"])
10
10
 
11
11
  class OrgInfo(TypedDict):
12
12
  url: str
13
- api: QuayApi
14
13
  push_token: dict[str, str] | None
15
14
  teams: list[str]
16
15
  managedRepos: bool
17
16
  mirror: OrgKey | None
18
17
  mirror_filters: dict[str, Any]
18
+ api: QuayApi
19
+
19
20
 
21
+ class QuayApiStore(UserDict[OrgKey, OrgInfo]):
22
+ def __init__(self) -> None:
23
+ super().__init__(get_quay_api_store())
20
24
 
21
- QuayApiStore = dict[OrgKey, OrgInfo]
25
+ def cleanup(self) -> None:
26
+ """Close all QuayApi sessions."""
27
+ for org_info in self.data.values():
28
+ org_info["api"].cleanup()
22
29
 
30
+ def __enter__(self) -> "QuayApiStore":
31
+ return self
23
32
 
24
- def get_quay_api_store() -> QuayApiStore:
33
+ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
34
+ self.cleanup()
35
+
36
+
37
+ def get_quay_api_store() -> dict[OrgKey, OrgInfo]:
25
38
  """
26
39
  Returns a dictionary with a key for each Quay organization
27
40
  managed in app-interface.
28
- Each key contains an initiated QuayApi instance.
29
41
  """
30
42
  quay_orgs = queries.get_quay_orgs()
31
43
  settings = queries.get_app_interface_settings()
@@ -61,14 +73,21 @@ def get_quay_api_store() -> QuayApiStore:
61
73
  else:
62
74
  push_token = None
63
75
 
76
+ # Create QuayApi instance for this org
77
+ api = QuayApi(
78
+ token=token,
79
+ organization=org_name,
80
+ base_url=base_url,
81
+ )
82
+
64
83
  org_info: OrgInfo = {
65
84
  "url": base_url,
66
- "api": QuayApi(token, org_name, base_url=base_url),
67
85
  "push_token": push_token,
68
86
  "teams": org_data.get("managedTeams") or [],
69
87
  "managedRepos": bool(org_data.get("managedRepos")),
70
88
  "mirror": mirror,
71
89
  "mirror_filters": mirror_filters,
90
+ "api": api,
72
91
  }
73
92
 
74
93
  store[org_key] = org_info
@@ -10,7 +10,7 @@ from reconcile.gql_definitions.quay_membership.quay_membership import (
10
10
  PermissionQuayOrgTeamV1,
11
11
  UserV1,
12
12
  )
13
- from reconcile.quay_base import QuayApiStore, get_quay_api_store
13
+ from reconcile.quay_base import QuayApiStore
14
14
  from reconcile.status import ExitCodes
15
15
  from reconcile.utils import (
16
16
  expiration,
@@ -58,10 +58,11 @@ def fetch_current_state(quay_api_store: QuayApiStore) -> AggregatedList:
58
58
  state = AggregatedList()
59
59
 
60
60
  for org_key, org_data in quay_api_store.items():
61
- quay_api = org_data["api"]
62
61
  teams = org_data["teams"]
63
62
  if not teams:
64
63
  continue
64
+
65
+ quay_api = org_data["api"]
65
66
  for team in teams:
66
67
  try:
67
68
  members = quay_api.list_team_members(team)
@@ -77,7 +78,11 @@ def fetch_current_state(quay_api_store: QuayApiStore) -> AggregatedList:
77
78
  # Teams are only added to the state if they exist so that
78
79
  # there is a proper diff between the desired and current state.
79
80
  state.add(
80
- {"service": "quay-membership", "org": org_key, "team": team},
81
+ {
82
+ "service": "quay-membership",
83
+ "org": org_key.org_name,
84
+ "team": team,
85
+ },
81
86
  members,
82
87
  )
83
88
  return state
@@ -117,9 +122,10 @@ class RunnerAction:
117
122
  def action(params: dict, items: list) -> bool:
118
123
  org = params["org"]
119
124
  team = params["team"]
125
+ org_data = self.quay_api_store[org]
126
+ quay_api = org_data["api"]
120
127
 
121
128
  missing_users = False
122
- quay_api = self.quay_api_store[org]["api"]
123
129
  for member in items:
124
130
  logging.info([label, member, org, team])
125
131
  user_exists = quay_api.user_exists(member)
@@ -147,10 +153,11 @@ class RunnerAction:
147
153
  def action(params: dict, items: list) -> bool:
148
154
  org = params["org"]
149
155
  team = params["team"]
156
+ org_data = self.quay_api_store[org]
150
157
 
151
158
  # Ensure all quay org/teams are declared as dependencies in a
152
159
  # `/dependencies/quay-org-1.yml` datafile.
153
- if team not in self.quay_api_store[org]["teams"]:
160
+ if team not in org_data["teams"]:
154
161
  raise RunnerError(
155
162
  f"Quay team {team} is not defined as a "
156
163
  f"managedTeam in the {org} org."
@@ -159,7 +166,7 @@ class RunnerAction:
159
166
  logging.info([label, org, team])
160
167
 
161
168
  if not self.dry_run:
162
- quay_api = self.quay_api_store[org]["api"]
169
+ quay_api = org_data["api"]
163
170
  quay_api.create_or_update_team(team)
164
171
 
165
172
  return True
@@ -172,12 +179,13 @@ class RunnerAction:
172
179
  def action(params: dict, items: list) -> bool:
173
180
  org = params["org"]
174
181
  team = params["team"]
182
+ org_data = self.quay_api_store[org]
175
183
 
184
+ quay_api = org_data["api"]
176
185
  if self.dry_run:
177
186
  for member in items:
178
187
  logging.info([label, member, org, team])
179
188
  else:
180
- quay_api = self.quay_api_store[org]["api"]
181
189
  for member in items:
182
190
  logging.info([label, member, org, team])
183
191
  quay_api.remove_user_from_team(member, team)
@@ -188,24 +196,23 @@ class RunnerAction:
188
196
 
189
197
 
190
198
  def run(dry_run: bool) -> None:
191
- quay_api_store = get_quay_api_store()
192
-
193
- current_state = fetch_current_state(quay_api_store)
194
- desired_state = fetch_desired_state()
195
-
196
- # calculate diff
197
- diff = current_state.diff(desired_state)
198
- logging.debug("State diff: %s", diff)
199
-
200
- # Run actions
201
- runner_action = RunnerAction(dry_run, quay_api_store)
202
- runner = AggregatedDiffRunner(diff)
203
-
204
- runner.register("insert", runner_action.create_team())
205
- runner.register("update-insert", runner_action.add_to_team())
206
- runner.register("update-delete", runner_action.del_from_team())
207
- runner.register("delete", runner_action.del_from_team())
208
-
209
- status = runner.run()
210
- if not status:
211
- sys.exit(ExitCodes.ERROR)
199
+ with QuayApiStore() as quay_api_store:
200
+ current_state = fetch_current_state(quay_api_store)
201
+ desired_state = fetch_desired_state()
202
+
203
+ # calculate diff
204
+ diff = current_state.diff(desired_state)
205
+ logging.debug("State diff: %s", diff)
206
+
207
+ # Run actions
208
+ runner_action = RunnerAction(dry_run, quay_api_store)
209
+ runner = AggregatedDiffRunner(diff)
210
+
211
+ runner.register("insert", runner_action.create_team())
212
+ runner.register("update-insert", runner_action.add_to_team())
213
+ runner.register("update-delete", runner_action.del_from_team())
214
+ runner.register("delete", runner_action.del_from_team())
215
+
216
+ status = runner.run()
217
+ if not status:
218
+ sys.exit(ExitCodes.ERROR)