qontract-reconcile 0.10.2.dev361__py3-none-any.whl → 0.10.2.dev474__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 (371) hide show
  1. {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev474.dist-info}/METADATA +14 -13
  2. {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev474.dist-info}/RECORD +371 -364
  3. {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev474.dist-info}/WHEEL +1 -1
  4. reconcile/acs_rbac.py +2 -2
  5. reconcile/aus/advanced_upgrade_service.py +18 -12
  6. reconcile/aus/aus_sts_gate_handler.py +59 -0
  7. reconcile/aus/base.py +137 -34
  8. reconcile/aus/cluster_version_data.py +15 -5
  9. reconcile/aus/models.py +3 -1
  10. reconcile/aus/ocm_addons_upgrade_scheduler_org.py +1 -0
  11. reconcile/aus/ocm_upgrade_scheduler.py +8 -1
  12. reconcile/aus/ocm_upgrade_scheduler_org.py +20 -5
  13. reconcile/aus/version_gate_approver.py +1 -16
  14. reconcile/aus/version_gates/sts_version_gate_handler.py +5 -72
  15. reconcile/automated_actions/config/integration.py +16 -4
  16. reconcile/aws_account_manager/integration.py +21 -9
  17. reconcile/aws_account_manager/reconciler.py +3 -3
  18. reconcile/aws_account_manager/utils.py +1 -1
  19. reconcile/aws_ami_cleanup/integration.py +8 -12
  20. reconcile/aws_ami_share.py +69 -62
  21. reconcile/aws_cloudwatch_log_retention/integration.py +155 -126
  22. reconcile/aws_ecr_image_pull_secrets.py +1 -1
  23. reconcile/aws_iam_keys.py +1 -0
  24. reconcile/aws_saml_idp/integration.py +12 -4
  25. reconcile/aws_saml_roles/integration.py +30 -23
  26. reconcile/aws_version_sync/integration.py +6 -12
  27. reconcile/change_owners/README.md +1 -1
  28. reconcile/change_owners/bundle.py +3 -3
  29. reconcile/change_owners/change_log_tracking.py +3 -2
  30. reconcile/change_owners/change_owners.py +108 -42
  31. reconcile/change_owners/decision.py +1 -1
  32. reconcile/change_owners/diff.py +0 -2
  33. reconcile/checkpoint.py +11 -3
  34. reconcile/cli.py +94 -11
  35. reconcile/dashdotdb_dora.py +5 -12
  36. reconcile/dashdotdb_slo.py +1 -1
  37. reconcile/database_access_manager.py +123 -117
  38. reconcile/dynatrace_token_provider/integration.py +1 -1
  39. reconcile/endpoints_discovery/integration.py +4 -1
  40. reconcile/endpoints_discovery/merge_request.py +1 -1
  41. reconcile/endpoints_discovery/merge_request_manager.py +8 -8
  42. reconcile/external_resources/factories.py +4 -6
  43. reconcile/external_resources/integration.py +1 -1
  44. reconcile/external_resources/manager.py +8 -6
  45. reconcile/external_resources/meta.py +0 -1
  46. reconcile/external_resources/metrics.py +1 -1
  47. reconcile/external_resources/model.py +19 -15
  48. reconcile/external_resources/reconciler.py +7 -4
  49. reconcile/external_resources/secrets_sync.py +6 -10
  50. reconcile/external_resources/state.py +26 -16
  51. reconcile/fleet_labeler/integration.py +1 -1
  52. reconcile/gabi_authorized_users.py +5 -2
  53. reconcile/gcp_image_mirror.py +2 -2
  54. reconcile/github_org.py +1 -1
  55. reconcile/github_owners.py +4 -0
  56. reconcile/gitlab_housekeeping.py +13 -15
  57. reconcile/gitlab_members.py +6 -12
  58. reconcile/gitlab_owners.py +15 -11
  59. reconcile/gitlab_permissions.py +8 -12
  60. reconcile/glitchtip_project_alerts/integration.py +3 -1
  61. reconcile/gql_definitions/acs/acs_instances.py +5 -5
  62. reconcile/gql_definitions/acs/acs_policies.py +5 -5
  63. reconcile/gql_definitions/acs/acs_rbac.py +5 -5
  64. reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +5 -5
  65. reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +5 -5
  66. reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +5 -5
  67. reconcile/gql_definitions/app_sre_tekton_access_revalidation/roles.py +5 -5
  68. reconcile/gql_definitions/app_sre_tekton_access_revalidation/users.py +5 -5
  69. reconcile/gql_definitions/automated_actions/instance.py +46 -7
  70. reconcile/gql_definitions/aws_account_manager/aws_accounts.py +14 -5
  71. reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +15 -5
  72. reconcile/gql_definitions/aws_cloudwatch_log_retention/aws_accounts.py +27 -66
  73. reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +15 -5
  74. reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +15 -5
  75. reconcile/gql_definitions/aws_saml_roles/roles.py +5 -5
  76. reconcile/gql_definitions/aws_version_sync/clusters.py +5 -5
  77. reconcile/gql_definitions/aws_version_sync/namespaces.py +5 -5
  78. reconcile/gql_definitions/change_owners/queries/change_types.py +5 -5
  79. reconcile/gql_definitions/change_owners/queries/self_service_roles.py +5 -5
  80. reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +5 -5
  81. reconcile/gql_definitions/common/alerting_services_settings.py +5 -5
  82. reconcile/gql_definitions/common/app_code_component_repos.py +5 -5
  83. reconcile/gql_definitions/common/app_interface_custom_messages.py +5 -5
  84. reconcile/gql_definitions/common/app_interface_dms_settings.py +5 -5
  85. reconcile/gql_definitions/common/app_interface_repo_settings.py +5 -5
  86. reconcile/gql_definitions/common/app_interface_roles.py +5 -5
  87. reconcile/gql_definitions/common/app_interface_state_settings.py +5 -5
  88. reconcile/gql_definitions/common/app_interface_vault_settings.py +5 -5
  89. reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +5 -5
  90. reconcile/gql_definitions/common/apps.py +5 -5
  91. reconcile/gql_definitions/common/aws_vpc_requests.py +18 -5
  92. reconcile/gql_definitions/common/aws_vpcs.py +5 -5
  93. reconcile/gql_definitions/common/clusters.py +7 -5
  94. reconcile/gql_definitions/common/clusters_minimal.py +5 -5
  95. reconcile/gql_definitions/common/clusters_with_dms.py +5 -5
  96. reconcile/gql_definitions/common/clusters_with_peering.py +5 -5
  97. reconcile/gql_definitions/common/github_orgs.py +5 -5
  98. reconcile/gql_definitions/common/jira_settings.py +5 -5
  99. reconcile/gql_definitions/common/jiralert_settings.py +5 -5
  100. reconcile/gql_definitions/common/ldap_settings.py +5 -5
  101. reconcile/gql_definitions/common/namespaces.py +5 -5
  102. reconcile/gql_definitions/common/namespaces_minimal.py +7 -5
  103. reconcile/gql_definitions/common/ocm_env_telemeter.py +5 -5
  104. reconcile/gql_definitions/common/ocm_environments.py +5 -5
  105. reconcile/gql_definitions/common/pagerduty_instances.py +5 -5
  106. reconcile/gql_definitions/common/pgp_reencryption_settings.py +5 -5
  107. reconcile/gql_definitions/common/pipeline_providers.py +5 -5
  108. reconcile/gql_definitions/common/quay_instances.py +5 -5
  109. reconcile/gql_definitions/common/quay_orgs.py +5 -5
  110. reconcile/gql_definitions/common/reserved_networks.py +5 -5
  111. reconcile/gql_definitions/common/rhcs_provider_settings.py +5 -5
  112. reconcile/gql_definitions/common/saas_files.py +5 -5
  113. reconcile/gql_definitions/common/saas_target_namespaces.py +5 -5
  114. reconcile/gql_definitions/common/saasherder_settings.py +5 -5
  115. reconcile/gql_definitions/common/slack_workspaces.py +5 -5
  116. reconcile/gql_definitions/common/smtp_client_settings.py +5 -5
  117. reconcile/gql_definitions/common/state_aws_account.py +5 -5
  118. reconcile/gql_definitions/common/users.py +5 -5
  119. reconcile/gql_definitions/common/users_with_paths.py +5 -5
  120. reconcile/gql_definitions/cost_report/app_names.py +5 -5
  121. reconcile/gql_definitions/cost_report/cost_namespaces.py +5 -5
  122. reconcile/gql_definitions/cost_report/settings.py +5 -5
  123. reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +5 -5
  124. reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +5 -5
  125. reconcile/gql_definitions/dynatrace_token_provider/token_specs.py +5 -5
  126. reconcile/gql_definitions/email_sender/apps.py +5 -5
  127. reconcile/gql_definitions/email_sender/emails.py +5 -5
  128. reconcile/gql_definitions/email_sender/users.py +5 -5
  129. reconcile/gql_definitions/endpoints_discovery/apps.py +5 -5
  130. reconcile/gql_definitions/external_resources/aws_accounts.py +5 -5
  131. reconcile/gql_definitions/external_resources/external_resources_modules.py +5 -5
  132. reconcile/gql_definitions/external_resources/external_resources_namespaces.py +38 -7
  133. reconcile/gql_definitions/external_resources/external_resources_settings.py +5 -5
  134. reconcile/gql_definitions/external_resources/fragments/external_resources_module_overrides.py +5 -5
  135. reconcile/gql_definitions/fleet_labeler/fleet_labels.py +5 -5
  136. reconcile/gql_definitions/fragments/aus_organization.py +5 -5
  137. reconcile/gql_definitions/fragments/aws_account_common.py +7 -5
  138. reconcile/gql_definitions/fragments/aws_account_managed.py +5 -5
  139. reconcile/gql_definitions/fragments/aws_account_sso.py +5 -5
  140. reconcile/gql_definitions/fragments/aws_infra_management_account.py +5 -5
  141. reconcile/gql_definitions/fragments/aws_organization.py +33 -0
  142. reconcile/gql_definitions/fragments/aws_vpc.py +5 -5
  143. reconcile/gql_definitions/fragments/aws_vpc_request.py +12 -5
  144. reconcile/gql_definitions/fragments/container_image_mirror.py +5 -5
  145. reconcile/gql_definitions/fragments/deploy_resources.py +5 -5
  146. reconcile/gql_definitions/fragments/disable.py +5 -5
  147. reconcile/gql_definitions/fragments/email_service.py +5 -5
  148. reconcile/gql_definitions/fragments/email_user.py +5 -5
  149. reconcile/gql_definitions/fragments/jumphost_common_fields.py +5 -5
  150. reconcile/gql_definitions/fragments/membership_source.py +5 -5
  151. reconcile/gql_definitions/fragments/minimal_ocm_organization.py +5 -5
  152. reconcile/gql_definitions/fragments/oc_connection_cluster.py +5 -5
  153. reconcile/gql_definitions/fragments/ocm_environment.py +5 -5
  154. reconcile/gql_definitions/fragments/pipeline_provider_retention.py +5 -5
  155. reconcile/gql_definitions/fragments/prometheus_instance.py +5 -5
  156. reconcile/gql_definitions/fragments/resource_limits_requirements.py +5 -5
  157. reconcile/gql_definitions/fragments/resource_requests_requirements.py +5 -5
  158. reconcile/gql_definitions/fragments/resource_values.py +5 -5
  159. reconcile/gql_definitions/fragments/saas_slo_document.py +5 -5
  160. reconcile/gql_definitions/fragments/saas_target_namespace.py +5 -5
  161. reconcile/gql_definitions/fragments/serviceaccount_token.py +5 -5
  162. reconcile/gql_definitions/fragments/terraform_state.py +5 -5
  163. reconcile/gql_definitions/fragments/upgrade_policy.py +5 -5
  164. reconcile/gql_definitions/fragments/user.py +5 -5
  165. reconcile/gql_definitions/fragments/vault_secret.py +5 -5
  166. reconcile/gql_definitions/gcp/gcp_docker_repos.py +5 -5
  167. reconcile/gql_definitions/gcp/gcp_projects.py +5 -5
  168. reconcile/gql_definitions/gitlab_members/gitlab_instances.py +5 -5
  169. reconcile/gql_definitions/gitlab_members/permissions.py +5 -5
  170. reconcile/gql_definitions/glitchtip/glitchtip_instance.py +5 -5
  171. reconcile/gql_definitions/glitchtip/glitchtip_project.py +5 -5
  172. reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +5 -5
  173. reconcile/gql_definitions/integrations/integrations.py +5 -5
  174. reconcile/gql_definitions/introspection.json +775 -136
  175. reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +5 -5
  176. reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +5 -5
  177. reconcile/gql_definitions/jira/jira_servers.py +5 -5
  178. reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +9 -5
  179. reconcile/gql_definitions/jumphosts/jumphosts.py +5 -5
  180. reconcile/gql_definitions/ldap_groups/roles.py +5 -5
  181. reconcile/gql_definitions/ldap_groups/settings.py +5 -5
  182. reconcile/gql_definitions/maintenance/maintenances.py +5 -5
  183. reconcile/gql_definitions/membershipsources/roles.py +5 -5
  184. reconcile/gql_definitions/ocm_labels/clusters.py +5 -5
  185. reconcile/gql_definitions/ocm_labels/organizations.py +5 -5
  186. reconcile/gql_definitions/openshift_cluster_bots/clusters.py +5 -5
  187. reconcile/gql_definitions/openshift_groups/managed_groups.py +5 -5
  188. reconcile/gql_definitions/openshift_groups/managed_roles.py +5 -5
  189. reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +5 -5
  190. reconcile/gql_definitions/quay_membership/quay_membership.py +5 -5
  191. reconcile/gql_definitions/rhcs/certs.py +25 -79
  192. reconcile/gql_definitions/rhcs/openshift_resource_rhcs_cert.py +43 -0
  193. reconcile/gql_definitions/rhidp/organizations.py +5 -5
  194. reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +5 -5
  195. reconcile/gql_definitions/service_dependencies/service_dependencies.py +5 -5
  196. reconcile/gql_definitions/sharding/aws_accounts.py +5 -5
  197. reconcile/gql_definitions/sharding/ocm_organization.py +5 -5
  198. reconcile/gql_definitions/skupper_network/site_controller_template.py +5 -5
  199. reconcile/gql_definitions/skupper_network/skupper_networks.py +5 -5
  200. reconcile/gql_definitions/slack_usergroups/clusters.py +5 -5
  201. reconcile/gql_definitions/slack_usergroups/permissions.py +5 -5
  202. reconcile/gql_definitions/slack_usergroups/users.py +5 -5
  203. reconcile/gql_definitions/slo_documents/slo_documents.py +5 -5
  204. reconcile/gql_definitions/status_board/status_board.py +5 -5
  205. reconcile/gql_definitions/statuspage/statuspages.py +5 -5
  206. reconcile/gql_definitions/templating/template_collection.py +5 -5
  207. reconcile/gql_definitions/templating/templates.py +5 -5
  208. reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +5 -5
  209. reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +5 -5
  210. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +5 -5
  211. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +5 -5
  212. reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +5 -5
  213. reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +5 -5
  214. reconcile/gql_definitions/terraform_init/aws_accounts.py +19 -5
  215. reconcile/gql_definitions/terraform_repo/terraform_repo.py +5 -5
  216. reconcile/gql_definitions/terraform_resources/database_access_manager.py +5 -5
  217. reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +37 -7
  218. reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +15 -5
  219. reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +5 -5
  220. reconcile/gql_definitions/vault_instances/vault_instances.py +5 -5
  221. reconcile/gql_definitions/vault_policies/vault_policies.py +5 -5
  222. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +8 -5
  223. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +6 -5
  224. reconcile/integrations_manager.py +3 -3
  225. reconcile/jenkins_worker_fleets.py +10 -8
  226. reconcile/jira_permissions_validator.py +237 -122
  227. reconcile/ldap_groups/integration.py +1 -1
  228. reconcile/ocm/types.py +35 -57
  229. reconcile/ocm_aws_infrastructure_access.py +1 -1
  230. reconcile/ocm_clusters.py +4 -4
  231. reconcile/ocm_labels/integration.py +3 -2
  232. reconcile/ocm_machine_pools.py +33 -27
  233. reconcile/openshift_base.py +113 -4
  234. reconcile/openshift_cluster_bots.py +1 -1
  235. reconcile/openshift_namespace_labels.py +1 -1
  236. reconcile/openshift_namespaces.py +96 -101
  237. reconcile/openshift_resources_base.py +6 -2
  238. reconcile/openshift_rhcs_certs.py +74 -37
  239. reconcile/openshift_rolebindings.py +7 -11
  240. reconcile/openshift_saas_deploy.py +4 -5
  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 +2 -2
  244. reconcile/openshift_upgrade_watcher.py +4 -4
  245. reconcile/oum/labelset.py +5 -3
  246. reconcile/oum/models.py +1 -4
  247. reconcile/prometheus_rules_tester/integration.py +3 -3
  248. reconcile/quay_base.py +25 -6
  249. reconcile/quay_membership.py +55 -29
  250. reconcile/quay_mirror.py +1 -1
  251. reconcile/quay_mirror_org.py +6 -4
  252. reconcile/quay_permissions.py +81 -75
  253. reconcile/quay_repos.py +35 -37
  254. reconcile/queries.py +132 -1
  255. reconcile/rhidp/common.py +3 -5
  256. reconcile/rhidp/sso_client/base.py +16 -5
  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/skupper_network/integration.py +2 -2
  260. reconcile/slack_usergroups.py +35 -14
  261. reconcile/sql_query.py +1 -0
  262. reconcile/status_board.py +6 -6
  263. reconcile/statuspage/atlassian.py +7 -7
  264. reconcile/statuspage/integrations/maintenances.py +4 -3
  265. reconcile/statuspage/page.py +4 -9
  266. reconcile/statuspage/status.py +5 -8
  267. reconcile/templates/rosa-classic-cluster-creation.sh.j2 +1 -1
  268. reconcile/templates/rosa-hcp-cluster-creation.sh.j2 +1 -1
  269. reconcile/templating/lib/rendering.py +3 -3
  270. reconcile/templating/renderer.py +2 -2
  271. reconcile/templating/validator.py +4 -4
  272. reconcile/terraform_aws_route53.py +7 -1
  273. reconcile/terraform_cloudflare_dns.py +3 -3
  274. reconcile/terraform_cloudflare_resources.py +5 -5
  275. reconcile/terraform_cloudflare_users.py +3 -2
  276. reconcile/terraform_init/integration.py +187 -23
  277. reconcile/terraform_repo.py +16 -12
  278. reconcile/terraform_resources.py +6 -6
  279. reconcile/terraform_tgw_attachments.py +27 -19
  280. reconcile/terraform_users.py +7 -0
  281. reconcile/terraform_vpc_peerings.py +14 -3
  282. reconcile/terraform_vpc_resources/integration.py +20 -8
  283. reconcile/terraform_vpc_resources/merge_request.py +12 -2
  284. reconcile/terraform_vpc_resources/merge_request_manager.py +43 -19
  285. reconcile/typed_queries/aws_account_tags.py +41 -0
  286. reconcile/typed_queries/cost_report/app_names.py +1 -1
  287. reconcile/typed_queries/cost_report/cost_namespaces.py +2 -2
  288. reconcile/typed_queries/saas_files.py +20 -15
  289. reconcile/typed_queries/status_board.py +2 -2
  290. reconcile/unleash_feature_toggles/integration.py +4 -2
  291. reconcile/utils/acs/base.py +6 -3
  292. reconcile/utils/acs/policies.py +2 -2
  293. reconcile/utils/aws_api.py +51 -20
  294. reconcile/utils/aws_api_typed/api.py +38 -9
  295. reconcile/utils/aws_api_typed/cloudformation.py +149 -0
  296. reconcile/utils/aws_api_typed/logs.py +73 -0
  297. reconcile/utils/aws_api_typed/organization.py +4 -2
  298. reconcile/utils/binary.py +7 -12
  299. reconcile/utils/datetime_util.py +67 -0
  300. reconcile/utils/deadmanssnitch_api.py +1 -1
  301. reconcile/utils/differ.py +2 -3
  302. reconcile/utils/early_exit_cache.py +11 -12
  303. reconcile/utils/environ.py +5 -0
  304. reconcile/utils/expiration.py +7 -3
  305. reconcile/utils/external_resource_spec.py +2 -0
  306. reconcile/utils/filtering.py +1 -1
  307. reconcile/utils/gitlab_api.py +19 -5
  308. reconcile/utils/glitchtip/client.py +6 -2
  309. reconcile/utils/glitchtip/models.py +25 -28
  310. reconcile/utils/gql.py +4 -7
  311. reconcile/utils/helpers.py +1 -1
  312. reconcile/utils/instrumented_wrappers.py +1 -1
  313. reconcile/utils/internal_groups/client.py +2 -2
  314. reconcile/utils/internal_groups/models.py +8 -17
  315. reconcile/utils/jinja2/utils.py +6 -101
  316. reconcile/utils/jira_client.py +82 -63
  317. reconcile/utils/jjb_client.py +26 -13
  318. reconcile/utils/jobcontroller/controller.py +2 -2
  319. reconcile/utils/jobcontroller/models.py +17 -1
  320. reconcile/utils/json.py +43 -1
  321. reconcile/utils/membershipsources/app_interface_resolver.py +4 -2
  322. reconcile/utils/membershipsources/models.py +16 -23
  323. reconcile/utils/membershipsources/resolver.py +4 -2
  324. reconcile/utils/merge_request_manager/merge_request_manager.py +4 -4
  325. reconcile/utils/merge_request_manager/parser.py +6 -6
  326. reconcile/utils/metrics.py +5 -5
  327. reconcile/utils/models.py +304 -82
  328. reconcile/utils/mr/app_interface_reporter.py +2 -2
  329. reconcile/utils/mr/notificator.py +3 -3
  330. reconcile/utils/mr/update_access_report_base.py +3 -4
  331. reconcile/utils/mr/user_maintenance.py +3 -2
  332. reconcile/utils/oc.py +252 -201
  333. reconcile/utils/oc_filters.py +3 -3
  334. reconcile/utils/ocm/addons.py +0 -1
  335. reconcile/utils/ocm/base.py +17 -20
  336. reconcile/utils/ocm/cluster_groups.py +1 -1
  337. reconcile/utils/ocm/identity_providers.py +2 -2
  338. reconcile/utils/ocm/labels.py +1 -1
  339. reconcile/utils/ocm/products.py +8 -8
  340. reconcile/utils/ocm/search_filters.py +3 -6
  341. reconcile/utils/ocm/service_log.py +4 -6
  342. reconcile/utils/ocm/sre_capability_labels.py +20 -13
  343. reconcile/utils/openshift_resource.py +8 -3
  344. reconcile/utils/pagerduty_api.py +10 -7
  345. reconcile/utils/promotion_state.py +6 -11
  346. reconcile/utils/quay_api.py +74 -87
  347. reconcile/utils/raw_github_api.py +1 -1
  348. reconcile/utils/rhcsv2_certs.py +86 -23
  349. reconcile/utils/rosa/session.py +16 -0
  350. reconcile/utils/runtime/integration.py +2 -3
  351. reconcile/utils/runtime/runner.py +2 -2
  352. reconcile/utils/saasherder/interfaces.py +13 -20
  353. reconcile/utils/saasherder/models.py +23 -20
  354. reconcile/utils/saasherder/saasherder.py +50 -27
  355. reconcile/utils/slack_api.py +2 -2
  356. reconcile/utils/sloth.py +171 -2
  357. reconcile/utils/structs.py +1 -1
  358. reconcile/utils/terraform_client.py +5 -4
  359. reconcile/utils/terrascript_aws_client.py +274 -124
  360. reconcile/utils/unleash/server.py +2 -8
  361. reconcile/utils/vault.py +5 -12
  362. reconcile/utils/vcs.py +8 -8
  363. reconcile/vault_replication.py +107 -42
  364. reconcile/vpc_peerings_validator.py +13 -0
  365. tools/app_interface_reporter.py +4 -4
  366. tools/cli_commands/cost_report/cost_management_api.py +3 -3
  367. tools/cli_commands/cost_report/view.py +7 -6
  368. tools/cli_commands/erv2.py +1 -1
  369. tools/qontract_cli.py +28 -17
  370. tools/template_validation.py +3 -1
  371. {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev474.dist-info}/entry_points.txt +0 -0
