qontract-reconcile 0.10.2.dev310__py3-none-any.whl → 0.10.2.dev439__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.

Potentially problematic release.


This version of qontract-reconcile might be problematic. Click here for more details.

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