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
@@ -0,0 +1,79 @@
1
+ from enum import Enum
2
+ from typing import TYPE_CHECKING, Literal
3
+
4
+ from pydantic import BaseModel, Field
5
+
6
+ if TYPE_CHECKING:
7
+ from mypy_boto3_support import SupportClient
8
+ else:
9
+ SupportClient = object
10
+
11
+
12
+ class AWSCase(BaseModel):
13
+ case_id: str = Field(..., alias="caseId")
14
+ subject: str
15
+ status: str
16
+
17
+
18
+ class SUPPORT_PLAN(Enum):
19
+ BASIC = "basic"
20
+ DEVELOPER = "developer"
21
+ BUSINESS = "business"
22
+ ENTERPRISE = "enterprise"
23
+
24
+
25
+ class AWSApiSupport:
26
+ def __init__(self, client: SupportClient) -> None:
27
+ self.client = client
28
+
29
+ def create_case(
30
+ self,
31
+ subject: str,
32
+ message: str,
33
+ category: str = "other-account-issues",
34
+ service: str = "customer-account",
35
+ issue_type: Literal["customer-service", "technical"] = "customer-service",
36
+ language: Literal["en", "zh", "ja", "ko"] = "en",
37
+ severity: str = "high",
38
+ ) -> str:
39
+ """Create a support case and return the case id."""
40
+ case = self.client.create_case(
41
+ subject=subject,
42
+ communicationBody=message,
43
+ categoryCode=category,
44
+ serviceCode=service,
45
+ issueType=issue_type,
46
+ language=language,
47
+ severityCode=severity,
48
+ )
49
+ return case["caseId"]
50
+
51
+ def describe_case(self, case_id: str) -> AWSCase:
52
+ """Return the status of a support case."""
53
+ case = self.client.describe_cases(caseIdList=[case_id])["cases"][0]
54
+ return AWSCase(**case)
55
+
56
+ def get_support_level(self) -> SUPPORT_PLAN:
57
+ """Return the support level of the account."""
58
+
59
+ try:
60
+ response = self.client.describe_severity_levels(language="en")
61
+ except self.client.exceptions.ClientError as err:
62
+ if err.response["Error"]["Code"] == "SubscriptionRequiredException":
63
+ return SUPPORT_PLAN.BASIC
64
+ raise err
65
+
66
+ severity_levels = {
67
+ level["code"].lower() for level in response["severityLevels"]
68
+ }
69
+ if "critical" in severity_levels:
70
+ return SUPPORT_PLAN.ENTERPRISE
71
+ if "urgent" in severity_levels:
72
+ return SUPPORT_PLAN.BUSINESS
73
+ if "high" in severity_levels:
74
+ return SUPPORT_PLAN.BUSINESS
75
+ if "normal" in severity_levels:
76
+ return SUPPORT_PLAN.DEVELOPER
77
+ if "low" in severity_levels:
78
+ return SUPPORT_PLAN.DEVELOPER
79
+ return SUPPORT_PLAN.BASIC
@@ -1,6 +1,10 @@
1
1
  from collections.abc import Iterable
2
- from typing import Any
2
+ from typing import Any, Protocol
3
3
 
4
+ from reconcile.utils.disabled_integrations import (
5
+ HasDisableIntegrations,
6
+ integration_is_enabled,
7
+ )
4
8
  from reconcile.utils.secret_reader import SecretReader
5
9
 
6
10
 
@@ -11,8 +15,8 @@ class AccountNotFoundError(Exception):
11
15
  Account = dict[str, Any]
12
16
 
13
17
 
14
- def get_user_id_from_arn(arn):
15
- # arn:aws:iam::12345:user/id --> id
18
+ def get_id_from_arn(arn):
19
+ # arn:aws:iam::12345:<arntype>/id --> id
16
20
  return arn.split("/")[1]
17
21
 
18
22
 
