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
@@ -3,13 +3,12 @@ import sys
3
3
  from collections.abc import (
4
4
  Callable,
5
5
  Iterable,
6
+ Sequence,
6
7
  )
7
8
  from datetime import datetime
8
9
  from typing import (
9
10
  Any,
10
- Optional,
11
- Sequence,
12
- Union,
11
+ TypedDict,
13
12
  )
14
13
  from urllib.parse import urlparse
15
14
 
@@ -47,6 +46,10 @@ from reconcile.utils.exceptions import (
47
46
  AppInterfaceSettingsError,
48
47
  UnknownError,
49
48
  )
49
+ from reconcile.utils.extended_early_exit import (
50
+ ExtendedEarlyExitRunnerResult,
51
+ extended_early_exit_run,
52
+ )
50
53
  from reconcile.utils.github_api import GithubRepositoryApi
51
54
  from reconcile.utils.gitlab_api import GitLabApi
52
55
  from reconcile.utils.pagerduty_api import (
@@ -67,10 +70,12 @@ from reconcile.utils.slack_api import (
67
70
 
68
71
  DATE_FORMAT = "%Y-%m-%d %H:%M"
69
72
  QONTRACT_INTEGRATION = "slack-usergroups"
73
+ INTEGRATION_VERSION = "0.1.0"
74
+
70
75
  error_occurred = False
71
76
 
72
77
 
73
- def get_git_api(url: str) -> Union[GithubRepositoryApi, GitLabApi]:
78
+ def get_git_api(url: str) -> GithubRepositoryApi | GitLabApi:
74
79
  """Return GitHub/GitLab API based on url."""
75
80
  parsed_url = urlparse(url)
76
81
 
@@ -109,12 +114,11 @@ class State(BaseModel):
109
114
  workspace: str = ""
110
115
  usergroup: str = ""
111
116
  description: str = ""
112
- users: set[SlackObject] = set()
113
- channels: set[SlackObject] = set()
114
- usergroup_id: Optional[str] = None
117
+ user_names: set[str] = set()
118
+ channel_names: set[str] = set()
115
119
 
116
120
  def __bool__(self) -> bool:
117
- return self.workspace != ""
121
+ return self.workspace != "" # noqa: PLC1901
118
122
 
119
123
 
120
124
  SlackState = dict[str, dict[str, State]]
@@ -141,7 +145,7 @@ def compute_cluster_user_group(name: str) -> str:
141
145
  def get_slack_map(
142
146
  secret_reader: SecretReader,
143
147
  permissions: Iterable[PermissionSlackUsergroupV1],
144
- desired_workspace_name: Optional[str] = None,
148
+ desired_workspace_name: str | None = None,
145
149
  ) -> SlackMap:
146
150
  """Return SlackMap (API) per workspaces."""
147
151
  slack_map = {}
@@ -177,8 +181,8 @@ def get_slack_map(
177
181
 
178
182
  def get_current_state(
179
183
  slack_map: SlackMap,
180
- desired_workspace_name: Optional[str],
181
- desired_usergroup_name: Optional[str],
184
+ desired_workspace_name: str | None,
185
+ desired_usergroup_name: str | None,
182
186
  cluster_usergroups: list[str],
183
187
  ) -> SlackState:
184
188
  """
@@ -207,10 +211,8 @@ def get_current_state(
207
211
  current_state.setdefault(workspace, {})[ug] = State(
208
212
  workspace=workspace,
209
213
  usergroup=ug,
210
- users={SlackObject(pk=pk, name=name) for pk, name in users.items()},
211
- channels={
212
- SlackObject(pk=pk, name=name) for pk, name in channels.items()
213
- },
214
+ user_names={name for _, name in users.items()},
215
+ channel_names={name for _, name in channels.items()},
214
216
  description=description,
215
217
  )
216
218
 
@@ -235,7 +237,7 @@ def get_usernames_from_pagerduty(
235
237
  pagerduty_map: PagerDutyMap,
236
238
  ) -> list[str]:
237
239
  """Return list of usernames from all pagerduties."""
238
- global error_occurred
240
+ global error_occurred # noqa: PLW0603
239
241
  all_output_usernames = []
240
242
  all_pagerduty_names = [get_pagerduty_name(u) for u in users]
241
243
  for pagerduty in pagerduties:
@@ -331,6 +333,7 @@ def get_slack_usernames_from_owners(
331
333
  get_slack_username(u)
332
334
  for u in users
333
335
  if getattr(u, user_key).lower() in [o.lower() for o in all_owners]
336
+ and u.tag_on_merge_requests is not False
334
337
  ]
335
338
  not_found_users = [
336
339
  owner
@@ -392,12 +395,11 @@ def include_user_to_cluster_usergroup(
392
395
 
393
396
 
394
397
  def get_desired_state(
395
- slack_map: SlackMap,
396
398
  pagerduty_map: PagerDutyMap,
397
399
  permissions: Iterable[PermissionSlackUsergroupV1],
398
400
  users: Iterable[User],
399
- desired_workspace_name: Optional[str],
400
- desired_usergroup_name: Optional[str],
401
+ desired_workspace_name: str | None,
402
+ desired_usergroup_name: str | None,
401
403
  ) -> SlackState:
402
404
  """Get the desired state of Slack usergroups."""
403
405
  desired_state: SlackState = {}
@@ -418,68 +420,68 @@ def get_desired_state(
418
420
  not in managed usergroups {p.workspace.managed_usergroups}"
419
421
  )
420
422
 
421
- slack = slack_map[p.workspace.name].slack
422
- ugid = slack.get_usergroup_id(usergroup)
423
-
424
- all_user_names = [get_slack_username(u) for r in p.roles or [] for u in r.users]
425
- slack_usernames_pagerduty = get_usernames_from_pagerduty(
426
- pagerduties=p.pagerduty or [],
427
- users=users,
428
- usergroup=usergroup,
429
- pagerduty_map=pagerduty_map,
430
- )
431
- all_user_names.extend(slack_usernames_pagerduty)
432
-
433
- if p.owners_from_repos:
434
- slack_usernames_repo = get_slack_usernames_from_owners(
435
- p.owners_from_repos, users, usergroup
436
- )
437
- all_user_names.extend(slack_usernames_repo)
438
-
439
- if p.schedule:
440
- slack_usernames_schedule = get_slack_usernames_from_schedule(
441
- p.schedule.schedule
423
+ try:
424
+ user_names = _get_user_names(p, pagerduty_map, usergroup, users)
425
+ except Exception:
426
+ logging.exception(
427
+ f"Error getting user names for {p.workspace.name} #{usergroup}, skipping"
442
428
  )
443
- all_user_names.extend(slack_usernames_schedule)
444
-
445
- user_names = list(set(all_user_names))
446
- slack_users = {
447
- SlackObject(pk=pk, name=name)
448
- for pk, name in slack.get_users_by_names(sorted(user_names)).items()
449
- }
450
- slack_channels = {
451
- SlackObject(pk=pk, name=name)
452
- for pk, name in slack.get_channels_by_names(
453
- sorted(p.channels or [])
454
- ).items()
455
- }
429
+ continue
456
430
 
457
431
  try:
458
- desired_state[p.workspace.name][usergroup].users.update(slack_users)
432
+ desired_state[p.workspace.name][usergroup].user_names.update(user_names)
459
433
  except KeyError:
460
434
  desired_state.setdefault(p.workspace.name, {})[usergroup] = State(
461
435
  workspace=p.workspace.name,
462
436
  usergroup=usergroup,
463
- usergroup_id=ugid,
464
- users=slack_users,
465
- channels=slack_channels,
437
+ user_names=user_names,
438
+ channel_names=sorted(set(p.channels or [])),
466
439
  description=p.description,
467
440
  )
468
441
  return desired_state
469
442
 
470
443
 
444
+ def _get_user_names(
445
+ permission: PermissionSlackUsergroupV1,
446
+ pagerduty_map: PagerDutyMap,
447
+ usergroup: str,
448
+ users: Iterable[User],
449
+ ) -> set[str]:
450
+ user_names = {
451
+ get_slack_username(u) for r in permission.roles or [] for u in r.users
452
+ }
453
+ slack_usernames_pagerduty = get_usernames_from_pagerduty(
454
+ pagerduties=permission.pagerduty or [],
455
+ users=users,
456
+ usergroup=usergroup,
457
+ pagerduty_map=pagerduty_map,
458
+ )
459
+ user_names.update(slack_usernames_pagerduty)
460
+ if permission.owners_from_repos:
461
+ slack_usernames_repo = get_slack_usernames_from_owners(
462
+ permission.owners_from_repos, users, usergroup
463
+ )
464
+ user_names.update(slack_usernames_repo)
465
+ if permission.schedule:
466
+ slack_usernames_schedule = get_slack_usernames_from_schedule(
467
+ permission.schedule.schedule
468
+ )
469
+ user_names.update(slack_usernames_schedule)
470
+ return user_names
471
+
472
+
471
473
  def get_desired_state_cluster_usergroups(
472
474
  slack_map: SlackMap,
473
475
  clusters: Iterable[ClusterV1],
474
476
  users: Iterable[UserV1],
475
- desired_workspace_name: Optional[str],
476
- desired_usergroup_name: Optional[str],
477
+ desired_workspace_name: str | None,
478
+ desired_usergroup_name: str | None,
477
479
  ) -> SlackState:
478
480
  """Get the desired state of Slack usergroups."""
479
481
  desired_state: SlackState = {}
480
- openshift_users_desired_state: list[
481
- dict[str, str]
482
- ] = openshift_users.fetch_desired_state(oc_map=None)
482
+ openshift_users_desired_state: list[dict[str, str]] = (
483
+ openshift_users.fetch_desired_state(oc_map=None)
484
+ )
483
485
  for cluster in clusters:
484
486
  if not integration_is_enabled(QONTRACT_INTEGRATION, cluster):
485
487
  logging.debug(
@@ -492,13 +494,11 @@ def get_desired_state_cluster_usergroups(
492
494
  for u in openshift_users_desired_state
493
495
  if u["cluster"] == cluster.name
494
496
  ]
495
- cluster_usernames = list(
496
- {
497
- get_slack_username(u)
498
- for u in users
499
- if include_user_to_cluster_usergroup(u, cluster, desired_cluster_users)
500
- }
501
- )
497
+ cluster_usernames = {
498
+ get_slack_username(u)
499
+ for u in users
500
+ if include_user_to_cluster_usergroup(u, cluster, desired_cluster_users)
501
+ }
502
502
  cluster_user_group = compute_cluster_user_group(cluster.name)
503
503
  for workspace, spec in slack_map.items():
504
504
  if not spec.slack.channel:
@@ -511,29 +511,16 @@ def get_desired_state_cluster_usergroups(
511
511
  if desired_workspace_name and desired_workspace_name != workspace:
512
512
  continue
513
513
 
514
- ugid = spec.slack.get_usergroup_id(cluster_user_group)
515
- slack_users = {
516
- SlackObject(pk=pk, name=name)
517
- for pk, name in spec.slack.get_users_by_names(
518
- sorted(cluster_usernames)
519
- ).items()
520
- }
521
- slack_channels = {
522
- SlackObject(pk=pk, name=name)
523
- for pk, name in spec.slack.get_channels_by_names(
524
- [spec.slack.channel]
525
- ).items()
526
- }
527
-
528
514
  try:
529
- desired_state[workspace][cluster_user_group].users.update(slack_users)
515
+ desired_state[workspace][cluster_user_group].user_names.update(
516
+ cluster_usernames
517
+ )
530
518
  except KeyError:
531
519
  desired_state.setdefault(workspace, {})[cluster_user_group] = State(
532
520
  workspace=workspace,
533
521
  usergroup=cluster_user_group,
534
- usergroup_id=ugid,
535
- users=slack_users,
536
- channels=slack_channels,
522
+ user_names=cluster_usernames,
523
+ channel_names={spec.slack.channel},
537
524
  description=f"Users with access to the {cluster.name} cluster",
538
525
  )
539
526
  return desired_state
@@ -544,25 +531,27 @@ def _create_usergroups(
544
531
  desired_ug_state: State,
545
532
  slack_client: SlackApi,
546
533
  dry_run: bool = True,
547
- ) -> None:
534
+ ) -> int:
548
535
  """Create Slack usergroups."""
549
- global error_occurred
536
+ global error_occurred # noqa: PLW0603
550
537
  if current_ug_state:
551
538
  logging.debug(
552
539
  f"[{desired_ug_state.workspace}] Usergroup exists and will not be created {desired_ug_state.usergroup}"
553
540
  )
554
- return
541
+ return 0
555
542
 
556
- logging.info(
557
- ["create_usergroup", desired_ug_state.workspace, desired_ug_state.usergroup]
558
- )
543
+ logging.info([
544
+ "create_usergroup",
545
+ desired_ug_state.workspace,
546
+ desired_ug_state.usergroup,
547
+ ])
559
548
  if not dry_run:
560
549
  try:
561
- usergroup_id = slack_client.create_usergroup(desired_ug_state.usergroup)
562
- desired_ug_state.usergroup_id = usergroup_id
550
+ slack_client.create_usergroup(desired_ug_state.usergroup)
563
551
  except SlackApiError as error:
564
552
  logging.error(error)
565
553
  error_occurred = True
554
+ return 1
566
555
 
567
556
 
568
557
  def _update_usergroup_users_from_state(
@@ -570,45 +559,55 @@ def _update_usergroup_users_from_state(
570
559
  desired_ug_state: State,
571
560
  slack_client: SlackApi,
572
561
  dry_run: bool = True,
573
- ) -> None:
562
+ ) -> int:
574
563
  """Update the users in a Slack usergroup."""
575
- global error_occurred
576
- if current_ug_state.users == desired_ug_state.users:
564
+ global error_occurred # noqa: PLW0603
565
+ if current_ug_state.user_names == desired_ug_state.user_names:
577
566
  logging.debug(
578
567
  f"No usergroup user changes detected for {desired_ug_state.usergroup}"
579
568
  )
580
- return
569
+ return 0
581
570
 
582
- for user in desired_ug_state.users - current_ug_state.users:
583
- logging.info(
584
- [
585
- "add_user_to_usergroup",
586
- desired_ug_state.workspace,
587
- desired_ug_state.usergroup,
588
- user.name,
589
- ]
590
- )
571
+ slack_user_objects = [
572
+ SlackObject(pk=pk, name=name)
573
+ for pk, name in slack_client.get_active_users_by_names(
574
+ desired_ug_state.user_names
575
+ ).items()
576
+ ]
577
+ active_user_names = {s.name for s in slack_user_objects}
591
578
 
592
- for user in current_ug_state.users - desired_ug_state.users:
579
+ if len(active_user_names) != len(desired_ug_state.user_names):
593
580
  logging.info(
594
- [
595
- "del_user_from_usergroup",
596
- desired_ug_state.workspace,
597
- desired_ug_state.usergroup,
598
- user.name,
599
- ]
581
+ f"Following usernames are incorrect for usergroup {desired_ug_state.usergroup} and could not be matched with slack users {desired_ug_state.user_names - active_user_names}"
600
582
  )
601
583
 
584
+ for user in active_user_names - current_ug_state.user_names:
585
+ logging.info([
586
+ "add_user_to_usergroup",
587
+ desired_ug_state.workspace,
588
+ desired_ug_state.usergroup,
589
+ user,
590
+ ])
591
+
592
+ for user in current_ug_state.user_names - active_user_names:
593
+ logging.info([
594
+ "del_user_from_usergroup",
595
+ desired_ug_state.workspace,
596
+ desired_ug_state.usergroup,
597
+ user,
598
+ ])
599
+
602
600
  if not dry_run:
603
601
  try:
604
- if not desired_ug_state.usergroup_id:
602
+ ugid = slack_client.get_usergroup_id(desired_ug_state.usergroup)
603
+ if not ugid:
605
604
  logging.info(
606
605
  f"Usergroup {desired_ug_state.usergroup} does not exist yet. Skipping for now."
607
606
  )
608
- return
607
+ return 0
609
608
  slack_client.update_usergroup_users(
610
- id=desired_ug_state.usergroup_id,
611
- users_list=sorted([user.pk for user in desired_ug_state.users]),
609
+ id=ugid,
610
+ users_list=sorted([s.pk for s in slack_user_objects]),
612
611
  )
613
612
  except SlackApiError as error:
614
613
  # Prior to adding this, we weren't handling failed updates to user
@@ -617,6 +616,7 @@ def _update_usergroup_users_from_state(
617
616
  # sensitive updates.
618
617
  logging.error(error)
619
618
  error_occurred = True
619
+ return 1
620
620
 
621
621
 
622
622
  def _update_usergroup_from_state(
@@ -624,65 +624,83 @@ def _update_usergroup_from_state(
624
624
  desired_ug_state: State,
625
625
  slack_client: SlackApi,
626
626
  dry_run: bool = True,
627
- ) -> None:
627
+ ) -> int:
628
628
  """Update a Slack usergroup."""
629
- global error_occurred
629
+ global error_occurred # noqa: PLW0603
630
+ change_detected = False
630
631
  if (
631
- current_ug_state.channels == desired_ug_state.channels
632
+ current_ug_state.channel_names == desired_ug_state.channel_names
632
633
  and current_ug_state.description == desired_ug_state.description
633
634
  ):
634
635
  logging.debug(
635
636
  f"No usergroup channel/description changes detected for {desired_ug_state.usergroup}",
636
637
  )
637
- return
638
+ return 0
638
639
 
639
- for channel in desired_ug_state.channels - current_ug_state.channels:
640
- logging.info(
641
- [
642
- "add_channel_to_usergroup",
643
- desired_ug_state.workspace,
644
- desired_ug_state.usergroup,
645
- channel.name,
646
- ]
647
- )
640
+ slack_channel_objects = [
641
+ SlackObject(pk=pk, name=name)
642
+ for pk, name in slack_client.get_channels_by_names(
643
+ desired_ug_state.channel_names or []
644
+ ).items()
645
+ ]
648
646
 
649
- for channel in current_ug_state.channels - desired_ug_state.channels:
650
- logging.info(
651
- [
652
- "del_channel_from_usergroup",
653
- desired_ug_state.workspace,
654
- desired_ug_state.usergroup,
655
- channel.name,
656
- ]
657
- )
647
+ # This is a hack to filter out the missing channels
648
+ desired_channel_names = {s.name for s in slack_channel_objects}
649
+
650
+ # Commenting this out is not correct, we should be checking the length of slack_channel_objects.
651
+ # However there are a couple of missing channels and filtering these out complies with current behavior.
652
+ # if len(slack_channel_objects) != len(desired_ug_state.channel_names):
653
+ # logging.info(
654
+ # f"Following channel names are incorrect for usergroup {desired_ug_state.usergroup} and could not be matched with slack channels {desired_ug_state.channel_names - set([s.name for s in slack_channel_objects])}"
655
+ # )
656
+ # error_occurred = True
657
+ # return
658
+
659
+ for channel in desired_channel_names - current_ug_state.channel_names:
660
+ change_detected = True
661
+ logging.info([
662
+ "add_channel_to_usergroup",
663
+ desired_ug_state.workspace,
664
+ desired_ug_state.usergroup,
665
+ channel,
666
+ ])
667
+
668
+ for channel in current_ug_state.channel_names - desired_channel_names:
669
+ change_detected = True
670
+ logging.info([
671
+ "del_channel_from_usergroup",
672
+ desired_ug_state.workspace,
673
+ desired_ug_state.usergroup,
674
+ channel,
675
+ ])
658
676
 
659
677
  if current_ug_state.description != desired_ug_state.description:
660
- logging.info(
661
- [
662
- "update_usergroup_description",
663
- desired_ug_state.workspace,
664
- desired_ug_state.usergroup,
665
- desired_ug_state.description,
666
- ]
667
- )
668
-
669
- if not dry_run:
678
+ change_detected = True
679
+ logging.info([
680
+ "update_usergroup_description",
681
+ desired_ug_state.workspace,
682
+ desired_ug_state.usergroup,
683
+ desired_ug_state.description,
684
+ ])
685
+
686
+ if not dry_run and change_detected:
670
687
  try:
671
- if not desired_ug_state.usergroup_id:
688
+ ugid = slack_client.get_usergroup_id(desired_ug_state.usergroup)
689
+ if not ugid:
672
690
  logging.info(
673
691
  f"Usergroup {desired_ug_state.usergroup} does not exist yet. Skipping for now."
674
692
  )
675
- return
693
+ return 0
676
694
  slack_client.update_usergroup(
677
- id=desired_ug_state.usergroup_id,
678
- channels_list=sorted(
679
- [channel.pk for channel in desired_ug_state.channels]
680
- ),
695
+ id=ugid,
696
+ channels_list=sorted(s.pk for s in slack_channel_objects),
681
697
  description=desired_ug_state.description,
682
698
  )
683
699
  except SlackApiError as error:
684
700
  logging.error(error)
685
701
  error_occurred = True
702
+ return 1
703
+ return 0
686
704
 
687
705
 
688
706
  def act(
@@ -690,35 +708,37 @@ def act(
690
708
  desired_state: SlackState,
691
709
  slack_map: SlackMap,
692
710
  dry_run: bool = True,
693
- ) -> None:
711
+ ) -> int:
694
712
  """Reconcile the differences between the desired and current state for
695
713
  Slack usergroups."""
714
+ apply_count = 0
696
715
  for workspace, desired_ws_state in desired_state.items():
697
716
  for usergroup, desired_ug_state in desired_ws_state.items():
698
717
  current_ug_state: State = current_state.get(workspace, {}).get(
699
718
  usergroup, State()
700
719
  )
701
720
 
702
- _create_usergroups(
721
+ apply_count += _create_usergroups(
703
722
  current_ug_state,
704
723
  desired_ug_state,
705
724
  slack_client=slack_map[workspace].slack,
706
725
  dry_run=dry_run,
707
726
  )
708
727
 
709
- _update_usergroup_users_from_state(
728
+ apply_count += _update_usergroup_users_from_state(
710
729
  current_ug_state,
711
730
  desired_ug_state,
712
731
  slack_client=slack_map[workspace].slack,
713
732
  dry_run=dry_run,
714
733
  )
715
734
 
716
- _update_usergroup_from_state(
735
+ apply_count += _update_usergroup_from_state(
717
736
  current_ug_state,
718
737
  desired_ug_state,
719
738
  slack_client=slack_map[workspace].slack,
720
739
  dry_run=dry_run,
721
740
  )
741
+ return apply_count
722
742
 
723
743
 
724
744
  def get_permissions(query_func: Callable) -> list[PermissionSlackUsergroupV1]:
@@ -740,17 +760,29 @@ def get_clusters(query_func: Callable) -> list[ClusterV1]:
740
760
  return clusters_query(query_func=query_func).clusters or []
741
761
 
742
762
 
763
+ class RunnerParams(TypedDict):
764
+ dry_run: bool
765
+ slack_map: SlackMap
766
+ desired_state: SlackState
767
+ clusters: list[ClusterV1]
768
+ workspace_name: str | None
769
+ usergroup_name: str | None
770
+
771
+
743
772
  def run(
744
773
  dry_run: bool,
745
- workspace_name: Optional[str] = None,
746
- usergroup_name: Optional[str] = None,
774
+ workspace_name: str | None = None,
775
+ usergroup_name: str | None = None,
776
+ enable_extended_early_exit: bool = False,
777
+ extended_early_exit_cache_ttl_seconds: int = 3600,
778
+ log_cached_log_output: bool = False,
747
779
  ) -> None:
748
- global error_occurred
780
+ global error_occurred # noqa: PLW0603
749
781
  error_occurred = False
750
782
 
751
783
  gqlapi = gql.get_api()
752
784
  secret_reader = SecretReader(queries.get_secret_reader_settings())
753
- init_users = False if usergroup_name else True
785
+ init_users = not usergroup_name
754
786
 
755
787
  # queries
756
788
  permissions = get_permissions(query_func=gqlapi.query)
@@ -770,7 +802,6 @@ def run(
770
802
 
771
803
  # run
772
804
  desired_state = get_desired_state(
773
- slack_map=slack_map,
774
805
  pagerduty_map=pagerduty_map,
775
806
  permissions=permissions,
776
807
  users=users,
@@ -786,6 +817,46 @@ def run(
786
817
  )
787
818
  # merge the two desired states recursively
788
819
  desired_state = deep_update(desired_state, desired_state_cluster_usergroups)
820
+
821
+ runner_params: RunnerParams = {
822
+ "dry_run": dry_run,
823
+ "slack_map": slack_map,
824
+ "desired_state": desired_state,
825
+ "clusters": clusters,
826
+ "workspace_name": workspace_name,
827
+ "usergroup_name": usergroup_name,
828
+ }
829
+
830
+ if enable_extended_early_exit:
831
+ extended_early_exit_run(
832
+ QONTRACT_INTEGRATION,
833
+ INTEGRATION_VERSION,
834
+ dry_run,
835
+ desired_state,
836
+ "",
837
+ extended_early_exit_cache_ttl_seconds,
838
+ logging.getLogger(),
839
+ runner,
840
+ runner_params=runner_params,
841
+ log_cached_log_output=log_cached_log_output,
842
+ secret_reader=secret_reader,
843
+ )
844
+ else:
845
+ runner(**runner_params)
846
+
847
+ if error_occurred:
848
+ logging.error("Error(s) occurred.")
849
+ sys.exit(1)
850
+
851
+
852
+ def runner(
853
+ dry_run: bool,
854
+ slack_map: SlackMap,
855
+ desired_state: SlackState,
856
+ clusters: list[ClusterV1],
857
+ workspace_name: str | None = None,
858
+ usergroup_name: str | None = None,
859
+ ) -> ExtendedEarlyExitRunnerResult:
789
860
  current_state = get_current_state(
790
861
  slack_map=slack_map,
791
862
  desired_workspace_name=workspace_name,
@@ -796,24 +867,31 @@ def run(
796
867
  if integration_is_enabled(QONTRACT_INTEGRATION, cluster)
797
868
  ],
798
869
  )
799
- act(
870
+ apply_count = act(
800
871
  current_state=current_state,
801
872
  desired_state=desired_state,
802
873
  slack_map=slack_map,
803
874
  dry_run=dry_run,
804
875
  )
805
- if error_occurred:
806
- logging.error("Error(s) occurred.")
807
- sys.exit(1)
876
+ return ExtendedEarlyExitRunnerResult(payload={}, applied_count=apply_count)
808
877
 
809
878
 
810
879
  def early_exit_desired_state(*args: Any, **kwargs: Any) -> dict[str, Any]:
811
880
  gqlapi = gql.get_api()
881
+ # exclude user.roles (cluster access roles) with tag_on_cluster_updates: false
882
+ # to speedup PR checks
883
+ users = get_users(gqlapi.query)
884
+ for user in users:
885
+ user.roles = [
886
+ role
887
+ for role in user.roles or []
888
+ if role.tag_on_cluster_updates is not False
889
+ ]
812
890
  return {
813
891
  "permissions": [p.dict() for p in get_permissions(gqlapi.query)],
814
892
  "pagerduty_instances": [
815
893
  p.dict() for p in get_pagerduty_instances(gqlapi.query)
816
894
  ],
817
- "users": [u.dict() for u in get_users(gqlapi.query)],
895
+ "users": [u.dict() for u in users],
818
896
  "clusters": [c.dict() for c in get_clusters(gqlapi.query)],
819
897
  }