qontract-reconcile 0.10.2.dev394__py3-none-any.whl → 0.10.2.dev427__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 (316) hide show
  1. {qontract_reconcile-0.10.2.dev394.dist-info → qontract_reconcile-0.10.2.dev427.dist-info}/METADATA +5 -4
  2. {qontract_reconcile-0.10.2.dev394.dist-info → qontract_reconcile-0.10.2.dev427.dist-info}/RECORD +316 -315
  3. reconcile/acs_rbac.py +2 -2
  4. reconcile/aus/advanced_upgrade_service.py +18 -12
  5. reconcile/aus/base.py +117 -18
  6. reconcile/aus/cluster_version_data.py +15 -5
  7. reconcile/aus/models.py +3 -1
  8. reconcile/aus/ocm_addons_upgrade_scheduler_org.py +1 -0
  9. reconcile/aus/ocm_upgrade_scheduler.py +8 -1
  10. reconcile/aus/ocm_upgrade_scheduler_org.py +20 -5
  11. reconcile/aus/version_gates/sts_version_gate_handler.py +54 -1
  12. reconcile/automated_actions/config/integration.py +16 -4
  13. reconcile/aws_account_manager/integration.py +6 -6
  14. reconcile/aws_account_manager/reconciler.py +3 -3
  15. reconcile/aws_ami_cleanup/integration.py +2 -5
  16. reconcile/aws_ami_share.py +69 -62
  17. reconcile/aws_saml_idp/integration.py +5 -3
  18. reconcile/aws_saml_roles/integration.py +23 -22
  19. reconcile/aws_version_sync/integration.py +6 -12
  20. reconcile/change_owners/bundle.py +3 -3
  21. reconcile/change_owners/change_log_tracking.py +3 -2
  22. reconcile/change_owners/change_owners.py +1 -1
  23. reconcile/cli.py +62 -4
  24. reconcile/dashdotdb_dora.py +1 -1
  25. reconcile/dashdotdb_slo.py +1 -1
  26. reconcile/database_access_manager.py +8 -9
  27. reconcile/dynatrace_token_provider/integration.py +1 -1
  28. reconcile/endpoints_discovery/integration.py +4 -1
  29. reconcile/endpoints_discovery/merge_request.py +1 -1
  30. reconcile/endpoints_discovery/merge_request_manager.py +1 -1
  31. reconcile/external_resources/integration.py +1 -1
  32. reconcile/external_resources/manager.py +3 -2
  33. reconcile/external_resources/metrics.py +1 -1
  34. reconcile/external_resources/model.py +13 -13
  35. reconcile/external_resources/reconciler.py +7 -4
  36. reconcile/external_resources/secrets_sync.py +2 -2
  37. reconcile/external_resources/state.py +22 -13
  38. reconcile/fleet_labeler/integration.py +1 -1
  39. reconcile/gcp_image_mirror.py +2 -2
  40. reconcile/github_org.py +1 -1
  41. reconcile/github_owners.py +4 -0
  42. reconcile/gitlab_members.py +6 -12
  43. reconcile/gitlab_permissions.py +8 -12
  44. reconcile/glitchtip_project_alerts/integration.py +3 -1
  45. reconcile/gql_definitions/acs/acs_instances.py +5 -5
  46. reconcile/gql_definitions/acs/acs_policies.py +5 -5
  47. reconcile/gql_definitions/acs/acs_rbac.py +5 -5
  48. reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +5 -5
  49. reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +5 -5
  50. reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +5 -5
  51. reconcile/gql_definitions/app_sre_tekton_access_revalidation/roles.py +5 -5
  52. reconcile/gql_definitions/app_sre_tekton_access_revalidation/users.py +5 -5
  53. reconcile/gql_definitions/automated_actions/instance.py +46 -7
  54. reconcile/gql_definitions/aws_account_manager/aws_accounts.py +5 -5
  55. reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +5 -5
  56. reconcile/gql_definitions/aws_cloudwatch_log_retention/aws_accounts.py +5 -5
  57. reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +5 -5
  58. reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +5 -5
  59. reconcile/gql_definitions/aws_saml_roles/roles.py +5 -5
  60. reconcile/gql_definitions/aws_version_sync/clusters.py +5 -5
  61. reconcile/gql_definitions/aws_version_sync/namespaces.py +5 -5
  62. reconcile/gql_definitions/change_owners/queries/change_types.py +5 -5
  63. reconcile/gql_definitions/change_owners/queries/self_service_roles.py +5 -5
  64. reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +5 -5
  65. reconcile/gql_definitions/common/alerting_services_settings.py +5 -5
  66. reconcile/gql_definitions/common/app_code_component_repos.py +5 -5
  67. reconcile/gql_definitions/common/app_interface_custom_messages.py +5 -5
  68. reconcile/gql_definitions/common/app_interface_dms_settings.py +5 -5
  69. reconcile/gql_definitions/common/app_interface_repo_settings.py +5 -5
  70. reconcile/gql_definitions/common/app_interface_roles.py +5 -5
  71. reconcile/gql_definitions/common/app_interface_state_settings.py +5 -5
  72. reconcile/gql_definitions/common/app_interface_vault_settings.py +5 -5
  73. reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +5 -5
  74. reconcile/gql_definitions/common/apps.py +5 -5
  75. reconcile/gql_definitions/common/aws_vpc_requests.py +5 -5
  76. reconcile/gql_definitions/common/aws_vpcs.py +5 -5
  77. reconcile/gql_definitions/common/clusters.py +5 -5
  78. reconcile/gql_definitions/common/clusters_minimal.py +5 -5
  79. reconcile/gql_definitions/common/clusters_with_dms.py +5 -5
  80. reconcile/gql_definitions/common/clusters_with_peering.py +5 -5
  81. reconcile/gql_definitions/common/github_orgs.py +5 -5
  82. reconcile/gql_definitions/common/jira_settings.py +5 -5
  83. reconcile/gql_definitions/common/jiralert_settings.py +5 -5
  84. reconcile/gql_definitions/common/ldap_settings.py +5 -5
  85. reconcile/gql_definitions/common/namespaces.py +5 -5
  86. reconcile/gql_definitions/common/namespaces_minimal.py +7 -5
  87. reconcile/gql_definitions/common/ocm_env_telemeter.py +5 -5
  88. reconcile/gql_definitions/common/ocm_environments.py +5 -5
  89. reconcile/gql_definitions/common/pagerduty_instances.py +5 -5
  90. reconcile/gql_definitions/common/pgp_reencryption_settings.py +5 -5
  91. reconcile/gql_definitions/common/pipeline_providers.py +5 -5
  92. reconcile/gql_definitions/common/quay_instances.py +5 -5
  93. reconcile/gql_definitions/common/quay_orgs.py +5 -5
  94. reconcile/gql_definitions/common/reserved_networks.py +5 -5
  95. reconcile/gql_definitions/common/rhcs_provider_settings.py +5 -5
  96. reconcile/gql_definitions/common/saas_files.py +5 -5
  97. reconcile/gql_definitions/common/saas_target_namespaces.py +5 -5
  98. reconcile/gql_definitions/common/saasherder_settings.py +5 -5
  99. reconcile/gql_definitions/common/slack_workspaces.py +5 -5
  100. reconcile/gql_definitions/common/smtp_client_settings.py +5 -5
  101. reconcile/gql_definitions/common/state_aws_account.py +5 -5
  102. reconcile/gql_definitions/common/users.py +5 -5
  103. reconcile/gql_definitions/common/users_with_paths.py +5 -5
  104. reconcile/gql_definitions/cost_report/app_names.py +5 -5
  105. reconcile/gql_definitions/cost_report/cost_namespaces.py +5 -5
  106. reconcile/gql_definitions/cost_report/settings.py +5 -5
  107. reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +5 -5
  108. reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +5 -5
  109. reconcile/gql_definitions/dynatrace_token_provider/token_specs.py +5 -5
  110. reconcile/gql_definitions/email_sender/apps.py +5 -5
  111. reconcile/gql_definitions/email_sender/emails.py +5 -5
  112. reconcile/gql_definitions/email_sender/users.py +5 -5
  113. reconcile/gql_definitions/endpoints_discovery/apps.py +5 -5
  114. reconcile/gql_definitions/external_resources/aws_accounts.py +5 -5
  115. reconcile/gql_definitions/external_resources/external_resources_modules.py +5 -5
  116. reconcile/gql_definitions/external_resources/external_resources_namespaces.py +5 -5
  117. reconcile/gql_definitions/external_resources/external_resources_settings.py +5 -5
  118. reconcile/gql_definitions/external_resources/fragments/external_resources_module_overrides.py +5 -5
  119. reconcile/gql_definitions/fleet_labeler/fleet_labels.py +5 -5
  120. reconcile/gql_definitions/fragments/aus_organization.py +5 -5
  121. reconcile/gql_definitions/fragments/aws_account_common.py +5 -5
  122. reconcile/gql_definitions/fragments/aws_account_managed.py +5 -5
  123. reconcile/gql_definitions/fragments/aws_account_sso.py +5 -5
  124. reconcile/gql_definitions/fragments/aws_infra_management_account.py +5 -5
  125. reconcile/gql_definitions/fragments/aws_organization.py +5 -5
  126. reconcile/gql_definitions/fragments/aws_vpc.py +5 -5
  127. reconcile/gql_definitions/fragments/aws_vpc_request.py +5 -5
  128. reconcile/gql_definitions/fragments/container_image_mirror.py +5 -5
  129. reconcile/gql_definitions/fragments/deploy_resources.py +5 -5
  130. reconcile/gql_definitions/fragments/disable.py +5 -5
  131. reconcile/gql_definitions/fragments/email_service.py +5 -5
  132. reconcile/gql_definitions/fragments/email_user.py +5 -5
  133. reconcile/gql_definitions/fragments/jumphost_common_fields.py +5 -5
  134. reconcile/gql_definitions/fragments/membership_source.py +5 -5
  135. reconcile/gql_definitions/fragments/minimal_ocm_organization.py +5 -5
  136. reconcile/gql_definitions/fragments/oc_connection_cluster.py +5 -5
  137. reconcile/gql_definitions/fragments/ocm_environment.py +5 -5
  138. reconcile/gql_definitions/fragments/pipeline_provider_retention.py +5 -5
  139. reconcile/gql_definitions/fragments/prometheus_instance.py +5 -5
  140. reconcile/gql_definitions/fragments/resource_limits_requirements.py +5 -5
  141. reconcile/gql_definitions/fragments/resource_requests_requirements.py +5 -5
  142. reconcile/gql_definitions/fragments/resource_values.py +5 -5
  143. reconcile/gql_definitions/fragments/saas_slo_document.py +5 -5
  144. reconcile/gql_definitions/fragments/saas_target_namespace.py +5 -5
  145. reconcile/gql_definitions/fragments/serviceaccount_token.py +5 -5
  146. reconcile/gql_definitions/fragments/terraform_state.py +5 -5
  147. reconcile/gql_definitions/fragments/upgrade_policy.py +5 -5
  148. reconcile/gql_definitions/fragments/user.py +5 -5
  149. reconcile/gql_definitions/fragments/vault_secret.py +5 -5
  150. reconcile/gql_definitions/gcp/gcp_docker_repos.py +5 -5
  151. reconcile/gql_definitions/gcp/gcp_projects.py +5 -5
  152. reconcile/gql_definitions/gitlab_members/gitlab_instances.py +5 -5
  153. reconcile/gql_definitions/gitlab_members/permissions.py +5 -5
  154. reconcile/gql_definitions/glitchtip/glitchtip_instance.py +5 -5
  155. reconcile/gql_definitions/glitchtip/glitchtip_project.py +5 -5
  156. reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +5 -5
  157. reconcile/gql_definitions/integrations/integrations.py +5 -5
  158. reconcile/gql_definitions/introspection.json +231 -0
  159. reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +5 -5
  160. reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +5 -5
  161. reconcile/gql_definitions/jira/jira_servers.py +5 -5
  162. reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +5 -5
  163. reconcile/gql_definitions/jumphosts/jumphosts.py +5 -5
  164. reconcile/gql_definitions/ldap_groups/roles.py +5 -5
  165. reconcile/gql_definitions/ldap_groups/settings.py +5 -5
  166. reconcile/gql_definitions/maintenance/maintenances.py +5 -5
  167. reconcile/gql_definitions/membershipsources/roles.py +5 -5
  168. reconcile/gql_definitions/ocm_labels/clusters.py +5 -5
  169. reconcile/gql_definitions/ocm_labels/organizations.py +5 -5
  170. reconcile/gql_definitions/openshift_cluster_bots/clusters.py +5 -5
  171. reconcile/gql_definitions/openshift_groups/managed_groups.py +5 -5
  172. reconcile/gql_definitions/openshift_groups/managed_roles.py +5 -5
  173. reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +5 -5
  174. reconcile/gql_definitions/quay_membership/quay_membership.py +5 -5
  175. reconcile/gql_definitions/rhcs/certs.py +24 -79
  176. reconcile/gql_definitions/rhcs/openshift_resource_rhcs_cert.py +42 -0
  177. reconcile/gql_definitions/rhidp/organizations.py +5 -5
  178. reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +5 -5
  179. reconcile/gql_definitions/service_dependencies/service_dependencies.py +5 -5
  180. reconcile/gql_definitions/sharding/aws_accounts.py +5 -5
  181. reconcile/gql_definitions/sharding/ocm_organization.py +5 -5
  182. reconcile/gql_definitions/skupper_network/site_controller_template.py +5 -5
  183. reconcile/gql_definitions/skupper_network/skupper_networks.py +5 -5
  184. reconcile/gql_definitions/slack_usergroups/clusters.py +5 -5
  185. reconcile/gql_definitions/slack_usergroups/permissions.py +5 -5
  186. reconcile/gql_definitions/slack_usergroups/users.py +5 -5
  187. reconcile/gql_definitions/slo_documents/slo_documents.py +5 -5
  188. reconcile/gql_definitions/status_board/status_board.py +5 -5
  189. reconcile/gql_definitions/statuspage/statuspages.py +5 -5
  190. reconcile/gql_definitions/templating/template_collection.py +5 -5
  191. reconcile/gql_definitions/templating/templates.py +5 -5
  192. reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +5 -5
  193. reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +5 -5
  194. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +5 -5
  195. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +5 -5
  196. reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +5 -5
  197. reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +5 -5
  198. reconcile/gql_definitions/terraform_init/aws_accounts.py +5 -5
  199. reconcile/gql_definitions/terraform_repo/terraform_repo.py +5 -5
  200. reconcile/gql_definitions/terraform_resources/database_access_manager.py +5 -5
  201. reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +5 -5
  202. reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +5 -5
  203. reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +5 -5
  204. reconcile/gql_definitions/vault_instances/vault_instances.py +5 -5
  205. reconcile/gql_definitions/vault_policies/vault_policies.py +5 -5
  206. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +5 -5
  207. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +5 -5
  208. reconcile/integrations_manager.py +3 -3
  209. reconcile/jenkins_worker_fleets.py +9 -8
  210. reconcile/jira_permissions_validator.py +2 -2
  211. reconcile/ldap_groups/integration.py +1 -1
  212. reconcile/ocm/types.py +35 -57
  213. reconcile/ocm_aws_infrastructure_access.py +1 -1
  214. reconcile/ocm_clusters.py +4 -4
  215. reconcile/ocm_labels/integration.py +3 -2
  216. reconcile/ocm_machine_pools.py +33 -27
  217. reconcile/openshift_base.py +113 -4
  218. reconcile/openshift_cluster_bots.py +1 -1
  219. reconcile/openshift_namespace_labels.py +1 -1
  220. reconcile/openshift_namespaces.py +97 -101
  221. reconcile/openshift_resources_base.py +6 -2
  222. reconcile/openshift_rhcs_certs.py +27 -29
  223. reconcile/openshift_rolebindings.py +7 -11
  224. reconcile/openshift_saas_deploy.py +4 -5
  225. reconcile/openshift_saas_deploy_change_tester.py +9 -7
  226. reconcile/openshift_serviceaccount_tokens.py +2 -2
  227. reconcile/openshift_upgrade_watcher.py +1 -1
  228. reconcile/oum/labelset.py +5 -3
  229. reconcile/oum/models.py +1 -4
  230. reconcile/prometheus_rules_tester/integration.py +3 -3
  231. reconcile/quay_mirror.py +1 -1
  232. reconcile/queries.py +6 -0
  233. reconcile/rhidp/common.py +3 -5
  234. reconcile/rhidp/sso_client/base.py +16 -5
  235. reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +1 -1
  236. reconcile/skupper_network/integration.py +2 -2
  237. reconcile/slack_usergroups.py +31 -11
  238. reconcile/status_board.py +6 -6
  239. reconcile/statuspage/atlassian.py +7 -7
  240. reconcile/statuspage/page.py +4 -9
  241. reconcile/templating/lib/rendering.py +3 -3
  242. reconcile/templating/renderer.py +2 -2
  243. reconcile/terraform_cloudflare_dns.py +3 -3
  244. reconcile/terraform_cloudflare_resources.py +5 -5
  245. reconcile/terraform_cloudflare_users.py +3 -2
  246. reconcile/terraform_init/integration.py +2 -2
  247. reconcile/terraform_repo.py +16 -12
  248. reconcile/terraform_resources.py +6 -6
  249. reconcile/terraform_tgw_attachments.py +20 -18
  250. reconcile/terraform_vpc_resources/integration.py +3 -1
  251. reconcile/typed_queries/cost_report/app_names.py +1 -1
  252. reconcile/typed_queries/cost_report/cost_namespaces.py +2 -2
  253. reconcile/typed_queries/saas_files.py +11 -11
  254. reconcile/typed_queries/status_board.py +2 -2
  255. reconcile/unleash_feature_toggles/integration.py +4 -2
  256. reconcile/utils/acs/base.py +6 -3
  257. reconcile/utils/acs/policies.py +2 -2
  258. reconcile/utils/aws_api.py +51 -20
  259. reconcile/utils/aws_api_typed/organization.py +4 -2
  260. reconcile/utils/binary.py +7 -12
  261. reconcile/utils/deadmanssnitch_api.py +1 -1
  262. reconcile/utils/early_exit_cache.py +8 -10
  263. reconcile/utils/gitlab_api.py +7 -5
  264. reconcile/utils/glitchtip/client.py +6 -2
  265. reconcile/utils/glitchtip/models.py +25 -28
  266. reconcile/utils/gql.py +4 -7
  267. reconcile/utils/instrumented_wrappers.py +1 -1
  268. reconcile/utils/internal_groups/client.py +2 -2
  269. reconcile/utils/internal_groups/models.py +8 -17
  270. reconcile/utils/jinja2/utils.py +2 -5
  271. reconcile/utils/jobcontroller/controller.py +2 -2
  272. reconcile/utils/jobcontroller/models.py +17 -1
  273. reconcile/utils/json.py +43 -1
  274. reconcile/utils/membershipsources/app_interface_resolver.py +4 -2
  275. reconcile/utils/membershipsources/models.py +16 -23
  276. reconcile/utils/membershipsources/resolver.py +4 -2
  277. reconcile/utils/merge_request_manager/merge_request_manager.py +1 -1
  278. reconcile/utils/merge_request_manager/parser.py +4 -4
  279. reconcile/utils/metrics.py +5 -5
  280. reconcile/utils/models.py +304 -82
  281. reconcile/utils/mr/notificator.py +1 -1
  282. reconcile/utils/mr/user_maintenance.py +3 -2
  283. reconcile/utils/oc.py +246 -201
  284. reconcile/utils/ocm/addons.py +0 -1
  285. reconcile/utils/ocm/base.py +17 -20
  286. reconcile/utils/ocm/cluster_groups.py +1 -1
  287. reconcile/utils/ocm/identity_providers.py +2 -2
  288. reconcile/utils/ocm/labels.py +1 -1
  289. reconcile/utils/ocm/products.py +8 -8
  290. reconcile/utils/ocm/service_log.py +1 -1
  291. reconcile/utils/ocm/sre_capability_labels.py +20 -13
  292. reconcile/utils/openshift_resource.py +5 -0
  293. reconcile/utils/pagerduty_api.py +5 -2
  294. reconcile/utils/promotion_state.py +6 -11
  295. reconcile/utils/raw_github_api.py +1 -1
  296. reconcile/utils/rhcsv2_certs.py +1 -4
  297. reconcile/utils/rosa/session.py +16 -0
  298. reconcile/utils/runtime/integration.py +1 -1
  299. reconcile/utils/saasherder/interfaces.py +13 -20
  300. reconcile/utils/saasherder/models.py +23 -20
  301. reconcile/utils/saasherder/saasherder.py +46 -24
  302. reconcile/utils/slack_api.py +2 -2
  303. reconcile/utils/structs.py +1 -1
  304. reconcile/utils/terraform_client.py +1 -1
  305. reconcile/utils/terrascript_aws_client.py +47 -43
  306. reconcile/utils/unleash/server.py +2 -8
  307. reconcile/utils/vault.py +5 -12
  308. reconcile/utils/vcs.py +8 -8
  309. reconcile/vault_replication.py +1 -1
  310. tools/cli_commands/cost_report/cost_management_api.py +3 -3
  311. tools/cli_commands/cost_report/view.py +7 -6
  312. tools/cli_commands/erv2.py +1 -1
  313. tools/qontract_cli.py +6 -5
  314. tools/template_validation.py +3 -1
  315. {qontract_reconcile-0.10.2.dev394.dist-info → qontract_reconcile-0.10.2.dev427.dist-info}/WHEEL +0 -0
  316. {qontract_reconcile-0.10.2.dev394.dist-info → qontract_reconcile-0.10.2.dev427.dist-info}/entry_points.txt +0 -0
