qontract-reconcile 0.10.2.dev361__py3-none-any.whl → 0.10.2.dev474__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 (371) hide show
  1. {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev474.dist-info}/METADATA +14 -13
  2. {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev474.dist-info}/RECORD +371 -364
  3. {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev474.dist-info}/WHEEL +1 -1
  4. reconcile/acs_rbac.py +2 -2
  5. reconcile/aus/advanced_upgrade_service.py +18 -12
  6. reconcile/aus/aus_sts_gate_handler.py +59 -0
  7. reconcile/aus/base.py +137 -34
  8. reconcile/aus/cluster_version_data.py +15 -5
  9. reconcile/aus/models.py +3 -1
  10. reconcile/aus/ocm_addons_upgrade_scheduler_org.py +1 -0
  11. reconcile/aus/ocm_upgrade_scheduler.py +8 -1
  12. reconcile/aus/ocm_upgrade_scheduler_org.py +20 -5
  13. reconcile/aus/version_gate_approver.py +1 -16
  14. reconcile/aus/version_gates/sts_version_gate_handler.py +5 -72
  15. reconcile/automated_actions/config/integration.py +16 -4
  16. reconcile/aws_account_manager/integration.py +21 -9
  17. reconcile/aws_account_manager/reconciler.py +3 -3
  18. reconcile/aws_account_manager/utils.py +1 -1
  19. reconcile/aws_ami_cleanup/integration.py +8 -12
  20. reconcile/aws_ami_share.py +69 -62
  21. reconcile/aws_cloudwatch_log_retention/integration.py +155 -126
  22. reconcile/aws_ecr_image_pull_secrets.py +1 -1
  23. reconcile/aws_iam_keys.py +1 -0
  24. reconcile/aws_saml_idp/integration.py +12 -4
  25. reconcile/aws_saml_roles/integration.py +30 -23
  26. reconcile/aws_version_sync/integration.py +6 -12
  27. reconcile/change_owners/README.md +1 -1
  28. reconcile/change_owners/bundle.py +3 -3
  29. reconcile/change_owners/change_log_tracking.py +3 -2
  30. reconcile/change_owners/change_owners.py +108 -42
  31. reconcile/change_owners/decision.py +1 -1
  32. reconcile/change_owners/diff.py +0 -2
  33. reconcile/checkpoint.py +11 -3
  34. reconcile/cli.py +94 -11
  35. reconcile/dashdotdb_dora.py +5 -12
  36. reconcile/dashdotdb_slo.py +1 -1
  37. reconcile/database_access_manager.py +123 -117
  38. reconcile/dynatrace_token_provider/integration.py +1 -1
  39. reconcile/endpoints_discovery/integration.py +4 -1
  40. reconcile/endpoints_discovery/merge_request.py +1 -1
  41. reconcile/endpoints_discovery/merge_request_manager.py +8 -8
  42. reconcile/external_resources/factories.py +4 -6
  43. reconcile/external_resources/integration.py +1 -1
  44. reconcile/external_resources/manager.py +8 -6
  45. reconcile/external_resources/meta.py +0 -1
  46. reconcile/external_resources/metrics.py +1 -1
  47. reconcile/external_resources/model.py +19 -15
  48. reconcile/external_resources/reconciler.py +7 -4
  49. reconcile/external_resources/secrets_sync.py +6 -10
  50. reconcile/external_resources/state.py +26 -16
  51. reconcile/fleet_labeler/integration.py +1 -1
  52. reconcile/gabi_authorized_users.py +5 -2
  53. reconcile/gcp_image_mirror.py +2 -2
  54. reconcile/github_org.py +1 -1
  55. reconcile/github_owners.py +4 -0
  56. reconcile/gitlab_housekeeping.py +13 -15
  57. reconcile/gitlab_members.py +6 -12
  58. reconcile/gitlab_owners.py +15 -11
  59. reconcile/gitlab_permissions.py +8 -12
  60. reconcile/glitchtip_project_alerts/integration.py +3 -1
  61. reconcile/gql_definitions/acs/acs_instances.py +5 -5
  62. reconcile/gql_definitions/acs/acs_policies.py +5 -5
  63. reconcile/gql_definitions/acs/acs_rbac.py +5 -5
  64. reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +5 -5
  65. reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +5 -5
  66. reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +5 -5
  67. reconcile/gql_definitions/app_sre_tekton_access_revalidation/roles.py +5 -5
  68. reconcile/gql_definitions/app_sre_tekton_access_revalidation/users.py +5 -5
  69. reconcile/gql_definitions/automated_actions/instance.py +46 -7
  70. reconcile/gql_definitions/aws_account_manager/aws_accounts.py +14 -5
  71. reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +15 -5
  72. reconcile/gql_definitions/aws_cloudwatch_log_retention/aws_accounts.py +27 -66
  73. reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +15 -5
  74. reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +15 -5
  75. reconcile/gql_definitions/aws_saml_roles/roles.py +5 -5
  76. reconcile/gql_definitions/aws_version_sync/clusters.py +5 -5
  77. reconcile/gql_definitions/aws_version_sync/namespaces.py +5 -5
  78. reconcile/gql_definitions/change_owners/queries/change_types.py +5 -5
  79. reconcile/gql_definitions/change_owners/queries/self_service_roles.py +5 -5
  80. reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +5 -5
  81. reconcile/gql_definitions/common/alerting_services_settings.py +5 -5
  82. reconcile/gql_definitions/common/app_code_component_repos.py +5 -5
  83. reconcile/gql_definitions/common/app_interface_custom_messages.py +5 -5
  84. reconcile/gql_definitions/common/app_interface_dms_settings.py +5 -5
  85. reconcile/gql_definitions/common/app_interface_repo_settings.py +5 -5
  86. reconcile/gql_definitions/common/app_interface_roles.py +5 -5
  87. reconcile/gql_definitions/common/app_interface_state_settings.py +5 -5
  88. reconcile/gql_definitions/common/app_interface_vault_settings.py +5 -5
  89. reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +5 -5
  90. reconcile/gql_definitions/common/apps.py +5 -5
  91. reconcile/gql_definitions/common/aws_vpc_requests.py +18 -5
  92. reconcile/gql_definitions/common/aws_vpcs.py +5 -5
  93. reconcile/gql_definitions/common/clusters.py +7 -5
  94. reconcile/gql_definitions/common/clusters_minimal.py +5 -5
  95. reconcile/gql_definitions/common/clusters_with_dms.py +5 -5
  96. reconcile/gql_definitions/common/clusters_with_peering.py +5 -5
  97. reconcile/gql_definitions/common/github_orgs.py +5 -5
  98. reconcile/gql_definitions/common/jira_settings.py +5 -5
  99. reconcile/gql_definitions/common/jiralert_settings.py +5 -5
  100. reconcile/gql_definitions/common/ldap_settings.py +5 -5
  101. reconcile/gql_definitions/common/namespaces.py +5 -5
  102. reconcile/gql_definitions/common/namespaces_minimal.py +7 -5
  103. reconcile/gql_definitions/common/ocm_env_telemeter.py +5 -5
  104. reconcile/gql_definitions/common/ocm_environments.py +5 -5
  105. reconcile/gql_definitions/common/pagerduty_instances.py +5 -5
  106. reconcile/gql_definitions/common/pgp_reencryption_settings.py +5 -5
  107. reconcile/gql_definitions/common/pipeline_providers.py +5 -5
  108. reconcile/gql_definitions/common/quay_instances.py +5 -5
  109. reconcile/gql_definitions/common/quay_orgs.py +5 -5
  110. reconcile/gql_definitions/common/reserved_networks.py +5 -5
  111. reconcile/gql_definitions/common/rhcs_provider_settings.py +5 -5
  112. reconcile/gql_definitions/common/saas_files.py +5 -5
  113. reconcile/gql_definitions/common/saas_target_namespaces.py +5 -5
  114. reconcile/gql_definitions/common/saasherder_settings.py +5 -5
  115. reconcile/gql_definitions/common/slack_workspaces.py +5 -5
  116. reconcile/gql_definitions/common/smtp_client_settings.py +5 -5
  117. reconcile/gql_definitions/common/state_aws_account.py +5 -5
  118. reconcile/gql_definitions/common/users.py +5 -5
  119. reconcile/gql_definitions/common/users_with_paths.py +5 -5
  120. reconcile/gql_definitions/cost_report/app_names.py +5 -5
  121. reconcile/gql_definitions/cost_report/cost_namespaces.py +5 -5
  122. reconcile/gql_definitions/cost_report/settings.py +5 -5
  123. reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +5 -5
  124. reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +5 -5
  125. reconcile/gql_definitions/dynatrace_token_provider/token_specs.py +5 -5
  126. reconcile/gql_definitions/email_sender/apps.py +5 -5
  127. reconcile/gql_definitions/email_sender/emails.py +5 -5
  128. reconcile/gql_definitions/email_sender/users.py +5 -5
  129. reconcile/gql_definitions/endpoints_discovery/apps.py +5 -5
  130. reconcile/gql_definitions/external_resources/aws_accounts.py +5 -5
  131. reconcile/gql_definitions/external_resources/external_resources_modules.py +5 -5
  132. reconcile/gql_definitions/external_resources/external_resources_namespaces.py +38 -7
  133. reconcile/gql_definitions/external_resources/external_resources_settings.py +5 -5
  134. reconcile/gql_definitions/external_resources/fragments/external_resources_module_overrides.py +5 -5
  135. reconcile/gql_definitions/fleet_labeler/fleet_labels.py +5 -5
  136. reconcile/gql_definitions/fragments/aus_organization.py +5 -5
  137. reconcile/gql_definitions/fragments/aws_account_common.py +7 -5
  138. reconcile/gql_definitions/fragments/aws_account_managed.py +5 -5
  139. reconcile/gql_definitions/fragments/aws_account_sso.py +5 -5
  140. reconcile/gql_definitions/fragments/aws_infra_management_account.py +5 -5
  141. reconcile/gql_definitions/fragments/aws_organization.py +33 -0
  142. reconcile/gql_definitions/fragments/aws_vpc.py +5 -5
  143. reconcile/gql_definitions/fragments/aws_vpc_request.py +12 -5
  144. reconcile/gql_definitions/fragments/container_image_mirror.py +5 -5
  145. reconcile/gql_definitions/fragments/deploy_resources.py +5 -5
  146. reconcile/gql_definitions/fragments/disable.py +5 -5
  147. reconcile/gql_definitions/fragments/email_service.py +5 -5
  148. reconcile/gql_definitions/fragments/email_user.py +5 -5
  149. reconcile/gql_definitions/fragments/jumphost_common_fields.py +5 -5
  150. reconcile/gql_definitions/fragments/membership_source.py +5 -5
  151. reconcile/gql_definitions/fragments/minimal_ocm_organization.py +5 -5
  152. reconcile/gql_definitions/fragments/oc_connection_cluster.py +5 -5
  153. reconcile/gql_definitions/fragments/ocm_environment.py +5 -5
  154. reconcile/gql_definitions/fragments/pipeline_provider_retention.py +5 -5
  155. reconcile/gql_definitions/fragments/prometheus_instance.py +5 -5
  156. reconcile/gql_definitions/fragments/resource_limits_requirements.py +5 -5
  157. reconcile/gql_definitions/fragments/resource_requests_requirements.py +5 -5
  158. reconcile/gql_definitions/fragments/resource_values.py +5 -5
  159. reconcile/gql_definitions/fragments/saas_slo_document.py +5 -5
  160. reconcile/gql_definitions/fragments/saas_target_namespace.py +5 -5
  161. reconcile/gql_definitions/fragments/serviceaccount_token.py +5 -5
  162. reconcile/gql_definitions/fragments/terraform_state.py +5 -5
  163. reconcile/gql_definitions/fragments/upgrade_policy.py +5 -5
  164. reconcile/gql_definitions/fragments/user.py +5 -5
  165. reconcile/gql_definitions/fragments/vault_secret.py +5 -5
  166. reconcile/gql_definitions/gcp/gcp_docker_repos.py +5 -5
  167. reconcile/gql_definitions/gcp/gcp_projects.py +5 -5
  168. reconcile/gql_definitions/gitlab_members/gitlab_instances.py +5 -5
  169. reconcile/gql_definitions/gitlab_members/permissions.py +5 -5
  170. reconcile/gql_definitions/glitchtip/glitchtip_instance.py +5 -5
  171. reconcile/gql_definitions/glitchtip/glitchtip_project.py +5 -5
  172. reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +5 -5
  173. reconcile/gql_definitions/integrations/integrations.py +5 -5
  174. reconcile/gql_definitions/introspection.json +775 -136
  175. reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +5 -5
  176. reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +5 -5
  177. reconcile/gql_definitions/jira/jira_servers.py +5 -5
  178. reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +9 -5
  179. reconcile/gql_definitions/jumphosts/jumphosts.py +5 -5
  180. reconcile/gql_definitions/ldap_groups/roles.py +5 -5
  181. reconcile/gql_definitions/ldap_groups/settings.py +5 -5
  182. reconcile/gql_definitions/maintenance/maintenances.py +5 -5
  183. reconcile/gql_definitions/membershipsources/roles.py +5 -5
  184. reconcile/gql_definitions/ocm_labels/clusters.py +5 -5
  185. reconcile/gql_definitions/ocm_labels/organizations.py +5 -5
  186. reconcile/gql_definitions/openshift_cluster_bots/clusters.py +5 -5
  187. reconcile/gql_definitions/openshift_groups/managed_groups.py +5 -5
  188. reconcile/gql_definitions/openshift_groups/managed_roles.py +5 -5
  189. reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +5 -5
  190. reconcile/gql_definitions/quay_membership/quay_membership.py +5 -5
  191. reconcile/gql_definitions/rhcs/certs.py +25 -79
  192. reconcile/gql_definitions/rhcs/openshift_resource_rhcs_cert.py +43 -0
  193. reconcile/gql_definitions/rhidp/organizations.py +5 -5
  194. reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +5 -5
  195. reconcile/gql_definitions/service_dependencies/service_dependencies.py +5 -5
  196. reconcile/gql_definitions/sharding/aws_accounts.py +5 -5
  197. reconcile/gql_definitions/sharding/ocm_organization.py +5 -5
  198. reconcile/gql_definitions/skupper_network/site_controller_template.py +5 -5
  199. reconcile/gql_definitions/skupper_network/skupper_networks.py +5 -5
  200. reconcile/gql_definitions/slack_usergroups/clusters.py +5 -5
  201. reconcile/gql_definitions/slack_usergroups/permissions.py +5 -5
  202. reconcile/gql_definitions/slack_usergroups/users.py +5 -5
  203. reconcile/gql_definitions/slo_documents/slo_documents.py +5 -5
  204. reconcile/gql_definitions/status_board/status_board.py +5 -5
  205. reconcile/gql_definitions/statuspage/statuspages.py +5 -5
  206. reconcile/gql_definitions/templating/template_collection.py +5 -5
  207. reconcile/gql_definitions/templating/templates.py +5 -5
  208. reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +5 -5
  209. reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +5 -5
  210. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +5 -5
  211. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +5 -5
  212. reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +5 -5
  213. reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +5 -5
  214. reconcile/gql_definitions/terraform_init/aws_accounts.py +19 -5
  215. reconcile/gql_definitions/terraform_repo/terraform_repo.py +5 -5
  216. reconcile/gql_definitions/terraform_resources/database_access_manager.py +5 -5
  217. reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +37 -7
  218. reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +15 -5
  219. reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +5 -5
  220. reconcile/gql_definitions/vault_instances/vault_instances.py +5 -5
  221. reconcile/gql_definitions/vault_policies/vault_policies.py +5 -5
  222. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +8 -5
  223. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +6 -5
  224. reconcile/integrations_manager.py +3 -3
  225. reconcile/jenkins_worker_fleets.py +10 -8
  226. reconcile/jira_permissions_validator.py +237 -122
  227. reconcile/ldap_groups/integration.py +1 -1
  228. reconcile/ocm/types.py +35 -57
  229. reconcile/ocm_aws_infrastructure_access.py +1 -1
  230. reconcile/ocm_clusters.py +4 -4
  231. reconcile/ocm_labels/integration.py +3 -2
  232. reconcile/ocm_machine_pools.py +33 -27
  233. reconcile/openshift_base.py +113 -4
  234. reconcile/openshift_cluster_bots.py +1 -1
  235. reconcile/openshift_namespace_labels.py +1 -1
  236. reconcile/openshift_namespaces.py +96 -101
  237. reconcile/openshift_resources_base.py +6 -2
  238. reconcile/openshift_rhcs_certs.py +74 -37
  239. reconcile/openshift_rolebindings.py +7 -11
  240. reconcile/openshift_saas_deploy.py +4 -5
  241. reconcile/openshift_saas_deploy_change_tester.py +9 -7
  242. reconcile/openshift_saas_deploy_trigger_cleaner.py +3 -5
  243. reconcile/openshift_serviceaccount_tokens.py +2 -2
  244. reconcile/openshift_upgrade_watcher.py +4 -4
  245. reconcile/oum/labelset.py +5 -3
  246. reconcile/oum/models.py +1 -4
  247. reconcile/prometheus_rules_tester/integration.py +3 -3
  248. reconcile/quay_base.py +25 -6
  249. reconcile/quay_membership.py +55 -29
  250. reconcile/quay_mirror.py +1 -1
  251. reconcile/quay_mirror_org.py +6 -4
  252. reconcile/quay_permissions.py +81 -75
  253. reconcile/quay_repos.py +35 -37
  254. reconcile/queries.py +132 -1
  255. reconcile/rhidp/common.py +3 -5
  256. reconcile/rhidp/sso_client/base.py +16 -5
  257. reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +1 -1
  258. reconcile/saas_auto_promotions_manager/subscriber.py +4 -3
  259. reconcile/skupper_network/integration.py +2 -2
  260. reconcile/slack_usergroups.py +35 -14
  261. reconcile/sql_query.py +1 -0
  262. reconcile/status_board.py +6 -6
  263. reconcile/statuspage/atlassian.py +7 -7
  264. reconcile/statuspage/integrations/maintenances.py +4 -3
  265. reconcile/statuspage/page.py +4 -9
  266. reconcile/statuspage/status.py +5 -8
  267. reconcile/templates/rosa-classic-cluster-creation.sh.j2 +1 -1
  268. reconcile/templates/rosa-hcp-cluster-creation.sh.j2 +1 -1
  269. reconcile/templating/lib/rendering.py +3 -3
  270. reconcile/templating/renderer.py +2 -2
  271. reconcile/templating/validator.py +4 -4
  272. reconcile/terraform_aws_route53.py +7 -1
  273. reconcile/terraform_cloudflare_dns.py +3 -3
  274. reconcile/terraform_cloudflare_resources.py +5 -5
  275. reconcile/terraform_cloudflare_users.py +3 -2
  276. reconcile/terraform_init/integration.py +187 -23
  277. reconcile/terraform_repo.py +16 -12
  278. reconcile/terraform_resources.py +6 -6
  279. reconcile/terraform_tgw_attachments.py +27 -19
  280. reconcile/terraform_users.py +7 -0
  281. reconcile/terraform_vpc_peerings.py +14 -3
  282. reconcile/terraform_vpc_resources/integration.py +20 -8
  283. reconcile/terraform_vpc_resources/merge_request.py +12 -2
  284. reconcile/terraform_vpc_resources/merge_request_manager.py +43 -19
  285. reconcile/typed_queries/aws_account_tags.py +41 -0
  286. reconcile/typed_queries/cost_report/app_names.py +1 -1
  287. reconcile/typed_queries/cost_report/cost_namespaces.py +2 -2
  288. reconcile/typed_queries/saas_files.py +20 -15
  289. reconcile/typed_queries/status_board.py +2 -2
  290. reconcile/unleash_feature_toggles/integration.py +4 -2
  291. reconcile/utils/acs/base.py +6 -3
  292. reconcile/utils/acs/policies.py +2 -2
  293. reconcile/utils/aws_api.py +51 -20
  294. reconcile/utils/aws_api_typed/api.py +38 -9
  295. reconcile/utils/aws_api_typed/cloudformation.py +149 -0
  296. reconcile/utils/aws_api_typed/logs.py +73 -0
  297. reconcile/utils/aws_api_typed/organization.py +4 -2
  298. reconcile/utils/binary.py +7 -12
  299. reconcile/utils/datetime_util.py +67 -0
  300. reconcile/utils/deadmanssnitch_api.py +1 -1
  301. reconcile/utils/differ.py +2 -3
  302. reconcile/utils/early_exit_cache.py +11 -12
  303. reconcile/utils/environ.py +5 -0
  304. reconcile/utils/expiration.py +7 -3
  305. reconcile/utils/external_resource_spec.py +2 -0
  306. reconcile/utils/filtering.py +1 -1
  307. reconcile/utils/gitlab_api.py +19 -5
  308. reconcile/utils/glitchtip/client.py +6 -2
  309. reconcile/utils/glitchtip/models.py +25 -28
  310. reconcile/utils/gql.py +4 -7
  311. reconcile/utils/helpers.py +1 -1
  312. reconcile/utils/instrumented_wrappers.py +1 -1
  313. reconcile/utils/internal_groups/client.py +2 -2
  314. reconcile/utils/internal_groups/models.py +8 -17
  315. reconcile/utils/jinja2/utils.py +6 -101
  316. reconcile/utils/jira_client.py +82 -63
  317. reconcile/utils/jjb_client.py +26 -13
  318. reconcile/utils/jobcontroller/controller.py +2 -2
  319. reconcile/utils/jobcontroller/models.py +17 -1
  320. reconcile/utils/json.py +43 -1
  321. reconcile/utils/membershipsources/app_interface_resolver.py +4 -2
  322. reconcile/utils/membershipsources/models.py +16 -23
  323. reconcile/utils/membershipsources/resolver.py +4 -2
  324. reconcile/utils/merge_request_manager/merge_request_manager.py +4 -4
  325. reconcile/utils/merge_request_manager/parser.py +6 -6
  326. reconcile/utils/metrics.py +5 -5
  327. reconcile/utils/models.py +304 -82
  328. reconcile/utils/mr/app_interface_reporter.py +2 -2
  329. reconcile/utils/mr/notificator.py +3 -3
  330. reconcile/utils/mr/update_access_report_base.py +3 -4
  331. reconcile/utils/mr/user_maintenance.py +3 -2
  332. reconcile/utils/oc.py +252 -201
  333. reconcile/utils/oc_filters.py +3 -3
  334. reconcile/utils/ocm/addons.py +0 -1
  335. reconcile/utils/ocm/base.py +17 -20
  336. reconcile/utils/ocm/cluster_groups.py +1 -1
  337. reconcile/utils/ocm/identity_providers.py +2 -2
  338. reconcile/utils/ocm/labels.py +1 -1
  339. reconcile/utils/ocm/products.py +8 -8
  340. reconcile/utils/ocm/search_filters.py +3 -6
  341. reconcile/utils/ocm/service_log.py +4 -6
  342. reconcile/utils/ocm/sre_capability_labels.py +20 -13
  343. reconcile/utils/openshift_resource.py +8 -3
  344. reconcile/utils/pagerduty_api.py +10 -7
  345. reconcile/utils/promotion_state.py +6 -11
  346. reconcile/utils/quay_api.py +74 -87
  347. reconcile/utils/raw_github_api.py +1 -1
  348. reconcile/utils/rhcsv2_certs.py +86 -23
  349. reconcile/utils/rosa/session.py +16 -0
  350. reconcile/utils/runtime/integration.py +2 -3
  351. reconcile/utils/runtime/runner.py +2 -2
  352. reconcile/utils/saasherder/interfaces.py +13 -20
  353. reconcile/utils/saasherder/models.py +23 -20
  354. reconcile/utils/saasherder/saasherder.py +50 -27
  355. reconcile/utils/slack_api.py +2 -2
  356. reconcile/utils/sloth.py +171 -2
  357. reconcile/utils/structs.py +1 -1
  358. reconcile/utils/terraform_client.py +5 -4
  359. reconcile/utils/terrascript_aws_client.py +274 -124
  360. reconcile/utils/unleash/server.py +2 -8
  361. reconcile/utils/vault.py +5 -12
  362. reconcile/utils/vcs.py +8 -8
  363. reconcile/vault_replication.py +107 -42
  364. reconcile/vpc_peerings_validator.py +13 -0
  365. tools/app_interface_reporter.py +4 -4
  366. tools/cli_commands/cost_report/cost_management_api.py +3 -3
  367. tools/cli_commands/cost_report/view.py +7 -6
  368. tools/cli_commands/erv2.py +1 -1
  369. tools/qontract_cli.py +28 -17
  370. tools/template_validation.py +3 -1
  371. {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev474.dist-info}/entry_points.txt +0 -0
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
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):
@@ -0,0 +1,59 @@
1
+ import logging
2
+
3
+ from reconcile.utils.jobcontroller.controller import K8sJobController
4
+ from reconcile.utils.ocm.base import OCMCluster
5
+ from reconcile.utils.ocm_base_client import OCMBaseClient
6
+ from reconcile.utils.rosa.rosa_cli import RosaCliError
7
+ from reconcile.utils.rosa.session import RosaSession
8
+ from reconcile.utils.semver_helper import get_version_prefix
9
+
10
+ STS_GATE_LABEL = "api.openshift.com/gate-sts"
11
+ AUS_VERSION_GATE_APPROVALS_LABEL = "sre-capabilities.aus.version-gate-approvals"
12
+
13
+
14
+ class AUSSTSGateHandler:
15
+ def __init__(
16
+ self,
17
+ job_controller: K8sJobController,
18
+ aws_iam_role: str,
19
+ rosa_job_service_account: str | None = None,
20
+ rosa_job_image: str | None = None,
21
+ ) -> None:
22
+ self.job_controller = job_controller
23
+ self.aws_iam_role = aws_iam_role
24
+ self.rosa_job_image = rosa_job_image
25
+ self.rosa_job_service_account = rosa_job_service_account
26
+
27
+ def upgrade_rosa_roles(
28
+ self,
29
+ cluster: OCMCluster,
30
+ upgrade_version: str,
31
+ dry_run: bool,
32
+ ocm_api: OCMBaseClient,
33
+ ocm_org_id: str,
34
+ ) -> bool:
35
+ if not cluster.aws:
36
+ return False
37
+ rosa = RosaSession(
38
+ aws_account_id=cluster.aws.aws_account_id,
39
+ aws_region=cluster.region.id,
40
+ aws_iam_role=self.aws_iam_role,
41
+ ocm_org_id=ocm_org_id,
42
+ ocm_api=ocm_api,
43
+ job_controller=self.job_controller,
44
+ image=self.rosa_job_image,
45
+ service_account=self.rosa_job_service_account,
46
+ )
47
+ policy_version = get_version_prefix(upgrade_version)
48
+ try:
49
+ rosa.upgrade_rosa_roles(
50
+ cluster_name=cluster.name,
51
+ upgrade_version=upgrade_version,
52
+ policy_version=policy_version,
53
+ dry_run=dry_run,
54
+ )
55
+ except RosaCliError as e:
56
+ logging.error(f"Failed to upgrade roles for cluster {cluster.name}: {e}")
57
+ e.write_logs_to_logger(logging.error)
58
+ return False
59
+ return True
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,10 +16,15 @@ 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
 
