qontract-reconcile 0.10.1rc884__py3-none-any.whl → 0.10.1rc886__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 (279) hide show
  1. {qontract_reconcile-0.10.1rc884.dist-info → qontract_reconcile-0.10.1rc886.dist-info}/METADATA +1 -1
  2. {qontract_reconcile-0.10.1rc884.dist-info → qontract_reconcile-0.10.1rc886.dist-info}/RECORD +279 -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 +31 -17
  272. tools/saas_promotion_state/__init__.py +0 -0
  273. tools/saas_promotion_state/saas_promotion_state.py +72 -0
  274. tools/template_validation.py +1 -1
  275. tools/test/conftest.py +45 -6
  276. tools/test/test_saas_promotion_state.py +86 -0
  277. {qontract_reconcile-0.10.1rc884.dist-info → qontract_reconcile-0.10.1rc886.dist-info}/WHEEL +0 -0
  278. {qontract_reconcile-0.10.1rc884.dist-info → qontract_reconcile-0.10.1rc886.dist-info}/entry_points.txt +0 -0
  279. {qontract_reconcile-0.10.1rc884.dist-info → qontract_reconcile-0.10.1rc886.dist-info}/top_level.txt +0 -0
reconcile/acs_rbac.py CHANGED
@@ -2,7 +2,6 @@ import logging
2
2
  from collections import defaultdict
3
3
  from collections.abc import Callable
4
4
  from typing import (
5
- Optional,
6
5
  Self,
7
6
  )
8
7
 
@@ -64,7 +63,7 @@ class AcsRole(BaseModel):
64
63
  assignments: list[AssignmentPair]
65
64
  permission_set_name: str
66
65
  access_scope: AcsAccessScope
67
- system_default: Optional[bool]
66
+ system_default: bool | None
68
67
 
69
68
  @classmethod
70
69
  def build(cls, permission: Permission, usernames: list[str]) -> Self:
@@ -197,7 +197,7 @@ class AdvancedUpgradeServiceIntegration(OCMClusterUpgradeSchedulerOrgIntegration
197
197
 
198
198
  def discover_clusters(
199
199
  ocm_api: OCMBaseClient,
200
- org_ids: Optional[set[str]] = None,
200
+ org_ids: set[str] | None = None,
201
201
  ignore_sts_clusters: bool = False,
202
202
  ) -> dict[str, list[ClusterDetails]]:
203
203
  """
@@ -222,7 +222,7 @@ def discover_clusters(
222
222
 
223
223
 
224
224
  def _get_org_labels(
225
- ocm_api: OCMBaseClient, org_ids: Optional[set[str]]
225
+ ocm_api: OCMBaseClient, org_ids: set[str] | None
226
226
  ) -> dict[str, LabelContainer]:
227
227
  """
228
228
  Fetch all AUS OCM org labels from organizations. They hold config
@@ -263,7 +263,7 @@ def _build_org_upgrade_specs_for_ocm_env(
263
263
  }
264
264
 
265
265
 
266
- def aus_label_key(config_atom: Optional[str] = None) -> str:
266
+ def aus_label_key(config_atom: str | None = None) -> str:
267
267
  """
268
268
  Generates label keys for aus, compliant with the naming schema defined in
269
269
  https://service.pages.redhat.com/dev-guidelines/docs/sre-capabilities/framework/ocm-labels/
@@ -276,7 +276,7 @@ class OrganizationLabelSet(BaseModel):
276
276
  Parses, represents and validates a set of organization labels for AUS.
277
277
  """
278
278
 
279
- blocked_versions: Optional[CSV] = Field(alias=aus_label_key("blocked-versions"))
279
+ blocked_versions: CSV | None = Field(alias=aus_label_key("blocked-versions"))
280
280
 
281
281
  sector_deps: dict[str, CSV] = labelset_groupfield(
282
282
  group_prefix=aus_label_key("sector-deps.")
@@ -395,10 +395,10 @@ class ClusterUpgradePolicyLabelSet(BaseModel):
395
395
  soak_days: int = Field(alias=aus_label_key("soak-days"), ge=0)
396
396
  workloads: CSV = Field(alias=aus_label_key("workloads"), csv_min_items=1)
397
397
  schedule: str = Field(alias=aus_label_key("schedule"))
398
- mutexes: Optional[CSV] = Field(alias=aus_label_key("mutexes"))
399
- sector: Optional[str] = Field(alias=aus_label_key("sector"))
400
- blocked_versions: Optional[CSV] = Field(alias=aus_label_key("blocked-versions"))
401
- version_gate_approvals: Optional[CSV] = Field(
398
+ mutexes: CSV | None = Field(alias=aus_label_key("mutexes"))
399
+ sector: str | None = Field(alias=aus_label_key("sector"))
400
+ blocked_versions: CSV | None = Field(alias=aus_label_key("blocked-versions"))
401
+ version_gate_approvals: CSV | None = Field(
402
402
  alias=aus_label_key("version-gate-approvals")
403
403
  )
404
404
  _schedule_validator = validator("schedule", allow_reuse=True)(cron_validator)
@@ -422,10 +422,10 @@ def build_cluster_upgrade_policy_label_set(
422
422
  workloads: list[str],
423
423
  schedule: str,
424
424
  soak_days: int,
425
- mutexes: Optional[list[str]] = None,
426
- sector: Optional[str] = None,
427
- blocked_versions: Optional[list[str]] = None,
428
- version_gate_approvals: Optional[list[str]] = None,
425
+ mutexes: list[str] | None = None,
426
+ sector: str | None = None,
427
+ blocked_versions: list[str] | None = None,
428
+ version_gate_approvals: list[str] | None = None,
429
429
  ) -> ClusterUpgradePolicyLabelSet:
430
430
  return ClusterUpgradePolicyLabelSet(**{
431
431
  aus_label_key("workloads"): ",".join(workloads),
@@ -463,7 +463,7 @@ def _build_policy_from_labels(labels: LabelContainer) -> ClusterUpgradePolicyV1:
463
463
 
464
464
 
465
465
  class VersionDataInheritanceLabelSet(BaseModel):
466
- inherit_version_data: Optional[CSV] = Field(
466
+ inherit_version_data: CSV | None = Field(
467
467
  alias=aus_label_key("version-data.inherit")
468
468
  )
469
469
  """
@@ -472,7 +472,7 @@ class VersionDataInheritanceLabelSet(BaseModel):
472
472
  Version data publishing/inheritance can also be defined between OCM environments.
473
473
  """
474
474
 
475
- publish_version_data: Optional[CSV] = Field(
475
+ publish_version_data: CSV | None = Field(
476
476
  alias=aus_label_key("version-data.publish")
477
477
  )
478
478
  """
@@ -1,5 +1,4 @@
1
- from collections.abc import Iterable
2
- from typing import Callable
1
+ from collections.abc import Callable, Iterable
3
2
 
4
3
  from reconcile.aus.advanced_upgrade_service import (
5
4
  aus_label_key,
reconcile/aus/base.py CHANGED
@@ -5,16 +5,13 @@ from abc import (
5
5
  ABC,
6
6
  abstractmethod,
7
7
  )
8
+ from collections.abc import Callable, Sequence
8
9
  from datetime import (
9
10
  datetime,
10
11
  timedelta,
11
- timezone,
12
12
  )
13
13
  from typing import (
14
- Callable,
15
- Optional,
16
14
  Protocol,
17
- Sequence,
18
15
  cast,
19
16
  )
20
17
 
@@ -112,9 +109,9 @@ MIN_DELTA_MINUTES = 6
112
109
 
113
110
 
114
111
  class AdvancedUpgradeSchedulerBaseIntegrationParams(PydanticRunParams):
115
- ocm_environment: Optional[str] = None
116
- ocm_organization_ids: Optional[set[str]] = None
117
- excluded_ocm_organization_ids: Optional[set[str]] = None
112
+ ocm_environment: str | None = None
113
+ ocm_organization_ids: set[str] | None = None
114
+ excluded_ocm_organization_ids: set[str] | None = None
118
115
  ignore_sts_clusters: bool = False
119
116
 
120
117
 
@@ -342,7 +339,7 @@ class AdvancedUpgradeSchedulerBaseIntegration(
342
339
  def _build_telemeter_health_check_provider_for_env(
343
340
  self,
344
341
  ocm_env_name: str,
345
- ) -> Optional[TelemeterClusterHealthProvider]:
342
+ ) -> TelemeterClusterHealthProvider | None:
346
343
  ocm_env = next(
347
344
  iter(
348
345
  ocm_env_telemeter_query(
@@ -403,12 +400,12 @@ class AbstractUpgradePolicy(ABC, BaseModel):
403
400
 
404
401
  cluster: OCMCluster
405
402
 
406
- id: Optional[str]
407
- next_run: Optional[str]
408
- schedule: Optional[str]
403
+ id: str | None
404
+ next_run: str | None
405
+ schedule: str | None
409
406
  schedule_type: str
410
407
  version: str
411
- state: Optional[str]
408
+ state: str | None
412
409
 
413
410
  @abstractmethod
414
411
  def create(self, ocm_api: OCMBaseClient) -> None:
@@ -424,7 +421,7 @@ class AbstractUpgradePolicy(ABC, BaseModel):
424
421
 
425
422
 
426
423
  def addon_upgrade_policy_soonest_next_run() -> str:
427
- now = datetime.now(tz=timezone.utc)
424
+ now = datetime.now(tz=dt.UTC)
428
425
  next_run = now + timedelta(minutes=MIN_DELTA_MINUTES)
429
426
  return next_run.strftime("%Y-%m-%dT%H:%M:%SZ")
430
427
 
@@ -683,7 +680,7 @@ def update_history(
683
680
  version_data.check_in = now
684
681
 
685
682
 
686
- def version_data_state_key(ocm_env: str, org_id: str, addon_id: Optional[str]) -> str:
683
+ def version_data_state_key(ocm_env: str, org_id: str, addon_id: str | None) -> str:
687
684
  return f"{ocm_env}/{org_id}/{addon_id}" if addon_id else f"{ocm_env}/{org_id}"
688
685
 
689
686
 
@@ -694,7 +691,7 @@ def get_version_data_map(
694
691
  integration: str,
695
692
  addon_id: str = "",
696
693
  inherit_version_data: bool = True,
697
- defer: Optional[Callable] = None,
694
+ defer: Callable | None = None,
698
695
  ) -> VersionDataMap:
699
696
  """Get a summary of versions history per OCM instance
700
697
 
@@ -788,7 +785,7 @@ def version_conditions_met(
788
785
  version: str,
789
786
  version_data: VersionData,
790
787
  upgrade_policy: ClusterUpgradePolicyV1,
791
- sector: Optional[Sector],
788
+ sector: Sector | None,
792
789
  ) -> bool:
793
790
  """Check that upgrade conditions are met for a version
794
791
 
@@ -887,8 +884,8 @@ def gates_to_agree(
887
884
  def upgradeable_version(
888
885
  spec: ClusterUpgradeSpec,
889
886
  version_data: VersionData,
890
- sector: Optional[Sector],
891
- ) -> Optional[str]:
887
+ sector: Sector | None,
888
+ ) -> str | None:
892
889
  """Get the highest next version we can upgrade to, fulfilling all conditions"""
893
890
  for version in reversed(sort_versions(spec.get_available_upgrades())):
894
891
  if spec.version_blocked(version):
@@ -908,7 +905,7 @@ def verify_current_should_skip(
908
905
  desired: ClusterUpgradeSpec,
909
906
  now: datetime,
910
907
  addon_id: str = "",
911
- ) -> tuple[bool, Optional[UpgradePolicyHandler]]:
908
+ ) -> tuple[bool, UpgradePolicyHandler | None]:
912
909
  current_policies = [c for c in current_state if c.cluster.id == desired.cluster.id]
913
910
  if not current_policies:
914
911
  return False, None
@@ -944,7 +941,7 @@ def verify_schedule_should_skip(
944
941
  desired: ClusterUpgradeSpec,
945
942
  now: datetime,
946
943
  addon_id: str = "",
947
- ) -> Optional[str]:
944
+ ) -> str | None:
948
945
  schedule = desired.upgrade_policy.schedule
949
946
  iter = croniter(schedule)
950
947
  # ClusterService refuses scheduling upgrades less than 5m in advance
@@ -1006,7 +1003,7 @@ def _create_upgrade_policy(
1006
1003
 
1007
1004
  def _calculate_node_pool_diffs(
1008
1005
  ocm_api: OCMBaseClient, spec: ClusterUpgradeSpec, now: datetime
1009
- ) -> Optional[UpgradePolicyHandler]:
1006
+ ) -> UpgradePolicyHandler | None:
1010
1007
  node_pools = get_node_pools(ocm_api, spec.cluster.id)
1011
1008
  if node_pools:
1012
1009
  for pool in node_pools:
@@ -1051,7 +1048,7 @@ def calculate_diff(
1051
1048
  """
1052
1049
 
1053
1050
  def set_mutex(
1054
- locked: dict[str, str], cluster_id: str, mutexes: Optional[set[str]] = None
1051
+ locked: dict[str, str], cluster_id: str, mutexes: set[str] | None = None
1055
1052
  ) -> None:
1056
1053
  for mutex in mutexes or set():
1057
1054
  locked[mutex] = cluster_id
@@ -1174,7 +1171,7 @@ def act(
1174
1171
  dry_run: bool,
1175
1172
  diffs: list[UpgradePolicyHandler],
1176
1173
  ocm_api: OCMBaseClient,
1177
- addon_id: Optional[str] = None,
1174
+ addon_id: str | None = None,
1178
1175
  ) -> None:
1179
1176
  diffs.sort(key=sort_diffs)
1180
1177
  for diff in diffs:
@@ -1207,8 +1204,8 @@ def get_orgs_for_environment(
1207
1204
  integration: str,
1208
1205
  ocm_env_name: str,
1209
1206
  query_func: Callable,
1210
- ocm_organization_ids: Optional[set[str]] = None,
1211
- excluded_ocm_organization_ids: Optional[set[str]] = None,
1207
+ ocm_organization_ids: set[str] | None = None,
1208
+ excluded_ocm_organization_ids: set[str] | None = None,
1212
1209
  only_addon_managed_upgrades: bool = False,
1213
1210
  ) -> list[AUSOCMOrganization]:
1214
1211
  """
@@ -1243,7 +1240,7 @@ def get_orgs_for_environment(
1243
1240
  def remaining_soak_day_metric_values_for_cluster(
1244
1241
  spec: ClusterUpgradeSpec,
1245
1242
  soaked_versions: dict[str, float],
1246
- current_upgrade: Optional[AbstractUpgradePolicy],
1243
+ current_upgrade: AbstractUpgradePolicy | None,
1247
1244
  ) -> dict[str, float]:
1248
1245
  """
1249
1246
  Calculate what versions and metric values to report for `AUS*VersionRemainingSoakDaysGauge` metrics.
@@ -1,8 +1,8 @@
1
1
  import json
2
+ from collections.abc import Iterable
2
3
  from datetime import datetime
3
4
  from typing import (
4
5
  Any,
5
- Iterable,
6
6
  Optional,
7
7
  )
8
8
 
@@ -93,9 +93,9 @@ class VersionData(BaseModel):
93
93
  upgrade policies.
94
94
  """
95
95
 
96
- check_in: Optional[datetime]
96
+ check_in: datetime | None
97
97
  versions: dict[str, VersionHistory] = Field(default_factory=dict)
98
- stats: Optional[Stats]
98
+ stats: Stats | None
99
99
 
100
100
  def jsondict(self) -> dict[str, Any]:
101
101
  return json.loads(self.json(exclude_none=True))
@@ -104,7 +104,7 @@ class VersionData(BaseModel):
104
104
  state.add(ocm_name, self.jsondict(), force=True)
105
105
 
106
106
  def workload_history(
107
- self, version: str, workload: str, default: Optional[WorkloadHistory] = None
107
+ self, version: str, workload: str, default: WorkloadHistory | None = None
108
108
  ) -> WorkloadHistory:
109
109
  if not default:
110
110
  vh = self.versions.get(version, VersionHistory())
reconcile/aus/models.py CHANGED
@@ -7,7 +7,6 @@ from collections.abc import (
7
7
  Mapping,
8
8
  Sequence,
9
9
  )
10
- from typing import Optional
11
10
 
12
11
  from pydantic import (
13
12
  BaseModel,
@@ -108,7 +107,7 @@ class OrganizationUpgradeSpec(BaseModel):
108
107
  def __init__(
109
108
  self,
110
109
  org: AUSOCMOrganization,
111
- specs: Optional[Iterable[ClusterUpgradeSpec]] = None,
110
+ specs: Iterable[ClusterUpgradeSpec] | None = None,
112
111
  ) -> None:
113
112
  super().__init__(org=org)
114
113
 
@@ -200,7 +199,7 @@ class SectorConfigError(Exception):
200
199
 
201
200
  class Sector(BaseModel):
202
201
  name: str
203
- dependencies: list["Sector"] = Field(default_factory=list)
202
+ dependencies: list[Sector] = Field(default_factory=list)
204
203
  _specs: dict[str, ClusterUpgradeSpec] = PrivateAttr(default_factory=dict)
205
204
 
206
205
  def __key(self) -> str:
@@ -1,9 +1,5 @@
1
1
  import logging
2
- from typing import (
3
- Callable,
4
- Iterable,
5
- Optional,
6
- )
2
+ from collections.abc import Callable, Iterable
7
3
 
8
4
  from reconcile.aus.advanced_upgrade_service import aus_label_key
9
5
  from reconcile.aus.base import gates_to_agree, get_orgs_for_environment
@@ -54,7 +50,7 @@ class VersionGateApproverParams(PydanticRunParams):
54
50
  job_controller_namespace: str
55
51
  rosa_job_service_account: str
56
52
  rosa_role: str
57
- rosa_job_image: Optional[str] = None
53
+ rosa_job_image: str | None = None
58
54
 
59
55
 
60
56
  class VersionGateApprover(QontractReconcileIntegration[VersionGateApproverParams]):
@@ -1,5 +1,3 @@
1
- from typing import Type
2
-
3
1
  from reconcile.aus.version_gates import (
4
2
  ingress_gate_handler,
5
3
  ocp_gate_handler,
@@ -7,7 +5,7 @@ from reconcile.aus.version_gates import (
7
5
  )
8
6
  from reconcile.aus.version_gates.handler import GateHandler
9
7
 
10
- HANDLERS: dict[str, Type[GateHandler]] = {
8
+ HANDLERS: dict[str, type[GateHandler]] = {
11
9
  ocp_gate_handler.GATE_LABEL: ocp_gate_handler.OCPGateHandler,
12
10
  sts_version_gate_handler.GATE_LABEL: sts_version_gate_handler.STSGateHandler,
13
11
  ingress_gate_handler.GATE_LABEL: ingress_gate_handler.IngressGateHandler,
@@ -1,5 +1,4 @@
1
1
  import logging
2
- from typing import Optional
3
2
 
4
3
  from reconcile.aus.version_gates.handler import GateHandler
5
4
  from reconcile.utils.jobcontroller.controller import K8sJobController
@@ -16,8 +15,8 @@ class STSGateHandler(GateHandler):
16
15
  self,
17
16
  job_controller: K8sJobController,
18
17
  aws_iam_role: str,
19
- rosa_job_service_account: Optional[str] = None,
20
- rosa_job_image: Optional[str] = None,
18
+ rosa_job_service_account: str | None = None,
19
+ rosa_job_image: str | None = None,
21
20
  ) -> None:
22
21
  self.job_controller = job_controller
23
22
  self.aws_iam_role = aws_iam_role
@@ -1,5 +1,5 @@
1
1
  from collections.abc import Callable, Iterable
2
- from datetime import datetime, timezone
2
+ from datetime import UTC, datetime
3
3
  from typing import Any
4
4
 
5
5
  import jinja2
@@ -99,7 +99,7 @@ class AwsAccountMgmtIntegration(
99
99
  "accountRequest": account_request.dict(by_alias=True),
100
100
  "uid": uid,
101
101
  "settings": settings,
102
- "timestamp": int(datetime.now(tz=timezone.utc).timestamp()),
102
+ "timestamp": int(datetime.now(tz=UTC).timestamp()),
103
103
  })
104
104
  return tmpl
105
105
 
@@ -12,7 +12,6 @@ from datetime import (
12
12
  from typing import (
13
13
  TYPE_CHECKING,
14
14
  Any,
15
- Optional,
16
15
  )
17
16
 
18
17
  from botocore.exceptions import ClientError
@@ -153,7 +152,7 @@ def get_region(
153
152
 
154
153
 
155
154
  def get_app_interface_amis(
156
- namespaces: Optional[list[NamespaceV1]], ts: Terrascript
155
+ namespaces: list[NamespaceV1] | None, ts: Terrascript
157
156
  ) -> list[AIAmi]:
158
157
  """Returns all the ami referenced in ASGs in app-interface."""
159
158
  app_interface_amis = []
@@ -185,7 +184,7 @@ def get_app_interface_amis(
185
184
 
186
185
  def check_aws_ami_in_use(
187
186
  aws_ami: AWSAmi, app_interface_amis: list[AIAmi]
188
- ) -> Optional[str]:
187
+ ) -> str | None:
189
188
  """Verifies if the given AWS ami is in use in a defined app-interface ASG."""
190
189
  for ai_ami in app_interface_amis:
191
190
  # This can happen if the ASG init template has changed over the time. We don't have a way
@@ -203,7 +202,7 @@ def check_aws_ami_in_use(
203
202
 
204
203
 
205
204
  @defer
206
- def run(dry_run: bool, thread_pool_size: int, defer: Optional[Callable] = None) -> None:
205
+ def run(dry_run: bool, thread_pool_size: int, defer: Callable | None = None) -> None:
207
206
  exit_code = ExitCodes.SUCCESS
208
207
 
209
208
  # We still use here a non-typed query; accounts is passed to AWSApi and Terrascript classes
@@ -4,10 +4,7 @@ from collections.abc import (
4
4
  Iterable,
5
5
  Mapping,
6
6
  )
7
- from typing import (
8
- Any,
9
- Optional,
10
- )
7
+ from typing import Any
11
8
 
12
9
  from pydantic import BaseModel
13
10
 
@@ -21,7 +18,7 @@ QONTRACT_INTEGRATION = "aws-iam-password-reset"
21
18
 
22
19
  def get_roles(
23
20
  roles: Iterable[Mapping[str, Any]], org_username: str
24
- ) -> Optional[Mapping[str, Any]]:
21
+ ) -> Mapping[str, Any] | None:
25
22
  for d in roles:
26
23
  if d["org_username"] == org_username:
27
24
  return d
@@ -3,7 +3,7 @@ from collections.abc import (
3
3
  Callable,
4
4
  Iterable,
5
5
  )
6
- from enum import Enum
6
+ from enum import StrEnum
7
7
  from typing import Any
8
8
 
9
9
  import semver
@@ -69,7 +69,7 @@ class ExternalResourceProvisioner(BaseModel):
69
69
  path: str | None = None
70
70
 
71
71
 
72
- class VersionFormat(str, Enum):
72
+ class VersionFormat(StrEnum):
73
73
  MAJOR = "major"
74
74
  MAJOR_MINOR = "major_minor"
75
75
  MAJOR_MINOR_PATCH = "major_minor_patch"
@@ -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 import queries
9
6
  from reconcile.closedbox_endpoint_monitoring_base import (
@@ -69,7 +66,7 @@ def get_blackbox_providers() -> list[EndpointMonitoringProvider]:
69
66
 
70
67
  def build_probe(
71
68
  provider: EndpointMonitoringProvider, endpoints: list[Endpoint]
72
- ) -> Optional[OpenshiftResource]:
69
+ ) -> OpenshiftResource | None:
73
70
  blackbox_exporter = provider.blackboxExporter
74
71
  if blackbox_exporter:
75
72
  prober_url = parse_prober_url(blackbox_exporter.exporterUrl)
@@ -1,6 +1,5 @@
1
1
  from dataclasses import dataclass
2
2
  from typing import (
3
- Optional,
4
3
  Protocol,
5
4
  )
6
5
 
@@ -17,25 +16,25 @@ class Approver:
17
16
  """
18
17
 
19
18
  org_username: str
20
- tag_on_merge_requests: Optional[bool] = False
19
+ tag_on_merge_requests: bool | None = False
21
20
 
22
21
 
23
22
  class ApproverResolver(Protocol):
24
- def lookup_approver_by_path(self, path: str) -> Optional[Approver]: ...
23
+ def lookup_approver_by_path(self, path: str) -> Approver | None: ...
25
24
 
26
25
 
27
26
  class GqlApproverResolver:
28
27
  def __init__(self, gqlapis: list[GqlApi]):
29
28
  self.gqlapis = gqlapis
30
29
 
31
- def lookup_approver_by_path(self, path: str) -> Optional[Approver]:
30
+ def lookup_approver_by_path(self, path: str) -> Approver | None:
32
31
  for gqlapi in self.gqlapis:
33
32
  approver = self._lookup_approver_by_path(gqlapi, path)
34
33
  if approver:
35
34
  return approver
36
35
  return None
37
36
 
38
- def _lookup_approver_by_path(self, gqlapi: GqlApi, path: str) -> Optional[Approver]:
37
+ def _lookup_approver_by_path(self, gqlapi: GqlApi, path: str) -> Approver | None:
39
38
  approvers = gqlapi.query(
40
39
  """
41
40
  query Approvers($path: String) {
@@ -1,11 +1,9 @@
1
1
  from abc import abstractmethod
2
2
  from dataclasses import dataclass
3
- from enum import Enum
3
+ from enum import StrEnum
4
4
  from typing import (
5
5
  Any,
6
- Optional,
7
6
  Protocol,
8
- Tuple,
9
7
  )
10
8
 
11
9
  from pydantic import (
@@ -20,7 +18,7 @@ DATAFILE_SHA256SUM_FIELD_NAME = "$file_sha256sum"
20
18
  DATAFILE_SCHEMA_FIELD_NAME = "$schema"
21
19
 
22
20
 
23
- class BundleFileType(str, Enum):
21
+ class BundleFileType(StrEnum):
24
22
  DATAFILE = "datafile"
25
23
  RESOURCEFILE = "resourcefile"
26
24
 
@@ -33,7 +31,7 @@ class FileRef:
33
31
 
34
32
  file_type: BundleFileType
35
33
  path: str
36
- schema: Optional[str]
34
+ schema: str | None
37
35
 
38
36
  def __str__(self) -> str:
39
37
  return f"{self.file_type.value}:{self.path}"
@@ -63,35 +61,35 @@ class QontractServerDatafileDiff(BaseModel):
63
61
 
64
62
  datafilepath: str
65
63
  datafileschema: str
66
- old: Optional[dict[str, Any]]
67
- new: Optional[dict[str, Any]]
64
+ old: dict[str, Any] | None
65
+ new: dict[str, Any] | None
68
66
 
69
67
  @property
70
- def old_datafilepath(self) -> Optional[str]:
68
+ def old_datafilepath(self) -> str | None:
71
69
  return self.old.get(DATAFILE_PATH_FIELD_NAME) if self.old else None
72
70
 
73
71
  @property
74
- def new_datafilepath(self) -> Optional[str]:
72
+ def new_datafilepath(self) -> str | None:
75
73
  return self.new.get(DATAFILE_PATH_FIELD_NAME) if self.new else None
76
74
 
77
75
  @property
78
- def old_data_sha(self) -> Optional[str]:
76
+ def old_data_sha(self) -> str | None:
79
77
  return self.old.get(DATAFILE_SHA256SUM_FIELD_NAME) if self.old else None
80
78
 
81
79
  @property
82
- def new_data_sha(self) -> Optional[str]:
80
+ def new_data_sha(self) -> str | None:
83
81
  return self.new.get(DATAFILE_SHA256SUM_FIELD_NAME) if self.new else None
84
82
 
85
83
  @property
86
- def cleaned_old_data(self) -> Optional[dict[str, Any]]:
84
+ def cleaned_old_data(self) -> dict[str, Any] | None:
87
85
  return _clean_datafile_content(self.old)
88
86
 
89
87
  @property
90
- def cleaned_new_data(self) -> Optional[dict[str, Any]]:
88
+ def cleaned_new_data(self) -> dict[str, Any] | None:
91
89
  return _clean_datafile_content(self.new)
92
90
 
93
91
 
94
- def _clean_datafile_content(data: Optional[dict[str, Any]]) -> Optional[dict[str, Any]]:
92
+ def _clean_datafile_content(data: dict[str, Any] | None) -> dict[str, Any] | None:
95
93
  """
96
94
  Sadly, datafiles mix and match data and metadata in the same file. This
97
95
  function removes some metadata that is otherwise annoying to deal with.
@@ -117,9 +115,9 @@ class QontractServerResourcefileDiffState(BaseModel):
117
115
 
118
116
  path: str
119
117
  content: str
120
- resourcefileschema: Optional[str] = Field(..., alias="$schema")
118
+ resourcefileschema: str | None = Field(..., alias="$schema")
121
119
  sha256sum: str
122
- backrefs: Optional[list[QontractServerResourcefileBackref]]
120
+ backrefs: list[QontractServerResourcefileBackref] | None
123
121
 
124
122
 
125
123
  class QontractServerResourcefileDiff(BaseModel):
@@ -128,11 +126,11 @@ class QontractServerResourcefileDiff(BaseModel):
128
126
  """
129
127
 
130
128
  resourcepath: str
131
- old: Optional[QontractServerResourcefileDiffState] = None
132
- new: Optional[QontractServerResourcefileDiffState] = None
129
+ old: QontractServerResourcefileDiffState | None = None
130
+ new: QontractServerResourcefileDiffState | None = None
133
131
 
134
132
  @property
135
- def resourcefileschema(self) -> Optional[str]:
133
+ def resourcefileschema(self) -> str | None:
136
134
  old_schema = self.old.resourcefileschema if self.old else None
137
135
  new_schema = self.new.resourcefileschema if self.new else None
138
136
  return new_schema or old_schema
@@ -160,7 +158,7 @@ class FileDiffResolver(Protocol):
160
158
  @abstractmethod
161
159
  def lookup_file_diff(
162
160
  self, file_ref: FileRef
163
- ) -> Tuple[Optional[dict[str, Any]], Optional[dict[str, Any]]]: ...
161
+ ) -> tuple[dict[str, Any] | None, dict[str, Any] | None]: ...
164
162
 
165
163
 
166
164
  @dataclass
@@ -174,7 +172,7 @@ class QontractServerFileDiffResolver:
174
172
 
175
173
  def lookup_file_diff(
176
174
  self, file_ref: FileRef
177
- ) -> Tuple[Optional[dict[str, Any]], Optional[dict[str, Any]]]:
175
+ ) -> tuple[dict[str, Any] | None, dict[str, Any] | None]:
178
176
  data = get_diff(
179
177
  old_sha=self.comparison_sha,
180
178
  file_type=file_ref.file_type.value,
@@ -191,7 +189,7 @@ class NoOpFileDiffResolver:
191
189
 
192
190
  def lookup_file_diff(
193
191
  self, file_ref: FileRef
194
- ) -> Tuple[Optional[dict[str, Any]], Optional[dict[str, Any]]]:
192
+ ) -> tuple[dict[str, Any] | None, dict[str, Any] | None]:
195
193
  raise Exception(
196
194
  "NoOpFileDiffResolver is not supposed to be used in "
197
195
  "runtime contexts where lookups are needed"