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
@@ -92,8 +92,7 @@ from reconcile.utils.state import State
92
92
  from reconcile.utils.vcs import VCS
93
93
 
94
94
  TARGET_CONFIG_HASH = "target_config_hash"
95
-
96
-
95
+ TEMPLATE_API_VERSION = "template.openshift.io/v1"
97
96
  UNIQUE_SAAS_FILE_ENV_COMBO_LEN = 56
98
97
  REQUEST_TIMEOUT = 60
99
98
 
@@ -765,7 +764,8 @@ class SaasHerder:
765
764
  case "gitlab":
766
765
  if not self.gitlab:
767
766
  raise Exception("gitlab is not initialized")
768
- project = self.gitlab.get_project(url)
767
+ if not (project := self.gitlab.get_project(url)):
768
+ raise Exception(f"Could not find gitlab project for {url}")
769
769
  content = self.gitlab.get_raw_file(
770
770
  project=project,
771
771
  path=path,
@@ -801,7 +801,8 @@ class SaasHerder:
801
801
  case "gitlab":
802
802
  if not self.gitlab:
803
803
  raise Exception("gitlab is not initialized")
804
- project = self.gitlab.get_project(url)
804
+ if not (project := self.gitlab.get_project(url)):
805
+ raise Exception(f"Could not find gitlab project for {url}")
805
806
  dir_contents = self.gitlab.get_directory_contents(
806
807
  project,
807
808
  ref=commit_sha,
@@ -826,7 +827,8 @@ class SaasHerder:
826
827
  case "gitlab":
827
828
  if not self.gitlab:
828
829
  raise Exception("gitlab is not initialized")
829
- project = self.gitlab.get_project(url)
830
+ if not (project := self.gitlab.get_project(url)):
831
+ raise Exception(f"Could not find gitlab project for {url}")
830
832
  commits = project.commits.list(ref_name=ref, per_page=1, page=1)
831
833
  return commits[0].id
832
834
  case _:
@@ -871,10 +873,23 @@ class SaasHerder:
871
873
  """
872
874
  if parameter_name in consolidated_parameters:
873
875
  return False
874
- for template_parameter in template.get("parameters", {}):
875
- if template_parameter["name"] == parameter_name:
876
- return True
877
- return False
876
+ return any(
877
+ template_parameter["name"] == parameter_name
878
+ for template_parameter in template.get("parameters") or []
879
+ )
880
+
881
+ @staticmethod
882
+ def _pre_process_template(template: dict[str, Any]) -> dict[str, Any]:
883
+ """
884
+ The only supported apiVersion for OpenShift Template is "template.openshift.io/v1".
885
+ There are examples of templates using "v1", it can't pass validation on 4.19+ oc versions.
886
+
887
+ Args:
888
+ template (dict): The OpenShift template dictionary.
889
+ Returns:
890
+ dict: The OpenShift template dictionary with the correct apiVersion.
891
+ """
892
+ return template | {"apiVersion": TEMPLATE_API_VERSION}
878
893
 
879
894
  def _process_template(
880
895
  self, spec: TargetSpec
@@ -964,7 +979,8 @@ class SaasHerder:
964
979
  oc = OCLocal("cluster", None, None, local=True)
965
980
  try:
966
981
  resources: Iterable[Mapping[str, Any]] = oc.process(
967
- template, consolidated_parameters
982
+ template=self._pre_process_template(template),
983
+ parameters=consolidated_parameters,
968
984
  )
969
985
  except StatusCodeError as e:
970
986
  logging.error(f"{error_prefix} error processing template: {e!s}")
@@ -1179,13 +1195,13 @@ class SaasHerder:
1179
1195
  images_list = threaded.run(
1180
1196
  self._collect_images, resources, self.available_thread_pool_size
1181
1197
  )
1182
- images = set(itertools.chain.from_iterable(images_list))
1183
- self.images.update(images)
1184
- if not images:
1198
+ images_set = set(itertools.chain.from_iterable(images_list))
1199
+ self.images.update(images_set)
1200
+ if not images_set:
1185
1201
  return False # no errors
1186
1202
  images = threaded.run(
1187
1203
  self._get_image,
1188
- images,
1204
+ images_set,
1189
1205
  self.available_thread_pool_size,
1190
1206
  image_patterns=spec.image_patterns,
1191
1207
  image_auth=spec.image_auth,
@@ -1250,7 +1266,9 @@ class SaasHerder:
1250
1266
  self.saas_files,
1251
1267
  self.thread_pool_size,
1252
1268
  )
1253
- desired_state_specs = list(itertools.chain.from_iterable(results))
1269
+ desired_state_specs: list[TargetSpec] = list(
1270
+ itertools.chain.from_iterable(results)
1271
+ )
1254
1272
  promotions = threaded.run(
1255
1273
  self.populate_desired_state_saas_file,
1256
1274
  desired_state_specs,
@@ -1898,21 +1916,23 @@ class SaasHerder:
1898
1916
  name=target.name,
1899
1917
  ref=target.ref,
1900
1918
  promotion=(
1901
- target.promotion.dict(by_alias=True) if target.promotion else None
1919
+ target.promotion.model_dump(by_alias=True) if target.promotion else None
1902
1920
  ),
1903
1921
  secretParameters=(
1904
- [p.dict(by_alias=True) for p in target.secret_parameters]
1922
+ [p.model_dump(by_alias=True) for p in target.secret_parameters]
1905
1923
  if target.secret_parameters
1906
1924
  else None
1907
1925
  ),
1908
1926
  slos=(
1909
- [slo.dict(by_alias=True) for slo in target.slos]
1927
+ [slo.model_dump(by_alias=True) for slo in target.slos]
1910
1928
  if target.slos
1911
1929
  else None
1912
1930
  ),
1913
- upstream=(target.upstream.dict(by_alias=True) if target.upstream else None),
1931
+ upstream=(
1932
+ target.upstream.model_dump(by_alias=True) if target.upstream else None
1933
+ ),
1914
1934
  images=(
1915
- [i.dict(by_alias=True) for i in target.images]
1935
+ [i.model_dump(by_alias=True) for i in target.images]
1916
1936
  if target.images
1917
1937
  else None
1918
1938
  ),
@@ -1948,16 +1968,16 @@ class SaasHerder:
1948
1968
  )
1949
1969
  if saas_file.managed_resource_names:
1950
1970
  state_content["saas_file_managed_resource_names"] = [
1951
- m.dict() for m in saas_file.managed_resource_names
1971
+ m.model_dump() for m in saas_file.managed_resource_names
1952
1972
  ]
1953
1973
  # include secret parameters from resource template and saas file
1954
1974
  if resource_template.secret_parameters:
1955
1975
  state_content["rt_secretparameters"] = [
1956
- p.dict() for p in resource_template.secret_parameters
1976
+ p.model_dump() for p in resource_template.secret_parameters
1957
1977
  ]
1958
1978
  if saas_file.secret_parameters:
1959
1979
  state_content["saas_file_secretparameters"] = [
1960
- p.dict() for p in saas_file.secret_parameters
1980
+ p.model_dump() for p in saas_file.secret_parameters
1961
1981
  ]
1962
1982
  return state_content
1963
1983
 
@@ -2240,7 +2260,9 @@ class SaasHerder:
2240
2260
  for rt in saas_file.resource_templates:
2241
2261
  for target in rt.targets:
2242
2262
  template_vars = {
2243
- "resource": {"namespace": target.namespace.dict(by_alias=True)}
2263
+ "resource": {
2264
+ "namespace": target.namespace.model_dump(by_alias=True)
2265
+ }
2244
2266
  }
2245
2267
  if target.parameters:
2246
2268
  for param in target.parameters:
@@ -71,14 +71,14 @@ class HasClientGlobalConfig(Protocol):
71
71
  max_retries: int | None
72
72
  timeout: int | None
73
73
 
74
- def dict(self) -> dict[str, int | None]: ...
74
+ def model_dump(self) -> dict[str, int | None]: ...
75
75
 
76
76
 
77
77
  class HasClientMethodConfig(Protocol):
78
78
  name: str
79
79
  args: Any
80
80
 
81
- def dict(self) -> dict[str, str]: ...
81
+ def model_dump(self) -> dict[str, str]: ...
82
82
 
83
83
 
84
84
  class HasClientConfig(Protocol):
@@ -1,4 +1,4 @@
1
- from pydantic.dataclasses import dataclass
1
+ from dataclasses import dataclass
2
2
 
3
3
 
4
4
  @dataclass
@@ -223,7 +223,7 @@ class TerraformClient:
223
223
  if disable_deletions_detected:
224
224
  raise RuntimeError("Terraform plan has disabled deletions detected")
225
225
 
226
- @retry(no_retry_exceptions=RdsUpgradeValidationError)
226
+ @retry(no_retry_exceptions=(RdsUpgradeValidationError,))
227
227
  def terraform_plan(
228
228
  self, spec: TerraformSpec, enable_deletion: bool
229
229
  ) -> tuple[bool, list[AccountUser], bool]:
@@ -1058,7 +1058,9 @@ class TerrascriptClient:
1058
1058
  ignore_changes = (
1059
1059
  "all" if "all" in lifecycle.ignore_changes else lifecycle.ignore_changes
1060
1060
  )
1061
- return lifecycle.dict(by_alias=True) | {"ignore_changes": ignore_changes}
1061
+ return lifecycle.model_dump(by_alias=True) | {
1062
+ "ignore_changes": ignore_changes
1063
+ }
1062
1064
  return None
1063
1065
 
1064
1066
  def populate_additional_providers(
@@ -1424,7 +1426,7 @@ class TerrascriptClient:
1424
1426
  req_account_name = req_account.name
1425
1427
  # Accepter's side of the connection - the cluster's account
1426
1428
  acc_account = accepter.account
1427
- acc_alias = self.get_provider_alias(acc_account.dict(by_alias=True))
1429
+ acc_alias = self.get_provider_alias(acc_account.model_dump(by_alias=True))
1428
1430
  acc_uid = acc_account.uid
1429
1431
  if acc_account.assume_role:
1430
1432
  acc_uid = awsh.get_account_uid_from_arn(acc_account.assume_role)
@@ -2210,6 +2212,43 @@ class TerrascriptClient:
2210
2212
  letters_and_digits = string.ascii_letters + string.digits
2211
2213
  return "".join(random.choice(letters_and_digits) for i in range(string_length))
2212
2214
 
2215
+ @staticmethod
2216
+ def _build_tf_resource_s3_lifecycle_rules(
2217
+ versioning: bool,
2218
+ common_values: Mapping[str, Any],
2219
+ ) -> list[dict]:
2220
+ lifecycle_rules = common_values.get("lifecycle_rules") or []
2221
+ if versioning and not any(
2222
+ "noncurrent_version_expiration" in lr for lr in lifecycle_rules
2223
+ ):
2224
+ # Add a default noncurrent object expiration rule
2225
+ # if one isn't already set
2226
+ rule = {
2227
+ "id": "expire_noncurrent_versions",
2228
+ "enabled": True,
2229
+ "noncurrent_version_expiration": {"days": 30},
2230
+ "expiration": {"expired_object_delete_marker": True},
2231
+ "abort_incomplete_multipart_upload_days": 3,
2232
+ }
2233
+ lifecycle_rules.append(rule)
2234
+
2235
+ if storage_class := common_values.get("storage_class"):
2236
+ sc = storage_class.upper()
2237
+ days = "1"
2238
+ if sc.endswith("_IA"):
2239
+ # Infrequent Access storage class has minimum 30 days
2240
+ # before transition
2241
+ days = "30"
2242
+ rule = {
2243
+ "id": sc + "_storage_class",
2244
+ "enabled": True,
2245
+ "transition": {"days": days, "storage_class": sc},
2246
+ "noncurrent_version_transition": {"days": days, "storage_class": sc},
2247
+ }
2248
+ lifecycle_rules.append(rule)
2249
+
2250
+ return lifecycle_rules
2251
+
2213
2252
  def populate_tf_resource_s3(self, spec: ExternalResourceSpec) -> aws_s3_bucket:
2214
2253
  account = spec.provisioner_name
2215
2254
  identifier = spec.identifier
@@ -2249,47 +2288,11 @@ class TerrascriptClient:
2249
2288
  request_payer = common_values.get("request_payer")
2250
2289
  if request_payer:
2251
2290
  values["request_payer"] = request_payer
2252
- lifecycle_rules = common_values.get("lifecycle_rules")
2253
- if lifecycle_rules:
2254
- # common_values['lifecycle_rules'] is a list of lifecycle_rules
2291
+ if lifecycle_rules := self._build_tf_resource_s3_lifecycle_rules(
2292
+ versioning=versioning,
2293
+ common_values=common_values,
2294
+ ):
2255
2295
  values["lifecycle_rule"] = lifecycle_rules
2256
- if versioning:
2257
- lrs = values.get("lifecycle_rule", [])
2258
- expiration_rule = False
2259
- for lr in lrs:
2260
- if "noncurrent_version_expiration" in lr:
2261
- expiration_rule = True
2262
- break
2263
- if not expiration_rule:
2264
- # Add a default noncurrent object expiration rule if
2265
- # if one isn't already set
2266
- rule = {
2267
- "id": "expire_noncurrent_versions",
2268
- "enabled": "true",
2269
- "noncurrent_version_expiration": {"days": 30},
2270
- }
2271
- if len(lrs) > 0:
2272
- lrs.append(rule)
2273
- else:
2274
- lrs = rule
2275
- sc = common_values.get("storage_class")
2276
- if sc:
2277
- sc = sc.upper()
2278
- days = "1"
2279
- if sc.endswith("_IA"):
2280
- # Infrequent Access storage class has minimum 30 days
2281
- # before transition
2282
- days = "30"
2283
- rule = {
2284
- "id": sc + "_storage_class",
2285
- "enabled": "true",
2286
- "transition": {"days": days, "storage_class": sc},
2287
- "noncurrent_version_transition": {"days": days, "storage_class": sc},
2288
- }
2289
- if values.get("lifecycle_rule"):
2290
- values["lifecycle_rule"].append(rule)
2291
- else:
2292
- values["lifecycle_rule"] = rule
2293
2296
  cors_rules = common_values.get("cors_rules")
2294
2297
  if cors_rules:
2295
2298
  # common_values['cors_rules'] is a list of cors_rules
@@ -5907,7 +5910,8 @@ class TerrascriptClient:
5907
5910
  return commit.sha
5908
5911
  case "gitlab":
5909
5912
  gitlab = self.init_gitlab()
5910
- project = gitlab.get_project(url)
5913
+ if not (project := gitlab.get_project(url)):
5914
+ raise ValueError(f"could not find gitlab project for url {url}")
5911
5915
  commits = project.commits.list(ref_name=ref, per_page=1, page=1)
5912
5916
  return commits[0].id
5913
5917
  case _:
@@ -24,30 +24,24 @@ class Environment(BaseModel):
24
24
  return self.name == other
25
25
 
26
26
 
27
- class FeatureToggle(BaseModel):
27
+ class FeatureToggle(BaseModel, validate_by_name=True, validate_by_alias=True):
28
28
  name: str
29
29
  type: FeatureToggleType = FeatureToggleType.release
30
30
  description: str | None = None
31
31
  impression_data: bool = Field(False, alias="impressionData")
32
32
  environments: list[Environment]
33
33
 
34
- class Config:
35
- allow_population_by_field_name = True
36
-
37
34
  def __eq__(self, other: object) -> bool:
38
35
  if isinstance(other, FeatureToggle):
39
36
  return self.name == other.name
40
37
  return self.name == other
41
38
 
42
39
 
43
- class Project(BaseModel):
40
+ class Project(BaseModel, validate_by_name=True, validate_by_alias=True):
44
41
  pk: str = Field(alias="id")
45
42
  name: str
46
43
  feature_toggles: list[FeatureToggle] = []
47
44
 
48
- class Config:
49
- allow_population_by_field_name = True
50
-
51
45
 
52
46
  class TokenAuth(BearerTokenAuth):
53
47
  def __call__(self, r: requests.PreparedRequest) -> requests.PreparedRequest:
reconcile/utils/vault.py CHANGED
@@ -6,7 +6,7 @@ import threading
6
6
  import time
7
7
  from collections.abc import Mapping
8
8
  from functools import lru_cache
9
- from typing import Any, Self, TypedDict
9
+ from typing import Any, Self
10
10
 
11
11
  import hvac
12
12
  import requests
@@ -48,13 +48,6 @@ class VaultConnectionError(Exception):
48
48
  pass
49
49
 
50
50
 
51
- class Secret(TypedDict):
52
- path: str
53
- field: str
54
- format: str | None
55
- version: str | None
56
-
57
-
58
51
  SECRET_VERSION_LATEST = "LATEST"
59
52
 
60
53
 
@@ -197,7 +190,7 @@ class VaultClient:
197
190
  self._client.auth_approle(self.role_id, self.secret_id)
198
191
 
199
192
  @retry()
200
- def read_all_with_version(self, secret: Mapping) -> tuple[Mapping, str | None]:
193
+ def read_all_with_version(self, secret: Mapping) -> tuple[dict, int | None]:
201
194
  """Returns a dictionary of keys and values in a Vault secret and the
202
195
  version of the secret, for V1 secrets, version will be None.
203
196
 
@@ -207,7 +200,7 @@ class VaultClient:
207
200
  a v2 KV engine)
208
201
  """
209
202
  secret_path = secret["path"]
210
- secret_version = secret.get("version", SECRET_VERSION_LATEST)
203
+ secret_version = secret.get("version") or SECRET_VERSION_LATEST
211
204
 
212
205
  kv_version = self._get_mount_version_by_secret_path(secret_path)
213
206
 
@@ -250,7 +243,7 @@ class VaultClient:
250
243
 
251
244
  def __read_all_v2(
252
245
  self, path: str, version: str | None
253
- ) -> tuple[dict[str, Any], str | None]:
246
+ ) -> tuple[dict[str, Any], int]:
254
247
  path_split = path.split("/")
255
248
  mount_point = path_split[0]
256
249
  read_path = "/".join(path_split[1:])
@@ -294,7 +287,7 @@ class VaultClient:
294
287
  return secret["data"]
295
288
 
296
289
  @retry()
297
- def read(self, secret: Secret) -> Any:
290
+ def read(self, secret: Mapping[str, Any]) -> Any:
298
291
  """Returns a value of a key in a Vault secret.
299
292
 
300
293
  The input secret is a dictionary which contains the following fields:
reconcile/utils/vcs.py CHANGED
@@ -140,7 +140,7 @@ class VCS:
140
140
  gitlab_instances: Iterable[GitlabInstanceV1],
141
141
  ) -> GitLabApi:
