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
reconcile/queries.py CHANGED
@@ -477,6 +477,12 @@ AWS_ACCOUNTS_QUERY = """
477
477
  integrations
478
478
  }
479
479
  deleteKeys
480
+ organization {
481
+ payerAccount {
482
+ organizationAccountTags
483
+ }
484
+ tags
485
+ }
480
486
  {% if reset_passwords %}
481
487
  resetPasswords {
482
488
  user {
@@ -499,6 +505,12 @@ AWS_ACCOUNTS_QUERY = """
499
505
  name
500
506
  uid
501
507
  supportedDeploymentRegions
508
+ organization {
509
+ payerAccount {
510
+ organizationAccountTags
511
+ }
512
+ tags
513
+ }
502
514
  }
503
515
  ... on AWSAccountSharingOptionAMI_v1 {
504
516
  regex
@@ -606,6 +618,12 @@ awsInfrastructureManagementAccounts {
606
618
  version
607
619
  format
608
620
  }
621
+ organization {
622
+ payerAccount {
623
+ organizationAccountTags
624
+ }
625
+ tags
626
+ }
609
627
  }
610
628
  accessLevel
611
629
  default
@@ -636,6 +654,12 @@ awsInfrastructureAccess {
636
654
  version
637
655
  format
638
656
  }
657
+ organization {
658
+ payerAccount {
659
+ organizationAccountTags
660
+ }
661
+ tags
662
+ }
639
663
  }
640
664
  roles {
641
665
  users {
@@ -745,6 +769,12 @@ CLUSTERS_QUERY = """
745
769
  version
746
770
  format
747
771
  }
772
+ organization {
773
+ payerAccount {
774
+ organizationAccountTags
775
+ }
776
+ tags
777
+ }
748
778
  rosa {
749
779
  ocm_environments {
750
780
  ocm {
@@ -773,6 +803,7 @@ CLUSTERS_QUERY = """
773
803
  private
774
804
  provision_shard_id
775
805
  disable_user_workload_monitoring
806
+ fips
776
807
  }
777
808
  externalConfiguration {
778
809
  labels
@@ -829,6 +860,12 @@ CLUSTERS_QUERY = """
829
860
  version
830
861
  format
831
862
  }
863
+ organization {
864
+ payerAccount {
865
+ organizationAccountTags
866
+ }
867
+ tags
868
+ }
832
869
  }
833
870
  vpc_id
834
871
  cidr_block
@@ -847,6 +884,12 @@ CLUSTERS_QUERY = """
847
884
  version
848
885
  format
849
886
  }
887
+ organization {
888
+ payerAccount {
889
+ organizationAccountTags
890
+ }
891
+ tags
892
+ }
850
893
  }
851
894
  tags
852
895
  }
@@ -861,6 +904,12 @@ CLUSTERS_QUERY = """
861
904
  version
862
905
  format
863
906
  }
907
+ organization {
908
+ payerAccount {
909
+ organizationAccountTags
910
+ }
911
+ tags
912
+ }
864
913
  }
865
914
  tags
866
915
  cidrBlock
@@ -889,6 +938,12 @@ CLUSTERS_QUERY = """
889
938
  version
890
939
  format
891
940
  }
941
+ organization {
942
+ payerAccount {
943
+ organizationAccountTags
944
+ }
945
+ tags
946
+ }
892
947
  }
893
948
  }
894
949
  accessLevel
@@ -914,6 +969,12 @@ CLUSTERS_QUERY = """
914
969
  version
915
970
  format
916
971
  }
972
+ organization {
973
+ payerAccount {
974
+ organizationAccountTags
975
+ }
976
+ tags
977
+ }
917
978
  }
918
979
  }
919
980
  }
@@ -1067,6 +1128,12 @@ CLUSTER_PEERING_QUERY = """
1067
1128
  version
1068
1129
  format
1069
1130
  }
1131
+ organization {
1132
+ payerAccount {
1133
+ organizationAccountTags
1134
+ }
1135
+ tags
1136
+ }
1070
1137
  }
1071
1138
  accessLevel
1072
1139
  default