@@ -32,6 +32,7 @@ from reconcile.typed_queries.app_interface_vault_settings import (
32
32
  get_app_interface_vault_settings,
33
33
  )
34
34
  from reconcile.typed_queries.clusters_with_peering import get_clusters_with_peering
35
+ from reconcile.typed_queries.external_resources import get_settings
35
36
  from reconcile.typed_queries.terraform_tgw_attachments.aws_accounts import (
36
37
  get_aws_accounts,
37
38
  )
@@ -68,7 +69,7 @@ class ValidationError(Exception):
68
69
  class TGWAccountProviderInfo(BaseModel):
69
70
  name: str
70
71
  uid: str
71
- assume_role: str | None
72
+ assume_role: str | None = None
72
73
  assume_region: str
73
74
 
74
75
 
@@ -80,10 +81,10 @@ class Requester(BaseModel):
80
81
  tgw_id: str
81
82
  tgw_arn: str
82
83
  region: str
83
- routes: list[dict] | None
84
- rules: list[dict] | None
85
- hostedzones: list[str] | None
86
- cidr_block: str | None
84
+ routes: list[dict] | None = None
85
+ rules: list[dict] | None = None
86
+ hostedzones: list[str] | None = None
87
+ cidr_block: str | None = None
87
88
  cidr_blocks: list[str]
