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,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"