@@ -1088,6 +1155,12 @@ CLUSTER_PEERING_QUERY = """
1088
1155
  version
1089
1156
  format
1090
1157
  }
1158
+ organization {
1159
+ payerAccount {
1160
+ organizationAccountTags
1161
+ }
1162
+ tags
1163
+ }
1091
1164
  }
1092
1165
  }
1093
1166
  }
@@ -1112,6 +1185,12 @@ CLUSTER_PEERING_QUERY = """
1112
1185
  version
1113
1186
  format
1114
1187
  }
1188
+ organization {
1189
+ payerAccount {
1190
+ organizationAccountTags
1191
+ }
1192
+ tags
1193
+ }
1115
1194
  }
1116
1195
  vpc_id
1117
1196
  cidr_block
@@ -1131,6 +1210,12 @@ CLUSTER_PEERING_QUERY = """
1131
1210
  version
1132
1211
  format
1133
1212
  }
1213
+ organization {
1214
+ payerAccount {
1215
+ organizationAccountTags
1216
+ }
1217
+ tags
1218
+ }
1134
1219
  }
1135
1220
  tags
1136
1221
  assumeRole
@@ -1146,6 +1231,12 @@ CLUSTER_PEERING_QUERY = """
1146
1231
  version
1147
1232
  format
1148
1233
  }
1234
+ organization {
1235
+ payerAccount {
1236
+ organizationAccountTags
1237
+ }
1238
+ tags
1239
+ }
1149
1240
  }
1150
1241
  tags
1151
1242
  cidrBlock
@@ -1175,6 +1266,12 @@ CLUSTER_PEERING_QUERY = """
1175
1266
  version
1176
1267
  format
1177
1268
  }
1269
+ organization {
1270
+ payerAccount {
1271
+ organizationAccountTags
1272
+ }
1273
+ tags
1274
+ }
1178
1275
  }
1179
1276
  }
1180
1277
  }
@@ -1190,6 +1287,12 @@ CLUSTER_PEERING_QUERY = """
1190
1287
  version
1191
1288
  format
1192
1289
  }
1290
+ organization {
1291
+ payerAccount {
1292
+ organizationAccountTags
1293
+ }
1294
+ tags
1295
+ }
1193
1296
  }
1194
1297
  accessLevel
1195
1298
  default
@@ -1216,6 +1319,12 @@ CLUSTER_PEERING_QUERY = """
1216
1319
  version
1217
1320
  format
1218
1321
  }
1322
+ organization {
1323
+ payerAccount {
1324
+ organizationAccountTags
1325
+ }
1326
+ tags
1327
+ }
1219
1328
  }
1220
1329
  }
1221
1330
  }
@@ -1231,6 +1340,12 @@ CLUSTER_PEERING_QUERY = """
1231
1340
  version
1232
1341
  format
1233
1342
  }
1343
+ organization {
1344
+ payerAccount {
1345
+ organizationAccountTags
1346
+ }
1347
+ tags
1348
+ }
1234
1349
  }
1235
1350
  }
1236
1351
  }
@@ -1700,7 +1815,7 @@ def get_review_repos() -> list[dict[str, str]]:
1700
1815
  return [
1701
1816
  {"url": c["url"], "name": c["name"]}
1702
1817
  for c in code_components
1703
- if c["showInReviewQueue"] is not None
1818
+ if c.get("showInReviewQueue", False)
1704
1819
  ]
1705
1820
 
1706
1821
 
@@ -2230,6 +2345,12 @@ JIRA_BOARDS_QUICK_QUERY = """
2230
2345
  version
2231
2346
  format
2232
2347
  }
2348
+ email {
2349
+ path
2350
+ field
2351
+ version
2352
+ format
2353
+ }
2233
2354
  }
2234
2355
  }
2235
2356
  }
@@ -2336,6 +2457,12 @@ DNS_ZONES_QUERY = """
2336
2457
  version
2337
2458
  format
2338
2459
  }
2460
+ organization {
2461
+ payerAccount {
2462
+ organizationAccountTags
2463
+ }
2464
+ tags
2465
+ }
2339
2466
  }