@@ -21,6 +25,17 @@ def get_account_uid_from_arn(arn):
21
25
  return arn.split(":")[4]
22
26
 
23
27
 
28
+ def get_role_name_from_arn(arn: str) -> str:
29
+ # arn:aws:iam::12345:role/role-1 --> role-1
30
+ return arn.split("/")[-1]
31
+
32
+
33
+ def is_aws_managed_resource(arn: str) -> bool:
34
+ # arn:aws:iam::aws:role/role-1 --> True
35
+ # arn:aws:iam::12345:role/role-1 --> False
36
+ return get_account_uid_from_arn(arn) == "aws"
37
+
38
+
24
39
  def get_details_from_role_link(role_link):
25
40
  # https://signin.aws.amazon.com/switchrole?
26
41
  # account=<uid>&roleName=<role_name> -->
@@ -61,3 +76,27 @@ def get_account(accounts: Iterable[Account], account_name: str) -> Account:
61
76
 
62
77
  def get_region_from_availability_zone(availability_zone: str) -> str:
63
78
  return availability_zone[:-1]
79
+
80
+
81
+ class AccountSSO(HasDisableIntegrations, Protocol):
82
+ name: str
83
+ uid: str
84
+ sso: bool | None
85
+
86
+
87
+ def unique_sso_aws_accounts(
88
+ integration: str, accounts: Iterable[AccountSSO], account_name: str | None = None
89
+ ) -> list[AccountSSO]:
90
+ """Return a unique list of AWS accounts with SSO enabled."""
91
+ filtered_account = {}
92
+ for account in accounts:
93
+ if account_name and account.name != account_name:
94
+ continue
95
+ if not account.sso:
96
+ continue
97
+ if not integration_is_enabled(integration, account):
98
+ continue
99
+ if account.uid in filtered_account:
100
+ continue
101
+ filtered_account[account.uid] = account
102
+ return list(filtered_account.values())
@@ -0,0 +1,11 @@
1
+ from collections.abc import Generator, Iterable
2
+ from itertools import islice
3
+ from typing import Any
4
+
5
+
6
+ def batched(iterable: Iterable[Any], size: int) -> Generator:
7
+ if size < 1:
8
+ raise ValueError("n must be at least one")
9
+ it = iter(iterable)
10
+ while batch := tuple(islice(it, size)):
11
+ yield batch
reconcile/utils/binary.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import re
2
+ import shutil
2
3
  import subprocess
3
- from distutils.spawn import find_executable # pylint: disable=deprecated-module
4
4
  from functools import wraps
5
5
 
6
6
 
@@ -13,7 +13,7 @@ def binary(binaries=None):
13
13
  @wraps(f)
14
14
  def f_binary(*args, **kwargs):
15
15
  for b in binaries:
16
- if not find_executable(b):
16
+ if not shutil.which(b):
17
17
  raise Exception(
18
18
  f"Aborting: Could not find binary: {b}. "
19
19
  + f"Hint: https://command-not-found.com/{b}"
@@ -25,7 +25,7 @@ def binary(binaries=None):
25
25
  return deco_binary
26
26
 
27
27
 
28
- def binary_version(binary, version_args, search_regex, expected_version):
28
+ def binary_version(binary, version_args, search_regex, expected_versions):
29
29
  """Check that a binary exists and is a desired version"""
30
30
 
31
31
  def deco_binary_version(f):
@@ -36,15 +36,13 @@ def binary_version(binary, version_args, search_regex, expected_version):
36
36
  cmd = [binary]
37
37
  cmd.extend(version_args)
38
38
  try:
39
- result = subprocess.run(
40
- cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True
41
- )
39
+ result = subprocess.run(cmd, capture_output=True, check=True)
42
40
  except subprocess.CalledProcessError as e:
43
41
  msg = (
44
42
  f"Could not execute binary '{binary}' "
45
43
  f"for binary version check: {e}"
46
44
  )
47
- raise Exception(msg)
45
+ raise Exception(msg) from e
48
46
 
49
47
  found = False
50
48
  match = None
@@ -62,10 +60,10 @@ def binary_version(binary, version_args, search_regex, expected_version):
62
60
  )
