qontract-reconcile 0.10.1rc879__py3-none-any.whl → 0.10.1rc894__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 (291) hide show
  1. {qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc894.dist-info}/METADATA +1 -1
  2. {qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc894.dist-info}/RECORD +291 -284
  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 +9 -14
  13. reconcile/aws_account_manager/reconciler.py +51 -1
  14. reconcile/aws_account_manager/utils.py +3 -0
  15. reconcile/aws_ami_cleanup/integration.py +3 -4
  16. reconcile/aws_iam_password_reset.py +2 -5
  17. reconcile/aws_version_sync/integration.py +2 -2
  18. reconcile/blackbox_exporter_endpoint_monitoring.py +2 -5
  19. reconcile/change_owners/approver.py +4 -5
  20. reconcile/change_owners/bundle.py +20 -22
  21. reconcile/change_owners/change_types.py +23 -24
  22. reconcile/change_owners/changes.py +13 -16
  23. reconcile/change_owners/decision.py +2 -5
  24. reconcile/change_owners/diff.py +11 -15
  25. reconcile/change_owners/self_service_roles.py +1 -2
  26. reconcile/change_owners/tester.py +7 -10
  27. reconcile/checkpoint.py +2 -5
  28. reconcile/cli.py +26 -12
  29. reconcile/closedbox_endpoint_monitoring_base.py +8 -11
  30. reconcile/cluster_deployment_mapper.py +2 -5
  31. reconcile/cna/assets/asset.py +4 -7
  32. reconcile/cna/assets/null.py +2 -5
  33. reconcile/cna/integration.py +2 -3
  34. reconcile/cna/state.py +2 -5
  35. reconcile/dashdotdb_base.py +8 -11
  36. reconcile/dashdotdb_cso.py +3 -6
  37. reconcile/dashdotdb_dora.py +10 -14
  38. reconcile/dashdotdb_dvo.py +10 -13
  39. reconcile/dashdotdb_slo.py +5 -8
  40. reconcile/database_access_manager.py +5 -6
  41. reconcile/dynatrace_token_provider/integration.py +3 -6
  42. reconcile/dynatrace_token_provider/integration_v2.py +20 -0
  43. reconcile/dynatrace_token_provider/meta.py +1 -0
  44. reconcile/external_resources/integration.py +1 -1
  45. reconcile/external_resources/manager.py +4 -4
  46. reconcile/external_resources/model.py +3 -3
  47. reconcile/external_resources/secrets_sync.py +5 -5
  48. reconcile/external_resources/state.py +5 -5
  49. reconcile/gabi_authorized_users.py +3 -6
  50. reconcile/gcr_mirror.py +1 -1
  51. reconcile/github_org.py +1 -3
  52. reconcile/github_repo_invites.py +2 -5
  53. reconcile/gitlab_housekeeping.py +7 -11
  54. reconcile/gitlab_labeler.py +1 -2
  55. reconcile/gitlab_members.py +2 -5
  56. reconcile/gitlab_permissions.py +1 -3
  57. reconcile/glitchtip/integration.py +5 -8
  58. reconcile/glitchtip_project_alerts/integration.py +57 -33
  59. reconcile/glitchtip_project_dsn/integration.py +8 -11
  60. reconcile/gql_definitions/aws_account_manager/aws_accounts.py +6 -0
  61. reconcile/gql_definitions/fragments/aws_account_managed.py +8 -0
  62. reconcile/gql_definitions/glitchtip/glitchtip_project.py +4 -4
  63. reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +27 -7
  64. reconcile/integrations_manager.py +5 -8
  65. reconcile/jenkins/types.py +5 -6
  66. reconcile/jenkins_job_builder.py +9 -12
  67. reconcile/jenkins_roles.py +1 -1
  68. reconcile/jira_watcher.py +2 -2
  69. reconcile/ldap_groups/integration.py +2 -5
  70. reconcile/ocm/types.py +21 -26
  71. reconcile/ocm_addons_upgrade_tests_trigger.py +3 -6
  72. reconcile/ocm_clusters.py +8 -8
  73. reconcile/ocm_internal_notifications/integration.py +1 -2
  74. reconcile/ocm_labels/integration.py +2 -5
  75. reconcile/ocm_machine_pools.py +11 -15
  76. reconcile/ocm_upgrade_scheduler_org_updater.py +2 -5
  77. reconcile/openshift_base.py +29 -30
  78. reconcile/openshift_groups.py +15 -20
  79. reconcile/openshift_namespace_labels.py +8 -14
  80. reconcile/openshift_namespaces.py +5 -8
  81. reconcile/openshift_network_policies.py +2 -4
  82. reconcile/openshift_resources_base.py +19 -29
  83. reconcile/openshift_saas_deploy.py +9 -10
  84. reconcile/openshift_saas_deploy_change_tester.py +7 -10
  85. reconcile/openshift_saas_deploy_trigger_base.py +4 -7
  86. reconcile/openshift_saas_deploy_trigger_cleaner.py +5 -8
  87. reconcile/openshift_saas_deploy_trigger_configs.py +1 -2
  88. reconcile/openshift_saas_deploy_trigger_images.py +1 -2
  89. reconcile/openshift_saas_deploy_trigger_moving_commits.py +1 -2
  90. reconcile/openshift_saas_deploy_trigger_upstream_jobs.py +1 -2
  91. reconcile/openshift_tekton_resources.py +7 -11
  92. reconcile/openshift_upgrade_watcher.py +10 -13
  93. reconcile/openshift_users.py +8 -11
  94. reconcile/oum/base.py +3 -4
  95. reconcile/oum/labelset.py +1 -2
  96. reconcile/oum/metrics.py +2 -2
  97. reconcile/oum/models.py +1 -2
  98. reconcile/oum/standalone.py +2 -3
  99. reconcile/prometheus_rules_tester/integration.py +6 -9
  100. reconcile/quay_membership.py +1 -2
  101. reconcile/quay_mirror.py +12 -13
  102. reconcile/quay_mirror_org.py +10 -10
  103. reconcile/queries.py +4 -7
  104. reconcile/resource_scraper.py +3 -4
  105. reconcile/rhidp/common.py +2 -2
  106. reconcile/saas_auto_promotions_manager/integration.py +5 -6
  107. reconcile/saas_auto_promotions_manager/merge_request_manager/batcher.py +1 -2
  108. reconcile/saas_auto_promotions_manager/publisher.py +5 -6
  109. reconcile/saas_auto_promotions_manager/subscriber.py +36 -15
  110. reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py +8 -0
  111. reconcile/saas_file_validator.py +2 -5
  112. reconcile/signalfx_endpoint_monitoring.py +2 -5
  113. reconcile/skupper_network/integration.py +3 -6
  114. reconcile/skupper_network/models.py +3 -5
  115. reconcile/slack_base.py +4 -7
  116. reconcile/slack_usergroups.py +15 -17
  117. reconcile/sql_query.py +5 -9
  118. reconcile/status_board.py +4 -5
  119. reconcile/statuspage/atlassian.py +14 -15
  120. reconcile/statuspage/integrations/maintenances.py +3 -3
  121. reconcile/statuspage/page.py +8 -8
  122. reconcile/statuspage/state.py +4 -5
  123. reconcile/statuspage/status.py +7 -8
  124. reconcile/templating/lib/rendering.py +8 -8
  125. reconcile/templating/renderer.py +10 -11
  126. reconcile/templating/validator.py +4 -4
  127. reconcile/terraform_aws_route53.py +3 -6
  128. reconcile/terraform_cloudflare_dns.py +9 -12
  129. reconcile/terraform_cloudflare_resources.py +9 -11
  130. reconcile/terraform_cloudflare_users.py +8 -11
  131. reconcile/terraform_init/integration.py +2 -2
  132. reconcile/terraform_repo.py +11 -14
  133. reconcile/terraform_resources.py +20 -21
  134. reconcile/terraform_tgw_attachments.py +32 -36
  135. reconcile/terraform_users.py +6 -7
  136. reconcile/terraform_vpc_resources/integration.py +6 -6
  137. reconcile/test/conftest.py +7 -10
  138. reconcile/test/fixtures.py +1 -1
  139. reconcile/test/saas_auto_promotions_manager/conftest.py +3 -2
  140. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py +2 -2
  141. reconcile/test/test_database_access_manager.py +3 -6
  142. reconcile/test/test_gitlab_labeler.py +2 -5
  143. reconcile/test/test_jump_host.py +5 -8
  144. reconcile/test/test_ocm_machine_pools.py +1 -4
  145. reconcile/test/test_openshift_base.py +3 -6
  146. reconcile/test/test_openshift_cluster_bots.py +5 -5
  147. reconcile/test/test_openshift_namespace_labels.py +2 -3
  148. reconcile/test/test_openshift_saas_deploy_trigger_cleaner.py +2 -2
  149. reconcile/test/test_saasherder.py +9 -12
  150. reconcile/test/test_slack_base.py +4 -6
  151. reconcile/test/test_status_board.py +4 -7
  152. reconcile/test/test_terraform_tgw_attachments.py +14 -20
  153. reconcile/typed_queries/alerting_services_settings.py +1 -2
  154. reconcile/typed_queries/app_interface_custom_messages.py +2 -3
  155. reconcile/typed_queries/app_interface_deadmanssnitch_settings.py +1 -3
  156. reconcile/typed_queries/app_interface_repo_url.py +1 -2
  157. reconcile/typed_queries/app_interface_state_settings.py +1 -3
  158. reconcile/typed_queries/app_interface_vault_settings.py +1 -2
  159. reconcile/typed_queries/aws_vpc_requests.py +1 -3
  160. reconcile/typed_queries/aws_vpcs.py +1 -3
  161. reconcile/typed_queries/clusters.py +2 -4
  162. reconcile/typed_queries/clusters_minimal.py +1 -3
  163. reconcile/typed_queries/clusters_with_dms.py +1 -3
  164. reconcile/typed_queries/dynatrace_environments.py +14 -0
  165. reconcile/typed_queries/external_resources.py +3 -4
  166. reconcile/typed_queries/pagerduty_instances.py +1 -2
  167. reconcile/typed_queries/repos.py +2 -3
  168. reconcile/typed_queries/reserved_networks.py +1 -3
  169. reconcile/typed_queries/saas_files.py +49 -59
  170. reconcile/typed_queries/slo_documents.py +1 -3
  171. reconcile/typed_queries/status_board.py +3 -7
  172. reconcile/typed_queries/tekton_pipeline_providers.py +1 -2
  173. reconcile/typed_queries/terraform_namespaces.py +1 -2
  174. reconcile/typed_queries/terraform_tgw_attachments/aws_accounts.py +1 -3
  175. reconcile/utils/acs/base.py +2 -3
  176. reconcile/utils/acs/notifiers.py +3 -3
  177. reconcile/utils/acs/policies.py +3 -3
  178. reconcile/utils/aggregated_list.py +1 -1
  179. reconcile/utils/amtool.py +1 -2
  180. reconcile/utils/aws_api.py +28 -31
  181. reconcile/utils/aws_api_typed/account.py +23 -0
  182. reconcile/utils/aws_api_typed/api.py +20 -9
  183. reconcile/utils/binary.py +1 -3
  184. reconcile/utils/clusterhealth/providerbase.py +1 -2
  185. reconcile/utils/clusterhealth/telemeter.py +2 -2
  186. reconcile/utils/deadmanssnitch_api.py +1 -2
  187. reconcile/utils/disabled_integrations.py +4 -6
  188. reconcile/utils/environ.py +1 -1
  189. reconcile/utils/expiration.py +3 -7
  190. reconcile/utils/external_resource_spec.py +3 -4
  191. reconcile/utils/external_resources.py +4 -7
  192. reconcile/utils/filtering.py +1 -2
  193. reconcile/utils/git.py +3 -9
  194. reconcile/utils/git_secrets.py +5 -5
  195. reconcile/utils/github_api.py +5 -9
  196. reconcile/utils/gitlab_api.py +2 -3
  197. reconcile/utils/glitchtip/client.py +2 -4
  198. reconcile/utils/glitchtip/models.py +8 -11
  199. reconcile/utils/gql.py +26 -35
  200. reconcile/utils/grouping.py +1 -3
  201. reconcile/utils/imap_client.py +2 -5
  202. reconcile/utils/internal_groups/client.py +1 -2
  203. reconcile/utils/internal_groups/models.py +8 -9
  204. reconcile/utils/jenkins_api.py +4 -4
  205. reconcile/utils/jinja2/extensions.py +1 -1
  206. reconcile/utils/jinja2/filters.py +4 -4
  207. reconcile/utils/jinja2/utils.py +16 -16
  208. reconcile/utils/jira_client.py +10 -11
  209. reconcile/utils/jjb_client.py +14 -17
  210. reconcile/utils/jobcontroller/controller.py +5 -5
  211. reconcile/utils/jobcontroller/models.py +2 -2
  212. reconcile/utils/jsonpath.py +4 -5
  213. reconcile/utils/jump_host.py +7 -8
  214. reconcile/utils/keycloak.py +3 -7
  215. reconcile/utils/ldap_client.py +2 -3
  216. reconcile/utils/lean_terraform_client.py +13 -17
  217. reconcile/utils/membershipsources/app_interface_resolver.py +1 -1
  218. reconcile/utils/membershipsources/models.py +19 -22
  219. reconcile/utils/metrics.py +13 -15
  220. reconcile/utils/mr/base.py +7 -11
  221. reconcile/utils/mr/glitchtip_access_reporter.py +2 -2
  222. reconcile/utils/mr/notificator.py +1 -2
  223. reconcile/utils/oc.py +38 -38
  224. reconcile/utils/oc_connection_parameters.py +24 -25
  225. reconcile/utils/oc_filters.py +2 -3
  226. reconcile/utils/oc_map.py +9 -15
  227. reconcile/utils/ocm/addons.py +7 -10
  228. reconcile/utils/ocm/base.py +38 -39
  229. reconcile/utils/ocm/clusters.py +6 -9
  230. reconcile/utils/ocm/label_sources.py +1 -2
  231. reconcile/utils/ocm/labels.py +3 -6
  232. reconcile/utils/ocm/ocm.py +11 -14
  233. reconcile/utils/ocm/products.py +1 -3
  234. reconcile/utils/ocm/search_filters.py +16 -17
  235. reconcile/utils/ocm/service_log.py +2 -3
  236. reconcile/utils/ocm/sre_capability_labels.py +4 -8
  237. reconcile/utils/ocm/subscriptions.py +1 -3
  238. reconcile/utils/ocm/syncsets.py +2 -4
  239. reconcile/utils/ocm/upgrades.py +5 -9
  240. reconcile/utils/ocm_base_client.py +13 -16
  241. reconcile/utils/openshift_resource.py +5 -11
  242. reconcile/utils/output.py +2 -3
  243. reconcile/utils/pagerduty_api.py +4 -5
  244. reconcile/utils/prometheus.py +2 -2
  245. reconcile/utils/promotion_state.py +4 -5
  246. reconcile/utils/promtool.py +2 -8
  247. reconcile/utils/quay_api.py +12 -22
  248. reconcile/utils/raw_github_api.py +3 -5
  249. reconcile/utils/rosa/rosa_cli.py +6 -6
  250. reconcile/utils/rosa/session.py +6 -7
  251. reconcile/utils/runtime/desired_state_diff.py +3 -8
  252. reconcile/utils/runtime/environment.py +4 -7
  253. reconcile/utils/runtime/integration.py +4 -4
  254. reconcile/utils/runtime/meta.py +1 -2
  255. reconcile/utils/runtime/runner.py +7 -10
  256. reconcile/utils/runtime/sharding.py +22 -27
  257. reconcile/utils/saasherder/interfaces.py +63 -69
  258. reconcile/utils/saasherder/models.py +30 -35
  259. reconcile/utils/saasherder/saasherder.py +39 -54
  260. reconcile/utils/secret_reader.py +17 -19
  261. reconcile/utils/slack_api.py +15 -17
  262. reconcile/utils/smtp_client.py +1 -2
  263. reconcile/utils/sqs_gateway.py +1 -3
  264. reconcile/utils/state.py +1 -2
  265. reconcile/utils/terraform/config_client.py +4 -5
  266. reconcile/utils/terraform_client.py +12 -8
  267. reconcile/utils/terrascript/cloudflare_client.py +4 -10
  268. reconcile/utils/terrascript/cloudflare_resources.py +10 -13
  269. reconcile/utils/terrascript/models.py +2 -3
  270. reconcile/utils/terrascript/resources.py +1 -2
  271. reconcile/utils/terrascript_aws_client.py +50 -38
  272. reconcile/utils/unleash/client.py +4 -7
  273. reconcile/utils/unleash/server.py +2 -2
  274. reconcile/utils/vault.py +8 -11
  275. reconcile/utils/vaultsecretref.py +2 -3
  276. reconcile/utils/vcs.py +7 -8
  277. reconcile/vault_replication.py +4 -8
  278. reconcile/vpc_peerings_validator.py +4 -9
  279. release/version.py +6 -7
  280. tools/app_interface_reporter.py +2 -2
  281. tools/cli_commands/gpg_encrypt.py +3 -6
  282. tools/cli_commands/systems_and_tools.py +4 -7
  283. tools/qontract_cli.py +105 -17
  284. tools/saas_promotion_state/__init__.py +0 -0
  285. tools/saas_promotion_state/saas_promotion_state.py +105 -0
  286. tools/template_validation.py +1 -1
  287. tools/test/conftest.py +45 -6
  288. tools/test/test_saas_promotion_state.py +187 -0
  289. {qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc894.dist-info}/WHEEL +0 -0
  290. {qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc894.dist-info}/entry_points.txt +0 -0
  291. {qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc894.dist-info}/top_level.txt +0 -0
