qontract-reconcile 0.10.1rc1168__py3-none-any.whl → 0.10.1rc1170__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.1rc1168.dist-info → qontract_reconcile-0.10.1rc1170.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc1168.dist-info → qontract_reconcile-0.10.1rc1170.dist-info}/RECORD +12 -12
- reconcile/cli.py +0 -7
- reconcile/jira_permissions_validator.py +16 -14
- reconcile/queries.py +14 -15
- reconcile/terraform_resources.py +2 -4
- reconcile/test/test_jira_permissions_validator.py +55 -16
- reconcile/utils/jira_client.py +4 -0
- reconcile/utils/terrascript_aws_client.py +40 -24
- {qontract_reconcile-0.10.1rc1168.dist-info → qontract_reconcile-0.10.1rc1170.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc1168.dist-info → qontract_reconcile-0.10.1rc1170.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc1168.dist-info → qontract_reconcile-0.10.1rc1170.dist-info}/top_level.txt +0 -0
{qontract_reconcile-0.10.1rc1168.dist-info → qontract_reconcile-0.10.1rc1170.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.1rc1170
|
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.1rc1168.dist-info → qontract_reconcile-0.10.1rc1170.dist-info}/RECORD
RENAMED
@@ -10,7 +10,7 @@ reconcile/aws_iam_password_reset.py,sha256=q96mwr2KeEQ5bpNniGlgIMZTxiuLSodcYfX-t
|
|
10
10
|
reconcile/aws_support_cases_sos.py,sha256=hl_9L53yQYRQxKs3IWrd69Cc60XK067g_bJRM9B0udo,2975
|
11
11
|
reconcile/blackbox_exporter_endpoint_monitoring.py,sha256=O1wFp52EyF538c6txaWBs8eMtUIy19gyHZ6VzJ6QXS8,3512
|
12
12
|
reconcile/checkpoint.py,sha256=_JhMxrye5BgkRMxWYuf7Upli6XayPINKSsuo3ynHTRc,5010
|
13
|
-
reconcile/cli.py,sha256
|
13
|
+
reconcile/cli.py,sha256=2W2_vnq68954f-lhNwX3yGgCrofwSbDtAk33b4TnicE,107467
|
14
14
|
reconcile/closedbox_endpoint_monitoring_base.py,sha256=rLh16BOlBOxTmJ8Si3wWyyEpmMlhh4Znx1Gc36qsmOc,4865
|
15
15
|
reconcile/cluster_deployment_mapper.py,sha256=5gumAaRCcFXsabUJ1dnuUy9WrP_FEEM5JnOnE8ch9sE,2326
|
16
16
|
reconcile/dashdotdb_base.py,sha256=l34QDu1G96_Ctnh7ZXdxXgSeCE93GQMdLAkWxmN6vDA,4775
|
@@ -46,7 +46,7 @@ reconcile/jenkins_roles.py,sha256=pNNYcnmyDCTVytG2mi3BFhq9A7_3l301oFRQtY_q6S8,44
|
|
46
46
|
reconcile/jenkins_webhooks.py,sha256=K5h0OlCghoHlpot40IRq4BuezfKB1rj4Xk0dCUvqp3o,1952
|
47
47
|
reconcile/jenkins_webhooks_cleaner.py,sha256=JsN_NVPfZJwv1JtSzZXDIHUqGiefL-DRffFnDGau9aY,1539
|
48
48
|
reconcile/jenkins_worker_fleets.py,sha256=PMNGOX0krubFjInPiFT0za0KCiWBLEcVDuXdKRd1BrE,5378
|
49
|
-
reconcile/jira_permissions_validator.py,sha256=
|
49
|
+
reconcile/jira_permissions_validator.py,sha256=GSjLwHrstuO4dGb9Oxfmg_9PLLreFsbJJ8WHhUM8FSY,13144
|
50
50
|
reconcile/jira_watcher.py,sha256=L_UL2MKm2SoIGNsCLThm28pnqCkoFc154JWsD6bURug,3593
|
51
51
|
reconcile/ldap_users.py,sha256=7hdO5CAPl-VNBvDRmKHg13LoblHXXPt7YEKNGomAoGg,3158
|
52
52
|
reconcile/mr_client_gateway.py,sha256=WhjMd-sIXDFCV8-rt8CEjurJ5OYB1pOD0K3o0tZRXQg,1885
|
@@ -94,7 +94,7 @@ reconcile/quay_mirror.py,sha256=mFp4Z5Nwl-DcFbbsJBOB8f9ldohFT-V67o868d5ux1s,1536
|
|
94
94
|
reconcile/quay_mirror_org.py,sha256=utrJpJaKCs7U6WX6DODdfCeB0EmX-lUC8Y5fkmpgFSs,10764
|
95
95
|
reconcile/quay_permissions.py,sha256=9KOutS1w4RFQqkvMSy54VtsKNx56-phzP6yI_rEW-B8,4244
|
96
96
|
reconcile/quay_repos.py,sha256=cuEYG0HUe0ut5yvLdEwOF5-CmccpXQHRb_wDazvDrvQ,6895
|
97
|
-
reconcile/queries.py,sha256=
|
97
|
+
reconcile/queries.py,sha256=of54G-Vqy-_deKdZcWs-B9LwxIdhQFUlQ198pBGCp3g,51488
|
98
98
|
reconcile/query_validator.py,sha256=MSh5pKLBksws4AqfuvT8nrIGucIbqX-IOzYyPYTLO7k,1491
|
99
99
|
reconcile/requests_sender.py,sha256=914iluuF4UVgG3VyxxtnHOu4yf6YKS2fIy6PViSsFTQ,3875
|
100
100
|
reconcile/resource_scraper.py,sha256=znXCHrU7YwPfKuxGBiUrV7T1tYtn4vlz9qmZlfy6Flg,2307
|
@@ -113,7 +113,7 @@ reconcile/terraform_cloudflare_dns.py,sha256=-aLEe2QnH5cJPu7HWqs-R9NmQ1NlFbcVUm0
|
|
113
113
|
reconcile/terraform_cloudflare_resources.py,sha256=pq8Ieo5NmB-dYQ9X2F0s6iEoINMzhiqGw2yQK4ovok4,14980
|
114
114
|
reconcile/terraform_cloudflare_users.py,sha256=iyTG5sj20Jg4J4qWJ144KVptfIHGOSfH8wQKxu0imq0,13942
|
115
115
|
reconcile/terraform_repo.py,sha256=TKqlodhQGoAtQ6nDm04TNlpx4wpgJ_n4atoUK5Rfd7o,16444
|
116
|
-
reconcile/terraform_resources.py,sha256=
|
116
|
+
reconcile/terraform_resources.py,sha256=iufjMJs_aSEvmh7Cg11beCxKmV8nrOLOpEtiTryPNx0,19470
|
117
117
|
reconcile/terraform_tgw_attachments.py,sha256=09svJG9pAiwWp4aY0xRoQRV90T4ZNwHG3r8flI-ZS_s,18810
|
118
118
|
reconcile/terraform_users.py,sha256=HqSm3ev3b8dZ9J6F_phDZB-FQsnlsdeKp9RPoY1cU94,10188
|
119
119
|
reconcile/terraform_vpc_peerings.py,sha256=VLSfuO7FvHN5McopRiKoKJDHCmIhYtlJEHv_hxV5kcM,27669
|
@@ -525,7 +525,7 @@ reconcile/test/test_gitlab_permissions.py,sha256=aMf5SUeVp-aQ1bWGQPQLYa85auzRlyf
|
|
525
525
|
reconcile/test/test_instrumented_wrappers.py,sha256=CZzhnQH0c4i7-Rxjg7-0dfFMvVPegLHL46z5NHOOCwo,608
|
526
526
|
reconcile/test/test_integrations_manager.py,sha256=xpyQAVz57wAbovrcQzAeuyq8VzdItUyW2d2kp1WW_5c,38184
|
527
527
|
reconcile/test/test_jenkins_worker_fleets.py,sha256=o1jlT7OBBSgu0M3iI4xMdz_x6SciF7yhNBpLk5gTJfg,2361
|
528
|
-
reconcile/test/test_jira_permissions_validator.py,sha256=
|
528
|
+
reconcile/test/test_jira_permissions_validator.py,sha256=OA3hcnsH0eYXA4khJO6d1PE7zo2f0vYg73PrCqTzkyo,17646
|
529
529
|
reconcile/test/test_jump_host.py,sha256=EeHMhT5rTZgx__R_29mtCBWt-NZCcKsQ6CR-B3xmCps,3284
|
530
530
|
reconcile/test/test_ldap_users.py,sha256=_clylG-Qfes8yNb9T3CMaDQovLwyVZlTfJgRtGHARgE,4080
|
531
531
|
reconcile/test/test_make.py,sha256=zTdjgq-3idFlec_0qJenk9wWw0QMLvSpJfPsptXmync,677
|
@@ -687,7 +687,7 @@ reconcile/utils/helpers.py,sha256=womAD2bKPUAFOjHvNPAe_2Hsb-oVTxuQiYPGeR-Thp0,17
|
|
687
687
|
reconcile/utils/imap_client.py,sha256=h8YDiCSCvroErhpH_-KGYI7Y2WU2Q2oSpuxDFbOkSbY,1989
|
688
688
|
reconcile/utils/instrumented_wrappers.py,sha256=eVwMoa6FCrYxLv3RML3WpZF9qKVfCTjMxphgVXG03OM,1073
|
689
689
|
reconcile/utils/jenkins_api.py,sha256=RaKuZmO7_lbI-hE6c_Pq2a6CQdmBVj7BcP2jR68cIbI,7081
|
690
|
-
reconcile/utils/jira_client.py,sha256=
|
690
|
+
reconcile/utils/jira_client.py,sha256=oWi7rcAP1C59oIBTPg6kRntI25Zm4e7FyvdVYvZ9RZ8,7881
|
691
691
|
reconcile/utils/jjb_client.py,sha256=9Aw4SfV4pBNW5Kj7dGZwakUlwsWuqtAAiSD9o1F4AZA,14524
|
692
692
|
reconcile/utils/jsonpath.py,sha256=wdxOMqR-GMpQf5vRPWRMqAF7bCiXDBkkcFfY2U4j_tk,5536
|
693
693
|
reconcile/utils/jump_host.py,sha256=svtWy64zZAx7XYY62vu580KgwdatmHjX4-BdxEl58Uw,5158
|
@@ -727,7 +727,7 @@ reconcile/utils/state.py,sha256=W0_awkLAPX18hNOF_60o73tkPxDUylqbzYNHfl_sDsk,1638
|
|
727
727
|
reconcile/utils/structs.py,sha256=LcbLEg8WxfRqM6nW7NhcWN0YeqF7SQzxOgntmLs1SgY,352
|
728
728
|
reconcile/utils/template.py,sha256=wTvRU4AnAV_o042tD4Mwls2dwWMuk7MKnde3MaCjaYg,331
|
729
729
|
reconcile/utils/terraform_client.py,sha256=LjX2U2E0Dglt2S_KA5jWQ_dVC8sPn4FEAh0xW_d6JTk,35953
|
730
|
-
reconcile/utils/terrascript_aws_client.py,sha256=
|
730
|
+
reconcile/utils/terrascript_aws_client.py,sha256=q6Ydbjle7K5Z3LYpoRJGXnb50ix6aGN6jLvP2vglPz8,283769
|
731
731
|
reconcile/utils/three_way_diff_strategy.py,sha256=oQcHXd9LVhirJfoaOBoHUYuZVGfyL2voKr6KVI34zZE,4833
|
732
732
|
reconcile/utils/throughput.py,sha256=iP4UWAe2LVhDo69mPPmgo9nQ7RxHD6_GS8MZe-aSiuM,344
|
733
733
|
reconcile/utils/vault.py,sha256=pi0PuyopvCq1gW0cldvy1-Ff6bqLUlCKC2MW0sifvSE,15043
|
@@ -880,8 +880,8 @@ tools/test/test_qontract_cli.py,sha256=iuzKbQ6ahinvjoQmQLBrG4shey0z-1rB6qCgS8T6d
|
|
880
880
|
tools/test/test_saas_promotion_state.py,sha256=dy4kkSSAQ7bC0Xp2CociETGN-2aABEfL6FU5D9Jl00Y,6056
|
881
881
|
tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
|
882
882
|
tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
|
883
|
-
qontract_reconcile-0.10.
|
884
|
-
qontract_reconcile-0.10.
|
885
|
-
qontract_reconcile-0.10.
|
886
|
-
qontract_reconcile-0.10.
|
887
|
-
qontract_reconcile-0.10.
|
883
|
+
qontract_reconcile-0.10.1rc1170.dist-info/METADATA,sha256=jImSzLQtbCTK_xWaoXSosEFCUSEwNc55O8fQkGPhaxA,2213
|
884
|
+
qontract_reconcile-0.10.1rc1170.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
|
885
|
+
qontract_reconcile-0.10.1rc1170.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
|
886
|
+
qontract_reconcile-0.10.1rc1170.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
|
887
|
+
qontract_reconcile-0.10.1rc1170.dist-info/RECORD,,
|
reconcile/cli.py
CHANGED
@@ -1158,18 +1158,12 @@ def jenkins_webhooks_cleaner(ctx):
|
|
1158
1158
|
|
1159
1159
|
|
1160
1160
|
@integration.command(short_help="Validate permissions in Jira.")
|
1161
|
-
@click.option(
|
1162
|
-
"--exit-on-permission-errors/--no-exit-on-permission-errors",
|
1163
|
-
help="Throw and error in case of board permission errors. Useful for PR checks.",
|
1164
|
-
default=True,
|
1165
|
-
)
|
1166
1161
|
@enable_extended_early_exit
|
1167
1162
|
@extended_early_exit_cache_ttl_seconds
|
1168
1163
|
@log_cached_log_output
|
1169
1164
|
@click.pass_context
|
1170
1165
|
def jira_permissions_validator(
|
1171
1166
|
ctx,
|
1172
|
-
exit_on_permission_errors,
|
1173
1167
|
enable_extended_early_exit,
|
1174
1168
|
extended_early_exit_cache_ttl_seconds,
|
1175
1169
|
log_cached_log_output,
|
@@ -1179,7 +1173,6 @@ def jira_permissions_validator(
|
|
1179
1173
|
run_integration(
|
1180
1174
|
reconcile.jira_permissions_validator,
|
1181
1175
|
ctx.obj,
|
1182
|
-
exit_on_permission_errors,
|
1183
1176
|
enable_extended_early_exit=enable_extended_early_exit,
|
1184
1177
|
extended_early_exit_cache_ttl_seconds=extended_early_exit_cache_ttl_seconds,
|
1185
1178
|
log_cached_log_output=log_cached_log_output,
|
@@ -61,11 +61,12 @@ class ValidationError(IntFlag):
|
|
61
61
|
PERMISSION_ERROR = auto()
|
62
62
|
PUBLIC_PROJECT_NO_SECURITY_LEVEL = auto()
|
63
63
|
INVALID_COMPONENT = auto()
|
64
|
+
PROJECT_ARCHIVED = auto()
|
64
65
|
|
65
66
|
|
66
67
|
class RunnerParams(TypedDict):
|
67
|
-
exit_on_permission_errors: bool
|
68
68
|
boards: list[JiraBoardV1]
|
69
|
+
dry_run: bool
|
69
70
|
|
70
71
|
|
71
72
|
class CacheSource(TypedDict):
|
@@ -82,6 +83,10 @@ def board_is_valid(
|
|
82
83
|
) -> ValidationError:
|
83
84
|
error = ValidationError(0)
|
84
85
|
try:
|
86
|
+
if jira.is_archived:
|
87
|
+
logging.error(f"[{board.name}] project is archived")
|
88
|
+
return ValidationError.PROJECT_ARCHIVED
|
89
|
+
|
85
90
|
if not jira.can_create_issues():
|
86
91
|
logging.error(f"[{board.name}] can not create issues in project")
|
87
92
|
error |= ValidationError.CANT_CREATE_ISSUE
|
@@ -196,11 +201,11 @@ def board_is_valid(
|
|
196
201
|
def validate_boards(
|
197
202
|
metrics_container: metrics.MetricsContainer,
|
198
203
|
secret_reader: SecretReaderBase,
|
199
|
-
exit_on_permission_errors: bool,
|
200
204
|
jira_client_settings: JiraWatcherSettings | None,
|
201
205
|
jira_boards: Iterable[JiraBoardV1],
|
202
206
|
default_issue_type: str,
|
203
207
|
default_reopen_state: str,
|
208
|
+
dry_run: bool,
|
204
209
|
jira_client_class: type[JiraClient] = JiraClient,
|
205
210
|
) -> bool:
|
206
211
|
error = False
|
@@ -238,15 +243,15 @@ def validate_boards(
|
|
238
243
|
),
|
239
244
|
value=1,
|
240
245
|
)
|
241
|
-
|
242
|
-
|
243
|
-
if exit_on_permission_errors:
|
246
|
+
if dry_run:
|
247
|
+
# throw an error for MR checks but not in prod mode
|
244
248
|
error = True
|
245
249
|
case (
|
246
|
-
ValidationError.
|
250
|
+
ValidationError.CANT_CREATE_ISSUE | ValidationError.PROJECT_ARCHIVED
|
247
251
|
):
|
248
|
-
|
249
|
-
|
252
|
+
if dry_run:
|
253
|
+
# throw an error for MR checks but not in prod mode
|
254
|
+
error = True
|
250
255
|
case _:
|
251
256
|
error = True
|
252
257
|
except Exception as e:
|
@@ -269,7 +274,6 @@ def export_boards(boards: list[JiraBoardV1]) -> list[dict]:
|
|
269
274
|
|
270
275
|
def run(
|
271
276
|
dry_run: bool,
|
272
|
-
exit_on_permission_errors: bool,
|
273
277
|
enable_extended_early_exit: bool = False,
|
274
278
|
extended_early_exit_cache_ttl_seconds: int = 3600,
|
275
279
|
log_cached_log_output: bool = False,
|
@@ -277,8 +281,8 @@ def run(
|
|
277
281
|
gql_api = gql.get_api()
|
278
282
|
boards = get_jira_boards(query_func=gql_api.query)
|
279
283
|
runner_params: RunnerParams = {
|
280
|
-
"exit_on_permission_errors": exit_on_permission_errors,
|
281
284
|
"boards": boards,
|
285
|
+
"dry_run": dry_run,
|
282
286
|
}
|
283
287
|
if enable_extended_early_exit and get_feature_toggle_state(
|
284
288
|
"jira-permissions-validator-extended-early-exit",
|
@@ -308,9 +312,7 @@ def run(
|
|
308
312
|
runner(**runner_params)
|
309
313
|
|
310
314
|
|
311
|
-
def runner(
|
312
|
-
exit_on_permission_errors: bool, boards: list[JiraBoardV1]
|
313
|
-
) -> ExtendedEarlyExitRunnerResult:
|
315
|
+
def runner(boards: list[JiraBoardV1], dry_run: bool) -> ExtendedEarlyExitRunnerResult:
|
314
316
|
gql_api = gql.get_api()
|
315
317
|
settings = get_jira_settings(gql_api=gql_api)
|
316
318
|
jiralert_settings = get_jiralert_settings(query_func=gql_api.query)
|
@@ -321,11 +323,11 @@ def runner(
|
|
321
323
|
error = validate_boards(
|
322
324
|
metrics_container=metrics_container,
|
323
325
|
secret_reader=secret_reader,
|
324
|
-
exit_on_permission_errors=exit_on_permission_errors,
|
325
326
|
jira_client_settings=settings.jira_watcher,
|
326
327
|
jira_boards=boards,
|
327
328
|
default_issue_type=jiralert_settings.default_issue_type,
|
328
329
|
default_reopen_state=jiralert_settings.default_reopen_state,
|
330
|
+
dry_run=dry_run,
|
329
331
|
)
|
330
332
|
|
331
333
|
if error:
|
reconcile/queries.py
CHANGED
@@ -102,11 +102,12 @@ APP_INTERFACE_SETTINGS_QUERY = """
|
|
102
102
|
readTimeout
|
103
103
|
connectTimeout
|
104
104
|
}
|
105
|
-
|
106
|
-
|
107
|
-
|
105
|
+
terraformResourcesProviderExclusions {
|
106
|
+
provider
|
107
|
+
excludeProvisioners {
|
108
|
+
name
|
108
109
|
}
|
109
|
-
|
110
|
+
excludeAllProvisioners
|
110
111
|
}
|
111
112
|
}
|
112
113
|
}
|
@@ -2767,12 +2768,13 @@ def get_jenkins_configs():
|
|
2767
2768
|
|
2768
2769
|
TF_RESOURCES_PROVIDER_EXCLUSIONS_BY_PROVISIONER = """
|
2769
2770
|
{
|
2770
|
-
|
2771
|
-
|
2772
|
-
|
2773
|
-
|
2771
|
+
tf_provider_exclusions: app_interface_settings_v1 {
|
2772
|
+
terraformResourcesProviderExclusions {
|
2773
|
+
provider
|
2774
|
+
excludeProvisioners {
|
2775
|
+
name
|
2774
2776
|
}
|
2775
|
-
|
2777
|
+
excludeAllProvisioners
|
2776
2778
|
}
|
2777
2779
|
}
|
2778
2780
|
}
|
@@ -2784,13 +2786,10 @@ def get_tf_resources_provider_exclusions_by_provisioner() -> (
|
|
2784
2786
|
):
|
2785
2787
|
gqlapi = gql.get_api()
|
2786
2788
|
settings = gqlapi.query(TF_RESOURCES_PROVIDER_EXCLUSIONS_BY_PROVISIONER)[
|
2787
|
-
"
|
2789
|
+
"tf_provider_exclusions"
|
2788
2790
|
]
|
2789
|
-
if (
|
2790
|
-
|
2791
|
-
and "terraformResourcesProviderExclusionsByProvisioner" in settings[0]
|
2792
|
-
):
|
2793
|
-
return settings[0]["terraformResourcesProviderExclusionsByProvisioner"]
|
2791
|
+
if len(settings) == 1 and "terraformResourcesProviderExclusions" in settings[0]:
|
2792
|
+
return settings[0]["terraformResourcesProviderExclusions"]
|
2794
2793
|
return None
|
2795
2794
|
|
2796
2795
|
|
reconcile/terraform_resources.py
CHANGED
@@ -266,13 +266,11 @@ def setup(
|
|
266
266
|
ocm_map = None
|
267
267
|
tf_namespaces_dicts = [ns.dict(by_alias=True) for ns in tf_namespaces]
|
268
268
|
|
269
|
-
|
270
|
-
settings.get("terraformResourcesProviderExclusionsByProvisioner") or []
|
271
|
-
)
|
269
|
+
provider_exclusions = settings.get("terraformResourcesProviderExclusions") or []
|
272
270
|
ts.init_populate_specs(
|
273
271
|
tf_namespaces_dicts,
|
274
272
|
account_names,
|
275
|
-
|
273
|
+
provider_exclusions,
|
276
274
|
)
|
277
275
|
tf.populate_terraform_output_secrets(
|
278
276
|
resource_specs=ts.resource_spec_inventory, init_rds_replica_source=True
|
@@ -93,7 +93,7 @@ def test_jira_permissions_validator_get_jira_boards(
|
|
93
93
|
|
94
94
|
|
95
95
|
@pytest.mark.parametrize(
|
96
|
-
"board_is_valid,
|
96
|
+
"board_is_valid, dry_run, error_returned, metric_set",
|
97
97
|
[
|
98
98
|
(0, True, False, False),
|
99
99
|
(ValidationError.CANT_CREATE_ISSUE, True, True, False),
|
@@ -104,19 +104,11 @@ def test_jira_permissions_validator_get_jira_boards(
|
|
104
104
|
(ValidationError.INVALID_PRIORITY, True, True, False),
|
105
105
|
(ValidationError.PUBLIC_PROJECT_NO_SECURITY_LEVEL, True, True, False),
|
106
106
|
(ValidationError.PERMISSION_ERROR, True, True, True),
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
False,
|
113
|
-
),
|
114
|
-
(
|
115
|
-
ValidationError.CANT_CREATE_ISSUE | ValidationError.PERMISSION_ERROR,
|
116
|
-
False,
|
117
|
-
True,
|
118
|
-
False,
|
119
|
-
),
|
107
|
+
(ValidationError.PROJECT_ARCHIVED, True, True, False),
|
108
|
+
# no dry-run
|
109
|
+
(ValidationError.CANT_CREATE_ISSUE, False, False, False),
|
110
|
+
(ValidationError.PERMISSION_ERROR, False, False, True),
|
111
|
+
(ValidationError.PROJECT_ARCHIVED, False, False, False),
|
120
112
|
# test with another error
|
121
113
|
(
|
122
114
|
ValidationError.INVALID_PRIORITY | ValidationError.PERMISSION_ERROR,
|
@@ -137,7 +129,7 @@ def test_jira_permissions_validator_validate_boards(
|
|
137
129
|
boards: list[JiraBoardV1],
|
138
130
|
secret_reader: Mock,
|
139
131
|
board_is_valid: ValidationError,
|
140
|
-
|
132
|
+
dry_run: bool,
|
141
133
|
error_returned: bool,
|
142
134
|
metric_set: bool,
|
143
135
|
) -> None:
|
@@ -151,11 +143,11 @@ def test_jira_permissions_validator_validate_boards(
|
|
151
143
|
validate_boards(
|
152
144
|
metrics_container=metrics_container_mock,
|
153
145
|
secret_reader=secret_reader,
|
154
|
-
exit_on_permission_errors=exit_on_permission_errors,
|
155
146
|
jira_client_settings=None,
|
156
147
|
jira_boards=boards,
|
157
148
|
default_issue_type="task",
|
158
149
|
default_reopen_state="new",
|
150
|
+
dry_run=dry_run,
|
159
151
|
jira_client_class=jira_client_class,
|
160
152
|
)
|
161
153
|
== error_returned
|
@@ -192,6 +184,7 @@ def test_jira_permissions_validator_board_is_valid_happy_path(
|
|
192
184
|
},
|
193
185
|
)
|
194
186
|
jira_client = mocker.create_autospec(spec=JiraClient)
|
187
|
+
jira_client.is_archived = False
|
195
188
|
jira_client.can_create_issues.return_value = True
|
196
189
|
jira_client.can_transition_issues.return_value = True
|
197
190
|
jira_client.project_issue_types.return_value = [
|
@@ -239,6 +232,7 @@ def test_jira_permissions_validator_board_is_valid_all_errors(
|
|
239
232
|
},
|
240
233
|
)
|
241
234
|
jira_client = mocker.create_autospec(spec=JiraClient)
|
235
|
+
jira_client.is_archived = False
|
242
236
|
jira_client.can_create_issues.return_value = False
|
243
237
|
jira_client.can_transition_issues.return_value = False
|
244
238
|
jira_client.project_issue_types.return_value = []
|
@@ -290,6 +284,7 @@ def test_jira_permissions_validator_board_is_valid_bad_issue_status(
|
|
290
284
|
},
|
291
285
|
)
|
292
286
|
jira_client = mocker.create_autospec(spec=JiraClient)
|
287
|
+
jira_client.is_archived = False
|
293
288
|
jira_client.can_create_issues.return_value = True
|
294
289
|
jira_client.can_transition_issues.return_value = True
|
295
290
|
jira_client.project_issue_types.return_value = [
|
@@ -340,6 +335,7 @@ def test_jira_permissions_validator_board_is_valid_public_project(
|
|
340
335
|
},
|
341
336
|
)
|
342
337
|
jira_client = mocker.create_autospec(spec=JiraClient)
|
338
|
+
jira_client.is_archived = False
|
343
339
|
jira_client.can_create_issues.return_value = True
|
344
340
|
jira_client.can_transition_issues.return_value = True
|
345
341
|
jira_client.project_issue_types.return_value = [
|
@@ -390,6 +386,7 @@ def test_jira_permissions_validator_board_is_valid_permission_error(
|
|
390
386
|
},
|
391
387
|
)
|
392
388
|
jira_client = mocker.create_autospec(spec=JiraClient)
|
389
|
+
jira_client.is_archived = False
|
393
390
|
jira_client.can_create_issues.side_effect = JIRAError(status_code=403)
|
394
391
|
assert (
|
395
392
|
board_is_valid(
|
@@ -430,6 +427,7 @@ def test_jira_permissions_validator_board_is_valid_exception(
|
|
430
427
|
},
|
431
428
|
)
|
432
429
|
jira_client = mocker.create_autospec(spec=JiraClient)
|
430
|
+
jira_client.is_archived = False
|
433
431
|
jira_client.can_create_issues.side_effect = JIRAError(status_code=500)
|
434
432
|
with pytest.raises(JIRAError):
|
435
433
|
board_is_valid(
|
@@ -468,6 +466,7 @@ def test_jira_permissions_validator_board_is_valid_exception_401(
|
|
468
466
|
},
|
469
467
|
)
|
470
468
|
jira_client = mocker.create_autospec(spec=JiraClient)
|
469
|
+
jira_client.is_archived = False
|
471
470
|
jira_client.can_create_issues.side_effect = JIRAError(status_code=401)
|
472
471
|
# no error for 401
|
473
472
|
board_is_valid(
|
@@ -478,3 +477,43 @@ def test_jira_permissions_validator_board_is_valid_exception_401(
|
|
478
477
|
jira_server_priorities={"Minor": "1", "Major": "2", "Critical": "3"},
|
479
478
|
public_projects=[],
|
480
479
|
)
|
480
|
+
|
481
|
+
|
482
|
+
def test_jira_permissions_validator_board_is_valid_archived(
|
483
|
+
mocker: MockerFixture, gql_class_factory: Callable
|
484
|
+
) -> None:
|
485
|
+
board = gql_class_factory(
|
486
|
+
JiraBoardV1,
|
487
|
+
{
|
488
|
+
"name": "jira-board-default",
|
489
|
+
"server": {
|
490
|
+
"serverUrl": "https://jira-server.com",
|
491
|
+
"token": {"path": "vault/path/token", "field": "token"},
|
492
|
+
},
|
493
|
+
"issueType": "bug",
|
494
|
+
"issueResolveState": "Closed",
|
495
|
+
"issueReopenState": "Open",
|
496
|
+
"issueSecurityId": "32168",
|
497
|
+
"severityPriorityMappings": {
|
498
|
+
"name": "major-major",
|
499
|
+
"mappings": [
|
500
|
+
{"priority": "Minor"},
|
501
|
+
{"priority": "Major"},
|
502
|
+
{"priority": "Critical"},
|
503
|
+
],
|
504
|
+
},
|
505
|
+
},
|
506
|
+
)
|
507
|
+
jira_client = mocker.create_autospec(spec=JiraClient)
|
508
|
+
jira_client.is_archived = True
|
509
|
+
assert (
|
510
|
+
board_is_valid(
|
511
|
+
jira=jira_client,
|
512
|
+
board=board,
|
513
|
+
default_issue_type="task",
|
514
|
+
default_reopen_state="new",
|
515
|
+
jira_server_priorities={"Minor": "1", "Major": "2", "Critical": "3"},
|
516
|
+
public_projects=[],
|
517
|
+
)
|
518
|
+
== ValidationError.PROJECT_ARCHIVED
|
519
|
+
)
|
reconcile/utils/jira_client.py
CHANGED
@@ -241,3 +241,7 @@ class JiraClient:
|
|
241
241
|
def components(self) -> list[str]:
|
242
242
|
"""Return a list of all components for the project."""
|
243
243
|
return [c.name for c in self.jira.project_components(self.project)]
|
244
|
+
|
245
|
+
@property
|
246
|
+
def is_archived(self) -> bool:
|
247
|
+
return self.jira.project(self.project).archived
|
@@ -9,7 +9,7 @@ import string
|
|
9
9
|
import tempfile
|
10
10
|
from collections import Counter
|
11
11
|
from collections.abc import Iterable, Mapping, MutableMapping
|
12
|
-
from dataclasses import dataclass
|
12
|
+
from dataclasses import dataclass, field
|
13
13
|
from ipaddress import (
|
14
14
|
ip_address,
|
15
15
|
ip_network,
|
@@ -379,6 +379,12 @@ class ElasticSearchLogGroupInfo:
|
|
379
379
|
log_group_identifier: str
|
380
380
|
|
381
381
|
|
382
|
+
@dataclass
|
383
|
+
class Exclusion:
|
384
|
+
all: bool = False
|
385
|
+
provisioners: set[str] = field(default_factory=set)
|
386
|
+
|
387
|
+
|
382
388
|
class ProviderExcludedError(Exception):
|
383
389
|
def __init__(self, spec: ExternalResourceSpec) -> None:
|
384
390
|
super().__init__(
|
@@ -1543,38 +1549,49 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1543
1549
|
for spec in specs:
|
1544
1550
|
self.populate_tf_resources(spec, ocm_map=ocm_map)
|
1545
1551
|
|
1546
|
-
def
|
1552
|
+
def _is_provisioner_excluded(
|
1547
1553
|
self,
|
1548
1554
|
spec: ExternalResourceSpec,
|
1549
|
-
|
1550
|
-
) ->
|
1551
|
-
|
1552
|
-
|
1553
|
-
|
1555
|
+
provider_exclusions: Mapping[str, Exclusion],
|
1556
|
+
) -> bool:
|
1557
|
+
e = provider_exclusions.get(spec.provider)
|
1558
|
+
if not e:
|
1559
|
+
return False
|
1560
|
+
return e.all or spec.provisioner_name in e.provisioners
|
1554
1561
|
|
1555
1562
|
def _filter_specs_managed_by_erv2(
|
1556
1563
|
self,
|
1557
1564
|
specs: Iterable[ExternalResourceSpec],
|
1558
|
-
|
1565
|
+
provider_exclusions: Mapping[str, Exclusion],
|
1559
1566
|
) -> list[ExternalResourceSpec]:
|
1560
|
-
filtered_specs
|
1561
|
-
|
1562
|
-
|
1563
|
-
continue
|
1567
|
+
filtered_specs = [
|
1568
|
+
spec for spec in specs if not spec.resource.get("managed_by_erv2")
|
1569
|
+
]
|
1564
1570
|
|
1565
|
-
|
1566
|
-
|
1567
|
-
):
|
1571
|
+
for spec in filtered_specs:
|
1572
|
+
if self._is_provisioner_excluded(spec, provider_exclusions):
|
1568
1573
|
raise ProviderExcludedError(spec)
|
1569
1574
|
|
1570
|
-
filtered_specs.append(spec)
|
1571
1575
|
return filtered_specs
|
1572
1576
|
|
1577
|
+
def _get_provider_exclusions_query_dict(
|
1578
|
+
self, provider_exclusions: Iterable[Mapping[str, Any]]
|
1579
|
+
) -> dict[str, Exclusion]:
|
1580
|
+
return {
|
1581
|
+
item["provider"]: Exclusion(
|
1582
|
+
all=item.get("excludeAllProvisioners") or False,
|
1583
|
+
provisioners={
|
1584
|
+
p["name"] for p in (item.get("excludeProvisioners") or [])
|
1585
|
+
},
|
1586
|
+
)
|
1587
|
+
for item in provider_exclusions
|
1588
|
+
}
|
1589
|
+
|
1573
1590
|
def init_populate_specs(
|
1574
1591
|
self,
|
1575
1592
|
namespaces: Iterable[Mapping[str, Any]],
|
1576
1593
|
account_names: Iterable[str] | None,
|
1577
|
-
|
1594
|
+
provider_exclusions: Iterable[Mapping[str, Any]] | None = None,
|
1578
1595
|
) -> None:
|
1579
1596
|
"""
|
1580
1597
|
Initiates resource specs from the definitions in app-interface
|
@@ -1586,15 +1603,14 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1586
1603
|
self.resource_spec_inventory: ExternalResourceSpecInventory = {}
|
1587
1604
|
|
1588
1605
|
# Ensure provider exclusions are fetched
|
1589
|
-
if
|
1590
|
-
|
1606
|
+
if provider_exclusions is None:
|
1607
|
+
provider_exclusions = (
|
1591
1608
|
queries.get_tf_resources_provider_exclusions_by_provisioner() or []
|
1592
1609
|
)
|
1593
1610
|
|
1594
|
-
|
1595
|
-
|
1596
|
-
|
1597
|
-
}
|
1611
|
+
provider_exclusions_query_dict = self._get_provider_exclusions_query_dict(
|
1612
|
+
provider_exclusions
|
1613
|
+
)
|
1598
1614
|
|
1599
1615
|
for namespace_info in namespaces:
|
1600
1616
|
all_specs = get_external_resource_specs(
|
@@ -1602,7 +1618,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1602
1618
|
provision_provider=PROVIDER_AWS,
|
1603
1619
|
)
|
1604
1620
|
specs = self._filter_specs_managed_by_erv2(
|
1605
|
-
all_specs,
|
1621
|
+
all_specs, provider_exclusions_query_dict
|
1606
1622
|
)
|
1607
1623
|
name_counter = Counter(spec.output_resource_name for spec in specs)
|
1608
1624
|
duplicates = [name for name, count in name_counter.items() if count > 1]
|
{qontract_reconcile-0.10.1rc1168.dist-info → qontract_reconcile-0.10.1rc1170.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|
File without changes
|