qontract-reconcile 0.10.2.dev361__py3-none-any.whl → 0.10.2.dev430__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 (351) hide show
  1. {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/METADATA +13 -12
  2. {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/RECORD +351 -345
  3. reconcile/acs_rbac.py +2 -2
  4. reconcile/aus/advanced_upgrade_service.py +18 -12
  5. reconcile/aus/base.py +134 -32
  6. reconcile/aus/cluster_version_data.py +15 -5
  7. reconcile/aus/models.py +3 -1
  8. reconcile/aus/ocm_addons_upgrade_scheduler_org.py +1 -0
  9. reconcile/aus/ocm_upgrade_scheduler.py +8 -1
  10. reconcile/aus/ocm_upgrade_scheduler_org.py +20 -5
  11. reconcile/aus/version_gates/sts_version_gate_handler.py +54 -1
  12. reconcile/automated_actions/config/integration.py +16 -4
  13. reconcile/aws_account_manager/integration.py +8 -8
  14. reconcile/aws_account_manager/reconciler.py +3 -3
  15. reconcile/aws_ami_cleanup/integration.py +8 -12
  16. reconcile/aws_ami_share.py +69 -62
  17. reconcile/aws_cloudwatch_log_retention/integration.py +155 -126
  18. reconcile/aws_iam_keys.py +1 -0
  19. reconcile/aws_saml_idp/integration.py +12 -4
  20. reconcile/aws_saml_roles/integration.py +30 -23
  21. reconcile/aws_version_sync/integration.py +6 -12
  22. reconcile/change_owners/bundle.py +3 -3
  23. reconcile/change_owners/change_log_tracking.py +3 -2
  24. reconcile/change_owners/change_owners.py +1 -1
  25. reconcile/change_owners/diff.py +0 -2
  26. reconcile/checkpoint.py +11 -3
  27. reconcile/cli.py +93 -10
  28. reconcile/dashdotdb_dora.py +5 -12
  29. reconcile/dashdotdb_slo.py +1 -1
  30. reconcile/database_access_manager.py +123 -117
  31. reconcile/dynatrace_token_provider/integration.py +1 -1
  32. reconcile/endpoints_discovery/integration.py +4 -1
  33. reconcile/endpoints_discovery/merge_request.py +1 -1
  34. reconcile/endpoints_discovery/merge_request_manager.py +8 -8
  35. reconcile/external_resources/factories.py +4 -6
  36. reconcile/external_resources/integration.py +1 -1
  37. reconcile/external_resources/manager.py +8 -6
  38. reconcile/external_resources/meta.py +0 -1
  39. reconcile/external_resources/metrics.py +1 -1
  40. reconcile/external_resources/model.py +19 -15
  41. reconcile/external_resources/reconciler.py +7 -4
  42. reconcile/external_resources/secrets_sync.py +4 -7
  43. reconcile/external_resources/state.py +26 -16
  44. reconcile/fleet_labeler/integration.py +1 -1
  45. reconcile/gabi_authorized_users.py +5 -2
  46. reconcile/gcp_image_mirror.py +2 -2
  47. reconcile/github_org.py +1 -1
  48. reconcile/github_owners.py +4 -0
  49. reconcile/gitlab_housekeeping.py +13 -15
  50. reconcile/gitlab_members.py +6 -12
  51. reconcile/gitlab_owners.py +15 -11
  52. reconcile/gitlab_permissions.py +8 -12
  53. reconcile/glitchtip_project_alerts/integration.py +3 -1
  54. reconcile/gql_definitions/acs/acs_instances.py +5 -5
  55. reconcile/gql_definitions/acs/acs_policies.py +5 -5
  56. reconcile/gql_definitions/acs/acs_rbac.py +5 -5
  57. reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +5 -5
  58. reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +5 -5
  59. reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +5 -5
  60. reconcile/gql_definitions/app_sre_tekton_access_revalidation/roles.py +5 -5
  61. reconcile/gql_definitions/app_sre_tekton_access_revalidation/users.py +5 -5
  62. reconcile/gql_definitions/automated_actions/instance.py +46 -7
  63. reconcile/gql_definitions/aws_account_manager/aws_accounts.py +5 -5
  64. reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +15 -5
  65. reconcile/gql_definitions/aws_cloudwatch_log_retention/aws_accounts.py +27 -66
  66. reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +15 -5
  67. reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +15 -5
  68. reconcile/gql_definitions/aws_saml_roles/roles.py +5 -5
  69. reconcile/gql_definitions/aws_version_sync/clusters.py +5 -5
  70. reconcile/gql_definitions/aws_version_sync/namespaces.py +5 -5
  71. reconcile/gql_definitions/change_owners/queries/change_types.py +5 -5
  72. reconcile/gql_definitions/change_owners/queries/self_service_roles.py +5 -5
  73. reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +5 -5
  74. reconcile/gql_definitions/common/alerting_services_settings.py +5 -5
  75. reconcile/gql_definitions/common/app_code_component_repos.py +5 -5
  76. reconcile/gql_definitions/common/app_interface_custom_messages.py +5 -5
  77. reconcile/gql_definitions/common/app_interface_dms_settings.py +5 -5
  78. reconcile/gql_definitions/common/app_interface_repo_settings.py +5 -5
  79. reconcile/gql_definitions/common/app_interface_roles.py +5 -5
  80. reconcile/gql_definitions/common/app_interface_state_settings.py +5 -5
  81. reconcile/gql_definitions/common/app_interface_vault_settings.py +5 -5
  82. reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +5 -5
  83. reconcile/gql_definitions/common/apps.py +5 -5
  84. reconcile/gql_definitions/common/aws_vpc_requests.py +15 -5
  85. reconcile/gql_definitions/common/aws_vpcs.py +5 -5
  86. reconcile/gql_definitions/common/clusters.py +5 -5
  87. reconcile/gql_definitions/common/clusters_minimal.py +5 -5
  88. reconcile/gql_definitions/common/clusters_with_dms.py +5 -5
  89. reconcile/gql_definitions/common/clusters_with_peering.py +5 -5
  90. reconcile/gql_definitions/common/github_orgs.py +5 -5
  91. reconcile/gql_definitions/common/jira_settings.py +5 -5
  92. reconcile/gql_definitions/common/jiralert_settings.py +5 -5
  93. reconcile/gql_definitions/common/ldap_settings.py +5 -5
  94. reconcile/gql_definitions/common/namespaces.py +5 -5
  95. reconcile/gql_definitions/common/namespaces_minimal.py +7 -5
  96. reconcile/gql_definitions/common/ocm_env_telemeter.py +5 -5
  97. reconcile/gql_definitions/common/ocm_environments.py +5 -5
  98. reconcile/gql_definitions/common/pagerduty_instances.py +5 -5
  99. reconcile/gql_definitions/common/pgp_reencryption_settings.py +5 -5
  100. reconcile/gql_definitions/common/pipeline_providers.py +5 -5
  101. reconcile/gql_definitions/common/quay_instances.py +5 -5
  102. reconcile/gql_definitions/common/quay_orgs.py +5 -5
  103. reconcile/gql_definitions/common/reserved_networks.py +5 -5
  104. reconcile/gql_definitions/common/rhcs_provider_settings.py +5 -5
  105. reconcile/gql_definitions/common/saas_files.py +5 -5
  106. reconcile/gql_definitions/common/saas_target_namespaces.py +5 -5
  107. reconcile/gql_definitions/common/saasherder_settings.py +5 -5
  108. reconcile/gql_definitions/common/slack_workspaces.py +5 -5
  109. reconcile/gql_definitions/common/smtp_client_settings.py +5 -5
  110. reconcile/gql_definitions/common/state_aws_account.py +5 -5
  111. reconcile/gql_definitions/common/users.py +5 -5
  112. reconcile/gql_definitions/common/users_with_paths.py +5 -5
  113. reconcile/gql_definitions/cost_report/app_names.py +5 -5
  114. reconcile/gql_definitions/cost_report/cost_namespaces.py +5 -5
  115. reconcile/gql_definitions/cost_report/settings.py +5 -5
  116. reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +5 -5
  117. reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +5 -5
  118. reconcile/gql_definitions/dynatrace_token_provider/token_specs.py +5 -5
  119. reconcile/gql_definitions/email_sender/apps.py +5 -5
  120. reconcile/gql_definitions/email_sender/emails.py +5 -5
  121. reconcile/gql_definitions/email_sender/users.py +5 -5
  122. reconcile/gql_definitions/endpoints_discovery/apps.py +5 -5
  123. reconcile/gql_definitions/external_resources/aws_accounts.py +5 -5
  124. reconcile/gql_definitions/external_resources/external_resources_modules.py +5 -5
  125. reconcile/gql_definitions/external_resources/external_resources_namespaces.py +33 -6
  126. reconcile/gql_definitions/external_resources/external_resources_settings.py +5 -5
  127. reconcile/gql_definitions/external_resources/fragments/external_resources_module_overrides.py +5 -5
  128. reconcile/gql_definitions/fleet_labeler/fleet_labels.py +5 -5
  129. reconcile/gql_definitions/fragments/aus_organization.py +5 -5
  130. reconcile/gql_definitions/fragments/aws_account_common.py +7 -5
  131. reconcile/gql_definitions/fragments/aws_account_managed.py +5 -5
  132. reconcile/gql_definitions/fragments/aws_account_sso.py +5 -5
  133. reconcile/gql_definitions/fragments/aws_infra_management_account.py +5 -5
  134. reconcile/gql_definitions/fragments/aws_organization.py +33 -0
  135. reconcile/gql_definitions/fragments/aws_vpc.py +5 -5
  136. reconcile/gql_definitions/fragments/aws_vpc_request.py +7 -5
  137. reconcile/gql_definitions/fragments/container_image_mirror.py +5 -5
  138. reconcile/gql_definitions/fragments/deploy_resources.py +5 -5
  139. reconcile/gql_definitions/fragments/disable.py +5 -5
  140. reconcile/gql_definitions/fragments/email_service.py +5 -5
  141. reconcile/gql_definitions/fragments/email_user.py +5 -5
  142. reconcile/gql_definitions/fragments/jumphost_common_fields.py +5 -5
  143. reconcile/gql_definitions/fragments/membership_source.py +5 -5
  144. reconcile/gql_definitions/fragments/minimal_ocm_organization.py +5 -5
  145. reconcile/gql_definitions/fragments/oc_connection_cluster.py +5 -5
  146. reconcile/gql_definitions/fragments/ocm_environment.py +5 -5
  147. reconcile/gql_definitions/fragments/pipeline_provider_retention.py +5 -5
  148. reconcile/gql_definitions/fragments/prometheus_instance.py +5 -5
  149. reconcile/gql_definitions/fragments/resource_limits_requirements.py +5 -5
  150. reconcile/gql_definitions/fragments/resource_requests_requirements.py +5 -5
  151. reconcile/gql_definitions/fragments/resource_values.py +5 -5
  152. reconcile/gql_definitions/fragments/saas_slo_document.py +5 -5
  153. reconcile/gql_definitions/fragments/saas_target_namespace.py +5 -5
  154. reconcile/gql_definitions/fragments/serviceaccount_token.py +5 -5
  155. reconcile/gql_definitions/fragments/terraform_state.py +5 -5
  156. reconcile/gql_definitions/fragments/upgrade_policy.py +5 -5
  157. reconcile/gql_definitions/fragments/user.py +5 -5
  158. reconcile/gql_definitions/fragments/vault_secret.py +5 -5
  159. reconcile/gql_definitions/gcp/gcp_docker_repos.py +5 -5
  160. reconcile/gql_definitions/gcp/gcp_projects.py +5 -5
  161. reconcile/gql_definitions/gitlab_members/gitlab_instances.py +5 -5
  162. reconcile/gql_definitions/gitlab_members/permissions.py +5 -5
  163. reconcile/gql_definitions/glitchtip/glitchtip_instance.py +5 -5
  164. reconcile/gql_definitions/glitchtip/glitchtip_project.py +5 -5
  165. reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +5 -5
  166. reconcile/gql_definitions/integrations/integrations.py +5 -5
  167. reconcile/gql_definitions/introspection.json +724 -129
  168. reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +5 -5
  169. reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +5 -5
  170. reconcile/gql_definitions/jira/jira_servers.py +5 -5
  171. reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +9 -5
  172. reconcile/gql_definitions/jumphosts/jumphosts.py +5 -5
  173. reconcile/gql_definitions/ldap_groups/roles.py +5 -5
  174. reconcile/gql_definitions/ldap_groups/settings.py +5 -5
  175. reconcile/gql_definitions/maintenance/maintenances.py +5 -5
  176. reconcile/gql_definitions/membershipsources/roles.py +5 -5
  177. reconcile/gql_definitions/ocm_labels/clusters.py +5 -5
  178. reconcile/gql_definitions/ocm_labels/organizations.py +5 -5
  179. reconcile/gql_definitions/openshift_cluster_bots/clusters.py +5 -5
  180. reconcile/gql_definitions/openshift_groups/managed_groups.py +5 -5
  181. reconcile/gql_definitions/openshift_groups/managed_roles.py +5 -5
  182. reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +5 -5
  183. reconcile/gql_definitions/quay_membership/quay_membership.py +5 -5
  184. reconcile/gql_definitions/rhcs/certs.py +25 -79
  185. reconcile/gql_definitions/rhcs/openshift_resource_rhcs_cert.py +43 -0
  186. reconcile/gql_definitions/rhidp/organizations.py +5 -5
  187. reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +5 -5
  188. reconcile/gql_definitions/service_dependencies/service_dependencies.py +5 -5
  189. reconcile/gql_definitions/sharding/aws_accounts.py +5 -5
  190. reconcile/gql_definitions/sharding/ocm_organization.py +5 -5
  191. reconcile/gql_definitions/skupper_network/site_controller_template.py +5 -5
  192. reconcile/gql_definitions/skupper_network/skupper_networks.py +5 -5
  193. reconcile/gql_definitions/slack_usergroups/clusters.py +5 -5
  194. reconcile/gql_definitions/slack_usergroups/permissions.py +5 -5
  195. reconcile/gql_definitions/slack_usergroups/users.py +5 -5
  196. reconcile/gql_definitions/slo_documents/slo_documents.py +5 -5
  197. reconcile/gql_definitions/status_board/status_board.py +5 -5
  198. reconcile/gql_definitions/statuspage/statuspages.py +5 -5
  199. reconcile/gql_definitions/templating/template_collection.py +5 -5
  200. reconcile/gql_definitions/templating/templates.py +5 -5
  201. reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +5 -5
  202. reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +5 -5
  203. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +5 -5
  204. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +5 -5
  205. reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +5 -5
  206. reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +5 -5
  207. reconcile/gql_definitions/terraform_init/aws_accounts.py +19 -5
  208. reconcile/gql_definitions/terraform_repo/terraform_repo.py +5 -5
  209. reconcile/gql_definitions/terraform_resources/database_access_manager.py +5 -5
  210. reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +30 -6
  211. reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +15 -5
  212. reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +5 -5
  213. reconcile/gql_definitions/vault_instances/vault_instances.py +5 -5
  214. reconcile/gql_definitions/vault_policies/vault_policies.py +5 -5
  215. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +5 -5
  216. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +5 -5
  217. reconcile/integrations_manager.py +3 -3
  218. reconcile/jenkins_worker_fleets.py +10 -8
  219. reconcile/jira_permissions_validator.py +237 -122
  220. reconcile/ldap_groups/integration.py +1 -1
  221. reconcile/ocm/types.py +35 -57
  222. reconcile/ocm_aws_infrastructure_access.py +1 -1
  223. reconcile/ocm_clusters.py +4 -4
  224. reconcile/ocm_labels/integration.py +3 -2
  225. reconcile/ocm_machine_pools.py +33 -27
  226. reconcile/openshift_base.py +113 -4
  227. reconcile/openshift_cluster_bots.py +1 -1
  228. reconcile/openshift_namespace_labels.py +1 -1
  229. reconcile/openshift_namespaces.py +97 -101
  230. reconcile/openshift_resources_base.py +6 -2
  231. reconcile/openshift_rhcs_certs.py +74 -37
  232. reconcile/openshift_rolebindings.py +7 -11
  233. reconcile/openshift_saas_deploy.py +4 -5
  234. reconcile/openshift_saas_deploy_change_tester.py +9 -7
  235. reconcile/openshift_saas_deploy_trigger_cleaner.py +3 -5
  236. reconcile/openshift_serviceaccount_tokens.py +2 -2
  237. reconcile/openshift_upgrade_watcher.py +4 -4
  238. reconcile/oum/labelset.py +5 -3
  239. reconcile/oum/models.py +1 -4
  240. reconcile/prometheus_rules_tester/integration.py +3 -3
  241. reconcile/quay_mirror.py +1 -1
  242. reconcile/queries.py +131 -0
  243. reconcile/rhidp/common.py +3 -5
  244. reconcile/rhidp/sso_client/base.py +16 -5
  245. reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +1 -1
  246. reconcile/saas_auto_promotions_manager/subscriber.py +4 -3
  247. reconcile/skupper_network/integration.py +2 -2
  248. reconcile/slack_usergroups.py +35 -14
  249. reconcile/sql_query.py +1 -0
  250. reconcile/status_board.py +6 -6
  251. reconcile/statuspage/atlassian.py +7 -7
  252. reconcile/statuspage/integrations/maintenances.py +4 -3
  253. reconcile/statuspage/page.py +4 -9
  254. reconcile/statuspage/status.py +5 -8
  255. reconcile/templating/lib/rendering.py +3 -3
  256. reconcile/templating/renderer.py +2 -2
  257. reconcile/terraform_aws_route53.py +7 -1
  258. reconcile/terraform_cloudflare_dns.py +3 -3
  259. reconcile/terraform_cloudflare_resources.py +5 -5
  260. reconcile/terraform_cloudflare_users.py +3 -2
  261. reconcile/terraform_init/integration.py +187 -23
  262. reconcile/terraform_repo.py +16 -12
  263. reconcile/terraform_resources.py +6 -6
  264. reconcile/terraform_tgw_attachments.py +27 -19
  265. reconcile/terraform_users.py +7 -0
  266. reconcile/terraform_vpc_peerings.py +14 -3
  267. reconcile/terraform_vpc_resources/integration.py +10 -1
  268. reconcile/typed_queries/aws_account_tags.py +41 -0
  269. reconcile/typed_queries/cost_report/app_names.py +1 -1
  270. reconcile/typed_queries/cost_report/cost_namespaces.py +2 -2
  271. reconcile/typed_queries/saas_files.py +11 -11
  272. reconcile/typed_queries/status_board.py +2 -2
  273. reconcile/unleash_feature_toggles/integration.py +4 -2
  274. reconcile/utils/acs/base.py +6 -3
  275. reconcile/utils/acs/policies.py +2 -2
  276. reconcile/utils/aws_api.py +51 -20
  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/binary.py +7 -12
  282. reconcile/utils/datetime_util.py +67 -0
  283. reconcile/utils/deadmanssnitch_api.py +1 -1
  284. reconcile/utils/differ.py +2 -3
  285. reconcile/utils/early_exit_cache.py +11 -12
  286. reconcile/utils/expiration.py +7 -3
  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/helpers.py +1 -1
  293. reconcile/utils/instrumented_wrappers.py +1 -1
  294. reconcile/utils/internal_groups/client.py +2 -2
  295. reconcile/utils/internal_groups/models.py +8 -17
  296. reconcile/utils/jinja2/utils.py +6 -101
  297. reconcile/utils/jira_client.py +82 -63
  298. reconcile/utils/jjb_client.py +7 -10
  299. reconcile/utils/jobcontroller/controller.py +2 -2
  300. reconcile/utils/jobcontroller/models.py +17 -1
  301. reconcile/utils/json.py +43 -1
  302. reconcile/utils/membershipsources/app_interface_resolver.py +4 -2
  303. reconcile/utils/membershipsources/models.py +16 -23
  304. reconcile/utils/membershipsources/resolver.py +4 -2
  305. reconcile/utils/merge_request_manager/merge_request_manager.py +4 -4
  306. reconcile/utils/merge_request_manager/parser.py +6 -6
  307. reconcile/utils/metrics.py +5 -5
  308. reconcile/utils/models.py +304 -82
  309. reconcile/utils/mr/app_interface_reporter.py +2 -2
  310. reconcile/utils/mr/notificator.py +3 -3
  311. reconcile/utils/mr/update_access_report_base.py +3 -4
  312. reconcile/utils/mr/user_maintenance.py +3 -2
  313. reconcile/utils/oc.py +246 -201
  314. reconcile/utils/oc_filters.py +3 -3
  315. reconcile/utils/ocm/addons.py +0 -1
  316. reconcile/utils/ocm/base.py +17 -20
  317. reconcile/utils/ocm/cluster_groups.py +1 -1
  318. reconcile/utils/ocm/identity_providers.py +2 -2
  319. reconcile/utils/ocm/labels.py +1 -1
  320. reconcile/utils/ocm/products.py +8 -8
  321. reconcile/utils/ocm/search_filters.py +3 -6
  322. reconcile/utils/ocm/service_log.py +4 -6
  323. reconcile/utils/ocm/sre_capability_labels.py +20 -13
  324. reconcile/utils/openshift_resource.py +8 -3
  325. reconcile/utils/pagerduty_api.py +10 -7
  326. reconcile/utils/promotion_state.py +6 -11
  327. reconcile/utils/raw_github_api.py +1 -1
  328. reconcile/utils/rhcsv2_certs.py +86 -23
  329. reconcile/utils/rosa/session.py +16 -0
  330. reconcile/utils/runtime/integration.py +2 -3
  331. reconcile/utils/runtime/runner.py +2 -2
  332. reconcile/utils/saasherder/interfaces.py +13 -20
  333. reconcile/utils/saasherder/models.py +23 -20
  334. reconcile/utils/saasherder/saasherder.py +50 -27
  335. reconcile/utils/slack_api.py +2 -2
  336. reconcile/utils/sloth.py +171 -2
  337. reconcile/utils/structs.py +1 -1
  338. reconcile/utils/terraform_client.py +5 -4
  339. reconcile/utils/terrascript_aws_client.py +134 -74
  340. reconcile/utils/unleash/server.py +2 -8
  341. reconcile/utils/vault.py +5 -12
  342. reconcile/utils/vcs.py +8 -8
  343. reconcile/vault_replication.py +107 -42
  344. tools/app_interface_reporter.py +4 -4
  345. tools/cli_commands/cost_report/cost_management_api.py +3 -3
  346. tools/cli_commands/cost_report/view.py +7 -6
  347. tools/cli_commands/erv2.py +1 -1
  348. tools/qontract_cli.py +28 -17
  349. tools/template_validation.py +3 -1
  350. {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/WHEEL +0 -0
  351. {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/entry_points.txt +0 -0
@@ -11,7 +11,7 @@ from typing import (
11
11
  TypedDict,
12
12
  )
13
13
 
14
- from pydantic import BaseModel
14
+ from pydantic import BaseModel, Field
15
15
  from sretoolbox.container.image import Image
16
16
 
17
17
  from reconcile import openshift_base, queries
@@ -61,17 +61,19 @@ def get_database_access_namespaces(
61
61
  return query(query_func).namespaces_v1 or []
62
62
 
63
63
 
64
- class DatabaseConnectionParameters(BaseModel):
65
- host: str
66
- port: str
67
- user: str
68
- password: str
69
- database: str
64
+ class DatabaseConnectionParameters(
65
+ BaseModel, validate_by_name=True, validate_by_alias=True
66
+ ):
67
+ host: str = Field(..., alias="db.host")
68
+ port: str = Field(..., alias="db.port")
69
+ user: str = Field(..., alias="db.user")
70
+ password: str = Field(..., alias="db.password")
71
+ database: str = Field(..., alias="db.name")
70
72
 
71
73
 
72
74
  class PSQLScriptGenerator(BaseModel):
73
75
  db_access: DatabaseAccessV1
74
- current_db_access: DatabaseAccessV1 | None
76
+ current_db_access: DatabaseAccessV1 | None = None
75
77
  connection_parameter: DatabaseConnectionParameters
76
78
  admin_connection_parameter: DatabaseConnectionParameters
77
79
  engine: str
@@ -225,7 +227,7 @@ def get_db_engine(resource: NamespaceTerraformResourceRDSV1) -> str:
225
227
 
226
228
  class JobData(BaseModel):
227
229
  engine: str
228
- name_suffix: str
230
+ name: str
229
231
  image: str
230
232
  service_account_name: str
231
233
  rds_admin_secret_name: str
@@ -234,7 +236,7 @@ class JobData(BaseModel):
234
236
 
235
237
 
236
238
  def get_job_spec(job_data: JobData) -> OpenshiftResource:
237
- job_name = f"dbam-{job_data.name_suffix}"
239
+ job_name = job_data.name
238
240
 
239
241
  image_tag = Image(job_data.image).tag
240
242
  image_pull_policy = "Always" if image_tag == "latest" else "IfNotPresent"
@@ -391,14 +393,6 @@ def get_service_account_spec(name: str) -> OpenshiftResource:
391
393
  )
392
394
 
393
395
 
394
- class DBAMResource(BaseModel):
395
- resource: OpenshiftResource
396
- clean_up: bool
397
-
398
- class Config:
399
- arbitrary_types_allowed = True
400
-
401
-
402
396
  class JobStatusCondition(BaseModel):
403
397
  type: str
404
398
 
@@ -424,18 +418,12 @@ def _populate_resources(
424
418
  user_connection: DatabaseConnectionParameters,
425
419
  admin_connection: DatabaseConnectionParameters,
426
420
  current_db_access: DatabaseAccessV1 | None = None,
427
- ) -> list[DBAMResource]:
421
+ ) -> list[OpenshiftResource]:
428
422
  if user_connection.database == admin_connection.database:
429
423
  raise ValueError(f"Can not use default database {admin_connection.database}")
430
424
 
431
- managed_resources: list[DBAMResource] = []
432
425
  # create service account
433
- managed_resources.append(
434
- DBAMResource(
435
- resource=get_service_account_spec(resource_prefix),
436
- clean_up=True,
437
- )
438
- )
426
+ service_account_resource = get_service_account_spec(resource_prefix)
439
427
 
440
428
  # create script secret
441
429
  generator = PSQLScriptGenerator(
@@ -446,74 +434,107 @@ def _populate_resources(
446
434
  engine=engine,
447
435
  )
448
436
  script_secret_name = f"{resource_prefix}-script"
449
- managed_resources.extend([
450
- DBAMResource(
451
- resource=generate_script_secret_spec(
452
- script_secret_name,
453
- generator.generate_script(),
454
- ),
455
- clean_up=True,
456
- ),
457
- # create user secret
458
- DBAMResource(
459
- resource=generate_user_secret_spec(resource_prefix, user_connection),
460
- clean_up=False,
461
- ),
462
- ])
437
+ secret_script_resource = generate_script_secret_spec(
438
+ script_secret_name,
439
+ generator.generate_script(),
440
+ )
441
+
442
+ # create user secret
443
+ user_secret_resource = generate_user_secret_spec(
444
+ resource_prefix,
445
+ user_connection,
446
+ )
447
+
463
448
  # create pull secret
464
- labels = pull_secret["labels"] or {}
465
- pull_secret_resources = orb.fetch_provider_vault_secret(
449
+ pull_secret_resource = orb.fetch_provider_vault_secret(
466
450
  path=pull_secret["path"],
467
451
  version=pull_secret["version"],
468
452
  name=f"{resource_prefix}-pull-secret",
469
- labels=labels,
453
+ labels=pull_secret["labels"] or {},
470
454
  annotations=pull_secret["annotations"] or {},
471
455
  type=pull_secret["type"],
472
456
  integration=QONTRACT_INTEGRATION,
473
457
  integration_version=QONTRACT_INTEGRATION_VERSION,
474
458
  settings=settings,
475
459
  )
476
- managed_resources.extend([
477
- DBAMResource(resource=pull_secret_resources, clean_up=True),
478
- # create job
479
- DBAMResource(
480
- resource=get_job_spec(
481
- JobData(
482
- engine=engine,
483
- name_suffix=db_access.name,
484
- image=job_image,
485
- service_account_name=resource_prefix,
486
- rds_admin_secret_name=admin_secret_name,
487
- script_secret_name=script_secret_name,
488
- pull_secret=f"{resource_prefix}-pull-secret",
489
- )
490
- ),
491
- clean_up=True,
492
- ),
493
- ])
494
460
 
495
- return managed_resources
461
+ job_resource = get_job_spec(
462
+ JobData(
463
+ engine=engine,
464
+ name=resource_prefix,
465
+ image=job_image,
466
+ service_account_name=resource_prefix,
467
+ rds_admin_secret_name=admin_secret_name,
468
+ script_secret_name=script_secret_name,
469
+ pull_secret=f"{resource_prefix}-pull-secret",
470
+ )
471
+ )
472
+
473
+ return [
474
+ service_account_resource,
475
+ secret_script_resource,
476
+ user_secret_resource,
477
+ pull_secret_resource,
478
+ job_resource,
479
+ ]
496
480
 
497
481
 
498
482
  def _generate_password() -> str:
499
483
  return "".join(choices(ascii_letters + digits, k=32))
500
484
 
501
485
 
502
- class _DBDonnections(TypedDict):
486
+ class DBConnections(TypedDict):
503
487
  user: DatabaseConnectionParameters
504
488
  admin: DatabaseConnectionParameters
505
489
 
506
490
 
491
+ def _decode_secret_value(value: str) -> str:
492
+ return base64.b64decode(value).decode("utf-8")
493
+
494
+
495
+ def _build_user_connection(
496
+ db_access: DatabaseAccessV1,
497
+ admin_secret: dict[str, Any],
498
+ user_secret: dict[str, Any],
499
+ ) -> DatabaseConnectionParameters:
500
+ """
501
+ Build user connection parameters.
502
+
503
+ If user secret exists, use values from it as that's the one used to provision new database user.
504
+ Otherwise, generate a new password, this info will be saved as cluster secret.
505
+ After job completes, the secret will be saved to vault then deleted from the cluster.
506
+
507
+ Args:
508
+ db_access (DatabaseAccessV1): Database access definition from app-interface.
509
+ admin_secret (dict[str, Any]): Admin secret fetched from the cluster.
510
+ user_secret (dict[str, Any]): User secret fetched from the cluster, may be empty if not exists.
511
+ Returns:
512
+ DatabaseConnectionParameters: Connection parameters for the database user.
513
+ """
514
+ if user_secret:
515
+ return DatabaseConnectionParameters(
516
+ host=_decode_secret_value(user_secret["data"]["db.host"]),
517
+ port=_decode_secret_value(user_secret["data"]["db.port"]),
518
+ user=_decode_secret_value(user_secret["data"]["db.user"]),
519
+ password=_decode_secret_value(user_secret["data"]["db.password"]),
520
+ database=_decode_secret_value(user_secret["data"]["db.name"]),
521
+ )
522
+ return DatabaseConnectionParameters(
523
+ host=_decode_secret_value(admin_secret["data"]["db.host"]),
524
+ port=_decode_secret_value(admin_secret["data"]["db.port"]),
525
+ user=db_access.username,
526
+ password=_generate_password(),
527
+ database=db_access.database,
528
+ )
529
+
530
+
507
531
  def _create_database_connection_parameter(
508
532
  db_access: DatabaseAccessV1,
509
533
  namespace_name: str,
510
534
  oc: OCClient,
511
535
  admin_secret_name: str,
512
536
  user_secret_name: str,
513
- ) -> _DBDonnections:
514
- def _decode_secret_value(value: str) -> str:
515
- return base64.b64decode(value).decode("utf-8")
516
-
537
+ ) -> DBConnections:
517
538
  user_secret = oc.get(
518
539
  namespace_name,
519
540
  "Secret",
@@ -526,26 +547,11 @@ def _create_database_connection_parameter(
526
547
  admin_secret_name,
527
548
  allow_not_found=False,
528
549
  )
529
-
530
- if user_secret:
531
- password = _decode_secret_value(user_secret["data"]["db.password"])
532
- host = _decode_secret_value(user_secret["data"]["db.host"])
533
- user = _decode_secret_value(user_secret["data"]["db.user"])
534
- port = _decode_secret_value(user_secret["data"]["db.port"])
535
- database = _decode_secret_value(user_secret["data"]["db.name"])
536
- else:
537
- host = _decode_secret_value(admin_secret["data"]["db.host"])
538
- port = _decode_secret_value(admin_secret["data"]["db.port"])
539
- user = db_access.username
540
- password = _generate_password()
541
- database = db_access.database
542
- return _DBDonnections(
543
- user=DatabaseConnectionParameters(
544
- host=host,
545
- port=port,
546
- user=user,
547
- password=password,
548
- database=database,
550
+ return DBConnections(
551
+ user=_build_user_connection(
552
+ db_access=db_access,
553
+ admin_secret=admin_secret,
554
+ user_secret=user_secret,
549
555
  ),
550
556
  admin=DatabaseConnectionParameters(
551
557
  host=_decode_secret_value(admin_secret["data"]["db.host"]),
@@ -557,10 +563,10 @@ def _create_database_connection_parameter(
557
563
  )
558
564
 
559
565
 
560
- def _db_access_acccess_is_valid(db_acces: DatabaseAccessV1) -> bool:
566
+ def _db_access_access_is_valid(db_access: DatabaseAccessV1) -> bool:
561
567
  found_schema: set[str] = set()
562
568
 
563
- for schema in db_acces.access or []:
569
+ for schema in db_access.access or []:
564
570
  if schema.target.dbschema in found_schema:
565
571
  return False
566
572
  found_schema.add(schema.target.dbschema)
@@ -575,6 +581,7 @@ class JobFailedError(Exception):
575
581
  def _process_db_access(
576
582
  dry_run: bool,
577
583
  state: State,
584
+ state_key: str,
578
585
  db_access: DatabaseAccessV1,
579
586
  namespace: NamespaceV1,
580
587
  admin_secret_name: str,
@@ -583,13 +590,13 @@ def _process_db_access(
583
590
  vault_output_path: str,
584
591
  vault_client: VaultClient,
585
592
  ) -> None:
586
- if not _db_access_acccess_is_valid(db_access):
593
+ if not _db_access_access_is_valid(db_access):
587
594
  raise ValueError("Duplicate schema in access list.")
588
595
 
589
596
  current_db_access: DatabaseAccessV1 | None = None
590
- if state.exists(db_access.name):
591
- current_state = state.get(db_access.name)
592
- if current_state == db_access.dict(by_alias=True):
597
+ if state.exists(state_key):
598
+ current_state = state.get(state_key)
599
+ if current_state == db_access.model_dump(by_alias=True):
593
600
  return
594
601
  current_db_access = DatabaseAccessV1(**current_state)
595
602
  if current_db_access.database != db_access.database:
@@ -600,9 +607,9 @@ def _process_db_access(
600
607
  cluster_name = namespace.cluster.name
601
608
  namespace_name = namespace.name
602
609
 
603
- resource_prefix = f"dbam-{db_access.name}"
610
+ resource_prefix = f"dbam-{state_key.replace('/', '-')}"
604
611
  with OC_Map(
605
- clusters=[namespace.cluster.dict(by_alias=True)],
612
+ clusters=[namespace.cluster.model_dump(by_alias=True)],
606
613
  integration=QONTRACT_INTEGRATION,
607
614
  settings=settings,
608
615
  ) as oc_map:
@@ -613,7 +620,7 @@ def _process_db_access(
613
620
  namespace_name,
614
621
  oc,
615
622
  admin_secret_name,
616
- resource_prefix,
623
+ user_secret_name=resource_prefix,
617
624
  )
618
625
 
619
626
  sql_query_settings = settings.get("sqlQuery")
@@ -642,7 +649,7 @@ def _process_db_access(
642
649
  job = oc.get(
643
650
  namespace_name,
644
651
  "Job",
645
- f"dbam-{db_access.name}",
652
+ resource_prefix,
646
653
  allow_not_found=True,
647
654
  )
648
655
  if not job:
@@ -652,8 +659,8 @@ def _process_db_access(
652
659
  oc_map=oc_map,
653
660
  cluster=cluster_name,
654
661
  namespace=namespace_name,
655
- resource_type=r.resource.kind,
656
- resource=r.resource,
662
+ resource_type=r.kind,
663
+ resource=r,
657
664
  wait_for_namespace=False,
658
665
  )
659
666
  return
@@ -665,34 +672,31 @@ def _process_db_access(
665
672
  )
666
673
  if job_status.is_complete():
667
674
  if job_status.has_errors():
668
- raise JobFailedError(
669
- f"Job dbam-{db_access.name} failed, please check logs"
670
- )
675
+ raise JobFailedError(f"Job {resource_prefix} failed, please check logs")
671
676
  if not dry_run and not db_access.delete:
672
677
  secret = {
673
- "path": f"{vault_output_path}/{QONTRACT_INTEGRATION}/{cluster_name}/{namespace_name}/{db_access.name}",
674
- "data": connections["user"].dict(by_alias=True),
678
+ "path": f"{vault_output_path}/{QONTRACT_INTEGRATION}/{state_key}",
679
+ "data": connections["user"].model_dump(by_alias=True),
675
680
  }
676
681
  vault_client.write(secret, decode_base64=False)
677
682
  logging.debug("job completed, cleaning up")
678
683
  for r in managed_resources:
679
- if r.clean_up:
680
- openshift_base.delete(
681
- dry_run=dry_run,
682
- oc_map=oc_map,
683
- cluster=cluster_name,
684
- namespace=namespace_name,
685
- resource_type=r.resource.kind,
686
- name=r.resource.name,
687
- enable_deletion=True,
688
- )
684
+ openshift_base.delete(
685
+ dry_run=dry_run,
686
+ oc_map=oc_map,
687
+ cluster=cluster_name,
688
+ namespace=namespace_name,
689
+ resource_type=r.kind,
690
+ name=r.name,
691
+ enable_deletion=True,
692
+ )
689
693
  state.add(
690
- db_access.name,
691
- value=db_access.dict(by_alias=True),
694
+ state_key,
695
+ value=db_access.model_dump(by_alias=True),
692
696
  force=True,
693
697
  )
694
698
  else:
695
- logging.info(f"Job dbam-{db_access.name} appears to be still running")
699
+ logging.info(f"Job {resource_prefix} appears to be still running")
696
700
 
697
701
 
698
702
  class DBAMIntegrationParams(PydanticRunParams):
@@ -734,9 +738,11 @@ class DatabaseAccessManagerIntegration(QontractReconcileIntegration):
734
738
 
735
739
  for db_access in resource.database_access or []:
736
740
  try:
741
+ state_key = f"{external_resource.provisioner.name}/{resource.identifier}/{db_access.name}"
737
742
  _process_db_access(
738
743
  dry_run,
739
744
  state,
745
+ state_key,
740
746
  db_access,
741
747
  namespace,
742
748
  admin_secret_name,
@@ -82,7 +82,7 @@ class DynatraceTokenProviderIntegration(QontractReconcileIntegration[NoParams]):
82
82
  return {
83
83
  "version": QONTRACT_INTEGRATION_VERSION,
84
84
  "specs": {
85
- spec.name: spec.dict()
85
+ spec.name: spec.model_dump()
86
86
  for spec in get_dynatrace_token_provider_token_specs()
87
87
  },
88
88
  }
@@ -150,7 +150,10 @@ class EndpointsDiscoveryIntegration(
150
150
  return []
151
151
 
152
152
  routes = defaultdict(list)
153
- for item in oc.get_items(kind="Route", namespace=namespace.name):
153
+ for item in oc.get_items(
154
+ kind="Route.route.openshift.io",
155
+ namespace=namespace.name,
156
+ ):
154
157
  tls = bool(item["spec"].get("tls"))
155
158
  host = item["spec"]["host"]
156
159
  # group all routes with the same hostname/tls
@@ -89,7 +89,7 @@ class Renderer:
89
89
 
90
90
  def render_description(self, hash: str) -> str:
91
91
  """Render the description for a merge request."""
92
- return DESC.safe_substitute(EPDInfo(hash=hash).dict())
92
+ return DESC.safe_substitute(EPDInfo(hash=hash).model_dump())
93
93
 
94
94
  def render_title(self) -> str:
95
95
  """Render the title for a merge request."""
@@ -1,7 +1,7 @@
1
1
  import hashlib
2
2
  import logging
3
3
  from collections.abc import Sequence
4
- from typing import Any, TypeAlias
4
+ from typing import Any
5
5
 
6
6
  from gitlab.exceptions import GitlabGetError
7
7
  from pydantic import BaseModel
@@ -64,20 +64,20 @@ class Endpoint(BaseModel):
64
64
 
65
65
  @property
66
66
  def hash(self) -> str:
67
- return hashlib.sha256(json_dumps(self.dict()).encode()).hexdigest()
67
+ return hashlib.sha256(json_dumps(self.model_dump()).encode()).hexdigest()
68
68
 
69
69
 
70
- EndpointsToAdd: TypeAlias = list[Endpoint]
71
- EndpointsToChange: TypeAlias = list[Endpoint]
72
- EndpointsToDelete: TypeAlias = list[Endpoint]
70
+ EndpointsToAdd = list[Endpoint]
71
+ EndpointsToChange = list[Endpoint]
72
+ EndpointsToDelete = list[Endpoint]
73
73
 
74
74
 
75
75
  class App(BaseModel):
76
76
  name: str
77
77
  path: str
78
- endpoints_to_add: EndpointsToAdd = EndpointsToAdd()
79
- endpoints_to_change: EndpointsToChange = EndpointsToChange()
80
- endpoints_to_delete: EndpointsToDelete = EndpointsToDelete()
78
+ endpoints_to_add: EndpointsToAdd = []
79
+ endpoints_to_change: EndpointsToChange = []
80
+ endpoints_to_delete: EndpointsToDelete = []
81
81
 
82
82
  @property
83
83
  def hash(self) -> str:
@@ -2,8 +2,7 @@ from abc import (
2
2
  ABC,
3
3
  abstractmethod,
4
4
  )
5
- from collections.abc import Mapping
6
- from typing import Generic, TypeVar
5
+ from typing import TypeVar
7
6
 
8
7
  from reconcile.external_resources.aws import (
9
8
  AWSDefaultResourceFactory,
@@ -34,7 +33,7 @@ from reconcile.utils.secret_reader import SecretReaderBase
34
33
  T = TypeVar("T")
35
34
 
36
35
 
37
- class ObjectFactory(Generic[T]):
36
+ class ObjectFactory[T]:
38
37
  def __init__(
39
38
  self, factories: dict[str, T], default_factory: T | None = None
40
39
  ) -> None:
@@ -116,7 +115,7 @@ class AWSExternalResourceFactory(ExternalResourceFactory):
116
115
  secret_reader: SecretReaderBase,
117
116
  provision_factories: ObjectFactory[ModuleProvisionDataFactory],
118
117
  resource_factories: ObjectFactory[AWSResourceFactory],
119
- default_tags: Mapping[str, str],
118
+ default_tags: dict[str, str],
120
119
  ):
121
120
  self.provision_factories = provision_factories
122
121
  self.resource_factories = resource_factories
@@ -132,8 +131,7 @@ class AWSExternalResourceFactory(ExternalResourceFactory):
132
131
  ) -> ExternalResource:
133
132
  f = self.resource_factories.get_factory(spec.provider)
134
133
  data = f.resolve(spec, module_conf)
135
- data["tags"] = spec.tags(integration=QONTRACT_INTEGRATION)
136
- data["default_tags"] = [{"tags": self.default_tags}]
134
+ data["tags"] = self.default_tags | spec.tags(integration=QONTRACT_INTEGRATION)
137
135
 
138
136
  region = data.get("region")
139
137
  if region:
@@ -45,7 +45,7 @@ from reconcile.utils.secret_reader import SecretReaderBase, create_secret_reader
45
45
  def fetch_current_state(
46
46
  ri: ResourceInventory, oc: OCCli, cluster: str, namespace: str
47
47
  ) -> None:
48
- for item in oc.get_items("Job", namespace=namespace):
48
+ for item in oc.get_items("Job.batch", namespace=namespace):
49
49
  r = OpenshiftResource(item, QONTRACT_INTEGRATION, QONTRACT_INTEGRATION_VERSION)
50
50
  ri.add_current(cluster, namespace, "Job", r.name, r)
51
51
 
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  from collections import Counter
3
3
  from collections.abc import Iterable
4
- from datetime import UTC, datetime
4
+ from typing import cast
5
5
 
6
6
  from sretoolbox.utils import threaded
7
7
 
@@ -41,6 +41,7 @@ from reconcile.external_resources.state import (
41
41
  from reconcile.gql_definitions.external_resources.external_resources_settings import (
42
42
  ExternalResourcesSettingsV1,
43
43
  )
44
+ from reconcile.utils.datetime_util import utc_now
44
45
  from reconcile.utils.external_resource_spec import (
45
46
  ExternalResourceSpec,
46
47
  )
@@ -67,7 +68,7 @@ def setup_factories(
67
68
  resource_factories=setup_aws_resource_factories(
68
69
  er_inventory, secret_reader
69
70
  ),
70
- default_tags=settings.default_tags,
71
+ default_tags=cast("dict[str, str]", settings.default_tags),
71
72
  )
72
73
  }
73
74
  )
@@ -142,7 +143,7 @@ class ExternalResourcesManager:
142
143
  def _resource_drift_detection_ttl_expired(
143
144
  self, reconciliation: Reconciliation, state: ExternalResourceState
144
145
  ) -> bool:
145
- return (datetime.now(state.ts.tzinfo) - state.ts).total_seconds() > (
146
+ return (utc_now() - state.ts).total_seconds() > (
146
147
  reconciliation.module_configuration.reconcile_drift_interval_minutes * 60
147
148
  )
148
149
 
@@ -243,7 +244,7 @@ class ExternalResourcesManager:
243
244
  reconciliation = Reconciliation(
244
245
  key=key,
245
246
  resource_hash=resource.hash(),
246
- input=resource.json(),
247
+ input=resource.export(),
247
248
  action=Action.APPLY,
248
249
  module_configuration=module_conf,
249
250
  linked_resources=self._find_linked_resources(spec),
@@ -356,7 +357,7 @@ class ExternalResourcesManager:
356
357
  def _set_resource_reconciliation_in_progress(
357
358
  self, r: Reconciliation, state: ExternalResourceState
358
359
  ) -> None:
359
- state.ts = datetime.now(UTC)
360
+ state.ts = utc_now()
360
361
  if r.action == Action.APPLY:
361
362
  state.resource_status = ResourceStatus.IN_PROGRESS
362
363
  elif r.action == Action.DESTROY:
@@ -449,7 +450,8 @@ class ExternalResourcesManager:
449
450
  r
450
451
  for r in desired_r.union(deleted_r)
451
452
  if self._reconciliation_needs_dry_run_run(
452
- r, self.state_mgr.get_external_resource_state(key=r.key)
453
+ r,
454
+ self.state_mgr.get_external_resource_state(key=r.key),
453
455
  )
454
456
  }
455
457
 
@@ -10,7 +10,6 @@ SECRET_ANN_PROVISIONER = SECRET_ANN_PREFIX + "/provisioner_name"
10
10
  SECRET_ANN_PROVIDER = SECRET_ANN_PREFIX + "/provider"
11
11
  SECRET_ANN_IDENTIFIER = SECRET_ANN_PREFIX + "/identifier"
12
12
  SECRET_UPDATED_AT = SECRET_ANN_PREFIX + "/updated_at"
13
- SECRET_UPDATED_AT_TIMEFORMAT = "%Y-%m-%dT%H:%M:%SZ"
14
13
 
15
14
  FLAG_RESOURCE_MANAGED_BY_ERV2 = "managed_by_erv2"
16
15
  FLAG_DELETE_RESOURCE = "delete"
@@ -13,7 +13,7 @@ from reconcile.utils.metrics import (
13
13
 
14
14
 
15
15
  class ExternalResourcesBaseMetric(BaseModel):
16
- integration = normalize_integration_name(QONTRACT_INTEGRATION)
16
+ integration: str = normalize_integration_name(QONTRACT_INTEGRATION)
17
17
  app: str
18
18
  environment: str
19
19
  provision_provider: str