qontract-reconcile 0.9.1rc298__py3-none-any.whl → 0.10.1.dev1203__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 (843) hide show
  1. qontract_reconcile-0.10.1.dev1203.dist-info/METADATA +500 -0
  2. qontract_reconcile-0.10.1.dev1203.dist-info/RECORD +771 -0
  3. {qontract_reconcile-0.9.1rc298.dist-info → qontract_reconcile-0.10.1.dev1203.dist-info}/WHEEL +1 -2
  4. {qontract_reconcile-0.9.1rc298.dist-info → qontract_reconcile-0.10.1.dev1203.dist-info}/entry_points.txt +4 -2
  5. reconcile/acs_notifiers.py +126 -0
  6. reconcile/acs_policies.py +243 -0
  7. reconcile/acs_rbac.py +596 -0
  8. reconcile/aus/advanced_upgrade_service.py +621 -8
  9. reconcile/aus/aus_label_source.py +115 -0
  10. reconcile/aus/base.py +1053 -353
  11. reconcile/{utils → aus}/cluster_version_data.py +27 -12
  12. reconcile/aus/healthchecks.py +77 -0
  13. reconcile/aus/metrics.py +158 -0
  14. reconcile/aus/models.py +245 -5
  15. reconcile/aus/node_pool_spec.py +35 -0
  16. reconcile/aus/ocm_addons_upgrade_scheduler_org.py +225 -110
  17. reconcile/aus/ocm_upgrade_scheduler.py +76 -71
  18. reconcile/aus/ocm_upgrade_scheduler_org.py +81 -23
  19. reconcile/aus/version_gate_approver.py +204 -0
  20. reconcile/aus/version_gates/__init__.py +12 -0
  21. reconcile/aus/version_gates/handler.py +33 -0
  22. reconcile/aus/version_gates/ingress_gate_handler.py +32 -0
  23. reconcile/aus/version_gates/ocp_gate_handler.py +26 -0
  24. reconcile/aus/version_gates/sts_version_gate_handler.py +100 -0
  25. reconcile/aws_account_manager/README.md +5 -0
  26. reconcile/aws_account_manager/integration.py +373 -0
  27. reconcile/aws_account_manager/merge_request_manager.py +114 -0
  28. reconcile/aws_account_manager/metrics.py +39 -0
  29. reconcile/aws_account_manager/reconciler.py +403 -0
  30. reconcile/aws_account_manager/utils.py +41 -0
  31. reconcile/aws_ami_cleanup/integration.py +273 -0
  32. reconcile/aws_ami_share.py +18 -14
  33. reconcile/aws_cloudwatch_log_retention/integration.py +253 -0
  34. reconcile/aws_iam_keys.py +1 -1
  35. reconcile/aws_iam_password_reset.py +56 -20
  36. reconcile/aws_saml_idp/integration.py +204 -0
  37. reconcile/aws_saml_roles/integration.py +322 -0
  38. reconcile/aws_support_cases_sos.py +2 -2
  39. reconcile/aws_version_sync/integration.py +430 -0
  40. reconcile/aws_version_sync/merge_request_manager/merge_request.py +156 -0
  41. reconcile/aws_version_sync/merge_request_manager/merge_request_manager.py +160 -0
  42. reconcile/aws_version_sync/utils.py +64 -0
  43. reconcile/blackbox_exporter_endpoint_monitoring.py +2 -5
  44. reconcile/change_owners/README.md +34 -0
  45. reconcile/change_owners/approver.py +7 -9
  46. reconcile/change_owners/bundle.py +134 -9
  47. reconcile/change_owners/change_log_tracking.py +236 -0
  48. reconcile/change_owners/change_owners.py +204 -194
  49. reconcile/change_owners/change_types.py +183 -265
  50. reconcile/change_owners/changes.py +488 -0
  51. reconcile/change_owners/decision.py +120 -41
  52. reconcile/change_owners/diff.py +63 -92
  53. reconcile/change_owners/implicit_ownership.py +19 -16
  54. reconcile/change_owners/self_service_roles.py +158 -35
  55. reconcile/change_owners/tester.py +20 -18
  56. reconcile/checkpoint.py +4 -6
  57. reconcile/cli.py +1523 -242
  58. reconcile/closedbox_endpoint_monitoring_base.py +10 -17
  59. reconcile/cluster_auth_rhidp/integration.py +257 -0
  60. reconcile/cluster_deployment_mapper.py +2 -5
  61. reconcile/cna/assets/asset.py +4 -7
  62. reconcile/cna/assets/null.py +2 -5
  63. reconcile/cna/integration.py +2 -3
  64. reconcile/cna/state.py +6 -9
  65. reconcile/dashdotdb_base.py +31 -10
  66. reconcile/dashdotdb_cso.py +3 -6
  67. reconcile/dashdotdb_dora.py +530 -0
  68. reconcile/dashdotdb_dvo.py +10 -13
  69. reconcile/dashdotdb_slo.py +75 -19
  70. reconcile/database_access_manager.py +753 -0
  71. reconcile/deadmanssnitch.py +207 -0
  72. reconcile/dynatrace_token_provider/dependencies.py +69 -0
  73. reconcile/dynatrace_token_provider/integration.py +656 -0
  74. reconcile/dynatrace_token_provider/metrics.py +62 -0
  75. reconcile/dynatrace_token_provider/model.py +14 -0
  76. reconcile/dynatrace_token_provider/ocm.py +140 -0
  77. reconcile/dynatrace_token_provider/validate.py +48 -0
  78. reconcile/endpoints_discovery/integration.py +348 -0
  79. reconcile/endpoints_discovery/merge_request.py +96 -0
  80. reconcile/endpoints_discovery/merge_request_manager.py +178 -0
  81. reconcile/external_resources/aws.py +204 -0
  82. reconcile/external_resources/factories.py +163 -0
  83. reconcile/external_resources/integration.py +194 -0
  84. reconcile/external_resources/integration_secrets_sync.py +47 -0
  85. reconcile/external_resources/manager.py +405 -0
  86. reconcile/external_resources/meta.py +17 -0
  87. reconcile/external_resources/metrics.py +95 -0
  88. reconcile/external_resources/model.py +350 -0
  89. reconcile/external_resources/reconciler.py +265 -0
  90. reconcile/external_resources/secrets_sync.py +465 -0
  91. reconcile/external_resources/state.py +258 -0
  92. reconcile/gabi_authorized_users.py +19 -11
  93. reconcile/gcr_mirror.py +43 -34
  94. reconcile/github_org.py +4 -6
  95. reconcile/github_owners.py +1 -1
  96. reconcile/github_repo_invites.py +2 -5
  97. reconcile/gitlab_fork_compliance.py +14 -13
  98. reconcile/gitlab_housekeeping.py +185 -91
  99. reconcile/gitlab_labeler.py +15 -14
  100. reconcile/gitlab_members.py +126 -120
  101. reconcile/gitlab_owners.py +53 -66
  102. reconcile/gitlab_permissions.py +167 -6
  103. reconcile/glitchtip/README.md +150 -0
  104. reconcile/glitchtip/integration.py +99 -51
  105. reconcile/glitchtip/reconciler.py +99 -70
  106. reconcile/glitchtip_project_alerts/__init__.py +0 -0
  107. reconcile/glitchtip_project_alerts/integration.py +333 -0
  108. reconcile/glitchtip_project_dsn/integration.py +43 -43
  109. reconcile/gql_definitions/acs/__init__.py +0 -0
  110. reconcile/gql_definitions/acs/acs_instances.py +83 -0
  111. reconcile/gql_definitions/acs/acs_policies.py +239 -0
  112. reconcile/gql_definitions/acs/acs_rbac.py +111 -0
  113. reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +46 -8
  114. reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +38 -8
  115. reconcile/gql_definitions/app_interface_metrics_exporter/__init__.py +0 -0
  116. reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +61 -0
  117. reconcile/gql_definitions/aws_account_manager/__init__.py +0 -0
  118. reconcile/gql_definitions/aws_account_manager/aws_accounts.py +177 -0
  119. reconcile/gql_definitions/aws_ami_cleanup/__init__.py +0 -0
  120. reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +161 -0
  121. reconcile/gql_definitions/aws_saml_idp/__init__.py +0 -0
  122. reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +117 -0
  123. reconcile/gql_definitions/aws_saml_roles/__init__.py +0 -0
  124. reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +117 -0
  125. reconcile/gql_definitions/aws_saml_roles/roles.py +97 -0
  126. reconcile/gql_definitions/aws_version_sync/__init__.py +0 -0
  127. reconcile/gql_definitions/aws_version_sync/clusters.py +83 -0
  128. reconcile/gql_definitions/aws_version_sync/namespaces.py +143 -0
  129. reconcile/gql_definitions/change_owners/queries/change_types.py +16 -29
  130. reconcile/gql_definitions/change_owners/queries/self_service_roles.py +45 -11
  131. reconcile/gql_definitions/cluster_auth_rhidp/__init__.py +0 -0
  132. reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +128 -0
  133. reconcile/gql_definitions/cna/queries/cna_provisioners.py +6 -8
  134. reconcile/gql_definitions/cna/queries/cna_resources.py +3 -5
  135. reconcile/gql_definitions/common/alerting_services_settings.py +2 -2
  136. reconcile/gql_definitions/common/app_code_component_repos.py +9 -5
  137. reconcile/gql_definitions/{glitchtip/glitchtip_settings.py → common/app_interface_custom_messages.py} +14 -16
  138. reconcile/gql_definitions/common/app_interface_dms_settings.py +86 -0
  139. reconcile/gql_definitions/common/app_interface_repo_settings.py +2 -2
  140. reconcile/gql_definitions/common/app_interface_state_settings.py +3 -5
  141. reconcile/gql_definitions/common/app_interface_vault_settings.py +3 -5
  142. reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +120 -0
  143. reconcile/gql_definitions/common/apps.py +72 -0
  144. reconcile/gql_definitions/common/aws_vpc_requests.py +109 -0
  145. reconcile/gql_definitions/common/aws_vpcs.py +84 -0
  146. reconcile/gql_definitions/common/clusters.py +120 -254
  147. reconcile/gql_definitions/common/clusters_minimal.py +11 -35
  148. reconcile/gql_definitions/common/clusters_with_dms.py +72 -0
  149. reconcile/gql_definitions/common/clusters_with_peering.py +70 -98
  150. reconcile/gql_definitions/common/github_orgs.py +2 -2
  151. reconcile/gql_definitions/common/jira_settings.py +68 -0
  152. reconcile/gql_definitions/common/jiralert_settings.py +68 -0
  153. reconcile/gql_definitions/common/namespaces.py +74 -32
  154. reconcile/gql_definitions/common/namespaces_minimal.py +4 -10
  155. reconcile/gql_definitions/common/ocm_env_telemeter.py +95 -0
  156. reconcile/gql_definitions/common/ocm_environments.py +4 -2
  157. reconcile/gql_definitions/common/pagerduty_instances.py +5 -5
  158. reconcile/gql_definitions/common/pgp_reencryption_settings.py +5 -11
  159. reconcile/gql_definitions/common/pipeline_providers.py +45 -90
  160. reconcile/gql_definitions/common/quay_instances.py +64 -0
  161. reconcile/gql_definitions/common/quay_orgs.py +68 -0
  162. reconcile/gql_definitions/common/reserved_networks.py +94 -0
  163. reconcile/gql_definitions/common/saas_files.py +133 -95
  164. reconcile/gql_definitions/common/saas_target_namespaces.py +41 -26
  165. reconcile/gql_definitions/common/saasherder_settings.py +2 -2
  166. reconcile/gql_definitions/common/slack_workspaces.py +62 -0
  167. reconcile/gql_definitions/common/smtp_client_settings.py +2 -2
  168. reconcile/gql_definitions/common/state_aws_account.py +77 -0
  169. reconcile/gql_definitions/common/users.py +3 -2
  170. reconcile/gql_definitions/cost_report/__init__.py +0 -0
  171. reconcile/gql_definitions/cost_report/app_names.py +68 -0
  172. reconcile/gql_definitions/cost_report/cost_namespaces.py +86 -0
  173. reconcile/gql_definitions/cost_report/settings.py +77 -0
  174. reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +42 -12
  175. reconcile/gql_definitions/dynatrace_token_provider/__init__.py +0 -0
  176. reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +79 -0
  177. reconcile/gql_definitions/dynatrace_token_provider/token_specs.py +84 -0
  178. reconcile/gql_definitions/endpoints_discovery/__init__.py +0 -0
  179. reconcile/gql_definitions/endpoints_discovery/namespaces.py +127 -0
  180. reconcile/gql_definitions/external_resources/__init__.py +0 -0
  181. reconcile/gql_definitions/external_resources/aws_accounts.py +73 -0
  182. reconcile/gql_definitions/external_resources/external_resources_modules.py +78 -0
  183. reconcile/gql_definitions/external_resources/external_resources_namespaces.py +1111 -0
  184. reconcile/gql_definitions/external_resources/external_resources_settings.py +98 -0
  185. reconcile/gql_definitions/fragments/aus_organization.py +34 -39
  186. reconcile/gql_definitions/fragments/aws_account_common.py +62 -0
  187. reconcile/gql_definitions/fragments/aws_account_managed.py +57 -0
  188. reconcile/gql_definitions/fragments/aws_account_sso.py +35 -0
  189. reconcile/gql_definitions/fragments/aws_infra_management_account.py +2 -2
  190. reconcile/gql_definitions/fragments/aws_vpc.py +47 -0
  191. reconcile/gql_definitions/fragments/aws_vpc_request.py +65 -0
  192. reconcile/gql_definitions/fragments/aws_vpc_request_subnet.py +29 -0
  193. reconcile/gql_definitions/fragments/deplopy_resources.py +7 -7
  194. reconcile/gql_definitions/fragments/disable.py +28 -0
  195. reconcile/gql_definitions/fragments/jumphost_common_fields.py +2 -2
  196. reconcile/gql_definitions/fragments/membership_source.py +47 -0
  197. reconcile/gql_definitions/fragments/minimal_ocm_organization.py +29 -0
  198. reconcile/gql_definitions/fragments/oc_connection_cluster.py +4 -9
  199. reconcile/gql_definitions/fragments/ocm_environment.py +5 -5
  200. reconcile/gql_definitions/fragments/pipeline_provider_retention.py +30 -0
  201. reconcile/gql_definitions/fragments/prometheus_instance.py +48 -0
  202. reconcile/gql_definitions/fragments/resource_limits_requirements.py +29 -0
  203. reconcile/gql_definitions/fragments/{resource_requirements.py → resource_requests_requirements.py} +3 -3
  204. reconcile/gql_definitions/fragments/resource_values.py +2 -2
  205. reconcile/gql_definitions/fragments/saas_target_namespace.py +55 -12
  206. reconcile/gql_definitions/fragments/serviceaccount_token.py +38 -0
  207. reconcile/gql_definitions/fragments/terraform_state.py +36 -0
  208. reconcile/gql_definitions/fragments/upgrade_policy.py +5 -3
  209. reconcile/gql_definitions/fragments/user.py +3 -2
  210. reconcile/gql_definitions/fragments/vault_secret.py +2 -2
  211. reconcile/gql_definitions/gitlab_members/gitlab_instances.py +6 -2
  212. reconcile/gql_definitions/gitlab_members/permissions.py +3 -5
  213. reconcile/gql_definitions/glitchtip/glitchtip_instance.py +16 -2
  214. reconcile/gql_definitions/glitchtip/glitchtip_project.py +22 -23
  215. reconcile/gql_definitions/glitchtip_project_alerts/__init__.py +0 -0
  216. reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +173 -0
  217. reconcile/gql_definitions/integrations/integrations.py +62 -45
  218. reconcile/gql_definitions/introspection.json +51176 -0
  219. reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +13 -5
  220. reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +79 -0
  221. reconcile/gql_definitions/jira/__init__.py +0 -0
  222. reconcile/gql_definitions/jira/jira_servers.py +80 -0
  223. reconcile/gql_definitions/jira_permissions_validator/__init__.py +0 -0
  224. reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +131 -0
  225. reconcile/gql_definitions/jumphosts/jumphosts.py +3 -5
  226. reconcile/gql_definitions/ldap_groups/__init__.py +0 -0
  227. reconcile/gql_definitions/ldap_groups/roles.py +111 -0
  228. reconcile/gql_definitions/ldap_groups/settings.py +79 -0
  229. reconcile/gql_definitions/maintenance/__init__.py +0 -0
  230. reconcile/gql_definitions/maintenance/maintenances.py +101 -0
  231. reconcile/gql_definitions/membershipsources/__init__.py +0 -0
  232. reconcile/gql_definitions/membershipsources/roles.py +112 -0
  233. reconcile/gql_definitions/ocm_labels/__init__.py +0 -0
  234. reconcile/gql_definitions/ocm_labels/clusters.py +112 -0
  235. reconcile/gql_definitions/ocm_labels/organizations.py +78 -0
  236. reconcile/gql_definitions/ocm_subscription_labels/__init__.py +0 -0
  237. reconcile/gql_definitions/openshift_cluster_bots/__init__.py +0 -0
  238. reconcile/gql_definitions/openshift_cluster_bots/clusters.py +126 -0
  239. reconcile/gql_definitions/openshift_groups/managed_groups.py +2 -2
  240. reconcile/gql_definitions/openshift_groups/managed_roles.py +3 -2
  241. reconcile/gql_definitions/openshift_serviceaccount_tokens/__init__.py +0 -0
  242. reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +132 -0
  243. reconcile/gql_definitions/quay_membership/quay_membership.py +3 -5
  244. reconcile/gql_definitions/rhidp/__init__.py +0 -0
  245. reconcile/gql_definitions/rhidp/organizations.py +96 -0
  246. reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +2 -2
  247. reconcile/gql_definitions/service_dependencies/service_dependencies.py +9 -31
  248. reconcile/gql_definitions/sharding/aws_accounts.py +2 -2
  249. reconcile/gql_definitions/sharding/ocm_organization.py +63 -0
  250. reconcile/gql_definitions/skupper_network/site_controller_template.py +2 -2
  251. reconcile/gql_definitions/skupper_network/skupper_networks.py +12 -38
  252. reconcile/gql_definitions/slack_usergroups/clusters.py +2 -2
  253. reconcile/gql_definitions/slack_usergroups/permissions.py +8 -15
  254. reconcile/gql_definitions/slack_usergroups/users.py +3 -2
  255. reconcile/gql_definitions/slo_documents/__init__.py +0 -0
  256. reconcile/gql_definitions/slo_documents/slo_documents.py +142 -0
  257. reconcile/gql_definitions/status_board/__init__.py +0 -0
  258. reconcile/gql_definitions/status_board/status_board.py +163 -0
  259. reconcile/gql_definitions/statuspage/statuspages.py +56 -7
  260. reconcile/gql_definitions/templating/__init__.py +0 -0
  261. reconcile/gql_definitions/templating/template_collection.py +130 -0
  262. reconcile/gql_definitions/templating/templates.py +108 -0
  263. reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +4 -8
  264. reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +8 -8
  265. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +6 -8
  266. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +45 -56
  267. reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +4 -8
  268. reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +4 -8
  269. reconcile/gql_definitions/terraform_init/__init__.py +0 -0
  270. reconcile/gql_definitions/terraform_init/aws_accounts.py +93 -0
  271. reconcile/gql_definitions/terraform_repo/__init__.py +0 -0
  272. reconcile/gql_definitions/terraform_repo/terraform_repo.py +141 -0
  273. reconcile/gql_definitions/terraform_resources/database_access_manager.py +158 -0
  274. reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +153 -162
  275. reconcile/gql_definitions/terraform_tgw_attachments/__init__.py +0 -0
  276. reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +119 -0
  277. reconcile/gql_definitions/unleash_feature_toggles/__init__.py +0 -0
  278. reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +113 -0
  279. reconcile/gql_definitions/vault_instances/vault_instances.py +17 -50
  280. reconcile/gql_definitions/vault_policies/vault_policies.py +2 -2
  281. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +49 -12
  282. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +7 -2
  283. reconcile/integrations_manager.py +25 -13
  284. reconcile/jenkins/types.py +5 -1
  285. reconcile/jenkins_base.py +36 -0
  286. reconcile/jenkins_job_builder.py +10 -48
  287. reconcile/jenkins_job_builds_cleaner.py +40 -25
  288. reconcile/jenkins_job_cleaner.py +1 -3
  289. reconcile/jenkins_roles.py +22 -26
  290. reconcile/jenkins_webhooks.py +9 -6
  291. reconcile/jenkins_worker_fleets.py +11 -6
  292. reconcile/jira_permissions_validator.py +340 -0
  293. reconcile/jira_watcher.py +3 -5
  294. reconcile/ldap_groups/__init__.py +0 -0
  295. reconcile/ldap_groups/integration.py +279 -0
  296. reconcile/ldap_users.py +3 -0
  297. reconcile/ocm/types.py +39 -59
  298. reconcile/ocm_additional_routers.py +0 -1
  299. reconcile/ocm_addons_upgrade_tests_trigger.py +10 -15
  300. reconcile/ocm_aws_infrastructure_access.py +30 -32
  301. reconcile/ocm_clusters.py +217 -130
  302. reconcile/ocm_external_configuration_labels.py +15 -0
  303. reconcile/ocm_github_idp.py +1 -1
  304. reconcile/ocm_groups.py +25 -5
  305. reconcile/ocm_internal_notifications/__init__.py +0 -0
  306. reconcile/ocm_internal_notifications/integration.py +119 -0
  307. reconcile/ocm_labels/__init__.py +0 -0
  308. reconcile/ocm_labels/integration.py +409 -0
  309. reconcile/ocm_machine_pools.py +517 -108
  310. reconcile/ocm_upgrade_scheduler_org_updater.py +15 -11
  311. reconcile/openshift_base.py +609 -207
  312. reconcile/openshift_cluster_bots.py +344 -0
  313. reconcile/openshift_clusterrolebindings.py +15 -15
  314. reconcile/openshift_groups.py +42 -45
  315. reconcile/openshift_limitranges.py +1 -0
  316. reconcile/openshift_namespace_labels.py +22 -28
  317. reconcile/openshift_namespaces.py +22 -22
  318. reconcile/openshift_network_policies.py +4 -8
  319. reconcile/openshift_prometheus_rules.py +43 -0
  320. reconcile/openshift_resourcequotas.py +2 -16
  321. reconcile/openshift_resources.py +12 -10
  322. reconcile/openshift_resources_base.py +304 -328
  323. reconcile/openshift_rolebindings.py +18 -20
  324. reconcile/openshift_saas_deploy.py +105 -21
  325. reconcile/openshift_saas_deploy_change_tester.py +30 -35
  326. reconcile/openshift_saas_deploy_trigger_base.py +39 -36
  327. reconcile/openshift_saas_deploy_trigger_cleaner.py +41 -27
  328. reconcile/openshift_saas_deploy_trigger_configs.py +1 -2
  329. reconcile/openshift_saas_deploy_trigger_images.py +1 -2
  330. reconcile/openshift_saas_deploy_trigger_moving_commits.py +1 -2
  331. reconcile/openshift_saas_deploy_trigger_upstream_jobs.py +1 -2
  332. reconcile/openshift_serviceaccount_tokens.py +138 -74
  333. reconcile/openshift_tekton_resources.py +89 -24
  334. reconcile/openshift_upgrade_watcher.py +110 -62
  335. reconcile/openshift_users.py +16 -15
  336. reconcile/openshift_vault_secrets.py +11 -6
  337. reconcile/oum/__init__.py +0 -0
  338. reconcile/oum/base.py +387 -0
  339. reconcile/oum/labelset.py +55 -0
  340. reconcile/oum/metrics.py +71 -0
  341. reconcile/oum/models.py +69 -0
  342. reconcile/oum/providers.py +59 -0
  343. reconcile/oum/standalone.py +196 -0
  344. reconcile/prometheus_rules_tester/integration.py +31 -23
  345. reconcile/quay_base.py +4 -1
  346. reconcile/quay_membership.py +1 -2
  347. reconcile/quay_mirror.py +111 -61
  348. reconcile/quay_mirror_org.py +34 -21
  349. reconcile/quay_permissions.py +7 -3
  350. reconcile/quay_repos.py +24 -32
  351. reconcile/queries.py +263 -198
  352. reconcile/query_validator.py +3 -5
  353. reconcile/resource_scraper.py +3 -4
  354. reconcile/{template_tester.py → resource_template_tester.py} +3 -3
  355. reconcile/rhidp/__init__.py +0 -0
  356. reconcile/rhidp/common.py +214 -0
  357. reconcile/rhidp/metrics.py +20 -0
  358. reconcile/rhidp/ocm_oidc_idp/__init__.py +0 -0
  359. reconcile/rhidp/ocm_oidc_idp/base.py +221 -0
  360. reconcile/rhidp/ocm_oidc_idp/integration.py +56 -0
  361. reconcile/rhidp/ocm_oidc_idp/metrics.py +22 -0
  362. reconcile/rhidp/sso_client/__init__.py +0 -0
  363. reconcile/rhidp/sso_client/base.py +266 -0
  364. reconcile/rhidp/sso_client/integration.py +60 -0
  365. reconcile/rhidp/sso_client/metrics.py +39 -0
  366. reconcile/run_integration.py +293 -0
  367. reconcile/saas_auto_promotions_manager/integration.py +69 -24
  368. reconcile/saas_auto_promotions_manager/merge_request_manager/batcher.py +208 -0
  369. reconcile/saas_auto_promotions_manager/merge_request_manager/desired_state.py +28 -0
  370. reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request.py +3 -4
  371. reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager_v2.py +172 -0
  372. reconcile/saas_auto_promotions_manager/merge_request_manager/metrics.py +42 -0
  373. reconcile/saas_auto_promotions_manager/merge_request_manager/mr_parser.py +226 -0
  374. reconcile/saas_auto_promotions_manager/merge_request_manager/open_merge_requests.py +23 -0
  375. reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +108 -32
  376. reconcile/saas_auto_promotions_manager/meta.py +4 -0
  377. reconcile/saas_auto_promotions_manager/publisher.py +32 -4
  378. reconcile/saas_auto_promotions_manager/s3_exporter.py +77 -0
  379. reconcile/saas_auto_promotions_manager/subscriber.py +110 -23
  380. reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py +48 -41
  381. reconcile/saas_file_validator.py +16 -6
  382. reconcile/sendgrid_teammates.py +27 -12
  383. reconcile/service_dependencies.py +0 -3
  384. reconcile/signalfx_endpoint_monitoring.py +2 -5
  385. reconcile/skupper_network/integration.py +10 -11
  386. reconcile/skupper_network/models.py +3 -5
  387. reconcile/skupper_network/reconciler.py +28 -35
  388. reconcile/skupper_network/site_controller.py +8 -8
  389. reconcile/slack_base.py +4 -7
  390. reconcile/slack_usergroups.py +249 -171
  391. reconcile/sql_query.py +324 -171
  392. reconcile/status.py +0 -1
  393. reconcile/status_board.py +275 -0
  394. reconcile/statuspage/__init__.py +0 -5
  395. reconcile/statuspage/atlassian.py +219 -80
  396. reconcile/statuspage/integration.py +9 -97
  397. reconcile/statuspage/integrations/__init__.py +0 -0
  398. reconcile/statuspage/integrations/components.py +77 -0
  399. reconcile/statuspage/integrations/maintenances.py +111 -0
  400. reconcile/statuspage/page.py +107 -72
  401. reconcile/statuspage/state.py +6 -11
  402. reconcile/statuspage/status.py +8 -12
  403. reconcile/templates/rosa-classic-cluster-creation.sh.j2 +60 -0
  404. reconcile/templates/rosa-hcp-cluster-creation.sh.j2 +61 -0
  405. reconcile/templating/__init__.py +0 -0
  406. reconcile/templating/lib/__init__.py +0 -0
  407. reconcile/templating/lib/merge_request_manager.py +180 -0
  408. reconcile/templating/lib/model.py +20 -0
  409. reconcile/templating/lib/rendering.py +191 -0
  410. reconcile/templating/renderer.py +410 -0
  411. reconcile/templating/validator.py +153 -0
  412. reconcile/terraform_aws_route53.py +13 -10
  413. reconcile/terraform_cloudflare_dns.py +92 -122
  414. reconcile/terraform_cloudflare_resources.py +15 -13
  415. reconcile/terraform_cloudflare_users.py +27 -27
  416. reconcile/terraform_init/__init__.py +0 -0
  417. reconcile/terraform_init/integration.py +165 -0
  418. reconcile/terraform_init/merge_request.py +57 -0
  419. reconcile/terraform_init/merge_request_manager.py +102 -0
  420. reconcile/terraform_repo.py +403 -0
  421. reconcile/terraform_resources.py +266 -168
  422. reconcile/terraform_tgw_attachments.py +417 -167
  423. reconcile/terraform_users.py +40 -17
  424. reconcile/terraform_vpc_peerings.py +310 -142
  425. reconcile/terraform_vpc_resources/__init__.py +0 -0
  426. reconcile/terraform_vpc_resources/integration.py +220 -0
  427. reconcile/terraform_vpc_resources/merge_request.py +57 -0
  428. reconcile/terraform_vpc_resources/merge_request_manager.py +107 -0
  429. reconcile/typed_queries/alerting_services_settings.py +1 -2
  430. reconcile/typed_queries/app_interface_custom_messages.py +24 -0
  431. reconcile/typed_queries/app_interface_deadmanssnitch_settings.py +17 -0
  432. reconcile/typed_queries/app_interface_metrics_exporter/__init__.py +0 -0
  433. reconcile/typed_queries/app_interface_metrics_exporter/onboarding_status.py +13 -0
  434. reconcile/typed_queries/app_interface_repo_url.py +1 -2
  435. reconcile/typed_queries/app_interface_state_settings.py +1 -3
  436. reconcile/typed_queries/app_interface_vault_settings.py +1 -2
  437. reconcile/typed_queries/app_quay_repos_escalation_policies.py +14 -0
  438. reconcile/typed_queries/apps.py +11 -0
  439. reconcile/typed_queries/aws_vpc_requests.py +9 -0
  440. reconcile/typed_queries/aws_vpcs.py +12 -0
  441. reconcile/typed_queries/cloudflare.py +10 -0
  442. reconcile/typed_queries/clusters.py +7 -5
  443. reconcile/typed_queries/clusters_minimal.py +6 -5
  444. reconcile/typed_queries/clusters_with_dms.py +16 -0
  445. reconcile/typed_queries/cost_report/__init__.py +0 -0
  446. reconcile/typed_queries/cost_report/app_names.py +22 -0
  447. reconcile/typed_queries/cost_report/cost_namespaces.py +43 -0
  448. reconcile/typed_queries/cost_report/settings.py +15 -0
  449. reconcile/typed_queries/dynatrace.py +10 -0
  450. reconcile/typed_queries/dynatrace_environments.py +14 -0
  451. reconcile/typed_queries/dynatrace_token_provider_token_specs.py +14 -0
  452. reconcile/typed_queries/external_resources.py +46 -0
  453. reconcile/typed_queries/get_state_aws_account.py +20 -0
  454. reconcile/typed_queries/glitchtip.py +10 -0
  455. reconcile/typed_queries/jenkins.py +25 -0
  456. reconcile/typed_queries/jira.py +7 -0
  457. reconcile/typed_queries/jira_settings.py +16 -0
  458. reconcile/typed_queries/jiralert_settings.py +22 -0
  459. reconcile/typed_queries/ocm.py +8 -0
  460. reconcile/typed_queries/pagerduty_instances.py +2 -7
  461. reconcile/typed_queries/quay.py +23 -0
  462. reconcile/typed_queries/repos.py +20 -8
  463. reconcile/typed_queries/reserved_networks.py +12 -0
  464. reconcile/typed_queries/saas_files.py +221 -167
  465. reconcile/typed_queries/slack.py +7 -0
  466. reconcile/typed_queries/slo_documents.py +12 -0
  467. reconcile/typed_queries/status_board.py +58 -0
  468. reconcile/typed_queries/tekton_pipeline_providers.py +1 -2
  469. reconcile/typed_queries/terraform_namespaces.py +1 -2
  470. reconcile/typed_queries/terraform_tgw_attachments/__init__.py +0 -0
  471. reconcile/typed_queries/terraform_tgw_attachments/aws_accounts.py +16 -0
  472. reconcile/typed_queries/unleash.py +10 -0
  473. reconcile/typed_queries/users.py +11 -0
  474. reconcile/typed_queries/vault.py +10 -0
  475. reconcile/unleash_feature_toggles/__init__.py +0 -0
  476. reconcile/unleash_feature_toggles/integration.py +287 -0
  477. reconcile/utils/acs/__init__.py +0 -0
  478. reconcile/utils/acs/base.py +81 -0
  479. reconcile/utils/acs/notifiers.py +143 -0
  480. reconcile/utils/acs/policies.py +163 -0
  481. reconcile/utils/acs/rbac.py +277 -0
  482. reconcile/utils/aggregated_list.py +11 -9
  483. reconcile/utils/amtool.py +6 -4
  484. reconcile/utils/aws_api.py +279 -66
  485. reconcile/utils/aws_api_typed/__init__.py +0 -0
  486. reconcile/utils/aws_api_typed/account.py +23 -0
  487. reconcile/utils/aws_api_typed/api.py +273 -0
  488. reconcile/utils/aws_api_typed/dynamodb.py +16 -0
  489. reconcile/utils/aws_api_typed/iam.py +67 -0
  490. reconcile/utils/aws_api_typed/organization.py +152 -0
  491. reconcile/utils/aws_api_typed/s3.py +26 -0
  492. reconcile/utils/aws_api_typed/service_quotas.py +79 -0
  493. reconcile/utils/aws_api_typed/sts.py +36 -0
  494. reconcile/utils/aws_api_typed/support.py +79 -0
  495. reconcile/utils/aws_helper.py +42 -3
  496. reconcile/utils/batches.py +11 -0
  497. reconcile/utils/binary.py +7 -9
  498. reconcile/utils/cloud_resource_best_practice/__init__.py +0 -0
  499. reconcile/utils/cloud_resource_best_practice/aws_rds.py +66 -0
  500. reconcile/utils/clusterhealth/__init__.py +0 -0
  501. reconcile/utils/clusterhealth/providerbase.py +39 -0
  502. reconcile/utils/clusterhealth/telemeter.py +39 -0
  503. reconcile/utils/config.py +3 -4
  504. reconcile/utils/deadmanssnitch_api.py +86 -0
  505. reconcile/utils/differ.py +205 -0
  506. reconcile/utils/disabled_integrations.py +4 -6
  507. reconcile/utils/dynatrace/__init__.py +0 -0
  508. reconcile/utils/dynatrace/client.py +93 -0
  509. reconcile/utils/early_exit_cache.py +289 -0
  510. reconcile/utils/elasticsearch_exceptions.py +5 -0
  511. reconcile/utils/environ.py +2 -2
  512. reconcile/utils/exceptions.py +4 -0
  513. reconcile/utils/expiration.py +4 -8
  514. reconcile/utils/extended_early_exit.py +210 -0
  515. reconcile/utils/external_resource_spec.py +34 -12
  516. reconcile/utils/external_resources.py +48 -20
  517. reconcile/utils/filtering.py +16 -0
  518. reconcile/utils/git.py +49 -16
  519. reconcile/utils/github_api.py +10 -9
  520. reconcile/utils/gitlab_api.py +333 -190
  521. reconcile/utils/glitchtip/client.py +97 -100
  522. reconcile/utils/glitchtip/models.py +89 -11
  523. reconcile/utils/gql.py +157 -58
  524. reconcile/utils/grouping.py +17 -0
  525. reconcile/utils/helm.py +89 -18
  526. reconcile/utils/helpers.py +51 -0
  527. reconcile/utils/imap_client.py +5 -6
  528. reconcile/utils/internal_groups/__init__.py +0 -0
  529. reconcile/utils/internal_groups/client.py +160 -0
  530. reconcile/utils/internal_groups/models.py +71 -0
  531. reconcile/utils/jenkins_api.py +10 -34
  532. reconcile/utils/jinja2/__init__.py +0 -0
  533. reconcile/utils/{jinja2_ext.py → jinja2/extensions.py} +6 -4
  534. reconcile/utils/jinja2/filters.py +142 -0
  535. reconcile/utils/jinja2/utils.py +278 -0
  536. reconcile/utils/jira_client.py +165 -8
  537. reconcile/utils/jjb_client.py +47 -35
  538. reconcile/utils/jobcontroller/__init__.py +0 -0
  539. reconcile/utils/jobcontroller/controller.py +413 -0
  540. reconcile/utils/jobcontroller/models.py +195 -0
  541. reconcile/utils/jsonpath.py +4 -5
  542. reconcile/utils/jump_host.py +13 -12
  543. reconcile/utils/keycloak.py +106 -0
  544. reconcile/utils/ldap_client.py +35 -6
  545. reconcile/utils/lean_terraform_client.py +115 -6
  546. reconcile/utils/membershipsources/__init__.py +0 -0
  547. reconcile/utils/membershipsources/app_interface_resolver.py +60 -0
  548. reconcile/utils/membershipsources/models.py +91 -0
  549. reconcile/utils/membershipsources/resolver.py +110 -0
  550. reconcile/utils/merge_request_manager/__init__.py +0 -0
  551. reconcile/utils/merge_request_manager/merge_request_manager.py +99 -0
  552. reconcile/utils/merge_request_manager/parser.py +67 -0
  553. reconcile/utils/metrics.py +511 -1
  554. reconcile/utils/models.py +123 -0
  555. reconcile/utils/mr/README.md +198 -0
  556. reconcile/utils/mr/__init__.py +14 -10
  557. reconcile/utils/mr/app_interface_reporter.py +2 -2
  558. reconcile/utils/mr/aws_access.py +4 -4
  559. reconcile/utils/mr/base.py +51 -31
  560. reconcile/utils/mr/clusters_updates.py +10 -7
  561. reconcile/utils/mr/glitchtip_access_reporter.py +2 -4
  562. reconcile/utils/mr/labels.py +14 -1
  563. reconcile/utils/mr/notificator.py +1 -3
  564. reconcile/utils/mr/ocm_update_recommended_version.py +1 -2
  565. reconcile/utils/mr/ocm_upgrade_scheduler_org_updates.py +7 -3
  566. reconcile/utils/mr/promote_qontract.py +203 -0
  567. reconcile/utils/mr/user_maintenance.py +24 -4
  568. reconcile/utils/oauth2_backend_application_session.py +132 -0
  569. reconcile/utils/oc.py +194 -170
  570. reconcile/utils/oc_connection_parameters.py +40 -51
  571. reconcile/utils/oc_filters.py +11 -13
  572. reconcile/utils/oc_map.py +14 -35
  573. reconcile/utils/ocm/__init__.py +30 -1
  574. reconcile/utils/ocm/addons.py +228 -0
  575. reconcile/utils/ocm/base.py +618 -5
  576. reconcile/utils/ocm/cluster_groups.py +5 -56
  577. reconcile/utils/ocm/clusters.py +111 -99
  578. reconcile/utils/ocm/identity_providers.py +66 -0
  579. reconcile/utils/ocm/label_sources.py +75 -0
  580. reconcile/utils/ocm/labels.py +139 -54
  581. reconcile/utils/ocm/manifests.py +39 -0
  582. reconcile/utils/ocm/ocm.py +182 -928
  583. reconcile/utils/ocm/products.py +758 -0
  584. reconcile/utils/ocm/search_filters.py +20 -28
  585. reconcile/utils/ocm/service_log.py +32 -79
  586. reconcile/utils/ocm/sre_capability_labels.py +51 -0
  587. reconcile/utils/ocm/status_board.py +66 -0
  588. reconcile/utils/ocm/subscriptions.py +49 -59
  589. reconcile/utils/ocm/syncsets.py +39 -0
  590. reconcile/utils/ocm/upgrades.py +181 -0
  591. reconcile/utils/ocm_base_client.py +71 -36
  592. reconcile/utils/openshift_resource.py +113 -67
  593. reconcile/utils/output.py +18 -11
  594. reconcile/utils/pagerduty_api.py +16 -10
  595. reconcile/utils/parse_dhms_duration.py +13 -1
  596. reconcile/utils/prometheus.py +123 -0
  597. reconcile/utils/promotion_state.py +56 -19
  598. reconcile/utils/promtool.py +5 -8
  599. reconcile/utils/quay_api.py +13 -25
  600. reconcile/utils/raw_github_api.py +3 -5
  601. reconcile/utils/repo_owners.py +2 -8
  602. reconcile/utils/rest_api_base.py +126 -0
  603. reconcile/utils/rosa/__init__.py +0 -0
  604. reconcile/utils/rosa/rosa_cli.py +310 -0
  605. reconcile/utils/rosa/session.py +201 -0
  606. reconcile/utils/ruamel.py +16 -0
  607. reconcile/utils/runtime/__init__.py +0 -1
  608. reconcile/utils/runtime/desired_state_diff.py +9 -20
  609. reconcile/utils/runtime/environment.py +33 -8
  610. reconcile/utils/runtime/integration.py +28 -12
  611. reconcile/utils/runtime/meta.py +1 -3
  612. reconcile/utils/runtime/runner.py +8 -11
  613. reconcile/utils/runtime/sharding.py +93 -36
  614. reconcile/utils/saasherder/__init__.py +1 -1
  615. reconcile/utils/saasherder/interfaces.py +143 -138
  616. reconcile/utils/saasherder/models.py +201 -43
  617. reconcile/utils/saasherder/saasherder.py +508 -378
  618. reconcile/utils/secret_reader.py +22 -27
  619. reconcile/utils/semver_helper.py +15 -1
  620. reconcile/utils/slack_api.py +124 -36
  621. reconcile/utils/smtp_client.py +1 -2
  622. reconcile/utils/sqs_gateway.py +10 -6
  623. reconcile/utils/state.py +276 -127
  624. reconcile/utils/terraform/config_client.py +6 -7
  625. reconcile/utils/terraform_client.py +284 -125
  626. reconcile/utils/terrascript/cloudflare_client.py +38 -17
  627. reconcile/utils/terrascript/cloudflare_resources.py +67 -18
  628. reconcile/utils/terrascript/models.py +2 -3
  629. reconcile/utils/terrascript/resources.py +1 -2
  630. reconcile/utils/terrascript_aws_client.py +1292 -540
  631. reconcile/utils/three_way_diff_strategy.py +157 -0
  632. reconcile/utils/unleash/__init__.py +11 -0
  633. reconcile/utils/{unleash.py → unleash/client.py} +35 -29
  634. reconcile/utils/unleash/server.py +145 -0
  635. reconcile/utils/vault.py +42 -32
  636. reconcile/utils/vaultsecretref.py +2 -4
  637. reconcile/utils/vcs.py +250 -0
  638. reconcile/vault_replication.py +38 -31
  639. reconcile/vpc_peerings_validator.py +82 -13
  640. tools/app_interface_metrics_exporter.py +70 -0
  641. tools/app_interface_reporter.py +44 -157
  642. tools/cli_commands/container_images_report.py +154 -0
  643. tools/cli_commands/cost_report/__init__.py +0 -0
  644. tools/cli_commands/cost_report/aws.py +137 -0
  645. tools/cli_commands/cost_report/cost_management_api.py +155 -0
  646. tools/cli_commands/cost_report/model.py +49 -0
  647. tools/cli_commands/cost_report/openshift.py +166 -0
  648. tools/cli_commands/cost_report/openshift_cost_optimization.py +187 -0
  649. tools/cli_commands/cost_report/response.py +124 -0
  650. tools/cli_commands/cost_report/util.py +72 -0
  651. tools/cli_commands/cost_report/view.py +524 -0
  652. tools/cli_commands/erv2.py +620 -0
  653. tools/cli_commands/gpg_encrypt.py +5 -8
  654. tools/cli_commands/systems_and_tools.py +489 -0
  655. tools/glitchtip_access_revalidation.py +1 -1
  656. tools/qontract_cli.py +2301 -673
  657. tools/saas_metrics_exporter/__init__.py +0 -0
  658. tools/saas_metrics_exporter/commit_distance/__init__.py +0 -0
  659. tools/saas_metrics_exporter/commit_distance/channel.py +63 -0
  660. tools/saas_metrics_exporter/commit_distance/commit_distance.py +103 -0
  661. tools/saas_metrics_exporter/commit_distance/metrics.py +19 -0
  662. tools/saas_metrics_exporter/main.py +99 -0
  663. tools/saas_promotion_state/__init__.py +0 -0
  664. tools/saas_promotion_state/saas_promotion_state.py +105 -0
  665. tools/sd_app_sre_alert_report.py +145 -0
  666. tools/template_validation.py +107 -0
  667. e2e_tests/cli.py +0 -83
  668. e2e_tests/create_namespace.py +0 -43
  669. e2e_tests/dedicated_admin_rolebindings.py +0 -44
  670. e2e_tests/dedicated_admin_test_base.py +0 -39
  671. e2e_tests/default_network_policies.py +0 -47
  672. e2e_tests/default_project_labels.py +0 -52
  673. e2e_tests/network_policy_test_base.py +0 -17
  674. e2e_tests/test_base.py +0 -56
  675. qontract_reconcile-0.9.1rc298.dist-info/METADATA +0 -63
  676. qontract_reconcile-0.9.1rc298.dist-info/RECORD +0 -585
  677. qontract_reconcile-0.9.1rc298.dist-info/top_level.txt +0 -4
  678. reconcile/ecr_mirror.py +0 -152
  679. reconcile/github_scanner.py +0 -74
  680. reconcile/gitlab_integrations.py +0 -63
  681. reconcile/gql_definitions/ocm_oidc_idp/clusters.py +0 -195
  682. reconcile/gql_definitions/ocp_release_mirror/ocp_release_mirror.py +0 -287
  683. reconcile/integrations_validator.py +0 -18
  684. reconcile/jenkins_plugins.py +0 -129
  685. reconcile/kafka_clusters.py +0 -208
  686. reconcile/ocm_cluster_admin.py +0 -42
  687. reconcile/ocm_oidc_idp.py +0 -198
  688. reconcile/ocp_release_mirror.py +0 -373
  689. reconcile/prometheus_rules_tester_old.py +0 -436
  690. reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager.py +0 -279
  691. reconcile/saas_auto_promotions_manager/utils/vcs.py +0 -141
  692. reconcile/sentry_config.py +0 -613
  693. reconcile/sentry_helper.py +0 -69
  694. reconcile/test/conftest.py +0 -187
  695. reconcile/test/fixtures.py +0 -24
  696. reconcile/test/saas_auto_promotions_manager/conftest.py +0 -69
  697. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py +0 -110
  698. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/data_keys.py +0 -10
  699. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_housekeeping.py +0 -200
  700. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_merge_request_manager.py +0 -151
  701. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py +0 -63
  702. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/data_keys.py +0 -4
  703. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_multiple_namespaces.py +0 -46
  704. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_namespace.py +0 -94
  705. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_target.py +0 -44
  706. reconcile/test/saas_auto_promotions_manager/subscriber/conftest.py +0 -74
  707. reconcile/test/saas_auto_promotions_manager/subscriber/data_keys.py +0 -11
  708. reconcile/test/saas_auto_promotions_manager/subscriber/test_content_hash.py +0 -155
  709. reconcile/test/saas_auto_promotions_manager/subscriber/test_diff.py +0 -173
  710. reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_channels_config_hash.py +0 -226
  711. reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_channels_moving_ref.py +0 -224
  712. reconcile/test/saas_auto_promotions_manager/subscriber/test_single_channel_with_single_publisher.py +0 -350
  713. reconcile/test/saas_auto_promotions_manager/test_integration_test.py +0 -129
  714. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_multiple_publishers_for_single_channel.py +0 -70
  715. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_use_target_config_hash.py +0 -63
  716. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_with_auto_promote.py +0 -74
  717. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_without_auto_promote.py +0 -65
  718. reconcile/test/test_aggregated_list.py +0 -237
  719. reconcile/test/test_amtool.py +0 -37
  720. reconcile/test/test_auto_promoter.py +0 -295
  721. reconcile/test/test_aws_ami_share.py +0 -68
  722. reconcile/test/test_aws_iam_keys.py +0 -70
  723. reconcile/test/test_aws_iam_password_reset.py +0 -35
  724. reconcile/test/test_aws_support_cases_sos.py +0 -23
  725. reconcile/test/test_checkpoint.py +0 -178
  726. reconcile/test/test_cli.py +0 -41
  727. reconcile/test/test_closedbox_endpoint_monitoring.py +0 -207
  728. reconcile/test/test_gabi_authorized_users.py +0 -72
  729. reconcile/test/test_github_org.py +0 -154
  730. reconcile/test/test_github_repo_invites.py +0 -123
  731. reconcile/test/test_gitlab_housekeeping.py +0 -88
  732. reconcile/test/test_gitlab_labeler.py +0 -129
  733. reconcile/test/test_gitlab_members.py +0 -283
  734. reconcile/test/test_instrumented_wrappers.py +0 -18
  735. reconcile/test/test_integrations_manager.py +0 -995
  736. reconcile/test/test_jenkins_worker_fleets.py +0 -55
  737. reconcile/test/test_jump_host.py +0 -117
  738. reconcile/test/test_ldap_users.py +0 -123
  739. reconcile/test/test_make.py +0 -28
  740. reconcile/test/test_ocm_additional_routers.py +0 -134
  741. reconcile/test/test_ocm_addons_upgrade_scheduler_org.py +0 -149
  742. reconcile/test/test_ocm_clusters.py +0 -598
  743. reconcile/test/test_ocm_clusters_manifest_updates.py +0 -89
  744. reconcile/test/test_ocm_oidc_idp.py +0 -315
  745. reconcile/test/test_ocm_update_recommended_version.py +0 -145
  746. reconcile/test/test_ocm_upgrade_scheduler.py +0 -614
  747. reconcile/test/test_ocm_upgrade_scheduler_org_updater.py +0 -129
  748. reconcile/test/test_openshift_base.py +0 -730
  749. reconcile/test/test_openshift_namespace_labels.py +0 -345
  750. reconcile/test/test_openshift_namespaces.py +0 -256
  751. reconcile/test/test_openshift_resource.py +0 -415
  752. reconcile/test/test_openshift_resources_base.py +0 -440
  753. reconcile/test/test_openshift_saas_deploy_change_tester.py +0 -310
  754. reconcile/test/test_openshift_tekton_resources.py +0 -253
  755. reconcile/test/test_openshift_upgrade_watcher.py +0 -146
  756. reconcile/test/test_prometheus_rules_tester.py +0 -151
  757. reconcile/test/test_prometheus_rules_tester_old.py +0 -77
  758. reconcile/test/test_quay_membership.py +0 -86
  759. reconcile/test/test_quay_mirror.py +0 -109
  760. reconcile/test/test_quay_mirror_org.py +0 -70
  761. reconcile/test/test_quay_repos.py +0 -59
  762. reconcile/test/test_queries.py +0 -53
  763. reconcile/test/test_repo_owners.py +0 -47
  764. reconcile/test/test_requests_sender.py +0 -139
  765. reconcile/test/test_saasherder.py +0 -1074
  766. reconcile/test/test_saasherder_allowed_secret_paths.py +0 -127
  767. reconcile/test/test_secret_reader.py +0 -153
  768. reconcile/test/test_slack_base.py +0 -185
  769. reconcile/test/test_slack_usergroups.py +0 -744
  770. reconcile/test/test_sql_query.py +0 -19
  771. reconcile/test/test_terraform_cloudflare_dns.py +0 -117
  772. reconcile/test/test_terraform_cloudflare_resources.py +0 -106
  773. reconcile/test/test_terraform_cloudflare_users.py +0 -749
  774. reconcile/test/test_terraform_resources.py +0 -257
  775. reconcile/test/test_terraform_tgw_attachments.py +0 -631
  776. reconcile/test/test_terraform_users.py +0 -57
  777. reconcile/test/test_terraform_vpc_peerings.py +0 -499
  778. reconcile/test/test_terraform_vpc_peerings_build_desired_state.py +0 -1061
  779. reconcile/test/test_unleash.py +0 -138
  780. reconcile/test/test_utils_aws_api.py +0 -240
  781. reconcile/test/test_utils_aws_helper.py +0 -80
  782. reconcile/test/test_utils_cluster_version_data.py +0 -177
  783. reconcile/test/test_utils_data_structures.py +0 -13
  784. reconcile/test/test_utils_disabled_integrations.py +0 -86
  785. reconcile/test/test_utils_expiration.py +0 -109
  786. reconcile/test/test_utils_external_resource_spec.py +0 -383
  787. reconcile/test/test_utils_external_resources.py +0 -247
  788. reconcile/test/test_utils_github_api.py +0 -73
  789. reconcile/test/test_utils_gitlab_api.py +0 -20
  790. reconcile/test/test_utils_gpg.py +0 -69
  791. reconcile/test/test_utils_gql.py +0 -81
  792. reconcile/test/test_utils_helm.py +0 -306
  793. reconcile/test/test_utils_helpers.py +0 -55
  794. reconcile/test/test_utils_imap_client.py +0 -65
  795. reconcile/test/test_utils_jjb_client.py +0 -52
  796. reconcile/test/test_utils_jsonpath.py +0 -286
  797. reconcile/test/test_utils_ldap_client.py +0 -51
  798. reconcile/test/test_utils_mr.py +0 -226
  799. reconcile/test/test_utils_mr_clusters_updates.py +0 -77
  800. reconcile/test/test_utils_oc.py +0 -984
  801. reconcile/test/test_utils_ocm.py +0 -110
  802. reconcile/test/test_utils_pagerduty_api.py +0 -251
  803. reconcile/test/test_utils_parse_dhms_duration.py +0 -34
  804. reconcile/test/test_utils_password_validator.py +0 -155
  805. reconcile/test/test_utils_quay_api.py +0 -86
  806. reconcile/test/test_utils_semver_helper.py +0 -19
  807. reconcile/test/test_utils_sharding.py +0 -56
  808. reconcile/test/test_utils_slack_api.py +0 -439
  809. reconcile/test/test_utils_smtp_client.py +0 -73
  810. reconcile/test/test_utils_state.py +0 -256
  811. reconcile/test/test_utils_terraform.py +0 -13
  812. reconcile/test/test_utils_terraform_client.py +0 -585
  813. reconcile/test/test_utils_terraform_config_client.py +0 -219
  814. reconcile/test/test_utils_terrascript_aws_client.py +0 -277
  815. reconcile/test/test_utils_terrascript_cloudflare_client.py +0 -597
  816. reconcile/test/test_utils_terrascript_cloudflare_resources.py +0 -26
  817. reconcile/test/test_vault_replication.py +0 -515
  818. reconcile/test/test_vault_utils.py +0 -47
  819. reconcile/test/test_version_bump.py +0 -18
  820. reconcile/test/test_vpc_peerings_validator.py +0 -103
  821. reconcile/test/test_wrong_region.py +0 -78
  822. reconcile/typed_queries/glitchtip_settings.py +0 -18
  823. reconcile/typed_queries/ocp_release_mirror.py +0 -11
  824. reconcile/unleash_watcher.py +0 -120
  825. reconcile/utils/git_secrets.py +0 -63
  826. reconcile/utils/mr/auto_promoter.py +0 -218
  827. reconcile/utils/sentry_client.py +0 -383
  828. release/test_version.py +0 -50
  829. release/version.py +0 -100
  830. tools/test/test_qontract_cli.py +0 -60
  831. tools/test/test_sre_checkpoints.py +0 -79
  832. /e2e_tests/__init__.py → /reconcile/aus/upgrades.py +0 -0
  833. /reconcile/{gql_definitions/ocp_release_mirror → aws_account_manager}/__init__.py +0 -0
  834. /reconcile/{test → aws_ami_cleanup}/__init__.py +0 -0
  835. /reconcile/{test/saas_auto_promotions_manager → aws_cloudwatch_log_retention}/__init__.py +0 -0
  836. /reconcile/{test/saas_auto_promotions_manager/merge_request_manager → aws_saml_idp}/__init__.py +0 -0
  837. /reconcile/{test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager → aws_saml_roles}/__init__.py +0 -0
  838. /reconcile/{test/saas_auto_promotions_manager/merge_request_manager/renderer → aws_version_sync}/__init__.py +0 -0
  839. /reconcile/{test/saas_auto_promotions_manager/subscriber → aws_version_sync/merge_request_manager}/__init__.py +0 -0
  840. /reconcile/{test/saas_auto_promotions_manager/utils → cluster_auth_rhidp}/__init__.py +0 -0
  841. /reconcile/{test/saas_auto_promotions_manager/utils/saas_files_inventory → dynatrace_token_provider}/__init__.py +0 -0
  842. {release → reconcile/endpoints_discovery}/__init__.py +0 -0
  843. {tools/test → reconcile/external_resources}/__init__.py +0 -0
