qontract-reconcile 0.10.2.dev310__py3-none-any.whl → 0.10.2.dev439__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.

Potentially problematic release.


This version of qontract-reconcile might be problematic. Click here for more details.

Files changed (400) hide show
  1. {qontract_reconcile-0.10.2.dev310.dist-info → qontract_reconcile-0.10.2.dev439.dist-info}/METADATA +13 -12
  2. {qontract_reconcile-0.10.2.dev310.dist-info → qontract_reconcile-0.10.2.dev439.dist-info}/RECORD +396 -391
  3. reconcile/acs_rbac.py +2 -2
  4. reconcile/aus/advanced_upgrade_service.py +18 -12
  5. reconcile/aus/base.py +134 -32
  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 +8 -8
  14. reconcile/aws_account_manager/reconciler.py +3 -3
  15. reconcile/aws_ami_cleanup/integration.py +8 -12
  16. reconcile/aws_ami_share.py +69 -62
  17. reconcile/aws_cloudwatch_log_retention/integration.py +155 -126
  18. reconcile/aws_ecr_image_pull_secrets.py +5 -5
  19. reconcile/aws_iam_keys.py +1 -0
  20. reconcile/aws_saml_idp/integration.py +12 -4
  21. reconcile/aws_saml_roles/integration.py +32 -25
  22. reconcile/aws_version_sync/integration.py +125 -84
  23. reconcile/change_owners/bundle.py +3 -3
  24. reconcile/change_owners/change_log_tracking.py +3 -2
  25. reconcile/change_owners/change_owners.py +1 -1
  26. reconcile/change_owners/diff.py +2 -4
  27. reconcile/checkpoint.py +12 -4
  28. reconcile/cli.py +111 -18
  29. reconcile/cluster_deployment_mapper.py +2 -3
  30. reconcile/dashdotdb_dora.py +5 -12
  31. reconcile/dashdotdb_slo.py +1 -1
  32. reconcile/database_access_manager.py +125 -121
  33. reconcile/deadmanssnitch.py +1 -5
  34. reconcile/dynatrace_token_provider/integration.py +1 -1
  35. reconcile/endpoints_discovery/integration.py +4 -1
  36. reconcile/endpoints_discovery/merge_request.py +1 -1
  37. reconcile/endpoints_discovery/merge_request_manager.py +9 -11
  38. reconcile/external_resources/factories.py +5 -12
  39. reconcile/external_resources/integration.py +1 -1
  40. reconcile/external_resources/manager.py +8 -5
  41. reconcile/external_resources/meta.py +0 -1
  42. reconcile/external_resources/metrics.py +1 -1
  43. reconcile/external_resources/model.py +20 -20
  44. reconcile/external_resources/reconciler.py +7 -4
  45. reconcile/external_resources/secrets_sync.py +10 -14
  46. reconcile/external_resources/state.py +26 -16
  47. reconcile/fleet_labeler/integration.py +1 -1
  48. reconcile/gabi_authorized_users.py +8 -5
  49. reconcile/gcp_image_mirror.py +2 -2
  50. reconcile/github_org.py +1 -1
  51. reconcile/github_owners.py +4 -0
  52. reconcile/gitlab_housekeeping.py +13 -15
  53. reconcile/gitlab_members.py +6 -12
  54. reconcile/gitlab_mr_sqs_consumer.py +2 -2
  55. reconcile/gitlab_owners.py +15 -11
  56. reconcile/gitlab_permissions.py +8 -12
  57. reconcile/glitchtip_project_alerts/integration.py +3 -1
  58. reconcile/gql_definitions/acs/acs_instances.py +10 -10
  59. reconcile/gql_definitions/acs/acs_policies.py +5 -5
  60. reconcile/gql_definitions/acs/acs_rbac.py +6 -6
  61. reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +32 -32
  62. reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +26 -26
  63. reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +6 -7
  64. reconcile/gql_definitions/app_sre_tekton_access_revalidation/roles.py +5 -5
  65. reconcile/gql_definitions/app_sre_tekton_access_revalidation/users.py +5 -5
  66. reconcile/gql_definitions/automated_actions/instance.py +51 -12
  67. reconcile/gql_definitions/aws_account_manager/aws_accounts.py +11 -11
  68. reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +20 -10
  69. reconcile/gql_definitions/aws_cloudwatch_log_retention/aws_accounts.py +28 -68
  70. reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +20 -10
  71. reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +20 -10
  72. reconcile/gql_definitions/aws_saml_roles/roles.py +5 -5
  73. reconcile/gql_definitions/aws_version_sync/clusters.py +10 -10
  74. reconcile/gql_definitions/aws_version_sync/namespaces.py +5 -5
  75. reconcile/gql_definitions/change_owners/queries/change_types.py +5 -5
  76. reconcile/gql_definitions/change_owners/queries/self_service_roles.py +9 -9
  77. reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +18 -18
  78. reconcile/gql_definitions/common/alerting_services_settings.py +9 -9
  79. reconcile/gql_definitions/common/app_code_component_repos.py +5 -5
  80. reconcile/gql_definitions/common/app_interface_custom_messages.py +5 -5
  81. reconcile/gql_definitions/common/app_interface_dms_settings.py +5 -5
  82. reconcile/gql_definitions/common/app_interface_repo_settings.py +5 -5
  83. reconcile/gql_definitions/common/app_interface_roles.py +120 -0
  84. reconcile/gql_definitions/common/app_interface_state_settings.py +10 -10
  85. reconcile/gql_definitions/common/app_interface_vault_settings.py +5 -5
  86. reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +5 -5
  87. reconcile/gql_definitions/common/apps.py +5 -5
  88. reconcile/gql_definitions/common/aws_vpc_requests.py +22 -9
  89. reconcile/gql_definitions/common/aws_vpcs.py +11 -11
  90. reconcile/gql_definitions/common/clusters.py +37 -35
  91. reconcile/gql_definitions/common/clusters_minimal.py +14 -14
  92. reconcile/gql_definitions/common/clusters_with_dms.py +6 -6
  93. reconcile/gql_definitions/common/clusters_with_peering.py +29 -30
  94. reconcile/gql_definitions/common/github_orgs.py +10 -10
  95. reconcile/gql_definitions/common/jira_settings.py +10 -10
  96. reconcile/gql_definitions/common/jiralert_settings.py +5 -5
  97. reconcile/gql_definitions/common/ldap_settings.py +5 -5
  98. reconcile/gql_definitions/common/namespaces.py +42 -44
  99. reconcile/gql_definitions/common/namespaces_minimal.py +15 -13
  100. reconcile/gql_definitions/common/ocm_env_telemeter.py +12 -12
  101. reconcile/gql_definitions/common/ocm_environments.py +19 -19
  102. reconcile/gql_definitions/common/pagerduty_instances.py +9 -9
  103. reconcile/gql_definitions/common/pgp_reencryption_settings.py +6 -6
  104. reconcile/gql_definitions/common/pipeline_providers.py +29 -29
  105. reconcile/gql_definitions/common/quay_instances.py +5 -5
  106. reconcile/gql_definitions/common/quay_orgs.py +5 -5
  107. reconcile/gql_definitions/common/reserved_networks.py +5 -5
  108. reconcile/gql_definitions/common/rhcs_provider_settings.py +5 -5
  109. reconcile/gql_definitions/common/saas_files.py +44 -44
  110. reconcile/gql_definitions/common/saas_target_namespaces.py +10 -10
  111. reconcile/gql_definitions/common/saasherder_settings.py +5 -5
  112. reconcile/gql_definitions/common/slack_workspaces.py +5 -5
  113. reconcile/gql_definitions/common/smtp_client_settings.py +19 -19
  114. reconcile/gql_definitions/common/state_aws_account.py +7 -8
  115. reconcile/gql_definitions/common/users.py +5 -5
  116. reconcile/gql_definitions/common/users_with_paths.py +5 -5
  117. reconcile/gql_definitions/cost_report/app_names.py +5 -5
  118. reconcile/gql_definitions/cost_report/cost_namespaces.py +5 -5
  119. reconcile/gql_definitions/cost_report/settings.py +9 -9
  120. reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +43 -43
  121. reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +10 -10
  122. reconcile/gql_definitions/dynatrace_token_provider/token_specs.py +5 -5
  123. reconcile/gql_definitions/email_sender/apps.py +5 -5
  124. reconcile/gql_definitions/email_sender/emails.py +8 -8
  125. reconcile/gql_definitions/email_sender/users.py +6 -6
  126. reconcile/gql_definitions/endpoints_discovery/apps.py +10 -10
  127. reconcile/gql_definitions/external_resources/aws_accounts.py +9 -9
  128. reconcile/gql_definitions/external_resources/external_resources_modules.py +23 -23
  129. reconcile/gql_definitions/external_resources/external_resources_namespaces.py +494 -410
  130. reconcile/gql_definitions/external_resources/external_resources_settings.py +28 -26
  131. reconcile/gql_definitions/external_resources/fragments/external_resources_module_overrides.py +5 -5
  132. reconcile/gql_definitions/fleet_labeler/fleet_labels.py +40 -40
  133. reconcile/gql_definitions/fragments/aus_organization.py +5 -5
  134. reconcile/gql_definitions/fragments/aws_account_common.py +7 -5
  135. reconcile/gql_definitions/fragments/aws_account_managed.py +5 -5
  136. reconcile/gql_definitions/fragments/aws_account_sso.py +5 -5
  137. reconcile/gql_definitions/fragments/aws_infra_management_account.py +5 -5
  138. reconcile/gql_definitions/fragments/{aws_vpc_request_subnet.py → aws_organization.py} +12 -8
  139. reconcile/gql_definitions/fragments/aws_vpc.py +5 -5
  140. reconcile/gql_definitions/fragments/aws_vpc_request.py +12 -5
  141. reconcile/gql_definitions/fragments/container_image_mirror.py +5 -5
  142. reconcile/gql_definitions/fragments/deploy_resources.py +5 -5
  143. reconcile/gql_definitions/fragments/disable.py +5 -5
  144. reconcile/gql_definitions/fragments/email_service.py +5 -5
  145. reconcile/gql_definitions/fragments/email_user.py +5 -5
  146. reconcile/gql_definitions/fragments/jumphost_common_fields.py +5 -5
  147. reconcile/gql_definitions/fragments/membership_source.py +5 -5
  148. reconcile/gql_definitions/fragments/minimal_ocm_organization.py +5 -5
  149. reconcile/gql_definitions/fragments/oc_connection_cluster.py +5 -5
  150. reconcile/gql_definitions/fragments/ocm_environment.py +5 -5
  151. reconcile/gql_definitions/fragments/pipeline_provider_retention.py +5 -5
  152. reconcile/gql_definitions/fragments/prometheus_instance.py +5 -5
  153. reconcile/gql_definitions/fragments/resource_limits_requirements.py +5 -5
  154. reconcile/gql_definitions/fragments/resource_requests_requirements.py +5 -5
  155. reconcile/gql_definitions/fragments/resource_values.py +5 -5
  156. reconcile/gql_definitions/fragments/saas_slo_document.py +5 -5
  157. reconcile/gql_definitions/fragments/saas_target_namespace.py +5 -5
  158. reconcile/gql_definitions/fragments/serviceaccount_token.py +5 -5
  159. reconcile/gql_definitions/fragments/terraform_state.py +5 -5
  160. reconcile/gql_definitions/fragments/upgrade_policy.py +5 -5
  161. reconcile/gql_definitions/fragments/user.py +5 -5
  162. reconcile/gql_definitions/fragments/vault_secret.py +5 -5
  163. reconcile/gql_definitions/gcp/gcp_docker_repos.py +9 -9
  164. reconcile/gql_definitions/gcp/gcp_projects.py +9 -9
  165. reconcile/gql_definitions/gitlab_members/gitlab_instances.py +9 -9
  166. reconcile/gql_definitions/gitlab_members/permissions.py +9 -9
  167. reconcile/gql_definitions/glitchtip/glitchtip_instance.py +9 -9
  168. reconcile/gql_definitions/glitchtip/glitchtip_project.py +11 -11
  169. reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +9 -9
  170. reconcile/gql_definitions/integrations/integrations.py +48 -51
  171. reconcile/gql_definitions/introspection.json +3510 -1865
  172. reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +11 -11
  173. reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +10 -10
  174. reconcile/gql_definitions/jira/jira_servers.py +5 -5
  175. reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +14 -10
  176. reconcile/gql_definitions/jumphosts/jumphosts.py +13 -13
  177. reconcile/gql_definitions/ldap_groups/roles.py +5 -5
  178. reconcile/gql_definitions/ldap_groups/settings.py +9 -9
  179. reconcile/gql_definitions/maintenance/maintenances.py +5 -5
  180. reconcile/gql_definitions/membershipsources/roles.py +5 -5
  181. reconcile/gql_definitions/ocm_labels/clusters.py +18 -19
  182. reconcile/gql_definitions/ocm_labels/organizations.py +5 -5
  183. reconcile/gql_definitions/openshift_cluster_bots/clusters.py +22 -22
  184. reconcile/gql_definitions/openshift_groups/managed_groups.py +5 -5
  185. reconcile/gql_definitions/openshift_groups/managed_roles.py +6 -6
  186. reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +10 -10
  187. reconcile/gql_definitions/quay_membership/quay_membership.py +6 -6
  188. reconcile/gql_definitions/rhcs/certs.py +33 -87
  189. reconcile/gql_definitions/rhcs/openshift_resource_rhcs_cert.py +43 -0
  190. reconcile/gql_definitions/rhidp/organizations.py +18 -18
  191. reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +5 -5
  192. reconcile/gql_definitions/service_dependencies/service_dependencies.py +8 -8
  193. reconcile/gql_definitions/sharding/aws_accounts.py +10 -10
  194. reconcile/gql_definitions/sharding/ocm_organization.py +8 -8
  195. reconcile/gql_definitions/skupper_network/site_controller_template.py +5 -5
  196. reconcile/gql_definitions/skupper_network/skupper_networks.py +10 -10
  197. reconcile/gql_definitions/slack_usergroups/clusters.py +5 -5
  198. reconcile/gql_definitions/slack_usergroups/permissions.py +9 -9
  199. reconcile/gql_definitions/slack_usergroups/users.py +5 -5
  200. reconcile/gql_definitions/slo_documents/slo_documents.py +5 -5
  201. reconcile/gql_definitions/status_board/status_board.py +6 -7
  202. reconcile/gql_definitions/statuspage/statuspages.py +9 -9
  203. reconcile/gql_definitions/templating/template_collection.py +5 -5
  204. reconcile/gql_definitions/templating/templates.py +5 -5
  205. reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +6 -6
  206. reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +11 -11
  207. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +11 -11
  208. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +20 -25
  209. reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +6 -6
  210. reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +12 -12
  211. reconcile/gql_definitions/terraform_init/aws_accounts.py +23 -9
  212. reconcile/gql_definitions/terraform_repo/terraform_repo.py +9 -9
  213. reconcile/gql_definitions/terraform_resources/database_access_manager.py +5 -5
  214. reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +450 -402
  215. reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +23 -17
  216. reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +9 -9
  217. reconcile/gql_definitions/vault_instances/vault_instances.py +61 -61
  218. reconcile/gql_definitions/vault_policies/vault_policies.py +11 -11
  219. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +8 -8
  220. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +5 -5
  221. reconcile/integrations_manager.py +3 -3
  222. reconcile/jenkins_job_builder.py +1 -1
  223. reconcile/jenkins_worker_fleets.py +80 -11
  224. reconcile/jira_permissions_validator.py +237 -122
  225. reconcile/ldap_groups/integration.py +1 -1
  226. reconcile/ocm/types.py +35 -56
  227. reconcile/ocm_aws_infrastructure_access.py +1 -1
  228. reconcile/ocm_clusters.py +4 -4
  229. reconcile/ocm_labels/integration.py +3 -2
  230. reconcile/ocm_machine_pools.py +33 -27
  231. reconcile/openshift_base.py +122 -10
  232. reconcile/openshift_cluster_bots.py +5 -5
  233. reconcile/openshift_groups.py +5 -0
  234. reconcile/openshift_limitranges.py +1 -1
  235. reconcile/openshift_namespace_labels.py +1 -1
  236. reconcile/openshift_namespaces.py +97 -101
  237. reconcile/openshift_resources_base.py +10 -5
  238. reconcile/openshift_rhcs_certs.py +77 -40
  239. reconcile/openshift_rolebindings.py +230 -130
  240. reconcile/openshift_saas_deploy.py +6 -7
  241. reconcile/openshift_saas_deploy_change_tester.py +9 -7
  242. reconcile/openshift_saas_deploy_trigger_cleaner.py +3 -5
  243. reconcile/openshift_serviceaccount_tokens.py +8 -7
  244. reconcile/openshift_tekton_resources.py +1 -1
  245. reconcile/openshift_upgrade_watcher.py +4 -4
  246. reconcile/openshift_users.py +5 -3
  247. reconcile/oum/labelset.py +5 -3
  248. reconcile/oum/models.py +1 -4
  249. reconcile/oum/providers.py +1 -1
  250. reconcile/prometheus_rules_tester/integration.py +4 -4
  251. reconcile/quay_mirror.py +1 -1
  252. reconcile/queries.py +131 -0
  253. reconcile/requests_sender.py +8 -3
  254. reconcile/resource_scraper.py +1 -5
  255. reconcile/rhidp/common.py +3 -5
  256. reconcile/rhidp/sso_client/base.py +19 -10
  257. reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +1 -1
  258. reconcile/saas_auto_promotions_manager/subscriber.py +4 -3
  259. reconcile/sendgrid_teammates.py +20 -9
  260. reconcile/skupper_network/integration.py +2 -2
  261. reconcile/slack_usergroups.py +35 -14
  262. reconcile/sql_query.py +1 -0
  263. reconcile/status.py +2 -2
  264. reconcile/status_board.py +6 -6
  265. reconcile/statuspage/atlassian.py +7 -7
  266. reconcile/statuspage/integrations/maintenances.py +4 -3
  267. reconcile/statuspage/page.py +4 -9
  268. reconcile/statuspage/status.py +5 -8
  269. reconcile/templates/rosa-classic-cluster-creation.sh.j2 +5 -1
  270. reconcile/templates/rosa-hcp-cluster-creation.sh.j2 +4 -1
  271. reconcile/templating/lib/merge_request_manager.py +2 -2
  272. reconcile/templating/lib/rendering.py +3 -3
  273. reconcile/templating/renderer.py +12 -13
  274. reconcile/terraform_aws_route53.py +18 -8
  275. reconcile/terraform_cloudflare_dns.py +3 -3
  276. reconcile/terraform_cloudflare_resources.py +12 -13
  277. reconcile/terraform_cloudflare_users.py +3 -2
  278. reconcile/terraform_init/integration.py +187 -23
  279. reconcile/terraform_repo.py +16 -12
  280. reconcile/terraform_resources.py +18 -10
  281. reconcile/terraform_tgw_attachments.py +28 -20
  282. reconcile/terraform_users.py +27 -22
  283. reconcile/terraform_vpc_peerings.py +15 -3
  284. reconcile/terraform_vpc_resources/integration.py +23 -8
  285. reconcile/typed_queries/app_interface_roles.py +10 -0
  286. reconcile/typed_queries/aws_account_tags.py +41 -0
  287. reconcile/typed_queries/cost_report/app_names.py +1 -1
  288. reconcile/typed_queries/cost_report/cost_namespaces.py +2 -2
  289. reconcile/typed_queries/saas_files.py +13 -13
  290. reconcile/typed_queries/status_board.py +2 -2
  291. reconcile/unleash_feature_toggles/integration.py +4 -2
  292. reconcile/utils/acs/base.py +6 -3
  293. reconcile/utils/acs/policies.py +2 -2
  294. reconcile/utils/aggregated_list.py +4 -3
  295. reconcile/utils/aws_api.py +51 -20
  296. reconcile/utils/aws_api_typed/api.py +38 -9
  297. reconcile/utils/aws_api_typed/cloudformation.py +149 -0
  298. reconcile/utils/aws_api_typed/logs.py +73 -0
  299. reconcile/utils/aws_api_typed/organization.py +4 -2
  300. reconcile/utils/binary.py +7 -12
  301. reconcile/utils/datetime_util.py +67 -0
  302. reconcile/utils/deadmanssnitch_api.py +1 -1
  303. reconcile/utils/differ.py +2 -3
  304. reconcile/utils/early_exit_cache.py +11 -12
  305. reconcile/utils/expiration.py +7 -3
  306. reconcile/utils/external_resource_spec.py +24 -1
  307. reconcile/utils/filtering.py +1 -1
  308. reconcile/utils/gitlab_api.py +7 -5
  309. reconcile/utils/glitchtip/client.py +6 -2
  310. reconcile/utils/glitchtip/models.py +25 -28
  311. reconcile/utils/gpg.py +5 -3
  312. reconcile/utils/gql.py +4 -7
  313. reconcile/utils/helm.py +2 -1
  314. reconcile/utils/helpers.py +1 -1
  315. reconcile/utils/imap_client.py +1 -1
  316. reconcile/utils/instrumented_wrappers.py +1 -1
  317. reconcile/utils/internal_groups/client.py +2 -2
  318. reconcile/utils/internal_groups/models.py +8 -17
  319. reconcile/utils/jenkins_api.py +24 -1
  320. reconcile/utils/jinja2/utils.py +6 -8
  321. reconcile/utils/jira_client.py +82 -63
  322. reconcile/utils/jjb_client.py +78 -46
  323. reconcile/utils/jobcontroller/controller.py +2 -2
  324. reconcile/utils/jobcontroller/models.py +17 -1
  325. reconcile/utils/json.py +74 -0
  326. reconcile/utils/ldap_client.py +4 -3
  327. reconcile/utils/lean_terraform_client.py +3 -1
  328. reconcile/utils/membershipsources/app_interface_resolver.py +4 -2
  329. reconcile/utils/membershipsources/models.py +16 -23
  330. reconcile/utils/membershipsources/resolver.py +4 -2
  331. reconcile/utils/merge_request_manager/merge_request_manager.py +4 -4
  332. reconcile/utils/merge_request_manager/parser.py +6 -6
  333. reconcile/utils/metrics.py +5 -5
  334. reconcile/utils/models.py +304 -82
  335. reconcile/utils/mr/__init__.py +3 -1
  336. reconcile/utils/mr/app_interface_reporter.py +6 -3
  337. reconcile/utils/mr/aws_access.py +1 -1
  338. reconcile/utils/mr/base.py +7 -13
  339. reconcile/utils/mr/clusters_updates.py +4 -2
  340. reconcile/utils/mr/notificator.py +3 -3
  341. reconcile/utils/mr/ocm_upgrade_scheduler_org_updates.py +4 -1
  342. reconcile/utils/mr/promote_qontract.py +28 -12
  343. reconcile/utils/mr/update_access_report_base.py +3 -4
  344. reconcile/utils/mr/user_maintenance.py +7 -6
  345. reconcile/utils/oc.py +445 -336
  346. reconcile/utils/oc_filters.py +3 -3
  347. reconcile/utils/ocm/addons.py +0 -1
  348. reconcile/utils/ocm/base.py +18 -21
  349. reconcile/utils/ocm/cluster_groups.py +1 -1
  350. reconcile/utils/ocm/identity_providers.py +2 -2
  351. reconcile/utils/ocm/labels.py +1 -1
  352. reconcile/utils/ocm/ocm.py +81 -71
  353. reconcile/utils/ocm/products.py +9 -3
  354. reconcile/utils/ocm/search_filters.py +3 -6
  355. reconcile/utils/ocm/service_log.py +4 -6
  356. reconcile/utils/ocm/sre_capability_labels.py +20 -13
  357. reconcile/utils/ocm_base_client.py +4 -4
  358. reconcile/utils/openshift_resource.py +83 -52
  359. reconcile/utils/openssl.py +2 -2
  360. reconcile/utils/output.py +3 -2
  361. reconcile/utils/pagerduty_api.py +10 -7
  362. reconcile/utils/promotion_state.py +6 -11
  363. reconcile/utils/raw_github_api.py +11 -8
  364. reconcile/utils/repo_owners.py +21 -29
  365. reconcile/utils/rhcsv2_certs.py +138 -35
  366. reconcile/utils/rosa/session.py +16 -0
  367. reconcile/utils/runtime/integration.py +2 -3
  368. reconcile/utils/runtime/meta.py +2 -1
  369. reconcile/utils/runtime/runner.py +2 -2
  370. reconcile/utils/saasherder/interfaces.py +13 -20
  371. reconcile/utils/saasherder/models.py +25 -21
  372. reconcile/utils/saasherder/saasherder.py +60 -32
  373. reconcile/utils/secret_reader.py +6 -6
  374. reconcile/utils/sharding.py +1 -1
  375. reconcile/utils/slack_api.py +26 -4
  376. reconcile/utils/sloth.py +224 -0
  377. reconcile/utils/sqs_gateway.py +16 -11
  378. reconcile/utils/state.py +2 -1
  379. reconcile/utils/structs.py +1 -1
  380. reconcile/utils/terraform_client.py +29 -26
  381. reconcile/utils/terrascript_aws_client.py +200 -116
  382. reconcile/utils/three_way_diff_strategy.py +1 -1
  383. reconcile/utils/unleash/server.py +2 -8
  384. reconcile/utils/vault.py +44 -41
  385. reconcile/utils/vcs.py +8 -8
  386. reconcile/vault_replication.py +119 -58
  387. tools/app_interface_reporter.py +4 -4
  388. tools/cli_commands/cost_report/cost_management_api.py +3 -3
  389. tools/cli_commands/cost_report/view.py +7 -6
  390. tools/cli_commands/erv2.py +1 -1
  391. tools/cli_commands/gpg_encrypt.py +4 -1
  392. tools/cli_commands/systems_and_tools.py +5 -1
  393. tools/qontract_cli.py +36 -21
  394. tools/template_validation.py +3 -1
  395. reconcile/gql_definitions/ocm_oidc_idp/__init__.py +0 -0
  396. reconcile/gql_definitions/ocm_subscription_labels/__init__.py +0 -0
  397. reconcile/jenkins/__init__.py +0 -0
  398. reconcile/jenkins/types.py +0 -77
  399. {qontract_reconcile-0.10.2.dev310.dist-info → qontract_reconcile-0.10.2.dev439.dist-info}/WHEEL +0 -0
  400. {qontract_reconcile-0.10.2.dev310.dist-info → qontract_reconcile-0.10.2.dev439.dist-info}/entry_points.txt +0 -0