63
61
 
64
62
  version = match.group(1)
65
- if version != expected_version:
63
+ if version not in expected_versions:
66
64
  raise Exception(
67
65
  f"Binary version check for binary {binary} failed! "
68
- f"Expected: {expected_version}, found: {version}"
66
+ f"Expected: {expected_versions}, found: {version}"
69
67
  )
70
68
 
71
69
  f(*args, **kwargs)
@@ -0,0 +1,66 @@
1
+ import operator
2
+ from typing import Any
3
+
4
+ from terrascript.resource import aws_db_instance
5
+
6
+ delete_automated_backups = "delete_automated_backups"
7
+ skip_final_snapshot = "skip_final_snapshot"
8
+ backup_retention_period = "backup_retention_period"
9
+
10
+
11
+ # Keeping the exception specific now, we can build a generic exception and refactor later
12
+ # as more cases arise in the future.
13
+ class RDSResourceComplianceError(Exception):
14
+ def __init__(
15
+ self, field_expected_actual: list[tuple[str, Any, Any]], db_identifier: str
16
+ ):
17
+ self.actual_vs_expected = field_expected_actual
18
+
19
+ self.message = (
20
+ f"AWS RDS instance {db_identifier} does not comply with best practices\n"
21
+ )
22
+
23
+ for field, actual, expected in field_expected_actual:
24
+ self.message += (
25
+ f'Expected field {field} with value "{expected}", found "{actual}" \n'
26
+ )
27
+ super().__init__(self.message)
28
+
29
+
30
+ __loss_impact_levels = {
31
+ "high": [
32
+ (delete_automated_backups, False, operator.__eq__),
33
+ (skip_final_snapshot, False, operator.__eq__),
34
+ (backup_retention_period, 7, operator.__ge__),
35
+ ],
36
+ "medium": [
37
+ (skip_final_snapshot, False, operator.__eq__),
38
+ (backup_retention_period, 7, operator.__ge__),
39
+ ],
40
+ "low": [(backup_retention_period, 3, operator.__ge__)],
41
+ "none": [(backup_retention_period, 0, operator.__ge__)],
42
+ }
43
+
44
+
45
+ # Keeping this method here for now, we can re-evaluate if this needs to go to separate util once more
46
+ # use-cases are built.
47
+ def _check(aws_db_instance: aws_db_instance, checks: list) -> None:
48
+ rds_fields_not_complied = []
49
+ for field, expected_value, op in checks:
50
+ if not op(aws_db_instance.get(field), expected_value):
51
+ rds_fields_not_complied.append((
52
+ field,
53
+ aws_db_instance.get(field),
54
+ expected_value,
55
+ ))
56
+
57
+ if len(rds_fields_not_complied) > 0:
58
+ raise RDSResourceComplianceError(rds_fields_not_complied, aws_db_instance._name)
59
+
60
+
61
+ def verify_rds_best_practices(
62
+ aws_db_instance: aws_db_instance, data_classification: dict
63
+ ) -> None:
64
+ if data_classification is None:
65
+ return
66
+ _check(aws_db_instance, __loss_impact_levels[data_classification["loss_impact"]])
File without changes
@@ -0,0 +1,39 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from pydantic import BaseModel
4
+
5
+
6
+ class ClusterHealth(BaseModel):
7
+ source: str
8
+ errors: set[str] | None = None
9
+
10
+ def has_health_errors(self) -> bool:
11
+ return bool(self.errors)
12
+
13
+
14
+ def build_assumed_cluster_health() -> ClusterHealth:
15
+ return ClusterHealth(source="assumption")
16
+
17
+
18
+ class ClusterHealthProvider(ABC):
19
+ """
20
+ A base class for cluster health providers.
21
+ """
22
+
23
+ @abstractmethod
24
+ def cluster_health(self, cluster_external_id: str, org_id: str) -> ClusterHealth:
25
+ """
26
+ Provides health information for an individual cluster in an organization
27
+ """
28
+
29
+
30
+ class EmptyClusterHealthProvider(ClusterHealthProvider):
31
+ """
32
+ A default implementation of a cluster health provider that returns no health
33
+ information. Not every environment has a healthprovider available and this
34
+ implementation helps avoiding to check for the existance of a health provider
35
+ in various code places for such environments.
36
+ """
37
+
38
+ def cluster_health(self, cluster_external_id: str, org_id: str) -> ClusterHealth:
39
+ return build_assumed_cluster_health()
@@ -0,0 +1,39 @@
1
+ from functools import lru_cache
2
+
3
+ from reconcile.utils.clusterhealth.providerbase import (
4
+ ClusterHealth,
5
+ ClusterHealthProvider,
6
+ )
7
+ from reconcile.utils.grouping import group_by
8
+ from reconcile.utils.prometheus import PrometheusQuerier
9
+
10
+ TELEMETER_SOURCE = "telemeter"
11
+
12
+
13
+ class TelemeterClusterHealthProvider(ClusterHealthProvider):
14
+ def __init__(self, querier: PrometheusQuerier):
15
+ self.querier = querier
16
+ self.cluster_health_for_org = lru_cache(maxsize=None)(
17
+ self._cluster_health_for_org
18
+ )
19
+
20
+ def _cluster_health_for_org(self, org_id: str) -> dict[str, ClusterHealth]:
21
+ vectors_by_cluster = group_by(
22
+ self.querier.instant_vector_query(telemeter_alert_query(org_id)),
23
+ lambda v: v.mandatory_label("_id"),
24
+ )
25
+ return {
26
+ cluster_id: ClusterHealth(
27
+ errors={alert.mandatory_label("alertname") for alert in vectors},
28
+ source=TELEMETER_SOURCE,
29
+ )
30
+ for cluster_id, vectors in vectors_by_cluster.items()
31
+ }
32
+
33
+ def cluster_health(self, cluster_external_id: str, org_id: str) -> ClusterHealth:
34
+ health = self.cluster_health_for_org(org_id=org_id).get(cluster_external_id)
35
+ return health or ClusterHealth(source=TELEMETER_SOURCE)
36
+
37
+
38
+ def telemeter_alert_query(organization_id: str) -> str:
39
+ return f'alerts{{alertstate="firing", severity="critical"}} * on (_id) group_left(organization) max(ocm_subscription{{organization="{organization_id}"}}) by (_id, organization)'
reconcile/utils/config.py CHANGED
@@ -12,12 +12,11 @@ class SecretNotFound(Exception):
12
12
 