@@ -1,41 +1,23 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import functools
4
- import logging
5
- import random
6
4
  import re
7
- import string
8
- from abc import abstractmethod
9
- from collections.abc import (
10
- Iterable,
11
- Mapping,
12
- )
13
- from dataclasses import (
14
- dataclass,
15
- field,
16
- )
17
- from typing import (
18
- Any,
19
- Optional,
20
- Union,
21
- )
5
+ from collections.abc import Mapping
6
+ from typing import Any
22
7
 
23
8
  from sretoolbox.utils import retry
24
9
 
25
10
  import reconcile.utils.aws_helper as awsh
26
11
  from reconcile.gql_definitions.fragments.vault_secret import VaultSecret
27
12
  from reconcile.ocm.types import (
28
- OCMClusterAutoscale,
29
- OCMClusterNetwork,
30
- OCMClusterSpec,
31
- OCMOidcIdp,
32
13
  OCMSpec,
33
- OSDClusterSpec,
34
- ROSAClusterAWSAccount,
35
- ROSAClusterSpec,
36
- ROSAOcmAwsAttrs,
37
14
  )
38
- from reconcile.utils.exceptions import ParameterError
15
+ from reconcile.utils.ocm.clusters import get_node_pools
16
+ from reconcile.utils.ocm.products import (
17
+ OCMProduct,
18
+ OCMProductPortfolio,
19
+ build_product_portfolio,
20
+ )
39
21
  from reconcile.utils.ocm_base_client import (
40
22
  OCMAPIClientConfiguration,
41
23
  OCMBaseClient,
@@ -49,11 +31,24 @@ STATUS_DELETING = "deleting"
49
31
 
50
32
  AMS_API_BASE = "/api/accounts_mgmt"
51
33
  CS_API_BASE = "/api/clusters_mgmt"
52
- KAS_API_BASE = "/api/kafkas_mgmt"
53
34
 
54
- MACHINE_POOL_DESIRED_KEYS = {"id", "instance_type", "replicas", "labels", "taints"}
35
+ MACHINE_POOL_DESIRED_KEYS = {
36
+ "id",
37
+ "instance_type",
38
+ "replicas",
39
+ "autoscaling",
40
+ "labels",
41
+ "taints",
42
+ }
55
43
  UPGRADE_CHANNELS = {"stable", "fast", "candidate"}
56
- UPGRADE_POLICY_DESIRED_KEYS = {"id", "schedule_type", "schedule", "next_run", "version"}
44
+ UPGRADE_POLICY_DESIRED_KEYS = {
45
+ "id",
46
+ "schedule_type",
47
+ "schedule",
48
+ "next_run",
49
+ "version",
50
+ "state",
51
+ }
57
52
  ADDON_UPGRADE_POLICY_DESIRED_KEYS = {
58
53
  "id",
59
54
  "addon_id",
@@ -68,511 +63,8 @@ CLUSTER_ADDON_DESIRED_KEYS = {"id", "parameters"}
68
63
 
69
64
  DISABLE_UWM_ATTR = "disable_user_workload_monitoring"
70
65
  CLUSTER_ADMIN_LABEL_KEY = "capability.cluster.manage_cluster_admin"
71
- BYTES_IN_GIGABYTE = 1024**3
72
66
  REQUEST_TIMEOUT_SEC = 60
73
67
 
74
- SPEC_ATTR_ACCOUNT = "account"
75
- SPEC_ATTR_DISABLE_UWM = "disable_user_workload_monitoring"
76
- SPEC_ATTR_AUTOSCALE = "autoscale"
77
- SPEC_ATTR_INSTANCE_TYPE = "instance_type"
78
- SPEC_ATTR_PRIVATE = "private"
79
- SPEC_ATTR_CHANNEL = "channel"
80
- SPEC_ATTR_NODES = "nodes"
81
- SPEC_ATTR_LOAD_BALANCERS = "load_balancers"
82
- SPEC_ATTR_STORAGE = "storage"
83
- SPEC_ATTR_ID = "id"
84
- SPEC_ATTR_EXTERNAL_ID = "external_id"
85
- SPEC_ATTR_PROVISION_SHARD_ID = "provision_shard_id"
86
- SPEC_ATTR_VERSION = "version"
87
- SPEC_ATTR_INITIAL_VERSION = "initial_version"
88
- SPEC_ATTR_MULTI_AZ = "multi_az"
89
- SPEC_ATTR_HYPERSHIFT = "hypershift"
90
- SPEC_ATTR_SUBNET_IDS = "subnet_ids"
91
- SPEC_ATTR_AVAILABILITY_ZONES = "availability_zones"
92
-
93
- SPEC_ATTR_NETWORK = "network"
94
-
95
- SPEC_ATTR_CONSOLE_URL = "consoleUrl"
96
- SPEC_ATTR_SERVER_URL = "serverUrl"
97
- SPEC_ATTR_ELBFQDN = "elbFQDN"
98
- SPEC_ATTR_PATH = "path"
99
-
100
- OCM_PRODUCT_OSD = "osd"
101
- OCM_PRODUCT_ROSA = "rosa"
102
-
103
-
104
- class OCMProduct:
105
-
106
- ALLOWED_SPEC_UPDATE_FIELDS: set[str]
107
- EXCLUDED_SPEC_FIELDS: set[str]
108
-
109
- @staticmethod
110
- @abstractmethod
111
- def create_cluster(ocm: OCM, name: str, cluster: OCMSpec, dry_run: bool):
112
- pass
113
-
114
- @staticmethod
115
- @abstractmethod
116
- def update_cluster(ocm: OCM, cluster_name: str, update_spec: Mapping[str, Any]):
117
- pass
118
-
119
- @staticmethod
120
- @abstractmethod
121
- def get_ocm_spec(
122
- ocm: OCM, cluster: Mapping[str, Any], init_provision_shards: bool
123
- ) -> OCMSpec:
124
- pass
125
-
126
-
127
- class OCMProductOsd(OCMProduct):
128
- ALLOWED_SPEC_UPDATE_FIELDS = {
129
- SPEC_ATTR_STORAGE,
130
- SPEC_ATTR_LOAD_BALANCERS,
131
- SPEC_ATTR_PRIVATE,
132
- SPEC_ATTR_CHANNEL,
133
- SPEC_ATTR_AUTOSCALE,
134
- SPEC_ATTR_NODES,
135
- SPEC_ATTR_DISABLE_UWM,
136
- }
137
-
138
- EXCLUDED_SPEC_FIELDS = {
139
- SPEC_ATTR_ID,
140
- SPEC_ATTR_EXTERNAL_ID,
141
- SPEC_ATTR_PROVISION_SHARD_ID,
142
- SPEC_ATTR_VERSION,
143
- SPEC_ATTR_INITIAL_VERSION,
144
- SPEC_ATTR_HYPERSHIFT,
145
- }
146
-
147
- @staticmethod
148
- def create_cluster(ocm: OCM, name: str, cluster: OCMSpec, dry_run: bool):
149
- ocm_spec = OCMProductOsd._get_create_cluster_spec(name, cluster)
150
- api = f"{CS_API_BASE}/v1/clusters"
151
- params = {}
152
- if dry_run:
153
- params["dryRun"] = "true"
154
-
155
- ocm._post(api, ocm_spec, params)
156
-
157
- @staticmethod
158
- def update_cluster(ocm: OCM, cluster_name: str, update_spec: Mapping[str, Any]):
159
- ocm_spec = OCMProductOsd._get_update_cluster_spec(update_spec)
160
- cluster_id = ocm.cluster_ids.get(cluster_name)
161
- api = f"{CS_API_BASE}/v1/clusters/{cluster_id}"
162
- params: dict[str, Any] = {}
163
- ocm._patch(api, ocm_spec, params)
164
-
165
- @staticmethod
166
- def get_ocm_spec(
167
- ocm: OCM, cluster: Mapping[str, Any], init_provision_shards: bool
168
- ) -> OCMSpec:
169
- if init_provision_shards:
170
- provision_shard_id = ocm.get_provision_shard(cluster["id"])["id"]
171
- else:
172
- provision_shard_id = None
173
-
174
- autoscale = cluster["nodes"].get("autoscale_compute")
175
- autoscale_spec = (
176
- OCMClusterAutoscale(
177
- max_replicas=autoscale.get("max_replicas"),
178
- min_replicas=autoscale.get("min_replicas"),
179
- )
180
- if autoscale
181
- else None
182
- )
183
-
184
- spec = OCMClusterSpec(
185
- product=cluster["product"]["id"],
186
- id=cluster["id"],
187
- external_id=cluster["external_id"],
188
- provider=cluster["cloud_provider"]["id"],
189
- region=cluster["region"]["id"],
190
- channel=cluster["version"]["channel_group"],
191
- version=cluster["version"]["raw_id"],
192
- multi_az=cluster["multi_az"],
193
- instance_type=cluster["nodes"]["compute_machine_type"]["id"],
194
- private=cluster["api"]["listening"] == "internal",
195
- disable_user_workload_monitoring=cluster[
196
- "disable_user_workload_monitoring"
197
- ],
198
- provision_shard_id=provision_shard_id,
199
- nodes=cluster["nodes"].get("compute"),
200
- autoscale=autoscale_spec,
201
- hypershift=cluster["hypershift"]["enabled"],
202
- )
203
-
204
- if not cluster["ccs"]["enabled"]:
205
- cluster_spec_data = spec.dict()
206
- cluster_spec_data["storage"] = (
207
- cluster["storage_quota"]["value"] // BYTES_IN_GIGABYTE
208
- )
209
- cluster_spec_data["load_balancers"] = cluster["load_balancer_quota"]
210
- spec = OSDClusterSpec(**cluster_spec_data)
211
-
212
- network = OCMClusterNetwork(
213
- type=cluster["network"].get("type") or "OVNKubernetes",
214
- vpc=cluster["network"]["machine_cidr"],
215
- service=cluster["network"]["service_cidr"],
216
- pod=cluster["network"]["pod_cidr"],
217
- )
218
-
219
- ocm_spec = OCMSpec(
220
- console_url=cluster["console"]["url"],
221
- server_url=cluster["api"]["url"],
222
- domain=cluster["dns"]["base_domain"],
223
- spec=spec,
224
- network=network,
225
- )
226
-
227
- return ocm_spec
228
-
229
- @staticmethod
230
- def _get_create_cluster_spec(cluster_name: str, cluster: OCMSpec) -> dict[str, Any]:
231
- ocm_spec: dict[str, Any] = {
232
- "name": cluster_name,
233
- "cloud_provider": {"id": cluster.spec.provider},
234
- "region": {"id": cluster.spec.region},
235
- "version": {
236
- "id": f"openshift-v{cluster.spec.initial_version}",
237
- "channel_group": cluster.spec.channel,
238
- },
239
- "multi_az": cluster.spec.multi_az,
240
- "nodes": {"compute_machine_type": {"id": cluster.spec.instance_type}},
241
- "network": {
242
- "type": cluster.network.type or "OVNKubernetes",
243
- "machine_cidr": cluster.network.vpc,
244
- "service_cidr": cluster.network.service,
245
- "pod_cidr": cluster.network.pod,
246
- },
247
- "api": {"listening": "internal" if cluster.spec.private else "external"},
248
- "disable_user_workload_monitoring": cluster.spec.disable_user_workload_monitoring
249
- or True,
250
- }
251
-
252
- # Workaround to enable type checks.
253
- # cluster.spec is a Union of pydantic models Union[OSDClusterSpec, RosaClusterSpec].
254
- # In this case, cluster.spec will always be an OSDClusterSpec because the type
255
- # assignment is managed by pydantic, however, mypy complains if OSD attributes are set
256
- # outside the isinstance check because it checks all the types set in the Union.
257
- if isinstance(cluster.spec, OSDClusterSpec):
258
- ocm_spec["storage_quota"] = {
259
- "value": float(cluster.spec.storage * BYTES_IN_GIGABYTE),
260
- }
261
- ocm_spec["load_balancer_quota"] = cluster.spec.load_balancers
262
-
263
- provision_shard_id = cluster.spec.provision_shard_id
264
- if provision_shard_id:
265
- ocm_spec.setdefault("properties", {})
266
- ocm_spec["properties"]["provision_shard_id"] = provision_shard_id
267
-
268
- autoscale = cluster.spec.autoscale
269
- if autoscale is not None:
270
- ocm_spec["nodes"]["autoscale_compute"] = autoscale.dict()
271
- else:
272
- ocm_spec["nodes"]["compute"] = cluster.spec.nodes
273
- return ocm_spec
274
-
275
- @staticmethod
276
- def _get_update_cluster_spec(update_spec: Mapping[str, Any]) -> dict[str, Any]:
277
- ocm_spec: dict[str, Any] = {}
278
-
279
- storage = update_spec.get("storage")
280
- if storage is not None:
281
- ocm_spec["storage_quota"] = {"value": float(storage * 1073741824)} # 1024^3
282
-
283
- load_balancers = update_spec.get("load_balancers")
284
- if load_balancers is not None:
285
- ocm_spec["load_balancer_quota"] = load_balancers
286
-
287
- private = update_spec.get("private")
288
- if private is not None:
289
- ocm_spec["api"] = {"listening": "internal" if private else "external"}
290
-
291
- channel = update_spec.get("channel")
292
- if channel is not None:
293
- ocm_spec["version"] = {"channel_group": channel}
294
-
295
- autoscale = update_spec.get("autoscale")
296
- if autoscale is not None:
297
- ocm_spec["nodes"] = {"autoscale_compute": autoscale}
298
-
299
- nodes = update_spec.get("nodes")
300
- if nodes:
301
- ocm_spec["nodes"] = {"compute": update_spec["nodes"]}
302
-
303
- disable_uwm = update_spec.get("disable_user_workload_monitoring")
304
- if disable_uwm is not None:
305
- ocm_spec["disable_user_workload_monitoring"] = disable_uwm
306
-
307
- return ocm_spec
308
-
309
-
310
- class OCMProductRosa(OCMProduct):
311
- ALLOWED_SPEC_UPDATE_FIELDS = {
312
- SPEC_ATTR_CHANNEL,
313
- SPEC_ATTR_AUTOSCALE,
314
- SPEC_ATTR_NODES,
315
- SPEC_ATTR_DISABLE_UWM,
316
- }
317
-
318
- EXCLUDED_SPEC_FIELDS = {
319
- SPEC_ATTR_ID,
320
- SPEC_ATTR_EXTERNAL_ID,
321
- SPEC_ATTR_PROVISION_SHARD_ID,
322
- SPEC_ATTR_VERSION,
323
- SPEC_ATTR_INITIAL_VERSION,
324
- SPEC_ATTR_ACCOUNT,
325
- SPEC_ATTR_HYPERSHIFT,
326
- SPEC_ATTR_SUBNET_IDS,
327
- SPEC_ATTR_AVAILABILITY_ZONES,
328
- }
329
-
330
- @staticmethod
331
- def create_cluster(ocm: OCM, name: str, cluster: OCMSpec, dry_run: bool):
332
- ocm_spec = OCMProductRosa._get_create_cluster_spec(name, cluster)
333
- api = f"{CS_API_BASE}/v1/clusters"
334
- params = {}
335
- if dry_run:
336
- params["dryRun"] = "true"
337
- if cluster.spec.hypershift:
338
- logging.info(
339
- "Dry-Run is not yet implemented for Hosted clusters. Here is the payload:"
340
- )
341
- logging.info(ocm_spec)
342
- return
343
- ocm._post(api, ocm_spec, params)
344
-
345
- @staticmethod
346
- def update_cluster(ocm: OCM, cluster_name: str, update_spec: Mapping[str, Any]):
347
- ocm_spec = OCMProductRosa._get_update_cluster_spec(update_spec)
348
- cluster_id = ocm.cluster_ids.get(cluster_name)
349
- api = f"{CS_API_BASE}/v1/clusters/{cluster_id}"
350
- params: dict[str, Any] = {}
351
- ocm._patch(api, ocm_spec, params)
352
-
353
- @staticmethod
354
- def get_ocm_spec(
355
- ocm: OCM, cluster: Mapping[str, Any], init_provision_shards: bool
356
- ) -> OCMSpec:
357
-
358
- if init_provision_shards:
359
- provision_shard_id = ocm.get_provision_shard(cluster["id"])["id"]
360
- else:
361
- provision_shard_id = None
362
-
363
- autoscale = cluster["nodes"].get("autoscale_compute")
364
- autoscale_spec = (
365
- OCMClusterAutoscale(
366
- max_replicas=autoscale.get("max_replicas"),
367
- min_replicas=autoscale.get("min_replicas"),
368
- )
369
- if autoscale
370
- else None
371
- )
372
-
373
- account = ROSAClusterAWSAccount(
374
- uid=cluster["properties"]["rosa_creator_arn"].split(":")[4],
375
- rosa=ROSAOcmAwsAttrs(
376
- creator_role_arn=cluster["properties"]["rosa_creator_arn"],
377
- installer_role_arn=cluster["aws"]["sts"]["role_arn"],
378
- support_role_arn=cluster["aws"]["sts"]["support_role_arn"],
379
- controlplane_role_arn=cluster["aws"]["sts"]["instance_iam_roles"][
380
- "master_role_arn"
381
- ],
382
- worker_role_arn=cluster["aws"]["sts"]["instance_iam_roles"][
383
- "worker_role_arn"
384
- ],
385
- ),
386
- )
387
-
388
- spec = ROSAClusterSpec(
389
- product=cluster["product"]["id"],
390
- account=account,
391
- id=cluster["id"],
392
- external_id=cluster.get("external_id"),
393
- provider=cluster["cloud_provider"]["id"],
394
- region=cluster["region"]["id"],
395
- channel=cluster["version"]["channel_group"],
396
- version=cluster["version"]["raw_id"],
397
- multi_az=cluster["multi_az"],
398
- instance_type=cluster["nodes"]["compute_machine_type"]["id"],
399
- private=cluster["api"]["listening"] == "internal",
400
- disable_user_workload_monitoring=cluster[
401
- "disable_user_workload_monitoring"
402
- ],
403
- provision_shard_id=provision_shard_id,
404
- nodes=cluster["nodes"].get("compute"),
405
- autoscale=autoscale_spec,
406
- hypershift=cluster["hypershift"]["enabled"],
407
- subnet_ids=cluster["aws"].get("subnet_ids"),
408
- availability_zones=cluster["nodes"].get("availability_zones"),
409
- )
410
-
411
- network = OCMClusterNetwork(
412
- type=cluster["network"].get("type") or "OVNKubernetes",
413
- vpc=cluster["network"]["machine_cidr"],
414
- service=cluster["network"]["service_cidr"],
415
- pod=cluster["network"]["pod_cidr"],
416
- )
417
-
418
- ocm_spec = OCMSpec(
419
- console_url=cluster["console"]["url"],
420
- server_url=cluster["api"]["url"],
421
- domain=cluster["dns"]["base_domain"],
422
- spec=spec,
423
- network=network,
424
- )
425
-
426
- return ocm_spec
427
-
428
- @staticmethod
429
- def _get_create_cluster_spec(cluster_name: str, cluster: OCMSpec) -> dict[str, Any]:
430
- operator_roles_prefix = "".join(
431
- "".join(random.choices(string.ascii_lowercase + string.digits, k=4))
432
- )
433
-
434
- ocm_spec: dict[str, Any] = {
435
- "api": {"listening": "internal" if cluster.spec.private else "external"},
436
- "name": cluster_name,
437
- "cloud_provider": {"id": cluster.spec.provider},
438
- "region": {"id": cluster.spec.region},
439
- "version": {
440
- "id": f"openshift-v{cluster.spec.initial_version}",
441
- "channel_group": cluster.spec.channel,
442
- },
443
- "hypershift": {"enabled": cluster.spec.hypershift},
444
- "multi_az": cluster.spec.multi_az,
445
- "nodes": {"compute_machine_type": {"id": cluster.spec.instance_type}},
446
- "network": {
447
- "type": cluster.network.type or "OVNKubernetes",
448
- "machine_cidr": cluster.network.vpc,
449
- "service_cidr": cluster.network.service,
450
- "pod_cidr": cluster.network.pod,
451
- },
452
- "disable_user_workload_monitoring": cluster.spec.disable_user_workload_monitoring
453
- or True,
454
- }
455
-
456
- provision_shard_id = cluster.spec.provision_shard_id
457
- if provision_shard_id:
458
- ocm_spec.setdefault("properties", {})
459
- ocm_spec["properties"]["provision_shard_id"] = provision_shard_id
460
-
461
- autoscale = cluster.spec.autoscale
462
- if autoscale is not None:
463
- ocm_spec["nodes"]["autoscale_compute"] = autoscale.dict()
464
- else:
465
- ocm_spec["nodes"]["compute"] = cluster.spec.nodes
466
-
467
- if isinstance(cluster.spec, ROSAClusterSpec):
468
- ocm_spec.setdefault("properties", {})
469
- ocm_spec["properties"][
470
- "rosa_creator_arn"
471
- ] = cluster.spec.account.rosa.creator_role_arn
472
-
473
- rosa_spec: dict[str, Any] = {
474
- "product": {"id": "rosa"},
475
- "ccs": {"enabled": True},
476
- "aws": {
477
- "account_id": cluster.spec.account.uid,
478
- "sts": {
479
- "enabled": True,
480
- "auto_mode": True,
481
- "role_arn": cluster.spec.account.rosa.installer_role_arn,
482
- "support_role_arn": cluster.spec.account.rosa.support_role_arn,
483
- "instance_iam_roles": {
484
- "master_role_arn": cluster.spec.account.rosa.controlplane_role_arn,
485
- "worker_role_arn": cluster.spec.account.rosa.worker_role_arn,
486
- },
487
- "operator_role_prefix": f"{cluster_name}-{operator_roles_prefix}",
488
- },
489
- },
490
- }
491
-
492
- if cluster.spec.hypershift:
493
- ocm_spec["nodes"][
494
- "availability_zones"
495
- ] = cluster.spec.availability_zones
496
- rosa_spec["aws"]["subnet_ids"] = cluster.spec.subnet_ids
497
-
498
- ocm_spec.update(rosa_spec)
499
- return ocm_spec
500
-
501
- @staticmethod
502
- def _get_update_cluster_spec(update_spec: Mapping[str, Any]) -> dict[str, Any]:
503
- ocm_spec: dict[str, Any] = {}
504
-
505
- channel = update_spec.get(SPEC_ATTR_CHANNEL)
506
- if channel is not None:
507
- ocm_spec["version"] = {"channel_group": channel}
508
-
509
- autoscale = update_spec.get(SPEC_ATTR_AUTOSCALE)
510
- if autoscale is not None:
511
- ocm_spec["nodes"] = {"autoscale_compute": autoscale}
512
-
513
- nodes = update_spec.get(SPEC_ATTR_NODES)
514
- if nodes:
515
- ocm_spec["nodes"] = {"compute": update_spec["nodes"]}
516
-
517
- disable_uwm = update_spec.get(SPEC_ATTR_DISABLE_UWM)
518
- if disable_uwm is not None:
519
- ocm_spec["disable_user_workload_monitoring"] = disable_uwm
520
-
521
- return ocm_spec
522
-
523
-
524
- OCM_PRODUCTS_IMPL = {
525
- OCM_PRODUCT_OSD: OCMProductOsd,
526
- OCM_PRODUCT_ROSA: OCMProductRosa,
527
- }
528
-
529
-
530
- class SectorConfigError(Exception):
531
- pass
532
-
533
-
534
- @dataclass
535
- class Sector:
536
- name: str
537
- ocm: OCM
538
- dependencies: list[Sector] = field(default_factory=lambda: [])
539
- cluster_infos: list[dict[Any, Any]] = field(default_factory=lambda: [])
540
- _validated_dependencies: Optional[set[Sector]] = None
541
-
542
- def __key(self):
543
- return (self.ocm.name, self.name)
544
-
545
- def __hash__(self) -> int:
546
- return hash(self.__key())
547
-
548
- def __str__(self) -> str:
549
- return f"{self.ocm.name}/{self.name}"
550
-
551
- def ocmspec(self, cluster_name: str) -> OCMSpec:
552
- return self.ocm.clusters[cluster_name]
553
-
554
- def _iter_dependencies(self) -> Iterable[Sector]:
555
- """
556
- iterate reccursively over all the sector dependencies
557
- """
558
- logging.debug(f"[{self}] checking dependencies")
559
- for dep in self.dependencies or []:
560
- if self == dep:
561
- raise SectorConfigError(
562
- f"[{self}] infinite sector dependency loop detected: depending on itself"
563
- )
564
- yield dep
565
- for d in dep._iter_dependencies():
566
- if self == d:
567
- raise SectorConfigError(
568
- f"[{self}] infinite sector dependency loop detected under {dep} dependencies"
569
- )
570
- yield d
571
-
572
- def validate_dependencies(self) -> bool:
573
- list(self._iter_dependencies())
574
- return True
575
-
576
68
 
577
69
  class OCM: # pylint: disable=too-many-public-methods
578
70
  """
@@ -595,18 +87,24 @@ class OCM: # pylint: disable=too-many-public-methods
595
87
  self,
596
88
  name,
597
89
  org_id,
90
+ ocm_env: str,
598
91
  ocm_client: OCMBaseClient,
599
92
  init_provision_shards=False,
600
93
  init_addons=False,
601
94
  init_version_gates=False,
602
95
  blocked_versions=None,
603
- sectors: Optional[list[dict[str, Any]]] = None,
604
- inheritVersionData: Optional[list[dict[str, Any]]] = None,
96
+ inheritVersionData: list[dict[str, Any]] | None = None,
97
+ product_portfolio: OCMProductPortfolio | None = None,
605
98
  ):
606
99
  """Initiates access token and gets clusters information."""
607
100
  self.name = name
608
101
  self._ocm_client = ocm_client
609
102
  self.org_id = org_id
103
+ self.ocm_env = ocm_env
104
+ if product_portfolio is None:
105
+ self.product_portfolio = build_product_portfolio()
106
+ else:
107
+ self.product_portfolio = product_portfolio
610
108
  self._init_clusters(init_provision_shards=init_provision_shards)
611
109
 
612
110
  if init_addons:
@@ -614,8 +112,6 @@ class OCM: # pylint: disable=too-many-public-methods
614
112
 
615
113
  self._init_blocked_versions(blocked_versions)
616
114
 
617
- self.inheritVersionData = inheritVersionData or []
618
-
619
115
  self.init_version_gates = init_version_gates
620
116
  self.version_gates: list[Any] = []
621
117
  if init_version_gates:
@@ -629,29 +125,25 @@ class OCM: # pylint: disable=too-many-public-methods
629
125
  self.get_aws_infrastructure_access_role_grants
630
126
  )
631
127
 
632
- # organization sectors and their dependencies
633
- self.sectors: dict[str, Sector] = {}
634
- for sector in sectors or []:
635
- sector_name = sector["name"]
636
- self.sectors[sector_name] = Sector(name=sector_name, ocm=self)
637
- for sector in sectors or []:
638
- s = self.sectors[sector["name"]]
639
- for dep in sector.get("dependencies") or []:
640
- s.dependencies.append(self.sectors[dep["name"]])
128
+ @property
129
+ def ocm_api(self) -> OCMBaseClient:
130
+ return self._ocm_client
641
131
 
642
- @staticmethod
643
- def _ready_for_app_interface(cluster: dict[str, Any]) -> bool:
132
+ def _ready_for_app_interface(self, cluster: dict[str, Any]) -> bool:
644
133
  return (
645
134
  cluster["managed"]
646
135
  and cluster["state"] == STATUS_READY
647
- and cluster["product"]["id"] in OCM_PRODUCTS_IMPL
136
+ and cluster["product"]["id"] in self.product_portfolio.product_names
648
137
  )
649
138
 
650
139
  def _init_clusters(self, init_provision_shards: bool):
651
140
  api = f"{CS_API_BASE}/v1/clusters"
652
- params = {"search": f"organization.id='{self.org_id}'"}
141
+ product_csv = ",".join([f"'{p}'" for p in self.product_portfolio.product_names])
142
+ params = {
143
+ "search": f"organization.id='{self.org_id}' and managed='true' and product.id in ({product_csv})"
144
+ }
653
145
  clusters = self._get_json(api, params=params).get("items", [])
654
- self.cluster_ids = {c["name"]: c["id"] for c in clusters}
146
+ self.cluster_ids: dict[str, str] = {c["name"]: c["id"] for c in clusters}
655
147
 
656
148
  self.clusters: dict[str, OCMSpec] = {}
657
149
  self.available_cluster_upgrades: dict[str, list[str]] = {}
@@ -668,30 +160,41 @@ class OCM: # pylint: disable=too-many-public-methods
668
160
  else:
669
161
  self.not_ready_clusters.add(cluster_name)
670
162
 
163
+ @property
164
+ def non_blocked_cluster_upgrades(self) -> dict[str, list[str]]:
165
+ return {
166
+ cluster: [v for v in versions or [] if not self.version_blocked(v)]
167
+ for cluster, versions in self.available_cluster_upgrades.items()
168
+ }
169
+
671
170
  def is_ready(self, cluster):
672
171
  return cluster in self.clusters
673
172
 
674
- def _get_ocm_impl(self, product: str):
675
- return OCM_PRODUCTS_IMPL[product]
173
+ def get_product_impl(
174
+ self, product: str, hypershift: bool | None = False
175
+ ) -> OCMProduct:
176
+ return self.product_portfolio.get_product_impl(product, hypershift)
676
177
 
677
178
  def _get_cluster_ocm_spec(
678
179
  self, cluster: Mapping[str, Any], init_provision_shards: bool
679
180
  ) -> OCMSpec:
680
-
681
- impl = self._get_ocm_impl(cluster["product"]["id"])
682
- spec = impl.get_ocm_spec(self, cluster, init_provision_shards)
181
+ impl = self.get_product_impl(
182
+ cluster["product"]["id"], cluster["hypershift"]["enabled"]
183
+ )
184
+ spec = impl.get_ocm_spec(self.ocm_api, cluster, init_provision_shards)
683
185
  return spec
684
186
 
685
187
  def create_cluster(self, name: str, cluster: OCMSpec, dry_run: bool):
686
- impl = self._get_ocm_impl(cluster.spec.product)
687
- impl.create_cluster(self, name, cluster, dry_run)
188
+ impl = self.get_product_impl(cluster.spec.product, cluster.spec.hypershift)
189
+ impl.create_cluster(self.ocm_api, self.org_id, name, cluster, dry_run)
688
190
 
689
191
  def update_cluster(
690
192
  self, cluster_name: str, update_spec: Mapping[str, Any], dry_run=False
691
193
  ):
692
194
  cluster = self.clusters[cluster_name]
693
- impl = self._get_ocm_impl(cluster.spec.product)
694
- impl.update_cluster(self, cluster_name, update_spec)
195
+ cluster_id = self.cluster_ids[cluster_name]
196
+ impl = self.get_product_impl(cluster.spec.product, cluster.spec.hypershift)
197
+ impl.update_cluster(self.ocm_api, cluster_id, update_spec, dry_run)
695
198
 
696
199
  def get_group_if_exists(self, cluster, group_id):
697
200
  """Returns a list of users in a group in a cluster.
@@ -749,7 +252,7 @@ class OCM: # pylint: disable=too-many-public-methods
749
252
  )
750
253
  self._delete(api)
751
254
 
752
- def get_cluster_aws_account_id(self, cluster: str) -> Optional[str]:
255
+ def get_cluster_aws_account_id(self, cluster: str) -> str | None:
753
256
  """Returns the AWS account id of the cluster.
754
257
  Since there is no direct API to get this information,
755
258
  we hack our way by relying on existing role grants
@@ -870,8 +373,6 @@ class OCM: # pylint: disable=too-many-public-methods
870
373
  for idp in idps:
871
374
  if idp["type"] != "GithubIdentityProvider":
872
375
  continue
873
- if idp["mapping_method"] != "claim":
874
- continue
875
376
  idp_name = idp["name"]
876
377
  idp_github = idp["github"]
877
378
 
@@ -899,7 +400,7 @@ class OCM: # pylint: disable=too-many-public-methods
899
400
  api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/identity_providers"
900
401
  payload = {
901
402
  "type": "GithubIdentityProvider",
902
- "mapping_method": "claim",
403
+ "mapping_method": "add",
903
404
  "name": spec["name"],
904
405
  "github": {
905
406
  "client_id": spec["client_id"],
@@ -909,98 +410,18 @@ class OCM: # pylint: disable=too-many-public-methods
909
410
  }
910
411
  self._post(api, payload)
911
412
 
912
- def _check_oidc_idp_params(self, oidc_idp: OCMOidcIdp, attrs: Iterable[str]):
913
- for attr in attrs:
914
- if not getattr(oidc_idp, attr):
915
- raise ParameterError(
916
- f"{attrs} are mandatory parameters cannot be empty."
917
- )
413
+ def get_kubeconfig(self, cluster: str) -> str | None:
414
+ """Returns the cluster credentials (kubeconfig)
415
+
416
+ :param cluster: cluster name
918
417
 
919
- def get_oidc_idps(self, cluster: str) -> list[OCMOidcIdp]:
920
- """Returns a list of details of OpenID connect IDP providers."""
418
+ :type cluster: string
419
+ """
921
420
  cluster_id = self.cluster_ids.get(cluster)
922
421
  if not cluster_id:
923
- return []
924
- api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/identity_providers"
925
- idps = self._get_json(api).get("items")
926
- if not idps:
927
- return []
928
-
929
- results = []
930
- for idp in idps:
931
- if idp["type"] != "OpenIDIdentityProvider":
932
- continue
933
- claims = idp["open_id"].get("claims", {})
934
- results.append(
935
- OCMOidcIdp(
936
- cluster=cluster,
937
- id=idp["id"],
938
- name=idp["name"],
939
- client_id=idp["open_id"]["client_id"],
940
- issuer=idp["open_id"]["issuer"],
941
- email_claims=claims.get("email", []),
942
- name_claims=claims.get("name", []),
943
- username_claims=claims.get("preferred_username", []),
944
- groups_claims=claims.get("groups", []),
945
- )
946
- )
947
- return results
948
-
949
- def create_oidc_idp(self, oidc_idp: OCMOidcIdp) -> None:
950
- """Creates a new OpenID Connect IDP."""
951
- cluster_id = self.cluster_ids[oidc_idp.cluster]
952
- api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/identity_providers"
953
- self._check_oidc_idp_params(
954
- oidc_idp,
955
- attrs=["email_claims", "name_claims", "username_claims", "client_secret"],
956
- )
957
- payload = {
958
- "type": "OpenIDIdentityProvider",
959
- "name": oidc_idp.name,
960
- "mapping_method": "claim",
961
- "open_id": {
962
- "claims": {
963
- "email": oidc_idp.email_claims,
964
- "name": oidc_idp.name_claims,
965
- "preferred_username": oidc_idp.username_claims,
966
- "groups": oidc_idp.groups_claims,
967
- },
968
- "client_id": oidc_idp.client_id,
969
- "client_secret": oidc_idp.client_secret,
970
- "issuer": oidc_idp.issuer,
971
- },
972
- }
973
- self._post(api, payload)
974
-
975
- def update_oidc_idp(self, id: str, oidc_idp: OCMOidcIdp) -> None:
976
- """Update an existing OpenID Connect IDP."""
977
- cluster_id = self.cluster_ids[oidc_idp.cluster]
978
- self._check_oidc_idp_params(
979
- oidc_idp,
980
- attrs=["email_claims", "name_claims", "username_claims", "client_secret"],
981
- )
982
- api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/identity_providers/{id}"
983
- payload = {
984
- "type": "OpenIDIdentityProvider",
985
- "open_id": {
986
- "claims": {
987
- "email": oidc_idp.email_claims,
988
- "name": oidc_idp.name_claims,
989
- "preferred_username": oidc_idp.username_claims,
990
- "groups": oidc_idp.groups_claims,
991
- },
992
- "client_id": oidc_idp.client_id,
993
- "client_secret": oidc_idp.client_secret,
994
- "issuer": oidc_idp.issuer,
995
- },
996
- }
997
- self._patch(api, payload)
998
-
999
- def delete_idp(self, cluster: str, idp_id: str) -> None:
1000
- """Delete an IDP."""
1001
- cluster_id = self.cluster_ids[cluster]
1002
- api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/identity_providers/{idp_id}"
1003
- self._delete(api)
422
+ return None
423
+ api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/credentials"
424
+ return self._get_json(api).get("kubeconfig")
1004
425
 
1005
426
  def get_external_configuration_labels(self, cluster: str) -> dict[str, str]:
1006
427
  """Returns details of External Configurations
@@ -1066,32 +487,6 @@ class OCM: # pylint: disable=too-many-public-methods
1066
487
  )
