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,58 +1,209 @@
1
- import contextlib
2
1
  import sys
3
- from collections.abc import Callable, Mapping, Sequence
4
- from typing import Any
2
+ from collections.abc import Callable
3
+ from dataclasses import dataclass
4
+ from typing import Any, Self
5
+
6
+ from pydantic.main import BaseModel
5
7
 
6
8
  import reconcile.openshift_base as ob
7
- from reconcile import queries
9
+ from reconcile.gql_definitions.common.app_interface_roles import (
10
+ AccessV1,
11
+ BotV1,
12
+ ClusterV1,
13
+ NamespaceV1,
14
+ RoleV1,
15
+ UserV1,
16
+ )
17
+ from reconcile.gql_definitions.common.namespaces import NamespaceV1 as CommonNamespaceV1
18
+ from reconcile.typed_queries.app_interface_roles import get_app_interface_roles
19
+ from reconcile.typed_queries.namespaces import get_namespaces
8
20
  from reconcile.utils import (
9
21
  expiration,
10
- gql,
11
22
  )
12
23
  from reconcile.utils.constants import DEFAULT_THREAD_POOL_SIZE
13
24
  from reconcile.utils.defer import defer
14
25
  from reconcile.utils.openshift_resource import OpenshiftResource as OR
15
26
  from reconcile.utils.openshift_resource import (
16
27
  ResourceInventory,
17
- ResourceKeyExistsError,
18
28
  )
19
29
  from reconcile.utils.semver_helper import make_semver
20
30
  from reconcile.utils.sharding import is_in_shard
21
31
 
22
- ROLES_QUERY = """
23
- {
24
- roles: roles_v1 {
25
- name
26
- users {
27
- org_username
28
- github_username
29
- }
30
- bots {
31
- openshift_serviceaccount
32
- }
33
- access {
34
- namespace {
35
- name
36
- clusterAdmin
37
- managedRoles
38
- delete
39
- cluster {
40
- name
41
- auth {
42
- service
43
- }
32
+ QONTRACT_INTEGRATION = "openshift-rolebindings"
33
+ QONTRACT_INTEGRATION_VERSION = make_semver(0, 3, 0)
34
+
35
+
36
+ class OCResource(BaseModel, arbitrary_types_allowed=True):
37
+ resource: OR
38
+ resource_name: str
39
+ privileged: bool
40
+
41
+
42
+ @dataclass
43
+ class ServiceAccountSpec:
44
+ sa_namespace_name: str
45
+ sa_name: str
46
+
47
+ @classmethod
48
+ def create_sa_spec(cls, bots: list[BotV1] | None) -> list[Self]:
49
+ return [
50
+ cls(
51
+ sa_namespace_name=full_service_account[0],
52
+ sa_name=full_service_account[1],
53
+ )
54
+ for bot in bots or []
55
+ if bot.openshift_serviceaccount
56
+ and (full_service_account := bot.openshift_serviceaccount.split("/"))
57
+ and len(full_service_account) == 2
58
+ ]
59
+
60
+
61
+ class RoleBindingSpec(BaseModel, validate_by_alias=True, arbitrary_types_allowed=True):
62
+ role_name: str
63
+ role_kind: str
64
+ namespace: NamespaceV1
65
+ cluster: ClusterV1
66
+ privileged: bool
67
+ usernames: set[str]
68
+ openshift_service_accounts: list[ServiceAccountSpec]
69
+
70
+ def get_users_desired_state(self) -> list[dict[str, str]]:
71
+ return [
72
+ {"cluster": self.cluster.name, "user": username}
73
+ for username in self.usernames
74
+ ]
75
+
76
+ @classmethod
77
+ def create_role_binding_spec(
78
+ cls,
79
+ access: AccessV1,
80
+ users: list[UserV1] | None = None,
81
+ enforced_user_keys: list[str] | None = None,
82
+ bots: list[BotV1] | None = None,
83
+ support_role_ref: bool = False,
84
+ ) -> Self | None:
85
+ if not access.namespace:
86
+ return None
87
+ if not (access.role or access.cluster_role):
88
+ return None
89
+ privileged = access.namespace.cluster_admin or False
90
+ auth_dict = [
91
+ auth.model_dump(by_alias=True) for auth in access.namespace.cluster.auth
92
+ ]
93
+ usernames = RoleBindingSpec.get_usernames_from_users(
94
+ users,
95
+ ob.determine_user_keys_for_access(
96
+ access.namespace.cluster.name,
97
+ auth_dict,
98
+ enforced_user_keys,
99
+ ),
100
+ )
101
+ service_accounts = ServiceAccountSpec.create_sa_spec(bots) if bots else []
102
+ role_kind = "Role" if access.role and support_role_ref else "ClusterRole"
103
+ return cls(
104
+ role_name=access.role or access.cluster_role,
105
+ role_kind=role_kind,
106
+ namespace=access.namespace,
107
+ cluster=access.namespace.cluster,
108
+ privileged=privileged,
109
+ usernames=usernames,
110
+ openshift_service_accounts=service_accounts,
111
+ )
112
+
113
+ @classmethod
114
+ def create_rb_specs_from_role(
115
+ cls,
116
+ role: RoleV1,
117
+ enforced_user_keys: list[str] | None = None,
118
+ support_role_ref: bool = False,
119
+ ) -> list[Self]:
120
+ rolebinding_spec_list = [
121
+ role_binding_spec
122
+ for access in role.access or []
123
+ if (
124
+ access.namespace
125
+ and is_valid_namespace(access.namespace)
126
+ and (
127
+ role_binding_spec := cls.create_role_binding_spec(
128
+ access,
129
+ role.users,
130
+ enforced_user_keys,
131
+ role.bots,
132
+ support_role_ref,
133
+ )
134
+ )
135
+ )
136
+ ]
137
+ return rolebinding_spec_list
138
+
139
+ @staticmethod
140
+ def get_usernames_from_users(
141
+ users: list[UserV1] | None = None, user_keys: list[str] | None = None
142
+ ) -> set[str]:
143
+ return {
144
+ name
145
+ for user in users or []
146
+ for user_key in user_keys or []
147
+ if (name := getattr(user, user_key, None))
44
148
  }
45
- }
46
- role
47
- }
48
- expirationDate
49
- }
50
- }
51
- """
52
149
 