142
142
  return GitLabApi(
143
- next(iter(gitlab_instances)).dict(by_alias=True),
143
+ next(iter(gitlab_instances)).model_dump(by_alias=True),
144
144
  secret_reader=self._secret_reader,
145
145
  )
146
146
 
@@ -150,7 +150,7 @@ class VCS:
150
150
  app_interface_repo_url: str,
151
151
  ) -> GitLabApi:
152
152
  return GitLabApi(
153
- next(iter(gitlab_instances)).dict(by_alias=True),
153
+ next(iter(gitlab_instances)).model_dump(by_alias=True),
154
154
  secret_reader=self._secret_reader,
155
155
  project_url=app_interface_repo_url,
156
156
  )
@@ -221,26 +221,26 @@ class VCS:
221
221
  match repo_info.platform:
222
222
  case "github":
223
223
  github = self._init_github(repo_url=repo_url, auth_code=auth_code)
224
- data = github.compare(commit_from=commit_from, commit_to=commit_to)
225
224
  return [
226
225
  Commit(
227
226
  repo=repo_url,
228
227
  sha=gh_commit.sha,
229
228
  date=gh_commit.commit.committer.date,
230
229
  )
231
- for gh_commit in data
230
+ for gh_commit in github.compare(
231
+ commit_from=commit_from, commit_to=commit_to
232
+ )
232
233
  ]