1067
488
  self._delete(api)
1068
489
 
1069
- def _get_subscription_labels_api(self, cluster: str) -> str:
1070
- cluster_id = self.cluster_ids[cluster]
1071
- api = f"{CS_API_BASE}/v1/clusters/{cluster_id}"
1072
- subscription_api = self._get_json(api)["subscription"]["href"]
1073
- return f"{subscription_api}/labels"
1074
-
1075
- def is_cluster_admin_enabled(self, cluster: str) -> bool:
1076
- api = self._get_subscription_labels_api(cluster)
1077
- subcription_labels = self._get_json(api).get("items")
1078
-
1079
- for sl in subcription_labels or []:
1080
- if sl["key"] == CLUSTER_ADMIN_LABEL_KEY and sl["value"] == "true":
1081
- return True
1082
-
1083
- return False
1084
-
1085
- def enable_cluster_admin(self, cluster: str):
1086
- api = self._get_subscription_labels_api(cluster)
1087
- data = {
1088
- "key": CLUSTER_ADMIN_LABEL_KEY,
1089
- "value": "true",
1090
- "internal": True,
1091
- }
1092
-
1093
- self._post(api, data)
1094
-
1095
490
  def get_machine_pools(self, cluster):
1096
491
  """Returns a list of details of Machine Pools
1097
492
 
@@ -1163,6 +558,63 @@ class OCM: # pylint: disable=too-many-public-methods
1163
558
  )
1164
559
  self._delete(api)
1165
560
 
561
+ def get_node_pools(self, cluster):
562
+ """Returns a list of details of Node Pools
563
+
564
+ :param cluster: cluster name
565
+
566
+ :type cluster: string
567
+ """
568
+ results = []
569
+ cluster_id = self.cluster_ids.get(cluster)
570
+ if not cluster_id:
571
+ return results
572
+
573
+ return get_node_pools(self._ocm_client, cluster_id)
574
+
575
+ def delete_node_pool(self, cluster, spec):
576
+ """Deletes an existing Node Pool
577
+
578
+ :param cluster: cluster name
579
+ :param spec: required information for node pool update
580
+
581
+ :type cluster: string
582
+ :type spec: dictionary
583
+ """
584
+ cluster_id = self.cluster_ids[cluster]
585
+ node_pool_id = spec["id"]
586
+ api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/node_pools/" + f"{node_pool_id}"
587
+ self._delete(api)
588
+
589
+ def create_node_pool(self, cluster, spec):
590
+ """Creates a new Node Pool
591
+
592
+ :param cluster: cluster name
593
+ :param spec: required information for node pool creation
594
+
595
+ :type cluster: string
596
+ :type spec: dictionary
597
+ """
598
+ cluster_id = self.cluster_ids[cluster]
599
+ api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/node_pools"
600
+ self._post(api, spec)
601
+
602
+ def update_node_pool(self, cluster, spec):
603
+ """Updates an existing Node Pool
604
+
605
+ :param cluster: cluster name
606
+ :param spec: required information for node pool update
607
+
608
+ :type cluster: string
609
+ :type spec: dictionary
610
+ """
611
+ cluster_id = self.cluster_ids[cluster]
612
+ node_pool_id = spec["id"]
613
+ labels = spec.get("labels", {})
614
+ spec["labels"] = labels
615
+ api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/node_pools/" + f"{node_pool_id}"
616
+ self._patch(api, spec)
617
+
1166
618
  def addon_version_blocked(self, version: str, addon_id: str) -> bool:
1167
619
  """Check if an addon version is blocked
