qontract-reconcile 0.10.2.dev349__py3-none-any.whl → 0.10.2.dev414__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 (356) hide show
  1. {qontract_reconcile-0.10.2.dev349.dist-info → qontract_reconcile-0.10.2.dev414.dist-info}/METADATA +12 -11
  2. {qontract_reconcile-0.10.2.dev349.dist-info → qontract_reconcile-0.10.2.dev414.dist-info}/RECORD +356 -350
  3. reconcile/acs_rbac.py +2 -2
  4. reconcile/aus/advanced_upgrade_service.py +15 -12
  5. reconcile/aus/base.py +26 -27
  6. reconcile/aus/cluster_version_data.py +15 -5
  7. reconcile/aus/models.py +1 -1
  8. reconcile/automated_actions/config/integration.py +15 -3
  9. reconcile/aws_account_manager/integration.py +8 -8
  10. reconcile/aws_account_manager/reconciler.py +3 -3
  11. reconcile/aws_ami_cleanup/integration.py +8 -12
  12. reconcile/aws_ami_share.py +69 -62
  13. reconcile/aws_cloudwatch_log_retention/integration.py +155 -126
  14. reconcile/aws_ecr_image_pull_secrets.py +2 -2
  15. reconcile/aws_iam_keys.py +7 -41
  16. reconcile/aws_saml_idp/integration.py +12 -4
  17. reconcile/aws_saml_roles/integration.py +32 -25
  18. reconcile/aws_version_sync/integration.py +6 -12
  19. reconcile/change_owners/bundle.py +3 -3
  20. reconcile/change_owners/change_log_tracking.py +3 -2
  21. reconcile/change_owners/change_owners.py +1 -1
  22. reconcile/change_owners/diff.py +2 -4
  23. reconcile/checkpoint.py +11 -3
  24. reconcile/cli.py +33 -8
  25. reconcile/dashdotdb_dora.py +5 -12
  26. reconcile/dashdotdb_slo.py +1 -1
  27. reconcile/database_access_manager.py +123 -117
  28. reconcile/dynatrace_token_provider/integration.py +1 -1
  29. reconcile/endpoints_discovery/integration.py +4 -1
  30. reconcile/endpoints_discovery/merge_request.py +1 -1
  31. reconcile/endpoints_discovery/merge_request_manager.py +9 -11
  32. reconcile/external_resources/factories.py +5 -12
  33. reconcile/external_resources/integration.py +1 -1
  34. reconcile/external_resources/manager.py +24 -10
  35. reconcile/external_resources/meta.py +0 -1
  36. reconcile/external_resources/metrics.py +1 -1
  37. reconcile/external_resources/model.py +13 -13
  38. reconcile/external_resources/reconciler.py +7 -4
  39. reconcile/external_resources/secrets_sync.py +6 -8
  40. reconcile/external_resources/state.py +60 -17
  41. reconcile/fleet_labeler/integration.py +1 -1
  42. reconcile/gabi_authorized_users.py +8 -5
  43. reconcile/gcp_image_mirror.py +2 -2
  44. reconcile/github_org.py +1 -1
  45. reconcile/github_owners.py +4 -0
  46. reconcile/gitlab_housekeeping.py +13 -15
  47. reconcile/gitlab_members.py +6 -12
  48. reconcile/gitlab_mr_sqs_consumer.py +2 -2
  49. reconcile/gitlab_owners.py +15 -11
  50. reconcile/gitlab_permissions.py +8 -12
  51. reconcile/glitchtip_project_alerts/integration.py +3 -1
  52. reconcile/gql_definitions/acs/acs_instances.py +5 -5
  53. reconcile/gql_definitions/acs/acs_policies.py +5 -5
  54. reconcile/gql_definitions/acs/acs_rbac.py +5 -5
  55. reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +5 -5
  56. reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +5 -5
  57. reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +5 -5
  58. reconcile/gql_definitions/app_sre_tekton_access_revalidation/roles.py +5 -5
  59. reconcile/gql_definitions/app_sre_tekton_access_revalidation/users.py +5 -5
  60. reconcile/gql_definitions/automated_actions/instance.py +46 -7
  61. reconcile/gql_definitions/aws_account_manager/aws_accounts.py +5 -5
  62. reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +15 -5
  63. reconcile/gql_definitions/aws_cloudwatch_log_retention/aws_accounts.py +27 -66
  64. reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +15 -5
  65. reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +15 -5
  66. reconcile/gql_definitions/aws_saml_roles/roles.py +5 -5
  67. reconcile/gql_definitions/aws_version_sync/clusters.py +5 -5
  68. reconcile/gql_definitions/aws_version_sync/namespaces.py +5 -5
  69. reconcile/gql_definitions/change_owners/queries/change_types.py +5 -5
  70. reconcile/gql_definitions/change_owners/queries/self_service_roles.py +5 -5
  71. reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +5 -5
  72. reconcile/gql_definitions/common/alerting_services_settings.py +5 -5
  73. reconcile/gql_definitions/common/app_code_component_repos.py +5 -5
  74. reconcile/gql_definitions/common/app_interface_custom_messages.py +5 -5
  75. reconcile/gql_definitions/common/app_interface_dms_settings.py +5 -5
  76. reconcile/gql_definitions/common/app_interface_repo_settings.py +5 -5
  77. reconcile/gql_definitions/common/app_interface_roles.py +5 -5
  78. reconcile/gql_definitions/common/app_interface_state_settings.py +5 -5
  79. reconcile/gql_definitions/common/app_interface_vault_settings.py +5 -5
  80. reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +5 -5
  81. reconcile/gql_definitions/common/apps.py +5 -5
  82. reconcile/gql_definitions/common/aws_vpc_requests.py +15 -5
  83. reconcile/gql_definitions/common/aws_vpcs.py +5 -5
  84. reconcile/gql_definitions/common/clusters.py +7 -5
  85. reconcile/gql_definitions/common/clusters_minimal.py +5 -5
  86. reconcile/gql_definitions/common/clusters_with_dms.py +5 -5
  87. reconcile/gql_definitions/common/clusters_with_peering.py +5 -5
  88. reconcile/gql_definitions/common/github_orgs.py +5 -5
  89. reconcile/gql_definitions/common/jira_settings.py +5 -5
  90. reconcile/gql_definitions/common/jiralert_settings.py +5 -5
  91. reconcile/gql_definitions/common/ldap_settings.py +5 -5
  92. reconcile/gql_definitions/common/namespaces.py +5 -5
  93. reconcile/gql_definitions/common/namespaces_minimal.py +7 -5
  94. reconcile/gql_definitions/common/ocm_env_telemeter.py +5 -5
  95. reconcile/gql_definitions/common/ocm_environments.py +5 -5
  96. reconcile/gql_definitions/common/pagerduty_instances.py +5 -5
  97. reconcile/gql_definitions/common/pgp_reencryption_settings.py +5 -5
  98. reconcile/gql_definitions/common/pipeline_providers.py +5 -5
  99. reconcile/gql_definitions/common/quay_instances.py +5 -5
  100. reconcile/gql_definitions/common/quay_orgs.py +5 -5
  101. reconcile/gql_definitions/common/reserved_networks.py +5 -5
  102. reconcile/gql_definitions/common/rhcs_provider_settings.py +5 -5
  103. reconcile/gql_definitions/common/saas_files.py +5 -5
  104. reconcile/gql_definitions/common/saas_target_namespaces.py +5 -5
  105. reconcile/gql_definitions/common/saasherder_settings.py +5 -5
  106. reconcile/gql_definitions/common/slack_workspaces.py +5 -5
  107. reconcile/gql_definitions/common/smtp_client_settings.py +5 -5
  108. reconcile/gql_definitions/common/state_aws_account.py +5 -5
  109. reconcile/gql_definitions/common/users.py +5 -5
  110. reconcile/gql_definitions/common/users_with_paths.py +5 -5
  111. reconcile/gql_definitions/cost_report/app_names.py +5 -5
  112. reconcile/gql_definitions/cost_report/cost_namespaces.py +5 -5
  113. reconcile/gql_definitions/cost_report/settings.py +5 -5
  114. reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +5 -5
  115. reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +5 -5
  116. reconcile/gql_definitions/dynatrace_token_provider/token_specs.py +5 -5
  117. reconcile/gql_definitions/email_sender/apps.py +5 -5
  118. reconcile/gql_definitions/email_sender/emails.py +5 -5
  119. reconcile/gql_definitions/email_sender/users.py +5 -5
  120. reconcile/gql_definitions/endpoints_discovery/apps.py +5 -5
  121. reconcile/gql_definitions/external_resources/aws_accounts.py +5 -5
  122. reconcile/gql_definitions/external_resources/external_resources_modules.py +5 -5
  123. reconcile/gql_definitions/external_resources/external_resources_namespaces.py +89 -6
  124. reconcile/gql_definitions/external_resources/external_resources_settings.py +7 -5
  125. reconcile/gql_definitions/external_resources/fragments/external_resources_module_overrides.py +5 -5
  126. reconcile/gql_definitions/fleet_labeler/fleet_labels.py +5 -5
  127. reconcile/gql_definitions/fragments/aus_organization.py +5 -5
  128. reconcile/gql_definitions/fragments/aws_account_common.py +7 -5
  129. reconcile/gql_definitions/fragments/aws_account_managed.py +5 -5
  130. reconcile/gql_definitions/fragments/aws_account_sso.py +5 -5
  131. reconcile/gql_definitions/fragments/aws_infra_management_account.py +5 -5
  132. reconcile/gql_definitions/fragments/aws_organization.py +33 -0
  133. reconcile/gql_definitions/fragments/aws_vpc.py +5 -5
  134. reconcile/gql_definitions/fragments/aws_vpc_request.py +7 -5
  135. reconcile/gql_definitions/fragments/container_image_mirror.py +5 -5
  136. reconcile/gql_definitions/fragments/deploy_resources.py +5 -5
  137. reconcile/gql_definitions/fragments/disable.py +5 -5
  138. reconcile/gql_definitions/fragments/email_service.py +5 -5
  139. reconcile/gql_definitions/fragments/email_user.py +5 -5
  140. reconcile/gql_definitions/fragments/jumphost_common_fields.py +5 -5
  141. reconcile/gql_definitions/fragments/membership_source.py +5 -5
  142. reconcile/gql_definitions/fragments/minimal_ocm_organization.py +5 -5
  143. reconcile/gql_definitions/fragments/oc_connection_cluster.py +5 -5
  144. reconcile/gql_definitions/fragments/ocm_environment.py +5 -5
  145. reconcile/gql_definitions/fragments/pipeline_provider_retention.py +5 -5
  146. reconcile/gql_definitions/fragments/prometheus_instance.py +5 -5
  147. reconcile/gql_definitions/fragments/resource_limits_requirements.py +5 -5
  148. reconcile/gql_definitions/fragments/resource_requests_requirements.py +5 -5
  149. reconcile/gql_definitions/fragments/resource_values.py +5 -5
  150. reconcile/gql_definitions/fragments/saas_slo_document.py +5 -5
  151. reconcile/gql_definitions/fragments/saas_target_namespace.py +5 -5
  152. reconcile/gql_definitions/fragments/serviceaccount_token.py +5 -5
  153. reconcile/gql_definitions/fragments/terraform_state.py +5 -5
  154. reconcile/gql_definitions/fragments/upgrade_policy.py +5 -5
  155. reconcile/gql_definitions/fragments/user.py +5 -5
  156. reconcile/gql_definitions/fragments/vault_secret.py +5 -5
  157. reconcile/gql_definitions/gcp/gcp_docker_repos.py +5 -5
  158. reconcile/gql_definitions/gcp/gcp_projects.py +5 -5
  159. reconcile/gql_definitions/gitlab_members/gitlab_instances.py +5 -5
  160. reconcile/gql_definitions/gitlab_members/permissions.py +5 -5
  161. reconcile/gql_definitions/glitchtip/glitchtip_instance.py +5 -5
  162. reconcile/gql_definitions/glitchtip/glitchtip_project.py +5 -5
  163. reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +5 -5
  164. reconcile/gql_definitions/integrations/integrations.py +5 -5
  165. reconcile/gql_definitions/introspection.json +2137 -1053
  166. reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +5 -5
  167. reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +5 -5
  168. reconcile/gql_definitions/jira/jira_servers.py +5 -5
  169. reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +9 -5
  170. reconcile/gql_definitions/jumphosts/jumphosts.py +5 -5
  171. reconcile/gql_definitions/ldap_groups/roles.py +5 -5
  172. reconcile/gql_definitions/ldap_groups/settings.py +5 -5
  173. reconcile/gql_definitions/maintenance/maintenances.py +5 -5
  174. reconcile/gql_definitions/membershipsources/roles.py +5 -5
  175. reconcile/gql_definitions/ocm_labels/clusters.py +5 -5
  176. reconcile/gql_definitions/ocm_labels/organizations.py +5 -5
  177. reconcile/gql_definitions/openshift_cluster_bots/clusters.py +5 -5
  178. reconcile/gql_definitions/openshift_groups/managed_groups.py +5 -5
  179. reconcile/gql_definitions/openshift_groups/managed_roles.py +5 -5
  180. reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +5 -5
  181. reconcile/gql_definitions/quay_membership/quay_membership.py +5 -5
  182. reconcile/gql_definitions/rhcs/certs.py +5 -5
  183. reconcile/gql_definitions/rhidp/organizations.py +5 -5
  184. reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +5 -5
  185. reconcile/gql_definitions/service_dependencies/service_dependencies.py +5 -5
  186. reconcile/gql_definitions/sharding/aws_accounts.py +5 -5
  187. reconcile/gql_definitions/sharding/ocm_organization.py +5 -5
  188. reconcile/gql_definitions/skupper_network/site_controller_template.py +5 -5
  189. reconcile/gql_definitions/skupper_network/skupper_networks.py +5 -5
  190. reconcile/gql_definitions/slack_usergroups/clusters.py +5 -5
  191. reconcile/gql_definitions/slack_usergroups/permissions.py +5 -5
  192. reconcile/gql_definitions/slack_usergroups/users.py +5 -5
  193. reconcile/gql_definitions/slo_documents/slo_documents.py +5 -5
  194. reconcile/gql_definitions/status_board/status_board.py +5 -5
  195. reconcile/gql_definitions/statuspage/statuspages.py +5 -5
  196. reconcile/gql_definitions/templating/template_collection.py +5 -5
  197. reconcile/gql_definitions/templating/templates.py +5 -5
  198. reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +5 -5
  199. reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +5 -5
  200. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +5 -5
  201. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +5 -5
  202. reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +5 -5
  203. reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +5 -5
  204. reconcile/gql_definitions/terraform_init/aws_accounts.py +19 -5
  205. reconcile/gql_definitions/terraform_repo/terraform_repo.py +5 -5
  206. reconcile/gql_definitions/terraform_resources/database_access_manager.py +5 -5
  207. reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +38 -6
  208. reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +15 -5
  209. reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +5 -5
  210. reconcile/gql_definitions/vault_instances/vault_instances.py +5 -5
  211. reconcile/gql_definitions/vault_policies/vault_policies.py +5 -5
  212. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +5 -5
  213. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +5 -5
  214. reconcile/integrations_manager.py +3 -3
  215. reconcile/jenkins_worker_fleets.py +10 -8
  216. reconcile/jira_permissions_validator.py +237 -122
  217. reconcile/ldap_groups/integration.py +1 -1
  218. reconcile/ocm/types.py +35 -56
  219. reconcile/ocm_aws_infrastructure_access.py +1 -1
  220. reconcile/ocm_clusters.py +4 -4
  221. reconcile/ocm_labels/integration.py +3 -2
  222. reconcile/ocm_machine_pools.py +23 -23
  223. reconcile/openshift_base.py +53 -2
  224. reconcile/openshift_cluster_bots.py +3 -2
  225. reconcile/openshift_namespace_labels.py +1 -1
  226. reconcile/openshift_namespaces.py +97 -101
  227. reconcile/openshift_resources_base.py +6 -2
  228. reconcile/openshift_rhcs_certs.py +5 -5
  229. reconcile/openshift_rolebindings.py +7 -11
  230. reconcile/openshift_saas_deploy.py +6 -7
  231. reconcile/openshift_saas_deploy_change_tester.py +9 -7
  232. reconcile/openshift_saas_deploy_trigger_cleaner.py +3 -5
  233. reconcile/openshift_serviceaccount_tokens.py +2 -2
  234. reconcile/openshift_upgrade_watcher.py +4 -4
  235. reconcile/oum/labelset.py +5 -3
  236. reconcile/oum/models.py +1 -4
  237. reconcile/prometheus_rules_tester/integration.py +3 -3
  238. reconcile/quay_mirror.py +1 -1
  239. reconcile/queries.py +131 -1
  240. reconcile/rhidp/common.py +3 -5
  241. reconcile/rhidp/sso_client/base.py +1 -1
  242. reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +1 -1
  243. reconcile/saas_auto_promotions_manager/subscriber.py +4 -3
  244. reconcile/skupper_network/integration.py +2 -2
  245. reconcile/slack_usergroups.py +35 -14
  246. reconcile/sql_query.py +1 -0
  247. reconcile/status_board.py +6 -6
  248. reconcile/statuspage/atlassian.py +7 -7
  249. reconcile/statuspage/integrations/maintenances.py +4 -3
  250. reconcile/statuspage/page.py +4 -9
  251. reconcile/statuspage/status.py +5 -8
  252. reconcile/templates/rosa-classic-cluster-creation.sh.j2 +4 -0
  253. reconcile/templates/rosa-hcp-cluster-creation.sh.j2 +3 -0
  254. reconcile/templating/lib/rendering.py +3 -3
  255. reconcile/templating/renderer.py +4 -3
  256. reconcile/terraform_aws_route53.py +7 -1
  257. reconcile/terraform_cloudflare_dns.py +3 -3
  258. reconcile/terraform_cloudflare_resources.py +5 -5
  259. reconcile/terraform_cloudflare_users.py +3 -2
  260. reconcile/terraform_init/integration.py +187 -23
  261. reconcile/terraform_repo.py +16 -12
  262. reconcile/terraform_resources.py +17 -7
  263. reconcile/terraform_tgw_attachments.py +27 -19
  264. reconcile/terraform_users.py +7 -0
  265. reconcile/terraform_vpc_peerings.py +14 -3
  266. reconcile/terraform_vpc_resources/integration.py +10 -1
  267. reconcile/typed_queries/aws_account_tags.py +41 -0
  268. reconcile/typed_queries/cost_report/app_names.py +1 -1
  269. reconcile/typed_queries/cost_report/cost_namespaces.py +2 -2
  270. reconcile/typed_queries/saas_files.py +13 -13
  271. reconcile/typed_queries/status_board.py +2 -2
  272. reconcile/unleash_feature_toggles/integration.py +4 -2
  273. reconcile/utils/acs/base.py +6 -3
  274. reconcile/utils/acs/policies.py +2 -2
  275. reconcile/utils/aggregated_list.py +4 -3
  276. reconcile/utils/aws_api.py +51 -54
  277. reconcile/utils/aws_api_typed/api.py +38 -9
  278. reconcile/utils/aws_api_typed/cloudformation.py +149 -0
  279. reconcile/utils/aws_api_typed/logs.py +73 -0
  280. reconcile/utils/aws_api_typed/organization.py +4 -2
  281. reconcile/utils/datetime_util.py +67 -0
  282. reconcile/utils/deadmanssnitch_api.py +1 -1
  283. reconcile/utils/differ.py +2 -3
  284. reconcile/utils/early_exit_cache.py +11 -12
  285. reconcile/utils/expiration.py +7 -3
  286. reconcile/utils/external_resource_spec.py +24 -1
  287. reconcile/utils/filtering.py +1 -1
  288. reconcile/utils/gitlab_api.py +7 -5
  289. reconcile/utils/glitchtip/client.py +6 -2
  290. reconcile/utils/glitchtip/models.py +25 -28
  291. reconcile/utils/gql.py +4 -7
  292. reconcile/utils/helm.py +2 -1
  293. reconcile/utils/helpers.py +1 -1
  294. reconcile/utils/instrumented_wrappers.py +1 -1
  295. reconcile/utils/internal_groups/client.py +2 -2
  296. reconcile/utils/internal_groups/models.py +8 -17
  297. reconcile/utils/jinja2/utils.py +6 -101
  298. reconcile/utils/jira_client.py +82 -63
  299. reconcile/utils/jjb_client.py +9 -12
  300. reconcile/utils/jobcontroller/controller.py +1 -1
  301. reconcile/utils/jobcontroller/models.py +17 -1
  302. reconcile/utils/json.py +70 -0
  303. reconcile/utils/membershipsources/app_interface_resolver.py +4 -2
  304. reconcile/utils/membershipsources/models.py +16 -23
  305. reconcile/utils/membershipsources/resolver.py +4 -2
  306. reconcile/utils/merge_request_manager/merge_request_manager.py +4 -4
  307. reconcile/utils/merge_request_manager/parser.py +6 -6
  308. reconcile/utils/metrics.py +5 -5
  309. reconcile/utils/models.py +304 -82
  310. reconcile/utils/mr/app_interface_reporter.py +2 -2
  311. reconcile/utils/mr/base.py +2 -2
  312. reconcile/utils/mr/notificator.py +3 -3
  313. reconcile/utils/mr/update_access_report_base.py +3 -4
  314. reconcile/utils/mr/user_maintenance.py +3 -2
  315. reconcile/utils/oc.py +118 -97
  316. reconcile/utils/oc_filters.py +3 -3
  317. reconcile/utils/ocm/addons.py +0 -1
  318. reconcile/utils/ocm/base.py +17 -20
  319. reconcile/utils/ocm/cluster_groups.py +1 -1
  320. reconcile/utils/ocm/identity_providers.py +2 -2
  321. reconcile/utils/ocm/labels.py +1 -1
  322. reconcile/utils/ocm/products.py +9 -3
  323. reconcile/utils/ocm/search_filters.py +3 -6
  324. reconcile/utils/ocm/service_log.py +4 -6
  325. reconcile/utils/ocm/sre_capability_labels.py +20 -13
  326. reconcile/utils/openshift_resource.py +10 -5
  327. reconcile/utils/output.py +3 -2
  328. reconcile/utils/pagerduty_api.py +10 -7
  329. reconcile/utils/promotion_state.py +6 -11
  330. reconcile/utils/raw_github_api.py +1 -1
  331. reconcile/utils/rhcsv2_certs.py +1 -4
  332. reconcile/utils/runtime/integration.py +2 -3
  333. reconcile/utils/runtime/runner.py +2 -2
  334. reconcile/utils/saasherder/interfaces.py +13 -20
  335. reconcile/utils/saasherder/models.py +25 -21
  336. reconcile/utils/saasherder/saasherder.py +35 -24
  337. reconcile/utils/slack_api.py +26 -4
  338. reconcile/utils/sloth.py +171 -2
  339. reconcile/utils/sqs_gateway.py +2 -1
  340. reconcile/utils/state.py +2 -1
  341. reconcile/utils/structs.py +1 -1
  342. reconcile/utils/terraform_client.py +5 -4
  343. reconcile/utils/terrascript_aws_client.py +171 -114
  344. reconcile/utils/unleash/server.py +2 -8
  345. reconcile/utils/vault.py +5 -12
  346. reconcile/utils/vcs.py +8 -8
  347. reconcile/vault_replication.py +107 -42
  348. tools/app_interface_reporter.py +4 -4
  349. tools/cli_commands/cost_report/cost_management_api.py +3 -3
  350. tools/cli_commands/cost_report/view.py +7 -6
  351. tools/cli_commands/erv2.py +3 -1
  352. tools/cli_commands/systems_and_tools.py +5 -1
  353. tools/qontract_cli.py +31 -18
  354. tools/template_validation.py +3 -1
  355. {qontract_reconcile-0.10.2.dev349.dist-info → qontract_reconcile-0.10.2.dev414.dist-info}/WHEEL +0 -0
  356. {qontract_reconcile-0.10.2.dev349.dist-info → qontract_reconcile-0.10.2.dev414.dist-info}/entry_points.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  from typing import Any
