qontract-reconcile 0.10.1rc884__py3-none-any.whl → 0.10.1rc885__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.
Files changed (276) hide show
  1. {qontract_reconcile-0.10.1rc884.dist-info → qontract_reconcile-0.10.1rc885.dist-info}/METADATA +1 -1
  2. {qontract_reconcile-0.10.1rc884.dist-info → qontract_reconcile-0.10.1rc885.dist-info}/RECORD +276 -276
  3. reconcile/acs_rbac.py +1 -2
  4. reconcile/aus/advanced_upgrade_service.py +14 -14
  5. reconcile/aus/aus_label_source.py +1 -2
  6. reconcile/aus/base.py +23 -26
  7. reconcile/aus/cluster_version_data.py +4 -4
  8. reconcile/aus/models.py +2 -3
  9. reconcile/aus/version_gate_approver.py +2 -6
  10. reconcile/aus/version_gates/__init__.py +1 -3
  11. reconcile/aus/version_gates/sts_version_gate_handler.py +2 -3
  12. reconcile/aws_account_manager/integration.py +2 -2
  13. reconcile/aws_ami_cleanup/integration.py +3 -4
  14. reconcile/aws_iam_password_reset.py +2 -5
  15. reconcile/aws_version_sync/integration.py +2 -2
  16. reconcile/blackbox_exporter_endpoint_monitoring.py +2 -5
  17. reconcile/change_owners/approver.py +4 -5
  18. reconcile/change_owners/bundle.py +20 -22
  19. reconcile/change_owners/change_types.py +23 -24
  20. reconcile/change_owners/changes.py +13 -16
  21. reconcile/change_owners/decision.py +2 -5
  22. reconcile/change_owners/diff.py +11 -15
  23. reconcile/change_owners/self_service_roles.py +1 -2
  24. reconcile/change_owners/tester.py +7 -10
  25. reconcile/checkpoint.py +2 -5
  26. reconcile/cli.py +9 -12
  27. reconcile/closedbox_endpoint_monitoring_base.py +8 -11
  28. reconcile/cluster_deployment_mapper.py +2 -5
  29. reconcile/cna/assets/asset.py +4 -7
  30. reconcile/cna/assets/null.py +2 -5
  31. reconcile/cna/integration.py +2 -3
  32. reconcile/cna/state.py +2 -5
  33. reconcile/dashdotdb_base.py +8 -11
  34. reconcile/dashdotdb_cso.py +3 -6
  35. reconcile/dashdotdb_dora.py +10 -14
  36. reconcile/dashdotdb_dvo.py +10 -13
  37. reconcile/dashdotdb_slo.py +5 -8
  38. reconcile/database_access_manager.py +5 -6
  39. reconcile/dynatrace_token_provider/integration.py +2 -5
  40. reconcile/external_resources/integration.py +1 -1
  41. reconcile/external_resources/manager.py +4 -4
  42. reconcile/external_resources/model.py +3 -3
  43. reconcile/external_resources/secrets_sync.py +5 -5
  44. reconcile/external_resources/state.py +5 -5
  45. reconcile/gabi_authorized_users.py +3 -6
  46. reconcile/gcr_mirror.py +1 -1
  47. reconcile/github_org.py +1 -3
  48. reconcile/github_repo_invites.py +2 -5
  49. reconcile/gitlab_housekeeping.py +7 -11
  50. reconcile/gitlab_labeler.py +1 -2
  51. reconcile/gitlab_members.py +2 -5
  52. reconcile/gitlab_permissions.py +1 -3
  53. reconcile/glitchtip/integration.py +2 -5
  54. reconcile/glitchtip_project_alerts/integration.py +3 -6
  55. reconcile/glitchtip_project_dsn/integration.py +4 -7
  56. reconcile/integrations_manager.py +5 -8
  57. reconcile/jenkins/types.py +5 -6
  58. reconcile/jenkins_job_builder.py +9 -12
  59. reconcile/jenkins_roles.py +1 -1
  60. reconcile/jira_watcher.py +2 -2
  61. reconcile/ldap_groups/integration.py +2 -5
  62. reconcile/ocm/types.py +21 -26
  63. reconcile/ocm_addons_upgrade_tests_trigger.py +3 -6
  64. reconcile/ocm_clusters.py +8 -8
  65. reconcile/ocm_internal_notifications/integration.py +1 -2
  66. reconcile/ocm_labels/integration.py +2 -5
  67. reconcile/ocm_machine_pools.py +11 -15
  68. reconcile/ocm_upgrade_scheduler_org_updater.py +2 -5
  69. reconcile/openshift_base.py +27 -29
  70. reconcile/openshift_groups.py +15 -20
  71. reconcile/openshift_namespace_labels.py +8 -14
  72. reconcile/openshift_namespaces.py +5 -8
  73. reconcile/openshift_network_policies.py +2 -4
  74. reconcile/openshift_resources_base.py +19 -29
  75. reconcile/openshift_saas_deploy.py +9 -10
  76. reconcile/openshift_saas_deploy_change_tester.py +7 -10
  77. reconcile/openshift_saas_deploy_trigger_base.py +4 -7
  78. reconcile/openshift_saas_deploy_trigger_cleaner.py +5 -8
  79. reconcile/openshift_saas_deploy_trigger_configs.py +1 -2
  80. reconcile/openshift_saas_deploy_trigger_images.py +1 -2
  81. reconcile/openshift_saas_deploy_trigger_moving_commits.py +1 -2
  82. reconcile/openshift_saas_deploy_trigger_upstream_jobs.py +1 -2
  83. reconcile/openshift_tekton_resources.py +7 -11
  84. reconcile/openshift_upgrade_watcher.py +10 -13
  85. reconcile/openshift_users.py +8 -11
  86. reconcile/oum/base.py +3 -4
  87. reconcile/oum/labelset.py +1 -2
  88. reconcile/oum/metrics.py +2 -2
  89. reconcile/oum/models.py +1 -2
  90. reconcile/oum/standalone.py +2 -3
  91. reconcile/prometheus_rules_tester/integration.py +6 -9
  92. reconcile/quay_membership.py +1 -2
  93. reconcile/quay_mirror.py +12 -13
  94. reconcile/quay_mirror_org.py +10 -10
  95. reconcile/queries.py +4 -7
  96. reconcile/resource_scraper.py +3 -4
  97. reconcile/rhidp/common.py +2 -2
  98. reconcile/saas_auto_promotions_manager/integration.py +5 -6
  99. reconcile/saas_auto_promotions_manager/merge_request_manager/batcher.py +1 -2
  100. reconcile/saas_auto_promotions_manager/publisher.py +5 -6
  101. reconcile/saas_auto_promotions_manager/subscriber.py +3 -4
  102. reconcile/saas_file_validator.py +2 -5
  103. reconcile/signalfx_endpoint_monitoring.py +2 -5
  104. reconcile/skupper_network/integration.py +3 -6
  105. reconcile/skupper_network/models.py +3 -5
  106. reconcile/slack_base.py +4 -7
  107. reconcile/slack_usergroups.py +15 -17
  108. reconcile/sql_query.py +5 -9
  109. reconcile/status_board.py +4 -5
  110. reconcile/statuspage/atlassian.py +14 -15
  111. reconcile/statuspage/integrations/maintenances.py +3 -3
  112. reconcile/statuspage/page.py +8 -8
  113. reconcile/statuspage/state.py +4 -5
  114. reconcile/statuspage/status.py +7 -8
  115. reconcile/templating/lib/rendering.py +8 -8
  116. reconcile/templating/renderer.py +10 -11
  117. reconcile/templating/validator.py +4 -4
  118. reconcile/terraform_aws_route53.py +3 -6
  119. reconcile/terraform_cloudflare_dns.py +9 -12
  120. reconcile/terraform_cloudflare_resources.py +9 -11
  121. reconcile/terraform_cloudflare_users.py +8 -11
  122. reconcile/terraform_init/integration.py +2 -2
  123. reconcile/terraform_repo.py +11 -14
  124. reconcile/terraform_resources.py +20 -21
  125. reconcile/terraform_tgw_attachments.py +32 -36
  126. reconcile/terraform_users.py +6 -7
  127. reconcile/terraform_vpc_resources/integration.py +5 -5
  128. reconcile/test/conftest.py +7 -10
  129. reconcile/test/fixtures.py +1 -1
  130. reconcile/test/saas_auto_promotions_manager/conftest.py +2 -2
  131. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py +2 -2
  132. reconcile/test/test_database_access_manager.py +3 -6
  133. reconcile/test/test_gitlab_labeler.py +2 -5
  134. reconcile/test/test_jump_host.py +5 -8
  135. reconcile/test/test_ocm_machine_pools.py +1 -4
  136. reconcile/test/test_openshift_base.py +3 -6
  137. reconcile/test/test_openshift_cluster_bots.py +5 -5
  138. reconcile/test/test_openshift_namespace_labels.py +2 -3
  139. reconcile/test/test_openshift_saas_deploy_trigger_cleaner.py +2 -2
  140. reconcile/test/test_saasherder.py +9 -12
  141. reconcile/test/test_slack_base.py +4 -6
  142. reconcile/test/test_status_board.py +4 -7
  143. reconcile/test/test_terraform_tgw_attachments.py +14 -20
  144. reconcile/typed_queries/alerting_services_settings.py +1 -2
  145. reconcile/typed_queries/app_interface_custom_messages.py +2 -3
  146. reconcile/typed_queries/app_interface_deadmanssnitch_settings.py +1 -3
  147. reconcile/typed_queries/app_interface_repo_url.py +1 -2
  148. reconcile/typed_queries/app_interface_state_settings.py +1 -3
  149. reconcile/typed_queries/app_interface_vault_settings.py +1 -2
  150. reconcile/typed_queries/aws_vpc_requests.py +1 -3
  151. reconcile/typed_queries/aws_vpcs.py +1 -3
  152. reconcile/typed_queries/clusters.py +2 -4
  153. reconcile/typed_queries/clusters_minimal.py +1 -3
  154. reconcile/typed_queries/clusters_with_dms.py +1 -3
  155. reconcile/typed_queries/external_resources.py +3 -4
  156. reconcile/typed_queries/pagerduty_instances.py +1 -2
  157. reconcile/typed_queries/repos.py +2 -3
  158. reconcile/typed_queries/reserved_networks.py +1 -3
  159. reconcile/typed_queries/saas_files.py +49 -59
  160. reconcile/typed_queries/slo_documents.py +1 -3
  161. reconcile/typed_queries/status_board.py +3 -7
  162. reconcile/typed_queries/tekton_pipeline_providers.py +1 -2
  163. reconcile/typed_queries/terraform_namespaces.py +1 -2
  164. reconcile/typed_queries/terraform_tgw_attachments/aws_accounts.py +1 -3
  165. reconcile/utils/acs/base.py +2 -3
  166. reconcile/utils/acs/notifiers.py +3 -3
  167. reconcile/utils/acs/policies.py +3 -3
  168. reconcile/utils/aggregated_list.py +1 -1
  169. reconcile/utils/amtool.py +1 -2
  170. reconcile/utils/aws_api.py +28 -31
  171. reconcile/utils/binary.py +1 -3
  172. reconcile/utils/clusterhealth/providerbase.py +1 -2
  173. reconcile/utils/clusterhealth/telemeter.py +2 -2
  174. reconcile/utils/deadmanssnitch_api.py +1 -2
  175. reconcile/utils/disabled_integrations.py +4 -6
  176. reconcile/utils/environ.py +1 -1
  177. reconcile/utils/expiration.py +3 -7
  178. reconcile/utils/external_resource_spec.py +3 -4
  179. reconcile/utils/external_resources.py +4 -7
  180. reconcile/utils/filtering.py +1 -2
  181. reconcile/utils/git.py +3 -9
  182. reconcile/utils/git_secrets.py +5 -5
  183. reconcile/utils/github_api.py +5 -9
  184. reconcile/utils/gitlab_api.py +2 -3
  185. reconcile/utils/glitchtip/client.py +2 -4
  186. reconcile/utils/glitchtip/models.py +8 -11
  187. reconcile/utils/gql.py +26 -35
  188. reconcile/utils/grouping.py +1 -3
  189. reconcile/utils/imap_client.py +2 -5
  190. reconcile/utils/internal_groups/client.py +1 -2
  191. reconcile/utils/internal_groups/models.py +8 -9
  192. reconcile/utils/jenkins_api.py +4 -4
  193. reconcile/utils/jinja2/extensions.py +1 -1
  194. reconcile/utils/jinja2/filters.py +4 -4
  195. reconcile/utils/jinja2/utils.py +16 -16
  196. reconcile/utils/jira_client.py +10 -11
  197. reconcile/utils/jjb_client.py +14 -17
  198. reconcile/utils/jobcontroller/controller.py +5 -5
  199. reconcile/utils/jobcontroller/models.py +2 -2
  200. reconcile/utils/jsonpath.py +4 -5
  201. reconcile/utils/jump_host.py +7 -8
  202. reconcile/utils/keycloak.py +3 -7
  203. reconcile/utils/ldap_client.py +2 -3
  204. reconcile/utils/lean_terraform_client.py +13 -17
  205. reconcile/utils/membershipsources/app_interface_resolver.py +1 -1
  206. reconcile/utils/membershipsources/models.py +19 -22
  207. reconcile/utils/metrics.py +13 -15
  208. reconcile/utils/mr/base.py +7 -11
  209. reconcile/utils/mr/glitchtip_access_reporter.py +2 -2
  210. reconcile/utils/mr/notificator.py +1 -2
  211. reconcile/utils/oc.py +32 -38
  212. reconcile/utils/oc_connection_parameters.py +24 -25
  213. reconcile/utils/oc_filters.py +2 -3
  214. reconcile/utils/oc_map.py +9 -15
  215. reconcile/utils/ocm/addons.py +7 -10
  216. reconcile/utils/ocm/base.py +38 -39
  217. reconcile/utils/ocm/clusters.py +6 -9
  218. reconcile/utils/ocm/label_sources.py +1 -2
  219. reconcile/utils/ocm/labels.py +3 -6
  220. reconcile/utils/ocm/ocm.py +11 -14
  221. reconcile/utils/ocm/products.py +1 -3
  222. reconcile/utils/ocm/search_filters.py +16 -17
  223. reconcile/utils/ocm/service_log.py +2 -3
  224. reconcile/utils/ocm/sre_capability_labels.py +4 -8
  225. reconcile/utils/ocm/subscriptions.py +1 -3
  226. reconcile/utils/ocm/syncsets.py +2 -4
  227. reconcile/utils/ocm/upgrades.py +5 -9
  228. reconcile/utils/ocm_base_client.py +13 -16
  229. reconcile/utils/openshift_resource.py +5 -11
  230. reconcile/utils/output.py +2 -3
  231. reconcile/utils/pagerduty_api.py +4 -5
  232. reconcile/utils/prometheus.py +2 -2
  233. reconcile/utils/promotion_state.py +4 -5
  234. reconcile/utils/promtool.py +2 -8
  235. reconcile/utils/quay_api.py +12 -22
  236. reconcile/utils/raw_github_api.py +3 -5
  237. reconcile/utils/rosa/rosa_cli.py +6 -6
  238. reconcile/utils/rosa/session.py +6 -7
  239. reconcile/utils/runtime/desired_state_diff.py +3 -8
  240. reconcile/utils/runtime/environment.py +4 -7
  241. reconcile/utils/runtime/integration.py +4 -4
  242. reconcile/utils/runtime/meta.py +1 -2
  243. reconcile/utils/runtime/runner.py +7 -10
  244. reconcile/utils/runtime/sharding.py +22 -27
  245. reconcile/utils/saasherder/interfaces.py +63 -69
  246. reconcile/utils/saasherder/models.py +30 -35
  247. reconcile/utils/saasherder/saasherder.py +37 -53
  248. reconcile/utils/secret_reader.py +17 -19
  249. reconcile/utils/slack_api.py +15 -17
  250. reconcile/utils/smtp_client.py +1 -2
  251. reconcile/utils/sqs_gateway.py +1 -3
  252. reconcile/utils/state.py +1 -2
  253. reconcile/utils/terraform/config_client.py +4 -5
  254. reconcile/utils/terraform_client.py +3 -8
  255. reconcile/utils/terrascript/cloudflare_client.py +4 -10
  256. reconcile/utils/terrascript/cloudflare_resources.py +10 -13
  257. reconcile/utils/terrascript/models.py +2 -3
  258. reconcile/utils/terrascript/resources.py +1 -2
  259. reconcile/utils/terrascript_aws_client.py +30 -38
  260. reconcile/utils/unleash/client.py +4 -7
  261. reconcile/utils/unleash/server.py +2 -2
  262. reconcile/utils/vault.py +8 -11
  263. reconcile/utils/vaultsecretref.py +2 -3
  264. reconcile/utils/vcs.py +7 -8
  265. reconcile/vault_replication.py +4 -8
  266. reconcile/vpc_peerings_validator.py +4 -9
  267. release/version.py +6 -7
  268. tools/app_interface_reporter.py +2 -2
  269. tools/cli_commands/gpg_encrypt.py +3 -6
  270. tools/cli_commands/systems_and_tools.py +4 -7
  271. tools/qontract_cli.py +12 -17
  272. tools/template_validation.py +1 -1
  273. tools/test/conftest.py +3 -6
  274. {qontract_reconcile-0.10.1rc884.dist-info → qontract_reconcile-0.10.1rc885.dist-info}/WHEEL +0 -0
  275. {qontract_reconcile-0.10.1rc884.dist-info → qontract_reconcile-0.10.1rc885.dist-info}/entry_points.txt +0 -0
  276. {qontract_reconcile-0.10.1rc884.dist-info → qontract_reconcile-0.10.1rc885.dist-info}/top_level.txt +0 -0
