qontract-reconcile 0.10.0__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 (844) 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.10.0.dist-info → qontract_reconcile-0.10.1.dev1203.dist-info}/WHEEL +1 -2
  4. {qontract_reconcile-0.10.0.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.10.0.dist-info/LICENSE +0 -201
  676. qontract_reconcile-0.10.0.dist-info/METADATA +0 -63
  677. qontract_reconcile-0.10.0.dist-info/RECORD +0 -586
  678. qontract_reconcile-0.10.0.dist-info/top_level.txt +0 -4
  679. reconcile/ecr_mirror.py +0 -152
  680. reconcile/github_scanner.py +0 -74
  681. reconcile/gitlab_integrations.py +0 -63
  682. reconcile/gql_definitions/ocm_oidc_idp/clusters.py +0 -195
  683. reconcile/gql_definitions/ocp_release_mirror/ocp_release_mirror.py +0 -287
  684. reconcile/integrations_validator.py +0 -18
  685. reconcile/jenkins_plugins.py +0 -129
  686. reconcile/kafka_clusters.py +0 -208
  687. reconcile/ocm_cluster_admin.py +0 -42
  688. reconcile/ocm_oidc_idp.py +0 -198
  689. reconcile/ocp_release_mirror.py +0 -373
  690. reconcile/prometheus_rules_tester_old.py +0 -436
  691. reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager.py +0 -279
  692. reconcile/saas_auto_promotions_manager/utils/vcs.py +0 -141
  693. reconcile/sentry_config.py +0 -613
  694. reconcile/sentry_helper.py +0 -69
  695. reconcile/test/conftest.py +0 -187
  696. reconcile/test/fixtures.py +0 -24
  697. reconcile/test/saas_auto_promotions_manager/conftest.py +0 -69
  698. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py +0 -110
  699. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/data_keys.py +0 -10
  700. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_housekeeping.py +0 -200
  701. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_merge_request_manager.py +0 -151
  702. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py +0 -63
  703. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/data_keys.py +0 -4
  704. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_multiple_namespaces.py +0 -46
  705. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_namespace.py +0 -94
  706. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_target.py +0 -44
  707. reconcile/test/saas_auto_promotions_manager/subscriber/conftest.py +0 -74
  708. reconcile/test/saas_auto_promotions_manager/subscriber/data_keys.py +0 -11
  709. reconcile/test/saas_auto_promotions_manager/subscriber/test_content_hash.py +0 -155
  710. reconcile/test/saas_auto_promotions_manager/subscriber/test_diff.py +0 -173
  711. reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_channels_config_hash.py +0 -226
  712. reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_channels_moving_ref.py +0 -224
  713. reconcile/test/saas_auto_promotions_manager/subscriber/test_single_channel_with_single_publisher.py +0 -350
  714. reconcile/test/saas_auto_promotions_manager/test_integration_test.py +0 -129
  715. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_multiple_publishers_for_single_channel.py +0 -70
  716. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_use_target_config_hash.py +0 -63
  717. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_with_auto_promote.py +0 -74
  718. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_without_auto_promote.py +0 -65
  719. reconcile/test/test_aggregated_list.py +0 -237
  720. reconcile/test/test_amtool.py +0 -37
  721. reconcile/test/test_auto_promoter.py +0 -295
  722. reconcile/test/test_aws_ami_share.py +0 -68
  723. reconcile/test/test_aws_iam_keys.py +0 -70
  724. reconcile/test/test_aws_iam_password_reset.py +0 -35
  725. reconcile/test/test_aws_support_cases_sos.py +0 -23
  726. reconcile/test/test_checkpoint.py +0 -178
  727. reconcile/test/test_cli.py +0 -41
  728. reconcile/test/test_closedbox_endpoint_monitoring.py +0 -207
  729. reconcile/test/test_gabi_authorized_users.py +0 -72
  730. reconcile/test/test_github_org.py +0 -154
  731. reconcile/test/test_github_repo_invites.py +0 -123
  732. reconcile/test/test_gitlab_housekeeping.py +0 -88
  733. reconcile/test/test_gitlab_labeler.py +0 -129
  734. reconcile/test/test_gitlab_members.py +0 -283
  735. reconcile/test/test_instrumented_wrappers.py +0 -18
  736. reconcile/test/test_integrations_manager.py +0 -995
  737. reconcile/test/test_jenkins_worker_fleets.py +0 -55
  738. reconcile/test/test_jump_host.py +0 -117
  739. reconcile/test/test_ldap_users.py +0 -123
  740. reconcile/test/test_make.py +0 -28
  741. reconcile/test/test_ocm_additional_routers.py +0 -134
  742. reconcile/test/test_ocm_addons_upgrade_scheduler_org.py +0 -149
  743. reconcile/test/test_ocm_clusters.py +0 -598
  744. reconcile/test/test_ocm_clusters_manifest_updates.py +0 -89
  745. reconcile/test/test_ocm_oidc_idp.py +0 -315
  746. reconcile/test/test_ocm_update_recommended_version.py +0 -145
  747. reconcile/test/test_ocm_upgrade_scheduler.py +0 -614
  748. reconcile/test/test_ocm_upgrade_scheduler_org_updater.py +0 -129
  749. reconcile/test/test_openshift_base.py +0 -730
  750. reconcile/test/test_openshift_namespace_labels.py +0 -345
  751. reconcile/test/test_openshift_namespaces.py +0 -256
  752. reconcile/test/test_openshift_resource.py +0 -415
  753. reconcile/test/test_openshift_resources_base.py +0 -440
  754. reconcile/test/test_openshift_saas_deploy_change_tester.py +0 -310
  755. reconcile/test/test_openshift_tekton_resources.py +0 -253
  756. reconcile/test/test_openshift_upgrade_watcher.py +0 -146
  757. reconcile/test/test_prometheus_rules_tester.py +0 -151
  758. reconcile/test/test_prometheus_rules_tester_old.py +0 -77
  759. reconcile/test/test_quay_membership.py +0 -86
  760. reconcile/test/test_quay_mirror.py +0 -109
  761. reconcile/test/test_quay_mirror_org.py +0 -70
  762. reconcile/test/test_quay_repos.py +0 -59
  763. reconcile/test/test_queries.py +0 -53
  764. reconcile/test/test_repo_owners.py +0 -47
  765. reconcile/test/test_requests_sender.py +0 -139
  766. reconcile/test/test_saasherder.py +0 -1074
  767. reconcile/test/test_saasherder_allowed_secret_paths.py +0 -127
  768. reconcile/test/test_secret_reader.py +0 -153
  769. reconcile/test/test_slack_base.py +0 -185
  770. reconcile/test/test_slack_usergroups.py +0 -744
  771. reconcile/test/test_sql_query.py +0 -19
  772. reconcile/test/test_terraform_cloudflare_dns.py +0 -117
  773. reconcile/test/test_terraform_cloudflare_resources.py +0 -106
  774. reconcile/test/test_terraform_cloudflare_users.py +0 -749
  775. reconcile/test/test_terraform_resources.py +0 -257
  776. reconcile/test/test_terraform_tgw_attachments.py +0 -631
  777. reconcile/test/test_terraform_users.py +0 -57
  778. reconcile/test/test_terraform_vpc_peerings.py +0 -499
  779. reconcile/test/test_terraform_vpc_peerings_build_desired_state.py +0 -1061
  780. reconcile/test/test_unleash.py +0 -138
  781. reconcile/test/test_utils_aws_api.py +0 -240
  782. reconcile/test/test_utils_aws_helper.py +0 -80
  783. reconcile/test/test_utils_cluster_version_data.py +0 -177
  784. reconcile/test/test_utils_data_structures.py +0 -13
  785. reconcile/test/test_utils_disabled_integrations.py +0 -86
  786. reconcile/test/test_utils_expiration.py +0 -109
  787. reconcile/test/test_utils_external_resource_spec.py +0 -383
  788. reconcile/test/test_utils_external_resources.py +0 -247
  789. reconcile/test/test_utils_github_api.py +0 -73
  790. reconcile/test/test_utils_gitlab_api.py +0 -20
  791. reconcile/test/test_utils_gpg.py +0 -69
  792. reconcile/test/test_utils_gql.py +0 -81
  793. reconcile/test/test_utils_helm.py +0 -306
  794. reconcile/test/test_utils_helpers.py +0 -55
  795. reconcile/test/test_utils_imap_client.py +0 -65
  796. reconcile/test/test_utils_jjb_client.py +0 -52
  797. reconcile/test/test_utils_jsonpath.py +0 -286
  798. reconcile/test/test_utils_ldap_client.py +0 -51
  799. reconcile/test/test_utils_mr.py +0 -226
  800. reconcile/test/test_utils_mr_clusters_updates.py +0 -77
  801. reconcile/test/test_utils_oc.py +0 -984
  802. reconcile/test/test_utils_ocm.py +0 -110
  803. reconcile/test/test_utils_pagerduty_api.py +0 -251
  804. reconcile/test/test_utils_parse_dhms_duration.py +0 -34
  805. reconcile/test/test_utils_password_validator.py +0 -155
  806. reconcile/test/test_utils_quay_api.py +0 -86
  807. reconcile/test/test_utils_semver_helper.py +0 -19
  808. reconcile/test/test_utils_sharding.py +0 -56
  809. reconcile/test/test_utils_slack_api.py +0 -439
  810. reconcile/test/test_utils_smtp_client.py +0 -73
  811. reconcile/test/test_utils_state.py +0 -256
  812. reconcile/test/test_utils_terraform.py +0 -13
  813. reconcile/test/test_utils_terraform_client.py +0 -585
  814. reconcile/test/test_utils_terraform_config_client.py +0 -219
  815. reconcile/test/test_utils_terrascript_aws_client.py +0 -277
  816. reconcile/test/test_utils_terrascript_cloudflare_client.py +0 -597
  817. reconcile/test/test_utils_terrascript_cloudflare_resources.py +0 -26
  818. reconcile/test/test_vault_replication.py +0 -515
  819. reconcile/test/test_vault_utils.py +0 -47
  820. reconcile/test/test_version_bump.py +0 -18
  821. reconcile/test/test_vpc_peerings_validator.py +0 -103
  822. reconcile/test/test_wrong_region.py +0 -78
  823. reconcile/typed_queries/glitchtip_settings.py +0 -18
  824. reconcile/typed_queries/ocp_release_mirror.py +0 -11
  825. reconcile/unleash_watcher.py +0 -120
  826. reconcile/utils/git_secrets.py +0 -63
  827. reconcile/utils/mr/auto_promoter.py +0 -218
  828. reconcile/utils/sentry_client.py +0 -383
  829. release/test_version.py +0 -50
  830. release/version.py +0 -100
  831. tools/test/test_qontract_cli.py +0 -60
  832. tools/test/test_sre_checkpoints.py +0 -79
  833. /e2e_tests/__init__.py → /reconcile/aus/upgrades.py +0 -0
  834. /reconcile/{gql_definitions/ocp_release_mirror → aws_account_manager}/__init__.py +0 -0
  835. /reconcile/{test → aws_ami_cleanup}/__init__.py +0 -0
  836. /reconcile/{test/saas_auto_promotions_manager → aws_cloudwatch_log_retention}/__init__.py +0 -0
  837. /reconcile/{test/saas_auto_promotions_manager/merge_request_manager → aws_saml_idp}/__init__.py +0 -0
  838. /reconcile/{test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager → aws_saml_roles}/__init__.py +0 -0
  839. /reconcile/{test/saas_auto_promotions_manager/merge_request_manager/renderer → aws_version_sync}/__init__.py +0 -0
  840. /reconcile/{test/saas_auto_promotions_manager/subscriber → aws_version_sync/merge_request_manager}/__init__.py +0 -0
  841. /reconcile/{test/saas_auto_promotions_manager/utils → cluster_auth_rhidp}/__init__.py +0 -0
  842. /reconcile/{test/saas_auto_promotions_manager/utils/saas_files_inventory → dynatrace_token_provider}/__init__.py +0 -0
  843. {release → reconcile/endpoints_discovery}/__init__.py +0 -0
  844. {tools/test → reconcile/external_resources}/__init__.py +0 -0
@@ -1,23 +1,29 @@
1
1
  from collections.abc import Callable
2
- from typing import Optional
3
2
 
4
3
  from sretoolbox.utils import threaded
5
4
 
6
5
  from reconcile.openshift_saas_deploy import (
7
6
  QONTRACT_INTEGRATION as OPENSHIFT_SAAS_DEPLOY,
8
7
  )
9
- from reconcile.saas_auto_promotions_manager.merge_request_manager.merge_request_manager import (
10
- MergeRequestManager,
8
+ from reconcile.saas_auto_promotions_manager.merge_request_manager.batcher import (
9
+ Batcher,
10
+ )
11
+ from reconcile.saas_auto_promotions_manager.merge_request_manager.merge_request_manager_v2 import (
12
+ MergeRequestManagerV2,
13
+ )
14
+ from reconcile.saas_auto_promotions_manager.merge_request_manager.mr_parser import (
15
+ MRParser,
11
16
  )
12
17
  from reconcile.saas_auto_promotions_manager.merge_request_manager.renderer import (
13
18
  Renderer,
14
19
  )
20
+ from reconcile.saas_auto_promotions_manager.meta import QONTRACT_INTEGRATION
15
21
  from reconcile.saas_auto_promotions_manager.publisher import Publisher
22
+ from reconcile.saas_auto_promotions_manager.s3_exporter import S3Exporter
16
23
  from reconcile.saas_auto_promotions_manager.subscriber import Subscriber
17
24
  from reconcile.saas_auto_promotions_manager.utils.saas_files_inventory import (
18
25
  SaasFilesInventory,
19
26
  )
20
- from reconcile.saas_auto_promotions_manager.utils.vcs import VCS
21
27
  from reconcile.typed_queries.app_interface_repo_url import get_app_interface_repo_url
22
28
  from reconcile.typed_queries.app_interface_vault_settings import (
23
29
  get_app_interface_vault_settings,
@@ -28,12 +34,9 @@ from reconcile.typed_queries.saas_files import get_saas_files
28
34
  from reconcile.utils.defer import defer
29
35
  from reconcile.utils.promotion_state import PromotionState
30
36
  from reconcile.utils.secret_reader import create_secret_reader
31
- from reconcile.utils.semver_helper import make_semver
32
- from reconcile.utils.state import init_state
37
+ from reconcile.utils.state import State, init_state
33
38
  from reconcile.utils.unleash import get_feature_toggle_state
34
-
35
- QONTRACT_INTEGRATION = "saas-auto-promotions-manager"
36
- QONTRACT_INTEGRATION_VERSION = make_semver(0, 1, 0)
39
+ from reconcile.utils.vcs import VCS
37
40
 
38
41
 
39
42
  class SaasAutoPromotionsManager:
@@ -42,14 +45,16 @@ class SaasAutoPromotionsManager:
42
45
  deployment_state: PromotionState,
43
46
  vcs: VCS,
44
47
  saas_file_inventory: SaasFilesInventory,
45
- merge_request_manager: MergeRequestManager,
48
+ merge_request_manager_v2: MergeRequestManagerV2,
49
+ s3_exporter: S3Exporter,
46
50
  thread_pool_size: int,
47
51
  dry_run: bool,
48
52
  ):
49
53
  self._deployment_state = deployment_state
50
54
  self._vcs = vcs
51
55
  self._saas_file_inventory = saas_file_inventory
52
- self._merge_request_manager = merge_request_manager
56
+ self._merge_request_manager_v2 = merge_request_manager_v2
57
+ self._s3_exporter = s3_exporter
53
58
  self._thread_pool_size = thread_pool_size
54
59
  self._dry_run = dry_run
55
60
 
@@ -81,16 +86,25 @@ class SaasAutoPromotionsManager:
81
86
  self._fetch_publisher_real_world_states()
82
87
  self._compute_desired_subscriber_states()
83
88
  subscribers_with_diff = self._get_subscribers_with_diff()
84
- self._merge_request_manager.fetch_sapm_managed_open_merge_requests()
85
- self._merge_request_manager.housekeeping()
86
- self._merge_request_manager.create_promotion_merge_requests(
87
- subscribers=subscribers_with_diff
89
+ self._merge_request_manager_v2.reconcile(subscribers=subscribers_with_diff)
90
+ self._s3_exporter.export_publisher_data(
91
+ publishers=self._saas_file_inventory.publishers
88
92
  )
89
93
 
90
94
 
91
95
  def init_external_dependencies(
92
96
  dry_run: bool,
93
- ) -> tuple[PromotionState, VCS, SaasFilesInventory, MergeRequestManager]:
97
+ env_name: str | None = None,
98
+ app_name: str | None = None,
99
+ ) -> tuple[
100
+ PromotionState,
101
+ VCS,
102
+ SaasFilesInventory,
103
+ MergeRequestManagerV2,
104
+ S3Exporter,
105
+ State,
106
+ State,
107
+ ]:
94
108
  """
95
109
  Lets initialize everything that involves calls to external dependencies:
96
110
  - VCS -> Gitlab / Github queries
@@ -117,38 +131,69 @@ def init_external_dependencies(
117
131
  allow_deleting_mrs=allow_deleting_mrs,
118
132
  allow_opening_mrs=allow_opening_mrs,
119
133
  )
120
- merge_request_manager = MergeRequestManager(
134
+ mr_parser = MRParser(vcs=vcs)
135
+ merge_request_manager_v2 = MergeRequestManagerV2(
121
136
  vcs=vcs,
137
+ reconciler=Batcher(),
138
+ mr_parser=mr_parser,
122
139
  renderer=Renderer(),
123
140
  )
124
- saas_files = get_saas_files()
141
+ saas_files = get_saas_files(env_name=env_name, app_name=app_name)
125
142
  saas_inventory = SaasFilesInventory(saas_files=saas_files)
143
+ saas_deploy_state = init_state(
144
+ integration=OPENSHIFT_SAAS_DEPLOY, secret_reader=secret_reader
145
+ )
126
146
  deployment_state = PromotionState(
127
- state=init_state(integration=OPENSHIFT_SAAS_DEPLOY, secret_reader=secret_reader)
147
+ state=saas_deploy_state,
148
+ )
149
+ sapm_state = init_state(
150
+ integration=QONTRACT_INTEGRATION, secret_reader=secret_reader
151
+ )
152
+ s3_exporter = S3Exporter(
153
+ state=sapm_state,
154
+ dry_run=dry_run,
155
+ )
156
+ return (
157
+ deployment_state,
158
+ vcs,
159
+ saas_inventory,
160
+ merge_request_manager_v2,
161
+ s3_exporter,
162
+ saas_deploy_state,
163
+ sapm_state,
128
164
  )
129
- return deployment_state, vcs, saas_inventory, merge_request_manager
130
165
 
131
166
 
132
167
  @defer
133
168
  def run(
134
169
  dry_run: bool,
135
170
  thread_pool_size: int,
136
- defer: Optional[Callable] = None,
171
+ env_name: str | None = None,
172
+ app_name: str | None = None,
173
+ defer: Callable | None = None,
137
174
  ) -> None:
138
175
  (
139
176
  deployment_state,
140
177
  vcs,
141
178
  saas_inventory,
142
- merge_request_manager,
143
- ) = init_external_dependencies(dry_run=dry_run)
179
+ merge_request_manager_v2,
180
+ s3_exporter,
181
+ saas_deploy_state,
182
+ sapm_state,
183
+ ) = init_external_dependencies(
184
+ dry_run=dry_run, env_name=env_name, app_name=app_name
185
+ )
144
186
  if defer:
145
187
  defer(vcs.cleanup)
188
+ defer(saas_deploy_state.cleanup)
189
+ defer(sapm_state.cleanup)
146
190
 
147
191
  integration = SaasAutoPromotionsManager(
148
192
  deployment_state=deployment_state,
149
193
  vcs=vcs,
150
194
  saas_file_inventory=saas_inventory,
151
- merge_request_manager=merge_request_manager,
195
+ merge_request_manager_v2=merge_request_manager_v2,
196
+ s3_exporter=s3_exporter,
152
197
  thread_pool_size=thread_pool_size,
153
198
  dry_run=dry_run,
154
199
  )
@@ -0,0 +1,208 @@
1
+ from collections.abc import Iterable
2
+ from dataclasses import dataclass
3
+ from enum import Enum
4
+
5
+ from reconcile.saas_auto_promotions_manager.merge_request_manager.open_merge_requests import (
6
+ OpenBatcherMergeRequest,
7
+ )
8
+
9
+
10
+ class Reason(Enum):
11
+ MISSING_UNBATCHING = "Closing this MR because it failed MR check and isn't marked as un-batchable yet."
12
+ OUTDATED_CONTENT = "Closing this MR because it has out-dated content."
13
+ NEW_BATCH = "Closing this MR in favor of a new batch MR."
14
+
15
+
16
+ @dataclass(order=True)
17
+ class Promotion:
18
+ content_hashes: set[str]
19
+ channels: set[str]
20
+
21
+
22
+ @dataclass
23
+ class Deletion:
24
+ mr: OpenBatcherMergeRequest
25
+ reason: Reason
26
+
27
+
28
+ @dataclass
29
+ class Addition:
30
+ content_hashes: set[str]
31
+ channels: set[str]
32
+ batchable: bool
33
+
34
+
35
+ @dataclass
36
+ class Diff:
37
+ deletions: list[Deletion]
38
+ additions: list[Addition]
39
+
40
+
41
+ class Batcher:
42
+ """
43
+ The batcher calculates a Diff. I.e., which MRs need to be opened (Addition)
44
+ and which MRs need to be closed (Deletion). The batcher has no external
45
+ dependencies and does not interact with VCS. The batcher expects to be
46
+ given the desired state (which promotions do we want) and the current state
47
+ (the currently open MRs) in order to calculate the Diff.
48
+ """
49
+
50
+ def __init__(self) -> None:
51
+ self._desired_promotions: Iterable[Promotion] = []
52
+ self._open_mrs: Iterable[OpenBatcherMergeRequest] = []
53
+
54
+ def _unbatch(self, diff: Diff) -> None:
55
+ """
56
+ We optimistically batch MRs together that didnt run through MR check yet.
57
+ Vast majority of auto-promotion MRs are succeeding checks, so we can stay optimistic.
58
+ In the rare case of an MR failing the check, we want to unbatch it.
59
+ I.e., we open a dedicated MR for each channel in the batched MR, mark the new MRs as non-batchable
60
+ and close the old batched MR. By doing so, we ensure that unrelated MRs are not blocking each other.
61
+ Unbatched MRs are marked and will never be batched again.
62
+ """
63
+ open_mrs_after_unbatching: list[OpenBatcherMergeRequest] = []
64
+ unbatchable_hashes: set[str] = set()
65
+ falsely_marked_batchable_hashes: set[str] = set()
66
+ for mr in self._open_mrs:
67
+ if not mr.is_batchable:
68
+ unbatchable_hashes.update(mr.content_hashes)
69
+ open_mrs_after_unbatching.append(mr)
70
+ elif mr.failed_mr_check:
71
+ falsely_marked_batchable_hashes.update(mr.content_hashes)
72
+ diff.deletions.append(
73
+ Deletion(
74
+ mr=mr,
75
+ reason=Reason.MISSING_UNBATCHING,
76
+ )
77
+ )
78
+ else:
79
+ open_mrs_after_unbatching.append(mr)
80
+ self._open_mrs = open_mrs_after_unbatching
81
+
82
+ desired_promotions_after_unbatching: list[Promotion] = []
83
+ for promotion in self._desired_promotions:
84
+ if promotion.content_hashes.issubset(unbatchable_hashes):
85
+ desired_promotions_after_unbatching.append(promotion)
86
+ continue
87
+ elif promotion.content_hashes.issubset(falsely_marked_batchable_hashes):
88
+ diff.additions.append(
89
+ Addition(
90
+ content_hashes=promotion.content_hashes,
91
+ channels=promotion.channels,
92
+ batchable=False,
93
+ )
94
+ )
95
+ continue
96
+ else:
97
+ desired_promotions_after_unbatching.append(promotion)
98
+ self._desired_promotions = desired_promotions_after_unbatching
99
+
100
+ def _remove_outdated(self, diff: Diff) -> None:
101
+ """
102
+ We want to be sure that the open MRs are still addressing desired content.
103
+ We close MRs that are not addressing any content hash in a desired promotion.
104
+ """
105
+ all_desired_content_hashes: set[str] = set()
106
+ for promotion in self._desired_promotions:
107
+ all_desired_content_hashes.update(promotion.content_hashes)
108
+
109
+ open_mrs_after_deletion: list[OpenBatcherMergeRequest] = []
110
+ for mr in self._open_mrs:
111
+ if mr.content_hashes.issubset(all_desired_content_hashes):
112
+ open_mrs_after_deletion.append(mr)
113
+ continue
114
+ diff.deletions.append(
115
+ Deletion(
116
+ mr=mr,
117
+ reason=Reason.OUTDATED_CONTENT,
118
+ )
119
+ )
120
+ self._open_mrs = open_mrs_after_deletion
121
+
122
+ def _batch_remaining_mrs(self, diff: Diff, batch_limit: int) -> None:
123
+ """
124
+ Remaining desired promotions should be batched together
125
+ if they are not addressed yet by a valid open MR.
126
+
127
+ We do not want to let MR batches grow infinitely,
128
+ as constant change of a batch might starve MRs that
129
+ are already part of the batch.
130
+ In order for MRs to not grow infinitely, we apply a
131
+ BATCH_LIMIT per MR, i.e., a maximum number of hashes
132
+ that can be batched together.
133
+ """
134
+ submitted_content_hashes: set[str] = set()
135
+ for open_mr in self._open_mrs:
136
+ submitted_content_hashes.update(open_mr.content_hashes)
137
+
138
+ unsubmitted_promotions = [
139
+ prom
140
+ for prom in self._desired_promotions
141
+ if not prom.content_hashes.issubset(submitted_content_hashes)
142
+ ]
143
+
144
+ if not unsubmitted_promotions:
145
+ return
146
+
147
+ batch_with_capacity: OpenBatcherMergeRequest | None = None
148
+ for mr in self._open_mrs:
149
+ if mr.is_batchable and len(mr.content_hashes) < batch_limit:
150
+ batch_with_capacity = mr
151
+ # Note, there should always only be maximum one batch with capacity available
152
+ break
153
+
154
+ if batch_with_capacity:
155
+ # We disassemble the batch to its promotions
156
+ # can be added to new batch(es)
157
+ unsubmitted_promotions.append(
158
+ Promotion(
159
+ content_hashes=batch_with_capacity.content_hashes,
160
+ channels=batch_with_capacity.channels,
161
+ )
162
+ )
163
+ # Lets close the current batch so remaining promotions can
164
+ # be aggregated in new batch(es)
165
+ diff.deletions.append(
166
+ Deletion(
167
+ mr=batch_with_capacity,
168
+ reason=Reason.NEW_BATCH,
169
+ )
170
+ )
171
+
172
+ batched_mr = Addition(
173
+ content_hashes=set(),
174
+ channels=set(),
175
+ batchable=True,
176
+ )
177
+
178
+ for promotion in unsubmitted_promotions:
179
+ batched_mr.content_hashes.update(promotion.content_hashes)
180
+ batched_mr.channels.update(promotion.channels)
181
+ if len(batched_mr.content_hashes) >= batch_limit:
182
+ # Note, we might also be above the batch limit, but thats ok.
183
+ # We only ensure that we create a new batch now and dont grow further.
184
+ diff.additions.append(batched_mr)
185
+ batched_mr = Addition(
186
+ content_hashes=set(),
187
+ channels=set(),
188
+ batchable=True,
189
+ )
190
+ if batched_mr.content_hashes:
191
+ diff.additions.append(batched_mr)
192
+
193
+ def reconcile(
194
+ self,
195
+ desired_promotions: Iterable[Promotion],
196
+ open_mrs: Iterable[OpenBatcherMergeRequest],
197
+ batch_limit: int,
198
+ ) -> Diff:
199
+ self._open_mrs = open_mrs
200
+ self._desired_promotions = desired_promotions
201
+ diff = Diff(
202
+ deletions=[],
203
+ additions=[],
204
+ )
205
+ self._unbatch(diff=diff)
206
+ self._remove_outdated(diff=diff)
207
+ self._batch_remaining_mrs(diff=diff, batch_limit=batch_limit)
208
+ return diff
@@ -0,0 +1,28 @@
1
+ from collections import defaultdict
2
+ from collections.abc import Iterable
3
+
4
+ from reconcile.saas_auto_promotions_manager.merge_request_manager.batcher import (
5
+ Promotion,
6
+ )
7
+ from reconcile.saas_auto_promotions_manager.subscriber import Subscriber
8
+
9
+
10
+ class DesiredState:
11
+ def __init__(self, subscribers: Iterable[Subscriber]) -> None:
12
+ self.content_hash_to_subscriber: dict[str, list[Subscriber]] = {}
13
+ subscribers_per_channel_combo: dict[str, list[Subscriber]] = defaultdict(list)
14
+ for subscriber in subscribers:
15
+ channel_combo = ",".join([c.name for c in subscriber.channels])
16
+ subscribers_per_channel_combo[channel_combo].append(subscriber)
17
+
18
+ desired_promotions: list[Promotion] = []
19
+ for channel_combo, subs in subscribers_per_channel_combo.items():
20
+ combined_content_hash = Subscriber.combined_content_hash(subscribers=subs)
21
+ self.content_hash_to_subscriber[combined_content_hash] = subs
22
+ desired_promotions.append(
23
+ Promotion(
24
+ content_hashes={combined_content_hash},
25
+ channels={channel_combo},
26
+ )
27
+ )
28
+ self.promotions = desired_promotions
@@ -1,9 +1,8 @@
1
1
  import logging
2
- from collections.abc import Mapping
2
+ from collections.abc import Iterable, Mapping
3
3
 
4
4
  from reconcile.utils.gitlab_api import GitLabApi
5
5
  from reconcile.utils.mr.base import MergeRequestBase
6
- from reconcile.utils.mr.labels import AUTO_MERGE
7
6
 
8
7
  LOG = logging.getLogger(__name__)
9
8
 
@@ -23,13 +22,13 @@ class SAPMMR(MergeRequestBase):
23
22
  content_by_path: Mapping[str, str],
24
23
  description: str,
25
24
  title: str,
26
- sapm_label: str,
25
+ labels: Iterable[str],
27
26
  ):
28
27
  super().__init__()
29
28
  self._content_by_path = content_by_path
30
29
  self._title = title
31
30
  self._description = description
32
- self.labels = [AUTO_MERGE, sapm_label]
31
+ self.labels = labels
33
32
 
34
33
  @property
35
34
  def title(self) -> str:
@@ -0,0 +1,172 @@
1
+ import logging
2
+ from collections.abc import Iterable
3
+
4
+ from gitlab.exceptions import GitlabGetError
5
+
6
+ from reconcile.change_owners.change_types import ChangeTypePriority
7
+ from reconcile.saas_auto_promotions_manager.merge_request_manager.batcher import (
8
+ Addition,
9
+ Batcher,
10
+ )
11
+ from reconcile.saas_auto_promotions_manager.merge_request_manager.desired_state import (
12
+ DesiredState,
13
+ )
14
+ from reconcile.saas_auto_promotions_manager.merge_request_manager.merge_request import (
15
+ SAPMMR,
16
+ )
17
+ from reconcile.saas_auto_promotions_manager.merge_request_manager.metrics import (
18
+ SAPMClosedMRsCounter as MRClosedCounter,
19
+ )
20
+ from reconcile.saas_auto_promotions_manager.merge_request_manager.metrics import (
21
+ SAPMOpenedMRsCounter as MROpenedCounter,
22
+ )
23
+ from reconcile.saas_auto_promotions_manager.merge_request_manager.metrics import (
24
+ SAPMParallelOpenMRsGauge as ParallelOpenMRGauge,
25
+ )
26
+ from reconcile.saas_auto_promotions_manager.merge_request_manager.mr_parser import (
27
+ MRParser,
28
+ )
29
+ from reconcile.saas_auto_promotions_manager.merge_request_manager.renderer import (
30
+ Renderer,
31
+ )
32
+ from reconcile.saas_auto_promotions_manager.subscriber import Subscriber
33
+ from reconcile.utils import metrics
34
+ from reconcile.utils.mr.labels import prioritized_approval_label
35
+ from reconcile.utils.vcs import VCS
36
+
37
+ BATCH_SIZE_LIMIT = 5
38
+
39
+ SAPM_LABEL = "SAPM"
40
+ SAPM_MR_LABELS = [
41
+ SAPM_LABEL,
42
+ prioritized_approval_label(ChangeTypePriority.PROGRESSIVE_DELIVERY.value),
43
+ ]
44
+
45
+ MR_DESC = """
46
+ This is an auto-promotion triggered by app-interface's [saas-auto-promotions-manager](https://github.com/app-sre/qontract-reconcile/tree/master/reconcile/saas_auto_promotions_manager) (SAPM).
47
+ This MR promotes all subscribers with auto-promotions for the channel(s) listed below.
48
+
49
+ Please **do not manually modify** this MR in any way, as it might result in blocking the auto-promotion.
50
+
51
+ This description is used by SAPM to manage auto-promotions.
52
+ """
53
+
54
+
55
+ class MergeRequestManagerV2:
56
+ """
57
+ Manager for SAPM merge requests.
58
+
59
+ This class uses MRParser to fetch current state (currently open MRs).
60
+ This class calculates the desired state (i.e., desired promotions).
61
+ Desired state and current state are given to the Reconciler, which will
62
+ then determine a Diff (Additions and Deletions of MRs).
63
+
64
+ This class interacts with VCS to realize the result of the Diff.
65
+ """
66
+
67
+ def __init__(
68
+ self, vcs: VCS, mr_parser: MRParser, reconciler: Batcher, renderer: Renderer
69
+ ):
70
+ self._vcs = vcs
71
+ self._mr_parser = mr_parser
72
+ self._renderer = renderer
73
+ self._reconciler = reconciler
74
+ self._sapm_mrs: list[SAPMMR] = []
75
+
76
+ def _render_mr(self, addition: Addition) -> None:
77
+ subs: list[Subscriber] = []
78
+ for content_hash in addition.content_hashes:
79
+ subs.extend(self._desired_state.content_hash_to_subscriber[content_hash])
80
+ content_by_path: dict[str, str] = {}
81
+ has_error = False
82
+ for sub in subs:
83
+ if sub.target_file_path not in content_by_path:
84
+ try:
85
+ content_by_path[sub.target_file_path] = (
86
+ self._vcs.get_file_content_from_app_interface_master(
87
+ file_path=sub.target_file_path
88
+ )
89
+ )
90
+ except GitlabGetError as e:
91
+ if e.response_code == 404:
92
+ logging.error(
93
+ "The saas file %s does not exist anylonger. Most likely qontract-server data not in synch. This should resolve soon on its own.",
94
+ sub.target_file_path,
95
+ )
96
+ has_error = True
97
+ break
98
+ raise e
99
+ content_by_path[sub.target_file_path] = (
100
+ self._renderer.render_merge_request_content(
101
+ subscriber=sub,
102
+ current_content=content_by_path[sub.target_file_path],
103
+ )
104
+ )
105
+ if has_error:
106
+ return
107
+
108
+ description_hashes = ",".join(addition.content_hashes)
109
+ description_channels = ",".join(addition.channels)
110
+
111
+ description = self._renderer.render_description(
112
+ message=MR_DESC,
113
+ content_hashes=description_hashes,
114
+ channels=description_channels,
115
+ is_batchable=addition.batchable,
116
+ )
117
+ title = self._renderer.render_title(
118
+ is_draft=False,
119
+ canary=False,
120
+ channels=description_channels,
121
+ batch_size=len(addition.content_hashes),
122
+ )
123
+ logging.info(
124
+ "Open MR for update in channel(s) %s",
125
+ description_channels,
126
+ )
127
+ self._sapm_mrs.append(
128
+ SAPMMR(
129
+ labels=SAPM_MR_LABELS,
130
+ content_by_path=content_by_path,
131
+ title=title,
132
+ description=description,
133
+ )
134
+ )
135
+
136
+ def reconcile(self, subscribers: Iterable[Subscriber]) -> None:
137
+ self._mr_parser.fetch_mrs(label=SAPM_LABEL)
138
+ current_state = self._mr_parser.get_open_batcher_mrs()
139
+ desired_state = DesiredState(subscribers=subscribers)
140
+ self._desired_state = desired_state
141
+
142
+ diff = self._reconciler.reconcile(
143
+ batch_limit=BATCH_SIZE_LIMIT,
144
+ desired_promotions=desired_state.promotions,
145
+ open_mrs=current_state,
146
+ )
147
+ parallel_open_mrs = (
148
+ len(current_state) - len(diff.deletions) + len(diff.additions)
149
+ )
150
+ metrics.set_gauge(ParallelOpenMRGauge(), parallel_open_mrs)
151
+ for deletion in diff.deletions:
152
+ metrics.inc_counter(
153
+ MRClosedCounter(
154
+ reason=deletion.reason.name,
155
+ ),
156
+ )
157
+ self._vcs.close_app_interface_mr(
158
+ mr=deletion.mr.raw,
159
+ comment=deletion.reason.value,
160
+ )
161
+
162
+ for addition in diff.additions:
163
+ metrics.inc_counter(
164
+ MROpenedCounter(
165
+ is_batchable=addition.batchable,
166
+ batch_size=len(addition.content_hashes),
167
+ ),
168
+ )
169
+ self._render_mr(addition=addition)
170
+
171
+ for rendered_mr in self._sapm_mrs:
172
+ self._vcs.open_app_interface_merge_request(mr=rendered_mr)
@@ -0,0 +1,42 @@
1
+ from pydantic import BaseModel
2
+
3
+ from reconcile.utils.metrics import (
4
+ CounterMetric,
5
+ GaugeMetric,
6
+ )
7
+
8
+
9
+ class SAPMBaseMetric(BaseModel):
10
+ "Base class for SAPM MR metrics"
11
+
12
+ integration: str = "saas_auto_promotions_manager"
13
+
14
+
15
+ class SAPMOpenedMRsCounter(SAPMBaseMetric, CounterMetric):
16
+ "Counter for the number of opened auto-promotion MRs"
17
+
18
+ is_batchable: bool
19
+ # We do not expect batches >10, i.e., cardinality will stay in check here.
20
+ batch_size: int
21
+
22
+ @classmethod
23
+ def name(cls) -> str:
24
+ return "sapm_opened_mrs"
25
+
26
+
27
+ class SAPMClosedMRsCounter(SAPMBaseMetric, CounterMetric):
28
+ "Counter for the number of closed auto-promotion MRs"
29
+
30
+ reason: str
31
+
32
+ @classmethod
33
+ def name(cls) -> str:
34
+ return "sapm_closed_mrs"
35
+
36
+
37
+ class SAPMParallelOpenMRsGauge(SAPMBaseMetric, GaugeMetric):
38
+ "Gauge for the number of parallel open auto-promotion MRs"
39
+
40
+ @classmethod
41
+ def name(cls) -> str:
42
+ return "sapm_parallel_open_mrs"