qontract-reconcile 0.9.1rc298__py3-none-any.whl → 0.10.1.dev1203__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (843) hide show
  1. qontract_reconcile-0.10.1.dev1203.dist-info/METADATA +500 -0
  2. qontract_reconcile-0.10.1.dev1203.dist-info/RECORD +771 -0
  3. {qontract_reconcile-0.9.1rc298.dist-info → qontract_reconcile-0.10.1.dev1203.dist-info}/WHEEL +1 -2
  4. {qontract_reconcile-0.9.1rc298.dist-info → qontract_reconcile-0.10.1.dev1203.dist-info}/entry_points.txt +4 -2
  5. reconcile/acs_notifiers.py +126 -0
  6. reconcile/acs_policies.py +243 -0
  7. reconcile/acs_rbac.py +596 -0
  8. reconcile/aus/advanced_upgrade_service.py +621 -8
  9. reconcile/aus/aus_label_source.py +115 -0
  10. reconcile/aus/base.py +1053 -353
  11. reconcile/{utils → aus}/cluster_version_data.py +27 -12
  12. reconcile/aus/healthchecks.py +77 -0
  13. reconcile/aus/metrics.py +158 -0
  14. reconcile/aus/models.py +245 -5
  15. reconcile/aus/node_pool_spec.py +35 -0
  16. reconcile/aus/ocm_addons_upgrade_scheduler_org.py +225 -110
  17. reconcile/aus/ocm_upgrade_scheduler.py +76 -71
  18. reconcile/aus/ocm_upgrade_scheduler_org.py +81 -23
  19. reconcile/aus/version_gate_approver.py +204 -0
  20. reconcile/aus/version_gates/__init__.py +12 -0
  21. reconcile/aus/version_gates/handler.py +33 -0
  22. reconcile/aus/version_gates/ingress_gate_handler.py +32 -0
  23. reconcile/aus/version_gates/ocp_gate_handler.py +26 -0
  24. reconcile/aus/version_gates/sts_version_gate_handler.py +100 -0
  25. reconcile/aws_account_manager/README.md +5 -0
  26. reconcile/aws_account_manager/integration.py +373 -0
  27. reconcile/aws_account_manager/merge_request_manager.py +114 -0
  28. reconcile/aws_account_manager/metrics.py +39 -0
  29. reconcile/aws_account_manager/reconciler.py +403 -0
  30. reconcile/aws_account_manager/utils.py +41 -0
  31. reconcile/aws_ami_cleanup/integration.py +273 -0
  32. reconcile/aws_ami_share.py +18 -14
  33. reconcile/aws_cloudwatch_log_retention/integration.py +253 -0
  34. reconcile/aws_iam_keys.py +1 -1
  35. reconcile/aws_iam_password_reset.py +56 -20
  36. reconcile/aws_saml_idp/integration.py +204 -0
  37. reconcile/aws_saml_roles/integration.py +322 -0
  38. reconcile/aws_support_cases_sos.py +2 -2
  39. reconcile/aws_version_sync/integration.py +430 -0
  40. reconcile/aws_version_sync/merge_request_manager/merge_request.py +156 -0
  41. reconcile/aws_version_sync/merge_request_manager/merge_request_manager.py +160 -0
  42. reconcile/aws_version_sync/utils.py +64 -0
  43. reconcile/blackbox_exporter_endpoint_monitoring.py +2 -5
  44. reconcile/change_owners/README.md +34 -0
  45. reconcile/change_owners/approver.py +7 -9
  46. reconcile/change_owners/bundle.py +134 -9
  47. reconcile/change_owners/change_log_tracking.py +236 -0
  48. reconcile/change_owners/change_owners.py +204 -194
  49. reconcile/change_owners/change_types.py +183 -265
  50. reconcile/change_owners/changes.py +488 -0
  51. reconcile/change_owners/decision.py +120 -41
  52. reconcile/change_owners/diff.py +63 -92
  53. reconcile/change_owners/implicit_ownership.py +19 -16
  54. reconcile/change_owners/self_service_roles.py +158 -35
  55. reconcile/change_owners/tester.py +20 -18
  56. reconcile/checkpoint.py +4 -6
  57. reconcile/cli.py +1523 -242
  58. reconcile/closedbox_endpoint_monitoring_base.py +10 -17
  59. reconcile/cluster_auth_rhidp/integration.py +257 -0
  60. reconcile/cluster_deployment_mapper.py +2 -5
  61. reconcile/cna/assets/asset.py +4 -7
  62. reconcile/cna/assets/null.py +2 -5
  63. reconcile/cna/integration.py +2 -3
  64. reconcile/cna/state.py +6 -9
  65. reconcile/dashdotdb_base.py +31 -10
  66. reconcile/dashdotdb_cso.py +3 -6
  67. reconcile/dashdotdb_dora.py +530 -0
  68. reconcile/dashdotdb_dvo.py +10 -13
  69. reconcile/dashdotdb_slo.py +75 -19
  70. reconcile/database_access_manager.py +753 -0
  71. reconcile/deadmanssnitch.py +207 -0
  72. reconcile/dynatrace_token_provider/dependencies.py +69 -0
  73. reconcile/dynatrace_token_provider/integration.py +656 -0
  74. reconcile/dynatrace_token_provider/metrics.py +62 -0
  75. reconcile/dynatrace_token_provider/model.py +14 -0
  76. reconcile/dynatrace_token_provider/ocm.py +140 -0
  77. reconcile/dynatrace_token_provider/validate.py +48 -0
  78. reconcile/endpoints_discovery/integration.py +348 -0
  79. reconcile/endpoints_discovery/merge_request.py +96 -0
  80. reconcile/endpoints_discovery/merge_request_manager.py +178 -0
  81. reconcile/external_resources/aws.py +204 -0
  82. reconcile/external_resources/factories.py +163 -0
  83. reconcile/external_resources/integration.py +194 -0
  84. reconcile/external_resources/integration_secrets_sync.py +47 -0
  85. reconcile/external_resources/manager.py +405 -0
  86. reconcile/external_resources/meta.py +17 -0
  87. reconcile/external_resources/metrics.py +95 -0
  88. reconcile/external_resources/model.py +350 -0
  89. reconcile/external_resources/reconciler.py +265 -0
  90. reconcile/external_resources/secrets_sync.py +465 -0
  91. reconcile/external_resources/state.py +258 -0
  92. reconcile/gabi_authorized_users.py +19 -11
  93. reconcile/gcr_mirror.py +43 -34
  94. reconcile/github_org.py +4 -6
  95. reconcile/github_owners.py +1 -1
  96. reconcile/github_repo_invites.py +2 -5
  97. reconcile/gitlab_fork_compliance.py +14 -13
  98. reconcile/gitlab_housekeeping.py +185 -91
  99. reconcile/gitlab_labeler.py +15 -14
  100. reconcile/gitlab_members.py +126 -120
  101. reconcile/gitlab_owners.py +53 -66
  102. reconcile/gitlab_permissions.py +167 -6
  103. reconcile/glitchtip/README.md +150 -0
  104. reconcile/glitchtip/integration.py +99 -51
  105. reconcile/glitchtip/reconciler.py +99 -70
  106. reconcile/glitchtip_project_alerts/__init__.py +0 -0
  107. reconcile/glitchtip_project_alerts/integration.py +333 -0
  108. reconcile/glitchtip_project_dsn/integration.py +43 -43
  109. reconcile/gql_definitions/acs/__init__.py +0 -0
  110. reconcile/gql_definitions/acs/acs_instances.py +83 -0
  111. reconcile/gql_definitions/acs/acs_policies.py +239 -0
  112. reconcile/gql_definitions/acs/acs_rbac.py +111 -0
  113. reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +46 -8
  114. reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +38 -8
  115. reconcile/gql_definitions/app_interface_metrics_exporter/__init__.py +0 -0
  116. reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +61 -0
  117. reconcile/gql_definitions/aws_account_manager/__init__.py +0 -0
  118. reconcile/gql_definitions/aws_account_manager/aws_accounts.py +177 -0
  119. reconcile/gql_definitions/aws_ami_cleanup/__init__.py +0 -0
  120. reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +161 -0
  121. reconcile/gql_definitions/aws_saml_idp/__init__.py +0 -0
  122. reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +117 -0
  123. reconcile/gql_definitions/aws_saml_roles/__init__.py +0 -0
  124. reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +117 -0
  125. reconcile/gql_definitions/aws_saml_roles/roles.py +97 -0
  126. reconcile/gql_definitions/aws_version_sync/__init__.py +0 -0
  127. reconcile/gql_definitions/aws_version_sync/clusters.py +83 -0
  128. reconcile/gql_definitions/aws_version_sync/namespaces.py +143 -0
  129. reconcile/gql_definitions/change_owners/queries/change_types.py +16 -29
  130. reconcile/gql_definitions/change_owners/queries/self_service_roles.py +45 -11
  131. reconcile/gql_definitions/cluster_auth_rhidp/__init__.py +0 -0
  132. reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +128 -0
  133. reconcile/gql_definitions/cna/queries/cna_provisioners.py +6 -8
  134. reconcile/gql_definitions/cna/queries/cna_resources.py +3 -5
  135. reconcile/gql_definitions/common/alerting_services_settings.py +2 -2
  136. reconcile/gql_definitions/common/app_code_component_repos.py +9 -5
  137. reconcile/gql_definitions/{glitchtip/glitchtip_settings.py → common/app_interface_custom_messages.py} +14 -16
  138. reconcile/gql_definitions/common/app_interface_dms_settings.py +86 -0
  139. reconcile/gql_definitions/common/app_interface_repo_settings.py +2 -2
  140. reconcile/gql_definitions/common/app_interface_state_settings.py +3 -5
  141. reconcile/gql_definitions/common/app_interface_vault_settings.py +3 -5
  142. reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +120 -0
  143. reconcile/gql_definitions/common/apps.py +72 -0
  144. reconcile/gql_definitions/common/aws_vpc_requests.py +109 -0
  145. reconcile/gql_definitions/common/aws_vpcs.py +84 -0
  146. reconcile/gql_definitions/common/clusters.py +120 -254
  147. reconcile/gql_definitions/common/clusters_minimal.py +11 -35
  148. reconcile/gql_definitions/common/clusters_with_dms.py +72 -0
  149. reconcile/gql_definitions/common/clusters_with_peering.py +70 -98
  150. reconcile/gql_definitions/common/github_orgs.py +2 -2
  151. reconcile/gql_definitions/common/jira_settings.py +68 -0
  152. reconcile/gql_definitions/common/jiralert_settings.py +68 -0
  153. reconcile/gql_definitions/common/namespaces.py +74 -32
  154. reconcile/gql_definitions/common/namespaces_minimal.py +4 -10
  155. reconcile/gql_definitions/common/ocm_env_telemeter.py +95 -0
  156. reconcile/gql_definitions/common/ocm_environments.py +4 -2
  157. reconcile/gql_definitions/common/pagerduty_instances.py +5 -5
  158. reconcile/gql_definitions/common/pgp_reencryption_settings.py +5 -11
  159. reconcile/gql_definitions/common/pipeline_providers.py +45 -90
  160. reconcile/gql_definitions/common/quay_instances.py +64 -0
  161. reconcile/gql_definitions/common/quay_orgs.py +68 -0
  162. reconcile/gql_definitions/common/reserved_networks.py +94 -0
  163. reconcile/gql_definitions/common/saas_files.py +133 -95
  164. reconcile/gql_definitions/common/saas_target_namespaces.py +41 -26
  165. reconcile/gql_definitions/common/saasherder_settings.py +2 -2
  166. reconcile/gql_definitions/common/slack_workspaces.py +62 -0
  167. reconcile/gql_definitions/common/smtp_client_settings.py +2 -2
  168. reconcile/gql_definitions/common/state_aws_account.py +77 -0
  169. reconcile/gql_definitions/common/users.py +3 -2
  170. reconcile/gql_definitions/cost_report/__init__.py +0 -0
  171. reconcile/gql_definitions/cost_report/app_names.py +68 -0
  172. reconcile/gql_definitions/cost_report/cost_namespaces.py +86 -0
  173. reconcile/gql_definitions/cost_report/settings.py +77 -0
  174. reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +42 -12
  175. reconcile/gql_definitions/dynatrace_token_provider/__init__.py +0 -0
  176. reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +79 -0
  177. reconcile/gql_definitions/dynatrace_token_provider/token_specs.py +84 -0
  178. reconcile/gql_definitions/endpoints_discovery/__init__.py +0 -0
  179. reconcile/gql_definitions/endpoints_discovery/namespaces.py +127 -0
  180. reconcile/gql_definitions/external_resources/__init__.py +0 -0
  181. reconcile/gql_definitions/external_resources/aws_accounts.py +73 -0
  182. reconcile/gql_definitions/external_resources/external_resources_modules.py +78 -0
  183. reconcile/gql_definitions/external_resources/external_resources_namespaces.py +1111 -0
  184. reconcile/gql_definitions/external_resources/external_resources_settings.py +98 -0
  185. reconcile/gql_definitions/fragments/aus_organization.py +34 -39
  186. reconcile/gql_definitions/fragments/aws_account_common.py +62 -0
  187. reconcile/gql_definitions/fragments/aws_account_managed.py +57 -0
  188. reconcile/gql_definitions/fragments/aws_account_sso.py +35 -0
  189. reconcile/gql_definitions/fragments/aws_infra_management_account.py +2 -2
  190. reconcile/gql_definitions/fragments/aws_vpc.py +47 -0
  191. reconcile/gql_definitions/fragments/aws_vpc_request.py +65 -0
  192. reconcile/gql_definitions/fragments/aws_vpc_request_subnet.py +29 -0
  193. reconcile/gql_definitions/fragments/deplopy_resources.py +7 -7
  194. reconcile/gql_definitions/fragments/disable.py +28 -0
  195. reconcile/gql_definitions/fragments/jumphost_common_fields.py +2 -2
  196. reconcile/gql_definitions/fragments/membership_source.py +47 -0
  197. reconcile/gql_definitions/fragments/minimal_ocm_organization.py +29 -0
  198. reconcile/gql_definitions/fragments/oc_connection_cluster.py +4 -9
  199. reconcile/gql_definitions/fragments/ocm_environment.py +5 -5
  200. reconcile/gql_definitions/fragments/pipeline_provider_retention.py +30 -0
  201. reconcile/gql_definitions/fragments/prometheus_instance.py +48 -0
  202. reconcile/gql_definitions/fragments/resource_limits_requirements.py +29 -0
  203. reconcile/gql_definitions/fragments/{resource_requirements.py → resource_requests_requirements.py} +3 -3
  204. reconcile/gql_definitions/fragments/resource_values.py +2 -2
  205. reconcile/gql_definitions/fragments/saas_target_namespace.py +55 -12
  206. reconcile/gql_definitions/fragments/serviceaccount_token.py +38 -0
  207. reconcile/gql_definitions/fragments/terraform_state.py +36 -0
  208. reconcile/gql_definitions/fragments/upgrade_policy.py +5 -3
  209. reconcile/gql_definitions/fragments/user.py +3 -2
  210. reconcile/gql_definitions/fragments/vault_secret.py +2 -2
  211. reconcile/gql_definitions/gitlab_members/gitlab_instances.py +6 -2
  212. reconcile/gql_definitions/gitlab_members/permissions.py +3 -5
  213. reconcile/gql_definitions/glitchtip/glitchtip_instance.py +16 -2
  214. reconcile/gql_definitions/glitchtip/glitchtip_project.py +22 -23
  215. reconcile/gql_definitions/glitchtip_project_alerts/__init__.py +0 -0
  216. reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +173 -0
  217. reconcile/gql_definitions/integrations/integrations.py +62 -45
  218. reconcile/gql_definitions/introspection.json +51176 -0
  219. reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +13 -5
  220. reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +79 -0
  221. reconcile/gql_definitions/jira/__init__.py +0 -0
  222. reconcile/gql_definitions/jira/jira_servers.py +80 -0
  223. reconcile/gql_definitions/jira_permissions_validator/__init__.py +0 -0
  224. reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +131 -0
  225. reconcile/gql_definitions/jumphosts/jumphosts.py +3 -5
  226. reconcile/gql_definitions/ldap_groups/__init__.py +0 -0
  227. reconcile/gql_definitions/ldap_groups/roles.py +111 -0
  228. reconcile/gql_definitions/ldap_groups/settings.py +79 -0
  229. reconcile/gql_definitions/maintenance/__init__.py +0 -0
  230. reconcile/gql_definitions/maintenance/maintenances.py +101 -0
  231. reconcile/gql_definitions/membershipsources/__init__.py +0 -0
  232. reconcile/gql_definitions/membershipsources/roles.py +112 -0
  233. reconcile/gql_definitions/ocm_labels/__init__.py +0 -0
  234. reconcile/gql_definitions/ocm_labels/clusters.py +112 -0
  235. reconcile/gql_definitions/ocm_labels/organizations.py +78 -0
  236. reconcile/gql_definitions/ocm_subscription_labels/__init__.py +0 -0
  237. reconcile/gql_definitions/openshift_cluster_bots/__init__.py +0 -0
  238. reconcile/gql_definitions/openshift_cluster_bots/clusters.py +126 -0
  239. reconcile/gql_definitions/openshift_groups/managed_groups.py +2 -2
  240. reconcile/gql_definitions/openshift_groups/managed_roles.py +3 -2
  241. reconcile/gql_definitions/openshift_serviceaccount_tokens/__init__.py +0 -0
  242. reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +132 -0
  243. reconcile/gql_definitions/quay_membership/quay_membership.py +3 -5
  244. reconcile/gql_definitions/rhidp/__init__.py +0 -0
  245. reconcile/gql_definitions/rhidp/organizations.py +96 -0
  246. reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +2 -2
  247. reconcile/gql_definitions/service_dependencies/service_dependencies.py +9 -31
  248. reconcile/gql_definitions/sharding/aws_accounts.py +2 -2
  249. reconcile/gql_definitions/sharding/ocm_organization.py +63 -0
  250. reconcile/gql_definitions/skupper_network/site_controller_template.py +2 -2
  251. reconcile/gql_definitions/skupper_network/skupper_networks.py +12 -38
  252. reconcile/gql_definitions/slack_usergroups/clusters.py +2 -2
  253. reconcile/gql_definitions/slack_usergroups/permissions.py +8 -15
  254. reconcile/gql_definitions/slack_usergroups/users.py +3 -2
  255. reconcile/gql_definitions/slo_documents/__init__.py +0 -0
  256. reconcile/gql_definitions/slo_documents/slo_documents.py +142 -0
  257. reconcile/gql_definitions/status_board/__init__.py +0 -0
  258. reconcile/gql_definitions/status_board/status_board.py +163 -0
  259. reconcile/gql_definitions/statuspage/statuspages.py +56 -7
  260. reconcile/gql_definitions/templating/__init__.py +0 -0
  261. reconcile/gql_definitions/templating/template_collection.py +130 -0
  262. reconcile/gql_definitions/templating/templates.py +108 -0
  263. reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +4 -8
  264. reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +8 -8
  265. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +6 -8
  266. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +45 -56
  267. reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +4 -8
  268. reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +4 -8
  269. reconcile/gql_definitions/terraform_init/__init__.py +0 -0
  270. reconcile/gql_definitions/terraform_init/aws_accounts.py +93 -0
  271. reconcile/gql_definitions/terraform_repo/__init__.py +0 -0
  272. reconcile/gql_definitions/terraform_repo/terraform_repo.py +141 -0
  273. reconcile/gql_definitions/terraform_resources/database_access_manager.py +158 -0
  274. reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +153 -162
  275. reconcile/gql_definitions/terraform_tgw_attachments/__init__.py +0 -0
  276. reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +119 -0
  277. reconcile/gql_definitions/unleash_feature_toggles/__init__.py +0 -0
  278. reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +113 -0
  279. reconcile/gql_definitions/vault_instances/vault_instances.py +17 -50
  280. reconcile/gql_definitions/vault_policies/vault_policies.py +2 -2
  281. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +49 -12
  282. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +7 -2
  283. reconcile/integrations_manager.py +25 -13
  284. reconcile/jenkins/types.py +5 -1
  285. reconcile/jenkins_base.py +36 -0
  286. reconcile/jenkins_job_builder.py +10 -48
  287. reconcile/jenkins_job_builds_cleaner.py +40 -25
  288. reconcile/jenkins_job_cleaner.py +1 -3
  289. reconcile/jenkins_roles.py +22 -26
  290. reconcile/jenkins_webhooks.py +9 -6
  291. reconcile/jenkins_worker_fleets.py +11 -6
  292. reconcile/jira_permissions_validator.py +340 -0
  293. reconcile/jira_watcher.py +3 -5
  294. reconcile/ldap_groups/__init__.py +0 -0
  295. reconcile/ldap_groups/integration.py +279 -0
  296. reconcile/ldap_users.py +3 -0
  297. reconcile/ocm/types.py +39 -59
  298. reconcile/ocm_additional_routers.py +0 -1
  299. reconcile/ocm_addons_upgrade_tests_trigger.py +10 -15
  300. reconcile/ocm_aws_infrastructure_access.py +30 -32
  301. reconcile/ocm_clusters.py +217 -130
  302. reconcile/ocm_external_configuration_labels.py +15 -0
  303. reconcile/ocm_github_idp.py +1 -1
  304. reconcile/ocm_groups.py +25 -5
  305. reconcile/ocm_internal_notifications/__init__.py +0 -0
  306. reconcile/ocm_internal_notifications/integration.py +119 -0
  307. reconcile/ocm_labels/__init__.py +0 -0
  308. reconcile/ocm_labels/integration.py +409 -0
  309. reconcile/ocm_machine_pools.py +517 -108
  310. reconcile/ocm_upgrade_scheduler_org_updater.py +15 -11
  311. reconcile/openshift_base.py +609 -207
  312. reconcile/openshift_cluster_bots.py +344 -0
  313. reconcile/openshift_clusterrolebindings.py +15 -15
  314. reconcile/openshift_groups.py +42 -45
  315. reconcile/openshift_limitranges.py +1 -0
  316. reconcile/openshift_namespace_labels.py +22 -28
  317. reconcile/openshift_namespaces.py +22 -22
  318. reconcile/openshift_network_policies.py +4 -8
  319. reconcile/openshift_prometheus_rules.py +43 -0
  320. reconcile/openshift_resourcequotas.py +2 -16
  321. reconcile/openshift_resources.py +12 -10
  322. reconcile/openshift_resources_base.py +304 -328
  323. reconcile/openshift_rolebindings.py +18 -20
  324. reconcile/openshift_saas_deploy.py +105 -21
  325. reconcile/openshift_saas_deploy_change_tester.py +30 -35
  326. reconcile/openshift_saas_deploy_trigger_base.py +39 -36
  327. reconcile/openshift_saas_deploy_trigger_cleaner.py +41 -27
  328. reconcile/openshift_saas_deploy_trigger_configs.py +1 -2
  329. reconcile/openshift_saas_deploy_trigger_images.py +1 -2
  330. reconcile/openshift_saas_deploy_trigger_moving_commits.py +1 -2
  331. reconcile/openshift_saas_deploy_trigger_upstream_jobs.py +1 -2
  332. reconcile/openshift_serviceaccount_tokens.py +138 -74
  333. reconcile/openshift_tekton_resources.py +89 -24
  334. reconcile/openshift_upgrade_watcher.py +110 -62
  335. reconcile/openshift_users.py +16 -15
  336. reconcile/openshift_vault_secrets.py +11 -6
  337. reconcile/oum/__init__.py +0 -0
  338. reconcile/oum/base.py +387 -0
  339. reconcile/oum/labelset.py +55 -0
  340. reconcile/oum/metrics.py +71 -0
  341. reconcile/oum/models.py +69 -0
  342. reconcile/oum/providers.py +59 -0
  343. reconcile/oum/standalone.py +196 -0
  344. reconcile/prometheus_rules_tester/integration.py +31 -23
  345. reconcile/quay_base.py +4 -1
  346. reconcile/quay_membership.py +1 -2
  347. reconcile/quay_mirror.py +111 -61
  348. reconcile/quay_mirror_org.py +34 -21
  349. reconcile/quay_permissions.py +7 -3
  350. reconcile/quay_repos.py +24 -32
  351. reconcile/queries.py +263 -198
  352. reconcile/query_validator.py +3 -5
  353. reconcile/resource_scraper.py +3 -4
  354. reconcile/{template_tester.py → resource_template_tester.py} +3 -3
  355. reconcile/rhidp/__init__.py +0 -0
  356. reconcile/rhidp/common.py +214 -0
  357. reconcile/rhidp/metrics.py +20 -0
  358. reconcile/rhidp/ocm_oidc_idp/__init__.py +0 -0
  359. reconcile/rhidp/ocm_oidc_idp/base.py +221 -0
  360. reconcile/rhidp/ocm_oidc_idp/integration.py +56 -0
  361. reconcile/rhidp/ocm_oidc_idp/metrics.py +22 -0
  362. reconcile/rhidp/sso_client/__init__.py +0 -0
  363. reconcile/rhidp/sso_client/base.py +266 -0
  364. reconcile/rhidp/sso_client/integration.py +60 -0
  365. reconcile/rhidp/sso_client/metrics.py +39 -0
  366. reconcile/run_integration.py +293 -0
  367. reconcile/saas_auto_promotions_manager/integration.py +69 -24
  368. reconcile/saas_auto_promotions_manager/merge_request_manager/batcher.py +208 -0
  369. reconcile/saas_auto_promotions_manager/merge_request_manager/desired_state.py +28 -0
  370. reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request.py +3 -4
  371. reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager_v2.py +172 -0
  372. reconcile/saas_auto_promotions_manager/merge_request_manager/metrics.py +42 -0
  373. reconcile/saas_auto_promotions_manager/merge_request_manager/mr_parser.py +226 -0
  374. reconcile/saas_auto_promotions_manager/merge_request_manager/open_merge_requests.py +23 -0
  375. reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +108 -32
  376. reconcile/saas_auto_promotions_manager/meta.py +4 -0
  377. reconcile/saas_auto_promotions_manager/publisher.py +32 -4
  378. reconcile/saas_auto_promotions_manager/s3_exporter.py +77 -0
  379. reconcile/saas_auto_promotions_manager/subscriber.py +110 -23
  380. reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py +48 -41
  381. reconcile/saas_file_validator.py +16 -6
  382. reconcile/sendgrid_teammates.py +27 -12
  383. reconcile/service_dependencies.py +0 -3
  384. reconcile/signalfx_endpoint_monitoring.py +2 -5
  385. reconcile/skupper_network/integration.py +10 -11
  386. reconcile/skupper_network/models.py +3 -5
  387. reconcile/skupper_network/reconciler.py +28 -35
  388. reconcile/skupper_network/site_controller.py +8 -8
  389. reconcile/slack_base.py +4 -7
  390. reconcile/slack_usergroups.py +249 -171
  391. reconcile/sql_query.py +324 -171
  392. reconcile/status.py +0 -1
  393. reconcile/status_board.py +275 -0
  394. reconcile/statuspage/__init__.py +0 -5
  395. reconcile/statuspage/atlassian.py +219 -80
  396. reconcile/statuspage/integration.py +9 -97
  397. reconcile/statuspage/integrations/__init__.py +0 -0
  398. reconcile/statuspage/integrations/components.py +77 -0
  399. reconcile/statuspage/integrations/maintenances.py +111 -0
  400. reconcile/statuspage/page.py +107 -72
  401. reconcile/statuspage/state.py +6 -11
  402. reconcile/statuspage/status.py +8 -12
  403. reconcile/templates/rosa-classic-cluster-creation.sh.j2 +60 -0
  404. reconcile/templates/rosa-hcp-cluster-creation.sh.j2 +61 -0
  405. reconcile/templating/__init__.py +0 -0
  406. reconcile/templating/lib/__init__.py +0 -0
  407. reconcile/templating/lib/merge_request_manager.py +180 -0
  408. reconcile/templating/lib/model.py +20 -0
  409. reconcile/templating/lib/rendering.py +191 -0
  410. reconcile/templating/renderer.py +410 -0
  411. reconcile/templating/validator.py +153 -0
  412. reconcile/terraform_aws_route53.py +13 -10
  413. reconcile/terraform_cloudflare_dns.py +92 -122
  414. reconcile/terraform_cloudflare_resources.py +15 -13
  415. reconcile/terraform_cloudflare_users.py +27 -27
  416. reconcile/terraform_init/__init__.py +0 -0
  417. reconcile/terraform_init/integration.py +165 -0
  418. reconcile/terraform_init/merge_request.py +57 -0
  419. reconcile/terraform_init/merge_request_manager.py +102 -0
  420. reconcile/terraform_repo.py +403 -0
  421. reconcile/terraform_resources.py +266 -168
  422. reconcile/terraform_tgw_attachments.py +417 -167
  423. reconcile/terraform_users.py +40 -17
  424. reconcile/terraform_vpc_peerings.py +310 -142
  425. reconcile/terraform_vpc_resources/__init__.py +0 -0
  426. reconcile/terraform_vpc_resources/integration.py +220 -0
  427. reconcile/terraform_vpc_resources/merge_request.py +57 -0
  428. reconcile/terraform_vpc_resources/merge_request_manager.py +107 -0
  429. reconcile/typed_queries/alerting_services_settings.py +1 -2
  430. reconcile/typed_queries/app_interface_custom_messages.py +24 -0
  431. reconcile/typed_queries/app_interface_deadmanssnitch_settings.py +17 -0
  432. reconcile/typed_queries/app_interface_metrics_exporter/__init__.py +0 -0
  433. reconcile/typed_queries/app_interface_metrics_exporter/onboarding_status.py +13 -0
  434. reconcile/typed_queries/app_interface_repo_url.py +1 -2
  435. reconcile/typed_queries/app_interface_state_settings.py +1 -3
  436. reconcile/typed_queries/app_interface_vault_settings.py +1 -2
  437. reconcile/typed_queries/app_quay_repos_escalation_policies.py +14 -0
  438. reconcile/typed_queries/apps.py +11 -0
  439. reconcile/typed_queries/aws_vpc_requests.py +9 -0
  440. reconcile/typed_queries/aws_vpcs.py +12 -0
  441. reconcile/typed_queries/cloudflare.py +10 -0
  442. reconcile/typed_queries/clusters.py +7 -5
  443. reconcile/typed_queries/clusters_minimal.py +6 -5
  444. reconcile/typed_queries/clusters_with_dms.py +16 -0
  445. reconcile/typed_queries/cost_report/__init__.py +0 -0
  446. reconcile/typed_queries/cost_report/app_names.py +22 -0
  447. reconcile/typed_queries/cost_report/cost_namespaces.py +43 -0
  448. reconcile/typed_queries/cost_report/settings.py +15 -0
  449. reconcile/typed_queries/dynatrace.py +10 -0
  450. reconcile/typed_queries/dynatrace_environments.py +14 -0
  451. reconcile/typed_queries/dynatrace_token_provider_token_specs.py +14 -0
  452. reconcile/typed_queries/external_resources.py +46 -0
  453. reconcile/typed_queries/get_state_aws_account.py +20 -0
  454. reconcile/typed_queries/glitchtip.py +10 -0
  455. reconcile/typed_queries/jenkins.py +25 -0
  456. reconcile/typed_queries/jira.py +7 -0
  457. reconcile/typed_queries/jira_settings.py +16 -0
  458. reconcile/typed_queries/jiralert_settings.py +22 -0
  459. reconcile/typed_queries/ocm.py +8 -0
  460. reconcile/typed_queries/pagerduty_instances.py +2 -7
  461. reconcile/typed_queries/quay.py +23 -0
  462. reconcile/typed_queries/repos.py +20 -8
  463. reconcile/typed_queries/reserved_networks.py +12 -0
  464. reconcile/typed_queries/saas_files.py +221 -167
  465. reconcile/typed_queries/slack.py +7 -0
  466. reconcile/typed_queries/slo_documents.py +12 -0
  467. reconcile/typed_queries/status_board.py +58 -0
  468. reconcile/typed_queries/tekton_pipeline_providers.py +1 -2
  469. reconcile/typed_queries/terraform_namespaces.py +1 -2
  470. reconcile/typed_queries/terraform_tgw_attachments/__init__.py +0 -0
  471. reconcile/typed_queries/terraform_tgw_attachments/aws_accounts.py +16 -0
  472. reconcile/typed_queries/unleash.py +10 -0
  473. reconcile/typed_queries/users.py +11 -0
  474. reconcile/typed_queries/vault.py +10 -0
  475. reconcile/unleash_feature_toggles/__init__.py +0 -0
  476. reconcile/unleash_feature_toggles/integration.py +287 -0
  477. reconcile/utils/acs/__init__.py +0 -0
  478. reconcile/utils/acs/base.py +81 -0
  479. reconcile/utils/acs/notifiers.py +143 -0
  480. reconcile/utils/acs/policies.py +163 -0
  481. reconcile/utils/acs/rbac.py +277 -0
  482. reconcile/utils/aggregated_list.py +11 -9
  483. reconcile/utils/amtool.py +6 -4
  484. reconcile/utils/aws_api.py +279 -66
  485. reconcile/utils/aws_api_typed/__init__.py +0 -0
  486. reconcile/utils/aws_api_typed/account.py +23 -0
  487. reconcile/utils/aws_api_typed/api.py +273 -0
  488. reconcile/utils/aws_api_typed/dynamodb.py +16 -0
  489. reconcile/utils/aws_api_typed/iam.py +67 -0
  490. reconcile/utils/aws_api_typed/organization.py +152 -0
  491. reconcile/utils/aws_api_typed/s3.py +26 -0
  492. reconcile/utils/aws_api_typed/service_quotas.py +79 -0
  493. reconcile/utils/aws_api_typed/sts.py +36 -0
  494. reconcile/utils/aws_api_typed/support.py +79 -0
  495. reconcile/utils/aws_helper.py +42 -3
  496. reconcile/utils/batches.py +11 -0
  497. reconcile/utils/binary.py +7 -9
  498. reconcile/utils/cloud_resource_best_practice/__init__.py +0 -0
  499. reconcile/utils/cloud_resource_best_practice/aws_rds.py +66 -0
  500. reconcile/utils/clusterhealth/__init__.py +0 -0
  501. reconcile/utils/clusterhealth/providerbase.py +39 -0
  502. reconcile/utils/clusterhealth/telemeter.py +39 -0
  503. reconcile/utils/config.py +3 -4
  504. reconcile/utils/deadmanssnitch_api.py +86 -0
  505. reconcile/utils/differ.py +205 -0
  506. reconcile/utils/disabled_integrations.py +4 -6
  507. reconcile/utils/dynatrace/__init__.py +0 -0
  508. reconcile/utils/dynatrace/client.py +93 -0
  509. reconcile/utils/early_exit_cache.py +289 -0
  510. reconcile/utils/elasticsearch_exceptions.py +5 -0
  511. reconcile/utils/environ.py +2 -2
  512. reconcile/utils/exceptions.py +4 -0
  513. reconcile/utils/expiration.py +4 -8
  514. reconcile/utils/extended_early_exit.py +210 -0
  515. reconcile/utils/external_resource_spec.py +34 -12
  516. reconcile/utils/external_resources.py +48 -20
  517. reconcile/utils/filtering.py +16 -0
  518. reconcile/utils/git.py +49 -16
  519. reconcile/utils/github_api.py +10 -9
  520. reconcile/utils/gitlab_api.py +333 -190
  521. reconcile/utils/glitchtip/client.py +97 -100
  522. reconcile/utils/glitchtip/models.py +89 -11
  523. reconcile/utils/gql.py +157 -58
  524. reconcile/utils/grouping.py +17 -0
  525. reconcile/utils/helm.py +89 -18
  526. reconcile/utils/helpers.py +51 -0
  527. reconcile/utils/imap_client.py +5 -6
  528. reconcile/utils/internal_groups/__init__.py +0 -0
  529. reconcile/utils/internal_groups/client.py +160 -0
  530. reconcile/utils/internal_groups/models.py +71 -0
  531. reconcile/utils/jenkins_api.py +10 -34
  532. reconcile/utils/jinja2/__init__.py +0 -0
  533. reconcile/utils/{jinja2_ext.py → jinja2/extensions.py} +6 -4
  534. reconcile/utils/jinja2/filters.py +142 -0
  535. reconcile/utils/jinja2/utils.py +278 -0
  536. reconcile/utils/jira_client.py +165 -8
  537. reconcile/utils/jjb_client.py +47 -35
  538. reconcile/utils/jobcontroller/__init__.py +0 -0
  539. reconcile/utils/jobcontroller/controller.py +413 -0
  540. reconcile/utils/jobcontroller/models.py +195 -0
  541. reconcile/utils/jsonpath.py +4 -5
  542. reconcile/utils/jump_host.py +13 -12
  543. reconcile/utils/keycloak.py +106 -0
  544. reconcile/utils/ldap_client.py +35 -6
  545. reconcile/utils/lean_terraform_client.py +115 -6
  546. reconcile/utils/membershipsources/__init__.py +0 -0
  547. reconcile/utils/membershipsources/app_interface_resolver.py +60 -0
  548. reconcile/utils/membershipsources/models.py +91 -0
  549. reconcile/utils/membershipsources/resolver.py +110 -0
  550. reconcile/utils/merge_request_manager/__init__.py +0 -0
  551. reconcile/utils/merge_request_manager/merge_request_manager.py +99 -0
  552. reconcile/utils/merge_request_manager/parser.py +67 -0
  553. reconcile/utils/metrics.py +511 -1
  554. reconcile/utils/models.py +123 -0
  555. reconcile/utils/mr/README.md +198 -0
  556. reconcile/utils/mr/__init__.py +14 -10
  557. reconcile/utils/mr/app_interface_reporter.py +2 -2
  558. reconcile/utils/mr/aws_access.py +4 -4
  559. reconcile/utils/mr/base.py +51 -31
  560. reconcile/utils/mr/clusters_updates.py +10 -7
  561. reconcile/utils/mr/glitchtip_access_reporter.py +2 -4
  562. reconcile/utils/mr/labels.py +14 -1
  563. reconcile/utils/mr/notificator.py +1 -3
  564. reconcile/utils/mr/ocm_update_recommended_version.py +1 -2
  565. reconcile/utils/mr/ocm_upgrade_scheduler_org_updates.py +7 -3
  566. reconcile/utils/mr/promote_qontract.py +203 -0
  567. reconcile/utils/mr/user_maintenance.py +24 -4
  568. reconcile/utils/oauth2_backend_application_session.py +132 -0
  569. reconcile/utils/oc.py +194 -170
  570. reconcile/utils/oc_connection_parameters.py +40 -51
  571. reconcile/utils/oc_filters.py +11 -13
  572. reconcile/utils/oc_map.py +14 -35
  573. reconcile/utils/ocm/__init__.py +30 -1
  574. reconcile/utils/ocm/addons.py +228 -0
  575. reconcile/utils/ocm/base.py +618 -5
  576. reconcile/utils/ocm/cluster_groups.py +5 -56
  577. reconcile/utils/ocm/clusters.py +111 -99
  578. reconcile/utils/ocm/identity_providers.py +66 -0
  579. reconcile/utils/ocm/label_sources.py +75 -0
  580. reconcile/utils/ocm/labels.py +139 -54
  581. reconcile/utils/ocm/manifests.py +39 -0
  582. reconcile/utils/ocm/ocm.py +182 -928
  583. reconcile/utils/ocm/products.py +758 -0
  584. reconcile/utils/ocm/search_filters.py +20 -28
  585. reconcile/utils/ocm/service_log.py +32 -79
  586. reconcile/utils/ocm/sre_capability_labels.py +51 -0
  587. reconcile/utils/ocm/status_board.py +66 -0
  588. reconcile/utils/ocm/subscriptions.py +49 -59
  589. reconcile/utils/ocm/syncsets.py +39 -0
  590. reconcile/utils/ocm/upgrades.py +181 -0
  591. reconcile/utils/ocm_base_client.py +71 -36
  592. reconcile/utils/openshift_resource.py +113 -67
  593. reconcile/utils/output.py +18 -11
  594. reconcile/utils/pagerduty_api.py +16 -10
  595. reconcile/utils/parse_dhms_duration.py +13 -1
  596. reconcile/utils/prometheus.py +123 -0
  597. reconcile/utils/promotion_state.py +56 -19
  598. reconcile/utils/promtool.py +5 -8
  599. reconcile/utils/quay_api.py +13 -25
  600. reconcile/utils/raw_github_api.py +3 -5
  601. reconcile/utils/repo_owners.py +2 -8
  602. reconcile/utils/rest_api_base.py +126 -0
  603. reconcile/utils/rosa/__init__.py +0 -0
  604. reconcile/utils/rosa/rosa_cli.py +310 -0
  605. reconcile/utils/rosa/session.py +201 -0
  606. reconcile/utils/ruamel.py +16 -0
  607. reconcile/utils/runtime/__init__.py +0 -1
  608. reconcile/utils/runtime/desired_state_diff.py +9 -20
  609. reconcile/utils/runtime/environment.py +33 -8
  610. reconcile/utils/runtime/integration.py +28 -12
  611. reconcile/utils/runtime/meta.py +1 -3
  612. reconcile/utils/runtime/runner.py +8 -11
  613. reconcile/utils/runtime/sharding.py +93 -36
  614. reconcile/utils/saasherder/__init__.py +1 -1
  615. reconcile/utils/saasherder/interfaces.py +143 -138
  616. reconcile/utils/saasherder/models.py +201 -43
  617. reconcile/utils/saasherder/saasherder.py +508 -378
  618. reconcile/utils/secret_reader.py +22 -27
  619. reconcile/utils/semver_helper.py +15 -1
  620. reconcile/utils/slack_api.py +124 -36
  621. reconcile/utils/smtp_client.py +1 -2
  622. reconcile/utils/sqs_gateway.py +10 -6
  623. reconcile/utils/state.py +276 -127
  624. reconcile/utils/terraform/config_client.py +6 -7
  625. reconcile/utils/terraform_client.py +284 -125
  626. reconcile/utils/terrascript/cloudflare_client.py +38 -17
  627. reconcile/utils/terrascript/cloudflare_resources.py +67 -18
  628. reconcile/utils/terrascript/models.py +2 -3
  629. reconcile/utils/terrascript/resources.py +1 -2
  630. reconcile/utils/terrascript_aws_client.py +1292 -540
  631. reconcile/utils/three_way_diff_strategy.py +157 -0
  632. reconcile/utils/unleash/__init__.py +11 -0
  633. reconcile/utils/{unleash.py → unleash/client.py} +35 -29
  634. reconcile/utils/unleash/server.py +145 -0
  635. reconcile/utils/vault.py +42 -32
  636. reconcile/utils/vaultsecretref.py +2 -4
  637. reconcile/utils/vcs.py +250 -0
  638. reconcile/vault_replication.py +38 -31
  639. reconcile/vpc_peerings_validator.py +82 -13
  640. tools/app_interface_metrics_exporter.py +70 -0
  641. tools/app_interface_reporter.py +44 -157
  642. tools/cli_commands/container_images_report.py +154 -0
  643. tools/cli_commands/cost_report/__init__.py +0 -0
  644. tools/cli_commands/cost_report/aws.py +137 -0
  645. tools/cli_commands/cost_report/cost_management_api.py +155 -0
  646. tools/cli_commands/cost_report/model.py +49 -0
  647. tools/cli_commands/cost_report/openshift.py +166 -0
  648. tools/cli_commands/cost_report/openshift_cost_optimization.py +187 -0
  649. tools/cli_commands/cost_report/response.py +124 -0
  650. tools/cli_commands/cost_report/util.py +72 -0
  651. tools/cli_commands/cost_report/view.py +524 -0
  652. tools/cli_commands/erv2.py +620 -0
  653. tools/cli_commands/gpg_encrypt.py +5 -8
  654. tools/cli_commands/systems_and_tools.py +489 -0
  655. tools/glitchtip_access_revalidation.py +1 -1
  656. tools/qontract_cli.py +2301 -673
  657. tools/saas_metrics_exporter/__init__.py +0 -0
  658. tools/saas_metrics_exporter/commit_distance/__init__.py +0 -0
  659. tools/saas_metrics_exporter/commit_distance/channel.py +63 -0
  660. tools/saas_metrics_exporter/commit_distance/commit_distance.py +103 -0
  661. tools/saas_metrics_exporter/commit_distance/metrics.py +19 -0
  662. tools/saas_metrics_exporter/main.py +99 -0
  663. tools/saas_promotion_state/__init__.py +0 -0
  664. tools/saas_promotion_state/saas_promotion_state.py +105 -0
  665. tools/sd_app_sre_alert_report.py +145 -0
  666. tools/template_validation.py +107 -0
  667. e2e_tests/cli.py +0 -83
  668. e2e_tests/create_namespace.py +0 -43
  669. e2e_tests/dedicated_admin_rolebindings.py +0 -44
  670. e2e_tests/dedicated_admin_test_base.py +0 -39
  671. e2e_tests/default_network_policies.py +0 -47
  672. e2e_tests/default_project_labels.py +0 -52
  673. e2e_tests/network_policy_test_base.py +0 -17
  674. e2e_tests/test_base.py +0 -56
  675. qontract_reconcile-0.9.1rc298.dist-info/METADATA +0 -63
  676. qontract_reconcile-0.9.1rc298.dist-info/RECORD +0 -585
  677. qontract_reconcile-0.9.1rc298.dist-info/top_level.txt +0 -4
  678. reconcile/ecr_mirror.py +0 -152
  679. reconcile/github_scanner.py +0 -74
  680. reconcile/gitlab_integrations.py +0 -63
  681. reconcile/gql_definitions/ocm_oidc_idp/clusters.py +0 -195
  682. reconcile/gql_definitions/ocp_release_mirror/ocp_release_mirror.py +0 -287
  683. reconcile/integrations_validator.py +0 -18
  684. reconcile/jenkins_plugins.py +0 -129
  685. reconcile/kafka_clusters.py +0 -208
  686. reconcile/ocm_cluster_admin.py +0 -42
  687. reconcile/ocm_oidc_idp.py +0 -198
  688. reconcile/ocp_release_mirror.py +0 -373
  689. reconcile/prometheus_rules_tester_old.py +0 -436
  690. reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager.py +0 -279
  691. reconcile/saas_auto_promotions_manager/utils/vcs.py +0 -141
  692. reconcile/sentry_config.py +0 -613
  693. reconcile/sentry_helper.py +0 -69
  694. reconcile/test/conftest.py +0 -187
  695. reconcile/test/fixtures.py +0 -24
  696. reconcile/test/saas_auto_promotions_manager/conftest.py +0 -69
  697. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py +0 -110
  698. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/data_keys.py +0 -10
  699. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_housekeeping.py +0 -200
  700. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_merge_request_manager.py +0 -151
  701. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py +0 -63
  702. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/data_keys.py +0 -4
  703. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_multiple_namespaces.py +0 -46
  704. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_namespace.py +0 -94
  705. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_target.py +0 -44
  706. reconcile/test/saas_auto_promotions_manager/subscriber/conftest.py +0 -74
  707. reconcile/test/saas_auto_promotions_manager/subscriber/data_keys.py +0 -11
  708. reconcile/test/saas_auto_promotions_manager/subscriber/test_content_hash.py +0 -155
  709. reconcile/test/saas_auto_promotions_manager/subscriber/test_diff.py +0 -173
  710. reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_channels_config_hash.py +0 -226
  711. reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_channels_moving_ref.py +0 -224
  712. reconcile/test/saas_auto_promotions_manager/subscriber/test_single_channel_with_single_publisher.py +0 -350
  713. reconcile/test/saas_auto_promotions_manager/test_integration_test.py +0 -129
  714. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_multiple_publishers_for_single_channel.py +0 -70
  715. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_use_target_config_hash.py +0 -63
  716. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_with_auto_promote.py +0 -74
  717. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_without_auto_promote.py +0 -65
  718. reconcile/test/test_aggregated_list.py +0 -237
  719. reconcile/test/test_amtool.py +0 -37
  720. reconcile/test/test_auto_promoter.py +0 -295
  721. reconcile/test/test_aws_ami_share.py +0 -68
  722. reconcile/test/test_aws_iam_keys.py +0 -70
  723. reconcile/test/test_aws_iam_password_reset.py +0 -35
  724. reconcile/test/test_aws_support_cases_sos.py +0 -23
  725. reconcile/test/test_checkpoint.py +0 -178
  726. reconcile/test/test_cli.py +0 -41
  727. reconcile/test/test_closedbox_endpoint_monitoring.py +0 -207
  728. reconcile/test/test_gabi_authorized_users.py +0 -72
  729. reconcile/test/test_github_org.py +0 -154
  730. reconcile/test/test_github_repo_invites.py +0 -123
  731. reconcile/test/test_gitlab_housekeeping.py +0 -88
  732. reconcile/test/test_gitlab_labeler.py +0 -129
  733. reconcile/test/test_gitlab_members.py +0 -283
  734. reconcile/test/test_instrumented_wrappers.py +0 -18
  735. reconcile/test/test_integrations_manager.py +0 -995
  736. reconcile/test/test_jenkins_worker_fleets.py +0 -55
  737. reconcile/test/test_jump_host.py +0 -117
  738. reconcile/test/test_ldap_users.py +0 -123
  739. reconcile/test/test_make.py +0 -28
  740. reconcile/test/test_ocm_additional_routers.py +0 -134
  741. reconcile/test/test_ocm_addons_upgrade_scheduler_org.py +0 -149
  742. reconcile/test/test_ocm_clusters.py +0 -598
  743. reconcile/test/test_ocm_clusters_manifest_updates.py +0 -89
  744. reconcile/test/test_ocm_oidc_idp.py +0 -315
  745. reconcile/test/test_ocm_update_recommended_version.py +0 -145
  746. reconcile/test/test_ocm_upgrade_scheduler.py +0 -614
  747. reconcile/test/test_ocm_upgrade_scheduler_org_updater.py +0 -129
  748. reconcile/test/test_openshift_base.py +0 -730
  749. reconcile/test/test_openshift_namespace_labels.py +0 -345
  750. reconcile/test/test_openshift_namespaces.py +0 -256
  751. reconcile/test/test_openshift_resource.py +0 -415
  752. reconcile/test/test_openshift_resources_base.py +0 -440
  753. reconcile/test/test_openshift_saas_deploy_change_tester.py +0 -310
  754. reconcile/test/test_openshift_tekton_resources.py +0 -253
  755. reconcile/test/test_openshift_upgrade_watcher.py +0 -146
  756. reconcile/test/test_prometheus_rules_tester.py +0 -151
  757. reconcile/test/test_prometheus_rules_tester_old.py +0 -77
  758. reconcile/test/test_quay_membership.py +0 -86
  759. reconcile/test/test_quay_mirror.py +0 -109
  760. reconcile/test/test_quay_mirror_org.py +0 -70
  761. reconcile/test/test_quay_repos.py +0 -59
  762. reconcile/test/test_queries.py +0 -53
  763. reconcile/test/test_repo_owners.py +0 -47
  764. reconcile/test/test_requests_sender.py +0 -139
  765. reconcile/test/test_saasherder.py +0 -1074
  766. reconcile/test/test_saasherder_allowed_secret_paths.py +0 -127
  767. reconcile/test/test_secret_reader.py +0 -153
  768. reconcile/test/test_slack_base.py +0 -185
  769. reconcile/test/test_slack_usergroups.py +0 -744
  770. reconcile/test/test_sql_query.py +0 -19
  771. reconcile/test/test_terraform_cloudflare_dns.py +0 -117
  772. reconcile/test/test_terraform_cloudflare_resources.py +0 -106
  773. reconcile/test/test_terraform_cloudflare_users.py +0 -749
  774. reconcile/test/test_terraform_resources.py +0 -257
  775. reconcile/test/test_terraform_tgw_attachments.py +0 -631
  776. reconcile/test/test_terraform_users.py +0 -57
  777. reconcile/test/test_terraform_vpc_peerings.py +0 -499
  778. reconcile/test/test_terraform_vpc_peerings_build_desired_state.py +0 -1061
  779. reconcile/test/test_unleash.py +0 -138
  780. reconcile/test/test_utils_aws_api.py +0 -240
  781. reconcile/test/test_utils_aws_helper.py +0 -80
  782. reconcile/test/test_utils_cluster_version_data.py +0 -177
  783. reconcile/test/test_utils_data_structures.py +0 -13
  784. reconcile/test/test_utils_disabled_integrations.py +0 -86
  785. reconcile/test/test_utils_expiration.py +0 -109
  786. reconcile/test/test_utils_external_resource_spec.py +0 -383
  787. reconcile/test/test_utils_external_resources.py +0 -247
  788. reconcile/test/test_utils_github_api.py +0 -73
  789. reconcile/test/test_utils_gitlab_api.py +0 -20
  790. reconcile/test/test_utils_gpg.py +0 -69
  791. reconcile/test/test_utils_gql.py +0 -81
  792. reconcile/test/test_utils_helm.py +0 -306
  793. reconcile/test/test_utils_helpers.py +0 -55
  794. reconcile/test/test_utils_imap_client.py +0 -65
  795. reconcile/test/test_utils_jjb_client.py +0 -52
  796. reconcile/test/test_utils_jsonpath.py +0 -286
  797. reconcile/test/test_utils_ldap_client.py +0 -51
  798. reconcile/test/test_utils_mr.py +0 -226
  799. reconcile/test/test_utils_mr_clusters_updates.py +0 -77
  800. reconcile/test/test_utils_oc.py +0 -984
  801. reconcile/test/test_utils_ocm.py +0 -110
  802. reconcile/test/test_utils_pagerduty_api.py +0 -251
  803. reconcile/test/test_utils_parse_dhms_duration.py +0 -34
  804. reconcile/test/test_utils_password_validator.py +0 -155
  805. reconcile/test/test_utils_quay_api.py +0 -86
  806. reconcile/test/test_utils_semver_helper.py +0 -19
  807. reconcile/test/test_utils_sharding.py +0 -56
  808. reconcile/test/test_utils_slack_api.py +0 -439
  809. reconcile/test/test_utils_smtp_client.py +0 -73
  810. reconcile/test/test_utils_state.py +0 -256
  811. reconcile/test/test_utils_terraform.py +0 -13
  812. reconcile/test/test_utils_terraform_client.py +0 -585
  813. reconcile/test/test_utils_terraform_config_client.py +0 -219
  814. reconcile/test/test_utils_terrascript_aws_client.py +0 -277
  815. reconcile/test/test_utils_terrascript_cloudflare_client.py +0 -597
  816. reconcile/test/test_utils_terrascript_cloudflare_resources.py +0 -26
  817. reconcile/test/test_vault_replication.py +0 -515
  818. reconcile/test/test_vault_utils.py +0 -47
  819. reconcile/test/test_version_bump.py +0 -18
  820. reconcile/test/test_vpc_peerings_validator.py +0 -103
  821. reconcile/test/test_wrong_region.py +0 -78
  822. reconcile/typed_queries/glitchtip_settings.py +0 -18
  823. reconcile/typed_queries/ocp_release_mirror.py +0 -11
  824. reconcile/unleash_watcher.py +0 -120
  825. reconcile/utils/git_secrets.py +0 -63
  826. reconcile/utils/mr/auto_promoter.py +0 -218
  827. reconcile/utils/sentry_client.py +0 -383
  828. release/test_version.py +0 -50
  829. release/version.py +0 -100
  830. tools/test/test_qontract_cli.py +0 -60
  831. tools/test/test_sre_checkpoints.py +0 -79
  832. /e2e_tests/__init__.py → /reconcile/aus/upgrades.py +0 -0
  833. /reconcile/{gql_definitions/ocp_release_mirror → aws_account_manager}/__init__.py +0 -0
  834. /reconcile/{test → aws_ami_cleanup}/__init__.py +0 -0
  835. /reconcile/{test/saas_auto_promotions_manager → aws_cloudwatch_log_retention}/__init__.py +0 -0
  836. /reconcile/{test/saas_auto_promotions_manager/merge_request_manager → aws_saml_idp}/__init__.py +0 -0
  837. /reconcile/{test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager → aws_saml_roles}/__init__.py +0 -0
  838. /reconcile/{test/saas_auto_promotions_manager/merge_request_manager/renderer → aws_version_sync}/__init__.py +0 -0
  839. /reconcile/{test/saas_auto_promotions_manager/subscriber → aws_version_sync/merge_request_manager}/__init__.py +0 -0
  840. /reconcile/{test/saas_auto_promotions_manager/utils → cluster_auth_rhidp}/__init__.py +0 -0
  841. /reconcile/{test/saas_auto_promotions_manager/utils/saas_files_inventory → dynatrace_token_provider}/__init__.py +0 -0
  842. {release → reconcile/endpoints_discovery}/__init__.py +0 -0
  843. {tools/test → reconcile/external_resources}/__init__.py +0 -0