1168
620
 
@@ -1191,81 +643,16 @@ class OCM: # pylint: disable=too-many-public-methods
1191
643
  """
1192
644
  return any(re.search(b, version) for b in self.blocked_versions)
1193
645
 
1194
- def get_available_upgrades(self, version, channel):
1195
- """Get available versions to upgrade from specified version
1196
- in the specified channel
646
+ def get_available_upgrades(self, cluster_name: str) -> list[str]:
647
+ """Get available versions to upgrade for a specific cluster.
1197
648
 
1198
649
  Args:
1199
- version (string): OpenShift version ID
1200
- channel (string): Upgrade channel
1201
-
1202
- Raises:
1203
- KeyError: if specified channel is not valid
650
+ cluster_name (string): cluster display name to get available upgrades for
1204
651
 
1205
652
  Returns:
1206
- list: available versions to upgrade to
1207
- """
1208
- if channel not in UPGRADE_CHANNELS:
1209
- raise KeyError(f"channel should be one of {UPGRADE_CHANNELS}")
1210
- version_id = f"openshift-v{version}"
1211
- if channel != "stable":
1212
- version_id = f"{version_id}-{channel}"
1213
- api = f"{CS_API_BASE}/v1/versions/{version_id}"
1214
- return self._get_json(api).get("available_upgrades", [])
1215
-
1216
- def get_upgrade_policies(self, cluster, schedule_type=None) -> list[dict[str, Any]]:
1217
- """Returns a list of details of Upgrade Policies
1218
-
1219
- :param cluster: cluster name
1220
-
1221
- :type cluster: string
1222
- """
1223
- results: list[dict[str, Any]] = []
1224
- cluster_id = self.cluster_ids.get(cluster)
1225
- if not cluster_id:
1226
- return results
1227
- api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/upgrade_policies"
1228
- items = self._get_json(api).get("items")
1229
- if not items:
1230
- return results
1231
-
1232
- for item in items:
1233
- if schedule_type and item["schedule_type"] != schedule_type:
1234
- continue
1235
- result = {k: v for k, v in item.items() if k in UPGRADE_POLICY_DESIRED_KEYS}
1236
- results.append(result)
1237
-
1238
- return results
1239
-
1240
- def create_upgrade_policy(self, cluster, spec):
1241
- """Creates a new Upgrade Policy
1242
-
1243
- :param cluster: cluster name
1244
- :param spec: required information for creation
1245
-
1246
- :type cluster: string
1247
- :type spec: dictionary
1248
- """
1249
- cluster_id = self.cluster_ids[cluster]
1250
- api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/upgrade_policies"
1251
- self._post(api, spec)
1252
-
1253
- def delete_upgrade_policy(self, cluster, spec):
1254
- """Deletes an existing Upgrade Policy
1255
-
1256
- :param cluster: cluster name
1257
- :param spec: required information for update
1258
-
1259
- :type cluster: string
1260
- :type spec: dictionary
653
+ list: a non-null but potentially empty list of available versions to upgrade to
1261
654
  """