@@ -12,9 +12,7 @@ from dataclasses import (
12
12
  )
13
13
  from typing import (
14
14
  Any,
15
- Optional,
16
15
  Protocol,
17
- Union,
18
16
  runtime_checkable,
19
17
  )
20
18
 
@@ -74,7 +72,7 @@ class BaseStateSpec:
74
72
  @dataclass
75
73
  class CurrentStateSpec(BaseStateSpec):
76
74
  kind: str
77
- resource_names: Optional[Iterable[str]]
75
+ resource_names: Iterable[str] | None
78
76
 
79
77
 
80
78
  @dataclass
@@ -84,7 +82,7 @@ class DesiredStateSpec(BaseStateSpec):
84
82
  privileged: bool = False
85
83
 
86
84
 
87
- StateSpec = Union[CurrentStateSpec, DesiredStateSpec]
85
+ StateSpec = CurrentStateSpec | DesiredStateSpec
88
86
 
89
87
 
90
88
  @runtime_checkable
@@ -114,7 +112,7 @@ class HasOrgAndGithubUsername(Protocol):
114
112
  class ClusterMap(Protocol):
115
113
  """An OCMap protocol."""
116
114
 
117
- def get(self, cluster: str, privileged: bool = False) -> Union[OCCli, OCLogMsg]: ...
115
+ def get(self, cluster: str, privileged: bool = False) -> OCCli | OCLogMsg: ...
118
116
 