88
89
  account: TGWAccountProviderInfo
89
90
 
@@ -91,11 +92,11 @@ class Requester(BaseModel):
91
92
  class Accepter(BaseModel):
92
93
  cidr_block: str
93
94
  region: str
94
- vpc_id: str | None
95
- route_table_ids: list[str] | None
96
- subnets_id_az: list[dict[str, str]] | None
95
+ vpc_id: str | None = None
96
+ route_table_ids: list[str] | None = None
97
+ subnets_id_az: list[dict[str, str]] | None = None
97
98
  account: ClusterAccountProviderInfo
98
- api_security_group_id: str | None
99
+ api_security_group_id: str | None = None
99
100
 
100
101
 
101
102
  class DesiredStateItem(BaseModel):
@@ -192,7 +193,7 @@ def _build_desired_state_tgw_connection(
192
193
  yield None
193
194
 
194
195
  account_tgws = awsapi.get_tgws_details(
195
- peer_connection.account.dict(by_alias=True),
196
+ peer_connection.account.model_dump(by_alias=True),
196
197
  cluster_region,
197
198
  cluster_cidr_block,
198
199
  tags=peer_connection.tags or {},
@@ -274,7 +275,7 @@ def _build_accepter(
274
275
  )
275
276
  (vpc_id, route_table_ids, subnets_id_az, api_security_group_id) = (
276
277
  awsapi.get_cluster_vpc_details(
277
- account.dict(by_alias=True),
278
+ account.model_dump(by_alias=True),
278
279
  route_tables=bool(peer_connection.manage_routes),
279
280
  subnets=True,
280
281
  hcp_vpc_endpoint_sg=allow_hcp_private_api_access,
@@ -317,12 +318,12 @@ def _build_ocm_map(
317
318
  clusters: Iterable[ClusterV1],
318
319
  vault_settings: AppInterfaceSettingsV1,
319
320
  ) -> OCMMap | None:
320
- ocm_clusters = [c.dict(by_alias=True) for c in clusters if c.ocm]
321
+ ocm_clusters = [c.model_dump(by_alias=True) for c in clusters if c.ocm]
321
322
  return (
322
323
  OCMMap(
323
324
  clusters=ocm_clusters,
324
325
  integration=QONTRACT_INTEGRATION,
325
- settings=vault_settings.dict(by_alias=True),
326
+ settings=vault_settings.model_dump(by_alias=True),
326
327
  )
327
328
  if ocm_clusters
328
329
  # this is a case for an OCP cluster which is not provisioned
@@ -346,7 +347,7 @@ def _populate_tgw_attachments_working_dirs(
346
347
  accounts_by_infra_account_name: dict[str, list[dict[str, Any]]] = {}
347
348
  for item in desired_state:
348
349
  accounts_by_infra_account_name.setdefault(item.infra_acount_name, []).append(
349
- item.accepter.account.dict(by_alias=True)
350
+ item.accepter.account.model_dump(by_alias=True)
350
351
  )
351
352
  for infra_account_name, accounts in accounts_by_infra_account_name.items():
352
353
  ts.populate_additional_providers(infra_account_name, accounts)
@@ -428,7 +429,9 @@ def setup(
428
429
  print_to_file: str | None = None,
429
430
  ) -> tuple[SecretReaderBase, AWSApi, Terraform, Terrascript]:
430
431
  tgw_clusters = desired_state_data_source.clusters
431
- all_accounts = [a.dict(by_alias=True) for a in desired_state_data_source.accounts]
432
+ all_accounts = [
433
+ a.model_dump(by_alias=True) for a in desired_state_data_source.accounts
434
+ ]
432
435
  account_by_name = {a["name"]: a for a in all_accounts}
433
436
  vault_settings = get_app_interface_vault_settings()
434
437
  secret_reader = create_secret_reader(vault_settings.vault)
@@ -444,13 +447,18 @@ def setup(
444
447
  raise RuntimeError("Could not find VPC ID for cluster")
445
448
 
446
449
  _validate_tgw_connection_names(desired_state)
447
-
450
+ try:
451
+ default_tags = get_settings().default_tags
452
+ except ValueError:
453
+ # no external resources settings found
454
+ default_tags = None
448
455
  ts = Terrascript(
449
456
  QONTRACT_INTEGRATION,
450
457
  "",
451
458
  thread_pool_size,
452
459
  tgw_accounts,
453
- settings=vault_settings.dict(by_alias=True),
460
+ settings=vault_settings.model_dump(by_alias=True),
461
+ default_tags=default_tags,
454
462
  )
455
463
  tgw_rosa_cluster_accounts = [
456
464
  account_by_name[c.spec.account.name]
@@ -510,7 +518,7 @@ def run(
510
518
  ) -> None:
511
519
  desired_state_data_source = _fetch_desired_state_data_source(account_name)
512
520
  tgw_accounts = [
513
- a.dict(by_alias=True)
521
+ a.model_dump(by_alias=True)
514
522
  for a in _filter_tgw_accounts(
515
523
  desired_state_data_source.accounts, desired_state_data_source.clusters
516
524
  )
@@ -567,7 +575,7 @@ def early_exit_desired_state(*args: Any, **kwargs: Any) -> dict[str, Any]:
567
575
  desired_state = _fetch_desired_state_data_source()
568
576
  for a in desired_state.accounts:
569
577
  a.deletion_approvals = []
570
- return desired_state.dict(by_alias=True)
578
+ return desired_state.model_dump(by_alias=True)
571
579
 
572
580
 
573
581
  def desired_state_shard_config() -> DesiredStateShardConfig:
@@ -11,6 +11,7 @@ from reconcile import (
11
11
  )
12
12
  from reconcile.change_owners.diff import IDENTIFIER_FIELD_NAME
13
13
  from reconcile.gql_definitions.common.pgp_reencryption_settings import query
14
+ from reconcile.typed_queries.external_resources import get_settings
14
15
  from reconcile.utils import (
15
16
  expiration,
16
17
  gql,
@@ -126,12 +127,18 @@ def setup(
126
127
  participating_aws_accounts = _filter_participating_aws_accounts(accounts, roles)
127
128
 
128
129
  settings = queries.get_app_interface_settings()
130
+ try:
131
+ default_tags = get_settings().default_tags
132
+ except ValueError:
133
+ # no external resources settings found
134
+ default_tags = None
129
135
  ts = Terrascript(
130
136
  QONTRACT_INTEGRATION,
131
137
  QONTRACT_TF_PREFIX,
132
138
  thread_pool_size,
133
139
  participating_aws_accounts,
134
140
  settings=settings,
141
+ default_tags=default_tags,
135
142
  )
136
143
  err = ts.populate_users(
137
144
  roles,
@@ -7,6 +7,7 @@ from typing import Any, TypedDict
7
7
  import reconcile.utils.terraform_client as terraform
8
8
  import reconcile.utils.terrascript_aws_client as terrascript
9
9
  from reconcile import queries
10
+ from reconcile.typed_queries import external_resources
10
11
  from reconcile.utils import (
11
12
  aws_api,
12
13
  ocm,
@@ -654,8 +655,18 @@ def run(
654
655
  ])
655
656
 
656
657
  account_by_name = {a["name"]: a for a in accounts}
658
+ try:
659
+ default_tags = external_resources.get_settings().default_tags
660
+ except ValueError:
661
+ # no external resources settings found
662
+ default_tags = None
657
663
  with terrascript.TerrascriptClient(
658
- QONTRACT_INTEGRATION, "", thread_pool_size, infra_accounts, settings=settings
664
+ QONTRACT_INTEGRATION,
665
+ "",
666
+ thread_pool_size,
667
+ infra_accounts,
668
+ settings=settings,
669
+ default_tags=default_tags,
659
670
  ) as ts:
660
671
  rosa_cluster_accounts = [
661
672
  account_by_name[c["spec"]["account"]["name"]]
@@ -664,8 +675,8 @@ def run(
664
675
  ]
665
676
  ts.populate_configs(rosa_cluster_accounts)
666
677
 
667
- for infra_account_name, items in participating_accounts.items():
668
- ts.populate_additional_providers(infra_account_name, items)
678
+ for infra_account_name, accounts in participating_accounts.items():
679
+ ts.populate_additional_providers(infra_account_name, accounts)
669
680
  ts.populate_vpc_peerings(desired_state)
670
681
  working_dirs = ts.dump(print_to_file=print_to_file)
671
682
  terraform_configurations = ts.terraform_configurations()
@@ -20,9 +20,11 @@ from reconcile.typed_queries.app_interface_vault_settings import (
20
20
  get_app_interface_vault_settings,
21
21
  )
22
22
  from reconcile.typed_queries.aws_vpc_requests import get_aws_vpc_requests
23
+ from reconcile.typed_queries.external_resources import get_settings
23
24
  from reconcile.typed_queries.github_orgs import get_github_orgs
24
25
  from reconcile.typed_queries.gitlab_instances import get_gitlab_instances
25
26
  from reconcile.utils import gql
27
+ from reconcile.utils.disabled_integrations import integration_is_enabled
26
28
  from reconcile.utils.runtime.integration import (
27
29
  DesiredStateShardConfig,
28
30
  PydanticRunParams,
@@ -61,12 +63,14 @@ class TerraformVpcResources(QontractReconcileIntegration[TerraformVpcResourcesPa
61
63
  ) -> list[AWSAccountV1]:
62
64
  """Return a list of accounts extracted from the provided VPCRequests.
63
65
  If account_name is given returns the account object with that name."""
64
- accounts = [vpc.account for vpc in data]
65
-
66
- if account_name:
67
- accounts = [account for account in accounts if account.name == account_name]
68
-
69
- return accounts
66
+ return [
67
+ vpc.account
68
+ for vpc in data
69
+ if (
70
+ integration_is_enabled(self.name, vpc.account)
71
+ and (not account_name or vpc.account.name == account_name)
72
+ )
73
+ ]
70
74
 
71
75
  def _handle_outputs(
72
76
  self, requests: Iterable[VPCRequest], outputs: Mapping[str, Any]
@@ -154,20 +158,28 @@ class TerraformVpcResources(QontractReconcileIntegration[TerraformVpcResourcesPa
154
158
  if data:
155
159
  accounts = self._filter_accounts(data, account_name)
156
160
  if account_name and not accounts:
157
- msg = f"The account {account_name} doesn't have any managed vpc. Verify your input"
161
+ msg = f"The account {account_name} doesn't have any managed vpcs or the {QONTRACT_INTEGRATION} integration is disabled for this account. Verify your input"
158
162
  logging.debug(msg)
159
163
  sys.exit(ExitCodes.SUCCESS)
160
164
  else:
161
165
  logging.debug("No VPC requests found, nothing to do.")
162
166
  sys.exit(ExitCodes.SUCCESS)
163
167
 
164
- accounts_untyped: list[dict] = [acc.dict(by_alias=True) for acc in accounts]
168
+ accounts_untyped: list[dict] = [
169
+ acc.model_dump(by_alias=True) for acc in accounts
170
+ ]
171
+ try:
172
+ default_tags = get_settings().default_tags
173
+ except ValueError:
174
+ # no external resources settings found
175
+ default_tags = None
165
176
  with TerrascriptClient(
166
177
  integration=QONTRACT_INTEGRATION,
167
178
  integration_prefix=QONTRACT_TF_PREFIX,
168
179
  thread_pool_size=thread_pool_size,
169
180
  accounts=accounts_untyped,
170
181
  secret_reader=secret_reader,
182
+ default_tags=default_tags,
171
183
  ) as ts_client:
172
184
  ts_client.populate_vpc_requests(data, AWS_PROVIDER_VERSION)
173
185
 
@@ -1,5 +1,6 @@
1
1
  import re
2
2
  import string
3
+ from enum import StrEnum
3
4
 
4
5
  from pydantic import BaseModel
5
6
 
@@ -9,6 +10,12 @@ PROMOTION_DATA_SEPARATOR = "**DO NOT MANUALLY CHANGE ANYTHING BELOW THIS LINE**"
9
10
  VERSION = "0.1.0"
10
11
  LABEL = "terraform-vpc-resources"
11
12
 
13
+
14
+ class Action(StrEnum):
15
+ CREATE = "create"
16
+ UPDATE = "update"
17
+
18
+
12
19
  VERSION_REF = "tf_vpc_resources_version"
13
20
  ACCOUNT_REF = "account"
14
21
  COMPILED_REGEXES = {
@@ -53,5 +60,8 @@ class Renderer:
53
60
  def render_description(self, account: str) -> str:
54
61
  return DESC.safe_substitute(account=account)
55
62
 
56
- def render_title(self, account: str) -> str:
57
- return f"[auto] VPC data file creation to {account}"
63
+ def render_title(self, account: str, action: Action) -> str:
64
+ return f"[auto] {action} VPC data file for {account}"
65
+
66
+ def render_update_title(self, account: str) -> str:
67
+ return f"[auto] VPC data file update for {account}"
@@ -5,6 +5,7 @@ from pydantic import BaseModel
5
5
 
6
6
  from reconcile.terraform_vpc_resources.merge_request import (
7
7
  LABEL,
8
+ Action,
8
9
  Info,
9
10
  Renderer,
10
11
  )
@@ -28,6 +29,7 @@ class VPCRequestMR(MergeRequestBase):
28
29
  vpc_tmpl_file_path: str,
29
30
  vpc_tmpl_file_content: str,
30
31
  labels: list[str],
32
+ action: Action,
31
33
  ):
32
34
  super().__init__()
33
35
  self._title = title
@@ -35,6 +37,7 @@ class VPCRequestMR(MergeRequestBase):
35
37
  self._vpc_tmpl_file_path = vpc_tmpl_file_path
36
38
  self._vpc_tmpl_file_content = vpc_tmpl_file_content
37
39
  self.labels = labels
40
+ self._action = action
38
41
 
39
42
  @property
40
43
  def title(self) -> str:
@@ -45,12 +48,21 @@ class VPCRequestMR(MergeRequestBase):
45
48
  return self._description
46
49
 
47
50
  def process(self, gitlab_cli: GitLabApi) -> None:
48
- gitlab_cli.create_file(
49
- branch_name=self.branch,
50
- file_path=self._vpc_tmpl_file_path,
51
- commit_message="add vpc datafile",
52
- content=self._vpc_tmpl_file_content,
53
- )
51
+ # Create or update file based on whether it already exists
52
+ if self._action == Action.UPDATE:
53
+ gitlab_cli.update_file(
54
+ branch_name=self.branch,
55
+ file_path=self._vpc_tmpl_file_path,
56
+ commit_message="update vpc datafile",
57
+ content=self._vpc_tmpl_file_content,
58
+ )
59
+ else:
60
+ gitlab_cli.create_file(
61
+ branch_name=self.branch,
62
+ file_path=self._vpc_tmpl_file_path,
63
+ commit_message="add vpc datafile",
64
+ content=self._vpc_tmpl_file_content,
65
+ )
54
66
 
55
67
 
56
68
  class MrData(BaseModel):
@@ -73,26 +85,37 @@ class MergeRequestManager(MergeRequestManagerBase[Info]):
73
85
  self._renderer = renderer
74
86
  self._auto_merge_enabled = auto_merge_enabled
75
87
 
76
- def create_merge_request(self, data: MrData) -> None:
77
- """Open a new MR, if not already present, for a VPC datafile and close any outdated before."""
78
- if not self._housekeeping_ran:
79
- self.housekeeping()
80
-
88
+ def _create_action(self, data: MrData) -> Action | None:
81
89
  if self._merge_request_already_exists({"account": data.account}):
82
90
  logging.info("MR already exists for %s", data.account)
83
91
  return None
84
-
85
92
  try:
86
- self._vcs.get_file_content_from_app_interface_ref(file_path=data.path)
87
- # the file exists, nothing to do
88
- return None
93
+ existing_content = self._vcs.get_file_content_from_app_interface_ref(
94
+ file_path=data.path
95
+ )
89
96
  except GitlabGetError as e:
90
- if e.response_code != 404:
91
- raise
97
+ if e.response_code == 404:
98
+ return Action.CREATE
99
+ raise
100
+
101
+ if existing_content.strip() != data.content.strip():
102
+ return Action.UPDATE
103
+
104
+ logging.info("VPC data file exists and is up-to-date for %s", data.account)
105
+ return None
106
+
107
+ def create_merge_request(self, data: MrData) -> None:
108
+ """Open a new MR for VPC datafile updates, or update existing if changed."""
109
+ if not self._housekeeping_ran:
110
+ self.housekeeping()
111
+ action = self._create_action(data)
112
+ if action is None:
113
+ return
92
114
 
93
115
  description = self._renderer.render_description(account=data.account)
94
- title = self._renderer.render_title(account=data.account)
95
- logging.info("Open MR for %s", data.account)
116
+ title = self._renderer.render_title(account=data.account, action=action)
117
+
118
+ logging.info("Open MR for %s (%s)", data.account, action)
96
119
  mr_labels = [LABEL]
97
120
  if self._auto_merge_enabled:
98
121
  mr_labels.append(AUTO_MERGE)
@@ -103,5 +126,6 @@ class MergeRequestManager(MergeRequestManagerBase[Info]):
103
126
  description=description,
104
127
  vpc_tmpl_file_content=data.content,
105
128
  labels=mr_labels,
129
+ action=action,
106
130
  )
107
131
  )
@@ -0,0 +1,41 @@
1
+ import json
2
+ from collections.abc import Mapping
3
+
4
+ from reconcile.gql_definitions.fragments.aws_organization import (
5
+ AWSOrganization,
6
+ )
7
+
8
+
9
+ def get_aws_account_tags(
10
+ organization: AWSOrganization | Mapping | None,
11
+ ) -> dict[str, str]:
12
+ """
13
+ Get AWS account tags by merging payer account tags
14
+
15
+ Args:
16
+ organization: AWSOrganization | Mapping | None - The organization object from which to extract tags.
17
+
18
+ Returns:
19
+ dict[str, str]: A dictionary containing the merged tags from the payer account and the account itself.
20
+ """
21
+ if organization is None:
22
+ return {}
23
+
24
+ match organization:
25
+ case AWSOrganization():
26
+ payer_account_tags = (
27
+ organization.payer_account.organization_account_tags or {}
28
+ )
29
+ account_tags = organization.tags or {}
30
+ case Mapping():
31
+ payer_account_tags = organization.get("payerAccount", {}).get(
32
+ "organizationAccountTags", {}
33
+ )
34
+ if isinstance(payer_account_tags, str):
35
+ payer_account_tags = json.loads(payer_account_tags)
36
+
37
+ account_tags = organization.get("tags", {})
38
+ if isinstance(account_tags, str):
39
+ account_tags = json.loads(account_tags)
40
+
41
+ return payer_account_tags | account_tags
@@ -6,7 +6,7 @@ from reconcile.utils.gql import GqlApi
6
6
 
7
7
  class App(BaseModel):
8
8
  name: str
9
- parent_app_name: str | None
9
+ parent_app_name: str | None = None
10
10
 
11
11
 
12
12
  def get_app_names(
@@ -13,7 +13,7 @@ class CostNamespace(BaseModel, frozen=True):
13
13
  labels: CostNamespaceLabels
14
14
  app_name: str
15
15
  cluster_name: str
16
- cluster_external_id: str | None
16
+ cluster_external_id: str | None = None
17
17
 
18
18
 
19
19
  def get_cost_namespaces(
@@ -32,7 +32,7 @@ def get_cost_namespaces(
32
32
  return [
33
33
  CostNamespace(
34
34
  name=namespace.name,
35
- labels=CostNamespaceLabels.parse_obj(namespace.labels or {}),
35
+ labels=CostNamespaceLabels.model_validate(namespace.labels or {}),
36
36
  app_name=namespace.app.name,
37
37
  cluster_name=namespace.cluster.name,
38
38
  cluster_external_id=namespace.cluster.spec.external_id
@@ -6,7 +6,6 @@ from typing import Any
6
6
  from jsonpath_ng.exceptions import JsonPathParserError
7
7
  from pydantic import (
8
8
  BaseModel,
9
- Extra,
10
9
  Field,
11
10
  Json,
12
11
  )
@@ -43,6 +42,7 @@ from reconcile.gql_definitions.fragments.saas_target_namespace import (
43
42
  SaasTargetNamespace,
44
43
  )
45
44
  from reconcile.utils import gql
45
+ from reconcile.utils.environ import used_for_security_is_enabled
46
46
  from reconcile.utils.exceptions import (
47
47
  AppInterfaceSettingsError,
48
48
  ParameterError,
@@ -51,7 +51,12 @@ from reconcile.utils.json import json_dumps
51
51
  from reconcile.utils.jsonpath import parse_jsonpath
52
52
 
53
53
 
54
- class SaasResourceTemplateTarget(ConfiguredBaseModel):
54
+ class SaasResourceTemplateTarget(
55
+ ConfiguredBaseModel,
56
+ validate_by_alias=True,
57
+ # ignore `namespaceSelector` and 'provider' fields from the GQL schema
58
+ extra="ignore",
59
+ ):
55
60
  path: str | None = Field(..., alias="path")
56
61
  name: str | None = Field(..., alias="name")
57
62
  # the namespace must be required to fulfill the saas file schema (utils.saasherder.interface.SaasFile)
@@ -74,17 +79,17 @@ class SaasResourceTemplateTarget(ConfiguredBaseModel):
74
79
  self, parent_saas_file_name: str, parent_resource_template_name: str
75
80
  ) -> str:
76
81
  """Returns a unique identifier for a target."""
77
- return hashlib.blake2s(
78
- f"{parent_saas_file_name}:{parent_resource_template_name}:{self.name or 'default'}:{self.namespace.cluster.name}:{self.namespace.name}".encode(),
79
- digest_size=20,
80
- ).hexdigest()
81
-
82
- class Config:
83
- # ignore `namespaceSelector` and 'provider' fields from the GQL schema
84
- extra = Extra.ignore
82
+ data = f"{parent_saas_file_name}:{parent_resource_template_name}:{self.name or 'default'}:{self.namespace.cluster.name}:{self.namespace.name}".encode()
83
+ if used_for_security_is_enabled():
84
+ # When USED_FOR_SECURITY is enabled, use blake2s without digest_size and truncate to 20 bytes
85
+ # This is needed for FIPS compliance where digest_size parameter is not supported
86
+ return hashlib.sha256(data).digest()[:20].hex()
87
+ else:
88
+ # Default behavior: use blake2s with digest_size=20
89
+ return hashlib.blake2s(data, digest_size=20).hexdigest()
85
90
 
86
91
 
87
- class SaasResourceTemplate(ConfiguredBaseModel):
92
+ class SaasResourceTemplate(ConfiguredBaseModel, validate_by_alias=True):
88
93
  name: str = Field(..., alias="name")
89
94
  url: str = Field(..., alias="url")
90
95
  path: str = Field(..., alias="path")
@@ -97,7 +102,7 @@ class SaasResourceTemplate(ConfiguredBaseModel):
97
102
  targets: list[SaasResourceTemplateTarget] = Field(..., alias="targets")
98
103
 
99
104
 
100
- class SaasFile(ConfiguredBaseModel):
105
+ class SaasFile(ConfiguredBaseModel, validate_by_alias=True):
101
106
  path: str = Field(..., alias="path")
102
107
  name: str = Field(..., alias="name")
103
108
  labels: Json | None = Field(..., alias="labels")
@@ -221,7 +226,7 @@ class SaasFileList:
221
226
  with self._namespaces_as_dict_lock:
222
227
  self._namespaces_as_dict_cache = {
223
228
  "namespace": [
224
- ns.dict(by_alias=True, exclude_none=True)
229
+ ns.model_dump(by_alias=True, exclude_none=True)
225
230
  for ns in self.namespaces
226
231
  ]
227
232
  }
@@ -283,7 +288,7 @@ class SaasFileList:
283
288
  if app_name and saas_file.app.name != app_name:
284
289
  continue
285
290
 
286
- sf = saas_file.copy(deep=True)
291
+ sf = saas_file.model_copy(deep=True)
287
292
  if env_name:
288
293
  for rt in sf.resource_templates[:]:
289
294
  for target in rt.targets[:]:
@@ -314,7 +319,7 @@ def convert_parameters_to_json_string(root: dict[str, Any]) -> dict[str, Any]:
314
319
 
315
320
 
316
321
  def export_model(model: BaseModel) -> dict[str, Any]:
317
- return convert_parameters_to_json_string(model.dict(by_alias=True))
322
+ return convert_parameters_to_json_string(model.model_dump(by_alias=True))
318
323
 
319
324
 
320
325
  def get_saas_files(
@@ -32,7 +32,7 @@ def get_selected_app_names(
32
32
  prefix = f"{namespace.app.parent_app.name}-"
33
33
  name = f"{prefix}{namespace.app.name}"
34
34
  selected_app_names.add(name)
35
- app = namespace.app.dict(by_alias=True)
35
+ app = namespace.app.model_dump(by_alias=True)
36
36
  app["name"] = name
37
37
  apps["apps"].append(app)
38
38
 
@@ -40,7 +40,7 @@ def get_selected_app_names(
40
40
  name = f"{namespace.app.name}-{child.name}"
41
41
  if name not in selected_app_names:
42
42
  selected_app_names.add(f"{namespace.app.name}-{child.name}")
43
- child_dict = child.dict(by_alias=True)
43
+ child_dict = child.model_dump(by_alias=True)
44
44
  child_dict["name"] = name
45
45
  apps["apps"].append(child_dict)
46
46
 
@@ -31,7 +31,7 @@ QONTRACT_INTEGRATION_VERSION = make_semver(1, 0, 0)
31
31
 
32
32
 
33
33
  class UnleashTogglesIntegrationParams(PydanticRunParams):
34
- instance: str | None
34
+ instance: str | None = None
35
35
 
36
36
 
37
37
  def feature_toggle_equal(c: FeatureToggle, d: FeatureToggleUnleashV1) -> bool:
@@ -68,7 +68,9 @@ class UnleashTogglesIntegration(
68
68
  if not query_func:
69
69
  query_func = gql.get_api().query
70
70
  return {
71
- "toggles": [ft.dict() for ft in self.get_unleash_instances(query_func)],
71
+ "toggles": [
72
+ ft.model_dump() for ft in self.get_unleash_instances(query_func)
73
+ ],
72
74
  }
73
75
 
74
76
  def get_unleash_instances(
@@ -6,7 +6,7 @@ from typing import (
6
6
  )
7
7
 
8
8
  import requests
9
- from pydantic import BaseModel
9
+ from pydantic import BaseModel, ConfigDict
10
10
 
11
11
  from reconcile.gql_definitions.acs.acs_instances import AcsInstanceV1
12
12
  from reconcile.gql_definitions.acs.acs_instances import query as acs_instances_query
@@ -19,8 +19,11 @@ class AcsBaseApi(BaseModel):
19
19
  timeout: int = 30
20
20
  session: requests.Session = requests.Session()
21
21
 
22
- class Config:
23
- arbitrary_types_allowed = True
22
+ model_config = ConfigDict(
23
+ validate_by_name=True,
24
+ validate_by_alias=True,
25
+ arbitrary_types_allowed=True,
26
+ )
24
27
 
25
28
  def __enter__(self) -> Self:
26
29
  return self
@@ -11,7 +11,7 @@ class Scope(BaseModel):
11
11
  """
12
12
 
13
13
  cluster: str
14
- namespace: str | None
14
+ namespace: str | None = None
15
15
 
16
16
 
17
17
  class PolicyCondition(BaseModel):
@@ -23,7 +23,7 @@ class PolicyCondition(BaseModel):
23
23
  """
24
24
 
25
25
  field_name: str
26
- negate: bool | None
26
+ negate: bool | None = None
27
27
  values: list[str]
28
28
 
29
29