233
234
  case "gitlab":
234
- data = self._gitlab_instance.repository_compare(
235
- repo_url=repo_url, ref_from=commit_from, ref_to=commit_to
236
- )
237
235
  return [
238
236
  Commit(
239
237
  repo=repo_url,
240
238
  sha=gl_commit["id"],
241
239
  date=datetime.fromisoformat(gl_commit["committed_date"]),
242
240
  )
243
- for gl_commit in data
241
+ for gl_commit in self._gitlab_instance.repository_compare(
242
+ repo_url=repo_url, ref_from=commit_from, ref_to=commit_to
243
+ )
244
244
  ]
245
245
  case _:
246
246
  raise ValueError(f"Unsupported repository URL: {repo_url}")
@@ -217,7 +217,7 @@ def copy_vault_secret(
217
217
  return
218
218
 
219
219
  # If we reach here, we successfully read the destination secret
220
- if dest_version is None and version is None:
220
+ if dest_version is None or version is None:
221
221
  # v1 secrets don't have version
222
222
  if source_data == dest_data:
223
223
  # If the secret is the same in both vaults, we don't need
@@ -74,7 +74,7 @@ class CostManagementApi(ApiBase):
74
74
  timeout=self.read_timeout,
75
75
  )
76
76
  response.raise_for_status()
