qontract-reconcile 0.10.2.dev361__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 (351) hide show
  1. {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/METADATA +13 -12
  2. {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/RECORD +351 -345
  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_iam_keys.py +1 -0
  19. reconcile/aws_saml_idp/integration.py +12 -4
  20. reconcile/aws_saml_roles/integration.py +30 -23
  21. reconcile/aws_version_sync/integration.py +6 -12
  22. reconcile/change_owners/bundle.py +3 -3
  23. reconcile/change_owners/change_log_tracking.py +3 -2
  24. reconcile/change_owners/change_owners.py +1 -1
  25. reconcile/change_owners/diff.py +0 -2
  26. reconcile/checkpoint.py +11 -3
  27. reconcile/cli.py +93 -10
  28. reconcile/dashdotdb_dora.py +5 -12
  29. reconcile/dashdotdb_slo.py +1 -1
  30. reconcile/database_access_manager.py +123 -117
  31. reconcile/dynatrace_token_provider/integration.py +1 -1
  32. reconcile/endpoints_discovery/integration.py +4 -1
  33. reconcile/endpoints_discovery/merge_request.py +1 -1
  34. reconcile/endpoints_discovery/merge_request_manager.py +8 -8
  35. reconcile/external_resources/factories.py +4 -6
  36. reconcile/external_resources/integration.py +1 -1
  37. reconcile/external_resources/manager.py +8 -6
  38. reconcile/external_resources/meta.py +0 -1
  39. reconcile/external_resources/metrics.py +1 -1
  40. reconcile/external_resources/model.py +19 -15
  41. reconcile/external_resources/reconciler.py +7 -4
  42. reconcile/external_resources/secrets_sync.py +4 -7
  43. reconcile/external_resources/state.py +26 -16
  44. reconcile/fleet_labeler/integration.py +1 -1
  45. reconcile/gabi_authorized_users.py +5 -2
  46. reconcile/gcp_image_mirror.py +2 -2
  47. reconcile/github_org.py +1 -1
  48. reconcile/github_owners.py +4 -0
  49. reconcile/gitlab_housekeeping.py +13 -15
  50. reconcile/gitlab_members.py +6 -12
  51. reconcile/gitlab_owners.py +15 -11
  52. reconcile/gitlab_permissions.py +8 -12
  53. reconcile/glitchtip_project_alerts/integration.py +3 -1
  54. reconcile/gql_definitions/acs/acs_instances.py +5 -5
  55. reconcile/gql_definitions/acs/acs_policies.py +5 -5
  56. reconcile/gql_definitions/acs/acs_rbac.py +5 -5
  57. reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +5 -5
  58. reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +5 -5
  59. reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +5 -5
  60. reconcile/gql_definitions/app_sre_tekton_access_revalidation/roles.py +5 -5
  61. reconcile/gql_definitions/app_sre_tekton_access_revalidation/users.py +5 -5
  62. reconcile/gql_definitions/automated_actions/instance.py +46 -7
  63. reconcile/gql_definitions/aws_account_manager/aws_accounts.py +5 -5
  64. reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +15 -5
  65. reconcile/gql_definitions/aws_cloudwatch_log_retention/aws_accounts.py +27 -66
  66. reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +15 -5
  67. reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +15 -5
  68. reconcile/gql_definitions/aws_saml_roles/roles.py +5 -5
  69. reconcile/gql_definitions/aws_version_sync/clusters.py +5 -5
  70. reconcile/gql_definitions/aws_version_sync/namespaces.py +5 -5
  71. reconcile/gql_definitions/change_owners/queries/change_types.py +5 -5
  72. reconcile/gql_definitions/change_owners/queries/self_service_roles.py +5 -5
  73. reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +5 -5
  74. reconcile/gql_definitions/common/alerting_services_settings.py +5 -5
  75. reconcile/gql_definitions/common/app_code_component_repos.py +5 -5
  76. reconcile/gql_definitions/common/app_interface_custom_messages.py +5 -5
  77. reconcile/gql_definitions/common/app_interface_dms_settings.py +5 -5
  78. reconcile/gql_definitions/common/app_interface_repo_settings.py +5 -5
  79. reconcile/gql_definitions/common/app_interface_roles.py +5 -5
  80. reconcile/gql_definitions/common/app_interface_state_settings.py +5 -5
  81. reconcile/gql_definitions/common/app_interface_vault_settings.py +5 -5
  82. reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +5 -5
  83. reconcile/gql_definitions/common/apps.py +5 -5
  84. reconcile/gql_definitions/common/aws_vpc_requests.py +15 -5
  85. reconcile/gql_definitions/common/aws_vpcs.py +5 -5
  86. reconcile/gql_definitions/common/clusters.py +5 -5
  87. reconcile/gql_definitions/common/clusters_minimal.py +5 -5
  88. reconcile/gql_definitions/common/clusters_with_dms.py +5 -5
  89. reconcile/gql_definitions/common/clusters_with_peering.py +5 -5
  90. reconcile/gql_definitions/common/github_orgs.py +5 -5
  91. reconcile/gql_definitions/common/jira_settings.py +5 -5
  92. reconcile/gql_definitions/common/jiralert_settings.py +5 -5
  93. reconcile/gql_definitions/common/ldap_settings.py +5 -5
  94. reconcile/gql_definitions/common/namespaces.py +5 -5
  95. reconcile/gql_definitions/common/namespaces_minimal.py +7 -5
  96. reconcile/gql_definitions/common/ocm_env_telemeter.py +5 -5
  97. reconcile/gql_definitions/common/ocm_environments.py +5 -5
  98. reconcile/gql_definitions/common/pagerduty_instances.py +5 -5
  99. reconcile/gql_definitions/common/pgp_reencryption_settings.py +5 -5
  100. reconcile/gql_definitions/common/pipeline_providers.py +5 -5
  101. reconcile/gql_definitions/common/quay_instances.py +5 -5
  102. reconcile/gql_definitions/common/quay_orgs.py +5 -5
  103. reconcile/gql_definitions/common/reserved_networks.py +5 -5
  104. reconcile/gql_definitions/common/rhcs_provider_settings.py +5 -5
  105. reconcile/gql_definitions/common/saas_files.py +5 -5
  106. reconcile/gql_definitions/common/saas_target_namespaces.py +5 -5
  107. reconcile/gql_definitions/common/saasherder_settings.py +5 -5
  108. reconcile/gql_definitions/common/slack_workspaces.py +5 -5
  109. reconcile/gql_definitions/common/smtp_client_settings.py +5 -5
  110. reconcile/gql_definitions/common/state_aws_account.py +5 -5
  111. reconcile/gql_definitions/common/users.py +5 -5
  112. reconcile/gql_definitions/common/users_with_paths.py +5 -5
  113. reconcile/gql_definitions/cost_report/app_names.py +5 -5
  114. reconcile/gql_definitions/cost_report/cost_namespaces.py +5 -5
  115. reconcile/gql_definitions/cost_report/settings.py +5 -5
  116. reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +5 -5
  117. reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +5 -5
  118. reconcile/gql_definitions/dynatrace_token_provider/token_specs.py +5 -5
  119. reconcile/gql_definitions/email_sender/apps.py +5 -5
  120. reconcile/gql_definitions/email_sender/emails.py +5 -5
  121. reconcile/gql_definitions/email_sender/users.py +5 -5
  122. reconcile/gql_definitions/endpoints_discovery/apps.py +5 -5
  123. reconcile/gql_definitions/external_resources/aws_accounts.py +5 -5
  124. reconcile/gql_definitions/external_resources/external_resources_modules.py +5 -5
  125. reconcile/gql_definitions/external_resources/external_resources_namespaces.py +33 -6
  126. reconcile/gql_definitions/external_resources/external_resources_settings.py +5 -5
  127. reconcile/gql_definitions/external_resources/fragments/external_resources_module_overrides.py +5 -5
  128. reconcile/gql_definitions/fleet_labeler/fleet_labels.py +5 -5
  129. reconcile/gql_definitions/fragments/aus_organization.py +5 -5
  130. reconcile/gql_definitions/fragments/aws_account_common.py +7 -5
  131. reconcile/gql_definitions/fragments/aws_account_managed.py +5 -5
  132. reconcile/gql_definitions/fragments/aws_account_sso.py +5 -5
  133. reconcile/gql_definitions/fragments/aws_infra_management_account.py +5 -5
  134. reconcile/gql_definitions/fragments/aws_organization.py +33 -0
  135. reconcile/gql_definitions/fragments/aws_vpc.py +5 -5
  136. reconcile/gql_definitions/fragments/aws_vpc_request.py +7 -5
  137. reconcile/gql_definitions/fragments/container_image_mirror.py +5 -5
  138. reconcile/gql_definitions/fragments/deploy_resources.py +5 -5
  139. reconcile/gql_definitions/fragments/disable.py +5 -5
  140. reconcile/gql_definitions/fragments/email_service.py +5 -5
  141. reconcile/gql_definitions/fragments/email_user.py +5 -5
  142. reconcile/gql_definitions/fragments/jumphost_common_fields.py +5 -5
  143. reconcile/gql_definitions/fragments/membership_source.py +5 -5
  144. reconcile/gql_definitions/fragments/minimal_ocm_organization.py +5 -5
  145. reconcile/gql_definitions/fragments/oc_connection_cluster.py +5 -5
  146. reconcile/gql_definitions/fragments/ocm_environment.py +5 -5
  147. reconcile/gql_definitions/fragments/pipeline_provider_retention.py +5 -5
  148. reconcile/gql_definitions/fragments/prometheus_instance.py +5 -5
  149. reconcile/gql_definitions/fragments/resource_limits_requirements.py +5 -5
  150. reconcile/gql_definitions/fragments/resource_requests_requirements.py +5 -5
  151. reconcile/gql_definitions/fragments/resource_values.py +5 -5
  152. reconcile/gql_definitions/fragments/saas_slo_document.py +5 -5
  153. reconcile/gql_definitions/fragments/saas_target_namespace.py +5 -5
  154. reconcile/gql_definitions/fragments/serviceaccount_token.py +5 -5
  155. reconcile/gql_definitions/fragments/terraform_state.py +5 -5
  156. reconcile/gql_definitions/fragments/upgrade_policy.py +5 -5
  157. reconcile/gql_definitions/fragments/user.py +5 -5
  158. reconcile/gql_definitions/fragments/vault_secret.py +5 -5
  159. reconcile/gql_definitions/gcp/gcp_docker_repos.py +5 -5
  160. reconcile/gql_definitions/gcp/gcp_projects.py +5 -5
  161. reconcile/gql_definitions/gitlab_members/gitlab_instances.py +5 -5
  162. reconcile/gql_definitions/gitlab_members/permissions.py +5 -5
  163. reconcile/gql_definitions/glitchtip/glitchtip_instance.py +5 -5
  164. reconcile/gql_definitions/glitchtip/glitchtip_project.py +5 -5
  165. reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +5 -5
  166. reconcile/gql_definitions/integrations/integrations.py +5 -5
  167. reconcile/gql_definitions/introspection.json +724 -129
  168. reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +5 -5
  169. reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +5 -5
  170. reconcile/gql_definitions/jira/jira_servers.py +5 -5
  171. reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +9 -5
  172. reconcile/gql_definitions/jumphosts/jumphosts.py +5 -5
  173. reconcile/gql_definitions/ldap_groups/roles.py +5 -5
  174. reconcile/gql_definitions/ldap_groups/settings.py +5 -5
  175. reconcile/gql_definitions/maintenance/maintenances.py +5 -5
  176. reconcile/gql_definitions/membershipsources/roles.py +5 -5
  177. reconcile/gql_definitions/ocm_labels/clusters.py +5 -5
  178. reconcile/gql_definitions/ocm_labels/organizations.py +5 -5
  179. reconcile/gql_definitions/openshift_cluster_bots/clusters.py +5 -5
  180. reconcile/gql_definitions/openshift_groups/managed_groups.py +5 -5
  181. reconcile/gql_definitions/openshift_groups/managed_roles.py +5 -5
  182. reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +5 -5
  183. reconcile/gql_definitions/quay_membership/quay_membership.py +5 -5
  184. reconcile/gql_definitions/rhcs/certs.py +25 -79
  185. reconcile/gql_definitions/rhcs/openshift_resource_rhcs_cert.py +43 -0
  186. reconcile/gql_definitions/rhidp/organizations.py +5 -5
  187. reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +5 -5
  188. reconcile/gql_definitions/service_dependencies/service_dependencies.py +5 -5
  189. reconcile/gql_definitions/sharding/aws_accounts.py +5 -5
  190. reconcile/gql_definitions/sharding/ocm_organization.py +5 -5
  191. reconcile/gql_definitions/skupper_network/site_controller_template.py +5 -5
  192. reconcile/gql_definitions/skupper_network/skupper_networks.py +5 -5
  193. reconcile/gql_definitions/slack_usergroups/clusters.py +5 -5
  194. reconcile/gql_definitions/slack_usergroups/permissions.py +5 -5
  195. reconcile/gql_definitions/slack_usergroups/users.py +5 -5
  196. reconcile/gql_definitions/slo_documents/slo_documents.py +5 -5
  197. reconcile/gql_definitions/status_board/status_board.py +5 -5
  198. reconcile/gql_definitions/statuspage/statuspages.py +5 -5
  199. reconcile/gql_definitions/templating/template_collection.py +5 -5
  200. reconcile/gql_definitions/templating/templates.py +5 -5
  201. reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +5 -5
  202. reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +5 -5
  203. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +5 -5
  204. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +5 -5
  205. reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +5 -5
  206. reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +5 -5
  207. reconcile/gql_definitions/terraform_init/aws_accounts.py +19 -5
  208. reconcile/gql_definitions/terraform_repo/terraform_repo.py +5 -5
  209. reconcile/gql_definitions/terraform_resources/database_access_manager.py +5 -5
  210. reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +30 -6
  211. reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +15 -5
  212. reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +5 -5
  213. reconcile/gql_definitions/vault_instances/vault_instances.py +5 -5
  214. reconcile/gql_definitions/vault_policies/vault_policies.py +5 -5
  215. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +5 -5
  216. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +5 -5
  217. reconcile/integrations_manager.py +3 -3
  218. reconcile/jenkins_worker_fleets.py +10 -8
  219. reconcile/jira_permissions_validator.py +237 -122
  220. reconcile/ldap_groups/integration.py +1 -1
  221. reconcile/ocm/types.py +35 -57
  222. reconcile/ocm_aws_infrastructure_access.py +1 -1
  223. reconcile/ocm_clusters.py +4 -4
  224. reconcile/ocm_labels/integration.py +3 -2
  225. reconcile/ocm_machine_pools.py +33 -27
  226. reconcile/openshift_base.py +113 -4
  227. reconcile/openshift_cluster_bots.py +1 -1
  228. reconcile/openshift_namespace_labels.py +1 -1
  229. reconcile/openshift_namespaces.py +97 -101
  230. reconcile/openshift_resources_base.py +6 -2
  231. reconcile/openshift_rhcs_certs.py +74 -37
  232. reconcile/openshift_rolebindings.py +7 -11
  233. reconcile/openshift_saas_deploy.py +4 -5
  234. reconcile/openshift_saas_deploy_change_tester.py +9 -7
  235. reconcile/openshift_saas_deploy_trigger_cleaner.py +3 -5
  236. reconcile/openshift_serviceaccount_tokens.py +2 -2
  237. reconcile/openshift_upgrade_watcher.py +4 -4
  238. reconcile/oum/labelset.py +5 -3
  239. reconcile/oum/models.py +1 -4
  240. reconcile/prometheus_rules_tester/integration.py +3 -3
  241. reconcile/quay_mirror.py +1 -1
  242. reconcile/queries.py +131 -0
  243. reconcile/rhidp/common.py +3 -5
  244. reconcile/rhidp/sso_client/base.py +16 -5
  245. reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +1 -1
  246. reconcile/saas_auto_promotions_manager/subscriber.py +4 -3
  247. reconcile/skupper_network/integration.py +2 -2
  248. reconcile/slack_usergroups.py +35 -14
  249. reconcile/sql_query.py +1 -0
  250. reconcile/status_board.py +6 -6
  251. reconcile/statuspage/atlassian.py +7 -7
  252. reconcile/statuspage/integrations/maintenances.py +4 -3
  253. reconcile/statuspage/page.py +4 -9
  254. reconcile/statuspage/status.py +5 -8
  255. reconcile/templating/lib/rendering.py +3 -3
  256. reconcile/templating/renderer.py +2 -2
  257. reconcile/terraform_aws_route53.py +7 -1
  258. reconcile/terraform_cloudflare_dns.py +3 -3
  259. reconcile/terraform_cloudflare_resources.py +5 -5
  260. reconcile/terraform_cloudflare_users.py +3 -2
  261. reconcile/terraform_init/integration.py +187 -23
  262. reconcile/terraform_repo.py +16 -12
  263. reconcile/terraform_resources.py +6 -6
  264. reconcile/terraform_tgw_attachments.py +27 -19
  265. reconcile/terraform_users.py +7 -0
  266. reconcile/terraform_vpc_peerings.py +14 -3
  267. reconcile/terraform_vpc_resources/integration.py +10 -1
  268. reconcile/typed_queries/aws_account_tags.py +41 -0
  269. reconcile/typed_queries/cost_report/app_names.py +1 -1
  270. reconcile/typed_queries/cost_report/cost_namespaces.py +2 -2
  271. reconcile/typed_queries/saas_files.py +11 -11
  272. reconcile/typed_queries/status_board.py +2 -2
  273. reconcile/unleash_feature_toggles/integration.py +4 -2
  274. reconcile/utils/acs/base.py +6 -3
  275. reconcile/utils/acs/policies.py +2 -2
  276. reconcile/utils/aws_api.py +51 -20
  277. reconcile/utils/aws_api_typed/api.py +38 -9
  278. reconcile/utils/aws_api_typed/cloudformation.py +149 -0
  279. reconcile/utils/aws_api_typed/logs.py +73 -0
  280. reconcile/utils/aws_api_typed/organization.py +4 -2
  281. reconcile/utils/binary.py +7 -12
  282. reconcile/utils/datetime_util.py +67 -0
  283. reconcile/utils/deadmanssnitch_api.py +1 -1
  284. reconcile/utils/differ.py +2 -3
  285. reconcile/utils/early_exit_cache.py +11 -12
  286. reconcile/utils/expiration.py +7 -3
  287. reconcile/utils/filtering.py +1 -1
  288. reconcile/utils/gitlab_api.py +7 -5
  289. reconcile/utils/glitchtip/client.py +6 -2
  290. reconcile/utils/glitchtip/models.py +25 -28
  291. reconcile/utils/gql.py +4 -7
  292. reconcile/utils/helpers.py +1 -1
  293. reconcile/utils/instrumented_wrappers.py +1 -1
  294. reconcile/utils/internal_groups/client.py +2 -2
  295. reconcile/utils/internal_groups/models.py +8 -17
  296. reconcile/utils/jinja2/utils.py +6 -101
  297. reconcile/utils/jira_client.py +82 -63
  298. reconcile/utils/jjb_client.py +7 -10
  299. reconcile/utils/jobcontroller/controller.py +2 -2
  300. reconcile/utils/jobcontroller/models.py +17 -1
  301. reconcile/utils/json.py +43 -1
  302. reconcile/utils/membershipsources/app_interface_resolver.py +4 -2
  303. reconcile/utils/membershipsources/models.py +16 -23
  304. reconcile/utils/membershipsources/resolver.py +4 -2
  305. reconcile/utils/merge_request_manager/merge_request_manager.py +4 -4
  306. reconcile/utils/merge_request_manager/parser.py +6 -6
  307. reconcile/utils/metrics.py +5 -5
  308. reconcile/utils/models.py +304 -82
  309. reconcile/utils/mr/app_interface_reporter.py +2 -2
  310. reconcile/utils/mr/notificator.py +3 -3
  311. reconcile/utils/mr/update_access_report_base.py +3 -4
  312. reconcile/utils/mr/user_maintenance.py +3 -2
  313. reconcile/utils/oc.py +246 -201
  314. reconcile/utils/oc_filters.py +3 -3
  315. reconcile/utils/ocm/addons.py +0 -1
  316. reconcile/utils/ocm/base.py +17 -20
  317. reconcile/utils/ocm/cluster_groups.py +1 -1
  318. reconcile/utils/ocm/identity_providers.py +2 -2
  319. reconcile/utils/ocm/labels.py +1 -1
  320. reconcile/utils/ocm/products.py +8 -8
  321. reconcile/utils/ocm/search_filters.py +3 -6
  322. reconcile/utils/ocm/service_log.py +4 -6
  323. reconcile/utils/ocm/sre_capability_labels.py +20 -13
  324. reconcile/utils/openshift_resource.py +8 -3
  325. reconcile/utils/pagerduty_api.py +10 -7
  326. reconcile/utils/promotion_state.py +6 -11
  327. reconcile/utils/raw_github_api.py +1 -1
  328. reconcile/utils/rhcsv2_certs.py +86 -23
  329. reconcile/utils/rosa/session.py +16 -0
  330. reconcile/utils/runtime/integration.py +2 -3
  331. reconcile/utils/runtime/runner.py +2 -2
  332. reconcile/utils/saasherder/interfaces.py +13 -20
  333. reconcile/utils/saasherder/models.py +23 -20
  334. reconcile/utils/saasherder/saasherder.py +50 -27
  335. reconcile/utils/slack_api.py +2 -2
  336. reconcile/utils/sloth.py +171 -2
  337. reconcile/utils/structs.py +1 -1
  338. reconcile/utils/terraform_client.py +5 -4
  339. reconcile/utils/terrascript_aws_client.py +134 -74
  340. reconcile/utils/unleash/server.py +2 -8
  341. reconcile/utils/vault.py +5 -12
  342. reconcile/utils/vcs.py +8 -8
  343. reconcile/vault_replication.py +107 -42
  344. tools/app_interface_reporter.py +4 -4
  345. tools/cli_commands/cost_report/cost_management_api.py +3 -3
  346. tools/cli_commands/cost_report/view.py +7 -6
  347. tools/cli_commands/erv2.py +1 -1
  348. tools/qontract_cli.py +28 -17
  349. tools/template_validation.py +3 -1
  350. {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/WHEEL +0 -0
  351. {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/entry_points.txt +0 -0
reconcile/acs_rbac.py CHANGED
@@ -65,7 +65,7 @@ class AcsRole(BaseModel):
65
65
  assignments: list[AssignmentPair]
66
66
  permission_set_name: str
67
67
  access_scope: AcsAccessScope
68
- system_default: bool | None
68
+ system_default: bool | None = None
69
69
 
70
70
  @classmethod
71
71
  def build(cls, permission: Permission, usernames: list[str]) -> Self:
@@ -151,7 +151,7 @@ class AcsRbacIntegration(QontractReconcileIntegration[NoParams]):
151
151
  for permission in role.oidc_permissions or []:
152
152
  if isinstance(permission, OidcPermissionAcsV1):
153
153
  permission_usernames[
154
- Permission(**permission.dict(by_alias=True))
154
+ Permission(**permission.model_dump(by_alias=True))
155
155
  ].append(user.org_username)
156
156
  return list(starmap(AcsRole.build, permission_usernames.items()))
157
157
 
@@ -1,13 +1,13 @@
1
1
  import logging
2
2
  from collections import defaultdict
3
3
  from datetime import timedelta
4
- from typing import Optional
4
+ from typing import Annotated, Optional
5
5
 
6
6
  from pydantic import (
7
7
  BaseModel,
8
8
  Field,
9
9
  ValidationError,
10
- validator,
10
+ field_validator,
11
11
  )
12
12
  from pydantic.dataclasses import dataclass
13
13
 
@@ -75,8 +75,10 @@ from reconcile.utils.ocm_base_client import (
75
75
  OCMBaseClient,
76
76
  init_ocm_base_client,
77
77
  )
78
+ from reconcile.utils.semver_helper import make_semver
78
79
 
79
80
  QONTRACT_INTEGRATION = "advanced-upgrade-scheduler"
81
+ QONTRACT_INTEGRATION_VERSION = make_semver(0, 1, 0)
80
82
 
81
83
 
82
84
  class AdvancedUpgradeServiceIntegration(OCMClusterUpgradeSchedulerOrgIntegration):
@@ -289,13 +291,16 @@ class OrganizationLabelSet(BaseModel):
289
291
 
290
292
  blocked_versions: CSV | None = Field(alias=aus_label_key("blocked-versions"))
291
293
 
292
- sector_max_parallel_upgrades: dict[str, str] = labelset_groupfield(
293
- group_prefix=aus_label_key("sector-max-parallel-upgrades.")
294
- )
294
+ sector_max_parallel_upgrades: Annotated[
295
+ dict[str, str],
296
+ labelset_groupfield(
297
+ group_prefix=aus_label_key("sector-max-parallel-upgrades.")
298
+ ),
299
+ ]
295
300
 
296
- sector_deps: dict[str, CSV] = labelset_groupfield(
297
- group_prefix=aus_label_key("sector-deps.")
298
- )
301
+ sector_deps: Annotated[
302
+ dict[str, CSV], labelset_groupfield(group_prefix=aus_label_key("sector-deps."))
303
+ ]
299
304
  """
300
305
  Each sector with dependencies is represented as a `sector-deps.<sector-name>` label
301
306
  with a CSV formatted list of dependant sectors. The custom `labelset_groupfield``
@@ -357,7 +362,7 @@ def _build_org_upgrade_spec(
357
362
  ]
358
363
 
359
364
  org_labelset = build_labelset(org_labels, OrganizationLabelSet)
360
- final_org = org.copy(deep=True)
365
+ final_org = org.model_copy(deep=True)
361
366
  final_org.blocked_versions = org_labelset.blocked_versions # type: ignore
362
367
  final_org.sectors = org_labelset.sector_dependencies()
363
368
  final_org.inherit_version_data = inherit_version_data
@@ -375,6 +380,7 @@ def _build_org_upgrade_spec(
375
380
  org=org_upgrade_spec.org,
376
381
  upgradePolicy=upgrade_policy,
377
382
  cluster=c.ocm_cluster,
383
+ cluster_labels=c.labels,
378
384
  health=cluster_health,
379
385
  nodePools=node_pool_specs_by_cluster_id.get(c.ocm_cluster.id) or [],
380
386
  )
@@ -411,7 +417,7 @@ class ClusterUpgradePolicyLabelSet(BaseModel):
411
417
  """
412
418
 
413
419
  soak_days: int = Field(alias=aus_label_key("soak-days"), ge=0)
414
- workloads: CSV = Field(alias=aus_label_key("workloads"), csv_min_items=1)
420
+ workloads: CSV = Field(alias=aus_label_key("workloads"), min_length=1)
415
421
  schedule: str = Field(alias=aus_label_key("schedule"))
416
422
  mutexes: CSV | None = Field(alias=aus_label_key("mutexes"))
417
423
  sector: str | None = Field(alias=aus_label_key("sector"))
@@ -419,14 +425,14 @@ class ClusterUpgradePolicyLabelSet(BaseModel):
419
425
  version_gate_approvals: CSV | None = Field(
420
426
  alias=aus_label_key("version-gate-approvals")
421
427
  )
422
- _schedule_validator = validator("schedule", allow_reuse=True)(cron_validator)
428
+ _schedule_validator = field_validator("schedule")(cron_validator)
423
429
 
424
430
  def build_labels_dict(self) -> dict[str, str]:
425
431
  """
426
432
  Build a dictionary of all labels in this labelset.
427
433
  """
428
434
  labels = {}
429
- for k, v in self.dict(by_alias=True).items():
435
+ for k, v in self.model_dump(by_alias=True).items():
430
436
  if v is None:
431
437
  continue
432
438
  if isinstance(v, list):
reconcile/aus/base.py CHANGED
@@ -1,4 +1,3 @@
1
- import datetime as dt
2
1
  import logging
3
2
  import sys
4
3
  from abc import (
@@ -17,7 +16,7 @@ from typing import (
17
16
  )
18
17
 
19
18
  from croniter import croniter
20
- from pydantic import BaseModel, Extra
19
+ from pydantic import BaseModel
21
20
  from requests.exceptions import HTTPError
22
21
  from semver import VersionInfo
23
22
 
@@ -47,7 +46,7 @@ from reconcile.aus.models import (
47
46
  OrganizationUpgradeSpec,
48
47
  Sector,
49
48
  )
50
- from reconcile.aus.version_gates import HANDLERS
49
+ from reconcile.aus.version_gates import HANDLERS, sts_version_gate_handler
51
50
  from reconcile.gql_definitions.advanced_upgrade_service.aus_organization import (
52
51
  query as aus_organizations_query,
53
52
  )
@@ -71,10 +70,18 @@ from reconcile.utils.clusterhealth.telemeter import (
71
70
  TELEMETER_SOURCE,
72
71
  TelemeterClusterHealthProvider,
73
72
  )
73
+ from reconcile.utils.datetime_util import (
74
+ ensure_utc,
75
+ from_utc_iso_format,
76
+ to_utc_seconds_iso_format,
77
+ utc_now,
78
+ )
74
79
  from reconcile.utils.defer import defer
75
80
  from reconcile.utils.disabled_integrations import integration_is_enabled
76
81
  from reconcile.utils.filtering import remove_none_values_from_dict
82
+ from reconcile.utils.jobcontroller.controller import build_job_controller
77
83
  from reconcile.utils.ocm.addons import AddonService, AddonServiceV1, AddonServiceV2
84
+ from reconcile.utils.ocm.base import LabelContainer
78
85
  from reconcile.utils.ocm.clusters import (
79
86
  OCMCluster,
80
87
  )
@@ -97,6 +104,7 @@ from reconcile.utils.runtime.integration import (
97
104
  PydanticRunParams,
98
105
  QontractReconcileIntegration,
99
106
  )
107
+ from reconcile.utils.secret_reader import SecretReaderBase
100
108
  from reconcile.utils.semver_helper import (
101
109
  get_version_prefix,
102
110
  parse_semver,
@@ -105,6 +113,18 @@ from reconcile.utils.semver_helper import (
105
113
  from reconcile.utils.state import init_state
106
114
 
107
115
  MIN_DELTA_MINUTES = 6
116
+ STS_GATE_LABEL = "api.openshift.com/gate-sts"
117
+ AUS_VERSION_GATE_APPROVALS_LABEL = "sre-capabilities.aus.version-gate-approvals"
118
+
119
+
120
+ class RosaRoleUpgradeHandlerParams(PydanticRunParams):
121
+ job_controller_cluster: str
122
+ job_controller_namespace: str
123
+ rosa_job_service_account: str
124
+ rosa_role: str
125
+ rosa_job_image: str | None = None
126
+ integration_name: str
127
+ integration_version: str
108
128
 
109
129
 
110
130
  class AdvancedUpgradeSchedulerBaseIntegrationParams(PydanticRunParams):
@@ -112,6 +132,7 @@ class AdvancedUpgradeSchedulerBaseIntegrationParams(PydanticRunParams):
112
132
  ocm_organization_ids: set[str] | None = None
113
133
  excluded_ocm_organization_ids: set[str] | None = None
114
134
  ignore_sts_clusters: bool = False
135
+ rosa_role_upgrade_handler_params: RosaRoleUpgradeHandlerParams | None = None
115
136
 
116
137
 
117
138
  class ReconcileError(Exception):
@@ -399,15 +420,20 @@ class AbstractUpgradePolicy(ABC, BaseModel):
399
420
 
400
421
  cluster: OCMCluster
401
422
 
402
- id: str | None
403
- next_run: str | None
404
- schedule: str | None
423
+ id: str | None = None
424
+ next_run: str | None = None
425
+ schedule: str | None = None
405
426
  schedule_type: str
406
427
  version: str
407
- state: str | None
428
+ state: str | None = None
408
429
 
409
430
  @abstractmethod
410
- def create(self, ocm_api: OCMBaseClient) -> None:
431
+ def create(
432
+ self,
433
+ ocm_api: OCMBaseClient,
434
+ rosa_role_upgrade_handler_params: RosaRoleUpgradeHandlerParams | None = None,
435
+ secret_reader: SecretReaderBase | None = None,
436
+ ) -> None:
411
437
  pass
412
438
 
413
439
  @abstractmethod
@@ -420,12 +446,12 @@ class AbstractUpgradePolicy(ABC, BaseModel):
420
446
 
421
447
 
422
448
  def addon_upgrade_policy_soonest_next_run() -> str:
423
- now = datetime.now(tz=dt.UTC)
449
+ now = utc_now()
424
450
  next_run = now + timedelta(minutes=MIN_DELTA_MINUTES)
425
- return next_run.strftime("%Y-%m-%dT%H:%M:%SZ")
451
+ return to_utc_seconds_iso_format(next_run)
426
452
 
427
453
 
428
- class AddonUpgradePolicy(AbstractUpgradePolicy):
454
+ class AddonUpgradePolicy(AbstractUpgradePolicy, arbitrary_types_allowed=True):
429
455
  """Class to create and delete Addon upgrade policies in OCM"""
430
456
 
431
457
  addon_id: str
@@ -434,7 +460,12 @@ class AddonUpgradePolicy(AbstractUpgradePolicy):
434
460
  class Config:
435
461
  arbitrary_types_allowed = True
436
462
 
437
- def create(self, ocm_api: OCMBaseClient) -> None:
463
+ def create(
464
+ self,
465
+ ocm_api: OCMBaseClient,
466
+ rosa_role_upgrade_handler_params: RosaRoleUpgradeHandlerParams | None = None,
467
+ secret_reader: SecretReaderBase | None = None,
468
+ ) -> None:
438
469
  self.addon_service.create_addon_upgrade_policy(
439
470
  ocm_api=ocm_api,
440
471
  cluster_id=self.cluster.id,
@@ -467,14 +498,63 @@ class AddonUpgradePolicy(AbstractUpgradePolicy):
467
498
  class ClusterUpgradePolicy(AbstractUpgradePolicy):
468
499
  """Class to create ClusterUpgradePolicies in OCM"""
469
500
 
470
- def create(self, ocm_api: OCMBaseClient) -> None:
501
+ organization_id: str
502
+ cluster_labels: LabelContainer
503
+
504
+ def create(
505
+ self,
506
+ ocm_api: OCMBaseClient,
507
+ rosa_role_upgrade_handler_params: RosaRoleUpgradeHandlerParams | None = None,
508
+ secret_reader: SecretReaderBase | None = None,
509
+ ) -> None:
471
510
  policy = {
472
511
  "version": self.version,
473
512
  "schedule_type": "manual",
474
513
  "next_run": self.next_run,
475
514
  }
515
+ if (
516
+ rosa_role_upgrade_handler_params
517
+ and secret_reader
518
+ and self.should_upgrade_roles()
519
+ ):
520
+ logging.info(f"Updating account and operator roles for {self.cluster.name}")
521
+ sts_gate_handler = sts_version_gate_handler.STSGateHandler(
522
+ job_controller=build_job_controller(
523
+ integration=rosa_role_upgrade_handler_params.integration_name,
524
+ integration_version=rosa_role_upgrade_handler_params.integration_version,
525
+ cluster=rosa_role_upgrade_handler_params.job_controller_cluster,
526
+ namespace=rosa_role_upgrade_handler_params.job_controller_namespace,
527
+ secret_reader=secret_reader,
528
+ dry_run=False,
529
+ ),
530
+ aws_iam_role=rosa_role_upgrade_handler_params.rosa_role,
531
+ rosa_job_service_account=rosa_role_upgrade_handler_params.rosa_job_service_account,
532
+ rosa_job_image=rosa_role_upgrade_handler_params.rosa_job_image,
533
+ )
534
+ if not sts_gate_handler.upgrade_rosa_roles_v2(
535
+ ocm_api=ocm_api,
536
+ cluster=self.cluster,
537
+ dry_run=False,
538
+ upgrade_version=self.version,
539
+ ocm_org_id=self.organization_id,
540
+ ):
541
+ logging.error(
542
+ f"Failed to update account and operator roles for {self.cluster.name}"
543
+ )
476
544
  create_upgrade_policy(ocm_api, self.cluster.id, policy)
477
545
 
546
+ def should_upgrade_roles(self) -> bool:
547
+ handler_csv = self.cluster_labels.get_label_value(
548
+ AUS_VERSION_GATE_APPROVALS_LABEL
549
+ )
550
+ if not handler_csv:
551
+ return False
552
+ return (
553
+ self.cluster.is_sts()
554
+ and self.cluster.is_rosa_classic()
555
+ and STS_GATE_LABEL in set(handler_csv.split(","))
556
+ )
557
+
478
558
  def delete(self, ocm_api: OCMBaseClient) -> None:
479
559
  raise NotImplementedError("ClusterUpgradePolicy.delete() not implemented")
480
560
 
@@ -492,7 +572,12 @@ class ClusterUpgradePolicy(AbstractUpgradePolicy):
492
572
  class ControlPlaneUpgradePolicy(AbstractUpgradePolicy):
493
573
  """Class to create and delete ControlPlanUpgradePolicies in OCM"""
494
574
 
495
- def create(self, ocm_api: OCMBaseClient) -> None:
575
+ def create(
576
+ self,
577
+ ocm_api: OCMBaseClient,
578
+ rosa_role_upgrade_handler_params: RosaRoleUpgradeHandlerParams | None = None,
579
+ secret_reader: SecretReaderBase | None = None,
580
+ ) -> None:
496
581
  policy = {
497
582
  "version": self.version,
498
583
  "schedule_type": "manual",
@@ -516,10 +601,16 @@ class ControlPlaneUpgradePolicy(AbstractUpgradePolicy):
516
601
 
517
602
 
518
603
  class NodePoolUpgradePolicy(AbstractUpgradePolicy):
519
- node_pool: str
520
604
  """Class to create NodePoolUpgradePolicies in OCM"""
521
605
 
522
- def create(self, ocm_api: OCMBaseClient) -> None:
606
+ node_pool: str
607
+
608
+ def create(
609
+ self,
610
+ ocm_api: OCMBaseClient,
611
+ rosa_role_upgrade_handler_params: RosaRoleUpgradeHandlerParams | None = None,
612
+ secret_reader: SecretReaderBase | None = None,
613
+ ) -> None:
523
614
  policy = {
524
615
  "version": self.version,
525
616
  "schedule_type": "manual",
@@ -545,13 +636,19 @@ class NodePoolUpgradePolicy(AbstractUpgradePolicy):
545
636
  return f"node pool upgrade policy - {remove_none_values_from_dict(details)}"
546
637
 
547
638
 
548
- class UpgradePolicyHandler(BaseModel, extra=Extra.forbid):
639
+ class UpgradePolicyHandler(BaseModel, extra="forbid"):
549
640
  """Class to handle upgrade policy actions"""
550
641
 
551
642
  action: str
552
643
  policy: AbstractUpgradePolicy
553
644
 
554
- def act(self, dry_run: bool, ocm_api: OCMBaseClient) -> None:
645
+ def act(
646
+ self,
647
+ dry_run: bool,
648
+ ocm_api: OCMBaseClient,
649
+ rosa_role_upgrade_handler_params: RosaRoleUpgradeHandlerParams | None = None,
650
+ secret_reader: SecretReaderBase | None = None,
651
+ ) -> None:
555
652
  logging.info(f"{self.action} {self.policy.summarize()}")
556
653
  if dry_run:
557
654
  return
@@ -561,7 +658,7 @@ class UpgradePolicyHandler(BaseModel, extra=Extra.forbid):
561
658
  elif self.action == "delete":
562
659
  self.policy.delete(ocm_api)
563
660
  elif self.action == "create":
564
- self.policy.create(ocm_api)
661
+ self.policy.create(ocm_api, rosa_role_upgrade_handler_params, secret_reader)
565
662
 
566
663
 
567
664
  def fetch_current_state(
@@ -579,6 +676,7 @@ def fetch_current_state(
579
676
  )
580
677
  current_state.extend(
581
678
  AddonUpgradePolicy(
679
+ organization_id=spec.org.org_id,
582
680
  id=addon_upgrade_policy.id,
583
681
  addon_id=addon_spec.addon.addon.id,
584
682
  cluster=spec.cluster,
@@ -615,6 +713,8 @@ def fetch_current_state(
615
713
  for upgrade_policy in upgrade_policies:
616
714
  policy = upgrade_policy | {
617
715
  "cluster": spec.cluster,
716
+ "organization_id": spec.org.org_id,
717
+ "cluster_labels": spec.cluster_labels,
618
718
  }
619
719
  current_state.append(ClusterUpgradePolicy(**policy))
620
720
 
@@ -638,8 +738,8 @@ def update_history(
638
738
  version_data (VersionData): version data, including history of soakdays
639
739
  upgrade_policies (list): query results of clusters upgrade policies
640
740
  """
641
- now = datetime.utcnow()
642
- check_in = version_data.check_in or now
741
+ now = utc_now()
742
+ check_in = ensure_utc(version_data.check_in or now)
643
743
 
644
744
  # we iterate over clusters upgrade policies and update the version history
645
745
  for spec in org_upgrade_spec.specs:
@@ -930,7 +1030,7 @@ def verify_schedule_should_skip(
930
1030
  # immediately
931
1031
  delay_minutes = 1 if addon_id else MIN_DELTA_MINUTES
932
1032
  next_schedule = iter.get_next(
933
- dt.datetime, start_time=now + timedelta(minutes=delay_minutes)
1033
+ datetime, start_time=now + timedelta(minutes=delay_minutes)
934
1034
  )
935
1035
  next_schedule_in_seconds = (next_schedule - now).total_seconds()
936
1036
  next_schedule_in_hours = next_schedule_in_seconds / 3600 # seconds in hour
@@ -947,7 +1047,7 @@ def verify_schedule_should_skip(
947
1047
  f"[{desired.org.org_id}/{desired.org.name}/{desired.cluster.name}] skipping cluster with no upcoming upgrade"
948
1048
  )
949
1049
  return None
950
- return next_schedule.strftime("%Y-%m-%dT%H:%M:%SZ")
1050
+ return to_utc_seconds_iso_format(next_schedule)
951
1051
 
952
1052
 
953
1053
  def verify_max_upgrades_should_skip(
@@ -1013,6 +1113,8 @@ def _create_upgrade_policy(
1013
1113
  )
1014
1114
  return ClusterUpgradePolicy(
1015
1115
  cluster=spec.cluster,
1116
+ organization_id=spec.org.org_id,
1117
+ cluster_labels=spec.cluster_labels,
1016
1118
  version=version,
1017
1119
  schedule_type="manual",
1018
1120
  next_run=next_schedule,
@@ -1024,8 +1126,8 @@ def _calculate_node_pool_diffs(
1024
1126
  ) -> UpgradePolicyHandler | None:
1025
1127
  for pool in spec.node_pools:
1026
1128
  if parse_semver(pool.version).match(f"<{spec.current_version}"):
1027
- next_schedule = (now + timedelta(minutes=MIN_DELTA_MINUTES)).strftime(
1028
- "%Y-%m-%dT%H:%M:%SZ"
1129
+ next_schedule = to_utc_seconds_iso_format(
1130
+ now + timedelta(minutes=MIN_DELTA_MINUTES)
1029
1131
  )
1030
1132
  return UpgradePolicyHandler(
1031
1133
  action="create",
@@ -1082,7 +1184,7 @@ def calculate_diff(
1082
1184
  set_upgrading(spec.cluster.id, spec.effective_mutexes, sector_name)
1083
1185
 
1084
1186
  addon_service = init_addon_service(desired_state.org.environment)
1085
- now = datetime.utcnow()
1187
+ now = utc_now()
1086
1188
  gates = get_version_gates(ocm_api)
1087
1189
  for spec in desired_state.specs:
1088
1190
  sector_name = spec.upgrade_policy.conditions.sector
@@ -1120,11 +1222,11 @@ def calculate_diff(
1120
1222
  action="create",
1121
1223
  policy=AddonUpgradePolicy(
1122
1224
  action="create",
1225
+ organization_id=spec.org.org_id,
1123
1226
  cluster=spec.cluster,
1124
1227
  version=version,
1125
1228
  schedule_type="manual",
1126
1229
  addon_id=addon_id,
1127
- upgrade_type="ADDON",
1128
1230
  addon_service=addon_service,
1129
1231
  ),
1130
1232
  )
@@ -1185,6 +1287,8 @@ def act(
1185
1287
  dry_run: bool,
1186
1288
  diffs: list[UpgradePolicyHandler],
1187
1289
  ocm_api: OCMBaseClient,
1290
+ rosa_role_upgrade_handler_params: RosaRoleUpgradeHandlerParams | None = None,
1291
+ secret_reader: SecretReaderBase | None = None,
1188
1292
  addon_id: str | None = None,
1189
1293
  ) -> None:
1190
1294
  diffs.sort(key=sort_diffs)
@@ -1197,7 +1301,7 @@ def act(
1197
1301
  ):
1198
1302
  continue
1199
1303
  try:
1200
- diff.act(dry_run, ocm_api)
1304
+ diff.act(dry_run, ocm_api, rosa_role_upgrade_handler_params, secret_reader)
1201
1305
  except HTTPError as e:
1202
1306
  logging.error(f"{policy.cluster.name}: {e}: {e.response.text}")
1203
1307
 
@@ -1297,10 +1401,8 @@ def remaining_soak_day_metric_values_for_cluster(
1297
1401
  remaining_soakdays[idx] = UPGRADE_STARTED_METRIC_VALUE
1298
1402
  if current_upgrade.next_run:
1299
1403
  # if an upgrade runs for over 6 hours, we mark it as a long running upgrade
1300
- next_run = datetime.strptime(
1301
- current_upgrade.next_run, "%Y-%m-%dT%H:%M:%SZ"
1302
- )
1303
- now = datetime.utcnow()
1404
+ next_run = from_utc_iso_format(current_upgrade.next_run)
1405
+ now = utc_now()
1304
1406
  hours_ago = (now - next_run).total_seconds() / 3600
1305
1407
  if hours_ago >= 6:
1306
1408
  remaining_soakdays[idx] = UPGRADE_LONG_RUNNING_METRIC_VALUE
@@ -1,4 +1,3 @@
1
- import json
2
1
  from collections.abc import Iterable
3
2
  from datetime import datetime
4
3
  from typing import (
@@ -20,6 +19,17 @@ class WorkloadHistory(BaseModel):
20
19
  soak_days: float = 0.0
21
20
  reporting: list[str] = Field(default_factory=list)
22
21
 
22
+ def __eq__(self, value: Any) -> bool:
23
+ if isinstance(value, WorkloadHistory):
24
+ return super().__eq__(value)
25
+
26
+ if isinstance(value, dict):
27
+ return self.soak_days == value.get("soak_days", 0.0) and sorted(
28
+ self.reporting
29
+ ) == sorted(value.get("reporting", []))
30
+
31
+ return False
32
+
23
33
 
24
34
  class VersionHistory(BaseModel):
25
35
  workloads: dict[str, WorkloadHistory] = Field(default_factory=dict)
@@ -38,7 +48,7 @@ class Stats(BaseModel):
38
48
 
39
49
  min_version: str
40
50
  min_version_per_workload: dict[str, str] = Field(default_factory=dict)
41
- inherited: Optional["Stats"]
51
+ inherited: Optional["Stats"] = None
42
52
 
43
53
  def inherit(self, added: "Stats") -> None:
44
54
  """adds the provided stats to our inherited data
@@ -93,12 +103,12 @@ class VersionData(BaseModel):
93
103
  upgrade policies.
94
104
  """
95
105
 
96
- check_in: datetime | None
106
+ check_in: datetime | None = None
97
107
  versions: dict[str, VersionHistory] = Field(default_factory=dict)
98
- stats: Stats | None
108
+ stats: Stats | None = None
99
109
 
100
110
  def jsondict(self) -> dict[str, Any]:
101
- return json.loads(self.json(exclude_none=True))
111
+ return self.model_dump(mode="json", exclude_none=True)
102
112
 
103
113
  def save(self, state: State, ocm_name: str) -> None:
104
114
  state.add(ocm_name, self.jsondict(), force=True)
reconcile/aus/models.py CHANGED
@@ -14,6 +14,7 @@ from reconcile.aus.healthchecks import AUSClusterHealth
14
14
  from reconcile.gql_definitions.fragments.aus_organization import AUSOCMOrganization
15
15
  from reconcile.gql_definitions.fragments.upgrade_policy import ClusterUpgradePolicyV1
16
16
  from reconcile.utils.ocm.addons import OCMAddonInstallation
17
+ from reconcile.utils.ocm.base import LabelContainer
17
18
  from reconcile.utils.ocm.clusters import OCMCluster
18
19
  from reconcile.utils.semver_helper import parse_semver
19
20
 
@@ -33,6 +34,7 @@ class ClusterUpgradeSpec(BaseModel):
33
34
 
34
35
  org: AUSOCMOrganization
35
36
  cluster: OCMCluster
37
+ cluster_labels: LabelContainer | None = None
36
38
  upgrade_policy: ClusterUpgradePolicyV1 = Field(..., alias="upgradePolicy")
37
39
  health: AUSClusterHealth
38
40
  node_pools: list[NodePoolSpec] = Field(default_factory=list, alias="nodePools")
@@ -232,7 +234,7 @@ class SectorConfigError(Exception):
232
234
 
233
235
  class Sector(BaseModel):
234
236
  name: str
235
- max_parallel_upgrades: str | None
237
+ max_parallel_upgrades: str | None = None
236
238
  dependencies: list[Sector] = Field(default_factory=list)
237
239
  _specs: dict[str, ClusterUpgradeSpec] = PrivateAttr(default_factory=dict)
238
240
 
@@ -260,6 +260,7 @@ def calculate_diff(
260
260
  aus.UpgradePolicyHandler(
261
261
  action="delete",
262
262
  policy=aus.AddonUpgradePolicy(
263
+ organization_id=org_upgrade_spec.org.org_id,
263
264
  cluster=current.cluster,
264
265
  version=current.schedule_type,
265
266
  id=current.id,
@@ -82,7 +82,14 @@ class OCMClusterUpgradeSchedulerIntegration(
82
82
  version_data,
83
83
  integration=self.name,
84
84
  )
85
- aus.act(dry_run, diffs, ocm_api)
85
+
86
+ aus.act(
87
+ dry_run,
88
+ diffs,
89
+ ocm_api,
90
+ self.params.rosa_role_upgrade_handler_params,
91
+ self.secret_reader,
92
+ )
86
93
 
87
94
  def expose_version_data_metrics(
88
95
  self,
@@ -1,4 +1,5 @@
1
1
  from collections import defaultdict
2
+ from dataclasses import dataclass
2
3
 
3
4
  from reconcile.aus.healthchecks import (
4
5
  AUSClusterHealthCheckProvider,
@@ -13,6 +14,7 @@ from reconcile.aus.node_pool_spec import get_node_pool_specs_by_org_cluster
13
14
  from reconcile.aus.ocm_upgrade_scheduler import OCMClusterUpgradeSchedulerIntegration
14
15
  from reconcile.gql_definitions.fragments.aus_organization import AUSOCMOrganization
15
16
  from reconcile.gql_definitions.fragments.ocm_environment import OCMEnvironment
17
+ from reconcile.utils.ocm.base import LabelContainer
16
18
  from reconcile.utils.ocm.clusters import (
17
19
  OCMCluster,
18
20
  discover_clusters_for_organizations,
@@ -22,6 +24,12 @@ from reconcile.utils.ocm_base_client import init_ocm_base_client
22
24
  QONTRACT_INTEGRATION = "ocm-upgrade-scheduler-org"
23
25
 
24
26
 
27
+ @dataclass
28
+ class ClusterUpgradeSpecWithLabels:
29
+ cluster: OCMCluster
30
+ cluster_labels: LabelContainer
31
+
32
+
25
33
  class OCMClusterUpgradeSchedulerOrgIntegration(OCMClusterUpgradeSchedulerIntegration):
26
34
  @property
27
35
  def name(self) -> str:
@@ -60,7 +68,10 @@ class OCMClusterUpgradeSchedulerOrgIntegration(OCMClusterUpgradeSchedulerIntegra
60
68
  specs=self._build_cluster_upgrade_specs(
61
69
  org=org,
62
70
  clusters_by_name={
63
- c.ocm_cluster.name: c.ocm_cluster
71
+ c.ocm_cluster.name: ClusterUpgradeSpecWithLabels(
72
+ cluster=c.ocm_cluster,
73
+ cluster_labels=c.labels,
74
+ )
64
75
  for c in clusters_by_org[org.org_id]
65
76
  },
66
77
  cluster_health_provider=build_cluster_health_providers_for_organization(
@@ -79,7 +90,7 @@ class OCMClusterUpgradeSchedulerOrgIntegration(OCMClusterUpgradeSchedulerIntegra
79
90
  def _build_cluster_upgrade_specs(
80
91
  self,
81
92
  org: AUSOCMOrganization,
82
- clusters_by_name: dict[str, OCMCluster],
93
+ clusters_by_name: dict[str, ClusterUpgradeSpecWithLabels],
83
94
  cluster_health_provider: AUSClusterHealthCheckProvider,
84
95
  node_pool_specs_by_cluster_id: dict[str, list[NodePoolSpec]],
85
96
  ) -> list[ClusterUpgradeSpec]:
@@ -87,12 +98,16 @@ class OCMClusterUpgradeSchedulerOrgIntegration(OCMClusterUpgradeSchedulerIntegra
87
98
  ClusterUpgradeSpec(
88
99
  org=org,
89
100
  upgradePolicy=cluster.upgrade_policy,
90
- cluster=clusters_by_name[cluster.name],
101
+ cluster=clusters_by_name[cluster.name].cluster,
102
+ cluster_labels=clusters_by_name[cluster.name].cluster_labels,
91
103
  health=cluster_health_provider.cluster_health(
92
- cluster_external_id=clusters_by_name[cluster.name].external_id,
104
+ cluster_external_id=clusters_by_name[
105
+ cluster.name
106
+ ].cluster.external_id,
93
107
  org_id=org.org_id,
94
108
  ),
95
- nodePools=node_pool_specs_by_cluster_id.get(ocm_cluster.id) or [],
109
+ nodePools=node_pool_specs_by_cluster_id.get(ocm_cluster.cluster.id)
110
+ or [],
96
111
  )
97
112
  for cluster in org.upgrade_policy_clusters or []
98
113
  # clusters that are not in the UUID dict will be ignored because