23
+ from reconcile.aus.aus_sts_gate_handler import (
24
+ AUS_VERSION_GATE_APPROVALS_LABEL,
25
+ STS_GATE_LABEL,
26
+ AUSSTSGateHandler,
27
+ )
24
28
  from reconcile.aus.cluster_version_data import (
25
29
  VersionData,
26
30
  VersionDataMap,
@@ -71,10 +75,18 @@ from reconcile.utils.clusterhealth.telemeter import (
71
75
  TELEMETER_SOURCE,
72
76
  TelemeterClusterHealthProvider,
73
77
  )
78
+ from reconcile.utils.datetime_util import (
79
+ ensure_utc,
80
+ from_utc_iso_format,
81
+ to_utc_seconds_iso_format,
82
+ utc_now,
83
+ )
74
84
  from reconcile.utils.defer import defer
75
85
  from reconcile.utils.disabled_integrations import integration_is_enabled
76
86
  from reconcile.utils.filtering import remove_none_values_from_dict
87
+ from reconcile.utils.jobcontroller.controller import build_job_controller
77
88
  from reconcile.utils.ocm.addons import AddonService, AddonServiceV1, AddonServiceV2
89
+ from reconcile.utils.ocm.base import LabelContainer
78
90
  from reconcile.utils.ocm.clusters import (
79
91
  OCMCluster,
80
92
  )
@@ -97,6 +109,7 @@ from reconcile.utils.runtime.integration import (
97
109
  PydanticRunParams,
98
110
  QontractReconcileIntegration,
99
111
  )
112
+ from reconcile.utils.secret_reader import SecretReaderBase
100
113
  from reconcile.utils.semver_helper import (
101
114
  get_version_prefix,
102
115
  parse_semver,
@@ -107,11 +120,22 @@ from reconcile.utils.state import init_state
107
120
  MIN_DELTA_MINUTES = 6
108
121
 
109
122
 
123
+ class RosaRoleUpgradeHandlerParams(PydanticRunParams):
124
+ job_controller_cluster: str
125
+ job_controller_namespace: str
126
+ rosa_job_service_account: str
127
+ rosa_role: str
128
+ rosa_job_image: str | None = None
129
+ integration_name: str
130
+ integration_version: str
131
+
132
+
110
133
  class AdvancedUpgradeSchedulerBaseIntegrationParams(PydanticRunParams):
111
134
  ocm_environment: str | None = None
112
135
  ocm_organization_ids: set[str] | None = None
113
136
  excluded_ocm_organization_ids: set[str] | None = None
114
137
  ignore_sts_clusters: bool = False
138
+ rosa_role_upgrade_handler_params: RosaRoleUpgradeHandlerParams | None = None
115
139
 
116
140
 
117
141
  class ReconcileError(Exception):
@@ -399,15 +423,20 @@ class AbstractUpgradePolicy(ABC, BaseModel):
399
423
 
400
424
  cluster: OCMCluster
401
425
 
402
- id: str | None
403
- next_run: str | None
404
- schedule: str | None
426
+ id: str | None = None
427
+ next_run: str | None = None
428
+ schedule: str | None = None
405
429
  schedule_type: str
406
430
  version: str
407
- state: str | None
431
+ state: str | None = None
408
432
 
409
433
  @abstractmethod
410
- def create(self, ocm_api: OCMBaseClient) -> None:
434
+ def create(
435
+ self,
436
+ ocm_api: OCMBaseClient,
437
+ rosa_role_upgrade_handler_params: RosaRoleUpgradeHandlerParams | None = None,
438
+ secret_reader: SecretReaderBase | None = None,
439
+ ) -> None:
411
440
  pass
412
441
 
413
442
  @abstractmethod
@@ -420,21 +449,23 @@ class AbstractUpgradePolicy(ABC, BaseModel):
420
449
 
421
450
 
422
451
  def addon_upgrade_policy_soonest_next_run() -> str:
423
- now = datetime.now(tz=dt.UTC)
452
+ now = utc_now()
424
453
  next_run = now + timedelta(minutes=MIN_DELTA_MINUTES)
425
- return next_run.strftime("%Y-%m-%dT%H:%M:%SZ")
454
+ return to_utc_seconds_iso_format(next_run)
426
455
 
427
456
 
428
- class AddonUpgradePolicy(AbstractUpgradePolicy):
457
+ class AddonUpgradePolicy(AbstractUpgradePolicy, arbitrary_types_allowed=True):
429
458
  """Class to create and delete Addon upgrade policies in OCM"""
430
459
 
431
460
  addon_id: str
432
461
  addon_service: AddonService
433
462
 
434
- class Config:
435
- arbitrary_types_allowed = True
436
-
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,64 @@ 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
+ aus_sts_gate_handler = AUSSTSGateHandler(
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 aus_sts_gate_handler.upgrade_rosa_roles(
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
+
553
+ return (
554
+ self.cluster.is_sts()
555
+ and self.cluster.is_rosa_classic()
556
+ and STS_GATE_LABEL in set(handler_csv.split(","))
557
+ )
558
+
478
559
  def delete(self, ocm_api: OCMBaseClient) -> None:
479
560
  raise NotImplementedError("ClusterUpgradePolicy.delete() not implemented")
480
561
 
@@ -492,7 +573,12 @@ class ClusterUpgradePolicy(AbstractUpgradePolicy):
492
573
  class ControlPlaneUpgradePolicy(AbstractUpgradePolicy):
493
574
  """Class to create and delete ControlPlanUpgradePolicies in OCM"""
494
575
 
495
- def create(self, ocm_api: OCMBaseClient) -> None:
576
+ def create(
577
+ self,
578
+ ocm_api: OCMBaseClient,
579
+ rosa_role_upgrade_handler_params: RosaRoleUpgradeHandlerParams | None = None,
580
+ secret_reader: SecretReaderBase | None = None,
581
+ ) -> None:
496
582
  policy = {
497
583
  "version": self.version,
498
584
  "schedule_type": "manual",
@@ -516,10 +602,16 @@ class ControlPlaneUpgradePolicy(AbstractUpgradePolicy):
516
602
 
517
603
 
518
604
  class NodePoolUpgradePolicy(AbstractUpgradePolicy):
519
- node_pool: str
520
605
  """Class to create NodePoolUpgradePolicies in OCM"""
521
606
 
522
- def create(self, ocm_api: OCMBaseClient) -> None:
607
+ node_pool: str
608
+
609
+ def create(
610
+ self,
611
+ ocm_api: OCMBaseClient,
612
+ rosa_role_upgrade_handler_params: RosaRoleUpgradeHandlerParams | None = None,
613
+ secret_reader: SecretReaderBase | None = None,
614
+ ) -> None:
523
615
  policy = {
524
616
  "version": self.version,
525
617
  "schedule_type": "manual",
@@ -545,13 +637,19 @@ class NodePoolUpgradePolicy(AbstractUpgradePolicy):
545
637
  return f"node pool upgrade policy - {remove_none_values_from_dict(details)}"
546
638
 
547
639
 
548
- class UpgradePolicyHandler(BaseModel, extra=Extra.forbid):
640
+ class UpgradePolicyHandler(BaseModel, extra="forbid"):
549
641
  """Class to handle upgrade policy actions"""
550
642
 
551
643
  action: str
552
644
  policy: AbstractUpgradePolicy
553
645
 
554
- def act(self, dry_run: bool, ocm_api: OCMBaseClient) -> None:
646
+ def act(
647
+ self,
648
+ dry_run: bool,
649
+ ocm_api: OCMBaseClient,
650
+ rosa_role_upgrade_handler_params: RosaRoleUpgradeHandlerParams | None = None,
651
+ secret_reader: SecretReaderBase | None = None,
652
+ ) -> None:
555
653
  logging.info(f"{self.action} {self.policy.summarize()}")
556
654
  if dry_run:
557
655
  return
@@ -561,7 +659,7 @@ class UpgradePolicyHandler(BaseModel, extra=Extra.forbid):
561
659
  elif self.action == "delete":
562
660
  self.policy.delete(ocm_api)
563
661
  elif self.action == "create":
564
- self.policy.create(ocm_api)
662
+ self.policy.create(ocm_api, rosa_role_upgrade_handler_params, secret_reader)
565
663
 
566
664
 
567
665
  def fetch_current_state(
@@ -579,6 +677,7 @@ def fetch_current_state(
579
677
  )
580
678
  current_state.extend(
581
679
  AddonUpgradePolicy(
680
+ organization_id=spec.org.org_id,
582
681
  id=addon_upgrade_policy.id,
583
682
  addon_id=addon_spec.addon.addon.id,
584
683
  cluster=spec.cluster,
@@ -615,6 +714,8 @@ def fetch_current_state(
615
714
  for upgrade_policy in upgrade_policies:
616
715
  policy = upgrade_policy | {
617
716
  "cluster": spec.cluster,
717
+ "organization_id": spec.org.org_id,
718
+ "cluster_labels": spec.cluster_labels,
618
719
  }
619
720
  current_state.append(ClusterUpgradePolicy(**policy))
620
721
 
@@ -638,8 +739,8 @@ def update_history(
638
739
  version_data (VersionData): version data, including history of soakdays
639
740
  upgrade_policies (list): query results of clusters upgrade policies
640
741
  """
641
- now = datetime.utcnow()
642
- check_in = version_data.check_in or now
742
+ now = utc_now()
743
+ check_in = ensure_utc(version_data.check_in or now)
643
744
 
644
745
  # we iterate over clusters upgrade policies and update the version history
645
746
  for spec in org_upgrade_spec.specs:
@@ -930,7 +1031,7 @@ def verify_schedule_should_skip(
930
1031
  # immediately
931
1032
  delay_minutes = 1 if addon_id else MIN_DELTA_MINUTES
932
1033
  next_schedule = iter.get_next(
933
- dt.datetime, start_time=now + timedelta(minutes=delay_minutes)
1034
+ datetime, start_time=now + timedelta(minutes=delay_minutes)
934
1035
  )
935
1036
  next_schedule_in_seconds = (next_schedule - now).total_seconds()
936
1037
  next_schedule_in_hours = next_schedule_in_seconds / 3600 # seconds in hour
@@ -947,7 +1048,7 @@ def verify_schedule_should_skip(
947
1048
  f"[{desired.org.org_id}/{desired.org.name}/{desired.cluster.name}] skipping cluster with no upcoming upgrade"
948
1049
  )
949
1050
  return None
950
- return next_schedule.strftime("%Y-%m-%dT%H:%M:%SZ")
1051
+ return to_utc_seconds_iso_format(next_schedule)
951
1052
 
952
1053
 
953
1054
  def verify_max_upgrades_should_skip(
@@ -1013,6 +1114,8 @@ def _create_upgrade_policy(
1013
1114
  )
1014
1115
  return ClusterUpgradePolicy(
1015
1116
  cluster=spec.cluster,
1117
+ organization_id=spec.org.org_id,
1118
+ cluster_labels=spec.cluster_labels,
1016
1119
  version=version,
1017
1120
  schedule_type="manual",
1018
1121
  next_run=next_schedule,
@@ -1024,8 +1127,8 @@ def _calculate_node_pool_diffs(
1024
1127
  ) -> UpgradePolicyHandler | None:
1025
1128
  for pool in spec.node_pools:
1026
1129
  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"
1130
+ next_schedule = to_utc_seconds_iso_format(
1131
+ now + timedelta(minutes=MIN_DELTA_MINUTES)
1029
1132
  )
1030
1133
  return UpgradePolicyHandler(
1031
1134
  action="create",
@@ -1082,7 +1185,7 @@ def calculate_diff(
1082
1185
  set_upgrading(spec.cluster.id, spec.effective_mutexes, sector_name)
1083
1186
 
1084
1187
  addon_service = init_addon_service(desired_state.org.environment)
1085
- now = datetime.utcnow()
1188
+ now = utc_now()
1086
1189
  gates = get_version_gates(ocm_api)
1087
1190
  for spec in desired_state.specs:
1088
1191
  sector_name = spec.upgrade_policy.conditions.sector
@@ -1120,11 +1223,11 @@ def calculate_diff(
1120
1223
  action="create",
1121
1224
  policy=AddonUpgradePolicy(
1122
1225
  action="create",
1226
+ organization_id=spec.org.org_id,
1123
1227
  cluster=spec.cluster,
1124
1228
  version=version,
1125
1229
  schedule_type="manual",
1126
1230
  addon_id=addon_id,
1127
- upgrade_type="ADDON",
1128
1231
  addon_service=addon_service,
1129
1232
  ),
1130
1233
  )
@@ -1185,6 +1288,8 @@ def act(
1185
1288
  dry_run: bool,
1186
1289
  diffs: list[UpgradePolicyHandler],
1187
1290
  ocm_api: OCMBaseClient,
1291
+ rosa_role_upgrade_handler_params: RosaRoleUpgradeHandlerParams | None = None,
1292
+ secret_reader: SecretReaderBase | None = None,
1188
1293
  addon_id: str | None = None,
1189
1294
  ) -> None:
1190
1295
  diffs.sort(key=sort_diffs)
@@ -1197,7 +1302,7 @@ def act(
1197
1302
  ):
1198
1303
  continue
1199
1304
  try:
1200
- diff.act(dry_run, ocm_api)
1305
+ diff.act(dry_run, ocm_api, rosa_role_upgrade_handler_params, secret_reader)
1201
1306
  except HTTPError as e:
1202
1307
  logging.error(f"{policy.cluster.name}: {e}: {e.response.text}")
1203
1308
 
@@ -1297,10 +1402,8 @@ def remaining_soak_day_metric_values_for_cluster(
1297
1402
  remaining_soakdays[idx] = UPGRADE_STARTED_METRIC_VALUE
1298
1403
  if current_upgrade.next_run:
1299
1404
  # 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()
1405
+ next_run = from_utc_iso_format(current_upgrade.next_run)
1406
+ now = utc_now()
1304
1407
  hours_ago = (now - next_run).total_seconds() / 3600
1305
1408
  if hours_ago >= 6:
1306
1409
  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,