150
+ def construct_user_oc_resource(self, user: str) -> OCResource:
151
+ name = f"{self.role_name}-{user}"
152
+ body: dict[str, Any] = {
153
+ "apiVersion": "rbac.authorization.k8s.io/v1",
154
+ "kind": "RoleBinding",
155
+ "metadata": {"name": name},
156
+ "roleRef": {"kind": self.role_kind, "name": self.role_name},
157
+ "subjects": [{"kind": "User", "name": user}],
158
+ }
159
+ return OCResource(
160
+ resource=OR(
161
+ body,
162
+ QONTRACT_INTEGRATION,
163
+ QONTRACT_INTEGRATION_VERSION,
164
+ error_details=name,
165
+ ),
166
+ resource_name=name,
167
+ privileged=self.privileged,
168
+ )
53
169
 
54
- QONTRACT_INTEGRATION = "openshift-rolebindings"
55
- QONTRACT_INTEGRATION_VERSION = make_semver(0, 3, 0)
170
+ def get_oc_resources(self) -> list[OCResource]:
171
+ user_oc_resources = [
172
+ self.construct_user_oc_resource(username) for username in self.usernames
173
+ ]
174
+ sa_oc_resources = [
175
+ self.construct_sa_oc_resource(sa.sa_namespace_name, sa.sa_name)
176
+ for sa in self.openshift_service_accounts
177
+ ]
178
+ return user_oc_resources + sa_oc_resources
179
+
180
+ def construct_sa_oc_resource(
181
+ self, sa_namespace_name: str, sa_name: str
182
+ ) -> OCResource:
183
+ name = f"{self.role_name}-{sa_namespace_name}-{sa_name}"
184
+ body: dict[str, Any] = {
185
+ "apiVersion": "rbac.authorization.k8s.io/v1",
186
+ "kind": "RoleBinding",
187
+ "metadata": {"name": name},
188
+ "roleRef": {"kind": self.role_kind, "name": self.role_name},
189
+ "subjects": [
190
+ {
191
+ "kind": "ServiceAccount",
192
+ "name": sa_name,
193
+ "namespace": sa_namespace_name,
194
+ }
195
+ ],
196
+ }
197
+ return OCResource(
198
+ resource=OR(
199
+ body,
200
+ QONTRACT_INTEGRATION,
201
+ QONTRACT_INTEGRATION_VERSION,
202
+ error_details=name,
203
+ ),
204
+ resource_name=name,
205
+ privileged=self.privileged,
206
+ )
56
207
 
