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
@@ -1,5 +1,4 @@
1
1
  from collections.abc import Callable
2
- from typing import Optional
3
2
 
4
3
  from sretoolbox.utils import threaded
5
4
 
@@ -95,8 +94,8 @@ class SaasAutoPromotionsManager:
95
94
 
96
95
  def init_external_dependencies(
97
96
  dry_run: bool,
98
- env_name: Optional[str] = None,
99
- app_name: Optional[str] = None,
97
+ env_name: str | None = None,
98
+ app_name: str | None = None,
100
99
  ) -> tuple[
101
100
  PromotionState,
102
101
  VCS,
@@ -169,9 +168,9 @@ def init_external_dependencies(
169
168
  def run(
170
169
  dry_run: bool,
171
170
  thread_pool_size: int,
172
- env_name: Optional[str] = None,
173
- app_name: Optional[str] = None,
174
- defer: Optional[Callable] = None,
171
+ env_name: str | None = None,
172
+ app_name: str | None = None,
173
+ defer: Callable | None = None,
175
174
  ) -> None:
176
175
  (
177
176
  deployment_state,
@@ -1,7 +1,6 @@
1
1
  from collections.abc import Iterable
2
2
  from dataclasses import dataclass
3
3
  from enum import Enum
4
- from typing import Optional
5
4
 
6
5
  from reconcile.saas_auto_promotions_manager.merge_request_manager.open_merge_requests import (
7
6
  OpenBatcherMergeRequest,
@@ -145,7 +144,7 @@ class Batcher:
145
144
  if not unsubmitted_promotions:
146
145
  return
147
146
 
148
- batch_with_capacity: Optional[OpenBatcherMergeRequest] = None
147
+ batch_with_capacity: OpenBatcherMergeRequest | None = None
149
148
  for mr in self._open_mrs:
150
149
  if mr.is_batchable and len(mr.content_hashes) < batch_limit:
151
150
  batch_with_capacity = mr
@@ -1,6 +1,5 @@
1
1
  from dataclasses import dataclass
2
2
  from datetime import datetime
3
- from typing import Optional
4
3
 
5
4
  from reconcile.utils.promotion_state import PromotionState
6
5
  from reconcile.utils.secret_reader import HasSecret
@@ -18,7 +17,7 @@ class DeploymentInfo:
18
17
  success: bool
19
18
  saas_file: str
20
19
  target_config_hash: str
21
- check_in: Optional[datetime]
20
+ check_in: datetime | None
22
21
 
23
22
 
24
23
  class Publisher:
@@ -37,10 +36,10 @@ class Publisher:
37
36
  app_name: str,
38
37
  namespace_name: str,
39
38
  resource_template_name: str,
40
- target_name: Optional[str],
39
+ target_name: str | None,
41
40
  cluster_name: str,
42
- auth_code: Optional[HasSecret],
43
- publish_job_logs: Optional[bool],
41
+ auth_code: HasSecret | None,
42
+ publish_job_logs: bool | None,
44
43
  has_subscriber: bool = True,
45
44
  ):
46
45
  self._ref = ref
@@ -48,7 +47,7 @@ class Publisher:
48
47
  self._auth_code = auth_code
49
48
  self.channels: set[str] = set()
50
49
  self.commit_sha: str = ""
51
- self.deployment_info_by_channel: dict[str, Optional[DeploymentInfo]] = {}
50
+ self.deployment_info_by_channel: dict[str, DeploymentInfo | None] = {}
52
51
  self.uid = uid
53
52
  self.saas_name = saas_name
54
53
  self.saas_file_path = saas_file_path
@@ -2,8 +2,7 @@ import hashlib
2
2
  import logging
3
3
  from collections.abc import Iterable
4
4
  from dataclasses import dataclass
5
- from datetime import datetime, timedelta, timezone
6
- from typing import Optional
5
+ from datetime import UTC, datetime, timedelta
7
6
 
8
7
  from reconcile.gql_definitions.fragments.saas_target_namespace import (
9
8
  SaasTargetNamespace,
@@ -80,7 +79,7 @@ class Subscriber:
80
79
 
81
80
  def _validate_deployment(
82
81
  self, publisher: Publisher, channel: Channel
83
- ) -> Optional[DeploymentInfo]:
82
+ ) -> DeploymentInfo | None:
84
83
  deployment_info = publisher.deployment_info_by_channel.get(channel.name)
85
84
  if not deployment_info:
86
85
  logging.info(
@@ -103,7 +102,7 @@ class Subscriber:
103
102
  We accumulate the time a ref is running on all publishers for this subscriber.
104
103
  We compare that accumulated time with the soak_days setting of the subscriber.
105
104
  """
106
- now = datetime.now(timezone.utc)
105
+ now = datetime.now(UTC)
107
106
  delta = timedelta(days=0)
108
107
  for channel in self.channels:
109
108
  for publisher in channel.publishers:
@@ -1,9 +1,6 @@
1
1
  import logging
2
2
  import sys
3
- from typing import (
4
- Callable,
5
- Optional,
6
- )
3
+ from collections.abc import Callable
7
4
 
8
5
  from reconcile.jenkins_job_builder import init_jjb
9
6
  from reconcile.status import ExitCodes
@@ -26,7 +23,7 @@ QONTRACT_INTEGRATION_VERSION = make_semver(0, 1, 0)
26
23
 
27
24
 
28
25
  @defer
29
- def run(dry_run: bool, defer: Optional[Callable] = None) -> None:
26
+ def run(dry_run: bool, defer: Callable | None = None) -> None:
30
27
  vault_settings = get_app_interface_vault_settings()
31
28
  saasherder_settings = get_saasherder_settings()
32
29
  secret_reader = create_secret_reader(use_vault=vault_settings.vault)
@@ -1,9 +1,6 @@
1
1
  import logging
2
2
  import sys
3
- from typing import (
4
- Any,
5
- Optional,
6
- )
3
+ from typing import Any
7
4
 
8
5
  from reconcile.closedbox_endpoint_monitoring_base import (
9
6
  Endpoint,
@@ -43,7 +40,7 @@ def run(
43
40
 
44
41
  def build_probe(
45
42
  provider: EndpointMonitoringProvider, endpoints: list[Endpoint]
46
- ) -> Optional[OpenshiftResource]:
43
+ ) -> OpenshiftResource | None:
47
44
  signalfx = provider.signalFx
48
45
  if not signalfx:
49
46
  return None
@@ -4,10 +4,7 @@ from collections.abc import (
4
4
  Callable,
5
5
  Iterable,
6
6
  )
7
- from typing import (
8
- Any,
9
- Optional,
10
- )
7
+ from typing import Any
11
8
 
12
9
  import jinja2
13
10
  import yaml
@@ -248,9 +245,9 @@ def get_skupper_networks(query_func: Callable) -> list[SkupperNetworkV1]:
248
245
  def run(
249
246
  dry_run: bool,
250
247
  thread_pool_size: int = 10,
251
- internal: Optional[bool] = None,
248
+ internal: bool | None = None,
252
249
  use_jump_host: bool = True,
253
- defer: Optional[Callable] = None,
250
+ defer: Callable | None = None,
254
251
  ) -> None:
255
252
  vault_settings = get_app_interface_vault_settings()
256
253
  secret_reader = create_secret_reader(use_vault=vault_settings.vault)
@@ -77,10 +77,8 @@ class SkupperSite(BaseModel):
77
77
  if (
78
78
  isinstance(
79
79
  c,
80
- (
81
- ClusterPeeringConnectionClusterRequesterV1,
82
- ClusterPeeringConnectionClusterAccepterV1,
83
- ),
80
+ ClusterPeeringConnectionClusterRequesterV1
81
+ | ClusterPeeringConnectionClusterAccepterV1,
84
82
  )
85
83
  ) and c.cluster.name == other.cluster.name:
86
84
  return True
@@ -168,7 +166,7 @@ class SkupperSite(BaseModel):
168
166
 
169
167
  def unique_token_name(self, other: SkupperSite) -> str:
170
168
  """Generate a unique token name for a site connection."""
171
- return hashlib.sha256(f"{other}-{self}".encode("UTF-8")).hexdigest()
169
+ return hashlib.sha256(f"{other}-{self}".encode()).hexdigest()
172
170
 
173
171
  def token_name(self, other: SkupperSite) -> str:
174
172
  """Get the token name for a site connection."""
reconcile/slack_base.py CHANGED
@@ -1,8 +1,5 @@
1
1
  from collections.abc import Mapping
2
- from typing import (
3
- Any,
4
- Optional,
5
- )
2
+ from typing import Any
6
3
 
7
4
  from reconcile import queries
8
5
  from reconcile.utils.secret_reader import (
@@ -31,7 +28,7 @@ def slackapi_from_slack_workspace(
31
28
  secret_reader: SecretReaderBase,
32
29
  integration_name: str,
33
30
  init_usergroups: bool = True,
34
- channel: Optional[str] = None,
31
+ channel: str | None = None,
35
32
  ) -> SlackApi:
36
33
  if "workspace" not in slack_workspace:
37
34
  raise ValueError('Slack workspace not containing keyword "workspace"')
@@ -104,9 +101,9 @@ def slackapi_from_permissions(
104
101
  def get_slackapi(
105
102
  workspace_name: str,
106
103
  token: str,
107
- client_config: Optional[HasClientConfig] = None,
104
+ client_config: HasClientConfig | None = None,
108
105
  init_usergroups: bool = True,
109
- channel: Optional[str] = None,
106
+ channel: str | None = None,
110
107
  ) -> SlackApi:
111
108
  """Initiate a SlackApi instance."""
112
109
  if client_config:
@@ -3,14 +3,12 @@ import sys
3
3
  from collections.abc import (
4
4
  Callable,
5
5
  Iterable,
6
+ Sequence,
6
7
  )
7
8
  from datetime import datetime
8
9
  from typing import (
9
10
  Any,
10
- Optional,
11
- Sequence,
12
11
  TypedDict,
13
- Union,
14
12
  )
15
13
  from urllib.parse import urlparse
16
14
 
@@ -77,7 +75,7 @@ INTEGRATION_VERSION = "0.1.0"
77
75
  error_occurred = False
78
76
 
79
77
 
80
- def get_git_api(url: str) -> Union[GithubRepositoryApi, GitLabApi]:
78
+ def get_git_api(url: str) -> GithubRepositoryApi | GitLabApi:
81
79
  """Return GitHub/GitLab API based on url."""
82
80
  parsed_url = urlparse(url)
83
81
 
@@ -147,7 +145,7 @@ def compute_cluster_user_group(name: str) -> str:
147
145
  def get_slack_map(
148
146
  secret_reader: SecretReader,
149
147
  permissions: Iterable[PermissionSlackUsergroupV1],
150
- desired_workspace_name: Optional[str] = None,
148
+ desired_workspace_name: str | None = None,
151
149
  ) -> SlackMap:
152
150
  """Return SlackMap (API) per workspaces."""
153
151
  slack_map = {}
@@ -183,8 +181,8 @@ def get_slack_map(
183
181
 
184
182
  def get_current_state(
185
183
  slack_map: SlackMap,
186
- desired_workspace_name: Optional[str],
187
- desired_usergroup_name: Optional[str],
184
+ desired_workspace_name: str | None,
185
+ desired_usergroup_name: str | None,
188
186
  cluster_usergroups: list[str],
189
187
  ) -> SlackState:
190
188
  """
@@ -399,8 +397,8 @@ def get_desired_state(
399
397
  pagerduty_map: PagerDutyMap,
400
398
  permissions: Iterable[PermissionSlackUsergroupV1],
401
399
  users: Iterable[User],
402
- desired_workspace_name: Optional[str],
403
- desired_usergroup_name: Optional[str],
400
+ desired_workspace_name: str | None,
401
+ desired_usergroup_name: str | None,
404
402
  ) -> SlackState:
405
403
  """Get the desired state of Slack usergroups."""
406
404
  desired_state: SlackState = {}
@@ -461,8 +459,8 @@ def get_desired_state_cluster_usergroups(
461
459
  slack_map: SlackMap,
462
460
  clusters: Iterable[ClusterV1],
463
461
  users: Iterable[UserV1],
464
- desired_workspace_name: Optional[str],
465
- desired_usergroup_name: Optional[str],
462
+ desired_workspace_name: str | None,
463
+ desired_usergroup_name: str | None,
466
464
  ) -> SlackState:
467
465
  """Get the desired state of Slack usergroups."""
468
466
  desired_state: SlackState = {}
@@ -752,14 +750,14 @@ class RunnerParams(TypedDict):
752
750
  slack_map: SlackMap
753
751
  desired_state: SlackState
754
752
  clusters: list[ClusterV1]
755
- workspace_name: Optional[str]
756
- usergroup_name: Optional[str]
753
+ workspace_name: str | None
754
+ usergroup_name: str | None
757
755
 
758
756
 
759
757
  def run(
760
758
  dry_run: bool,
761
- workspace_name: Optional[str] = None,
762
- usergroup_name: Optional[str] = None,
759
+ workspace_name: str | None = None,
760
+ usergroup_name: str | None = None,
763
761
  enable_extended_early_exit: bool = False,
764
762
  extended_early_exit_cache_ttl_seconds: int = 3600,
765
763
  log_cached_log_output: bool = False,
@@ -841,8 +839,8 @@ def runner(
841
839
  slack_map: SlackMap,
842
840
  desired_state: SlackState,
843
841
  clusters: list[ClusterV1],
844
- workspace_name: Optional[str] = None,
845
- usergroup_name: Optional[str] = None,
842
+ workspace_name: str | None = None,
843
+ usergroup_name: str | None = None,
846
844
  ) -> ExtendedEarlyExitRunnerResult:
847
845
  current_state = get_current_state(
848
846
  slack_map=slack_map,
reconcile/sql_query.py CHANGED
@@ -2,17 +2,13 @@ import logging
2
2
  import sys
3
3
  import time
4
4
  from collections.abc import (
5
+ Callable,
5
6
  Iterable,
6
7
  Mapping,
7
8
  )
8
9
  from enum import Enum
9
10
  from textwrap import indent
10
- from typing import (
11
- Any,
12
- Callable,
13
- Optional,
14
- Union,
15
- )
11
+ from typing import Any
16
12
 
17
13
  import jinja2
18
14
 
@@ -162,7 +158,7 @@ spec:
162
158
 
163
159
  def get_tf_resource_info(
164
160
  terrascript: Terrascript, namespace: Mapping[str, Any], identifier: str
165
- ) -> Union[dict[str, str], None]:
161
+ ) -> dict[str, str] | None:
166
162
  """
167
163
  Extracting the external resources information from the namespace
168
164
  for a given identifier
@@ -191,7 +187,7 @@ def get_tf_resource_info(
191
187
 
192
188
 
193
189
  def collect_queries(
194
- settings: dict[str, Any], smtp_client: SmtpClient, query_name: Optional[str] = None
190
+ settings: dict[str, Any], smtp_client: SmtpClient, query_name: str | None = None
195
191
  ) -> list[dict[str, Any]]:
196
192
  """
197
193
  Consults the app-interface and constructs the list of queries
@@ -835,7 +831,7 @@ def _process_new_query(
835
831
  def run(
836
832
  dry_run: bool,
837
833
  enable_deletion: bool = False,
838
- defer: Optional[Callable] = None,
834
+ defer: Callable | None = None,
839
835
  ) -> None:
840
836
  settings = queries.get_app_interface_settings()
841
837
  state = init_state(integration=QONTRACT_INTEGRATION)
reconcile/status_board.py CHANGED
@@ -3,10 +3,9 @@ from abc import (
3
3
  ABC,
4
4
  abstractmethod,
5
5
  )
6
+ from collections.abc import Iterable, Mapping
6
7
  from typing import (
7
8
  Any,
8
- Iterable,
9
- Mapping,
10
9
  Optional,
11
10
  )
12
11
 
@@ -39,10 +38,10 @@ class AbstractStatusBoard(ABC, BaseModel):
39
38
  """Abstract class for upgrade policies
40
39
  Used to create and delete upgrade policies in OCM."""
41
40
 
42
- id: Optional[str]
41
+ id: str | None
43
42
  name: str
44
43
  fullname: str
45
- metadata: Optional[dict[str, Any]]
44
+ metadata: dict[str, Any] | None
46
45
 
47
46
  @abstractmethod
48
47
  def create(self, ocm: OCMBaseClient) -> None:
@@ -63,7 +62,7 @@ class AbstractStatusBoard(ABC, BaseModel):
63
62
 
64
63
 
65
64
  class Product(AbstractStatusBoard):
66
- applications: Optional[list["Application"]]
65
+ applications: list["Application"] | None
67
66
 
68
67
  def create(self, ocm: OCMBaseClient) -> None:
69
68
  spec = self.dict(by_alias=True)
@@ -2,7 +2,6 @@ import logging
2
2
  import time
3
3
  from typing import (
4
4
  Any,
5
- Optional,
6
5
  Self,
7
6
  )
8
7
 
@@ -29,12 +28,12 @@ class AtlassianRawComponent(BaseModel):
29
28
 
30
29
  id: str
31
30
  name: str
32
- description: Optional[str]
31
+ description: str | None
33
32
  position: int
34
33
  status: str
35
- automation_email: Optional[str]
36
- group_id: Optional[str]
37
- group: Optional[bool]
34
+ automation_email: str | None
35
+ group_id: str | None
36
+ group: bool | None
38
37
 
39
38
 
40
39
  class AtlassianRawMaintenanceUpdate(BaseModel):
@@ -56,9 +55,9 @@ class AtlassianRawMaintenance(BaseModel):
56
55
  scheduled_until: str
57
56
  incident_updates: list[AtlassianRawMaintenanceUpdate]
58
57
  components: list[AtlassianRawComponent]
59
- auto_transition_deliver_notifications_at_end: Optional[bool]
60
- auto_transition_deliver_notifications_at_start: Optional[bool]
61
- scheduled_remind_prior: Optional[bool]
58
+ auto_transition_deliver_notifications_at_end: bool | None
59
+ auto_transition_deliver_notifications_at_start: bool | None
60
+ scheduled_remind_prior: bool | None
62
61
 
63
62
 
64
63
  class AtlassianAPI:
@@ -177,13 +176,13 @@ class AtlassianStatusPageProvider:
177
176
  self._group_name_to_id = {g.name: g.id for g in self._components if g.group}
178
177
  self._group_id_to_name = {g.id: g.name for g in self._components if g.group}
179
178
 
180
- def get_component_by_id(self, id: str) -> Optional[StatusComponent]:
179
+ def get_component_by_id(self, id: str) -> StatusComponent | None:
181
180
  raw = self.get_raw_component_by_id(id)
182
181
  if raw:
183
182
  return self._bound_raw_component_to_status_component(raw)
184
183
  return None
185
184
 
186
- def get_raw_component_by_id(self, id: str) -> Optional[AtlassianRawComponent]:
185
+ def get_raw_component_by_id(self, id: str) -> AtlassianRawComponent | None:
187
186
  return self._components_by_id.get(id)
188
187
 
189
188
  def get_current_page(self) -> StatusPage:
@@ -201,7 +200,7 @@ class AtlassianStatusPageProvider:
201
200
  )
202
201
 
203
202
  def _raw_component_to_status_component(
204
- self, raw_component: AtlassianRawComponent, name_override: Optional[str] = None
203
+ self, raw_component: AtlassianRawComponent, name_override: str | None = None
205
204
  ) -> StatusComponent:
206
205
  group_name = (
207
206
  self._group_id_to_name.get(raw_component.group_id)
@@ -222,7 +221,7 @@ class AtlassianStatusPageProvider:
222
221
 
223
222
  def _bound_raw_component_to_status_component(
224
223
  self, raw_component: AtlassianRawComponent
225
- ) -> Optional[StatusComponent]:
224
+ ) -> StatusComponent | None:
226
225
  bound_component_name = self._binding_state.get_name_for_component_id(
227
226
  raw_component.id
228
227
  )
@@ -234,7 +233,7 @@ class AtlassianStatusPageProvider:
234
233
 
235
234
  def lookup_component(
236
235
  self, desired_component: StatusComponent
237
- ) -> tuple[Optional[AtlassianRawComponent], bool]:
236
+ ) -> tuple[AtlassianRawComponent | None, bool]:
238
237
  """
239
238
  Finds the component on the page that matches the desired component. This
240
239
  is either done explicitely by using binding information if available or
@@ -268,7 +267,7 @@ class AtlassianStatusPageProvider:
268
267
  return component, bound
269
268
 
270
269
  def should_apply(
271
- self, desired: StatusComponent, current: Optional[AtlassianRawComponent]
270
+ self, desired: StatusComponent, current: AtlassianRawComponent | None
272
271
  ) -> bool:
273
272
  """
274
273
  Verifies if the desired component should be applied to the status page
@@ -410,7 +409,7 @@ class AtlassianStatusPageProvider:
410
409
  def _raw_maintenance_to_status_maintenance(
411
410
  self,
412
411
  raw_maintenance: AtlassianRawMaintenance,
413
- name_override: Optional[str] = None,
412
+ name_override: str | None = None,
414
413
  ) -> StatusMaintenance:
415
414
  return StatusMaintenance(
416
415
  name=name_override or raw_maintenance.name,
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  import sys
3
- from datetime import datetime, timedelta, timezone
3
+ from datetime import UTC, datetime, timedelta
4
4
 
5
5
  from reconcile.slack_base import slackapi_from_queries
6
6
  from reconcile.statuspage.atlassian import AtlassianStatusPageProvider
@@ -52,7 +52,7 @@ class StatusPageMaintenancesIntegration(QontractReconcileIntegration[NoParams]):
52
52
  desired_state: list[StatusMaintenance],
53
53
  binding_state: S3ComponentBindingState,
54
54
  ) -> None:
55
- now = datetime.now(timezone.utc)
55
+ now = datetime.now(UTC)
56
56
  slack = slackapi_from_queries(QONTRACT_INTEGRATION, init_usergroups=False)
57
57
  for m in desired_state:
58
58
  scheduled_start = datetime.fromisoformat(m.schedule_start)
@@ -68,7 +68,7 @@ class StatusPageMaintenancesIntegration(QontractReconcileIntegration[NoParams]):
68
68
  def run(self, dry_run: bool = False) -> None:
69
69
  binding_state = get_binding_state(self.name, self.secret_reader)
70
70
  pages = get_status_pages()
71
- now = datetime.now(timezone.utc)
71
+ now = datetime.now(UTC)
72
72
 
73
73
  error = False
74
74
  for p in pages:
@@ -1,4 +1,4 @@
1
- from typing import Optional, Self, cast
1
+ from typing import Self, cast
2
2
 
3
3
  from pydantic import BaseModel
4
4
 
@@ -25,8 +25,8 @@ class StatusComponent(BaseModel):
25
25
 
26
26
  name: str
27
27
  display_name: str
28
- description: Optional[str]
29
- group_name: Optional[str]
28
+ description: str | None
29
+ group_name: str | None
30
30
  status_provider_configs: list[StatusProvider]
31
31
  """
32
32
  Status provider configs hold different ways for a component to determine its status
@@ -39,7 +39,7 @@ class StatusComponent(BaseModel):
39
39
  """
40
40
  return bool(self.status_provider_configs)
41
41
 
42
- def desired_component_status(self) -> Optional[str]:
42
+ def desired_component_status(self) -> str | None:
43
43
  if self.status_management_enabled():
44
44
  for provider in self.status_provider_configs:
45
45
  status = provider.get_status()
@@ -53,7 +53,7 @@ class StatusComponent(BaseModel):
53
53
 
54
54
  @classmethod
55
55
  def init_from_page_component(
56
- cls, component: StatusPageComponentV1, name_override: Optional[str] = None
56
+ cls, component: StatusPageComponentV1, name_override: str | None = None
57
57
  ) -> Self:
58
58
  status_configs = [
59
59
  build_status_provider_config(cfg) for cfg in component.status_config or []
@@ -106,9 +106,9 @@ class StatusMaintenanceAnnouncement(BaseModel):
106
106
  Represents the desired state of a status maintenance.
107
107
  """
108
108
 
109
- remind_subscribers: Optional[bool] = None
110
- notify_subscribers_on_start: Optional[bool] = None
111
- notify_subscribers_on_completion: Optional[bool] = None
109
+ remind_subscribers: bool | None = None
110
+ notify_subscribers_on_start: bool | None = None
111
+ notify_subscribers_on_completion: bool | None = None
112
112
 
113
113
  @classmethod
114
114
  def init_from_announcement(
@@ -1,5 +1,4 @@
1
1
  from typing import (
2
- Optional,
3
2
  Protocol,
4
3
  )
5
4
 
@@ -13,9 +12,9 @@ from reconcile.utils.state import State
13
12
 
14
13
 
15
14
  class ComponentBindingState(Protocol):
16
- def get_id_for_component_name(self, component_name: str) -> Optional[str]: ...
15
+ def get_id_for_component_name(self, component_name: str) -> str | None: ...
17
16
 
18
- def get_name_for_component_id(self, component_id: str) -> Optional[str]: ...
17
+ def get_name_for_component_id(self, component_id: str) -> str | None: ...
19
18
 
20
19
  def bind_component(self, component_name: str, component_id: str) -> None: ...
21
20
 
@@ -33,10 +32,10 @@ class S3ComponentBindingState(ComponentBindingState):
33
32
  v: k for k, v in self.name_to_id_cache.items()
34
33
  }
35
34
 
36
- def get_id_for_component_name(self, component_name: str) -> Optional[str]:
35
+ def get_id_for_component_name(self, component_name: str) -> str | None:
37
36
  return self.name_to_id_cache.get(component_name)
38
37
 
39
- def get_name_for_component_id(self, component_id: str) -> Optional[str]:
38
+ def get_name_for_component_id(self, component_id: str) -> str | None:
40
39
  return self.id_to_name_cache.get(component_id)
41
40
 
42
41
  def bind_component(self, component_name: str, component_id: str) -> None:
@@ -3,10 +3,9 @@ from abc import (
3
3
  abstractmethod,
4
4
  )
5
5
  from datetime import (
6
+ UTC,
6
7
  datetime,
7
- timezone,
8
8
  )
9
- from typing import Optional
10
9
 
11
10
  from dateutil.parser import isoparse
12
11
  from pydantic import BaseModel
@@ -28,7 +27,7 @@ class StatusProvider(ABC):
28
27
  """
29
28
 
30
29
  @abstractmethod
31
- def get_status(self) -> Optional[str]: ...
30
+ def get_status(self) -> str | None: ...
32
31
 
33
32
 
34
33
  class ManualStatusProvider(StatusProvider, BaseModel):
@@ -38,13 +37,13 @@ class ManualStatusProvider(StatusProvider, BaseModel):
38
37
  the component.
39
38
  """
40
39
 
41
- start: Optional[datetime] = None
40
+ start: datetime | None = None
42
41
  """
43
42
  The optional start time of the time window in which the manually
44
43
  defined status is active.
45
44
  """
46
45
 
47
- end: Optional[datetime] = None
46
+ end: datetime | None = None
48
47
  """
49
48
  The optional end time of the time window in which the manually
50
49
  defined status is active.
@@ -56,7 +55,7 @@ class ManualStatusProvider(StatusProvider, BaseModel):
56
55
  time window is active or if no time window is defined.
57
56
  """
58
57
 
59
- def get_status(self) -> Optional[str]:
58
+ def get_status(self) -> str | None:
60
59
  if self._is_active():
61
60
  return self.component_status
62
61
  return None
@@ -71,7 +70,7 @@ class ManualStatusProvider(StatusProvider, BaseModel):
71
70
  raise ValueError(
72
71
  "manual component status time window is invalid: end before start"
73
72
  )
74
- now = datetime.now(timezone.utc)
73
+ now = datetime.now(UTC)
75
74
  if self.start and now < self.start:
76
75
  return False
77
76
  if self.end and self.end < now:
@@ -81,7 +80,7 @@ class ManualStatusProvider(StatusProvider, BaseModel):
81
80
 
82
81
  def build_status_provider_config(
83
82
  cfg: StatusProviderV1,
84
- ) -> Optional[StatusProvider]:
83
+ ) -> StatusProvider | None:
85
84
  """
86
85
  Translates a status provider config from the desired state into
87
86
  provider specific implementation that provides the status resolution logic.