reconcile/ocm/types.py CHANGED
@@ -1,10 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from pydantic import (
4
- BaseModel,
5
- Extra,
6
- Field,
7
- )
3
+ from pydantic import BaseModel, Field, field_validator
8
4
 
9
5
 
10
6
  class OCMClusterAutoscale(BaseModel):
@@ -13,100 +9,82 @@ class OCMClusterAutoscale(BaseModel):
13
9
 
14
10
 
15
11
  class OCMClusterNetwork(BaseModel):
16
- type: str | None
12
+ type: str | None = None
17
13
  vpc: str
18
14
  service: str
19
15
  pod: str
20
16
 
21
17
 
22
- class OCMClusterSpec(BaseModel):
23
- autoscale: OCMClusterAutoscale | None
18
+ class OCMClusterSpec(BaseModel, extra="forbid"):
19
+ autoscale: OCMClusterAutoscale | None = None
24
20
  channel: str
25
- disable_user_workload_monitoring: bool | None
26
- external_id: str | None
27
- id: str | None
28
- instance_type: str | None
29
- multi_az: bool | None
30
- nodes: int | None
21
+ disable_user_workload_monitoring: bool | None = None
22
+ external_id: str | None = None
23
+ id: str | None = None
24
+ instance_type: str | None = None
25
+ multi_az: bool | None = None
26
+ nodes: int | None = None
31
27
  private: bool
32
28
  product: str
33
29
  provider: str
34
- provision_shard_id: str | None
30
+ provision_shard_id: str | None = None
35
31
  region: str
36
- initial_version: str | None
32
+ initial_version: str | None = None
37
33
  version: str
38
- hypershift: bool | None
39
- fips: bool | None
34
+ hypershift: bool | None = None
35
+ fips: bool = False
40
36
 
41
- class Config:
42
- extra = Extra.forbid
37
+ @field_validator("fips", mode="before")
38
+ @classmethod
39
+ def set_fips_default(cls, v: bool | None) -> bool:
40
+ return v or False
43
41
 
44
42
 
45
- class OSDClusterSpec(OCMClusterSpec):
43
+ class OSDClusterSpec(OCMClusterSpec, extra="forbid"):
46
44
  load_balancers: int
47
45
  storage: int
48
46
 
49
- class Config:
50
- extra = Extra.forbid
51
47
 
52
-
53
- class ROSAOcmAwsStsAttrs(BaseModel):
48
+ class ROSAOcmAwsStsAttrs(BaseModel, extra="forbid"):
54
49
  installer_role_arn: str
55
50
  support_role_arn: str
56
- controlplane_role_arn: str | None
51
+ controlplane_role_arn: str | None = None
57
52
  worker_role_arn: str
58
53
 
59
- class Config:
60
- extra = Extra.forbid
61
-
62
54
 
63
- class ROSAOcmAwsAttrs(BaseModel):
55
+ class ROSAOcmAwsAttrs(BaseModel, extra="forbid"):
64
56
  creator_role_arn: str
65
- sts: ROSAOcmAwsStsAttrs | None
66
-
67
- class Config:
68
- extra = Extra.forbid
57
+ sts: ROSAOcmAwsStsAttrs | None = None
69
58
 
70
59
 
71
- class ROSAClusterAWSAccount(BaseModel):
60
+ class ROSAClusterAWSAccount(BaseModel, extra="forbid"):
72
61
  uid: str
73
- rosa: ROSAOcmAwsAttrs | None
74
- billing_account_id: str | None
62
+ rosa: ROSAOcmAwsAttrs | None = None
63
+ billing_account_id: str | None = None
75
64
 
76
- class Config:
77
- extra = Extra.forbid
78
65
 
79
-
80
- class ROSAClusterSpec(OCMClusterSpec):
66
+ class ROSAClusterSpec(OCMClusterSpec, extra="forbid"):
81
67
  account: ROSAClusterAWSAccount
82
- subnet_ids: list[str] | None
83
- availability_zones: list[str] | None
84
- oidc_endpoint_url: str | None
85
-
86
- class Config:
87
- extra = Extra.forbid
68
+ subnet_ids: list[str] | None = None
69
+ availability_zones: list[str] | None = None
70
+ oidc_endpoint_url: str | None = None
88
71
 
89
72
 
90
73
  class ClusterMachinePool(BaseModel):
91
74
  id: str
92
75
  instance_type: str
93
- replicas: int | None
94
- autoscale: OCMClusterAutoscale | None
76
+ replicas: int | None = None
77
+ autoscale: OCMClusterAutoscale | None = None
95
78
 
96
79
 
97
- class OCMSpec(BaseModel):
98
- path: str | None
80
+ class OCMSpec(BaseModel, validate_by_name=True, validate_by_alias=True):
81
+ path: str | None = None
99
82
  spec: OSDClusterSpec | ROSAClusterSpec | OCMClusterSpec
100
83
  machine_pools: list[ClusterMachinePool] = Field(
101
84
  default_factory=list, alias="machinePools"
102
85
  )
103
86
  network: OCMClusterNetwork
104
- domain: str | None
87
+ domain: str | None = None
105
88
  server_url: str = Field("", alias="serverUrl")
106
89
  console_url: str = Field("", alias="consoleUrl")
107
90
  elb_fqdn: str = Field("", alias="elbFQDN")
108
-
109
- class Config:
110
- smart_union = True
111
- # This is need to populate by either console_url or consoleUrl, for instance
112
- allow_population_by_field_name = True
@@ -103,7 +103,7 @@ def fetch_desired_state(clusters: Iterable[Mapping[str, Any]]) -> list[dict[str,
103
103
  namespaces = get_namespaces()
104
104
  for namespace_info in namespaces:
105
105
  specs = get_external_resource_specs(
106
- namespace_info.dict(by_alias=True), provision_provider=PROVIDER_AWS
106
+ namespace_info.model_dump(by_alias=True), provision_provider=PROVIDER_AWS
107
107
  )
108
108
  for spec in specs:
109
109
  if spec.provider != "aws-iam-service-account":
reconcile/ocm_clusters.py CHANGED
@@ -248,13 +248,13 @@ def get_cluster_ocm_update_spec(
248
248
  if not desired_spec.network.type:
249
249
  desired_spec.network.type = "OVNKubernetes"
250
250
 
251
- cspec = current_spec.spec.dict()
252
- cspec[ocmmod.SPEC_ATTR_NETWORK] = current_spec.network.dict(
251
+ cspec = current_spec.spec.model_dump()
252
+ cspec[ocmmod.SPEC_ATTR_NETWORK] = current_spec.network.model_dump(
253
253
  exclude={IGNORE_NETWORK_TYPE_ATTR}
254
254
  )
255
255
 
256
- dspec = desired_spec.spec.dict()
257
- dspec[ocmmod.SPEC_ATTR_NETWORK] = desired_spec.network.dict(
256
+ dspec = desired_spec.spec.model_dump()
257
+ dspec[ocmmod.SPEC_ATTR_NETWORK] = desired_spec.network.model_dump(
258
258
  exclude={IGNORE_NETWORK_TYPE_ATTR}
259
259
  )
260
260
 
@@ -4,7 +4,7 @@ import logging
4
4
  from typing import TYPE_CHECKING, Any
5
5
 
6
6
  from deepdiff import DeepHash
7
- from pydantic import validator
7
+ from pydantic import field_validator
8
8
 
9
9
  from reconcile.aus.aus_label_source import (
10
10
  init_aus_cluster_label_source,
@@ -62,7 +62,8 @@ class OcmLabelsIntegrationParams(PydanticRunParams):
62
62
  managed_label_prefixes: list[str] = []
63
63
  ignored_label_prefixes: list[str] = []
64
64
 
65
- @validator("managed_label_prefixes", "ignored_label_prefixes")
65
+ @field_validator("managed_label_prefixes", "ignored_label_prefixes")
66
+ @classmethod
66
67
  def must_end_with_dot(cls, v: list[str]) -> list[str]:
67
68
  return [prefix + "." if not prefix.endswith(".") else prefix for prefix in v]
68
69
 
@@ -7,11 +7,7 @@ from collections.abc import Iterable, Mapping
7
7
  from enum import Enum
8
8
  from typing import Any, Self
9
9
 
10
- from pydantic import (
11
- BaseModel,
12
- Field,
13
- root_validator,
14
- )
10
+ from pydantic import BaseModel, Field, SerializeAsAny, model_validator
15
11
 
16
12
  from reconcile import queries
17
13
  from reconcile.gql_definitions.common.clusters import (
@@ -22,6 +18,7 @@ from reconcile.gql_definitions.common.clusters import (
22
18
  from reconcile.typed_queries.clusters import get_clusters
23
19
  from reconcile.utils.differ import diff_mappings
24
20
  from reconcile.utils.disabled_integrations import integration_is_enabled
21
+ from reconcile.utils.json import json_dumps
25
22
  from reconcile.utils.ocm import (
26
23
  DEFAULT_OCM_MACHINE_POOL_ID,
27
24
  OCM,
@@ -61,7 +58,8 @@ class MachinePoolAutoscaling(AbstractAutoscaling):
61
58
  min_replicas: int
62
59
  max_replicas: int
63
60
 
64
- @root_validator()
61
+ @model_validator(mode="before")
62
+ @classmethod
65
63
  def max_greater_min(cls, field_values: Mapping[str, Any]) -> Mapping[str, Any]:
66
64
  min_replicas = field_values.get("min_replicas")
67
65
  max_replicas = field_values.get("max_replicas")
@@ -82,7 +80,8 @@ class NodePoolAutoscaling(AbstractAutoscaling):
82
80
  min_replica: int
83
81
  max_replica: int
84
82
 
85
- @root_validator()
83
+ @model_validator(mode="before")
84
+ @classmethod
86
85
  def max_greater_min(cls, field_values: Mapping[str, Any]) -> Mapping[str, Any]:
87
86
  min_replica = field_values.get("min_replica")
88
87
  max_replica = field_values.get("max_replica")
@@ -103,14 +102,15 @@ class AbstractPool(ABC, BaseModel):
103
102
  # Abstract class for machine pools, to be implemented by OSD/HyperShift classes
104
103
 
105
104
  id: str
106
- replicas: int | None
107
- taints: list[Mapping[str, str]] | None
108
- labels: Mapping[str, str] | None
105
+ replicas: int | None = None
106
+ taints: list[Mapping[str, str]] | None = None
107
+ labels: Mapping[str, str] | None = None
109
108
  cluster: str
110
109
  cluster_type: ClusterType = Field(..., exclude=True)
111
- autoscaling: AbstractAutoscaling | None
110
+ autoscaling: SerializeAsAny[AbstractAutoscaling] | None = None
112
111
 
113
- @root_validator()
112
+ @model_validator(mode="before")
113
+ @classmethod
114
114
  def validate_scaling(cls, field_values: Mapping[str, Any]) -> Mapping[str, Any]:
115
115
  if field_values.get("autoscaling") and field_values.get("replicas"):
116
116
  raise ValueError("autoscaling and replicas are mutually exclusive")
@@ -154,13 +154,13 @@ class MachinePool(AbstractPool):
154
154
  instance_type: str
155
155
 
156
156
  def delete(self, ocm: OCM) -> None:
157
- ocm.delete_machine_pool(self.cluster, self.dict(by_alias=True))
157
+ ocm.delete_machine_pool(self.cluster, self.model_dump(by_alias=True))
158
158
 
159
159
  def create(self, ocm: OCM) -> None:
160
- ocm.create_machine_pool(self.cluster, self.dict(by_alias=True))
160
+ ocm.create_machine_pool(self.cluster, self.model_dump(by_alias=True))
161
161
 
162
162
  def update(self, ocm: OCM) -> None:
163
- update_dict = self.dict(by_alias=True)
163
+ update_dict = self.model_dump(by_alias=True)
164
164
  # can not update instance_type
165
165
  del update_dict["instance_type"]
166
166
  if not update_dict["labels"]:
@@ -170,7 +170,10 @@ class MachinePool(AbstractPool):
170
170
  ocm.update_machine_pool(self.cluster, update_dict)
171
171
 
172
172
  def has_diff(self, pool: ClusterMachinePoolV1) -> bool:
173
- if self.taints != pool.taints or self.labels != pool.labels:
173
+ pool_taints = (
174
+ [p.model_dump(by_alias=True) for p in pool.taints] if pool.taints else None
175
+ )
176
+ if self.taints != pool_taints or self.labels != pool.labels:
174
177
  logging.warning(
175
178
  f"updating labels or taints for machine pool {pool.q_id} "
176
179
  f"will only be applied to new Nodes"
@@ -178,7 +181,7 @@ class MachinePool(AbstractPool):
178
181
 
179
182
  return (
180
183
  self.replicas != pool.replicas
181
- or self.taints != pool.taints
184
+ or self.taints != pool_taints
182
185
  or self.labels != pool.labels
183
186
  or self.instance_type != pool.instance_type
184
187
  or self._has_diff_autoscale(pool)
@@ -214,7 +217,7 @@ class MachinePool(AbstractPool):
214
217
  replicas=pool.replicas,
215
218
  autoscaling=autoscaling,
216
219
  instance_type=pool.instance_type,
217
- taints=[p.dict(by_alias=True) for p in pool.taints or []],
220
+ taints=[p.model_dump(by_alias=True) for p in pool.taints or []],
218
221
  labels=pool.labels,
219
222
  cluster=cluster,
220
223
  cluster_type=cluster_type,
@@ -232,14 +235,14 @@ class NodePool(AbstractPool):
232
235
  subnet: str | None
233
236
 
234
237
  def delete(self, ocm: OCM) -> None:
235
- ocm.delete_node_pool(self.cluster, self.dict(by_alias=True))
238
+ ocm.delete_node_pool(self.cluster, self.model_dump(by_alias=True))
236
239
 
237
240
  def create(self, ocm: OCM) -> None:
238
- spec = self.dict(by_alias=True)
241
+ spec = self.model_dump(by_alias=True)
239
242
  ocm.create_node_pool(self.cluster, spec)
240
243
 
241
244
  def update(self, ocm: OCM) -> None:
242
- update_dict = self.dict(by_alias=True)
245
+ update_dict = self.model_dump(by_alias=True)
243
246
  # can not update instance_type
244
247
  del update_dict["aws_node_pool"]
245
248
  # can not update subnet
@@ -251,7 +254,10 @@ class NodePool(AbstractPool):
251
254
  ocm.update_node_pool(self.cluster, update_dict)
252
255
 
253
256
  def has_diff(self, pool: ClusterMachinePoolV1) -> bool:
254
- if self.taints != pool.taints or self.labels != pool.labels:
257
+ pool_taints = (
258
+ [p.model_dump(by_alias=True) for p in pool.taints] if pool.taints else None
259
+ )
260
+ if self.taints != pool_taints or self.labels != pool.labels:
255
261
  logging.warning(
256
262
  f"updating labels or taints for node pool {pool.q_id} "
257
263
  f"will only be applied to new Nodes"
@@ -259,7 +265,7 @@ class NodePool(AbstractPool):
259
265
 
260
266
  return (
261
267
  self.replicas != pool.replicas
262
- or self.taints != pool.taints
268
+ or self.taints != pool_taints
263
269
  or self.labels != pool.labels
264
270
  or self.aws_node_pool.instance_type != pool.instance_type
265
271
  or self.subnet != pool.subnet
@@ -297,7 +303,7 @@ class NodePool(AbstractPool):
297
303
  aws_node_pool=AWSNodePool(
298
304
  instance_type=pool.instance_type,
299
305
  ),
300
- taints=[p.dict(by_alias=True) for p in pool.taints or []],
306
+ taints=[p.model_dump(by_alias=True) for p in pool.taints or []],
301
307
  labels=pool.labels,
302
308
  subnet=pool.subnet,
303
309
  cluster=cluster,
@@ -312,7 +318,7 @@ class PoolHandler(BaseModel):
312
318
  pool: AbstractPool
313
319
 
314
320
  def act(self, dry_run: bool, ocm: OCM) -> None:
315
- logging.info(f"{self.action} {self.pool.dict(by_alias=True)}")
321
+ logging.info(f"{self.action} {self.pool.model_dump(by_alias=True)}")
316
322
  if dry_run:
317
323
  return
318
324
 
@@ -469,7 +475,7 @@ def calculate_diff(
469
475
  if invalid_diff:
470
476
  errors.append(
471
477
  InvalidUpdateError(
472
- f"can not update {invalid_diff} for existing machine pool on cluster {cluster_name}, CURRENT: {diff_pair.current.json()}, DESIRED: {diff_pair.desired.json()}"
478
+ f"can not update {invalid_diff} for existing machine pool on cluster {cluster_name}, CURRENT: {json_dumps(diff_pair.current)}, DESIRED: {json_dumps(diff_pair.desired)}"
473
479
  )
474
480
  )
475
481
  else:
@@ -531,7 +537,7 @@ def run(dry_run: bool) -> None:
531
537
 
532
538
  settings = queries.get_app_interface_settings()
533
539
  cluster_like_objects = [
534
- cluster.dict(by_alias=True) for cluster in filtered_clusters
540
+ cluster.model_dump(by_alias=True) for cluster in filtered_clusters
535
541
  ]
536
542
  ocm_map = OCMMap(
537
543
  clusters=cluster_like_objects,
@@ -29,10 +29,14 @@ from reconcile.utils import (
29
29
  metrics,
30
30
  )
31
31
  from reconcile.utils.constants import DEFAULT_THREAD_POOL_SIZE
32
+ from reconcile.utils.differ import DiffPair
32
33
  from reconcile.utils.oc import (
34
+ POD_RECYCLE_SUPPORTED_OWNER_KINDS,
35
+ AmbiguousResourceTypeError,
33
36
  DeploymentFieldIsImmutableError,
34
37
  FieldIsImmutableError,
35
38
  InvalidValueApplyError,
39
+ KindNotFoundError,
36
40
  MayNotChangeOnceSetError,
37
41
  MetaDataAnnotationsTooLongApplyError,
38
42
  OC_Map,
@@ -60,6 +64,10 @@ AUTH_METHOD_USER_KEY = {
60
64
  "oidc": "org_username",
61
65
  "rhidp": "org_username",
62
66
  }
67
+ RECYCLE_POD_ANNOTATIONS = [
68
+ "kubectl.kubernetes.io/restartedAt",
69
+ "openshift.openshift.io/restartedAt",
70
+ ]
63
71
 
64
72
 
65
73
  class ValidationError(Exception):
@@ -128,6 +136,29 @@ class ClusterMap(Protocol):
128
136
  ) -> list[str]: ...
129
137
 
130
138
 
139
+ def validate_managed_resource_types(
140
+ oc: OCCli,
141
+ managed_resource_types: Iterable[str],
142
+ managed_resource_names: Iterable[Mapping[str, Any]],
143
+ cluster_scope_resource_validation: bool,
144
+ ) -> None:
145
+ """Validate the managed resource types."""
146
+ managed_resources = [
147
+ managed_resource_name["resource"]
148
+ for managed_resource_name in managed_resource_names
149
+ ]
150
+ for managed_resource_type in managed_resource_types:
151
+ # The k8s kind must be supported by the cluster
152
+ resource = oc.get_api_resource(managed_resource_type)
153
+
154
+ if cluster_scope_resource_validation and not resource.namespaced:
155
+ # cluster-scoped resources must be use managedResourceNames!
156
+ if managed_resource_type not in managed_resources:
157
+ raise ValidationError(
158
+ f"Cluster-scoped resource {managed_resource_type} must be managed by name only. Please use 'managedResourceNames' field to specify the names of the resources to manage."
159
+ )
160
+
161
+
131
162
  def init_specs_to_fetch(
132
163
  ri: ResourceInventory,
133
164
  oc_map: ClusterMap,
@@ -136,6 +167,7 @@ def init_specs_to_fetch(
136
167
  override_managed_types: Iterable[str] | None = None,
137
168
  managed_types_key: str = "managedResourceTypes",
138
169
  cluster_admin: bool = False,
170
+ cluster_scope_resource_validation: bool = False,
139
171
  ) -> list[StateSpec]:
140
172
  state_specs: list[StateSpec] = []
141
173
 
@@ -163,9 +195,27 @@ def init_specs_to_fetch(
163
195
  logging.log(level=ex.log_level, msg=ex.message)
164
196
  continue
165
197
 
198
+ managed_resource_names = namespace_info.get("managedResourceNames") or []
199
+ try:
200
+ validate_managed_resource_types(
201
+ oc,
202
+ managed_types,
203
+ managed_resource_names,
204
+ cluster_scope_resource_validation=cluster_scope_resource_validation,
205
+ )
206
+ except KindNotFoundError:
207
+ # We must allow kinds that are not supported by the cluster because:
208
+ # 1. We install CRD with an operator in the same MR
209
+ # 2. SAAS files initialize the namespace objects with managedResourceTypes from the SAAS file
210
+ # and we can't expect that all of those are valid for all clusters
211
+ pass
212
+ except (AmbiguousResourceTypeError, ValidationError) as e:
213
+ ri.register_error()
214
+ logging.error(f"[{cluster}/{namespace_info['name']}] {e}")
215
+ continue
216
+
166
217
  namespace = namespace_info["name"]
167
218
  # These may exit but have a value of None
168
- managed_resource_names = namespace_info.get("managedResourceNames") or []
169
219
  managed_resource_type_overrides = (
170
220
  namespace_info.get("managedResourceTypeOverrides") or []
171
221
  )
@@ -340,6 +390,7 @@ def fetch_current_state(
340
390
  cluster_admin: bool = False,
341
391
  caller: str | None = None,
342
392
  init_projects: bool = False,
393
+ cluster_scope_resource_validation: bool = False,
343
394
  ) -> tuple[ResourceInventory, OC_Map]:
344
395
  ri = ResourceInventory()
345
396
  settings = queries.get_app_interface_settings()
@@ -362,6 +413,7 @@ def fetch_current_state(
362
413
  clusters=clusters,
363
414
  override_managed_types=override_managed_types,
364
415
  cluster_admin=cluster_admin,
416
+ cluster_scope_resource_validation=cluster_scope_resource_validation,
365
417
  )
366
418
  threaded.run(
367
419
  populate_current_state,
@@ -542,7 +594,7 @@ def apply(
542
594
  oc.resize_pvcs(namespace, owned_pvc_names, desired_storage)
543
595
 
544
596
  if recycle_pods:
545
- oc.recycle_pods(dry_run, namespace, resource_type, resource)
597
+ oc.recycle_pods(dry_run, namespace, resource)
546
598
 
547
599
 
548
600
  def create(
@@ -786,10 +838,56 @@ def handle_identical_resources(
786
838
  return actions
787
839
 
788
840
 
841
+ def patch_desired_resource_for_recycle_annotations(
842
+ desired: OR,
843
+ current: OR,
844
+ ) -> OR:
845
+ """
846
+ Patch desired resource with recycle annotations to pod template from current resource.
847
+ This is to avoid full pods recycle when changes are not affecting pod template.
848
+ Note desired annotations can override current annotations.
849
+ For example, if desired resource has kubectl.kubernetes.io/restartedAt defined,
850
+ it will be used instead of current resource annotation.
851
+
852
+ Args:
853
+ desired: desired resource
854
+ current: current resource
855
+
856
+ Returns:
857
+ patched desired resource
858
+ """
859
+ if current.kind not in POD_RECYCLE_SUPPORTED_OWNER_KINDS:
860
+ return desired
861
+
862
+ current_annotations = (
863
+ current.body.get("spec", {})
864
+ .get("template", {})
865
+ .get("metadata", {})
866
+ .get("annotations")
867
+ or {}
868
+ )
869
+ patch_annotations = {
870
+ k: value
871
+ for k in RECYCLE_POD_ANNOTATIONS
872
+ if (value := current_annotations.get(k))
873
+ }
874
+ if patch_annotations:
875
+ desired_annotations = (
876
+ desired.body.setdefault("spec", {})
877
+ .setdefault("template", {})
878
+ .setdefault("metadata", {})
879
+ .setdefault("annotations", {})
880
+ )
881
+ desired.body["spec"]["template"]["metadata"]["annotations"] = (
882
+ patch_annotations | desired_annotations
883
+ )
884
+ return desired
885
+
886
+
789
887
  def handle_modified_resources(
790
888
  oc_map: ClusterMap,
791
889
  ri: ResourceInventory,
792
- modified_resources: Mapping[Any, Any],
890
+ modified_resources: Mapping[str, DiffPair[OR, OR]],
793
891
  cluster: str,
794
892
  namespace: str,
795
893
  resource_type: str,
@@ -985,6 +1083,12 @@ def _realize_resource_data_3way_diff(
985
1083
  if options.enable_deletion and options.override_enable_deletion is False:
986
1084
  options.enable_deletion = False
987
1085
 
1086
+ for k in data["current"].keys() & data["desired"].keys():
1087
+ patch_desired_resource_for_recycle_annotations(
1088
+ desired=data["desired"][k],
1089
+ current=data["current"][k],
1090
+ )
1091
+
988
1092
  diff_result = differ.diff_mappings(
989
1093
  data["current"], data["desired"], equal=three_way_diff_using_hash
990
1094
  )
@@ -1363,6 +1467,11 @@ class HasOpenShiftResources(Protocol):
1363
1467
  openshift_resources: list | None
1364
1468
 
1365
1469
 
1470
+ @runtime_checkable
1471
+ class HasOpenShiftResourcesRequired(Protocol):
1472
+ openshift_resources: list
1473
+
1474
+
1366
1475
  @runtime_checkable
1367
1476
  class HasOpenshiftServiceAccountTokens(Protocol):
1368
1477
  openshift_service_account_tokens: list | None
@@ -1371,7 +1480,7 @@ class HasOpenshiftServiceAccountTokens(Protocol):
1371
1480
  @runtime_checkable
1372
1481
  class HasSharedResourcesOpenShiftResources(Protocol):
1373
1482
  @property
1374
- def shared_resources(self) -> Sequence[HasOpenShiftResources] | None: ...
1483
+ def shared_resources(self) -> Sequence[HasOpenShiftResourcesRequired] | None: ...
1375
1484
 
1376
1485
 
1377
1486
  @runtime_checkable
@@ -301,7 +301,7 @@ def filter_clusters(clusters: list[ClusterV1]) -> list[ClusterV1]:
301
301
 
302
302
  def get_ocm_map(clusters: list[ClusterV1]) -> OCMMap:
303
303
  settings = queries.get_app_interface_settings()
304
- clusters_info = [c.dict(by_alias=True) for c in clusters]
304
+ clusters_info = [c.model_dump(by_alias=True) for c in clusters]
305
305
  return OCMMap(
306
306
  settings=settings,
307
307
  clusters=clusters_info,
@@ -229,7 +229,7 @@ def get_gql_namespaces_in_shard() -> list[NamespaceV1]:
229
229
  return [
230
230
  ns
231
231
  for ns in all_namespaces
232
- if not ob.is_namespace_deleted(ns.dict(by_alias=True))
232
+ if not ob.is_namespace_deleted(ns.model_dump(by_alias=True))
233
233
  and is_in_shard(f"{ns.cluster.name}/{ns.name}")
234
234
  ]
235
235