@@ -1,4 +1,6 @@
1
+ # ruff: noqa: SIM114
1
2
  import base64
3
+ import contextlib
2
4
  import copy
3
5
  import datetime
4
6
  import hashlib
@@ -6,12 +8,12 @@ import json
6
8
  import re
7
9
  from collections.abc import Mapping
8
10
  from threading import Lock
9
- from typing import (
10
- Optional,
11
- Union,
12
- )
13
11
 
14
12
  import semver
13
+ from pydantic import BaseModel
14
+
15
+ from reconcile.external_resources.meta import SECRET_UPDATED_AT
16
+ from reconcile.utils.metrics import GaugeMetric
15
17
 
16
18
  SECRET_MAX_KEY_LENGTH = 253
17
19
 
@@ -20,6 +22,10 @@ class ResourceKeyExistsError(Exception):
20
22
  pass
21
23
 
22
24
 
25
+ class ResourceNotManagedError(Exception):
26
+ pass
27
+
28
+
23
29
  class ConstructResourceError(Exception):
24
30
  def __init__(self, msg):
25
31
  super().__init__("error constructing openshift resource: " + str(msg))
@@ -40,7 +46,7 @@ IGNORABLE_DATA_FIELDS = ["service-ca.crt"]
40
46
  # these labels existance and/or value is determined by a controller running