1262
- cluster_id = self.cluster_ids[cluster]
1263
- upgrade_policy_id = spec["id"]
1264
- api = (
1265
- f"{CS_API_BASE}/v1/clusters/{cluster_id}/"
1266
- + f"upgrade_policies/{upgrade_policy_id}"
1267
- )
1268
- self._delete(api)
655
+ return self.available_cluster_upgrades.get(cluster_name) or []
1269
656
 
1270
657
  def get_additional_routers(self, cluster):
1271
658
  """Returns a list of Additional Application Routers
@@ -1319,16 +706,6 @@ class OCM: # pylint: disable=too-many-public-methods
1319
706
  api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/" + f"ingresses/{router_id}"
1320
707
  self._delete(api)
1321
708
 
1322
- def get_provision_shard(self, cluster_id):
1323
- """Returns details of the provision shard
1324
-
1325
- :param cluster: cluster id
1326
-
1327
- :type cluster: string
1328
- """
1329
- api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/provision_shard"
1330
- return self._get_json(api)
1331
-
1332
709
  @staticmethod
1333
710
  def _get_autoscale(cluster):
1334
711
  autoscale = cluster["nodes"].get("autoscale_compute", None)
@@ -1346,45 +723,6 @@ class OCM: # pylint: disable=too-many-public-methods
1346
723
  api = f"{AMS_API_BASE}/v1/access_token"
1347
724
  return self._post(api)
1348
725
 
1349
- def get_kafka_clusters(self, fields=None):
1350
- """Returns details of the Kafka clusters"""
1351
- api = f"{KAS_API_BASE}/v1/kafkas"
1352
- clusters = self._get_json(api)["items"]
1353
- if fields:
1354
- clusters = [
1355
- {k: v for k, v in cluster.items() if k in fields}
1356
- for cluster in clusters
1357
- ]
1358
- return clusters
1359
-
1360
- def get_kafka_service_accounts(self, fields=None):
1361
- """Returns details of the Kafka service accounts"""
1362
- results = []
1363
- api = f"{KAS_API_BASE}/v1/service_accounts"
1364
- service_accounts = self._get_json(api)["items"]
1365
- for sa in service_accounts:
1366
- sa_id = sa["id"]
1367
- id_api = f"{api}/{sa_id}"
1368
- sa_details = self._get_json(id_api)
1369
- if fields:
1370
- sa_details = {k: v for k, v in sa_details.items() if k in fields}
1371
- results.append(sa_details)
1372
- return results
1373
-
1374
- def create_kafka_cluster(self, data):
1375
- """Creates (async) a Kafka cluster"""
1376
- api = f"{KAS_API_BASE}/v1/kafkas"
1377
- params = {"async": "true"}
1378
- self._post(api, data, params)
1379
-
1380
- def create_kafka_service_account(self, name, fields=None):
1381
- """Creates a Kafka service account"""
1382
- api = f"{KAS_API_BASE}/v1/service_accounts"
1383
- result = self._post(api, {"name": name})
1384
- if fields:
1385
- result = {k: v for k, v in result.items() if k in fields}
1386
- return result
1387
-
1388
726
  def _init_addons(self):
1389
727
  """Returns a list of Addons"""
1390
728
  api = f"{CS_API_BASE}/v1/addons"
@@ -1411,58 +749,6 @@ class OCM: # pylint: disable=too-many-public-methods
1411
749
  return addon["version"]["id"]
1412
750
  return None
1413
751
 
1414
- def get_addon_upgrade_policies(
1415
- self, cluster_name: str, addon_id: str = ""
1416
- ) -> list[dict[str, Any]]:
1417
- results: list[dict[str, Any]] = []
1418
- cluster_id = self.cluster_ids.get(cluster_name)
1419
- if not cluster_id:
1420
- return results
1421
- api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/addon_upgrade_policies"
1422
- items = self._get_json(api).get("items")
1423
- if not items:
1424
- return results
1425
-
1426
- for item in items:
1427
- if addon_id and item["addon_id"] != addon_id:
1428
- continue
1429
- result = {
1430
- k: v for k, v in item.items() if k in ADDON_UPGRADE_POLICY_DESIRED_KEYS
1431
- }
1432
- results.append(result)
1433
-
1434
- return results
1435
-
1436
- def create_addon_upgrade_policy(self, cluster_name: str, spec: dict) -> None:
1437
- """Creates a new Addon Upgrade Policy
1438
-
1439
- :param cluster: cluster name
1440
- :param spec: required information for creation
1441
-
1442
- :type cluster: string
1443
- :type spec: dictionary
1444
- """
1445
- cluster_id = self.cluster_ids[cluster_name]
1446
- api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/addon_upgrade_policies"
1447
- self._post(api, spec)
1448
-
1449
- def delete_addon_upgrade_policy(self, cluster_name: str, spec: dict) -> None:
1450
- """Deletes an existing Addon Upgrade Policy
1451
-
1452
- :param cluster: cluster name
1453
- :param spec: required information for delete
1454
-
1455
- :type cluster: string
1456
- :type spec: dictionary
1457
- """
1458
- cluster_id = self.cluster_ids[cluster_name]
1459
- upgrade_policy_id = spec["id"]
1460
- api = (
1461
- f"{CS_API_BASE}/v1/clusters/{cluster_id}/"
1462
- + f"addon_upgrade_policies/{upgrade_policy_id}"
1463
- )
1464
- self._delete(api)
1465
-
1466
752
  def get_version_gates(
1467
753
  self, version_prefix: str, sts_only: bool = False
1468
754
  ) -> list[dict[str, Any]]:
@@ -1475,31 +761,17 @@ class OCM: # pylint: disable=too-many-public-methods
1475
761
  and g["sts_only"] == sts_only
1476
762
  ]
1477
763
 
1478
- def get_version_agreement(self, cluster: str) -> list[dict[str, Any]]:
1479
- cluster_id = self.cluster_ids.get(cluster)
1480
- if not cluster_id:
1481
- return []
1482
- api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/gate_agreements"
1483
- agreements = self._get_json(api).get("items")
1484
- if agreements:
1485
- return agreements
1486
- return []
1487
-
1488
- def create_version_agreement(
1489
- self, gate_id: str, cluster: str
1490
- ) -> dict[str, Union[str, bool]]:
1491
- cluster_id = self.cluster_ids.get(cluster)
1492
- if not cluster_id:
1493
- return {}
1494
- api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/gate_agreements"
1495
- return self._post(api, {"version_gate": {"id": gate_id}})
1496
-
1497
764
  def get_cluster_addons(
1498
- self, cluster: str, with_version: bool = False
765
+ self,
766
+ cluster: str,
767
+ with_version: bool = False,
768
+ required_state: str | None = None,
1499
769
  ) -> list[dict[str, str]]:
1500
770
  """Returns a list of Addons installed on a cluster