@@ -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
 
@@ -1,14 +1,11 @@
1
1
  import logging
2
2
  from collections.abc import Callable
3
3
  from datetime import (
4
+ UTC,
4
5
  datetime,
5
6
  timedelta,
6
- timezone,
7
- )
8
- from typing import (
9
- Any,
10
- Optional,
11
7
  )
8
+ from typing import Any
12
9
 
13
10
  from dateutil import parser
14
11
 
@@ -67,11 +64,11 @@ def get_pipeline_runs_to_delete(
67
64
  def run(
68
65
  dry_run: bool,
69
66
  thread_pool_size: int = 10,
70
- internal: Optional[bool] = None,
67
+ internal: bool | None = None,
71
68
  use_jump_host: bool = True,
72
- defer: Optional[Callable] = None,
69
+ defer: Callable | None = None,
73
70
  ) -> None:
74
- now_date = datetime.now(timezone.utc)
71
+ now_date = datetime.now(UTC)
75
72
  vault_settings = get_app_interface_vault_settings()
76
73
  secret_reader = create_secret_reader(use_vault=vault_settings.vault)
77
74
  pipeline_providers = get_tekton_pipeline_providers()
@@ -1,5 +1,4 @@
1
1
  import sys
2
- from typing import Optional
3
2
 
4
3
  import reconcile.openshift_saas_deploy_trigger_base as osdt_base
5
4
  from reconcile.status import ExitCodes
@@ -13,7 +12,7 @@ QONTRACT_INTEGRATION_VERSION = make_semver(0, 3, 0)
13
12
  def run(
14
13
  dry_run: bool,
15
14
  thread_pool_size: int = 10,
16
- internal: Optional[bool] = None,
15
+ internal: bool | None = None,
17
16
  use_jump_host: bool = True,
18
17
  include_trigger_trace: bool = False,
19
18
  ) -> None:
@@ -1,5 +1,4 @@
1
1
  import sys
2
- from typing import Optional
3
2
 
4
3
  import reconcile.openshift_saas_deploy_trigger_base as osdt_base
5
4
  from reconcile.status import ExitCodes
@@ -13,7 +12,7 @@ QONTRACT_INTEGRATION_VERSION = make_semver(0, 1, 0)
13
12
  def run(
14
13
  dry_run: bool,
15
14
  thread_pool_size: int = 10,
16
- internal: Optional[bool] = None,
15
+ internal: bool | None = None,
17
16
  use_jump_host: bool = True,
18
17
  include_trigger_trace: bool = False,
19
18
  ) -> None:
@@ -1,5 +1,4 @@
1
1
  import sys
2
- from typing import Optional
3
2
 
4
3
  import reconcile.openshift_saas_deploy_trigger_base as osdt_base
5
4
  from reconcile.status import ExitCodes
@@ -13,7 +12,7 @@ QONTRACT_INTEGRATION_VERSION = make_semver(0, 3, 0)
13
12
  def run(
14
13
  dry_run: bool,
15
14
  thread_pool_size: int = 10,
16
- internal: Optional[bool] = None,
15
+ internal: bool | None = None,
17
16
  use_jump_host: bool = True,
18
17
  include_trigger_trace: bool = False,
19
18
  ) -> None:
@@ -1,5 +1,4 @@
1
1
  import sys
2
- from typing import Optional
3
2
 
4
3
  import reconcile.openshift_saas_deploy_trigger_base as osdt_base
5
4
  from reconcile.status import ExitCodes
@@ -13,7 +12,7 @@ QONTRACT_INTEGRATION_VERSION = make_semver(0, 3, 0)
13
12
  def run(
14
13
  dry_run: bool,
15
14
  thread_pool_size: int = 10,
16
- internal: Optional[bool] = None,
15
+ internal: bool | None = None,
17
16
  use_jump_host: bool = True,
18
17
  include_trigger_trace: bool = False,
19
18
  ) -> None:
@@ -2,11 +2,7 @@ import json
2
2
  import logging
3
3
  import sys
4
4
  from collections.abc import Mapping
5
- from typing import (
6
- Any,
7
- Optional,
8
- Union,
9
- )
5
+ from typing import Any
10
6
 
11
7
  import jinja2
12
8
  import yaml
@@ -77,7 +73,7 @@ class OpenshiftTektonResourcesBadConfigError(Exception):
77
73
  pass
78
74
 
79
75
 
80
- def fetch_saas_files(saas_file_name: Optional[str]) -> list[dict[str, Any]]:
76
+ def fetch_saas_files(saas_file_name: str | None) -> list[dict[str, Any]]:
81
77
  """Fetch saas v2 files"""
82
78
  saas_files = gql.get_api().query(SAAS_FILES_QUERY)["saas_files"]
83
79
 
@@ -93,7 +89,7 @@ def fetch_saas_files(saas_file_name: Optional[str]) -> list[dict[str, Any]]:
93
89
  return saas_files
94
90
 
95
91
 
96
- def fetch_tkn_providers(saas_file_name: Optional[str]) -> dict[str, Any]:
92
+ def fetch_tkn_providers(saas_file_name: str | None) -> dict[str, Any]:
97
93
  """Fetch tekton providers data for the saas files handled here"""
98
94
  saas_files = fetch_saas_files(saas_file_name)
99
95
  if not saas_files:
@@ -138,7 +134,7 @@ def fetch_tkn_providers(saas_file_name: Optional[str]) -> dict[str, Any]:
138
134
 
139
135
  def fetch_desired_resources(
140
136
  tkn_providers: dict[str, Any],
141
- ) -> list[dict[str, Union[str, OR]]]:
137
+ ) -> list[dict[str, str | OR]]:
142
138
  """Create an array of dicts that will be used as args of ri.add_desired
143
139
  This will also add resourceNames inside tkn_providers['namespace']
144
140
  while we are migrating from the current system to this integration"""