57
208
 
58
209
  def construct_user_oc_resource(role: str, user: str) -> tuple[OR, str]:
@@ -93,116 +244,65 @@ def construct_sa_oc_resource(role: str, namespace: str, sa_name: str) -> tuple[O
93
244
 
94
245
  def fetch_desired_state(
95
246
  ri: ResourceInventory | None,
96
- oc_map: ob.ClusterMap | None,
247
+ support_role_ref: bool = False,
97
248
  enforced_user_keys: list[str] | None = None,
249
+ allowed_clusters: set[str] | None = None,
98
250
  ) -> list[dict[str, str]]:
99
- gqlapi = gql.get_api()
100
- roles_query_result = gqlapi.query(ROLES_QUERY)
101
- if not roles_query_result:
251
+ if allowed_clusters is not None and not allowed_clusters:
102
252
  return []
103
- roles: Sequence[Mapping[str, Any]] = expiration.filter(roles_query_result["roles"])
104
- users_desired_state = []
253
+ roles: list[RoleV1] = expiration.filter(get_app_interface_roles())
254
+ users_desired_state: list[dict[str, str]] = []
105
255
  for role in roles:
106
- permissions = [
107
- {
108
- "cluster": a["namespace"]["cluster"],
109
- "namespace": a["namespace"],
110
- "role": a["role"],
111
- }
112
- for a in role["access"] or []
113
- if a["namespace"]
114
- and a["role"]
115
- and a["namespace"].get("managedRoles")
116
- and not ob.is_namespace_deleted(a["namespace"])
117
- ]
118
- if not permissions:
119
- continue
120
-
121
- service_accounts = [
122
- bot["openshift_serviceaccount"]
123
- for bot in role["bots"]
124
- if bot.get("openshift_serviceaccount")
125
- ]
126
-
127
- for permission in permissions:
128
- cluster_info = permission["cluster"]
129
- cluster = cluster_info["name"]
130
- namespace_info = permission["namespace"]
131
- perm_namespace_name = namespace_info["name"]
132
- privileged = namespace_info.get("clusterAdmin") or False
133
- if not is_in_shard(f"{cluster}/{perm_namespace_name}"):
134
- continue
135
- if oc_map and not oc_map.get(cluster):
256
+ rolebindings: list[RoleBindingSpec] = RoleBindingSpec.create_rb_specs_from_role(
257
+ role, enforced_user_keys, support_role_ref
258
+ )
259
+ if allowed_clusters is not None:
260
+ rolebindings = [
261
+ rolebinding
262
+ for rolebinding in rolebindings
263
+ if rolebinding.cluster.name in allowed_clusters
264
+ ]
265
+ for rolebinding in rolebindings:
266
+ users_desired_state.extend(rolebinding.get_users_desired_state())
267
+ if ri is None:
136
268
  continue
137
-
138
- # get username keys based on used IDPs
139
- user_keys = ob.determine_user_keys_for_access(
140
- cluster,
141
- cluster_info.get("auth") or [],
142
- enforced_user_keys=enforced_user_keys,
143
- )
144
- # create user rolebindings for user * user_keys
145
- for user in role.get("users") or []:
146
- for username in {user.get(key) for key in user_keys}:
147
- if not username:
148
- continue
149
- # used by openshift-users and github integrations
150
- # this is just to simplify things a bit on the their side
151
- users_desired_state.append({"cluster": cluster, "user": username})
152
- if ri is None:
153
- continue
154
- oc_resource, resource_name = construct_user_oc_resource(
155
- permission["role"], username
156
- )
157
- with contextlib.suppress(ResourceKeyExistsError):
158
- # a user may have a Role assigned to them
159
- # from multiple app-interface roles
160
- ri.add_desired(
161
- cluster,
162
- perm_namespace_name,
163
- "RoleBinding.rbac.authorization.k8s.io",
164
- resource_name,
165
- oc_resource,
166
- privileged=privileged,
167
- )
168
-
169
- for sa in service_accounts:
170
- if ri is None:
171
- continue
172
- sa_namespace_name, sa_name = sa.split("/")
173
- oc_resource, resource_name = construct_sa_oc_resource(
174
- permission["role"], sa_namespace_name, sa_name
175
- )
176
- with contextlib.suppress(ResourceKeyExistsError):
177
- # a ServiceAccount may have a Role assigned to it
178
- # from multiple app-interface roles
179
- ri.add_desired(
180
- cluster,
181
- perm_namespace_name,
182
- "RoleBinding.rbac.authorization.k8s.io",
183
- resource_name,
184
- oc_resource,
185
- privileged=privileged,
269
+ for oc_resource in rolebinding.get_oc_resources():
270
+ if not ri.get_desired(
271
+ rolebinding.cluster.name,
272
+ rolebinding.namespace.name,
273
+ "RoleBinding.rbac.authorization.k8s.io",
274
+ oc_resource.resource_name,
275
+ ):
276
+ ri.add_desired_resource(
277
+ cluster=rolebinding.cluster.name,
278
+ namespace=rolebinding.namespace.name,
279
+ resource=oc_resource.resource,
280
+ privileged=oc_resource.privileged,
186
281
  )
187
282
  return users_desired_state
188
283
 
189
284
 
285
+ def is_valid_namespace(namespace: NamespaceV1 | CommonNamespaceV1) -> bool:
286
+ return (
287
+ bool(namespace.managed_roles)
288
+ and is_in_shard(f"{namespace.cluster.name}/{namespace.name}")
289
+ and not ob.is_namespace_deleted(namespace.model_dump(by_alias=True))
290
+ )
291
+
292
+
190
293
  @defer
191
294
  def run(
192
295
  dry_run: bool,
193
296
  thread_pool_size: int = DEFAULT_THREAD_POOL_SIZE,
194
297
  internal: bool | None = None,
195
298
  use_jump_host: bool = True,
299
+ support_role_ref: bool = False,
196
300
  defer: Callable | None = None,
197
301
  ) -> None:
198
302
  namespaces = [
199
- namespace_info
200
- for namespace_info in queries.get_namespaces()
201
- if namespace_info.get("managedRoles")
202
- and is_in_shard(
203
- f"{namespace_info['cluster']['name']}/" + f"{namespace_info['name']}"
204
- )
205
- and not ob.is_namespace_deleted(namespace_info)
303
+ namespace.model_dump(by_alias=True, exclude={"openshift_resources"})
304
+ for namespace in get_namespaces()
305
+ if is_valid_namespace(namespace)
206
306
  ]
207
307
  ri, oc_map = ob.fetch_current_state(
208
308
  namespaces=namespaces,
@@ -215,7 +315,7 @@ def run(
215
315
  )
216
316
  if defer:
217
317
  defer(oc_map.cleanup)
218
- fetch_desired_state(ri, oc_map)
318
+ fetch_desired_state(ri, support_role_ref, allowed_clusters=set(oc_map.clusters()))
219
319
  ob.publish_metrics(ri, QONTRACT_INTEGRATION)
220
320
  ob.realize_data(dry_run, oc_map, ri, thread_pool_size)
221
321
 
@@ -1,4 +1,3 @@
1
- import json
2
1
  import logging
3
2
  import os
4
3
  import sys
@@ -28,6 +27,7 @@ from reconcile.typed_queries.saas_files import (
28
27
  from reconcile.utils.constants import DEFAULT_THREAD_POOL_SIZE
29
28
  from reconcile.utils.defer import defer
30
29
  from reconcile.utils.gitlab_api import GitLabApi
30
+ from reconcile.utils.json import json_dumps
31
31
  from reconcile.utils.openshift_resource import ResourceInventory
32
32
  from reconcile.utils.saasherder import SaasHerder
33
33
  from reconcile.utils.secret_reader import create_secret_reader
@@ -150,7 +150,7 @@ def run(
150
150
  + "when using slack notifications"
151
151
  )
152
152
  slack = slackapi_from_slack_workspace(
153
- saas_file.slack.dict(by_alias=True),
153
+ saas_file.slack.model_dump(by_alias=True),
154
154
  secret_reader,
155
155
  QONTRACT_INTEGRATION,
156
156
  init_usergroups=False,
@@ -224,7 +224,7 @@ def run(
224
224
  default=False,
225
225
  )
226
226
  ri, oc_map = ob.fetch_current_state(
227
- namespaces=[ns.dict(by_alias=True) for ns in saasherder.namespaces],
227
+ namespaces=[ns.model_dump(by_alias=True) for ns in saasherder.namespaces],
228
228
  thread_pool_size=thread_pool_size,
229
229
  integration=QONTRACT_INTEGRATION,
230
230
  integration_version=QONTRACT_INTEGRATION_VERSION,
@@ -319,14 +319,13 @@ def run(
319
319
  openshift_saas_deploy_trigger_upstream_jobs.QONTRACT_INTEGRATION,
320
320
  openshift_saas_deploy_trigger_images.QONTRACT_INTEGRATION,
321
321
  ]
322
- scan = (
322
+ if (
323
323
  not dry_run
324
324
  and len(saas_files) == 1
325
325
  and trigger_integration
326
326
  and trigger_integration in allowed_integration
327
327
  and trigger_reason
328
- )
329
- if scan:
328
+ ):
330
329
  saas_file = saas_files[0]
331
330
  owners = saas_file.app.service_owners or []
332
331
  emails = " ".join([o.email for o in owners])
@@ -346,4 +345,4 @@ def run(
346
345
  if image_auth.auth_server:
347
346
  json_file = os.path.join(io_dir, "dockerconfigjson")
348
347
  with open(json_file, "w", encoding="locale") as f:
349
- f.write(json.dumps(image_auth.get_docker_config_json(), indent=2))
348
+ f.write(json_dumps(image_auth.get_docker_config_json(), indent=2))
@@ -34,7 +34,7 @@ class Definition(BaseModel):
34
34
  class State(BaseModel):
35
35
  saas_file_path: str
36
36
  saas_file_name: str
37
- saas_file_deploy_resources: DeployResourcesV1 | None
37
+ saas_file_deploy_resources: DeployResourcesV1 | None = None
38
38
  resource_template_name: str
39
39
  cluster: str
40
40
  namespace: str
@@ -44,10 +44,10 @@ class State(BaseModel):
44
44
  parameters: dict[str, Any]
45
45
  secret_parameters: dict[str, VaultSecret]
46
46
  saas_file_definitions: Definition
47
- upstream: SaasResourceTemplateTargetUpstreamV1 | None
48
- disable: bool | None
49
- delete: bool | None
50
- target_path: str | None
47
+ upstream: SaasResourceTemplateTargetUpstreamV1 | None = None
48
+ disable: bool | None = None
49
+ delete: bool | None = None
50
+ target_path: str | None = None
51
51
 
52
52
 
53
53
  def osd_run_wrapper(
@@ -213,11 +213,13 @@ def run(
213
213
  saas_file_list = SaasFileList()
214
214
  desired_saas_file_state = collect_state(saas_file_list.saas_files)
215
215
  # compare dicts against dicts which is much faster than comparing BaseModel objects
216
- comparison_saas_file_state_dicts = [s.dict() for s in comparison_saas_file_state]
216
+ comparison_saas_file_state_dicts = [
217
+ s.model_dump() for s in comparison_saas_file_state
218
+ ]
217
219
  saas_file_state_diffs = [
218
220
  s
219
221
  for s in desired_saas_file_state
220
- if s.dict() not in comparison_saas_file_state_dicts
222
+ if s.model_dump() not in comparison_saas_file_state_dicts
221
223
  ]
222
224
  if not saas_file_state_diffs:
223
225
  return
@@ -1,14 +1,11 @@
1
1
  import logging
2
2
  from collections.abc import Callable
3
3
  from datetime import (
4
- UTC,
5
4
  datetime,
6
5
  timedelta,
7
6
  )
8
7
  from typing import Any
9
8
 
10
- from dateutil import parser
11
-
12
9
  from reconcile.gql_definitions.fragments.pipeline_provider_retention import (
13
10
  PipelineProviderRetention,
14
11
  )
@@ -19,6 +16,7 @@ from reconcile.typed_queries.tekton_pipeline_providers import (
19
16
  get_tekton_pipeline_providers,
20
17
  )
21
18
  from reconcile.utils.constants import DEFAULT_THREAD_POOL_SIZE
19
+ from reconcile.utils.datetime_util import from_utc_iso_format, utc_now
22
20
  from reconcile.utils.defer import defer
23
21
  from reconcile.utils.oc_map import (
24
22
  OCLogMsg,
@@ -35,7 +33,7 @@ def within_retention_days(
35
33
  resource: dict[str, Any], days: int, now_date: datetime
36
34
  ) -> bool:
37
35
  metadata = resource["metadata"]
38
- creation_date = parser.parse(metadata["creationTimestamp"])
36
+ creation_date = from_utc_iso_format(metadata["creationTimestamp"])
39
37
  interval = now_date.timestamp() - creation_date.timestamp()
40
38
 
41
39
  return interval < timedelta(days=days).total_seconds()
@@ -69,7 +67,7 @@ def run(
69
67
  use_jump_host: bool = True,
70
68
  defer: Callable | None = None,
71
69
  ) -> None:
72
- now_date = datetime.now(UTC)
70
+ now_date = utc_now()
73
71
  vault_settings = get_app_interface_vault_settings()
74
72
  secret_reader = create_secret_reader(use_vault=vault_settings.vault)
75
73
  pipeline_providers = get_tekton_pipeline_providers()
@@ -87,13 +87,14 @@ def fetch_desired_state(
87
87
  if not namespace.openshift_service_account_tokens:
88
88
  continue
89
89
 
90
- if not (oc := oc_map.get(namespace.cluster.name)):
90
+ oc = oc_map.get(namespace.cluster.name)
91
+ if isinstance(oc, ob.OCLogMsg):
91
92
  logging.log(level=oc.log_level, msg=oc.message)
92
93
  continue
93
94
 
94
95
  for sat in namespace.openshift_service_account_tokens:
95
96
  oc = oc_map.get(sat.namespace.cluster.name)
96
- if not oc:
97
+ if isinstance(oc, ob.OCLogMsg):
97
98
  if oc.log_level >= logging.ERROR:
98
99
  ri.register_error()
99
100
  logging.log(level=oc.log_level, msg=oc.message)
@@ -156,11 +157,11 @@ def write_outputs_to_vault(
156
157
  f"{vault_path}/{integration_name}/{cluster}/{namespace}/{name}"
157
158
  )
158
159
  secret = {"path": secret_path, "data": body_data}
159
- vault_client.write(secret) # type: ignore
160
+ vault_client.write(secret)
160
161
  # write secret to shared-resources location
161
162
  secret_path = f"{vault_path}/{integration_name}/shared-resources/{name}"
162
163
  secret = {"path": secret_path, "data": body_data}
163
- vault_client.write(secret) # type: ignore
164
+ vault_client.write(secret)
164
165
 
165
166
 
166
167
  def canonicalize_namespaces(namespaces: Iterable[NamespaceV1]) -> list[NamespaceV1]:
@@ -176,7 +177,7 @@ def canonicalize_namespaces(namespaces: Iterable[NamespaceV1]) -> list[Namespace
176
177
  key = f"{sat.namespace.cluster.name}/{sat.namespace.name}"
177
178
  if key not in canonicalized_namespaces:
178
179
  canonicalized_namespaces[key] = NamespaceV1(
179
- **sat.namespace.dict(by_alias=True),
180
+ **sat.namespace.model_dump(by_alias=True),
180
181
  sharedResources=None,
181
182
  openshiftServiceAccountTokens=None,
182
183
  )
@@ -216,7 +217,7 @@ def run(
216
217
  get_namespaces_with_serviceaccount_tokens(gql_api.query)
217
218
  )
218
219
  ri, oc_map = ob.fetch_current_state(
219
- namespaces=[ns.dict(by_alias=True) for ns in namespaces],
220
+ namespaces=[ns.model_dump(by_alias=True) for ns in namespaces],
220
221
  thread_pool_size=thread_pool_size,
221
222
  integration=QONTRACT_INTEGRATION,
222
223
  integration_version=QONTRACT_INTEGRATION_VERSION,
@@ -230,7 +231,7 @@ def run(
230
231
  ob.publish_metrics(ri, QONTRACT_INTEGRATION)
231
232
  ob.realize_data(dry_run, oc_map, ri, thread_pool_size)
232
233
  if not dry_run and vault_output_path:
233
- write_outputs_to_vault(VaultClient(), vault_output_path, ri)
234
+ write_outputs_to_vault(VaultClient.get_instance(), vault_output_path, ri)
234
235
 
235
236
  if ri.has_error_registered():
236
237
  sys.exit(1)
@@ -456,7 +456,7 @@ def run(
456
456
 
457
457
  LOG.debug("Adding desired resources to inventory")
458
458
  for desired_resource in desired_resources:
459
- ri.add_desired(**desired_resource)
459
+ ri.add_desired(**desired_resource) # type: ignore
460
460
 
461
461
  LOG.debug("Publishing metrics")
462
462
  ob.publish_metrics(ri, QONTRACT_INTEGRATION)
@@ -3,7 +3,6 @@ from collections.abc import (
3
3
  Callable,
4
4
  Iterable,
5
5
  )
6
- from datetime import datetime
7
6
 
8
7
  from reconcile import queries
9
8
  from reconcile.gql_definitions.common.clusters import ClusterV1
@@ -13,6 +12,7 @@ from reconcile.typed_queries.app_interface_vault_settings import (
13
12
  )
14
13
  from reconcile.typed_queries.clusters import get_clusters
15
14
  from reconcile.utils.constants import DEFAULT_THREAD_POOL_SIZE
15
+ from reconcile.utils.datetime_util import from_utc_iso_format, utc_now
16
16
  from reconcile.utils.defer import defer
17
17
  from reconcile.utils.oc_map import (
18
18
  OCLogMsg,
@@ -101,7 +101,7 @@ def notify_upgrades_start(
101
101
  state: State,
102
102
  slack: SlackApi | None,
103
103
  ) -> None:
104
- now = datetime.utcnow()
104
+ now = utc_now()
105
105
  for cluster in clusters:
106
106
  if cluster.spec and not cluster.spec.hypershift:
107
107
  upgrade_at, version = _get_start_osd(oc_map, cluster.name)
@@ -113,7 +113,7 @@ def notify_upgrades_start(
113
113
  continue
114
114
 
115
115
  if upgrade_at and version:
116
- upgrade_at_obj = datetime.strptime(upgrade_at, "%Y-%m-%dT%H:%M:%SZ")
116
+ upgrade_at_obj = from_utc_iso_format(upgrade_at)
117
117
  state_key = f"{cluster.name}-{upgrade_at}1"
118
118
  # if this is the first iteration in which 'now' had passed
119
119
  # the upgrade at date time, we send a notification
@@ -185,7 +185,7 @@ def run(
185
185
  if defer:
186
186
  defer(oc_map.cleanup)
187
187
 
188
- cluster_like_objects = [cluster.dict(by_alias=True) for cluster in clusters]
188
+ cluster_like_objects = [cluster.model_dump(by_alias=True) for cluster in clusters]
189
189
  ocm_map = OCMMap(
190
190
  clusters=cluster_like_objects,
191
191
  integration=QONTRACT_INTEGRATION,
@@ -101,14 +101,16 @@ def fetch_desired_state(
101
101
  oc_map: OCMap | None, enforced_user_keys: Any = None
102
102
  ) -> list[Any]:
103
103
  desired_state = []
104
-
104
+ filtered_clusters = oc_map.clusters() if oc_map else None
105
105
  flat_rolebindings_desired_state = openshift_rolebindings.fetch_desired_state(
106
- ri=None, oc_map=oc_map, enforced_user_keys=enforced_user_keys
106
+ ri=None,
107
+ enforced_user_keys=enforced_user_keys,
108
+ allowed_clusters=set(filtered_clusters) if filtered_clusters else None,
107
109
  )
108
110
  desired_state.extend(flat_rolebindings_desired_state)
109
111
 
110
112
  groups_desired_state = openshift_groups.fetch_desired_state(
111
- clusters=oc_map.clusters() if oc_map else [],
113
+ clusters=filtered_clusters or [],
112
114
  enforced_user_keys=enforced_user_keys,
113
115
  )
114
116
  flat_groups_desired_state = [