1501
771
 
1502
772
  :param cluster: cluster name
773
+ :param with_version: include addon version
774
+ :param required_state: add search parameter to filter by specified state
1503
775
 
1504
776
  :type cluster: string
1505
777
  """
@@ -1508,7 +780,12 @@ class OCM: # pylint: disable=too-many-public-methods
1508
780
  if not cluster_id:
1509
781
  return results
1510
782
  api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/addons"
1511
- items = self._get_json(api).get("items")
783
+
784
+ p: dict[str, Any] | None = None
785
+ if required_state:
786
+ p = {"search": f"state='{required_state}'"}
787
+
788
+ items = self._get_json(api, params=p).get("items")
1512
789
  if not items:
1513
790
  return results
1514
791
 
@@ -1551,7 +828,9 @@ class OCM: # pylint: disable=too-many-public-methods
1551
828
  try:
1552
829
  re.compile(b)
1553
830
  except re.error:
1554
- raise TypeError(f"blocked version is not a valid regex expression: {b}")
831
+ raise TypeError(
832
+ f"blocked version is not a valid regex expression: {b}"
833
+ ) from None
1555
834
 
1556
835
  @retry(max_attempts=10)
1557
836
  def _do_get_request(self, api: str, params: Mapping[str, str]) -> dict[str, Any]:
@@ -1565,7 +844,7 @@ class OCM: # pylint: disable=too-many-public-methods
1565
844
  return rs["kind"].endswith("List")
1566
845
 
1567
846
  def _get_json(
1568
- self, api: str, params: Optional[dict[str, Any]] = None, page_size: int = 100
847
+ self, api: str, params: dict[str, Any] | None = None, page_size: int = 100
1569
848
  ) -> dict[str, Any]:
1570
849
  responses = []
1571
850
  if not params:
@@ -1653,11 +932,11 @@ class OCMMap: # pylint: disable=too-many-public-methods
1653
932
  init_provision_shards=False,
1654
933
  init_addons=False,
1655
934
  init_version_gates=False,
1656
- ):
935
+ product_portfolio: OCMProductPortfolio | None = None,
936
+ ) -> None:
1657
937
  """Initiates OCM instances for each OCM referenced in a cluster."""
1658
- self.clusters_map = {}
1659
- self.ocm_map = {}
1660
- self.sector_map = {}
938
+ self.clusters_map: dict[str, str] = {}
939
+ self.ocm_map: dict[str, OCM] = {}
1661
940
  self.calling_integration = integration
1662
941
  self.settings = settings
1663
942
 
@@ -1671,6 +950,7 @@ class OCMMap: # pylint: disable=too-many-public-methods
1671
950
  init_provision_shards,
1672
951
  init_addons,
1673
952
  init_version_gates=init_version_gates,
953
+ product_portfolio=product_portfolio,
1674
954
  )
1675
955
  elif namespaces:
1676
956
  for namespace_info in namespaces:
@@ -1680,6 +960,7 @@ class OCMMap: # pylint: disable=too-many-public-methods
1680
960
  init_provision_shards,
1681
961
  init_addons,
1682
962
  init_version_gates=init_version_gates,
963
+ product_portfolio=product_portfolio,
1683
964
  )
1684
965
  elif ocms:
1685
966
  for ocm in ocms:
@@ -1688,20 +969,21 @@ class OCMMap: # pylint: disable=too-many-public-methods
1688
969
  init_provision_shards,
1689
970
  init_addons,
1690
971
  init_version_gates=init_version_gates,
972
+ product_portfolio=product_portfolio,
1691
973
  )
1692
974
  else:
1693
975
  raise KeyError("expected one of clusters, namespaces or ocm.")
1694
976
 
1695
- # check sectors dependencies loop
1696
- for ocm in self.ocm_map.values():
1697
- for sector in ocm.sectors.values():
1698
- sector.validate_dependencies()
1699
-
1700
- def __getitem__(self, ocm_name) -> OCM:
977
+ def __getitem__(self, ocm_name: str) -> OCM:
1701
978
  return self.ocm_map[ocm_name]
1702
979
 
1703
980
  def init_ocm_client_from_cluster(
1704
- self, cluster_info, init_provision_shards, init_addons, init_version_gates
981
+ self,
982
+ cluster_info,
983
+ init_provision_shards,
984
+ init_addons,
985
+ init_version_gates,
986
+ product_portfolio: OCMProductPortfolio | None = None,
1705
987
  ):
1706
988
  if self.cluster_disabled(cluster_info):
1707
989
  return
@@ -1713,22 +995,20 @@ class OCMMap: # pylint: disable=too-many-public-methods
1713
995
 
1714
996
  if ocm_name not in self.ocm_map:
1715
997
  self.init_ocm_client(
1716
- ocm_info, init_provision_shards, init_addons, init_version_gates
998
+ ocm_info,
999
+ init_provision_shards,
1000
+ init_addons,
1001
+ init_version_gates,
1002
+ product_portfolio,
1717
1003
  )
1718
1004
 
1719
- if (
1720
- cluster_info.get("upgradePolicy") is not None
1721
- and cluster_info["upgradePolicy"].get("conditions") is not None
1722
- ):
1723
- sector_name = cluster_info["upgradePolicy"]["conditions"].get("sector")
1724
- if sector_name:
1725
- ocm = self.ocm_map.get(ocm_name)
1726
- # ensure our cluster actually runs in an OCM org we have access to
1727
- if ocm and ocm.is_ready(cluster_name):
1728
- ocm.sectors[sector_name].cluster_infos.append(cluster_info)
1729
-
1730
1005
  def init_ocm_client(
1731
- self, ocm_info, init_provision_shards, init_addons, init_version_gates
1006
+ self,
1007
+ ocm_info,
1008
+ init_provision_shards,
1009
+ init_addons,
1010
+ init_version_gates,
1011
+ product_portfolio: OCMProductPortfolio | None = None,
1732
1012
  ):
1733
1013
  """