2
2
 
3
- from pydantic import Field
4
- from pydantic.fields import ModelField
3
+ from pydantic import WithJsonSchema
4
+ from pydantic.fields import FieldInfo
5
5
 
6
6
  from reconcile.utils.ocm.base import (
7
7
  LabelContainer,
@@ -22,11 +22,11 @@ def sre_capability_label_key(
22
22
  return f"sre-capabilities.{sre_capability}.{config_atom}"
23
23
 
24
24
 
25
- def labelset_groupfield(group_prefix: str) -> Any:
25
+ def labelset_groupfield(group_prefix: str) -> WithJsonSchema:
26
26
  """
27
27
  Helper function to build the FieldMeta for a labelset field that groups labels.
28
28
  """
29
- return Field(group_by_prefix=group_prefix)
29
+ return WithJsonSchema({"group_by_prefix": group_prefix})
30
30
 
31
31
 
32
32
  def build_labelset(
@@ -36,16 +36,23 @@ def build_labelset(
36
36
  Instantiates a dataclass from a set of labels.
37
37
  """
38
38
  raw_data = {
39
- field.alias: _labelset_field_value(labels, field)
40
- for field in dataclass.__fields__.values()
39
+ field.alias or name: _labelset_field_value(labels, name, field)
40
+ for name, field in dataclass.model_fields.items()
41
41
  }
42
42
  return dataclass(**raw_data)
43
43
 
44
44
 
45
- def _labelset_field_value(labels: LabelContainer, field: ModelField) -> Any | None:
46
- key_prefix = field.field_info.extra.get("group_by_prefix")
47
- if key_prefix:
48
- return build_container_for_prefix(
49
- labels, key_prefix, strip_key_prefix=True
50
- ).get_values_dict()
51
- return labels.get_label_value(field.alias)
45
+ def _labelset_field_value(
46
+ labels: LabelContainer, name: str, field: FieldInfo
47
+ ) -> Any | None:
48
+ schema = next((m for m in field.metadata if isinstance(m, WithJsonSchema)), None)
49
+ if (
50
+ schema is None
51
+ or not schema.json_schema
52
+ or "group_by_prefix" not in schema.json_schema
53
+ ):
54
+ return labels.get_label_value(field.alias or name)
55
+
56
+ return build_container_for_prefix(
57
+ labels, schema.json_schema["group_by_prefix"], strip_key_prefix=True
58
+ ).get_values_dict()
@@ -4,9 +4,8 @@ from __future__ import annotations
4
4
  import base64
5
5
  import contextlib
6
6
  import copy
7
- import datetime
8
7
  import hashlib
9
- import json
8
+ import logging
10
9
  import re
11
10
  from threading import Lock
12
11
  from typing import TYPE_CHECKING, Any
@@ -15,6 +14,8 @@ import semver
15
14
  from pydantic import BaseModel
16
15
 
17
16
  from reconcile.external_resources.meta import SECRET_UPDATED_AT
17
+ from reconcile.utils.datetime_util import to_utc_seconds_iso_format, utc_now
18
+ from reconcile.utils.json import json_dumps
18
19
  from reconcile.utils.metrics import GaugeMetric
19
20
 
20
21
  if TYPE_CHECKING:
@@ -368,8 +369,8 @@ class OpenshiftResource:
368
369
  annotations[QONTRACT_ANNOTATION_INTEGRATION] = self.integration
369
370
  annotations[QONTRACT_ANNOTATION_INTEGRATION_VERSION] = self.integration_version
370
371
  annotations[QONTRACT_ANNOTATION_SHA256SUM] = sha256sum
371
- now = datetime.datetime.utcnow().replace(microsecond=0).isoformat()
372
- annotations[QONTRACT_ANNOTATION_UPDATE] = now
372
+ now = utc_now()
373
+ annotations[QONTRACT_ANNOTATION_UPDATE] = to_utc_seconds_iso_format(now)
373
374
  if self.caller_name:
374
375
  annotations[QONTRACT_ANNOTATION_CALLER_NAME] = self.caller_name
375
376
 
@@ -530,7 +531,7 @@ class OpenshiftResource:
530
531
 
531
532
  @staticmethod
532
533
  def serialize(body: dict[str, Any]) -> str:
533
- return json.dumps(body, sort_keys=True)
534
+ return json_dumps(body)
534
535
 
535
536
  @staticmethod
536
537
  def calculate_sha256sum(body: str) -> str:
@@ -601,6 +602,10 @@ class ResourceInventory:
601
602
  resource: OpenshiftResource,
602
603
  privileged: bool = False,
603
604
  ) -> None:
605
+ if cluster not in self._clusters:
606
+ logging.error(f"Cluster {cluster} not initialized in ResourceInventory")
607
+ return
608
+
604
609
  if resource.kind_and_group in self._clusters[cluster][namespace]:
605
610
  kind = resource.kind_and_group
606
611
  else:
reconcile/utils/output.py CHANGED
@@ -1,10 +1,11 @@
1
- import json
2
1
  import re
3
2
  from collections.abc import Iterable, Mapping
4
3
 
5
4
  import yaml
6
5
  from tabulate import tabulate
7
6
 
7
+ from reconcile.utils.json import json_dumps
8
+
8
9
 
9
10
  def print_output(
10
11
  options: Mapping[str, str | bool],
@@ -30,7 +31,7 @@ def print_output(
30
31
  )
31
32
  print(formatted_content)
32
33
  elif output == "json":
33
- formatted_content = json.dumps(content)
34
+ formatted_content = json_dumps(content)
34
35
  print(formatted_content)
35
36
  elif output == "yaml":
36
37
  formatted_content = yaml.dump(content)
@@ -3,8 +3,7 @@ from collections.abc import (
3
3
  Callable,
4
4
  Iterable,
5
5
  )
6
- from datetime import datetime as dt
7
- from datetime import timedelta
6
+ from datetime import datetime, timedelta
8
7
  from typing import (
9
8
  Protocol,
10
9
  )
@@ -14,6 +13,7 @@ import requests
14
13
  from pydantic import BaseModel
15
14
  from sretoolbox.utils import retry
16
15
 
16
+ from reconcile.utils.datetime_util import utc_now
17
17
  from reconcile.utils.secret_reader import (
18
18
  HasSecret,
19
19
  SecretReader,
@@ -52,10 +52,13 @@ class PagerDutyTarget(Protocol):
52
52
  which must be implemented by a class to be compatible."""
53
53
 
54
54
  name: str
55
- instance: PagerDutyInstance
56
55
  escalation_policy_id: str | None
57
56
  schedule_id: str | None
58
57
 
58
+ @property
59
+ def instance(self) -> PagerDutyInstance:
60
+ pass
61
+
59
62
 
60
63
  class PagerDutyConfig(BaseModel):
61
64
  """PagerDuty Config."""
@@ -80,7 +83,7 @@ class PagerDutyApi:
80
83
  def get_pagerduty_users(
81
84
  self, resource_type: str, resource_id: str
82
85
  ) -> list[pypd.User]:
83
- now = dt.utcnow()
86
+ now = utc_now()
84
87
 
85
88
  try:
86
89
  if resource_type == "schedule":
@@ -103,7 +106,7 @@ class PagerDutyApi:
103
106
  self.users.append(user)
104
107
  return user.email.split("@")[0]
105
108
 
106
- def get_schedule_users(self, schedule_id: str, now: dt) -> list[pypd.User]:
109
+ def get_schedule_users(self, schedule_id: str, now: datetime) -> list[pypd.User]:
107
110
  until = now + timedelta(seconds=60)
108
111
  s = pypd.Schedule.fetch(id=schedule_id, since=now, until=until, time_zone="UTC")
109
112
  entries = s["final_schedule"]["rendered_schedule_entries"]
@@ -115,7 +118,7 @@ class PagerDutyApi:
115
118
  ]
116
119
 
117
120
  def get_escalation_policy_users(
118
- self, escalation_policy_id: str, now: dt
121
+ self, escalation_policy_id: str, now: datetime
119
122
  ) -> list[pypd.User]:
120
123
  ep = pypd.EscalationPolicy.fetch(
121
124
  id=escalation_policy_id, since=now, until=now, time_zone="UTC"
@@ -189,7 +192,7 @@ def get_pagerduty_name(user: PagerDutyUser) -> str:
189
192
  return user.pagerduty_username or user.org_username
190
193
 
191
194
 
192
- @retry(no_retry_exceptions=PagerDutyTargetError)
195
+ @retry(no_retry_exceptions=(PagerDutyTargetError,))
193
196
  def get_usernames_from_pagerduty(
194
197
  pagerduties: Iterable[PagerDutyTarget],
195
198
  users: Iterable[PagerDutyUser],
@@ -3,13 +3,12 @@ from collections import defaultdict
3
3
 
4
4
  from pydantic import (
5
5
  BaseModel,
6
- Extra,
7
6
  )
8
7
 
9
8
  from reconcile.utils.state import State
10
9
 
11
10
 
12
- class PromotionData(BaseModel):
11
+ class PromotionData(BaseModel, extra="forbid"):
13
12
  """
14
13
  A class that strictly corresponds to the json stored in S3.
15
14
 
@@ -20,17 +19,13 @@ class PromotionData(BaseModel):
20
19
 
21
20
  # The success is primarily used for SAPM auto-promotions
22
21
  success: bool
23
- target_config_hash: str | None
24
- saas_file: str | None
25
- check_in: str | None
22
+ target_config_hash: str | None = None
23
+ saas_file: str | None = None
24
+ check_in: str | None = None
26
25
  # Whether this promotion has ever succeeded
27
26
  # Note, this shouldnt be overridden on subsequent promotions of same ref
28
27
  # This attribute is primarily used by saasherder validations
29
- has_succeeded_once: bool | None
30
-
31
- class Config:
32
- smart_union = True
33
- extra = Extra.forbid
28
+ has_succeeded_once: bool | None = None
34
29
 
35
30
 
36
31
  class PromotionState:
@@ -107,5 +102,5 @@ class PromotionState:
107
102
  self, sha: str, channel: str, target_uid: str, data: PromotionData
108
103
  ) -> None:
109
104
  state_key_v2 = f"promotions_v2/{channel}/{target_uid}/{sha}"
110
- self._state.add(state_key_v2, data.dict(), force=True)
105
+ self._state.add(state_key_v2, data.model_dump(), force=True)
111
106
  logging.info("Uploaded %s to %s", data, state_key_v2)
@@ -76,7 +76,7 @@ class RawGithubApi:
76
76
  if login is not None
77
77
  ]
78
78
 
79
- def team_invitations(self, org_id: str, team_id: str) -> list[str]:
79
+ def team_invitations(self, org_id: str | int, team_id: str | int) -> list[str]:
80
80
  invitations = self.query(f"/organizations/{org_id}/team/{team_id}/invitations")
81
81
 
82
82
  return [
@@ -9,15 +9,12 @@ from cryptography.x509.oid import NameOID
9
9
  from pydantic import BaseModel, Field
10
10
 
11
11
 
12
- class RhcsV2Cert(BaseModel):
12
+ class RhcsV2Cert(BaseModel, validate_by_name=True, validate_by_alias=True):
13
13
  certificate: str = Field(alias="tls.crt")
14
14
  private_key: str = Field(alias="tls.key")
15
15
  ca_cert: str = Field(alias="ca.crt")
16
16
  expiration_timestamp: int
17
17
 
18
- class Config:
19
- allow_population_by_field_name = True
20
-
21
18
 
22
19
  def extract_cert(text: str) -> re.Match:
23
20
  # The CA webform returns an HTML page with inline JS that builds an array of “outputList”
@@ -7,7 +7,6 @@ from dataclasses import dataclass
7
7
  from types import ModuleType
8
8
  from typing import (
9
9
  Any,
10
- Generic,
11
10
  Optional,
12
11
  TypeVar,
13
12
  )
@@ -120,7 +119,7 @@ class PydanticRunParams(RunParams, BaseModel):
120
119
  def copy_and_update(
121
120
  self: PydanticRunParamsSelfTypeVar, update: dict[str, Any]
122
121
  ) -> PydanticRunParamsSelfTypeVar:
123
- return self.copy(update=update)
122
+ return self.model_copy(update=update)
124
123
 
125
124
  def get(self, field: str) -> Any:
126
125
  return getattr(self, field)
@@ -144,7 +143,7 @@ IntegrationClassTypeVar = TypeVar(
144
143
  )
145
144
 
146
145
 
147
- class QontractReconcileIntegration(ABC, Generic[RunParamsTypeVar]):
146
+ class QontractReconcileIntegration[RunParamsTypeVar: RunParams](ABC):
148
147
  """
149
148
  The base class for all integrations. It defines the basic interface to interact
150
149
  with an integration and offers hook methods that allow the integration to opt
@@ -156,7 +156,7 @@ def run_integration_cfg(run_cfg: IntegrationRunConfiguration) -> None:
156
156
  _integration_wet_run(run_cfg.integration)
157
157
 
158
158
 
159
- def _integration_wet_run(
159
+ def _integration_wet_run[RunParamsTypeVar: RunParams](
160
160
  integration: QontractReconcileIntegration[RunParamsTypeVar],
161
161
  ) -> None:
162
162
  """
@@ -165,7 +165,7 @@ def _integration_wet_run(
165
165
  integration.run(False)
166
166
 
167
167
 
168
- def _integration_dry_run(
168
+ def _integration_dry_run[RunParamsTypeVar: RunParams](
169
169
  integration: QontractReconcileIntegration[RunParamsTypeVar],
170
170
  desired_state_diff: DesiredStateDiff | None,
171
171
  ) -> None:
@@ -1,7 +1,7 @@
1
1
  # ruff: noqa: N801
2
2
  from __future__ import annotations
3
3
 
4
- from collections.abc import Mapping, Sequence, Set
4
+ from collections.abc import Sequence
5
5
  from typing import (
6
6
  TYPE_CHECKING,
7
7
  Any,
@@ -12,6 +12,8 @@ from typing import (
12
12
  from reconcile.utils import oc_connection_parameters
13
13
 
14
14
  if TYPE_CHECKING:
15
+ from pydantic.main import IncEx
16
+
15
17
  from reconcile.gql_definitions.fragments.saas_slo_document import SLODocument
16
18
  from reconcile.utils.secret_reader import HasSecret
17
19
 
@@ -27,18 +29,12 @@ class SaasFileSecretParameters(Protocol):
27
29
  @property
28
30
  def secret(self) -> HasSecret: ...
29
31
 
30
- def dict(
31
- self,
32
- *,
33
- by_alias: bool = False,
34
- include: AbstractSetIntStr | MappingIntStrAny | None = None,
32
+ def model_dump(
33
+ self, *, by_alias: bool = False, include: IncEx | None = None
35
34
  ) -> dict[str, Any]: ...
36
35
 
37
36
 
38
37
  SaasSecretParameters = Sequence[SaasFileSecretParameters] | None
39
- # Taken from pydantic.typing
40
- AbstractSetIntStr = Set[int | str]
41
- MappingIntStrAny = Mapping[int | str, Any]
42
38
 
43
39
 
44
40
  @runtime_checkable
@@ -212,11 +208,8 @@ class SaasResourceTemplateTargetNamespace(Protocol):
212
208
  @property
213
209
  def cluster(self) -> oc_connection_parameters.Cluster: ...
214
210
 
215
- def dict(
216
- self,
217
- *,
218
- by_alias: bool = False,
219
- include: AbstractSetIntStr | MappingIntStrAny | None = None,
211
+ def model_dump(
212
+ self, *, by_alias: bool = False, include: IncEx | None = None
220
213
  ) -> dict[str, Any]: ...
221
214
 
222
215
 
@@ -249,7 +242,7 @@ class SaasResourceTemplateTargetPromotion(Protocol):
249
242
  @property
250
243
  def promotion_data(self) -> Sequence[SaasPromotionData] | None: ...
251
244
 
252
- def dict(self, *, by_alias: bool = False) -> dict[str, Any]: ...
245
+ def model_dump(self, *, by_alias: bool = False) -> dict[str, Any]: ...
253
246
 
254
247
 
255
248
  class Channel(Protocol):
@@ -274,7 +267,7 @@ class SaasPromotion(Protocol):
274
267
  @property
275
268
  def subscribe(self) -> list[Channel] | None: ...
276
269
 
277
- def dict(self, *, by_alias: bool = False) -> dict[str, Any]: ...
270
+ def model_dump(self, *, by_alias: bool = False) -> dict[str, Any]: ...
278
271
 
279
272
 
280
273
  class SaasResourceTemplateTarget_SaasSecretParameters(Protocol):
@@ -295,7 +288,7 @@ class SaasResourceTemplateTargetUpstream(Protocol):
295
288
  @property
296
289
  def instance(self) -> SaasJenkinsInstance: ...
297
290
 
298
- def dict(self, *, by_alias: bool = False) -> dict[str, Any]: ...
291
+ def model_dump(self, *, by_alias: bool = False) -> dict[str, Any]: ...
299
292
 
300
293
 
301
294
  class SaasQuayInstance(Protocol):
@@ -315,7 +308,7 @@ class SaasResourceTemplateTargetImage(Protocol):
315
308
  @property
316
309
  def org(self) -> SaasQuayOrg: ...
317
310
 
318
- def dict(self, *, by_alias: bool = False) -> dict[str, Any]: ...
311
+ def model_dump(self, *, by_alias: bool = False) -> dict[str, Any]: ...
319
312
 
320
313
 
321
314
  class SaasResourceTemplateTarget(HasParameters, HasSecretParameters, Protocol):
@@ -344,7 +337,7 @@ class SaasResourceTemplateTarget(HasParameters, HasSecretParameters, Protocol):
344
337
  self, parent_saas_file_name: str, parent_resource_template_name: str
345
338
  ) -> str: ...
346
339
 
347
- def dict(self, *, by_alias: bool = False) -> dict[str, Any]: ...
340
+ def model_dump(self, *, by_alias: bool = False) -> dict[str, Any]: ...
348
341
 
349
342
 
350
343
  class SaasResourceTemplate(HasParameters, HasSecretParameters, Protocol):
@@ -381,7 +374,7 @@ class ManagedResourceName(Protocol):
381
374
  resource: str
382
375
  resource_names: list[str]
383
376
 
384
- def dict(self) -> dict[str, str]: ...
377
+ def model_dump(self) -> dict[str, str]: ...
385
378
 
386
379
 
387
380
  class SaasFile(HasParameters, HasSecretParameters, Protocol):
@@ -7,15 +7,13 @@ from enum import Enum
7
7
  from typing import Any, NotRequired, TypedDict
8
8
 
9
9
  from github import Github
10
- from pydantic import (
11
- BaseModel,
12
- Field,
13
- )
10
+ from pydantic import BaseModel, Field, model_validator
14
11
 
15
12
  from reconcile.gql_definitions.fragments.saas_slo_document import (
16
13
  SLODocument,
17
14
  )
18
15
  from reconcile.utils.jenkins_api import JobBuildState
16
+ from reconcile.utils.json import json_dumps
19
17
  from reconcile.utils.oc_connection_parameters import Cluster
20
18
  from reconcile.utils.saasherder.interfaces import (
21
19
  HasParameters,
@@ -206,7 +204,12 @@ TriggerSpecUnion = (
206
204
  )
207
205
 
208
206
 
209
- class Namespace(BaseModel):
207
+ class Namespace(
208
+ BaseModel,
209
+ validate_by_name=True,
210
+ validate_by_alias=True,
211
+ arbitrary_types_allowed=True,
212
+ ):
210
213
  name: str
211
214
  environment: SaasEnvironment
212
215
  app: SaasApp
@@ -216,29 +219,19 @@ class Namespace(BaseModel):
216
219
  ..., alias="managedResourceNames"
217
220
  )
218
221
 
219
- class Config:
220
- arbitrary_types_allowed = True
221
- allow_population_by_field_name = True
222
-
223
222
 
224
- class PromotionChannelData(BaseModel):
223
+ class PromotionChannelData(BaseModel, validate_by_name=True, validate_by_alias=True):
225
224
  q_type: str = Field(..., alias="type")
226
225
 
227
- class Config:
228
- allow_population_by_field_name = True
229
226
 
230
-
231
- class ParentSaasPromotion(BaseModel):
227
+ class ParentSaasPromotion(BaseModel, validate_by_name=True, validate_by_alias=True):
232
228
  q_type: str = Field(..., alias="type")
233
- parent_saas: str | None
234
- target_config_hash: str | None
235
-
236
- class Config:
237
- allow_population_by_field_name = True
229
+ parent_saas: str | None = None
230
+ target_config_hash: str | None = None
238
231
 
239
232
 
240
233
  class PromotionData(BaseModel):
241
- channel: str | None
234
+ channel: str | None = None
242
235
  data: list[ParentSaasPromotion | PromotionChannelData] | None = None
243
236
 
244
237
 
@@ -263,6 +256,17 @@ class Promotion(BaseModel):
263
256
  saas_file_paths: list[str] | None = None
264
257
  target_paths: list[str] | None = None
265
258
 
259
+ @model_validator(mode="before")
260
+ @classmethod
261
+ def handle_gql_classes(cls, data: Any) -> Any:
262
+ if data.get("promotion_data"):
263
+ data["promotion_data"] = [
264
+ # convert a GQL class to a dict
265
+ item.model_dump() if hasattr(item, "model_dump") else item
266
+ for item in data["promotion_data"]
267
+ ]
268
+ return data
269
+
266
270
 
267
271
  @dataclass
268
272
  class ImageAuth:
@@ -422,7 +426,7 @@ class TargetSpec:
422
426
  elif v is False:
423
427
  parameters[k] = "false"
424
428
  elif any(isinstance(v, t) for t in [dict, list, tuple]):
425
- parameters[k] = json.dumps(v)
429
+ parameters[k] = json_dumps(v)
426
430
  return parameters
427
431
 
428
432
  def _collect_secret_parameters(