41
47
  # on the cluster. we need to ignore their existance in the current state,
42
48
  # otherwise we will deal with constant reconciliation
43
- CONTROLLER_MANAGED_LABELS: dict[str, set[Union[str, re.Pattern]]] = {
49
+ CONTROLLER_MANAGED_LABELS: dict[str, set[str | re.Pattern]] = {
44
50
  "ManagedCluster": {
45
51
  "clusterID",
46
52
  "managed-by",
@@ -49,7 +55,22 @@ CONTROLLER_MANAGED_LABELS: dict[str, set[Union[str, re.Pattern]]] = {
49
55
  }
50
56
  }
51
57
 
58
+ QONTRACT_ANNOTATION_INTEGRATION = "qontract.integration"
59
+ QONTRACT_ANNOTATION_INTEGRATION_VERSION = "qontract.integration_version"
60
+ QONTRACT_ANNOTATION_SHA256SUM = "qontract.sha256sum"
61
+ QONTRACT_ANNOTATION_UPDATE = "qontract.update"
62
+ QONTRACT_ANNOTATION_CALLER_NAME = "qontract.caller_name"
63
+
64
+ QONTRACT_ANNOTATIONS = {
65
+ QONTRACT_ANNOTATION_INTEGRATION,
66
+ QONTRACT_ANNOTATION_INTEGRATION_VERSION,
67
+ QONTRACT_ANNOTATION_SHA256SUM,
68
+ QONTRACT_ANNOTATION_UPDATE,
69
+ QONTRACT_ANNOTATION_CALLER_NAME,
70
+ }
71
+
52
72
 
73
+ # pylint: disable=R0904
53
74
  class OpenshiftResource:
54
75
  def __init__(
55
76
  self,
@@ -81,7 +102,7 @@ class OpenshiftResource:
81
102
  for obj1_k, obj1_v in obj1.items():
82
103
  obj2_v = obj2.get(obj1_k, None)
83
104
  if obj2_v is None:
84
- if obj1_v not in [None, ""]:
105
+ if obj1_v:
85
106
  return False
86
107
  if self.ignorable_field(obj1_k):
87
108
  pass
@@ -100,7 +121,7 @@ class OpenshiftResource:
100
121
  ]
101
122
  if diff or not self.obj_intersect_equal(obj1_v, obj2_v, depth + 1):
102
123
  return False
103
- elif obj1_k in ["data", "matchLabels"]:
124
+ elif obj1_k in {"data", "matchLabels"}:
104
125
  diff = [
105
126
  k
106
127
  for k in obj2_v
@@ -153,28 +174,22 @@ class OpenshiftResource:
153
174
  "uid",
154
175
  "fieldRef",
155
176
  ]
156
- if val in ignorable_fields:
157
- return True
158
- return False
177
+ return val in ignorable_fields
159
178
 
160
179
  @staticmethod
161
180
  def ignorable_key_value_pair(key, val):
162
181
  ignorable_key_value_pair = {"annotations": None, "divisor": "0"}
163
- if key in ignorable_key_value_pair and ignorable_key_value_pair[key] == val:
164
- return True
165
- return False
182
+ return bool(
183
+ key in ignorable_key_value_pair and ignorable_key_value_pair[key] == val
184
+ )
166
185
 
167
186
  @staticmethod
168
187
  def cpu_equal(val1, val2):
169
188
  # normalize both to string
170
- try:
189
+ with contextlib.suppress(Exception):
171
190
  val1 = f"{int(float(val1) * 1000)}m"
172
- except Exception:
173
- pass
174
- try:
191
+ with contextlib.suppress(Exception):
175
192
  val2 = f"{int(float(val2) * 1000)}m"
176
- except Exception:
177
- pass
178
193
  return val1 == val2
179
194
 
180
195
  @staticmethod
@@ -191,12 +206,20 @@ class OpenshiftResource:
191
206
 
192
207
  @property
193
208
  def name(self):
194
- return self.body["metadata"]["name"]
209
+ # PipelineRun name can be empty when creating
210
+ if self.kind == "PipelineRun" and "name" not in self.body["metadata"]:
211
+ return self.body["metadata"]["generateName"][:-1]
212
+ else:
213
+ return self.body["metadata"]["name"]
195
214
 
196
215
  @property
197
216
  def kind(self):
198
217
  return self.body["kind"]
199
218
 
219
+ @property
220
+ def annotations(self):
221
+ return self.body["metadata"].get("annotations", {})
222
+
200
223
  @property
201
224
  def kind_and_group(self):
202
225
  return fully_qualified_kind(self.kind, self.body["apiVersion"])
@@ -213,20 +236,18 @@ class OpenshiftResource:
213
236
 
214
237
  def verify_valid_k8s_object(self):
215
238
  try:
216
- self.name # pylint: disable=pointless-statement
217
- self.kind # pylint: disable=pointless-statement
239
+ assert self.name
240
+ assert self.kind
218
241
  except (KeyError, TypeError) as e:
219
- msg = "resource invalid data ({}). details: {}".format(
220
- e.__class__.__name__, self.error_details
221
- )
222
- raise ConstructResourceError(msg)
242
+ msg = f"resource invalid data ({e.__class__.__name__}). details: {self.error_details}"
243
+ raise ConstructResourceError(msg) from None
223
244
 
224
- if self.kind not in [
245
+ if self.kind not in {
225
246
  "Role",
226
247
  "RoleBinding",
227
248
  "ClusterRole",
228
249
  "ClusterRoleBinding",
229
- ] and (
250
+ } and (
230
251
  not DNS_SUBDOMAIN_RE.match(self.name)
231
252
  or not len(self.name) <= DNS_SUBDOMAIN_MAX_LENGTH
232
253
  ):
@@ -283,15 +304,15 @@ class OpenshiftResource:
283
304
  try:
284
305
  annotations = self.body["metadata"]["annotations"]
285
306
 
286
- assert annotations["qontract.integration"] == self.integration
307
+ assert annotations[QONTRACT_ANNOTATION_INTEGRATION] == self.integration
287
308
 
288
- integration_version = annotations["qontract.integration_version"]
309
+ integration_version = annotations[QONTRACT_ANNOTATION_INTEGRATION_VERSION]
289
310
  assert (
290
311
  semver.VersionInfo.parse(integration_version).major
291
312
  == semver.VersionInfo.parse(self.integration_version).major
292
313
  )
293
314
 
294
- assert annotations["qontract.sha256sum"] is not None
315
+ assert annotations[QONTRACT_ANNOTATION_SHA256SUM] is not None
295
316
  except KeyError:
296
317
  return False
297
318
  except AssertionError:
@@ -314,7 +335,7 @@ class OpenshiftResource:
314
335
  except KeyError:
315
336
  return False
316
337
 
317
- def annotate(self):
338
+ def annotate(self, canonicalize=True):
318
339
  """
319
340
  Creates a OpenshiftResource with the qontract annotations, and removes
320
341
  unneeded Openshift fields.
@@ -323,10 +344,9 @@ class OpenshiftResource:
323
344
  openshift_resource: new OpenshiftResource object with
324
345
  annotations.
325
346
  """
347
+ body = self.canonicalize(self.body) if canonicalize else self.body
326
348
 
327
- # calculate sha256sum of canonical body
328
- canonical_body = self.canonicalize(self.body)
329
- sha256sum = self.calculate_sha256sum(self.serialize(canonical_body))
349
+ sha256sum = self.calculate_sha256sum(self.serialize(body))
330
350
 
331
351
  # create new body object
332
352
  body = copy.deepcopy(self.body)
@@ -339,13 +359,13 @@ class OpenshiftResource:
339
359
  annotations = body["metadata"]["annotations"]
340
360
 
341
361
  # add qontract annotations
342
- annotations["qontract.integration"] = self.integration
343
- annotations["qontract.integration_version"] = self.integration_version
344
- annotations["qontract.sha256sum"] = sha256sum
362
+ annotations[QONTRACT_ANNOTATION_INTEGRATION] = self.integration
363
+ annotations[QONTRACT_ANNOTATION_INTEGRATION_VERSION] = self.integration_version
364
+ annotations[QONTRACT_ANNOTATION_SHA256SUM] = sha256sum
345
365
  now = datetime.datetime.utcnow().replace(microsecond=0).isoformat()
346
- annotations["qontract.update"] = now
366
+ annotations[QONTRACT_ANNOTATION_UPDATE] = now
347
367
  if self.caller_name:
348
- annotations["qontract.caller_name"] = self.caller_name
368
+ annotations[QONTRACT_ANNOTATION_CALLER_NAME] = self.caller_name
349
369
 
350
370
  return OpenshiftResource(body, self.integration, self.integration_version)
351
371
 
@@ -389,7 +409,7 @@ class OpenshiftResource:
389
409
 
390
410
  # Default fields for specific resource types
391
411
  # ConfigMaps and Secrets are by default Opaque
392
- if body["kind"] in ("ConfigMap", "Secret") and body.get("type") == "Opaque":
412
+ if body["kind"] in {"ConfigMap", "Secret"} and body.get("type") == "Opaque":
393
413
  body.pop("type")
394
414
 
395
415
  if body["kind"] == "Secret":
@@ -397,7 +417,7 @@ class OpenshiftResource:
397
417
  if string_data:
398
418
  body.setdefault("data", {})
399
419
  for k, v in string_data.items():
400
- v = base64.b64encode(str(v).encode()).decode("utf-8")
420
+ v = base64_encode_secret_field_value(str(v))
401
421
  body["data"][k] = v
402
422
 
403
423
  if body["kind"] == "Deployment":
@@ -419,7 +439,7 @@ class OpenshiftResource:
419
439
  tls.pop("key", None)
420
440
  tls.pop("certificate", None)
421
441
  subdomain = body["spec"].get("subdomain", None)
422
- if subdomain == "":
442
+ if not subdomain:
423
443
  body["spec"].pop("subdomain", None)
424
444
 
425
445
  if body["kind"] == "ServiceAccount":
@@ -448,9 +468,6 @@ class OpenshiftResource:
448
468
  and not rule["attributeRestrictions"]
449
469
  ):
450
470
  rule.pop("attributeRestrictions")
451
- # TODO: remove this once we have no 3.11 clusters
452
- if body["apiVersion"] == "authorization.openshift.io/v1":
453
- body["apiVersion"] = "rbac.authorization.k8s.io/v1"
454
471
 
455
472
  if body["kind"] == "OperatorGroup":
456
473
  annotations.pop("olm.providedAPIs", None)
@@ -472,18 +489,11 @@ class OpenshiftResource:
472
489
  if "namespace" in subject:
473
490
  subject.pop("namespace")
474
491
  if "apiGroup" in subject and (
475
- subject["apiGroup"] == ""
476
- or subject["apiGroup"] in body["apiVersion"]
492
+ not subject["apiGroup"] or subject["apiGroup"] in body["apiVersion"]
477
493
  ):
478
494
  subject.pop("apiGroup")
479
- # TODO: remove this once we have no 3.11 clusters
480
- if body["apiVersion"] == "rbac.authorization.k8s.io/v1":
481
- body["apiVersion"] = "authorization.openshift.io/v1"
482
495
 
483
496
  if body["kind"] == "ClusterRoleBinding":
484
- # TODO: remove this once we have no 3.11 clusters
485
- if body["apiVersion"] == "authorization.openshift.io/v1":
486
- body["apiVersion"] = "rbac.authorization.k8s.io/v1"
487
497
  if "userNames" in body:
488
498
  body.pop("userNames")
489
499
  if "roleRef" in body:
@@ -502,12 +512,11 @@ class OpenshiftResource:
502
512
  spec.pop("clusterIP", None)
503
513
 
504
514
  # remove qontract specific params
505
- annotations.pop("qontract.integration", None)
506
- annotations.pop("qontract.integration_version", None)
507
- annotations.pop("qontract.sha256sum", None)
508
- annotations.pop("qontract.update", None)
509
- annotations.pop("qontract.caller_name", None)
515
+ for a in QONTRACT_ANNOTATIONS:
516
+ annotations.pop(a, None)
510
517
 
518
+ # Remove external resources annotation used for optimistic locking
519
+ annotations.pop(SECRET_UPDATED_AT, None)
511
520
  return body
512
521
 
513
522
  @staticmethod
@@ -528,6 +537,25 @@ def fully_qualified_kind(kind: str, api_version: str) -> str:
528
537
  return kind
529
538
 
530
539
 
540
+ class OpenshiftResourceBaseMetric(BaseModel):
541
+ "Base class Openshift Resource metrics"
542
+
543
+ integration: str
544
+
545
+
546
+ class OpenshiftResourceInventoryGauge(OpenshiftResourceBaseMetric, GaugeMetric):
547
+ "Inventory Gauge"
548
+
549
+ cluster: str
550
+ namespace: str
551
+ kind: str
552
+ state: str
553
+
554
+ @classmethod
555
+ def name(cls) -> str:
556
+ return "qontract_reconcile_openshift_resource_inventory"
557
+
558
+
531
559
  class ResourceInventory:
532
560
  def __init__(self):
533
561
  self._clusters = {}
@@ -535,11 +563,23 @@ class ResourceInventory:
535
563
  self._error_registered_clusters = {}
536
564
  self._lock = Lock()
537
565
 
538
- def initialize_resource_type(self, cluster, namespace, resource_type):
566
+ def initialize_resource_type(
567
+ self,
568
+ cluster,
569
+ namespace,
570
+ resource_type,
571
+ managed_names: list[str] | None = None,
572
+ ):
539
573
  self._clusters.setdefault(cluster, {})
540
574
  self._clusters[cluster].setdefault(namespace, {})
541
575
  self._clusters[cluster][namespace].setdefault(
542
- resource_type, {"current": {}, "desired": {}, "use_admin_token": {}}
576
+ resource_type,
577
+ {
578
+ "current": {},
579
+ "desired": {},
580
+ "use_admin_token": {},
581
+ "managed_names": managed_names,
582
+ },
543
583
  )
544
584
 
545
585
  def is_cluster_present(self, cluster: str) -> bool:
@@ -575,6 +615,13 @@ class ResourceInventory:
575
615
  # mismatch between schema and implementation for now, it will enable
576
616
  # us to implement per-resource configuration in the future
577
617
  with self._lock:
618
+ # fail if the name of the resource is not within the managed names if they are defined
619
+ managed_names = self._clusters[cluster][namespace][resource_type][
620
+ "managed_names"
621
+ ]
622
+ if managed_names is not None and name not in managed_names:
623
+ raise ResourceNotManagedError(name)
624
+
578
625
  desired = self._clusters[cluster][namespace][resource_type]["desired"]
579
626
  if name in desired:
580
627
  raise ResourceKeyExistsError(name)
@@ -630,10 +677,9 @@ def build_secret(
630
677
  integration_version: str,
631
678
  unencoded_data: Mapping[str, str],
632
679
  error_details: str = "",
633
- caller_name: Optional[str] = None,
634
- annotations: Optional[Mapping[str, str]] = None,
680
+ caller_name: str | None = None,
681
+ annotations: Mapping[str, str] | None = None,
635
682
  ) -> OpenshiftResource:
636
-
637
683
  encoded_data = {
638
684
  k: base64_encode_secret_field_value(v) for k, v in unencoded_data.items()
639
685
  }
@@ -655,7 +701,7 @@ def build_secret(
655
701
  )
656
702
 
657
703
 
658
- def base64_encode_secret_field_value(value: str) -> Optional[str]:
659
- if value == "":
660
- return None
704
+ def base64_encode_secret_field_value(value: str) -> str:
705
+ if not value:
706
+ return ""
661
707
  return base64.b64encode(str(value).encode()).decode("utf-8")
reconcile/utils/output.py CHANGED
@@ -1,19 +1,19 @@
1
1
  import json
2
+ import re
2
3
  from collections.abc import (
3
4
  Iterable,
4
5
  Mapping,
5
6
  )
6
- from typing import Union
7
7
 
8
8
  import yaml
9
9
  from tabulate import tabulate
10
10
 
11
11
 
12
12
  def print_output(
13
- options: Mapping[str, Union[str, bool]],
13
+ options: Mapping[str, str | bool],
14
14
  content: list[dict],
15
15
  columns: Iterable[str] = (),
16
- ):
16
+ ) -> str | None:
17
17
  if options["sort"]:
18
18
  content.sort(key=lambda c: tuple(c.values()))
19
19
  if options.get("to_string"):
@@ -23,17 +23,26 @@ def print_output(
23
23
 
24
24
  output = options["output"]
25
25
 
26
+ formatted_content = None
26
27
  if output == "table":
27
- print_table(content, columns)
28
+ formatted_content = format_table(content, columns)
29
+ print(formatted_content)
28
30
  elif output == "md":
29
- print_table(content, columns, table_format="github")
31
+ formatted_content = re.sub(
32
+ r" +", " ", format_table(content, columns, table_format="github")
33
+ )
34
+ print(formatted_content)
30
35
  elif output == "json":
31
- print(json.dumps(content))
36
+ formatted_content = json.dumps(content)
37
+ print(formatted_content)
32
38
  elif output == "yaml":
33
- print(yaml.dump(content))
39
+ formatted_content = yaml.dump(content)
40
+ print(formatted_content)
34
41
  else:
35
42
  pass # error
36
43
 
44
+ return formatted_content
45
+
37
46
 
38
47
  def format_table(content, columns, table_format="simple") -> str:
39
48
  headers = [column.upper() for column in columns]
@@ -53,10 +62,8 @@ def format_table(content, columns, table_format="simple") -> str:
53
62
  cell = "<br />".join(cell)
54
63
  else:
55
64
  cell = "\n".join(cell)
65
+ if table_format == "github" and isinstance(cell, str):
66
+ cell = cell.replace("|", "&#124;")
56
67
  row_data.append(cell)
57
68
  table_data.append(row_data)
58
69
  return tabulate(table_data, headers=headers, tablefmt=table_format)
59
-
60
-
61
- def print_table(content, columns, table_format="simple"):
62
- print(format_table(content, columns, table_format))
@@ -4,8 +4,8 @@ from collections.abc import (
4
4
  Iterable,
5
5
  )
6
6
  from datetime import datetime as dt
7
+ from datetime import timedelta
7
8
  from typing import (
8
- Optional,
9
9
  Protocol,
10
10
  )
11
11
 
@@ -44,7 +44,7 @@ class PagerDutyUser(Protocol):
44
44
  which must be implemented by a class to be compatible."""
45
45
 
46
46
  org_username: str
47
- pagerduty_username: Optional[str]
47
+ pagerduty_username: str | None
48
48
 
49
49
 
50
50
  class PagerDutyTarget(Protocol):
@@ -53,8 +53,8 @@ class PagerDutyTarget(Protocol):
53
53
 
54
54
  name: str
55
55
  instance: PagerDutyInstance
56
- escalation_policy_id: Optional[str]
57
- schedule_id: Optional[str]
56
+ escalation_policy_id: str | None
57
+ schedule_id: str | None
58
58
 
59
59
 
60
60
  class PagerDutyConfig(BaseModel):
@@ -75,7 +75,7 @@ class PagerDutyApi:
75
75
  self.users: list[pypd.User] = []
76
76
 
77
77
  def init_users(self) -> None:
78
- self.users = pypd.User.find()
78
+ self.users = pypd.User.find(limit=100)
79
79
 
80
80
  def get_pagerduty_users(
81
81
  self, resource_type: str, resource_id: str
@@ -104,7 +104,8 @@ class PagerDutyApi:
104
104
  return user.email.split("@")[0]
105
105
 
106
106
  def get_schedule_users(self, schedule_id: str, now: dt) -> list[pypd.User]:
107
- s = pypd.Schedule.fetch(id=schedule_id, since=now, until=now, time_zone="UTC")
107
+ until = now + timedelta(seconds=60)
108
+ s = pypd.Schedule.fetch(id=schedule_id, since=now, until=until, time_zone="UTC")
108
109
  entries = s["final_schedule"]["rendered_schedule_entries"]
109
110
 
110
111
  return [
@@ -164,16 +165,21 @@ class PagerDutyMap:
164
165
 
165
166
  def get_pagerduty_map(
166
167
  secret_reader: SecretReader,
167
- pagerduty_instances: Iterable[PagerDutyInstance],
168
+ pagerduty_instances: Iterable[PagerDutyInstance] | None,
168
169
  init_users: bool = True,
169
170
  pager_duty_api_class: type[PagerDutyApi] = PagerDutyApi,
170
171
  ) -> PagerDutyMap:
171
172
  """Initiate a PagerDutyMap for given PagerDuty instances."""
172
- return PagerDutyMap(
173
- instances=[
173
+ instances = (
174
+ [
174
175
  PagerDutyConfig(name=i.name, token=secret_reader.read_secret(i.token))
175
176
  for i in pagerduty_instances
176
- ],
177
+ ]
178
+ if pagerduty_instances
179
+ else []
180
+ )
181
+ return PagerDutyMap(
182
+ instances=instances,
177
183
  init_users=init_users,
178
184
  pager_duty_api_class=pager_duty_api_class,
179
185
  )
@@ -31,6 +31,18 @@ HANDLE_UNIT_MAP = {
31
31
  }
32
32
 
33
33
 
34
+ def seconds_to_hms(seconds: int) -> str:
35
+ minutes, s = divmod(seconds, 60)
36
+ if minutes == 0:
37
+ return f"{s}s"
38
+
39
+ h, m = divmod(minutes, 60)
40
+ if h == 0:
41
+ return f"{m}m{s}s"
42
+
43
+ return f"{h}h{m}m{s}s"
44
+
45
+
34
46
  def dhms_to_seconds(time_str: str) -> int:
35
47
  """Parses durations and returns seconds. The format is a subset of Go's
36
48
  ParseDuration format, only allowing from days to seconds in resolution,
@@ -46,7 +58,7 @@ def dhms_to_seconds(time_str: str) -> int:
46
58
  if s.isnumeric():
47
59
  previous_number += s
48
60
  else:
49
- if previous_number == "":
61
+ if not previous_number:
50
62
  raise BadHDMSDurationError(f"Invalid time duration {time_str}")
51
63
 
52
64
  if s in HANDLE_UNIT_MAP:
@@ -0,0 +1,123 @@
1
+ from typing import NamedTuple, Protocol
2
+
3
+ import requests
4
+ from pydantic import BaseModel, Field
5
+
6
+ from reconcile.gql_definitions.fragments.prometheus_instance import (
7
+ PrometheusInstance,
8
+ PrometheusInstanceBearerAuthV1,
9
+ PrometheusInstanceOidcAuthV1,
10
+ )
11
+ from reconcile.utils.secret_reader import SecretReaderBase
12
+
13
+ INSTANT_VECTOR_RESULT_TYPE = "vector"
14
+
15
+
16
+ class PrometheusQueryError(Exception):
17
+ pass
18
+
19
+
20
+ class PrometheusValue(NamedTuple):
21
+ timestamp: float
22
+ value: float
23
+
24
+
25
+ class PrometheusVector(BaseModel):
26
+ metric: dict[str, str]
27
+ raw_value: PrometheusValue = Field(..., alias="value")
28
+
29
+ @property
30
+ def name(self) -> str:
31
+ return self.metric["__name__"]
32
+
33
+ @property
34
+ def timestamp(self) -> float:
35
+ return self.raw_value[0]
36
+
37
+ @property
38
+ def value(self) -> float:
39
+ return self.raw_value[1]
40
+
41
+ def mandatory_label(self, label_name: str) -> str:
42
+ return self.metric[label_name]
43
+
44
+ def label(self, label_name: str, default: str | None = None) -> str | None:
45
+ return self.metric.get(label_name, default)
46
+
47
+
48
+ class PrometheusQuerier(Protocol):
49
+ """
50
+ A protocol for a querier of Prometheus.
51
+ """
52
+
53
+ def instant_vector_query(self, query: str) -> list[PrometheusVector]:
54
+ """
55
+ Query for instant vectors.
56
+ """
57
+
58
+
59
+ class PrometheusHttpQuerier(BaseModel):
60
+ query_url: str
61
+ auth_token: str
62
+
63
+ def instant_vector_query(self, query: str) -> list[PrometheusVector]:
64
+ response = requests.get(
65
+ self.query_url,
66
+ params={"query": query},
67
+ headers={
68
+ "Authorization": f"Bearer {self.auth_token}",
69
+ },
70
+ )
71
+
72
+ response.raise_for_status()
73
+
74
+ # Parse the response JSON
75
+ try:
76
+ parsed = response.json()
77
+ except Exception as e:
78
+ raise PrometheusQueryError(
79
+ f"Query failed with invalid JSON response: {response.text[:100]}..."
80
+ ) from e
81
+ if parsed.get("status") != "success":
82
+ raise PrometheusQueryError(
83
+ f"Query response status was not `success`but {parsed.get('status')}"
84
+ )
85
+ if "data" not in parsed:
86
+ raise PrometheusQueryError(
87
+ f"Query response does not contain `data`: {response.text[:100]}..."
88
+ )
89
+ result_type = parsed.get("data", {}).get("resultType")
90
+ if result_type != INSTANT_VECTOR_RESULT_TYPE:
91
+ raise PrometheusQueryError(
92
+ f"Query failed with unexpected result type. Expected {INSTANT_VECTOR_RESULT_TYPE} got {result_type}"
93
+ )
94
+ return [PrometheusVector(**m) for m in parsed["data"]["result"]]
95
+
96
+
97
+ def init_prometheus_http_querier_from_prometheus_instance(
98
+ prometheus: PrometheusInstance, secret_reader: SecretReaderBase
99
+ ) -> PrometheusHttpQuerier:
100
+ match prometheus.auth:
101
+ case PrometheusInstanceBearerAuthV1():
102
+ auth_token = secret_reader.read_secret(prometheus.auth.token)
103
+ case PrometheusInstanceOidcAuthV1():
104
+ client_secret = secret_reader.read_secret(
105
+ prometheus.auth.access_token_client_secret
106
+ )
107
+ data = {
108
+ "grant_type": "client_credentials",
109
+ "client_id": prometheus.auth.access_token_client_id,
110
+ "client_secret": client_secret,
111
+ }
112
+ response = requests.post(
113
+ prometheus.auth.access_token_url, data=data, timeout=15
114
+ )
115
+ response.raise_for_status()
116
+ auth_token = response.json().get("access_token")
117
+ case _:
118
+ raise Exception(f"Unsupported auth type: {prometheus.auth.provider}")
119
+
120
+ return PrometheusHttpQuerier(
121
+ query_url=f"{prometheus.base_url}/{prometheus.query_path}",
122
+ auth_token=auth_token,
123
+ )