qontract-reconcile 0.10.2.dev394__py3-none-any.whl → 0.10.2.dev427__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (316) hide show
  1. {qontract_reconcile-0.10.2.dev394.dist-info → qontract_reconcile-0.10.2.dev427.dist-info}/METADATA +5 -4
  2. {qontract_reconcile-0.10.2.dev394.dist-info → qontract_reconcile-0.10.2.dev427.dist-info}/RECORD +316 -315
  3. reconcile/acs_rbac.py +2 -2
  4. reconcile/aus/advanced_upgrade_service.py +18 -12
  5. reconcile/aus/base.py +117 -18
  6. reconcile/aus/cluster_version_data.py +15 -5
  7. reconcile/aus/models.py +3 -1
  8. reconcile/aus/ocm_addons_upgrade_scheduler_org.py +1 -0
  9. reconcile/aus/ocm_upgrade_scheduler.py +8 -1
  10. reconcile/aus/ocm_upgrade_scheduler_org.py +20 -5
  11. reconcile/aus/version_gates/sts_version_gate_handler.py +54 -1
  12. reconcile/automated_actions/config/integration.py +16 -4
  13. reconcile/aws_account_manager/integration.py +6 -6
  14. reconcile/aws_account_manager/reconciler.py +3 -3
  15. reconcile/aws_ami_cleanup/integration.py +2 -5
  16. reconcile/aws_ami_share.py +69 -62
  17. reconcile/aws_saml_idp/integration.py +5 -3
  18. reconcile/aws_saml_roles/integration.py +23 -22
  19. reconcile/aws_version_sync/integration.py +6 -12
  20. reconcile/change_owners/bundle.py +3 -3
  21. reconcile/change_owners/change_log_tracking.py +3 -2
  22. reconcile/change_owners/change_owners.py +1 -1
  23. reconcile/cli.py +62 -4
  24. reconcile/dashdotdb_dora.py +1 -1
  25. reconcile/dashdotdb_slo.py +1 -1
  26. reconcile/database_access_manager.py +8 -9
  27. reconcile/dynatrace_token_provider/integration.py +1 -1
  28. reconcile/endpoints_discovery/integration.py +4 -1
  29. reconcile/endpoints_discovery/merge_request.py +1 -1
  30. reconcile/endpoints_discovery/merge_request_manager.py +1 -1
  31. reconcile/external_resources/integration.py +1 -1
  32. reconcile/external_resources/manager.py +3 -2
  33. reconcile/external_resources/metrics.py +1 -1
  34. reconcile/external_resources/model.py +13 -13
  35. reconcile/external_resources/reconciler.py +7 -4
  36. reconcile/external_resources/secrets_sync.py +2 -2
  37. reconcile/external_resources/state.py +22 -13
  38. reconcile/fleet_labeler/integration.py +1 -1
  39. reconcile/gcp_image_mirror.py +2 -2
  40. reconcile/github_org.py +1 -1
  41. reconcile/github_owners.py +4 -0
  42. reconcile/gitlab_members.py +6 -12
  43. reconcile/gitlab_permissions.py +8 -12
  44. reconcile/glitchtip_project_alerts/integration.py +3 -1
  45. reconcile/gql_definitions/acs/acs_instances.py +5 -5
  46. reconcile/gql_definitions/acs/acs_policies.py +5 -5
  47. reconcile/gql_definitions/acs/acs_rbac.py +5 -5
  48. reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +5 -5
  49. reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +5 -5
  50. reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +5 -5
  51. reconcile/gql_definitions/app_sre_tekton_access_revalidation/roles.py +5 -5
  52. reconcile/gql_definitions/app_sre_tekton_access_revalidation/users.py +5 -5
  53. reconcile/gql_definitions/automated_actions/instance.py +46 -7
  54. reconcile/gql_definitions/aws_account_manager/aws_accounts.py +5 -5
  55. reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +5 -5
  56. reconcile/gql_definitions/aws_cloudwatch_log_retention/aws_accounts.py +5 -5
  57. reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +5 -5
  58. reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +5 -5
  59. reconcile/gql_definitions/aws_saml_roles/roles.py +5 -5
  60. reconcile/gql_definitions/aws_version_sync/clusters.py +5 -5
  61. reconcile/gql_definitions/aws_version_sync/namespaces.py +5 -5
  62. reconcile/gql_definitions/change_owners/queries/change_types.py +5 -5
  63. reconcile/gql_definitions/change_owners/queries/self_service_roles.py +5 -5
  64. reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +5 -5
  65. reconcile/gql_definitions/common/alerting_services_settings.py +5 -5
  66. reconcile/gql_definitions/common/app_code_component_repos.py +5 -5
  67. reconcile/gql_definitions/common/app_interface_custom_messages.py +5 -5
  68. reconcile/gql_definitions/common/app_interface_dms_settings.py +5 -5
  69. reconcile/gql_definitions/common/app_interface_repo_settings.py +5 -5
  70. reconcile/gql_definitions/common/app_interface_roles.py +5 -5
  71. reconcile/gql_definitions/common/app_interface_state_settings.py +5 -5
  72. reconcile/gql_definitions/common/app_interface_vault_settings.py +5 -5
  73. reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +5 -5
  74. reconcile/gql_definitions/common/apps.py +5 -5
  75. reconcile/gql_definitions/common/aws_vpc_requests.py +5 -5
  76. reconcile/gql_definitions/common/aws_vpcs.py +5 -5
  77. reconcile/gql_definitions/common/clusters.py +5 -5
  78. reconcile/gql_definitions/common/clusters_minimal.py +5 -5
  79. reconcile/gql_definitions/common/clusters_with_dms.py +5 -5
  80. reconcile/gql_definitions/common/clusters_with_peering.py +5 -5
  81. reconcile/gql_definitions/common/github_orgs.py +5 -5
  82. reconcile/gql_definitions/common/jira_settings.py +5 -5
  83. reconcile/gql_definitions/common/jiralert_settings.py +5 -5
  84. reconcile/gql_definitions/common/ldap_settings.py +5 -5
  85. reconcile/gql_definitions/common/namespaces.py +5 -5
  86. reconcile/gql_definitions/common/namespaces_minimal.py +7 -5
  87. reconcile/gql_definitions/common/ocm_env_telemeter.py +5 -5
  88. reconcile/gql_definitions/common/ocm_environments.py +5 -5
  89. reconcile/gql_definitions/common/pagerduty_instances.py +5 -5
  90. reconcile/gql_definitions/common/pgp_reencryption_settings.py +5 -5
  91. reconcile/gql_definitions/common/pipeline_providers.py +5 -5
  92. reconcile/gql_definitions/common/quay_instances.py +5 -5
  93. reconcile/gql_definitions/common/quay_orgs.py +5 -5
  94. reconcile/gql_definitions/common/reserved_networks.py +5 -5
  95. reconcile/gql_definitions/common/rhcs_provider_settings.py +5 -5
  96. reconcile/gql_definitions/common/saas_files.py +5 -5
  97. reconcile/gql_definitions/common/saas_target_namespaces.py +5 -5
  98. reconcile/gql_definitions/common/saasherder_settings.py +5 -5
  99. reconcile/gql_definitions/common/slack_workspaces.py +5 -5
  100. reconcile/gql_definitions/common/smtp_client_settings.py +5 -5
  101. reconcile/gql_definitions/common/state_aws_account.py +5 -5
  102. reconcile/gql_definitions/common/users.py +5 -5
  103. reconcile/gql_definitions/common/users_with_paths.py +5 -5
  104. reconcile/gql_definitions/cost_report/app_names.py +5 -5
  105. reconcile/gql_definitions/cost_report/cost_namespaces.py +5 -5
  106. reconcile/gql_definitions/cost_report/settings.py +5 -5
  107. reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +5 -5
  108. reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +5 -5
  109. reconcile/gql_definitions/dynatrace_token_provider/token_specs.py +5 -5
  110. reconcile/gql_definitions/email_sender/apps.py +5 -5
  111. reconcile/gql_definitions/email_sender/emails.py +5 -5
  112. reconcile/gql_definitions/email_sender/users.py +5 -5
  113. reconcile/gql_definitions/endpoints_discovery/apps.py +5 -5
  114. reconcile/gql_definitions/external_resources/aws_accounts.py +5 -5
  115. reconcile/gql_definitions/external_resources/external_resources_modules.py +5 -5
  116. reconcile/gql_definitions/external_resources/external_resources_namespaces.py +5 -5
  117. reconcile/gql_definitions/external_resources/external_resources_settings.py +5 -5
  118. reconcile/gql_definitions/external_resources/fragments/external_resources_module_overrides.py +5 -5
  119. reconcile/gql_definitions/fleet_labeler/fleet_labels.py +5 -5
  120. reconcile/gql_definitions/fragments/aus_organization.py +5 -5
  121. reconcile/gql_definitions/fragments/aws_account_common.py +5 -5
  122. reconcile/gql_definitions/fragments/aws_account_managed.py +5 -5
  123. reconcile/gql_definitions/fragments/aws_account_sso.py +5 -5
  124. reconcile/gql_definitions/fragments/aws_infra_management_account.py +5 -5
  125. reconcile/gql_definitions/fragments/aws_organization.py +5 -5
  126. reconcile/gql_definitions/fragments/aws_vpc.py +5 -5
  127. reconcile/gql_definitions/fragments/aws_vpc_request.py +5 -5
  128. reconcile/gql_definitions/fragments/container_image_mirror.py +5 -5
  129. reconcile/gql_definitions/fragments/deploy_resources.py +5 -5
  130. reconcile/gql_definitions/fragments/disable.py +5 -5
  131. reconcile/gql_definitions/fragments/email_service.py +5 -5
  132. reconcile/gql_definitions/fragments/email_user.py +5 -5
  133. reconcile/gql_definitions/fragments/jumphost_common_fields.py +5 -5
  134. reconcile/gql_definitions/fragments/membership_source.py +5 -5
  135. reconcile/gql_definitions/fragments/minimal_ocm_organization.py +5 -5
  136. reconcile/gql_definitions/fragments/oc_connection_cluster.py +5 -5
  137. reconcile/gql_definitions/fragments/ocm_environment.py +5 -5
  138. reconcile/gql_definitions/fragments/pipeline_provider_retention.py +5 -5
  139. reconcile/gql_definitions/fragments/prometheus_instance.py +5 -5
  140. reconcile/gql_definitions/fragments/resource_limits_requirements.py +5 -5
  141. reconcile/gql_definitions/fragments/resource_requests_requirements.py +5 -5
  142. reconcile/gql_definitions/fragments/resource_values.py +5 -5
  143. reconcile/gql_definitions/fragments/saas_slo_document.py +5 -5
  144. reconcile/gql_definitions/fragments/saas_target_namespace.py +5 -5
  145. reconcile/gql_definitions/fragments/serviceaccount_token.py +5 -5
  146. reconcile/gql_definitions/fragments/terraform_state.py +5 -5
  147. reconcile/gql_definitions/fragments/upgrade_policy.py +5 -5
  148. reconcile/gql_definitions/fragments/user.py +5 -5
  149. reconcile/gql_definitions/fragments/vault_secret.py +5 -5
  150. reconcile/gql_definitions/gcp/gcp_docker_repos.py +5 -5
  151. reconcile/gql_definitions/gcp/gcp_projects.py +5 -5
  152. reconcile/gql_definitions/gitlab_members/gitlab_instances.py +5 -5
  153. reconcile/gql_definitions/gitlab_members/permissions.py +5 -5
  154. reconcile/gql_definitions/glitchtip/glitchtip_instance.py +5 -5
  155. reconcile/gql_definitions/glitchtip/glitchtip_project.py +5 -5
  156. reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +5 -5
  157. reconcile/gql_definitions/integrations/integrations.py +5 -5
  158. reconcile/gql_definitions/introspection.json +231 -0
  159. reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +5 -5
  160. reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +5 -5
  161. reconcile/gql_definitions/jira/jira_servers.py +5 -5
  162. reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +5 -5
  163. reconcile/gql_definitions/jumphosts/jumphosts.py +5 -5
  164. reconcile/gql_definitions/ldap_groups/roles.py +5 -5
  165. reconcile/gql_definitions/ldap_groups/settings.py +5 -5
  166. reconcile/gql_definitions/maintenance/maintenances.py +5 -5
  167. reconcile/gql_definitions/membershipsources/roles.py +5 -5
  168. reconcile/gql_definitions/ocm_labels/clusters.py +5 -5
  169. reconcile/gql_definitions/ocm_labels/organizations.py +5 -5
  170. reconcile/gql_definitions/openshift_cluster_bots/clusters.py +5 -5
  171. reconcile/gql_definitions/openshift_groups/managed_groups.py +5 -5
  172. reconcile/gql_definitions/openshift_groups/managed_roles.py +5 -5
  173. reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +5 -5
  174. reconcile/gql_definitions/quay_membership/quay_membership.py +5 -5
  175. reconcile/gql_definitions/rhcs/certs.py +24 -79
  176. reconcile/gql_definitions/rhcs/openshift_resource_rhcs_cert.py +42 -0
  177. reconcile/gql_definitions/rhidp/organizations.py +5 -5
  178. reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +5 -5
  179. reconcile/gql_definitions/service_dependencies/service_dependencies.py +5 -5
  180. reconcile/gql_definitions/sharding/aws_accounts.py +5 -5
  181. reconcile/gql_definitions/sharding/ocm_organization.py +5 -5
  182. reconcile/gql_definitions/skupper_network/site_controller_template.py +5 -5
  183. reconcile/gql_definitions/skupper_network/skupper_networks.py +5 -5
  184. reconcile/gql_definitions/slack_usergroups/clusters.py +5 -5
  185. reconcile/gql_definitions/slack_usergroups/permissions.py +5 -5
  186. reconcile/gql_definitions/slack_usergroups/users.py +5 -5
  187. reconcile/gql_definitions/slo_documents/slo_documents.py +5 -5
  188. reconcile/gql_definitions/status_board/status_board.py +5 -5
  189. reconcile/gql_definitions/statuspage/statuspages.py +5 -5
  190. reconcile/gql_definitions/templating/template_collection.py +5 -5
  191. reconcile/gql_definitions/templating/templates.py +5 -5
  192. reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +5 -5
  193. reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +5 -5
  194. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +5 -5
  195. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +5 -5
  196. reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +5 -5
  197. reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +5 -5
  198. reconcile/gql_definitions/terraform_init/aws_accounts.py +5 -5
  199. reconcile/gql_definitions/terraform_repo/terraform_repo.py +5 -5
  200. reconcile/gql_definitions/terraform_resources/database_access_manager.py +5 -5
  201. reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +5 -5
  202. reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +5 -5
  203. reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +5 -5
  204. reconcile/gql_definitions/vault_instances/vault_instances.py +5 -5
  205. reconcile/gql_definitions/vault_policies/vault_policies.py +5 -5
  206. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +5 -5
  207. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +5 -5
  208. reconcile/integrations_manager.py +3 -3
  209. reconcile/jenkins_worker_fleets.py +9 -8
  210. reconcile/jira_permissions_validator.py +2 -2
  211. reconcile/ldap_groups/integration.py +1 -1
  212. reconcile/ocm/types.py +35 -57
  213. reconcile/ocm_aws_infrastructure_access.py +1 -1
  214. reconcile/ocm_clusters.py +4 -4
  215. reconcile/ocm_labels/integration.py +3 -2
  216. reconcile/ocm_machine_pools.py +33 -27
  217. reconcile/openshift_base.py +113 -4
  218. reconcile/openshift_cluster_bots.py +1 -1
  219. reconcile/openshift_namespace_labels.py +1 -1
  220. reconcile/openshift_namespaces.py +97 -101
  221. reconcile/openshift_resources_base.py +6 -2
  222. reconcile/openshift_rhcs_certs.py +27 -29
  223. reconcile/openshift_rolebindings.py +7 -11
  224. reconcile/openshift_saas_deploy.py +4 -5
  225. reconcile/openshift_saas_deploy_change_tester.py +9 -7
  226. reconcile/openshift_serviceaccount_tokens.py +2 -2
  227. reconcile/openshift_upgrade_watcher.py +1 -1
  228. reconcile/oum/labelset.py +5 -3
  229. reconcile/oum/models.py +1 -4
  230. reconcile/prometheus_rules_tester/integration.py +3 -3
  231. reconcile/quay_mirror.py +1 -1
  232. reconcile/queries.py +6 -0
  233. reconcile/rhidp/common.py +3 -5
  234. reconcile/rhidp/sso_client/base.py +16 -5
  235. reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +1 -1
  236. reconcile/skupper_network/integration.py +2 -2
  237. reconcile/slack_usergroups.py +31 -11
  238. reconcile/status_board.py +6 -6
  239. reconcile/statuspage/atlassian.py +7 -7
  240. reconcile/statuspage/page.py +4 -9
  241. reconcile/templating/lib/rendering.py +3 -3
  242. reconcile/templating/renderer.py +2 -2
  243. reconcile/terraform_cloudflare_dns.py +3 -3
  244. reconcile/terraform_cloudflare_resources.py +5 -5
  245. reconcile/terraform_cloudflare_users.py +3 -2
  246. reconcile/terraform_init/integration.py +2 -2
  247. reconcile/terraform_repo.py +16 -12
  248. reconcile/terraform_resources.py +6 -6
  249. reconcile/terraform_tgw_attachments.py +20 -18
  250. reconcile/terraform_vpc_resources/integration.py +3 -1
  251. reconcile/typed_queries/cost_report/app_names.py +1 -1
  252. reconcile/typed_queries/cost_report/cost_namespaces.py +2 -2
  253. reconcile/typed_queries/saas_files.py +11 -11
  254. reconcile/typed_queries/status_board.py +2 -2
  255. reconcile/unleash_feature_toggles/integration.py +4 -2
  256. reconcile/utils/acs/base.py +6 -3
  257. reconcile/utils/acs/policies.py +2 -2
  258. reconcile/utils/aws_api.py +51 -20
  259. reconcile/utils/aws_api_typed/organization.py +4 -2
  260. reconcile/utils/binary.py +7 -12
  261. reconcile/utils/deadmanssnitch_api.py +1 -1
  262. reconcile/utils/early_exit_cache.py +8 -10
  263. reconcile/utils/gitlab_api.py +7 -5
  264. reconcile/utils/glitchtip/client.py +6 -2
  265. reconcile/utils/glitchtip/models.py +25 -28
  266. reconcile/utils/gql.py +4 -7
  267. reconcile/utils/instrumented_wrappers.py +1 -1
  268. reconcile/utils/internal_groups/client.py +2 -2
  269. reconcile/utils/internal_groups/models.py +8 -17
  270. reconcile/utils/jinja2/utils.py +2 -5
  271. reconcile/utils/jobcontroller/controller.py +2 -2
  272. reconcile/utils/jobcontroller/models.py +17 -1
  273. reconcile/utils/json.py +43 -1
  274. reconcile/utils/membershipsources/app_interface_resolver.py +4 -2
  275. reconcile/utils/membershipsources/models.py +16 -23
  276. reconcile/utils/membershipsources/resolver.py +4 -2
  277. reconcile/utils/merge_request_manager/merge_request_manager.py +1 -1
  278. reconcile/utils/merge_request_manager/parser.py +4 -4
  279. reconcile/utils/metrics.py +5 -5
  280. reconcile/utils/models.py +304 -82
  281. reconcile/utils/mr/notificator.py +1 -1
  282. reconcile/utils/mr/user_maintenance.py +3 -2
  283. reconcile/utils/oc.py +246 -201
  284. reconcile/utils/ocm/addons.py +0 -1
  285. reconcile/utils/ocm/base.py +17 -20
  286. reconcile/utils/ocm/cluster_groups.py +1 -1
  287. reconcile/utils/ocm/identity_providers.py +2 -2
  288. reconcile/utils/ocm/labels.py +1 -1
  289. reconcile/utils/ocm/products.py +8 -8
  290. reconcile/utils/ocm/service_log.py +1 -1
  291. reconcile/utils/ocm/sre_capability_labels.py +20 -13
  292. reconcile/utils/openshift_resource.py +5 -0
  293. reconcile/utils/pagerduty_api.py +5 -2
  294. reconcile/utils/promotion_state.py +6 -11
  295. reconcile/utils/raw_github_api.py +1 -1
  296. reconcile/utils/rhcsv2_certs.py +1 -4
  297. reconcile/utils/rosa/session.py +16 -0
  298. reconcile/utils/runtime/integration.py +1 -1
  299. reconcile/utils/saasherder/interfaces.py +13 -20
  300. reconcile/utils/saasherder/models.py +23 -20
  301. reconcile/utils/saasherder/saasherder.py +46 -24
  302. reconcile/utils/slack_api.py +2 -2
  303. reconcile/utils/structs.py +1 -1
  304. reconcile/utils/terraform_client.py +1 -1
  305. reconcile/utils/terrascript_aws_client.py +47 -43
  306. reconcile/utils/unleash/server.py +2 -8
  307. reconcile/utils/vault.py +5 -12
  308. reconcile/utils/vcs.py +8 -8
  309. reconcile/vault_replication.py +1 -1
  310. tools/cli_commands/cost_report/cost_management_api.py +3 -3
  311. tools/cli_commands/cost_report/view.py +7 -6
  312. tools/cli_commands/erv2.py +1 -1
  313. tools/qontract_cli.py +6 -5
  314. tools/template_validation.py +3 -1
  315. {qontract_reconcile-0.10.2.dev394.dist-info → qontract_reconcile-0.10.2.dev427.dist-info}/WHEEL +0 -0
  316. {qontract_reconcile-0.10.2.dev394.dist-info → qontract_reconcile-0.10.2.dev427.dist-info}/entry_points.txt +0 -0
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
@@ -16,7 +16,7 @@ from typing import (
16
16
  )