@@ -344,7 +340,7 @@ def load_tkn_template(path: str, variables: dict[str, str]) -> dict[str, Any]:
344
340
 
345
341
  def build_desired_resource(
346
342
  tkn_object: dict[str, Any], path: str, cluster: str, namespace: str
347
- ) -> dict[str, Union[str, OR]]:
343
+ ) -> dict[str, str | OR]:
348
344
  """Returns a dict with ResourceInventory.add_desired args"""
349
345
  openshift_resource = OR(
350
346
  tkn_object,
@@ -424,9 +420,9 @@ def build_one_per_saas_file_tkn_task_name(
424
420
  def run(
425
421
  dry_run: bool,
426
422
  thread_pool_size: int = 10,
427
- internal: Optional[bool] = None,
423
+ internal: bool | None = None,
428
424
  use_jump_host: bool = True,
429
- saas_file_name: Optional[str] = None,
425
+ saas_file_name: str | None = None,
430
426
  ) -> None:
431
427
  tkn_providers = fetch_tkn_providers(saas_file_name)
432
428
 
@@ -4,7 +4,6 @@ from collections.abc import (
4
4
  Iterable,
5
5
  )
6
6
  from datetime import datetime
7
- from typing import Optional
8
7
 
9
8
  from reconcile import queries
10
9
  from reconcile.gql_definitions.common.clusters import ClusterV1
@@ -32,7 +31,7 @@ from reconcile.utils.state import (
32
31
  QONTRACT_INTEGRATION = "openshift-upgrade-watcher"
33
32
 
34
33
 
35
- def cluster_slack_handle(cluster: str, slack: Optional[SlackApi]) -> str:
34
+ def cluster_slack_handle(cluster: str, slack: SlackApi | None) -> str:
36
35
  usergroup = f"{cluster}-cluster"
37
36
  usergroup_id = f"@{usergroup}"
38
37
  if slack:
@@ -42,10 +41,10 @@ def cluster_slack_handle(cluster: str, slack: Optional[SlackApi]) -> str:
42
41
 
43
42
  def handle_slack_notification(
44
43
  msg: str,
45
- slack: Optional[SlackApi],
44
+ slack: SlackApi | None,
46
45
  state: State,
47
46
  state_key: str,
48
- state_value: Optional[str],
47
+ state_value: str | None,
49
48
  ) -> None:
50
49
  """Check notification status, notify if needed and update the notification status"""
51
50
  if state.exists(state_key) and state.get(state_key) == state_value:
@@ -58,9 +57,7 @@ def handle_slack_notification(
58
57
  state.add(state_key, state_value, force=True)
59
58
 
60
59
 
61
- def _get_start_osd(
62
- oc_map: OCMap, cluster_name: str
63
- ) -> tuple[Optional[str], Optional[str]]:
60
+ def _get_start_osd(oc_map: OCMap, cluster_name: str) -> tuple[str | None, str | None]:
64
61
  oc = oc_map.get(cluster_name)
65
62
  if isinstance(oc, OCLogMsg):
66
63
  logging.log(level=oc.log_level, msg=oc.message)
@@ -84,7 +81,7 @@ def _get_start_osd(
84
81
 
85
82
  def _get_start_hypershift(
86
83
  ocm_api: OCMBaseClient, cluster_id: str
87
- ) -> tuple[Optional[str], Optional[str]]:
84
+ ) -> tuple[str | None, str | None]:
88
85
  schedules = get_control_plane_upgrade_policies(ocm_api, cluster_id)
89
86
  schedule = [s for s in schedules if s["state"] == "started"]
90
87
  if not schedule:
@@ -101,7 +98,7 @@ def notify_upgrades_start(
101
98
  oc_map: OCMap,
102
99
  ocm_map: OCMMap,
103
100
  state: State,
104
- slack: Optional[SlackApi],
101
+ slack: SlackApi | None,
105
102
  ) -> None:
106
103
  now = datetime.utcnow()
107
104
  for cluster in clusters:
@@ -135,7 +132,7 @@ def notify_upgrades_start(
135
132
 
136
133
 
137
134
  def notify_cluster_new_version(
138
- clusters: Iterable[ClusterV1], state: State, slack: Optional[SlackApi]
135
+ clusters: Iterable[ClusterV1], state: State, slack: SlackApi | None
139
136
  ) -> None:
140
137
  # Send a notification, if a cluster runs a version it was not running in the past
141
138
  # This does not check if an upgrade was successful or not
@@ -159,11 +156,11 @@ def notify_cluster_new_version(
159
156
  def run(
160
157
  dry_run: bool,
161
158
  thread_pool_size: int = 10,
162
- internal: Optional[bool] = None,
159
+ internal: bool | None = None,
163
160
  use_jump_host: bool = True,
164
- defer: Optional[Callable] = None,
161
+ defer: Callable | None = None,
165
162
  ) -> None:
166
- slack: Optional[SlackApi] = None
163
+ slack: SlackApi | None = None
167
164
  if not dry_run:
168
165
  slack = slackapi_from_queries(QONTRACT_INTEGRATION)
169
166