2340
2467
  vpc {
2341
2468
  vpc_id
@@ -2697,6 +2824,10 @@ APP_METADATA = """
2697
2824
  path
2698
2825
  field
2699
2826
  }
2827
+ email {
2828
+ path
2829
+ field
2830
+ }
2700
2831
  }
2701
2832
  }
2702
2833
  slackUserGroup {
reconcile/rhidp/common.py CHANGED
@@ -7,10 +7,7 @@ from enum import StrEnum
7
7
  from typing import Any
8
8
  from urllib.parse import urlparse
9
9
 
10
- from pydantic import (
11
- BaseModel,
12
- root_validator,
13
- )
10
+ from pydantic import BaseModel, model_validator
14
11
 
15
12
  from reconcile.gql_definitions.common.ocm_environments import (
16
13
  query as ocm_environment_query,
@@ -63,7 +60,8 @@ class ClusterAuth(BaseModel):
63
60
  issuer: str
64
61
  status: str
65
62
 
66
- @root_validator
63
+ @model_validator(mode="before")
64
+ @classmethod
67
65
  def name_no_spaces(
68
66
  cls, values: MutableMapping[str, Any]
69
67
  ) -> MutableMapping[str, Any]:
@@ -1,3 +1,4 @@
1
+ import http
1
2
  import logging
2
3
  from collections.abc import (
3
4
  Iterable,
@@ -10,6 +11,7 @@ from urllib.parse import (
10
11
  )
11
12
 
12
13
  import jwt
14
+ from requests import HTTPError
13
15
 
14
16
  from reconcile.rhidp.common import (
15
17
  Cluster,
@@ -237,7 +239,7 @@ def create_sso_client(
237
239
  secret_reader.vault_client.write(
238
240
  secret={
239
241
  "path": secret.path,
240
- "data": sso_client.dict(),
242
+ "data": sso_client.model_dump(),
241
243
  },
242
244
  decode_base64=False,
243
245
  )
@@ -256,9 +258,18 @@ def delete_sso_client(
256
258
  )
257
259
  sso_client = SSOClient(**secret_reader.read_all_secret(secret=secret))
258
260
  keycloak_api = keycloak_map.get(sso_client.issuer)
259
- keycloak_api.delete_client(
260
- registration_client_uri=sso_client.registration_client_uri,
261
- registration_access_token=sso_client.registration_access_token,
262
- )
261
+ try:
262
+ keycloak_api.delete_client(
263
+ registration_client_uri=sso_client.registration_client_uri,
264
+ registration_access_token=sso_client.registration_access_token,
265
+ )
266
+ except HTTPError as e:
267
+ if e.response.status_code != http.HTTPStatus.UNAUTHORIZED:
268
+ logging.error(f"Failed to delete SSO client {sso_client_id}: {e}")
269
+ raise
270
+ # something went wrong with the registration token, maybe it expired
271
+ logging.error(
272
+ f"Failed to delete SSO client {sso_client_id} due to unauthorized error: {e}. Continuing to delete the vault secret."
273
+ )
263
274
 
264
275
  secret_reader.vault_client.delete(path=secret.path)
@@ -177,7 +177,7 @@ def is_namespace_addressed_by_selector(
177
177
  # json representation of namespace to filter on
178
178
  # remove all the None values to simplify the jsonpath expressions
179
179
  namespace_as_dict = {
180
- "namespace": [namespace.dict(by_alias=True, exclude_none=True)]
180
+ "namespace": [namespace.model_dump(by_alias=True, exclude_none=True)]
181
181
  }
182
182
 
183
183
  do_include = any(
@@ -2,7 +2,7 @@ import hashlib
2
2
  import logging
3
3
  from collections.abc import Iterable
4
4
  from dataclasses import dataclass
5
- from datetime import UTC, datetime, timedelta
5
+ from datetime import timedelta
6
6
 
7
7
  from croniter import croniter
8
8
 
@@ -13,6 +13,7 @@ from reconcile.saas_auto_promotions_manager.publisher import (
13
13
  DeploymentInfo,
14
14
  Publisher,
15
15
  )
16
+ from reconcile.utils.datetime_util import utc_now
16
17
  from reconcile.utils.slo_document_manager import SLODocumentManager
17
18
 
18
19
  CONTENT_HASH_LENGTH = 32
@@ -113,7 +114,7 @@ class Subscriber:
113
114
  We accumulate the time a ref is running on all publishers for this subscriber.
114
115
  We compare that accumulated time with the soak_days setting of the subscriber.
115
116
  """
116
- now = datetime.now(UTC)
117
+ now = utc_now()
117
118
  delta = timedelta(days=0)
118
119
  for channel in self.channels:
119
120
  for publisher in channel.publishers:
@@ -136,7 +137,7 @@ class Subscriber:
136
137
  self.schedule,
137
138
  )