1734
1014
  Initiate OCM client.
@@ -1771,18 +1051,19 @@ class OCMMap: # pylint: disable=too-many-public-methods
1771
1051
  self.ocm_map[ocm_name] = OCM(
1772
1052
  name,
1773
1053
  org_id,
1054
+ ocm_environment["name"],
1774
1055
  ocm_client,
1775
1056
  init_provision_shards=init_provision_shards,
1776
1057
  init_addons=init_addons,
1777
1058
  blocked_versions=ocm_info.get("blockedVersions"),
1778
1059
  init_version_gates=init_version_gates,
1779
- sectors=ocm_info.get("sectors"),
1780
1060
  inheritVersionData=ocm_info.get("inheritVersionData"),
1061
+ product_portfolio=product_portfolio,
1781
1062
  )
1782
1063
 
1783
1064
  def instances(self) -> list[str]:
1784
1065
  """Get list of OCM instance names initiated in the OCM map."""
1785
- return self.ocm_map.keys()
1066
+ return list(self.ocm_map.keys())
1786
1067
 
1787
1068
  def cluster_disabled(self, cluster_info):
1788
1069
  """
@@ -1810,46 +1091,19 @@ class OCMMap: # pylint: disable=too-many-public-methods
1810
1091
  :type cluster: string
1811
1092
  """