13
13
 
14
14
  def get_config():
15
- global _config
16
15
  return _config
17
16
 
18
17
 
19
18
  def init(config):
20
- global _config
19
+ global _config # noqa: PLW0603
21
20
  _config = config
22
21
  return _config
23
22
 
@@ -36,7 +35,7 @@ def read(secret):
36
35
  config = config[t]
37
36
  return config[field]
38
37
  except Exception as e:
39
- raise SecretNotFound(f"key not found in config file {path}: {str(e)}")
38
+ raise SecretNotFound(f"key not found in config file {path}: {e!s}") from None
40
39
 
41
40
 
42
41
  def read_all(secret):
@@ -48,4 +47,4 @@ def read_all(secret):
48
47
  config = config[t]
49
48
  return config
50
49
  except Exception as e:
51
- raise SecretNotFound(f"secret {path} not found in config file: {str(e)}")
50
+ raise SecretNotFound(f"secret {path} not found in config file: {e!s}") from None
@@ -0,0 +1,86 @@
1
+ import logging
2
+ from typing import (
3
+ Any,
4
+ Self,
5
+ )
6
+
7
+ import requests
8
+ from pydantic import BaseModel
9
+
10
+ BASE_URL = "https://api.deadmanssnitch.com/v1/snitches"
11
+ REQUEST_TIMEOUT = 60
12
+
13
+
14
+ class DeadManssnitchException(Exception):
15
+ pass
16
+
17
+
18
+ class Snitch(BaseModel):
19
+ token: str
20
+ href: str
21
+ name: str
22
+ tags: list[str]
23
+ notes: str
24
+ status: str
25
+ check_in_url: str
26
+ interval: str
27
+ alert_type: str
28
+ alert_email: list[str]
29
+ vault_data: str | None
30
+
31
+ def needs_vault_update(self) -> bool:
32
+ return self.vault_data is not None and self.check_in_url != self.vault_data
33
+
34
+
35
+ class DeadMansSnitchApi:
36
+ def __init__(
37
+ self, token: str, url: str = BASE_URL, timeout: int = REQUEST_TIMEOUT
38
+ ) -> None:
39
+ self.token = token
40
+ self.url = url
41
+ self.timeout = timeout
42
+ self.session = requests.Session()
43
+
44
+ def __enter__(self) -> Self:
45
+ return self
46
+
47
+ def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
48
+ self.session.close()
49
+
50
+ def get_snitches(self, tags: list[str]) -> list[Snitch]:
51
+ logging.debug("Getting snitches for tags:%s", tags)
52
+ response = self.session.get(
53
+ url=self.url,
54
+ params={"tags": ",".join(tags)},
55
+ auth=(self.token, ""),
56
+ timeout=self.timeout,
57
+ )
58
+ response.raise_for_status()
59
+ snitches = [Snitch(**item) for item in response.json()]
60
+ return snitches
61
+
62
+ def create_snitch(self, payload: dict) -> Snitch:
63
+ if payload.get("name") is None or payload.get("interval") is None:
64
+ raise DeadManssnitchException(
65
+ "Invalid payload,name and interval are mandatory"
66
+ )
67
+ headers = {"Content-Type": "application/json"}
68
+ logging.debug("Creating new snitch with name:: %s ", payload["name"])
69
+ response = self.session.post(
70
+ url=self.url,
71
+ json=payload,
72
+ auth=(self.token, ""),
73
+ headers=headers,
74
+ timeout=self.timeout,
75
+ )
76
+ response.raise_for_status()
77
+ response_json = response.json()
78
+ return Snitch(**response_json)
79
+
80
+ def delete_snitch(self, token: str) -> None:
81
+ delete_api_url = f"{self.url}/{token}"
82
+ response = self.session.delete(
83
+ url=delete_api_url, auth=(self.token, ""), timeout=self.timeout
84
+ )
85
+ response.raise_for_status()
86
+ logging.debug("Successfully deleted snich: %s", token)
@@ -0,0 +1,205 @@
1
+ from collections.abc import (
2
+ Callable,
3
+ Iterable,
4
+ Mapping,
5
+ )
6
+ from dataclasses import dataclass
7
+ from typing import (
8
+ Any,
9
+ Generic,
10
+ TypeVar,
11
+ )
12
+
13
+ T = TypeVar("T")
14
+ Current = TypeVar("Current")
15
+ Desired = TypeVar("Desired")
16
+ Key = TypeVar("Key")
17
+
18
+
19
+ @dataclass(frozen=True, eq=True)
20
+ class DiffPair(Generic[Current, Desired]):
21
+ current: Current
22
+ desired: Desired
23
+
24
+
25
+ @dataclass(frozen=True, eq=True)
26
+ class DiffResult(Generic[Current, Desired, Key]):
27
+ add: dict[Key, Desired]
28
+ delete: dict[Key, Current]
29
+ change: dict[Key, DiffPair[Current, Desired]]
30
+ identical: dict[Key, DiffPair[Current, Desired]]
31
+
32
+
33
+ def _default_equal(current: Current, desired: Desired) -> bool:
34
+ return current == desired
35
+
36
+
37
+ def _default_key(item: Any) -> Any:
38
+ return item
39
+
40
+
41
+ def diff_mappings(
42
+ current: Mapping[Key, Current],
43
+ desired: Mapping[Key, Desired],
44
+ equal: Callable[[Current, Desired], bool] = _default_equal,
45
+ ) -> DiffResult[Current, Desired, Key]:
46
+ """
47
+ Compare two mappings and return a `DiffResult` instance containing the differences between them.
48
+
49
+ :param current: The current mapping to compare.
50
+ :type current: Mapping[Key, Current]
51
+ :param desired: The desired mapping to compare.
52
+ :type desired: Mapping[Key, Desired]
53
+ :param equal: A function that compares two elements in the mappings and returns True if they are equal.
54
+ The default behavior is to use the `==` operator.
55
+ :type equal: Callable[[Current, Desired], bool]
56
+ :return: A `DiffResult` instance containing the differences between the `current` and `desired` mappings,
57
+ including elements that were added, deleted, changed or identical.
58
+ :rtype: DiffResult[Current, Desired, Key]
59
+ :raises: None
60
+
61
+ Example:
62
+ >>> current = {"i": 1, "c": 2, "d": 3}
63
+ >>> desired = {"i": 1, "c": 20, "a": 30}
64
+ >>> result = diff_mappings(current, desired, equal=lambda c, d: c == d)
65
+ DiffResult(
66
+ add={'a': 30},
67
+ delete={'d': 3},
68
+ change={'c': DiffPair(current=2, desired=20),
69
+ identical={'i': DiffPair(current=1, desired=1)},
70
+ )
71
+ """
72
+ add = {k: desired[k] for k in desired.keys() - current.keys()}
73
+ delete = {k: current[k] for k in current.keys() - desired.keys()}
74
+ change, identical = {}, {}
75
+ for k in current.keys() & desired.keys():
76
+ diff_pair = DiffPair(current=current[k], desired=desired[k])
77
+ if equal(diff_pair.current, diff_pair.desired):
78
+ identical[k] = diff_pair
79
+ else:
80
+ change[k] = diff_pair
81
+ return DiffResult(
82
+ add=add,
83
+ delete=delete,
84
+ change=change,
85
+ identical=identical,
86
+ )
87
+
88
+
89
+ def diff_any_iterables(
90
+ current: Iterable[Current],
91
+ desired: Iterable[Desired],
92
+ current_key: Callable[[Current], Key] = _default_key,
93
+ desired_key: Callable[[Desired], Key] = _default_key,
94
+ equal: Callable[[Current, Desired], bool] = _default_equal,
95
+ ) -> DiffResult[Current, Desired, Key]:
96
+ """
97
+ Compare two iterables and return a `DiffResult` instance containing the differences between them.
98
+
99
+ :param current: The current iterable to compare.
100
+ :type current: Iterable[Current]
101
+ :param desired: The desired iterable to compare.
102
+ :type desired: Iterable[Desired]
103
+ :param current_key: A function that returns the key for an element in the `current` iterable.
104
+ If not provided, the default behavior is to use the element itself as the key.
105
+ :type current_key: Callable[[Current], Key]
106
+ :param desired_key: A function that returns the key for an element in the `desired` iterable.
107
+ If not provided, the default behavior is to use the element itself as the key.
108
+ :type desired_key: Callable[[Desired], Key]
109
+ :param equal: A function that compares two elements in the iterables and returns True if they are equal.
110
+ If not provided, the default behavior is to use the `==` operator.
111
+ :type equal: Callable[[Current, Desired], bool]
112
+ :return: A `DiffResult` instance containing the differences between the `current` and `desired` iterables,
113
+ including elements that were added, deleted, changed or identical.
114
+ :rtype: DiffResult[Current, Desired, Key]
115
+ :raises: None
116
+
117
+ Example:
118
+ >>> current = [
119
+ ... {"name": "i", "value": 1},
120
+ ... {"name": "c", "value": 2},
121
+ ... {"name": "d", "value": 3},
122
+ ... ]
123
+ >>> desired = [
124
+ ... {"name": "i", "value": 1},
125
+ ... {"name": "c", "value": 20},
126
+ ... {"name": "a", "value": 30},
127
+ ... ]
128
+ >>> result = diff_any_iterables(
129
+ ... current,
130
+ ... desired,
131
+ ... lambda c: c["name"],
132
+ ... lambda d: d["name"],
133
+ ... equal=lambda c, d: c["value"] == d["value"],
134
+ ... )
135
+ DiffResult(
136
+ add={'a': {'name': 'a', 'value': 30}},
137
+ delete={'d': {'name': 'd', 'value': 3}},
138
+ change={'c': DiffPair(current={'name': 'c', 'value': 2}, desired={'name': 'c', 'value': 20})),
139
+ identical={'i': DiffPair(current={'name': 'i', 'value': 1}, desired={'name': 'i', 'value': 1})},
140
+ )
141
+ """
142
+ current_dict = {current_key(c): c for c in current}
143
+ desired_dict = {desired_key(d): d for d in desired}
144
+ return diff_mappings(
145
+ current_dict,
146
+ desired_dict,
147
+ equal=equal,
148
+ )
149
+
150
+
151
+ def diff_iterables(
152
+ current: Iterable[T],
153
+ desired: Iterable[T],
154
+ key: Callable[[T], Key] = _default_key,
155
+ equal: Callable[[T, T], bool] = _default_equal,
156
+ ) -> DiffResult[T, T, Key]:
157
+ """
158
+ Compare two iterables with same type and return a `DiffResult` instance containing the differences between them.
159
+
160
+ :param current: The current iterable to compare.
161
+ :type current: Iterable[T]
162
+ :param desired: The desired iterable to compare.
163
+ :type desired: Iterable[T]
164
+ :param key: A function that returns the key for an element in the `current` and `desired` iterable.
165
+ If not provided, the default behavior is to use the element itself as the key.
166
+ :type key: Callable[[Current], Key]
167
+ :param equal: A function that compares two elements in the iterables and returns True if they are equal.
168
+ If not provided, the default behavior is to use the `==` operator.
169
+ :type equal: Callable[[Current, Desired], bool]
170
+ :return: A `DiffResult` instance containing the differences between the `current` and `desired` iterables,
171
+ including elements that were added, deleted, changed or identical.
172
+ :rtype: DiffResult[T, T, Key]
173
+ :raises: None
174
+
175
+ Example:
176
+ >>> current = [
177
+ ... {"name": "i", "value": 1},
178
+ ... {"name": "c", "value": 2},
179
+ ... {"name": "d", "value": 3},
180
+ ... ]
181
+ >>> desired = [
182
+ ... {"name": "i", "value": 1},
183
+ ... {"name": "c", "value": 20},
184
+ ... {"name": "a", "value": 30},
185
+ ... ]
186
+ >>> result = diff_iterables(
187
+ ... current,
188
+ ... desired,
189
+ ... lambda x: x["name"],
190
+ ... equal=lambda c, d: c["value"] == d["value"],
191
+ ... )
192
+ DiffResult(
193
+ add={'a': {'name': 'a', 'value': 30}},
194
+ delete={'d': {'name': 'd', 'value': 3}},
195
+ change={'c': DiffPair(current={'name': 'c', 'value': 2}, desired={'name': 'c', 'value': 20})),
196
+ identical={'i': DiffPair(current={'name': 'i', 'value': 1}, desired={'name': 'i', 'value': 1})},
197
+ )
198
+ """
199
+ return diff_any_iterables(
200
+ current,
201
+ desired,
202
+ current_key=key,
203
+ desired_key=key,
204
+ equal=equal,
205
+ )