138
139
  return False
139
- return croniter.match(self.schedule, datetime.now(UTC), day_or=False)
140
+ return croniter.match(self.schedule, utc_now(), day_or=False)
140
141
 
141
142
  def _compute_desired_ref(self) -> None:
142
143
  """
@@ -85,7 +85,7 @@ def compile_skupper_sites(
85
85
  or skupper_network.site_controller_templates
86
86
  ):
87
87
  tmpl_vars = tmpl.variables or {}
88
- tmpl_vars["resource"] = {"namespace": ns.dict(by_alias=True)}
88
+ tmpl_vars["resource"] = {"namespace": ns.model_dump(by_alias=True)}
89
89
 
90
90
  site_controller_objects.append(
91
91
  load_site_controller_template(tmpl.path, tmpl_vars)
@@ -304,6 +304,6 @@ def early_exit_desired_state(*args: Any, **kwargs: Any) -> dict[str, Any]:
304
304
  skupper_networks = get_skupper_networks(gqlapi.query)
305
305
  return {
306
306
  "skupper_sites": [
307
- site.dict() for site in compile_skupper_sites(skupper_networks)
307
+ site.model_dump() for site in compile_skupper_sites(skupper_networks)
308
308
  ],
309
309
  }
@@ -3,18 +3,19 @@ import sys
3
3
  from collections.abc import (
4
4
  Callable,
5
5
  Iterable,
6
+ MutableMapping,
6
7
  Sequence,
7
8
  )
8
9
  from datetime import datetime
9
10
  from typing import (
10
11
  Any,
11
12
  TypedDict,
13
+ TypeVar,
12
14
  )
13
15
 
14
16
  from github.GithubException import UnknownObjectException
15
17
  from pydantic import BaseModel
16
- from pydantic.utils import deep_update
17
- from sretoolbox.utils import retry
18
+ from sretoolbox.utils import datatransformation, retry
18
19
 
19
20
  from reconcile import (
20
21
  openshift_users,
@@ -40,6 +41,7 @@ from reconcile.typed_queries.app_interface_vault_settings import (
40
41
  )
41
42
  from reconcile.typed_queries.pagerduty_instances import get_pagerduty_instances
42
43
  from reconcile.utils import gql
44
+ from reconcile.utils.datetime_util import ensure_utc, utc_now
43
45
  from reconcile.utils.disabled_integrations import integration_is_enabled
44
46
  from reconcile.utils.exceptions import (
45
47
  AppInterfaceSettingsError,
@@ -74,6 +76,26 @@ INTEGRATION_VERSION = "0.1.0"
74
76
 
75
77
  error_occurred = False
76
78
 
79
+ KeyType = TypeVar("KeyType")
80
+
81
+
82
+ def deep_update(
83
+ mapping: dict[KeyType, Any],
84
+ *updating_mappings: MutableMapping[KeyType, Any],
85
+ ) -> dict[KeyType, Any]:
86
+ updated_mapping = mapping.copy()
87
+ for updating_mapping in updating_mappings:
88
+ for k, v in updating_mapping.items():
89
+ if (
90
+ k in updated_mapping
91
+ and isinstance(updated_mapping[k], dict)
92
+ and isinstance(v, dict)
93
+ ):
94
+ updated_mapping[k] = deep_update(updated_mapping[k], v)
95
+ else:
96
+ updated_mapping[k] = v
97
+ return updated_mapping
98
+
77
99
 
78
100
  def get_git_api(url: str) -> GithubRepositoryApi | GitLabApi:
79
101
  """Return GitHub/GitLab API based on url."""
@@ -122,15 +144,12 @@ class State(BaseModel):
122
144
  SlackState = dict[str, dict[str, State]]
123
145
 
124
146
 
125
- class WorkspaceSpec(BaseModel):
147
+ class WorkspaceSpec(BaseModel, arbitrary_types_allowed=True):
126
148
  """Slack workspace spec."""
127
149
 
128
150
  slack: SlackApi
129
151
  managed_usergroups: list[str] = []
130
152
 
131
- class Config:
132
- arbitrary_types_allowed = True
133
-
134
153
 
135
154
  SlackMap = dict[str, WorkspaceSpec]
136
155
 
@@ -357,11 +376,11 @@ def get_slack_usernames_from_owners(
357
376
 
358
377
  def get_slack_usernames_from_schedule(schedule: Iterable[ScheduleEntryV1]) -> list[str]:
359
378
  """Return list of usernames from all schedules."""
360
- now = datetime.utcnow()
379
+ now = utc_now()
361
380
  all_slack_usernames: list[str] = []
362
381
  for entry in schedule:
363
- start = datetime.strptime(entry.start, DATE_FORMAT)
364
- end = datetime.strptime(entry.end, DATE_FORMAT)
382
+ start = ensure_utc(datetime.strptime(entry.start, DATE_FORMAT)) # noqa: DTZ007
383
+ end = ensure_utc(datetime.strptime(entry.end, DATE_FORMAT)) # noqa: DTZ007
365
384
  if start <= now <= end:
366
385
  all_slack_usernames.extend(get_slack_username(u) for u in entry.users)
367
386
  return all_slack_usernames
@@ -819,7 +838,9 @@ def run(
819
838
  desired_usergroup_name=usergroup_name,
820
839
  )
821
840
  # merge the two desired states recursively
822
- desired_state = deep_update(desired_state, desired_state_cluster_usergroups)
841
+ desired_state = datatransformation.deep_merge(
842
+ desired_state, desired_state_cluster_usergroups
843
+ )
823
844
 
824
845
  runner_params: RunnerParams = {
825
846
  "dry_run": dry_run,
@@ -891,10 +912,10 @@ def early_exit_desired_state(*args: Any, **kwargs: Any) -> dict[str, Any]:
891
912
  if role.tag_on_cluster_updates is not False
892
913
  ]
893
914
  return {
894
- "permissions": [p.dict() for p in get_permissions(gqlapi.query)],
915
+ "permissions": [p.model_dump() for p in get_permissions(gqlapi.query)],
895
916
  "pagerduty_instances": [
896
- p.dict() for p in get_pagerduty_instances(gqlapi.query)
917
+ p.model_dump() for p in get_pagerduty_instances(gqlapi.query)
897
918
  ],
898
- "users": [u.dict() for u in users],
899
- "clusters": [c.dict() for c in get_clusters(gqlapi.query)],
919
+ "users": [u.model_dump() for u in users],
920
+ "clusters": [c.model_dump() for c in get_clusters(gqlapi.query)],
900
921
  }
reconcile/sql_query.py CHANGED
@@ -229,6 +229,7 @@ def collect_queries(
229
229
  accounts=[],
230
230
  prefetch_resources_by_schemas=["/aws/rds-defaults-1.yml"],
231
231
  secret_reader=secret_reader,
232
+ default_tags=None,
232
233
  )
233
234
 
234
235
  for sql_query in sql_queries:
reconcile/status_board.py CHANGED
@@ -52,7 +52,7 @@ class AbstractStatusBoard(ABC, BaseModel):
52
52
  """Abstract class for upgrade policies
