qontract-reconcile 0.10.2.dev299__py3-none-any.whl → 0.10.2.dev430__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 (403) hide show
  1. {qontract_reconcile-0.10.2.dev299.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/METADATA +13 -12
  2. {qontract_reconcile-0.10.2.dev299.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/RECORD +399 -394
  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 +4 -4
  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 +8 -11
  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 +23 -10
  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 +492 -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 +10 -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 +3050 -1393
  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 +448 -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 +5 -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 +4 -0
  270. reconcile/templates/rosa-hcp-cluster-creation.sh.j2 +3 -0
  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 +27 -19
  282. reconcile/terraform_users.py +29 -21
  283. reconcile/terraform_vpc_peerings.py +16 -4
  284. reconcile/terraform_vpc_resources/integration.py +32 -2
  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 +59 -43
  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 +27 -20
  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 +4 -4
  380. reconcile/utils/terraform_client.py +32 -29
  381. reconcile/utils/terrascript_aws_client.py +658 -480
  382. reconcile/utils/three_way_diff_strategy.py +1 -1
  383. reconcile/utils/throughput.py +1 -1
  384. reconcile/utils/unleash/server.py +2 -8
  385. reconcile/utils/vault.py +44 -41
  386. reconcile/utils/vcs.py +8 -8
  387. reconcile/vault_replication.py +119 -58
  388. reconcile/vpc_peerings_validator.py +2 -2
  389. tools/app_interface_reporter.py +4 -4
  390. tools/cli_commands/cost_report/cost_management_api.py +3 -3
  391. tools/cli_commands/cost_report/view.py +7 -6
  392. tools/cli_commands/erv2.py +1 -1
  393. tools/cli_commands/gpg_encrypt.py +4 -1
  394. tools/cli_commands/systems_and_tools.py +5 -1
  395. tools/qontract_cli.py +36 -21
  396. tools/sre_checkpoints/util.py +5 -3
  397. tools/template_validation.py +3 -1
  398. reconcile/gql_definitions/ocm_oidc_idp/__init__.py +0 -0
  399. reconcile/gql_definitions/ocm_subscription_labels/__init__.py +0 -0
  400. reconcile/jenkins/__init__.py +0 -0
  401. reconcile/jenkins/types.py +0 -77
  402. {qontract_reconcile-0.10.2.dev299.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/WHEEL +0 -0
  403. {qontract_reconcile-0.10.2.dev299.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/entry_points.txt +0 -0
@@ -1,25 +1,27 @@
1
1
  import logging
2
- import sys
2
+ from collections import defaultdict
3
3
  from collections.abc import (
4
4
  Callable,
5
5
  Iterable,
6
- Mapping,
7
6
  Sequence,
8
7
  )
8
+ from dataclasses import dataclass
9
+ from enum import StrEnum
9
10
  from typing import Any
10
11
 
11
12
  from sretoolbox.utils import threaded
12
13
 
13
14
  import reconcile.openshift_base as ob
14
15
  from reconcile.gql_definitions.common.namespaces_minimal import NamespaceV1
15
- from reconcile.status import ExitCodes
16
16
  from reconcile.typed_queries.app_interface_vault_settings import (
17
17
  get_app_interface_vault_settings,
18
18
  )
19
19
  from reconcile.typed_queries.namespaces_minimal import get_namespaces_minimal
20
20
  from reconcile.utils.constants import DEFAULT_THREAD_POOL_SIZE
21
21
  from reconcile.utils.defer import defer
22
- from reconcile.utils.oc_filters import filter_namespaces_by_cluster_and_namespace
22
+ from reconcile.utils.oc_filters import (
23
+ filter_namespaces_by_cluster_and_namespace,
24
+ )
23
25
  from reconcile.utils.oc_map import (
24
26
  OCLogMsg,
25
27
  OCMap,
@@ -30,113 +32,112 @@ from reconcile.utils.sharding import is_in_shard
30
32
 
31
33
  QONTRACT_INTEGRATION = "openshift-namespaces"
32
34
 
33
- NS_STATE_PRESENT = "present"
34
- NS_STATE_ABSENT = "absent"
35
-
36
- NS_ACTION_CREATE = "create"
37
- NS_ACTION_DELETE = "delete"
38
35
 
36
+ class Action(StrEnum):
37
+ CREATE = "create"
38
+ DELETE = "delete"
39
39
 
40
- DUPLICATES_LOG_MSG = "Found multiple definitions for the namespace {key}"
41
40
 
41
+ @dataclass(frozen=True)
42
+ class DesiredState:
43
+ cluster: str
44
+ namespace: str
45
+ delete: bool
42
46
 
43
- def get_desired_state(namespaces: Iterable[NamespaceV1]) -> list[dict[str, str]]:
44
- desired_state: list[dict[str, str]] = []
45
- for ns in namespaces:
46
- state = NS_STATE_PRESENT
47
- if ns.delete:
48
- state = NS_STATE_ABSENT
49
47
 
50
- desired_state.append({
51
- "cluster": ns.cluster.name,
52
- "namespace": ns.name,
53
- "desired_state": state,
54
- })
48
+ class NamespaceDuplicateError(Exception):
49
+ pass
55
50
 
56
- return desired_state
57
51
 
52
+ def get_namespaces(
53
+ cluster_name: Sequence[str] | None,
54
+ namespace_name: Sequence[str] | None,
55
+ ) -> tuple[list[NamespaceV1], list[NamespaceDuplicateError]]:
56
+ all_namespaces = get_namespaces_minimal()
58
57
 
59
- def get_shard_namespaces(
60
- namespaces: Iterable[NamespaceV1],
61
- ) -> tuple[list[NamespaceV1], bool]:
62
- # Structure holding duplicates by namespace key
63
- duplicates: dict[str, list[NamespaceV1]] = {}
64
- # namespace filtered list without duplicates
65
- filtered_ns: dict[str, NamespaceV1] = {}
66
-
67
- err = False
68
- for ns in namespaces:
69
- key = f"{ns.cluster.name}/{ns.name}"
58
+ namespaces_by_shard_key = defaultdict(list)
70
59
 
60
+ for namespace in all_namespaces:
61
+ key = f"{namespace.cluster.name}/{namespace.name}"
71
62
  if is_in_shard(key):
72
- if key not in filtered_ns:
73
- filtered_ns[key] = ns
74
- else:
75
- # Duplicated NS
76
- dupe_list_by_key = duplicates.setdefault(key, [])
77
- dupe_list_by_key.append(ns)
78
-
79
- for key, dupe_list in duplicates.items():
80
- dupe_list.append(filtered_ns[key])
81
- delete_flags = (
82
- [ns.delete for ns in dupe_list_by_key] if dupe_list_by_key else []
83
- )
63
+ namespaces_by_shard_key[key].append(namespace)
84
64
 
85
- if len(set(delete_flags)) > 1:
86
- # If true only some definitions in list have the delete flag.
87
- # this case will generate an error
88
- err = True
89
- # Remove the namespace found from the filtered list
90
- del filtered_ns[key]
91
- logging.error(DUPLICATES_LOG_MSG.format(key=key))
65
+ managed_namespaces = []
66
+ duplicate_errors = []
67
+
68
+ for key, namespaces in namespaces_by_shard_key.items():
69
+ if len(namespaces) == 1:
70
+ namespace = namespaces[0]
71
+ if not namespace.managed_by_external:
72
+ managed_namespaces.append(namespace)
92
73
  else:
93
- # If all namespaces have the same delete option
94
- # The action will be performaed
95
- logging.debug(DUPLICATES_LOG_MSG.format(key=key))
74
+ msg = f"Found multiple definitions for the namespace {key}"
75
+ duplicate_errors.append(NamespaceDuplicateError(msg))
76
+ logging.error(msg)
77
+
78
+ namespaces = filter_namespaces_by_cluster_and_namespace(
79
+ namespaces=managed_namespaces,
80
+ cluster_names=cluster_name,
81
+ namespace_names=namespace_name,
82
+ )
83
+
84
+ return namespaces, duplicate_errors
85
+
96
86
 
97
- return list(filtered_ns.values()), err
87
+ def build_desired_state(
88
+ namespaces: Iterable[NamespaceV1],
89
+ ) -> list[DesiredState]:
90
+ return [
91
+ DesiredState(
92
+ cluster=namespace.cluster.name,
93
+ namespace=namespace.name,
94
+ delete=namespace.delete or False,
95
+ )
96
+ for namespace in namespaces
97
+ ]
98
98
 
99
99
 
100
- def manage_namespaces(spec: Mapping[str, str], oc_map: OCMap, dry_run: bool) -> None:
101
- cluster = spec["cluster"]
102
- namespace = spec["namespace"]
103
- desired_state = spec["desired_state"]
100
+ def manage_namespace(
101
+ desired_state: DesiredState,
102
+ oc_map: OCMap,
103
+ dry_run: bool,
104
+ ) -> None:
105
+ namespace = desired_state.namespace
104
106
 
105
- oc = oc_map.get(cluster)
107
+ oc = oc_map.get(desired_state.cluster)
106
108
  if isinstance(oc, OCLogMsg):
107
109
  logging.log(level=oc.log_level, msg=oc.message)
108
- return None
110
+ return
109
111
 
110
- act = {NS_ACTION_CREATE: oc.new_project, NS_ACTION_DELETE: oc.delete_project}
112
+ current_delete = not oc.project_exists(namespace)
111
113
 
112
- exists = oc.project_exists(namespace)
113
- action = None
114
- if not exists and desired_state == NS_STATE_PRESENT:
115
- if namespace.startswith("openshift-"):
116
- raise ValueError('cannot request a project starting with "openshift-"')
117
- action = NS_ACTION_CREATE
118
- elif exists and desired_state == NS_STATE_ABSENT:
119
- action = NS_ACTION_DELETE
114
+ if desired_state.delete == current_delete:
115
+ return
120
116
 
121
- if action:
122
- logging.info([action, cluster, namespace])
123
- if not dry_run:
124
- act[action](namespace)
117
+ action = Action.DELETE if desired_state.delete else Action.CREATE
125
118
 
119
+ if namespace.startswith("openshift-"):
120
+ raise ValueError(f'cannot {action} a project starting with "openshift-"')
126
121
 
127
- def check_results(
128
- desired_state: Iterable[Mapping[str, str]], results: Iterable[Any]
129
- ) -> bool:
130
- err = False
122
+ logging.info([str(action), desired_state.cluster, namespace])
123
+ if not dry_run:
124
+ match action:
125
+ case Action.CREATE:
126
+ oc.new_project(namespace)
127
+ case Action.DELETE:
128
+ oc.delete_project(namespace)
129
+
130
+
131
+ def build_runtime_errors(
132
+ desired_state: Iterable[DesiredState],
133
+ results: Iterable[Any],
134
+ ) -> list[Exception]:
135
+ exceptions = []
131
136
  for s, e in zip(desired_state, results, strict=False):
132
137
  if isinstance(e, Exception):
133
- err = True
134
- msg = (
135
- f"cluster: {s['cluster']}, namespace: {s['namespace']}, "
136
- f"exception: {e!s}"
137
- )
138
- logging.error(msg)
139
- return err
138
+ e.add_note(f"cluster: {s.cluster}, namespace: {s.namespace}")
139
+ exceptions.append(e)
140
+ return exceptions
140
141
 
141
142
 
142
143
  @defer
@@ -149,15 +150,8 @@ def run(
149
150
  namespace_name: Sequence[str] | None = None,
150
151
  defer: Callable | None = None,
151
152
  ) -> None:
152
- all_namespaces = get_namespaces_minimal()
153
- shard_namespaces, duplicates = get_shard_namespaces(all_namespaces)
154
- namespaces = filter_namespaces_by_cluster_and_namespace(
155
- namespaces=shard_namespaces,
156
- cluster_names=cluster_name,
157
- namespace_names=namespace_name,
158
- )
159
-
160
- desired_state = get_desired_state(namespaces)
153
+ namespaces, duplicate_errors = get_namespaces(cluster_name, namespace_name)
154
+ desired_state = build_desired_state(namespaces)
161
155
 
162
156
  vault_settings = get_app_interface_vault_settings()
163
157
  secret_reader = create_secret_reader(use_vault=vault_settings.vault)
@@ -171,16 +165,17 @@ def run(
171
165
  thread_pool_size=thread_pool_size,
172
166
  init_projects=True,
173
167
  )
174
-
175
168
  if defer:
176
169
  defer(oc_map.cleanup)
177
170
 
178
171
  ob.publish_cluster_desired_metrics_from_state(
179
- desired_state, QONTRACT_INTEGRATION, "Namespace"
172
+ state=({"cluster": s.cluster} for s in desired_state),
173
+ integration=QONTRACT_INTEGRATION,
174
+ kind="Namespace",
180
175
  )
181
176
 
182
177
  results = threaded.run(
183
- manage_namespaces,
178
+ manage_namespace,
184
179
  desired_state,
185
180
  thread_pool_size,
186
181
  return_exceptions=True,
@@ -188,6 +183,7 @@ def run(
188
183
  oc_map=oc_map,
189
184
  )
190
185
 
191
- err = check_results(desired_state=desired_state, results=results)
192
- if err or duplicates:
193
- sys.exit(ExitCodes.ERROR)
186
+ runtime_errors = build_runtime_errors(desired_state, results)
187
+ errors = runtime_errors + duplicate_errors
188
+ if errors:
189
+ raise ExceptionGroup("Reconcile errors occurred", errors)
@@ -806,7 +806,11 @@ def fetch_data(
806
806
  init_api_resources=init_api_resources,
807
807
  )
808
808
  state_specs = ob.init_specs_to_fetch(
809
- ri, oc_map, namespaces=namespaces, override_managed_types=overrides
809
+ ri,
810
+ oc_map,
811
+ namespaces=namespaces,
812
+ override_managed_types=overrides,
813
+ cluster_scope_resource_validation=True,
810
814
  )
811
815
  threaded.run(fetch_states, state_specs, thread_pool_size, ri=ri, settings=settings)
812
816
 
@@ -861,7 +865,7 @@ def canonicalize_namespaces(
861
865
  elif providers[0] == "route":
862
866
  override = ["Route"]
863
867
  elif providers[0] == "prometheus-rule":
864
- override = ["PrometheusRule"]
868
+ override = ["PrometheusRule.monitoring.coreos.com"]
865
869
 
866
870
  namespace_info["openshiftResources"] = ors
867
871
  canonicalized_namespaces.append(namespace_info)
@@ -1005,8 +1009,9 @@ class CheckClusterScopedResourceNames:
1005
1009
  for kind in cluster_scoped_types:
1006
1010
  declared_items = mrn.get(kind, [])
1007
1011
  desired_items = set(
1008
- self.ri.get_desired_by_type(
1009
- cluster_name, ns["name"], kind
1012
+ (
1013
+ self.ri.get_desired_by_type(cluster_name, ns["name"], kind)
1014
+ or {}
1010
1015
  ).keys()
1011
1016
  )
1012
1017
  diff = desired_items.difference(declared_items)
@@ -1212,7 +1217,7 @@ def _early_exit_fetch_resource(spec: Sequence, settings: Mapping) -> dict[str, s
1212
1217
  c = resource["resource"].get("content")
1213
1218
  del resource["resource"]
1214
1219
  resource[IDENTIFIER_FIELD_NAME] = id
1215
- content_sha = hashlib.md5(c.encode("utf-8")).hexdigest()
1220
+ content_sha = hashlib.md5(str(c).encode("utf-8")).hexdigest()
1216
1221
  return {
1217
1222
  IDENTIFIER_FIELD_NAME: id,
1218
1223
  "cluster": cluster_name,
@@ -2,7 +2,7 @@ import logging
2
2
  import sys
3
3
  import time
4
4
  from collections.abc import Callable, Iterable, Mapping
5
- from typing import Any, cast
5
+ from typing import Any
6
6
 
7
7
  import reconcile.openshift_base as ob
8
8
  import reconcile.openshift_resources_base as orb
@@ -10,8 +10,8 @@ from reconcile.gql_definitions.common.rhcs_provider_settings import (
10
10
  RhcsProviderSettingsV1,
11
11
  )
12
12
  from reconcile.gql_definitions.rhcs.certs import (
13
- NamespaceOpenshiftResourceRhcsCertV1,
14
13
  NamespaceV1,
14
+ OpenshiftResourceRhcsCert,
15
15
  )
16
16
  from reconcile.gql_definitions.rhcs.certs import (
17
17
  query as rhcs_certs_query,
@@ -32,7 +32,12 @@ from reconcile.utils.openshift_resource import (
32
32
  ResourceInventory,
33
33
  base64_encode_secret_field_value,
34
34
  )
35
- from reconcile.utils.rhcsv2_certs import RhcsV2Cert, generate_cert
35
+ from reconcile.utils.rhcsv2_certs import (
36
+ CertificateFormat,
37
+ RhcsV2CertPem,
38
+ RhcsV2CertPkcs12,
39
+ generate_cert,
40
+ )
36
41
  from reconcile.utils.runtime.integration import DesiredStateShardConfig
37
42
  from reconcile.utils.secret_reader import create_secret_reader
38
43
  from reconcile.utils.semver_helper import make_semver
@@ -40,7 +45,6 @@ from reconcile.utils.vault import SecretNotFoundError, VaultClient
40
45
 
41
46
  QONTRACT_INTEGRATION = "openshift-rhcs-certs"
42
47
  QONTRACT_INTEGRATION_VERSION = make_semver(1, 9, 3)
43
- PROVIDERS = ["rhcs-cert"]
44
48
 
45
49
 
46
50
  def desired_state_shard_config() -> DesiredStateShardConfig:
@@ -67,8 +71,29 @@ class OpenshiftRhcsCertExpiration(GaugeMetric):
67
71
  return "qontract_reconcile_rhcs_cert_expiration_timestamp"
68
72
 
69
73
 
70
- def _is_rhcs_cert(obj: Any) -> bool:
71
- return getattr(obj, "provider", None) == "rhcs-cert"
74
+ def _generate_placeholder_cert(
75
+ cert_format: CertificateFormat,
76
+ ) -> RhcsV2CertPem | RhcsV2CertPkcs12:
77
+ match cert_format:
78
+ case CertificateFormat.PKCS12:
79
+ return RhcsV2CertPkcs12(
80
+ pkcs12_keystore="PLACEHOLDER_KEYSTORE",
81
+ pkcs12_truststore="PLACEHOLDER_TRUSTSTORE",
82
+ expiration_timestamp=int(time.time()),
83
+ )
84
+ case CertificateFormat.PEM:
85
+ return RhcsV2CertPem(
86
+ certificate="PLACEHOLDER_CERT",
87
+ private_key="PLACEHOLDER_PRIVATE_KEY",
88
+ ca_cert="PLACEHOLDER_CA_CERT",
89
+ expiration_timestamp=int(time.time()),
90
+ )
91
+
92
+
93
+ def get_certificate_format(
94
+ cert_resource: OpenshiftResourceRhcsCert,
95
+ ) -> CertificateFormat:
96
+ return CertificateFormat(cert_resource.certificate_format or "PEM")
72
97
 
73
98
 
74
99
  def get_namespaces_with_rhcs_certs(
@@ -77,26 +102,33 @@ def get_namespaces_with_rhcs_certs(
77
102
  ) -> list[NamespaceV1]:
78
103
  result: list[NamespaceV1] = []
79
104
  for ns in rhcs_certs_query(query_func=query_func).namespaces or []:
80
- ob.aggregate_shared_resources_typed(cast("Any", ns)) # mypy: ignore[arg-type]
105
+ ob.aggregate_shared_resources_typed(ns)
81
106
  if (
82
107
  integration_is_enabled(QONTRACT_INTEGRATION, ns.cluster)
83
108
  and not bool(ns.delete)
84
109
  and (not cluster_name or ns.cluster.name in cluster_name)
85
- and any(_is_rhcs_cert(r) for r in ns.openshift_resources or [])
110
+ and ns.openshift_resources
86
111
  ):
87
112
  result.append(ns)
88
113
  return result
89
114
 
90
115
 
91
116
  def construct_rhcs_cert_oc_secret(
92
- secret_name: str, cert: Mapping[str, Any], annotations: Mapping[str, str]
117
+ secret_name: str,
118
+ cert: Mapping[str, Any],
119
+ annotations: Mapping[str, str],
120
+ certificate_format: CertificateFormat,
93
121
  ) -> OR:
94
122
  body: dict[str, Any] = {
95
123
  "apiVersion": "v1",
96
124
  "kind": "Secret",
97
- "type": "kubernetes.io/tls",
98
125
  "metadata": {"name": secret_name, "annotations": annotations},
99
126
  }
127
+ match certificate_format:
128
+ case CertificateFormat.PKCS12:
129
+ body["type"] = "Opaque"
130
+ case CertificateFormat.PEM:
131
+ body["type"] = "kubernetes.io/tls"
100
132
  for k, v in cert.items():
101
133
  v = base64_encode_secret_field_value(v)
102
134
  body.setdefault("data", {})[k] = v
@@ -105,7 +137,7 @@ def construct_rhcs_cert_oc_secret(
105
137
 
106
138
  def cert_expires_within_threshold(
107
139
  ns: NamespaceV1,
108
- cert_resource: NamespaceOpenshiftResourceRhcsCertV1,
140
+ cert_resource: OpenshiftResourceRhcsCert,
109
141
  vault_cert_secret: Mapping[str, Any],
110
142
  ) -> bool:
111
143
  auto_renew_threshold_days = cert_resource.auto_renew_threshold_days or 7
@@ -121,13 +153,13 @@ def cert_expires_within_threshold(
121
153
 
122
154
  def get_vault_cert_secret(
123
155
  ns: NamespaceV1,
124
- cert_resource: NamespaceOpenshiftResourceRhcsCertV1,
156
+ cert_resource: OpenshiftResourceRhcsCert,
125
157
  vault: VaultClient,
126
158
  vault_base_path: str,
127
159
  ) -> dict | None:
128
160
  vault_cert_secret = None
129
161
  try:
130
- vault_cert_secret = vault.read_all({ # type: ignore[attr-defined]
162
+ vault_cert_secret = vault.read_all({
131
163
  "path": f"{vault_base_path}/{ns.cluster.name}/{ns.name}/{cert_resource.secret_name}"
132
164
  })
133
165
  except SecretNotFoundError:
@@ -140,7 +172,7 @@ def get_vault_cert_secret(
140
172
  def generate_vault_cert_secret(
141
173
  dry_run: bool,
142
174
  ns: NamespaceV1,
143
- cert_resource: NamespaceOpenshiftResourceRhcsCertV1,
175
+ cert_resource: OpenshiftResourceRhcsCert,
144
176
  vault: VaultClient,
145
177
  vault_base_path: str,
146
178
  issuer_url: str,
@@ -149,18 +181,19 @@ def generate_vault_cert_secret(
149
181
  logging.info(
150
182
  f"Creating cert with service account credentials for '{cert_resource.service_account_name}'. cluster='{ns.cluster.name}', namespace='{ns.name}', secret='{cert_resource.secret_name}'"
151
183
  )
152
- sa_password = vault.read(cert_resource.service_account_password.dict()) # type: ignore[attr-defined]
184
+ sa_password = vault.read(cert_resource.service_account_password.model_dump())
185
+ cert_format = get_certificate_format(cert_resource)
186
+
153
187
  if dry_run:
154
- rhcs_cert = RhcsV2Cert(
155
- certificate="PLACEHOLDER_CERT",
156
- private_key="PLACEHOLDER_PRIVATE_KEY",
157
- ca_cert="PLACEHOLDER_CA_CERT",
158
- expiration_timestamp=int(time.time()),
159
- )
188
+ rhcs_cert = _generate_placeholder_cert(cert_format)
160
189
  else:
161
190
  try:
162
191
  rhcs_cert = generate_cert(
163
- issuer_url, cert_resource.service_account_name, sa_password, ca_cert_url
192
+ issuer_url=issuer_url,
193
+ uid=cert_resource.service_account_name,
194
+ pwd=sa_password,
195
+ ca_url=ca_cert_url,
196
+ cert_format=cert_format,
164
197
  )
165
198
  except ValueError as e:
166
199
  raise Exception(
@@ -169,20 +202,20 @@ def generate_vault_cert_secret(
169
202
  logging.info(
170
203
  f"Writing cert details to Vault at {vault_base_path}/{ns.cluster.name}/{ns.name}/{cert_resource.secret_name}"
171
204
  )
172
- vault.write( # type: ignore[attr-defined]
205
+ vault.write(
173
206
  secret={
174
- "data": rhcs_cert.dict(by_alias=True),
207
+ "data": rhcs_cert.model_dump(by_alias=True, exclude_none=True),
175
208
  "path": f"{vault_base_path}/{ns.cluster.name}/{ns.name}/{cert_resource.secret_name}",
176
209
  },
177
210
  decode_base64=False,
178
211
  )
179
- return rhcs_cert.dict(by_alias=True)
212
+ return rhcs_cert.model_dump(by_alias=True, exclude_none=True)
180
213
 
181
214
 
182
215
  def fetch_openshift_resource_for_cert_resource(
183
216
  dry_run: bool,
184
217
  ns: NamespaceV1,
185
- cert_resource: NamespaceOpenshiftResourceRhcsCertV1,
218
+ cert_resource: OpenshiftResourceRhcsCert,
186
219
  vault: VaultClient,
187
220
  rhcs_settings: RhcsProviderSettingsV1,
188
221
  ) -> OR:
@@ -218,6 +251,7 @@ def fetch_openshift_resource_for_cert_resource(
218
251
  secret_name=cert_resource.secret_name,
219
252
  cert=vault_cert_secret,
220
253
  annotations=cert_resource.annotations or {},
254
+ certificate_format=get_certificate_format(cert_resource),
221
255
  )
222
256
 
223
257
 
@@ -227,22 +261,17 @@ def fetch_desired_state(
227
261
  ri: ResourceInventory,
228
262
  query_func: Callable,
229
263
  ) -> None:
230
- vault = VaultClient()
264
+ vault = VaultClient.get_instance()
231
265
  cert_provider = get_rhcs_provider_settings(query_func=query_func)
232
266
  for ns in namespaces:
233
267
  for cert_resource in ns.openshift_resources or []:
234
- if _is_rhcs_cert(cert_resource):
235
- ri.add_desired_resource(
236
- cluster=ns.cluster.name,
237
- namespace=ns.name,
238
- resource=fetch_openshift_resource_for_cert_resource(
239
- dry_run,
240
- ns,
241
- cast("NamespaceOpenshiftResourceRhcsCertV1", cert_resource),
242
- vault,
243
- cert_provider,
244
- ),
245
- )
268
+ ri.add_desired_resource(
269
+ cluster=ns.cluster.name,
270
+ namespace=ns.name,
271
+ resource=fetch_openshift_resource_for_cert_resource(
272
+ dry_run, ns, cert_resource, vault, cert_provider
273
+ ),
274
+ )
246
275
 
247
276
 
248
277
  @defer
@@ -277,7 +306,7 @@ def run(
277
306
  state_specs = ob.init_specs_to_fetch(
278
307
  ri,
279
308
  oc_map,
280
- namespaces=[ns.dict(by_alias=True) for ns in namespaces],
309
+ namespaces=[ns.model_dump(by_alias=True) for ns in namespaces],
281
310
  override_managed_types=["Secret"],
282
311
  )
283
312
  for spec in state_specs:
@@ -295,3 +324,11 @@ def run(
295
324
  ob.publish_metrics(ri, QONTRACT_INTEGRATION)
296
325
  if ri.has_error_registered():
297
326
  sys.exit(1)
327
+
328
+
329
+ def early_exit_desired_state(*args: Any, **kwargs: Any) -> dict[str, Any]:
330
+ if not (query_func := kwargs.get("query_func")):
331
+ query_func = gql.get_api().query
332
+
333
+ cluster_name = kwargs.get("cluster_name")
334
+ return {"namespace": get_namespaces_with_rhcs_certs(query_func, cluster_name)}