119
117
  def get_cluster(self, cluster: str, privileged: bool = False) -> OCCli: ...
120
118
 
@@ -126,9 +124,9 @@ class ClusterMap(Protocol):
126
124
  def init_specs_to_fetch(
127
125
  ri: ResourceInventory,
128
126
  oc_map: ClusterMap,
129
- namespaces: Optional[Iterable[Mapping]] = None,
130
- clusters: Optional[Iterable[Mapping]] = None,
131
- override_managed_types: Optional[Iterable[str]] = None,
127
+ namespaces: Iterable[Mapping] | None = None,
128
+ clusters: Iterable[Mapping] | None = None,
129
+ override_managed_types: Iterable[str] | None = None,
132
130
  managed_types_key: str = "managedResourceTypes",
133
131
  ) -> list[StateSpec]:
134
132
  state_specs: list[StateSpec] = []
@@ -289,7 +287,7 @@ def populate_current_state(
289
287
  ri: ResourceInventory,
290
288
  integration: str,
291
289
  integration_version: str,
292
- caller: Optional[str] = None,
290
+ caller: str | None = None,
293
291
  ):
294
292
  # if spec.oc is None: - oc can't be none because init_namespace_specs_to_fetch does not create specs if oc is none
295
293
  # return
@@ -319,17 +317,17 @@ def populate_current_state(
319
317
 
320
318
 
321
319
  def fetch_current_state(
322
- namespaces: Optional[Iterable[Mapping]] = None,
323
- clusters: Optional[Iterable[Mapping]] = None,
324
- thread_pool_size: Optional[int] = None,
325
- integration: Optional[str] = None,
326
- integration_version: Optional[str] = None,
327
- override_managed_types: Optional[Iterable[str]] = None,
328
- internal: Optional[bool] = None,
320
+ namespaces: Iterable[Mapping] | None = None,
321
+ clusters: Iterable[Mapping] | None = None,
322
+ thread_pool_size: int | None = None,
323
+ integration: str | None = None,
324
+ integration_version: str | None = None,
325
+ override_managed_types: Iterable[str] | None = None,
326
+ internal: bool | None = None,
329
327
  use_jump_host: bool = True,
330
328
  init_api_resources: bool = False,
331
329
  cluster_admin: bool = False,
332
- caller: Optional[str] = None,
330
+ caller: str | None = None,
333
331
  ) -> tuple[ResourceInventory, OC_Map]:
334
332
  ri = ResourceInventory()
335
333
  settings = queries.get_app_interface_settings()
@@ -568,11 +566,11 @@ class ApplyOptions:
568
566
  wait_for_namespace: bool
569
567
  recycle_pods: bool
570
568
  take_over: bool
571
- override_enable_deletion: Optional[bool]
572
- caller: Optional[str]
573
- all_callers: Optional[Sequence[str]]
574
- privileged: Optional[bool]
575
- enable_deletion: Optional[bool]
569
+ override_enable_deletion: bool | None
570
+ caller: str | None
571
+ all_callers: Sequence[str] | None
572
+ privileged: bool | None
573
+ enable_deletion: bool | None
576
574
 
577
575
 
578
576
  def should_apply(
@@ -887,7 +885,7 @@ def delete_action(
887
885
  )
888
886
  except StatusCodeError as e:
889
887
  ri.register_error()
890
- msg = "[{}/{}] {}".format(cluster, namespace, str(e))
888
+ msg = f"[{cluster}/{namespace}] {str(e)}"
891
889
  logging.error(msg)
892
890
 
893
891
 
@@ -932,7 +930,7 @@ def _realize_resource_data_3way_diff(
932
930
  actions: list[dict] = []
933
931
 
934
932
  if ri.has_error_registered(cluster=cluster):
935
- msg = ("[{}] skipping realize_data for " "cluster with errors").format(cluster)
933
+ msg = f"[{cluster}] skipping realize_data for " "cluster with errors"
936
934
  logging.error(msg)
937
935
  return actions
938
936
 
@@ -1306,8 +1304,8 @@ def aggregate_shared_resources(namespace_info, shared_resources_type):
1306
1304
 
1307
1305
  def determine_user_keys_for_access(
1308
1306
  cluster_name: str,
1309
- auth_list: Sequence[Union[dict[str, str], HasService]],
1310
- enforced_user_keys: Optional[list[str]] = None,
1307
+ auth_list: Sequence[dict[str, str] | HasService],
1308
+ enforced_user_keys: list[str] | None = None,
1311
1309
  ) -> list[str]:
1312
1310
  """Return user keys based on enabled cluster authentication methods."""
1313
1311
  AUTH_METHOD_USER_KEY = {
@@ -1353,7 +1351,7 @@ def user_has_cluster_access(
1353
1351
  ) -> bool:
1354
1352
  """Check user has access to cluster."""
1355
1353
  userkeys = determine_user_keys_for_access(cluster.name, cluster.auth)
1356
- return any((getattr(user, userkey) in cluster_users for userkey in userkeys))
1354
+ return any(getattr(user, userkey) in cluster_users for userkey in userkeys)
1357
1355
 
1358
1356
 
1359
1357
  def get_namespace_type_overrides(namespace: Mapping) -> dict[str, str]:
@@ -1369,7 +1367,7 @@ def get_namespace_type_overrides(namespace: Mapping) -> dict[str, str]:
1369
1367
 
1370
1368
 
1371
1369
  def get_namespace_resource_types(
1372
- namespace: Mapping, type_overrides: Optional[dict[str, str]] = None
1370
+ namespace: Mapping, type_overrides: dict[str, str] | None = None
1373
1371
  ) -> list[str]:
1374
1372
  """Returns a list with the namespace ResourceTypes, with the overrides in place
1375
1373
 
@@ -1386,7 +1384,7 @@ def get_namespace_resource_types(
1386
1384
 
1387
1385
 
1388
1386
  def get_namespace_resource_names(
1389
- namespace: Mapping, type_overrides: Optional[dict[str, str]] = None
1387
+ namespace: Mapping, type_overrides: dict[str, str] | None = None
1390
1388
  ) -> dict[str, list[str]]:
1391
1389
  """Returns a list with the namespace ResourceTypeNames, with the overrides in place
1392
1390
 
@@ -5,10 +5,7 @@ from collections.abc import (
5
5
  Iterable,
6
6
  Mapping,
7
7
  )
8
- from typing import (
9
- Any,
10
- Optional,
11
- )
8
+ from typing import Any
12
9
 
13
10
  from sretoolbox.utils import threaded
14
11
 
@@ -53,9 +50,7 @@ def get_cluster_state(
53
50
  try:
54
51
  group = oc.get_group_if_exists(group_name)
55
52
  except Exception as e:
56
- msg = ("could not get group state for cluster/group combination: {}/{}").format(
57
- cluster, group_name
58
- )
53
+ msg = f"could not get group state for cluster/group combination: {cluster}/{group_name}"
59
54
  logging.error(msg)
60
55
  raise e
61
56
  if group is None:
@@ -84,7 +79,7 @@ def create_groups_list(
84
79
 
85
80
 
86
81
  def fetch_current_state(
87
- thread_pool_size: int, internal: Optional[bool], use_jump_host: bool
82
+ thread_pool_size: int, internal: bool | None, use_jump_host: bool
88
83
  ) -> tuple[OCMap, list[dict[str, str]], list[str], list[dict[str, str]]]:
89
84
  clusters = [c for c in get_clusters() if is_in_shard(c.name)]
90
85
  ocm_clusters = [c.name for c in clusters if c.ocm is not None]
@@ -110,7 +105,7 @@ def fetch_current_state(
110
105
 
111
106
 
112
107
  def fetch_desired_state(
113
- clusters: list[str], enforced_user_keys: Optional[list[str]] = None
108
+ clusters: list[str], enforced_user_keys: list[str] | None = None
114
109
  ) -> list[dict[str, str]]:
115
110
  gqlapi = gql.get_api()
116
111
  roles = expiration.filter(query_managed_roles(query_func=gqlapi.query).roles or [])
@@ -145,8 +140,8 @@ def fetch_desired_state(
145
140
  def calculate_diff(
146
141
  current_state: Iterable[Mapping[str, str]],
147
142
  desired_state: Iterable[Mapping[str, str]],
148
- ) -> list[dict[str, Optional[str]]]:
149
- diff: list[dict[str, Optional[str]]] = []
143
+ ) -> list[dict[str, str | None]]:
144
+ diff: list[dict[str, str | None]] = []
150
145
  users_to_add = subtract_states(
151
146
  desired_state, current_state, "add_user_to_group", "create_group"
152
147
  )
@@ -164,8 +159,8 @@ def subtract_states(
164
159
  subtract_state: Iterable[Mapping[str, str]],
165
160
  user_action: str,
166
161
  group_action: str,
167
- ) -> list[dict[str, Optional[str]]]:
168
- result: list[dict[str, Optional[str]]] = []
162
+ ) -> list[dict[str, str | None]]:
163
+ result: list[dict[str, str | None]] = []
169
164
 
170
165
  for f_user in from_state:
171
166
  found = False
@@ -199,14 +194,14 @@ def subtract_states(
199
194
  return result
200
195
 
201
196
 
202
- def validate_diffs(diffs: Iterable[Mapping[str, Optional[str]]]) -> None:
197
+ def validate_diffs(diffs: Iterable[Mapping[str, str | None]]) -> None:
203
198
  gqlapi = gql.get_api()
204
199
  clusters_query = query_managed_groups(query_func=gqlapi.query).clusters or []
205
200
 
206
201
  desired_combos = [
207
202
  {"cluster": diff["cluster"], "group": diff["group"]} for diff in diffs
208
203
  ]
209
- desired_combos_unique: list[dict[str, Optional[str]]] = []
204
+ desired_combos_unique: list[dict[str, str | None]] = []
210
205
  for combo in desired_combos:
211
206
  if combo in desired_combos_unique:
212
207
  continue
@@ -232,13 +227,13 @@ def validate_diffs(diffs: Iterable[Mapping[str, Optional[str]]]) -> None:
232
227
  raise RuntimeError(msg)
233
228
 
234
229
 
235
- def sort_diffs(diff: Mapping[str, Optional[str]]) -> int:
230
+ def sort_diffs(diff: Mapping[str, str | None]) -> int:
236
231
  if diff["action"] in {"create_group", "del_user_from_group"}:
237
232
  return 1
238
233
  return 2
239
234
 
240
235
 
241
- def act(diff: Mapping[str, Optional[str]], oc_map: ClusterMap) -> None:
236
+ def act(diff: Mapping[str, str | None], oc_map: ClusterMap) -> None:
242
237
  cluster = diff.get("cluster") or ""
243
238
  group = diff["group"]
244
239
  user = diff["user"]
@@ -257,16 +252,16 @@ def act(diff: Mapping[str, Optional[str]], oc_map: ClusterMap) -> None:
257
252
  elif action == "delete_group":
258
253
  logging.debug("skipping group deletion")
259
254
  else:
260
- raise Exception("invalid action: {}".format(action))
255
+ raise Exception(f"invalid action: {action}")
261
256
 
262
257
 
263
258
  @defer
264
259
  def run(
265
260
  dry_run: bool,
266
261
  thread_pool_size: int = 10,
267
- internal: Optional[bool] = None,
262
+ internal: bool | None = None,
268
263
  use_jump_host: bool = True,
269
- defer: Optional[Callable] = None,
264
+ defer: Callable | None = None,
270
265
  ) -> None:
271
266
  oc_map, current_state, ocm_clusters, groups_list = fetch_current_state(
272
267
  thread_pool_size, internal, use_jump_host
@@ -5,11 +5,7 @@ from collections.abc import (
5
5
  Generator,
6
6
  )
7
7
  from threading import Lock
8
- from typing import (
9
- Any,
10
- Optional,
11
- Union,
12
- )
8
+ from typing import Any
13
9
 
14
10
  from kubernetes.client.exceptions import ApiException
15
11
  from sretoolbox.utils import threaded
@@ -47,9 +43,9 @@ CURRENT = "current"
47
43
  CHANGED = "changed"
48
44
  UPDATED_MANAGED = "updated-managed"
49
45
 
50
- Labels = dict[str, Optional[str]]
46
+ Labels = dict[str, str | None]
51
47
  LabelKeys = list[str]
52
- LabelsOrKeys = Union[Labels, LabelKeys]
48
+ LabelsOrKeys = Labels | LabelKeys
53
49
  Types = dict[str, LabelsOrKeys]
54
50
 
55
51
  InternalLabelInventory = dict[str, dict[str, Types]]
@@ -104,8 +100,8 @@ class LabelInventory:
104
100
  cluster: str,
105
101
  namespace: str,
106
102
  type: str,
107
- default: Optional[LabelsOrKeys] = None,
108
- ) -> Optional[LabelsOrKeys]:
103
+ default: LabelsOrKeys | None = None,
104
+ ) -> LabelsOrKeys | None:
109
105
  """Get the labels or keys for the given cluster / namespace / type"""
110
106
  return self._inv.get(cluster, {}).get(namespace, {}).get(type, default)
111
107
 
@@ -293,9 +289,7 @@ def get_managed(inventory: LabelInventory, state: State) -> None:
293
289
  inventory.set(cluster=cluster, namespace=ns_name, type=MANAGED, labels=managed)
294
290
 
295
291
 
296
- def lookup_namespaces(
297
- cluster: str, oc_map: OCMap
298
- ) -> tuple[str, Optional[dict[str, Any]]]:
292
+ def lookup_namespaces(cluster: str, oc_map: OCMap) -> tuple[str, dict[str, Any] | None]:
299
293
  """
300
294
  Retrieve all namespaces from the given cluster
301
295
  """
@@ -410,9 +404,9 @@ class NamespaceLabelError(Exception):
410
404
  def run(
411
405
  dry_run: bool,
412
406
  thread_pool_size: int = 10,
413
- internal: Optional[bool] = None,
407
+ internal: bool | None = None,
414
408
  use_jump_host: bool = True,
415
- defer: Optional[Callable] = None,
409
+ defer: Callable | None = None,
416
410
  raise_errors: bool = False,
417
411
  ) -> None:
418
412
  _LOG.debug("Collecting GQL data ...")
@@ -6,10 +6,7 @@ from collections.abc import (
6
6
  Mapping,
7
7
  Sequence,
8
8
  )
9
- from typing import (
10
- Any,
11
- Optional,
12
- )
9
+ from typing import Any
13
10
 
14
11
  from sretoolbox.utils import threaded
15
12
 
@@ -145,11 +142,11 @@ def check_results(
145
142
  def run(
146
143
  dry_run: bool,
147
144
  thread_pool_size: int = 10,
148
- internal: Optional[bool] = None,
145
+ internal: bool | None = None,
149
146
  use_jump_host: bool = True,
150
- cluster_name: Optional[Sequence[str]] = None,
151
- namespace_name: Optional[Sequence[str]] = None,
152
- defer: Optional[Callable] = None,
147
+ cluster_name: Sequence[str] | None = None,
148
+ namespace_name: Sequence[str] | None = None,
149
+ defer: Callable | None = None,
153
150
  ) -> None:
154
151
  all_namespaces = get_namespaces_minimal()
155
152
  shard_namespaces, duplicates = get_shard_namespaces(all_namespaces)
@@ -94,12 +94,10 @@ def fetch_desired_state(namespaces, ri, oc_map):
94
94
  source_cluster = source_namespace_info["cluster"]["name"]
95
95
  if cluster != source_cluster:
96
96
  ri.register_error()
97
- msg = ("[{}/{}] Network Policy from cluster '{}' not allowed.").format(
98
- cluster, namespace, source_cluster
99
- )
97
+ msg = f"[{cluster}/{namespace}] Network Policy from cluster '{source_cluster}' not allowed."
100
98
  logging.error(msg)
101
99
  continue
102
- resource_name = "allow-from-{}-namespace".format(source_namespace)
100
+ resource_name = f"allow-from-{source_namespace}-namespace"
103
101
  oc_resource = construct_oc_resource(resource_name, source_namespace)
104
102
  ri.add_desired(
105
103
  cluster,
@@ -20,9 +20,7 @@ from textwrap import indent
20
20
  from threading import Lock
21
21
  from typing import (
22
22
  Any,
23
- Optional,
24
23
  Protocol,
25
- Tuple,
26
24
  )
27
25
  from unittest.mock import DEFAULT, patch
28
26
 
@@ -479,9 +477,7 @@ def fetch_provider_route(
479
477
  tls[k] = v
480
478
  continue
481
479
 
482
- msg = "Route secret '{}' key '{}' not in valid keys {}".format(
483
- tls_path, k, valid_keys
484
- )
480
+ msg = f"Route secret '{tls_path}' key '{k}' not in valid keys {valid_keys}"
485
481
  _locked_info_log(msg)
486
482
 
487
483
  host = openshift_resource.body["spec"].get("host")
@@ -504,7 +500,7 @@ def fetch_openshift_resource(
504
500
  provider = resource["provider"]
505
501
  if provider == "resource":
506
502
  path = resource["resource"]["path"]
507
- _locked_debug_log("Processing {}: {}".format(provider, path))
503
+ _locked_debug_log(f"Processing {provider}: {path}")
508
504
  validate_json = resource.get("validate_json") or False
509
505
  add_path_to_prom_rules = resource.get("add_path_to_prom_rules", True)
510
506
  validate_alertmanager_config = (
@@ -524,7 +520,7 @@ def fetch_openshift_resource(
524
520
  )
525
521
  elif provider == "resource-template":
526
522
  path = resource["resource"]["path"]
527
- _locked_debug_log("Processing {}: {}".format(provider, path))
523
+ _locked_debug_log(f"Processing {provider}: {path}")
528
524
  add_path_to_prom_rules = resource.get("add_path_to_prom_rules", True)
529
525
  validate_alertmanager_config = (
530
526
  resource.get("validate_alertmanager_config") or False
@@ -557,12 +553,12 @@ def fetch_openshift_resource(
557
553
  settings=settings,
558
554
  )
559
555
  except Exception as e:
560
- msg = "could not render template at path {}\n{}".format(path, e)
556
+ msg = f"could not render template at path {path}\n{e}"
561
557
  raise ResourceTemplateRenderError(msg)
562
558
  elif provider == "vault-secret":
563
559
  path = resource["path"]
564
560
  version = resource["version"]
565
- _locked_debug_log("Processing {}: {} - {}".format(provider, path, version))
561
+ _locked_debug_log(f"Processing {provider}: {path} - {version}")
566
562
  rn = resource["name"]
567
563
  name = path.split("/")[-1] if rn is None else rn
568
564
  rl = resource["labels"]
@@ -595,7 +591,7 @@ def fetch_openshift_resource(
595
591
  raise FetchSecretError(e)
596
592
  elif provider == "route":
597
593
  path = resource["resource"]["path"]
598
- _locked_debug_log("Processing {}: {}".format(provider, path))
594
+ _locked_debug_log(f"Processing {provider}: {path}")
599
595
  tls_path = resource["vault_tls_secret_path"]
600
596
  tls_version = resource["vault_tls_secret_version"]
601
597
  openshift_resource = fetch_provider_route(
@@ -603,7 +599,7 @@ def fetch_openshift_resource(
603
599
  )
604
600
  elif provider == "prometheus-rule":
605
601
  path = resource["resource"]["path"]
606
- _locked_debug_log("Processing {}: {}".format(provider, path))
602
+ _locked_debug_log(f"Processing {provider}: {path}")
607
603
  add_path_to_prom_rules = resource.get("add_path_to_prom_rules", True)
608
604
  tv = {}
609
605
  if resource["variables"]:
@@ -631,7 +627,7 @@ def fetch_openshift_resource(
631
627
  settings=settings,
632
628
  )
633
629
  except Exception as e:
634
- msg = "could not render template at path {}\n{}".format(path, e)
630
+ msg = f"could not render template at path {path}\n{e}"
635
631
  raise ResourceTemplateRenderError(msg)
636
632
 
637
633
  else:
@@ -684,7 +680,7 @@ def fetch_desired_state(
684
680
  UnknownProviderError,
685
681
  ) as e:
686
682
  ri.register_error()
687
- msg = "[{}/{}] {}".format(cluster, namespace, str(e))
683
+ msg = f"[{cluster}/{namespace}] {str(e)}"
688
684
  _locked_error_log(msg)
689
685
  return
690
686
 
@@ -702,9 +698,7 @@ def fetch_desired_state(
702
698
  # combination was not initialized, meaning that it shouldn't be
703
699
  # managed. But someone is trying to add it via app-interface
704
700
  ri.register_error()
705
- msg = "[{}/{}] unknown kind: {}. hint: is it missing from managedResourceTypes?".format(
706
- cluster, namespace, openshift_resource.kind
707
- )
701
+ msg = f"[{cluster}/{namespace}] unknown kind: {openshift_resource.kind}. hint: is it missing from managedResourceTypes?"
708
702
  _locked_error_log(msg)
709
703
  return
710
704
  except ResourceKeyExistsError:
@@ -712,18 +706,14 @@ def fetch_desired_state(
712
706
  # a desired resource with the same name and
713
707
  # the same type was already added previously
714
708
  ri.register_error()
715
- msg = ("[{}/{}] desired item already exists: {}/{}.").format(
716
- cluster, namespace, openshift_resource.kind, openshift_resource.name
717
- )
709
+ msg = f"[{cluster}/{namespace}] desired item already exists: {openshift_resource.kind}/{openshift_resource.name}."
718
710
  _locked_error_log(msg)
719
711
  return
720
712
  except ResourceNotManagedError:
721
713
  # This is failing because the resource name is
722
714
  # not in the list of resource names that are managed
723
715
  ri.register_error()
724
- msg = "[{}/{}] desired item is not managed: {}/{}.".format(
725
- cluster, namespace, openshift_resource.kind, openshift_resource.name
726
- )
716
+ msg = f"[{cluster}/{namespace}] desired item is not managed: {openshift_resource.kind}/{openshift_resource.name}."
727
717
  _locked_error_log(msg)
728
718
  return
729
719
 
@@ -1000,7 +990,7 @@ class CheckClusterScopedResourceNames:
1000
990
  @dataclass
1001
991
  class CheckClusterScopedResourceDuplicates:
1002
992
  oc_map: OC_Map
1003
- all_namespaces: Optional[Iterable[Mapping]] = None
993
+ all_namespaces: Iterable[Mapping] | None = None
1004
994
 
1005
995
  def check(self) -> list[Exception]:
1006
996
  errors: list[Exception] = []
@@ -1022,13 +1012,13 @@ class CheckClusterScopedResourceDuplicates:
1022
1012
 
1023
1013
  def _find_resource_duplicates(
1024
1014
  self, cluster_cs_resources: dict[str, dict[str, dict[str, list[str]]]]
1025
- ) -> list[Tuple[str, str, str, list[str]]]:
1015
+ ) -> list[tuple[str, str, str, list[str]]]:
1026
1016
  # ) -> dict[Tuple[str, str, str], list[str]]:
1027
1017
  """Finds cluster resource duplicates by kind/name.
1028
1018
  :param cluster_cs_resources
1029
1019
  :return: duplicates as [(cluster, kind, name, [namespaces])]
1030
1020
  """
1031
- duplicates: list[Tuple[str, str, str, list[str]]] = []
1021
+ duplicates: list[tuple[str, str, str, list[str]]] = []
1032
1022
 
1033
1023
  for cluster, cluster_resources in cluster_cs_resources.items():
1034
1024
  _kind_name: dict[str, dict[str, list[str]]] = {}
@@ -1048,7 +1038,7 @@ def check_cluster_scoped_resources(
1048
1038
  oc_map: OC_Map,
1049
1039
  ri: ResourceInventory,
1050
1040
  namespaces: Iterable[Mapping[str, Any]],
1051
- all_namespaces: Optional[Iterable[Mapping[str, Any]]] = None,
1041
+ all_namespaces: Iterable[Mapping[str, Any]] | None = None,
1052
1042
  ) -> bool:
1053
1043
  checks = [
1054
1044
  CheckClusterScopedResourceNames(oc_map, ri, namespaces),
@@ -1069,7 +1059,7 @@ def check_cluster_scoped_resources(
1069
1059
  def get_cluster_scoped_resources(
1070
1060
  oc_map: OC_Map,
1071
1061
  clusters: Iterable[str],
1072
- namespaces: Optional[Iterable[Mapping[str, Any]]] = None,
1062
+ namespaces: Iterable[Mapping[str, Any]] | None = None,
1073
1063
  thread_pool_size: int = 10,
1074
1064
  ) -> dict[str, dict[str, dict[str, list[str]]]]:
1075
1065
  """Returns cluster scoped resources for a list of clusters
@@ -1106,7 +1096,7 @@ def get_cluster_scoped_resources(
1106
1096
  def _get_namespace_cluster_scoped_resources(
1107
1097
  namespace: Mapping,
1108
1098
  oc_map: OC_Map,
1109
- ) -> Tuple[str, str, dict[str, dict[str, Any]]]:
1099
+ ) -> tuple[str, str, dict[str, dict[str, Any]]]:
1110
1100
  """Returns all non-namespaced resources defined in a namespace manifest.
1111
1101
 
1112
1102
  :param namespace: the namespace dict
@@ -1125,7 +1115,7 @@ def _get_namespace_cluster_scoped_resources(
1125
1115
 
1126
1116
 
1127
1117
  def early_exit_desired_state(
1128
- providers: list[str], resource_schema_filter: Optional[str] = None
1118
+ providers: list[str], resource_schema_filter: str | None = None
1129
1119
  ) -> dict[str, Any]:
1130
1120
  settings = queries.get_secret_reader_settings()
1131
1121
  namespaces, _ = get_namespaces(
@@ -3,7 +3,6 @@ import logging
3
3
  import os
4
4
  import sys
5
5
  from collections.abc import Callable
6
- from typing import Optional
7
6
 
8
7
  import reconcile.openshift_base as ob
9
8
  from reconcile import (
@@ -68,9 +67,9 @@ def slack_notify(
68
67
  ri: ResourceInventory,
69
68
  console_url: str,
70
69
  in_progress: bool,
71
- trigger_integration: Optional[str] = None,
72
- trigger_reason: Optional[str] = None,
73
- skip_successful_notifications: Optional[bool] = False,
70
+ trigger_integration: str | None = None,
71
+ trigger_reason: str | None = None,
72
+ skip_successful_notifications: bool | None = False,
74
73
  ) -> None:
75
74
  success = not ri.has_error_registered()
76
75
  # if the deployment doesn't want any notifications for successful
@@ -112,12 +111,12 @@ def run(
112
111
  thread_pool_size: int = 10,
113
112
  io_dir: str = "throughput/",
114
113
  use_jump_host: bool = True,
115
- saas_file_name: Optional[str] = None,
116
- env_name: Optional[str] = None,
117
- trigger_integration: Optional[str] = None,
118
- trigger_reason: Optional[str] = None,
119
- saas_file_list: Optional[SaasFileList] = None,
120
- defer: Optional[Callable] = None,
114
+ saas_file_name: str | None = None,
115
+ env_name: str | None = None,
116
+ trigger_integration: str | None = None,
117
+ trigger_reason: str | None = None,
118
+ saas_file_list: SaasFileList | None = None,
119
+ defer: Callable | None = None,
121
120
  ) -> None:
122
121
  vault_settings = get_app_interface_vault_settings()
123
122
  secret_reader = create_secret_reader(use_vault=vault_settings.vault)
@@ -1,10 +1,7 @@
1
1
  import logging
2
2
  import sys
3
3
  from collections.abc import Iterable
4
- from typing import (
5
- Any,
6
- Optional,
7
- )
4
+ from typing import Any
8
5
 
9
6
  from pydantic import BaseModel
10
7
  from sretoolbox.utils import threaded
@@ -37,7 +34,7 @@ class Definition(BaseModel):
37
34
  class State(BaseModel):
38
35
  saas_file_path: str
39
36
  saas_file_name: str
40
- saas_file_deploy_resources: Optional[DeployResourcesV1]
37
+ saas_file_deploy_resources: DeployResourcesV1 | None
41
38
  resource_template_name: str
42
39
  cluster: str
43
40
  namespace: str
@@ -47,10 +44,10 @@ class State(BaseModel):
47
44
  parameters: dict[str, Any]
48
45
  secret_parameters: dict[str, VaultSecret]
49
46
  saas_file_definitions: Definition
50
- upstream: Optional[SaasResourceTemplateTargetUpstreamV1]
51
- disable: Optional[bool]
52
- delete: Optional[bool]
53
- target_path: Optional[str]
47
+ upstream: SaasResourceTemplateTargetUpstreamV1 | None
48
+ disable: bool | None
49
+ delete: bool | None
50
+ target_path: str | None
54
51
 
55
52
 
56
53
  def osd_run_wrapper(
@@ -58,7 +55,7 @@ def osd_run_wrapper(
58
55
  dry_run: bool,
59
56
  available_thread_pool_size: int,
60
57
  use_jump_host: bool,
61
- saas_file_list: Optional[SaasFileList],
58
+ saas_file_list: SaasFileList | None,
62
59
  ) -> int:
63
60
  saas_file_name, env_name = spec
64
61
  exit_code = 0
@@ -1,10 +1,7 @@
1
1
  import logging
2
2
  from collections.abc import Callable
3
3
  from threading import Lock
4
- from typing import (
5
- Any,
6
- Optional,
7
- )
4
+ from typing import Any
8
5
 
9
6
  from sretoolbox.utils import threaded
10
7
 
@@ -63,7 +60,7 @@ def run(
63
60
  internal: bool,
64
61
  use_jump_host: bool,
65
62
  include_trigger_trace: bool,
66
- defer: Optional[Callable] = None,
63
+ defer: Callable | None = None,
67
64
  ) -> bool:
68
65
  """Run trigger integration
69
66
 
@@ -327,13 +324,13 @@ def _construct_tekton_trigger_resource(
327
324
  saas_file_name: str,
328
325
  env_name: str,
329
326
  tkn_pipeline_name: str,
330
- timeout: Optional[str],
327
+ timeout: str | None,
331
328
  tkn_cluster_console_url: str,
332
329
  tkn_namespace_name: str,
333
330
  integration: str,
334
331
  integration_version: str,
335
332
  include_trigger_trace: bool,
336
- reason: Optional[str],
333
+ reason: str | None,
337
334
  ) -> tuple[OR, str]:
338
335
  """Construct a resource (PipelineRun) to trigger a deployment via Tekton.
339
336