53
53
  Used to create and delete upgrade policies in OCM."""
54
54
 
55
- id: str | None
55
+ id: str | None = None
56
56
  name: str
57
57
  fullname: str
58
58
 
@@ -88,7 +88,7 @@ class AbstractStatusBoard(ABC, BaseModel):
88
88
 
89
89
 
90
90
  class Product(AbstractStatusBoard):
91
- applications: list["Application"] | None
91
+ applications: list["Application"] | None = None
92
92
 
93
93
  def create(self, ocm: OCMBaseClient) -> None:
94
94
  spec = self.to_ocm_spec()
@@ -121,7 +121,7 @@ class Product(AbstractStatusBoard):
121
121
 
122
122
  class Application(AbstractStatusBoard):
123
123
  product: Product
124
- services: list["Service"] | None
124
+ services: list["Service"] | None = None
125
125
 
126
126
  def create(self, ocm: OCMBaseClient) -> None:
127
127
  if self.product.id:
@@ -214,9 +214,9 @@ class Service(AbstractStatusBoard):
214
214
 
215
215
 
216
216
  # Resolve forward references after class definitions
217
- Product.update_forward_refs()
218
- Application.update_forward_refs()
219
- Service.update_forward_refs()
217
+ Product.model_rebuild()
218
+ Application.model_rebuild()
219
+ Service.model_rebuild()
220
220
 
221
221
 
222
222
  class UpdateNotSupportedError(Exception):
@@ -29,12 +29,12 @@ class AtlassianRawComponent(BaseModel):
29
29
 
30
30
  id: str
31
31
  name: str
32
- description: str | None
32
+ description: str | None = None
33
33
  position: int
34
34
  status: str
35
- automation_email: str | None
36
- group_id: str | None
37
- group: bool | None
35
+ automation_email: str | None = None
36
+ group_id: str | None = None
37
+ group: bool | None = None
38
38
 
39
39
 
40
40
  class AtlassianRawMaintenanceUpdate(BaseModel):
@@ -56,9 +56,9 @@ class AtlassianRawMaintenance(BaseModel):
56
56
  scheduled_until: str
57
57
  incident_updates: list[AtlassianRawMaintenanceUpdate]
58
58
  components: list[AtlassianRawComponent]
59
- auto_transition_deliver_notifications_at_end: bool | None
60
- auto_transition_deliver_notifications_at_start: bool | None
61
- scheduled_remind_prior: bool | None
59
+ auto_transition_deliver_notifications_at_end: bool | None = None
60
+ auto_transition_deliver_notifications_at_start: bool | None = None
61
+ scheduled_remind_prior: bool | None = None
62
62
 
63
63
 
64
64
  class AtlassianAPI:
@@ -1,12 +1,13 @@
1
1
  import logging
2
2
  import sys
3
- from datetime import UTC, datetime, timedelta
3
+ from datetime import datetime, timedelta
4
4
 
5
5
  from reconcile.slack_base import slackapi_from_queries
6
6
  from reconcile.statuspage.atlassian import AtlassianStatusPageProvider
7
7
  from reconcile.statuspage.integration import get_binding_state, get_status_pages
8
8
  from reconcile.statuspage.page import StatusMaintenance
9
9
  from reconcile.statuspage.state import S3ComponentBindingState
10
+ from reconcile.utils.datetime_util import utc_now
10
11
  from reconcile.utils.differ import diff_iterables
11
12
  from reconcile.utils.runtime.integration import (
12
13
  NoParams,
@@ -52,7 +53,7 @@ class StatusPageMaintenancesIntegration(QontractReconcileIntegration[NoParams]):
52
53
  desired_state: list[StatusMaintenance],
53
54
  binding_state: S3ComponentBindingState,
54
55
  ) -> None:
55
- now = datetime.now(UTC)
56
+ now = utc_now()
56
57
  slack = slackapi_from_queries(QONTRACT_INTEGRATION, init_usergroups=False)
57
58
  for m in desired_state:
58
59
  scheduled_start = m.schedule_start
@@ -68,7 +69,7 @@ class StatusPageMaintenancesIntegration(QontractReconcileIntegration[NoParams]):
68
69
  def run(self, dry_run: bool = False) -> None:
69
70
  binding_state = get_binding_state(self.name, self.secret_reader)
70
71
  pages = get_status_pages()
71
- now = datetime.now(UTC)
72
+ now = utc_now()
72
73
 
73
74
  error = False
74
75
  for p in pages:
@@ -19,19 +19,17 @@ from reconcile.statuspage.status import (
19
19
  PROVIDER_NAME = "statuspage"
20
20
 
21
21
 
22
- class StatusComponent(BaseModel):
22
+ class StatusComponent(BaseModel, arbitrary_types_allowed=True):
23
23
  """
24
24
  Represents a status page component from the desired state.
25
25
  """
26
26
 
27
27
  name: str
28
28
  display_name: str
29
- description: str | None
30
- group_name: str | None
29
+ description: str | None = None
30
+ group_name: str | None = None
31
+ # Status provider configs hold different ways for a component to determine its status
31
32
  status_provider_configs: list[StatusProvider]
32
- """
33
- Status provider configs hold different ways for a component to determine its status
34
- """
35
33
 
36
34
  def status_management_enabled(self) -> bool:
37
35
  """
@@ -49,9 +47,6 @@ class StatusComponent(BaseModel):
49
47
  return "operational"
50
48
  return None
51
49
 
52
- class Config:
53
- arbitrary_types_allowed = True
54
-
55
50
  def __eq__(self, other: object) -> bool:
56
51
  if not isinstance(other, StatusComponent):
57
52
  raise NotImplementedError("Cannot compare to non StatusComponent objects.")