17
17
 
18
18
  from croniter import croniter
19
- from pydantic import BaseModel, Extra
19
+ from pydantic import BaseModel
20
20
  from requests.exceptions import HTTPError
21
21
  from semver import VersionInfo
22
22
 
@@ -46,7 +46,7 @@ from reconcile.aus.models import (
46
46
  OrganizationUpgradeSpec,
47
47
  Sector,
48
48
  )
49
- from reconcile.aus.version_gates import HANDLERS
49
+ from reconcile.aus.version_gates import HANDLERS, sts_version_gate_handler
50
50
  from reconcile.gql_definitions.advanced_upgrade_service.aus_organization import (
51
51
  query as aus_organizations_query,
52
52
  )
@@ -79,7 +79,9 @@ from reconcile.utils.datetime_util import (
79
79
  from reconcile.utils.defer import defer
80
80
  from reconcile.utils.disabled_integrations import integration_is_enabled
81
81
  from reconcile.utils.filtering import remove_none_values_from_dict
82
+ from reconcile.utils.jobcontroller.controller import build_job_controller
82
83
  from reconcile.utils.ocm.addons import AddonService, AddonServiceV1, AddonServiceV2
84
+ from reconcile.utils.ocm.base import LabelContainer
83
85
  from reconcile.utils.ocm.clusters import (
84
86
  OCMCluster,
85
87
  )
@@ -102,6 +104,7 @@ from reconcile.utils.runtime.integration import (
102
104
  PydanticRunParams,
103
105
  QontractReconcileIntegration,
104
106
  )
107
+ from reconcile.utils.secret_reader import SecretReaderBase
105
108
  from reconcile.utils.semver_helper import (
106
109
  get_version_prefix,
107
110
  parse_semver,
@@ -110,6 +113,18 @@ from reconcile.utils.semver_helper import (
110
113
  from reconcile.utils.state import init_state
111
114
 
112
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
113
128
 
114
129
 
115
130
  class AdvancedUpgradeSchedulerBaseIntegrationParams(PydanticRunParams):
@@ -117,6 +132,7 @@ class AdvancedUpgradeSchedulerBaseIntegrationParams(PydanticRunParams):
117
132
  ocm_organization_ids: set[str] | None = None
118
133
  excluded_ocm_organization_ids: set[str] | None = None
119
134
  ignore_sts_clusters: bool = False
135
+ rosa_role_upgrade_handler_params: RosaRoleUpgradeHandlerParams | None = None
120
136
 
121
137
 
122
138
  class ReconcileError(Exception):
@@ -404,15 +420,20 @@ class AbstractUpgradePolicy(ABC, BaseModel):
404
420
 
405
421
  cluster: OCMCluster
406
422
 
407
- id: str | None
408
- next_run: str | None
409
- schedule: str | None
423
+ id: str | None = None
424
+ next_run: str | None = None
425
+ schedule: str | None = None
410
426
  schedule_type: str
411
427
  version: str
412
- state: str | None
428
+ state: str | None = None
413
429
 
414
430
  @abstractmethod
415
- 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:
416
437
  pass
417
438
 
418
439
  @abstractmethod
@@ -430,7 +451,7 @@ def addon_upgrade_policy_soonest_next_run() -> str:
430
451
  return to_utc_seconds_iso_format(next_run)
431
452
 
432
453
 
433
- class AddonUpgradePolicy(AbstractUpgradePolicy):
454
+ class AddonUpgradePolicy(AbstractUpgradePolicy, arbitrary_types_allowed=True):
434
455
  """Class to create and delete Addon upgrade policies in OCM"""
435
456
 
436
457
  addon_id: str
@@ -439,7 +460,12 @@ class AddonUpgradePolicy(AbstractUpgradePolicy):
439
460
  class Config:
440
461
  arbitrary_types_allowed = True
441
462
 
442
- 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:
443
469
  self.addon_service.create_addon_upgrade_policy(
444
470
  ocm_api=ocm_api,
445
471
  cluster_id=self.cluster.id,
@@ -472,14 +498,63 @@ class AddonUpgradePolicy(AbstractUpgradePolicy):
472
498
  class ClusterUpgradePolicy(AbstractUpgradePolicy):
473
499
  """Class to create ClusterUpgradePolicies in OCM"""
474
500
 
475
- 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:
476
510
  policy = {
477
511
  "version": self.version,
478
512
  "schedule_type": "manual",
479
513
  "next_run": self.next_run,
480
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
+ )
481
544
  create_upgrade_policy(ocm_api, self.cluster.id, policy)
482
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
+
483
558
  def delete(self, ocm_api: OCMBaseClient) -> None:
484
559
  raise NotImplementedError("ClusterUpgradePolicy.delete() not implemented")
485
560
 
@@ -497,7 +572,12 @@ class ClusterUpgradePolicy(AbstractUpgradePolicy):
497
572
  class ControlPlaneUpgradePolicy(AbstractUpgradePolicy):
498
573
  """Class to create and delete ControlPlanUpgradePolicies in OCM"""
499
574
 
500
- 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:
501
581
  policy = {
502
582
  "version": self.version,
503
583
  "schedule_type": "manual",
@@ -521,10 +601,16 @@ class ControlPlaneUpgradePolicy(AbstractUpgradePolicy):
521
601
 
522
602
 
523
603
  class NodePoolUpgradePolicy(AbstractUpgradePolicy):
524
- node_pool: str
525
604
  """Class to create NodePoolUpgradePolicies in OCM"""
526
605
 
527
- 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:
528
614
  policy = {
529
615
  "version": self.version,
530
616
  "schedule_type": "manual",
@@ -550,13 +636,19 @@ class NodePoolUpgradePolicy(AbstractUpgradePolicy):
550
636
  return f"node pool upgrade policy - {remove_none_values_from_dict(details)}"
551
637
 
552
638
 
553
- class UpgradePolicyHandler(BaseModel, extra=Extra.forbid):
639
+ class UpgradePolicyHandler(BaseModel, extra="forbid"):
554
640
  """Class to handle upgrade policy actions"""
555
641
 
556
642
  action: str
557
643
  policy: AbstractUpgradePolicy
558
644
 
559
- 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:
560
652
  logging.info(f"{self.action} {self.policy.summarize()}")
561
653
  if dry_run:
562
654
  return
@@ -566,7 +658,7 @@ class UpgradePolicyHandler(BaseModel, extra=Extra.forbid):
566
658
  elif self.action == "delete":
567
659
  self.policy.delete(ocm_api)
568
660
  elif self.action == "create":
569
- self.policy.create(ocm_api)
661
+ self.policy.create(ocm_api, rosa_role_upgrade_handler_params, secret_reader)
570
662
 
571
663
 
572
664
  def fetch_current_state(
@@ -584,6 +676,7 @@ def fetch_current_state(
584
676
  )
585
677
  current_state.extend(
586
678
  AddonUpgradePolicy(
679
+ organization_id=spec.org.org_id,
587
680
  id=addon_upgrade_policy.id,
588
681
  addon_id=addon_spec.addon.addon.id,
589
682
  cluster=spec.cluster,
@@ -620,6 +713,8 @@ def fetch_current_state(
620
713
  for upgrade_policy in upgrade_policies:
621
714
  policy = upgrade_policy | {
622
715
  "cluster": spec.cluster,
716
+ "organization_id": spec.org.org_id,
717
+ "cluster_labels": spec.cluster_labels,
623
718
  }
624
719
  current_state.append(ClusterUpgradePolicy(**policy))
625
720
 
@@ -1018,6 +1113,8 @@ def _create_upgrade_policy(
1018
1113
  )
1019
1114
  return ClusterUpgradePolicy(
1020
1115
  cluster=spec.cluster,
1116
+ organization_id=spec.org.org_id,
1117
+ cluster_labels=spec.cluster_labels,
1021
1118
  version=version,
1022
1119
  schedule_type="manual",
1023
1120
  next_run=next_schedule,
@@ -1125,11 +1222,11 @@ def calculate_diff(
1125
1222
  action="create",
1126
1223
  policy=AddonUpgradePolicy(
1127
1224
  action="create",
1225
+ organization_id=spec.org.org_id,
1128
1226
  cluster=spec.cluster,
1129
1227
  version=version,
1130
1228
  schedule_type="manual",
1131
1229
  addon_id=addon_id,
1132
- upgrade_type="ADDON",
1133
1230
  addon_service=addon_service,
1134
1231
  ),
1135
1232
  )
@@ -1190,6 +1287,8 @@ def act(
1190
1287
  dry_run: bool,
1191
1288
  diffs: list[UpgradePolicyHandler],
1192
1289
  ocm_api: OCMBaseClient,
1290
+ rosa_role_upgrade_handler_params: RosaRoleUpgradeHandlerParams | None = None,
1291
+ secret_reader: SecretReaderBase | None = None,
1193
1292
  addon_id: str | None = None,
1194
1293
  ) -> None:
1195
1294
  diffs.sort(key=sort_diffs)
@@ -1202,7 +1301,7 @@ def act(
1202
1301
  ):
1203
1302
  continue
1204
1303
  try:
1205
- diff.act(dry_run, ocm_api)
1304
+ diff.act(dry_run, ocm_api, rosa_role_upgrade_handler_params, secret_reader)
1206
1305
  except HTTPError as e:
1207
1306
  logging.error(f"{policy.cluster.name}: {e}: {e.response.text}")
1208
1307
 
@@ -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
@@ -6,6 +6,7 @@ from reconcile.utils.ocm.base import OCMCluster, OCMVersionGate
6
6
  from reconcile.utils.ocm_base_client import OCMBaseClient
7
7
  from reconcile.utils.rosa.rosa_cli import RosaCliError
8
8
  from reconcile.utils.rosa.session import RosaSession
9
+ from reconcile.utils.semver_helper import get_version_prefix
9
10
 
10
11
  GATE_LABEL = "api.openshift.com/gate-sts"
11
12
 
@@ -63,6 +64,24 @@ class STSGateHandler(GateHandler):
63
64
  )
64
65
  return False
65
66
 
67
+ return self.upgrade_rosa_roles(
68
+ cluster=cluster,
69
+ version_raw_id_prefix=gate.version_raw_id_prefix,
70
+ dry_run=dry_run,
71
+ ocm_api=ocm_api,
72
+ ocm_org_id=ocm_org_id,
73
+ )
74
+
75
+ def upgrade_rosa_roles(
76
+ self,
77
+ cluster: OCMCluster,
78
+ version_raw_id_prefix: str,
79
+ dry_run: bool,
80
+ ocm_api: OCMBaseClient,
81
+ ocm_org_id: str,
82
+ ) -> bool:
83
+ if not cluster.aws:
84
+ return False
66
85
  rosa = RosaSession(
67
86
  aws_account_id=cluster.aws.aws_account_id,
68
87
  aws_region=cluster.region.id,
@@ -83,7 +102,7 @@ class STSGateHandler(GateHandler):
83
102
  )
84
103
  rosa.upgrade_account_roles(
85
104
  role_prefix=account_role_prefix,
86
- minor_version=gate.version_raw_id_prefix,
105
+ minor_version=version_raw_id_prefix,
87
106
  channel_group=cluster.version.channel_group,
88
107
  dry_run=dry_run,
89
108
  )
@@ -98,3 +117,37 @@ class STSGateHandler(GateHandler):
98
117
  e.write_logs_to_logger(logging.error)
99
118
  return False
100
119
  return True
120
+
121
+ def upgrade_rosa_roles_v2(
122
+ self,
123
+ cluster: OCMCluster,
124
+ upgrade_version: str,
125
+ dry_run: bool,
126
+ ocm_api: OCMBaseClient,
127
+ ocm_org_id: str,
128
+ ) -> bool:
129
+ if not cluster.aws:
130
+ return False
131
+ rosa = RosaSession(
132
+ aws_account_id=cluster.aws.aws_account_id,
133
+ aws_region=cluster.region.id,
134
+ aws_iam_role=self.aws_iam_role,
135
+ ocm_org_id=ocm_org_id,
136
+ ocm_api=ocm_api,
137
+ job_controller=self.job_controller,
138
+ image=self.rosa_job_image,
139
+ service_account=self.rosa_job_service_account,
140
+ )
141
+ policy_version = get_version_prefix(upgrade_version)
142
+ try:
143
+ rosa.upgrade_rosa_roles(
144
+ cluster_name=cluster.name,
145
+ upgrade_version=upgrade_version,
146
+ policy_version=policy_version,
147
+ dry_run=dry_run,
148
+ )
149
+ except RosaCliError as e:
150
+ logging.error(f"Failed to upgrade roles for cluster {cluster.name}: {e}")
151
+ e.write_logs_to_logger(logging.error)
152
+ return False
153
+ return True