1812
1093
  ocm = self.clusters_map[cluster]
1813
- return self.ocm_map.get(ocm, None)
1094
+ return self.ocm_map[ocm]
1814
1095
 
1815
1096
  def clusters(self) -> list[str]:
1816
1097
  """Get list of cluster names initiated in the OCM map."""
1817
1098
  return [k for k, v in self.clusters_map.items() if v]
1818
1099
 
1819
- def cluster_specs(self) -> tuple[dict[str, OCMSpec], list]:
1100
+ def cluster_specs(self) -> tuple[dict[str, OCMSpec], list[str]]:
1820
1101
  """Get dictionary of cluster names and specs in the OCM map."""
1821
1102
  cluster_specs = {}
1822
1103
  for v in self.ocm_map.values():
1823
1104
  cluster_specs.update(v.clusters)
1824
1105
 
1825
- not_ready_cluster_names = []
1106
+ not_ready_cluster_names: list[str] = []
1826
1107
  for v in self.ocm_map.values():
1827
1108
  not_ready_cluster_names.extend(v.not_ready_clusters)
1828
1109
  return cluster_specs, not_ready_cluster_names
1829
-
1830
- def kafka_cluster_specs(self):
1831
- """Get dictionary of Kafka cluster names and specs in the OCM map."""
1832
- fields = [
1833
- "id",
1834
- "status",
1835
- "cloud_provider",
1836
- "region",
1837
- "multi_az",
1838
- "name",
1839
- "bootstrap_server_host",
1840
- "failed_reason",
1841
- ]
1842
- cluster_specs = []
1843
- for ocm in self.ocm_map.values():
1844
- clusters = ocm.get_kafka_clusters(fields=fields)
1845
- cluster_specs.extend(clusters)
1846
- return cluster_specs
1847
-
1848
- def kafka_service_account_specs(self):
1849
- """Get dictionary of Kafka service account specs in the OCM map."""
1850
- fields = ["name", "client_id"]
1851
- service_account_specs = []
1852
- for ocm in self.ocm_map.values():
1853
- service_accounts = ocm.get_kafka_service_accounts(fields=fields)
1854
- service_account_specs.extend(service_accounts)
1855
- return service_account_specs