@@ -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
  )
@@ -315,7 +365,6 @@ def populate_current_state(
315
365
 
316
366
  if caller and openshift_resource.caller != caller:
317
367
  continue
318
-
319
368
  ri.add_current(
320
369
  spec.cluster,
321
370
  spec.namespace,
@@ -341,6 +390,7 @@ def fetch_current_state(
341
390
  cluster_admin: bool = False,
342
391
  caller: str | None = None,
343
392
  init_projects: bool = False,
393
+ cluster_scope_resource_validation: bool = False,
344
394
  ) -> tuple[ResourceInventory, OC_Map]:
345
395
  ri = ResourceInventory()
346
396
  settings = queries.get_app_interface_settings()
@@ -363,6 +413,7 @@ def fetch_current_state(
363
413
  clusters=clusters,
364
414
  override_managed_types=override_managed_types,
365
415
  cluster_admin=cluster_admin,
416
+ cluster_scope_resource_validation=cluster_scope_resource_validation,
366
417
  )
367
418
  threaded.run(
368
419
  populate_current_state,
@@ -535,11 +586,15 @@ def apply(
535
586
  # take care of the resize ourselves.
536
587
  # ref: https://github.com/kubernetes/enhancements/pull/2842
537
588
  if resize_required:
589
+ if desired_storage is None:
590
+ raise ValidationError(
591
+ "Resource body does not contain storage information."
592
+ ) from None
538
593
  logging.info(["resizing_pvcs", cluster, namespace, owned_pvc_names])
539
594
  oc.resize_pvcs(namespace, owned_pvc_names, desired_storage)
540
595
 
541
596
  if recycle_pods:
542
- oc.recycle_pods(dry_run, namespace, resource_type, resource)
597
+ oc.recycle_pods(dry_run, namespace, resource)
543
598
 
544
599
 
545
600
  def create(
@@ -783,10 +838,56 @@ def handle_identical_resources(
783
838
  return actions
784
839
 
785
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
+
786
887
  def handle_modified_resources(
787
888
  oc_map: ClusterMap,
788
889
  ri: ResourceInventory,
789
- modified_resources: Mapping[Any, Any],
890
+ modified_resources: Mapping[str, DiffPair[OR, OR]],
790
891
  cluster: str,
791
892
  namespace: str,
792
893
  resource_type: str,
@@ -982,6 +1083,12 @@ def _realize_resource_data_3way_diff(
982
1083
  if options.enable_deletion and options.override_enable_deletion is False:
983
1084
  options.enable_deletion = False
984
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
+
985
1092
  diff_result = differ.diff_mappings(
986
1093
  data["current"], data["desired"], equal=three_way_diff_using_hash
987
1094
  )
@@ -1095,11 +1202,11 @@ def _validate_resources_used_exist(
1095
1202
  )
1096
1203
  for used_name, used_keys in used_resources.items():
1097
1204
  # perhaps used resource is deployed together with the using resource?
1098
- resource = ri.get_desired(cluster, namespace, used_kind, used_name)
1205
+ desired_resource = ri.get_desired(cluster, namespace, used_kind, used_name)
1099
1206
  # if not, perhaps it's a secret that will be created from a Service's
1100
1207
  # serving-cert that is deployed along with the using resource?
1101
1208
  # lets iterate through all resources and find Services that have the annotation
1102
- if not resource and used_kind == "Secret":
1209
+ if not desired_resource and used_kind == "Secret":
1103
1210
  # consider only Service resources that are in the same cluster & namespace
1104
1211
  service_resources = []
1105
1212
  for cname, nname, restype, res in ri:
@@ -1123,12 +1230,12 @@ def _validate_resources_used_exist(
1123
1230
  }:
1124
1231
  # found a match. we assume the serving cert secret will
1125
1232
  # be present at some point soon after the Service is deployed
1126
- resource = service
1233
+ desired_resource = service
1127
1234
  break
1128
1235
 
1129
- if resource:
1236
+ if desired_resource:
1130
1237
  # get the body to match with the possible result from oc.get
1131
- resource = resource.body
1238
+ resource = desired_resource.body
1132
1239
  else:
1133
1240
  # no. perhaps used resource exists in the namespace?
1134
1241
  resource = oc.get(
@@ -1360,6 +1467,11 @@ class HasOpenShiftResources(Protocol):
1360
1467
  openshift_resources: list | None
1361
1468
 
1362
1469
 
1470
+ @runtime_checkable
1471
+ class HasOpenShiftResourcesRequired(Protocol):
1472
+ openshift_resources: list
1473
+
1474
+
1363
1475
  @runtime_checkable
1364
1476
  class HasOpenshiftServiceAccountTokens(Protocol):
1365
1477
  openshift_service_account_tokens: list | None
@@ -1368,7 +1480,7 @@ class HasOpenshiftServiceAccountTokens(Protocol):
1368
1480
  @runtime_checkable
1369
1481
  class HasSharedResourcesOpenShiftResources(Protocol):
1370
1482
  @property
1371
- def shared_resources(self) -> Sequence[HasOpenShiftResources] | None: ...
1483
+ def shared_resources(self) -> Sequence[HasOpenShiftResourcesRequired] | None: ...
1372
1484
 
1373
1485
 
1374
1486
  @runtime_checkable
@@ -5,7 +5,6 @@ import subprocess
5
5
  import sys
6
6
  import tempfile
7
7
  import urllib.request
8
- from typing import cast
9
8
  from urllib.error import URLError
10
9
 
11
10
  from pydantic import BaseModel
@@ -17,6 +16,7 @@ from reconcile.gql_definitions.openshift_cluster_bots.clusters import ClusterV1
17
16
  from reconcile.status import ExitCodes
18
17
  from reconcile.utils import gql
19
18
  from reconcile.utils.disabled_integrations import integration_is_enabled
19
+ from reconcile.utils.json import json_dumps
20
20
  from reconcile.utils.mr import clusters_updates
21
21
  from reconcile.utils.ocm import OCM, OCMMap
22
22
  from reconcile.utils.openshift_resource import (
@@ -24,7 +24,7 @@ from reconcile.utils.openshift_resource import (
24
24
  QONTRACT_ANNOTATION_INTEGRATION_VERSION,
25
25
  )
26
26
  from reconcile.utils.semver_helper import make_semver
27
- from reconcile.utils.vault import VaultClient, _VaultClient
27
+ from reconcile.utils.vault import VaultClient
28
28
 
29
29
  QONTRACT_INTEGRATION = "openshift-cluster-bots"
30
30
  QONTRACT_INTEGRATION_VERSION = make_semver(0, 1, 0)
@@ -103,7 +103,7 @@ def oc(
103
103
 
104
104
  def oc_apply(kubeconfig: str, namespace: str, items: list[dict]) -> None:
105
105
  for item in items:
106
- stdin = json.dumps(item).encode()
106
+ stdin = json_dumps(item).encode()
107
107
  oc(kubeconfig, namespace, ["apply", "-f", "-"], stdin)
108
108
 
109
109
 
@@ -238,7 +238,7 @@ def create_cluster_bots(
238
238
  def update_vault(
239
239
  cluster: ClusterV1, config: Config, token: str, admin_token: str | None
240
240
  ) -> None:
241
- vault = cast("_VaultClient", VaultClient())
241
+ vault = VaultClient.get_instance()
242
242
  vault.write(
243
243
  {
244
244
  "path": vault_secret(cluster, config, cluster_admin=False)["path"],
@@ -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,
@@ -243,10 +243,15 @@ def act(diff: Mapping[str, str | None], oc_map: ClusterMap) -> None:
243
243
  return None
244
244
 
245
245
  if action == "create_group":
246
+ assert group # make mypy happy
246
247
  oc.create_group(group)
247
248
  elif action == "add_user_to_group":
249
+ assert group # make mypy happy
250
+ assert user # make mypy happy
248
251
  oc.add_user_to_group(group, user)
249
252
  elif action == "del_user_from_group":
253
+ assert group # make mypy happy
254
+ assert user # make mypy happy
250
255
  oc.del_user_from_group(group, user)
251
256
  elif action == "delete_group":
252
257
  logging.debug("skipping group deletion")
@@ -39,7 +39,7 @@ def construct_resources(
39
39
  # Get the linked limitRanges schema settings
40
40
  limitranges = namespace.get("limitRanges", {})
41
41
 
42
- body: MutableMapping[str, Any] = {
42
+ body: dict[str, Any] = {
43
43
  "apiVersion": "v1",
44
44
  "kind": "LimitRange",
45
45
  "metadata": {
@@ -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