77
- return AwsReportCostResponse.parse_obj(response.json())
77
+ return AwsReportCostResponse.model_validate(response.json())
78
78
 
79
79
  def get_openshift_costs_report(
80
80
  self,
@@ -97,7 +97,7 @@ class CostManagementApi(ApiBase):
97
97
  timeout=self.read_timeout,
98
98
  )
99
99
  response.raise_for_status()
100
- return OpenShiftReportCostResponse.parse_obj(response.json())
100
+ return OpenShiftReportCostResponse.model_validate(response.json())
101
101
 
102
102
  def get_openshift_cost_optimization_report(
103
103
  self,
@@ -120,7 +120,7 @@ class CostManagementApi(ApiBase):
120
120
  response.raise_for_status()
121
121
 
122
122
  data = self._get_paginated(response)
123
- return OpenShiftCostOptimizationReportResponse.parse_obj(data)
123
+ return OpenShiftCostOptimizationReportResponse.model_validate(data)
124
124
 
125
125
  def _get_paginated(
126
126
  self,
@@ -4,6 +4,7 @@ from typing import Any
4
4
 
5
5
  from pydantic import BaseModel
6
6
 
7
+ from reconcile.utils.json import json_dumps
7
8
  from tools.cli_commands.cost_report.model import OptimizationReport, Report
8
9
 
9
10
  LAYOUT = """\
@@ -244,7 +245,7 @@ def render_summary(
244
245
  return template.format(
245
246
  date=get_date(reports),
246
247
  total_cost=format_cost_value(total_cost),
247
- json_table=json_table.json(indent=2),
248
+ json_table=json_dumps(json_table, indent=2, mode="python"),
248
249
  )
249
250
 
250
251
 
@@ -274,7 +275,7 @@ def render_month_over_month_change(reports: Mapping[str, Report]) -> str:
274
275
  )
275
276
  return MONTH_OVER_MONTH_CHANGE.format(
276
277
  date=get_date(reports),
277
- json_table=json_table.json(indent=2),
278
+ json_table=json_dumps(json_table, indent=2, mode="python"),
278
279
  )
279
280
 
280
281
 
@@ -304,7 +305,7 @@ def render_aws_services_cost(
304
305
  items_total=format_cost_value(report.items_total),
305
306
  items_delta_value=format_delta_value(report.items_delta_value),
306
307
  items_delta_percent=format_delta_percent(report.items_delta_percent),
307
- json_table=json_table.json(indent=2),
308
+ json_table=json_dumps(json_table, indent=2, mode="python"),
308
309
  )
309
310
 
310
311
 
@@ -316,7 +317,7 @@ def render_openshift_workloads_cost(
316
317
  items_total=format_cost_value(report.items_total),
317
318
  items_delta_value=format_delta_value(report.items_delta_value),
318
319
  items_delta_percent=format_delta_percent(report.items_delta_percent),
319
- json_table=json_table.json(indent=2),
320
+ json_table=json_dumps(json_table, indent=2, mode="python"),
320
321
  )
321
322
 
322
323
 
@@ -362,7 +363,7 @@ def render_child_apps_cost(report: Report) -> str:
362
363
  )
363
364
  return CHILD_APPS_COST.format(
364
365
  child_apps_total=format_cost_value(report.child_apps_total),
365
- json_table=json_table.json(indent=2),
366
+ json_table=json_dumps(json_table, indent=2, mode="python"),
366
367
  )
367
368
 
368
369
 
@@ -509,7 +510,7 @@ def render_optimization(
509
510
  )
510
511
  return OPTIMIZATION.format(
511
512
  app_name=report.app_name,
512
- json_table=json_table.json(indent=2),
513
+ json_table=json_dumps(json_table, indent=2, mode="python"),
513
514
  )
514
515
 
515
516
 
@@ -133,7 +133,7 @@ class Erv2Cli:
133
133
 
134
134
  @property
135
135
  def input_data(self) -> str:
136
- return self._resource.json(exclude={"data": {FLAG_RESOURCE_MANAGED_BY_ERV2}})
136
+ return self._resource.export(exclude={"data": {FLAG_RESOURCE_MANAGED_BY_ERV2}})
137
137
 
138
138
  @property
139
139
  def image(self) -> str:
tools/qontract_cli.py CHANGED
@@ -141,6 +141,7 @@ from reconcile.utils.gitlab_api import (
141
141
  )
142
142
  from reconcile.utils.glitchtip.client import GlitchtipClient
143
143
  from reconcile.utils.gql import GqlApiSingleton
144
+ from reconcile.utils.json import json_dumps
144
145
  from reconcile.utils.keycloak import (
145
146
  KeycloakAPI,
146
147
  SSOClient,
@@ -1566,7 +1567,7 @@ def rosa_create_cluster_command(ctx: click.Context, cluster_name: str) -> None:
1566
1567
  billing_account = account.billing_account.uid
1567
1568
  else:
1568
1569
  with AWSApi(
1569
- 1, [account.dict(by_alias=True)], settings=settings, init_users=False
1570
+ 1, [account.model_dump(by_alias=True)], settings=settings, init_users=False
1570
1571
  ) as aws_api:
1571
1572
  billing_account = aws_api.get_organization_billing_account(account.name)
1572
1573
 
@@ -1750,7 +1751,7 @@ def aws_terraform_resources(ctx: click.Context) -> None:
1750
1751
  for ns_info in namespaces:
1751
1752
  specs = (
1752
1753
  get_external_resource_specs(
1753
- ns_info.dict(by_alias=True), provision_provider=PROVIDER_AWS
1754
+ ns_info.model_dump(by_alias=True), provision_provider=PROVIDER_AWS
1754
1755
  )
1755
1756
  or []
1756
1757
  )
@@ -1808,7 +1809,7 @@ def rds(ctx: click.Context) -> None:
1808
1809
  specs = [
1809
1810
  s
1810
1811
  for s in get_external_resource_specs(
1811
- namespace.dict(by_alias=True), provision_provider=PROVIDER_AWS
1812
+ namespace.model_dump(by_alias=True), provision_provider=PROVIDER_AWS
1812
1813
  )
1813
1814
  if s.provider == "rds"
1814
1815
  ]
@@ -2961,7 +2962,7 @@ def maintenances(ctx: click.Context) -> None:
2961
2962
  maintenances = maintenances_gql.query(gql.get_api().query).maintenances or []
2962
2963
  data = [
2963
2964
  {
2964
- **m.dict(),
2965
+ **m.model_dump(),
2965
2966
  "services": ", ".join(a.name for a in m.affected_services),
2966
2967
  }
2967
2968
  for m in maintenances
@@ -4298,7 +4299,7 @@ def create(
4298
4299
  bg="red",
4299
4300
  fg="white",
4300
4301
  )
4301
- print(sso_client.json(by_alias=True, indent=2))
4302
+ print(json_dumps(sso_client, indent=2))
4302
4303
 
4303
4304
 
4304
4305
  @sso_client.command()
@@ -67,7 +67,9 @@ def main(templates: tuple[str]) -> None:
67
67
  tests.append(test_yaml)
68
68
 
69
69
  template_raw["templateTest"] = tests
70
- template: TemplateV1 = TemplateV1(**data_default_none(TemplateV1, template_raw))
70
+ data = data_default_none(TemplateV1, template_raw)
71
+ assert isinstance(data, dict)
72
+ template: TemplateV1 = TemplateV1(**data)
71
73
 
72
74
  # templates_to_validate = {}
73
75
  for test in template.template_test: