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
@@ -155,7 +155,8 @@ class ChangeLogIntegration(QontractReconcileIntegration[ChangeLogIntegrationPara
155
155
  changes = aggregate_resource_changes(
156
156
  bundle_changes=aggregate_file_moves(parse_bundle_changes(diff)),
157
157
  content_store={
158
- c.path: c.dict(by_alias=True) for c in namespaces + jenkins_configs
158
+ c.path: c.model_dump(by_alias=True)
159
+ for c in namespaces + jenkins_configs
159
160
  },
160
161
  supported_schemas={
161
162
  "/openshift/namespace-1.yml",
@@ -239,4 +240,4 @@ class ChangeLogIntegration(QontractReconcileIntegration[ChangeLogIntegrationPara
239
240
  change_log.items, key=lambda i: i.merged_at, reverse=True
240
241
  )
241
242
  if not dry_run:
242
- integration_state.add(BUNDLE_DIFFS_OBJ, change_log.dict(), force=True)
243
+ integration_state.add(BUNDLE_DIFFS_OBJ, change_log.model_dump(), force=True)
@@ -23,6 +23,7 @@ from reconcile.change_owners.changes import (
23
23
  )
24
24
  from reconcile.change_owners.decision import (
25
25
  ChangeDecision,
26
+ ChangeResponsibles,
26
27
  DecisionCommand,
27
28
  apply_decisions_to_changes,
28
29
  get_approver_decisions_from_mr_comments,
@@ -115,6 +116,77 @@ def manage_conditional_label(
115
116
  return set(new_labels)
116
117
 
117
118
 
119
+ def build_status_message(
120
+ self_serviceable: bool,
121
+ authoritative: bool,
122
+ change_admitted: bool,
123
+ approver_reachability: set[str],
124
+ supported_commands: list[str],
125
+ ) -> str:
126
+ """
127
+ Build a user-friendly status message based on the MR state.
128
+ """
129
+ approver_section = _build_approver_contact_section(approver_reachability)
130
+
131
+ # Check if changes are not admitted (security gate - takes priority)
132
+ if not change_admitted:
133
+ return f"""## ⏸️ Approval Required
134
+ Your changes need `/ok-to-test` approval from a listed approver before review can begin.
135
+
136
+ {approver_section}"""
137
+
138
+ commands_text = (
139
+ f"**Available commands:** {' '.join(f'`{cmd}`' for cmd in supported_commands)}"
140
+ )
141
+
142
+ code_warning = ""
143
+ if not authoritative:
144
+ code_warning = "⚠️ **Code changes outside of data and resources detected** - please review carefully\n\n"
145
+
146
+ if self_serviceable:
147
+ return f"""## ✅ Ready for Review
148
+ Get `/lgtm` approval from the listed approvers below.
149
+
150
+ {code_warning}{approver_section}
151
+
152
+ {commands_text}"""
153
+
154
+ return f"""## 🔍 AppSRE Review Required
155
+ **What happens next:**
156
+ * AppSRE will review via their [review queue](https://gitlab.cee.redhat.com/service/app-interface-output/-/blob/master/app-interface-review-queue.md)
157
+ * Please don't ping directly unless this is **urgent**
158
+ * See [etiquette guide](https://gitlab.cee.redhat.com/service/app-interface#app-interface-etiquette) for more info
159
+
160
+ {code_warning}{approver_section}
161
+
162
+ {commands_text}"""
163
+
164
+
165
+ def _build_approver_contact_section(approver_reachability: set[str]) -> str:
166
+ """Build the approver contact information section."""
167
+ if not approver_reachability:
168
+ return ""
169
+
170
+ return "**Reach out to approvers:**\n" + "\n".join([
171
+ f"* {ar}" for ar in approver_reachability
172
+ ])
173
+
174
+
175
+ def _format_change_responsible(cr: ChangeResponsibles) -> str:
176
+ """
177
+ Format a ChangeResponsibles object.
178
+ """
179
+ usernames = [
180
+ f"@{a.org_username}"
181
+ if (a.tag_on_merge_requests or len(cr.approvers) == 1)
182
+ else a.org_username
183
+ for a in cr.approvers
184
+ ]
185
+
186
+ usernames_text = " ".join(usernames)
187
+ return f"<details><summary>{cr.context}</summary>{usernames_text}</details>"
188
+
189
+
118
190
  def write_coverage_report_to_mr(
119
191
  self_serviceable: bool,
120
192
  change_decisions: list[ChangeDecision],
@@ -135,14 +207,11 @@ def write_coverage_report_to_mr(
135
207
  startswith=change_coverage_report_header,
136
208
  )
137
209
 
138
- # add new report comment
210
+ # Build change coverage table
139
211
  results = []
140
212
  approver_reachability = set()
141
213
  for d in change_decisions:
142
- approvers = [
143
- f"{cr.context} - {' '.join([f'@{a.org_username}' if a.tag_on_merge_requests else a.org_username for a in cr.approvers])}"
144
- for cr in d.change_responsibles
145
- ]
214
+ approvers = [_format_change_responsible(cr) for cr in d.change_responsibles]
146
215
  if d.coverable_by_fragment_decisions:
147
216
  approvers.append(
148
217
  "automatically approved if all sub-properties are approved"
@@ -164,41 +233,33 @@ def write_coverage_report_to_mr(
164
233
  item["status"] = "hold"
165
234
  elif d.is_approved():
166
235
  item["status"] = "approved"
167
- item["approvers"] = approvers
236
+ item["approvers"] = "".join(approvers)
168
237
  results.append(item)
238
+
169
239
  coverage_report = format_table(
170
240
  results, ["file", "change", "status", "approvers"], table_format="github"
171
241
  )
172
242
 
173
- self_serviceability_hint = "All changes require an `/lgtm` from a listed approver "
174
- if not self_serviceable:
175
- self_serviceability_hint += (
176
- "but <b>not all changes are self-serviceable and require AppSRE approval</b>."
177
- "The AppSRE Interrupt Catcher (IC) will review your Merge Request (MR) as it comes up in their "
178
- "<a href='https://gitlab.cee.redhat.com/service/app-interface-output/-/blob/master/app-interface-review-queue.md'>queue</a>, "
179
- "please do not ping them directly unless this is <b>urgent</b>."
180
- "\nPlease see https://gitlab.cee.redhat.com/service/app-interface#app-interface-etiquette for more information. Thank you :)"
181
- )
182
- if not authoritative:
183
- self_serviceability_hint += "\n\nchanges outside of data and resources detected - <b>PAY EXTRA ATTENTION WHILE REVIEWING</b>\n\n"
184
-
185
- if not change_admitted:
186
- self_serviceability_hint += "\n\nchanges are not admitted. Please request `/good-to-test` from one of the approvers.\n\n"
187
-
188
- approver_reachability_hint = "Reach out to approvers for reviews"
189
- if approver_reachability:
190
- approver_reachability_hint += " on\n" + "\n".join([
191
- f"* {ar}" for ar in approver_reachability or []
192
- ])
193
- gl.add_comment_to_merge_request(
194
- merge_request,
195
- f"{change_coverage_report_header}<br/>"
196
- f"{self_serviceability_hint}\n"
197
- f"{coverage_report}\n\n"
198
- f"{approver_reachability_hint}\n\n"
199
- + f"Supported commands: {' '.join([f'`{d.value}`' for d in DecisionCommand])} ",
243
+ # Build user-friendly status message
244
+ supported_commands = [d.value for d in DecisionCommand]
245
+ status_message = build_status_message(
246
+ self_serviceable=self_serviceable,
247
+ authoritative=authoritative,
248
+ change_admitted=change_admitted,
249
+ approver_reachability=approver_reachability,
250
+ supported_commands=supported_commands,
200
251
  )
201
252
 
253
+ # Create the full comment
254
+ full_comment = f"""{change_coverage_report_header}
255
+
256
+ {status_message}
257
+
258
+ ## 📋 Change Summary
259
+ {coverage_report}"""
260
+
261
+ gl.add_comment_to_merge_request(merge_request, full_comment)
262
+
202
263
 
203
264
  def write_coverage_report_to_stdout(change_decisions: list[ChangeDecision]) -> None:
204
265
  results = []
@@ -261,22 +322,22 @@ def init_gitlab(gitlab_project_id: str) -> GitLabApi:
261
322
 
262
323
 
263
324
  def is_coverage_admitted(
264
- coverage: ChangeTypeContext, mr_author: str, good_to_test_approvers: set[str]
325
+ coverage: ChangeTypeContext, mr_author: str, ok_to_test_approvers: set[str]
265
326
  ) -> bool:
266
327
  return any(
267
- a.org_username == mr_author or a.org_username in good_to_test_approvers
328
+ a.org_username == mr_author or a.org_username in ok_to_test_approvers
268
329
  for a in coverage.approvers
269
330
  )
270
331
 
271
332
 
272
333
  def is_change_admitted(
273
- changes: list[BundleFileChange], mr_author: str, good_to_test_approvers: set[str]
334
+ changes: list[BundleFileChange], mr_author: str, ok_to_test_approvers: set[str]
274
335
  ) -> bool:
275
336
  # Checks if mr authors are allowed to do the changes in the merge request.
276
337
  # If a change type is restrictive and the author is not an approver,
277
338
  # this is not admitted.
278
339
  # A change might be admitted if a user that has the restrictive change
279
- # type is an approver or an approver adds an /good-to-test comment.
340
+ # type is an approver or an approver adds an /ok-to-test comment.
280
341
 
281
342
  restrictive_coverages = [
282
343
  c
@@ -290,7 +351,7 @@ def is_change_admitted(
290
351
  change_types_approved = {
291
352
  c.origin
292
353
  for c in restrictive_coverages
293
- if is_coverage_admitted(c, mr_author, good_to_test_approvers)
354
+ if is_coverage_admitted(c, mr_author, ok_to_test_approvers)
294
355
  }
295
356
  return change_types_to_approve == change_types_approved
296
357
 
@@ -381,17 +442,22 @@ def run(
381
442
  merge_request = gl.get_merge_request(gitlab_merge_request_id)
382
443
 
383
444
  comments = gl.get_merge_request_comments(merge_request)
384
- good_to_test_approvers = {
385
- c.username for c in comments if c.body.strip() == "/good-to-test"
445
+ ok_to_test_approvers = {
446
+ c.username for c in comments if c.body.strip() == "/ok-to-test"
386
447
  }
387
448
 
388
449
  change_admitted = is_change_admitted(
389
450
  changes,
390
451
  gl.get_merge_request_author_username(merge_request),
391
- good_to_test_approvers,
452
+ ok_to_test_approvers,
392
453
  )
393
454
  approver_decisions = get_approver_decisions_from_mr_comments(
394
- gl.get_merge_request_comments(merge_request, include_description=True)
455
+ gl.get_merge_request_comments(
456
+ merge_request,
457
+ include_description=True,
458
+ include_approvals=True,
459
+ approval_body=DecisionCommand.APPROVED.value,
460
+ )
395
461
  )
396
462
  change_decisions = apply_decisions_to_changes(
397
463
  changes,
@@ -20,7 +20,7 @@ class DecisionCommand(Enum):
20
20
  CANCEL_APPROVED = "/lgtm cancel"
21
21
  HOLD = "/hold"
22
22
  CANCEL_HOLD = "/hold cancel"
23
- GOOD_TO_TEST = "/good-to-test"
23
+ OK_TO_TEST = "/ok-to-test"
24
24
 
25
25
 
26
26
  @dataclass
@@ -251,8 +251,6 @@ def deepdiff_path_to_jsonpath(deep_diff_path: str) -> jsonpath_ng.JSONPath:
251
251
  case int():
252
252
  return jsonpath_ng.Index(element)
253
253
  case str():
254
- if "." in element:
255
- return jsonpath_ng.Fields(f"'{element}'")
256
254
  return jsonpath_ng.Fields(element)
257
255
 
258
256
  path_parts = [build_jsonpath_part(p) for p in parse_path(deep_diff_path)]
reconcile/checkpoint.py CHANGED
@@ -26,6 +26,7 @@ from jira import Issue
26
26
 
27
27
  from reconcile.utils.constants import PROJ_ROOT
28
28
  from reconcile.utils.jira_client import JiraClient
29
+ from reconcile.utils.secret_reader import SecretReaderBase
29
30
 
30
31
  DEFAULT_CHECKPOINT_LABELS = ("sre-checkpoint",)
31
32
 
@@ -118,8 +119,8 @@ def file_ticket(
118
119
  def report_invalid_metadata(
119
120
  app: Mapping[str, Any],
120
121
  path: str,
121
- board: Mapping[str, str | Mapping],
122
- settings: Mapping[str, Any],
122
+ board: Mapping[str, Any],
123
+ secret_reader: SecretReaderBase,
123
124
  parent: str,
124
125
  dry_run: bool = False,
125
126
  ) -> None:
@@ -150,7 +151,14 @@ def report_invalid_metadata(
150
151
  path=path,
151
152
  )
152
153
  else:
153
- jira = JiraClient(board, settings)
154
+ jira = JiraClient.create(
155
+ project_name=board["name"],
156
+ token=secret_reader.read_secret(board["server"]["token"]),
157
+ email=secret_reader.read_secret(board["server"]["email"])
158
+ if board["server"]["email"]
159
+ else None,
160
+ server_url=board["server"]["server_url"],
161
+ )
154
162
  do_cut = partial(
155
163
  file_ticket, # type: ignore
156
164
  jira=jira,
reconcile/cli.py CHANGED
@@ -50,10 +50,10 @@ from reconcile.utils.unleash import get_feature_toggle_state
50
50
  TERRAFORM_VERSION = ["1.6.6"]
51
51
  TERRAFORM_VERSION_REGEX = r"^Terraform\sv([\d]+\.[\d]+\.[\d]+)$"
52
52
 
53
- OC_VERSIONS = ["4.16.2", "4.12.46", "4.10.15"]
54
- OC_VERSION_REGEX = r"^Client\sVersion:\s([\d]+\.[\d]+\.[\d]+)$"
53
+ OC_VERSIONS = ["4.19.0", "4.16.2"]
54
+ OC_VERSION_REGEX = r"^Client\sVersion:\s([\d]+\.[\d]+\.[\d]+)"
55
55
 
56
- HELM_VERSIONS = ["3.11.1"]
56
+ HELM_VERSIONS = ["3.19.2"]
57
57
  HELM_VERSION_REGEX = r"^version.BuildInfo{Version:\"v([\d]+\.[\d]+\.[\d]+)\".*$"
58
58
 
59
59
 
@@ -1028,7 +1028,7 @@ def aws_account_manager(
1028
1028
  "--state-tmpl-resource",
1029
1029
  help="Resource name of the state template-collection template in the app-interface.",
1030
1030
  required=True,
1031
- default="/terraform-init/terraform-state.yml",
1031
+ default="/terraform-init/terraform-state.yml.j2",
1032
1032
  )
1033
1033
  @click.option(
1034
1034
  "--template-collection-root-path",
@@ -1036,12 +1036,26 @@ def aws_account_manager(
1036
1036
  required=True,
1037
1037
  default="data/templating/collections/terraform-init",
1038
1038
  )
1039
+ @click.option(
1040
+ "--cloudformation-template-resource",
1041
+ help="Resource name of the CloudFormation template to create the S3 bucket",
1042
+ required=True,
1043
+ default="/terraform-init/terraform-state-s3-bucket.yaml",
1044
+ )
1045
+ @click.option(
1046
+ "--cloudformation-import-template-resource",
1047
+ help="Resource name of the CloudFormation template to import existing S3 bucket",
1048
+ required=True,
1049
+ default="/terraform-init/terraform-state-s3-bucket-import.yaml",
1050
+ )
1039
1051
  @click.pass_context
1040
1052
  def terraform_init(
1041
1053
  ctx: click.Context,
1042
1054
  account_name: str | None,
1043
1055
  state_tmpl_resource: str,
1044
1056
  template_collection_root_path: str,
1057
+ cloudformation_template_resource: str,
1058
+ cloudformation_import_template_resource: str,
1045
1059
  ) -> None:
1046
1060
  from reconcile.terraform_init.integration import (
1047
1061
  TerraformInitIntegration,
@@ -1054,6 +1068,8 @@ def terraform_init(
1054
1068
  account_name=account_name,
1055
1069
  state_tmpl_resource=state_tmpl_resource,
1056
1070
  template_collection_root_path=template_collection_root_path,
1071
+ cloudformation_template_resource=cloudformation_template_resource,
1072
+ cloudformation_import_template_resource=cloudformation_import_template_resource,
1057
1073
  )
1058
1074
  ),
1059
1075
  ctx=ctx,
@@ -1135,9 +1151,17 @@ def jenkins_webhooks_cleaner(ctx: click.Context) -> None:
1135
1151
  "--jira-board-name", help="The Jira board to act on.", default=None, multiple=True
1136
1152
  )
1137
1153
  @click.option("--board-check-interval", help="Check interval in minutes", default=120)
1154
+ @click.option(
1155
+ "--use-cache/--no-use-cache",
1156
+ default=True,
1157
+ help="Use cached results for validation.",
1158
+ )
1138
1159
  @click.pass_context
1139
1160
  def jira_permissions_validator(
1140
- ctx: click.Context, jira_board_name: Iterable[str] | None, board_check_interval: int
1161
+ ctx: click.Context,
1162
+ jira_board_name: Iterable[str] | None,
1163
+ board_check_interval: int,
1164
+ use_cache: bool,
1141
1165
  ) -> None:
1142
1166
  import reconcile.jira_permissions_validator
1143
1167
 
@@ -1146,6 +1170,7 @@ def jira_permissions_validator(
1146
1170
  ctx,
1147
1171
  jira_board_name=jira_board_name,
1148
1172
  board_check_interval_sec=board_check_interval * 60,
1173
+ use_cache=use_cache,
1149
1174
  )
1150
1175
 
1151
1176
 
@@ -1270,14 +1295,14 @@ def aws_ami_cleanup(ctx: click.Context, thread_pool_size: int) -> None:
1270
1295
  run_integration(reconcile.aws_ami_cleanup.integration, ctx, thread_pool_size)
1271
1296
 
1272
1297
 
1273
- @integration.command(short_help="Set up retention period for Cloudwatch logs.")
1274
- @threaded()
1298
+ @integration.command(short_help="Set up retention period and tags for Cloudwatch logs.")
1275
1299
  @click.pass_context
1276
- def aws_cloudwatch_log_retention(ctx: click.Context, thread_pool_size: int) -> None:
1300
+ def aws_cloudwatch_log_retention(ctx: click.Context) -> None:
1277
1301
  import reconcile.aws_cloudwatch_log_retention.integration
1278
1302
 
1279
1303
  run_integration(
1280
- reconcile.aws_cloudwatch_log_retention.integration, ctx, thread_pool_size
1304
+ reconcile.aws_cloudwatch_log_retention.integration,
1305
+ ctx,
1281
1306
  )
1282
1307
 
1283
1308
 
@@ -2830,6 +2855,36 @@ def ocm_addons_upgrade_scheduler_org(
2830
2855
  default=bool(os.environ.get("IGNORE_STS_CLUSTERS")),
2831
2856
  help="Ignore STS clusters",
2832
2857
  )
2858
+ @click.option(
2859
+ "--job-controller-cluster",
2860
+ help="The cluster holding the job-controller namepsace",
2861
+ required=False,
2862
+ envvar="JOB_CONTROLLER_CLUSTER",
2863
+ )
2864
+ @click.option(
2865
+ "--job-controller-namespace",
2866
+ help="The namespace used for ROSA jobs",
2867
+ required=False,
2868
+ envvar="JOB_CONTROLLER_NAMESPACE",
2869
+ )
2870
+ @click.option(
2871
+ "--rosa-job-service-account",
2872
+ help="The service-account used for ROSA jobs",
2873
+ required=False,
2874
+ envvar="ROSA_JOB_SERVICE_ACCOUNT",
2875
+ )
2876
+ @click.option(
2877
+ "--rosa-job-image",
2878
+ help="The container image to use to run ROSA cli command jobs",
2879
+ required=False,
2880
+ envvar="ROSA_JOB_IMAGE",
2881
+ )
2882
+ @click.option(
2883
+ "--rosa-role",
2884
+ help="The role to assume in the ROSA cluster account",
2885
+ required=False,
2886
+ envvar="ROSA_ROLE",
2887
+ )
2833
2888
  @click.pass_context
2834
2889
  def advanced_upgrade_scheduler(
2835
2890
  ctx: click.Context,
@@ -2837,9 +2892,21 @@ def advanced_upgrade_scheduler(
2837
2892
  org_id: Iterable[str],
2838
2893
  exclude_org_id: Iterable[str],
2839
2894
  ignore_sts_clusters: bool,
2895
+ job_controller_cluster: str | None,
2896
+ job_controller_namespace: str | None,
2897
+ rosa_job_service_account: str | None,
2898
+ rosa_role: str | None,
2899
+ rosa_job_image: str | None,
2840
2900
  ) -> None:
2841
- from reconcile.aus.advanced_upgrade_service import AdvancedUpgradeServiceIntegration
2842
- from reconcile.aus.base import AdvancedUpgradeSchedulerBaseIntegrationParams
2901
+ from reconcile.aus.advanced_upgrade_service import (
2902
+ QONTRACT_INTEGRATION,
2903
+ QONTRACT_INTEGRATION_VERSION,
2904
+ AdvancedUpgradeServiceIntegration,
2905
+ )
2906
+ from reconcile.aus.base import (
2907
+ AdvancedUpgradeSchedulerBaseIntegrationParams,
2908
+ RosaRoleUpgradeHandlerParams,
2909
+ )
2843
2910
 
2844
2911
  run_class_integration(
2845
2912
  integration=AdvancedUpgradeServiceIntegration(
@@ -2848,6 +2915,22 @@ def advanced_upgrade_scheduler(
2848
2915
  ocm_organization_ids=set(org_id),
2849
2916
  excluded_ocm_organization_ids=set(exclude_org_id),
2850
2917
  ignore_sts_clusters=ignore_sts_clusters,
2918
+ rosa_role_upgrade_handler_params=RosaRoleUpgradeHandlerParams(
2919
+ job_controller_cluster=job_controller_cluster,
2920
+ job_controller_namespace=job_controller_namespace,
2921
+ rosa_job_service_account=rosa_job_service_account,
2922
+ rosa_role=rosa_role,
2923
+ rosa_job_image=rosa_job_image,
2924
+ integration_name=QONTRACT_INTEGRATION,
2925
+ integration_version=QONTRACT_INTEGRATION_VERSION,
2926
+ )
2927
+ if all([
2928
+ job_controller_cluster,
2929
+ job_controller_namespace,
2930
+ rosa_job_service_account,
2931
+ rosa_role,
2932
+ ])
2933
+ else None,
2851
2934
  )
2852
2935
  ),
2853
2936
  ctx=ctx,
@@ -4,7 +4,6 @@ from collections import defaultdict
4
4
  from collections.abc import Iterable, Mapping
5
5
  from dataclasses import dataclass
6
6
  from datetime import (
7
- UTC,
8
7
  datetime,
9
8
  timedelta,
10
9
  )
@@ -31,6 +30,7 @@ from reconcile.typed_queries.app_interface_vault_settings import (
31
30
  get_app_interface_vault_settings,
32
31
  )
33
32
  from reconcile.typed_queries.saas_files import get_saas_files
33
+ from reconcile.utils.datetime_util import ensure_utc, utc_now
34
34
  from reconcile.utils.github_api import GithubRepositoryApi
35
35
  from reconcile.utils.gitlab_api import GitLabApi
36
36
  from reconcile.utils.secret_reader import create_secret_reader
@@ -159,15 +159,8 @@ class Commit:
159
159
  date: datetime
160
160
 
161
161
  def lttc(self, finish_timestamp: datetime) -> int:
162
- commit_date_tzaware = self.date
163
- finish_timestamp_tzaware = finish_timestamp
164
-
165
- if commit_date_tzaware.tzinfo is None:
166
- commit_date_tzaware = commit_date_tzaware.replace(tzinfo=UTC)
167
-
168
- if finish_timestamp_tzaware.tzinfo is None:
169
- finish_timestamp_tzaware = finish_timestamp_tzaware.replace(tzinfo=UTC)
170
-
162
+ commit_date_tzaware = ensure_utc(self.date)
163
+ finish_timestamp_tzaware = ensure_utc(finish_timestamp)
171
164
  return int((finish_timestamp_tzaware - commit_date_tzaware).total_seconds())
172
165
 
173
166
 
@@ -277,7 +270,7 @@ class DashdotdbDORA(DashdotdbBase):
277
270
  # from the DB for a unique (app_name, env_name) multiple times.
278
271
  app_envs = {s.app_env for s in saastargets}
279
272
 
280
- since_default = datetime.now() - timedelta(days=90)
273
+ since_default = utc_now() - timedelta(days=90)
281
274
  app_env_since_list: list[tuple[AppEnv, datetime]] = threaded.run(
282
275
  func=functools.partial(self.get_latest_with_default, since_default),
283
276
  iterable=app_envs,
@@ -473,7 +466,7 @@ class DashdotdbDORA(DashdotdbBase):
473
466
  ]
474
467
 
475
468
  def _github_compare_commits(self, rc: RepoChanges, repo: str) -> list[Commit]:
476
- if not rc.repo_url:
469
+ if not rc.repo_url or not rc.ref_from or not rc.ref_to:
477
470
  return []
478
471
 
479
472
  return [
@@ -119,4 +119,4 @@ def run(
119
119
 
120
120
 
121
121
  def early_exit_desired_state(*args: Any, **kwargs: Any) -> dict[str, Any]:
122
- return {doc.name: doc.dict() for doc in get_slo_documents()}
122
+ return {doc.name: doc.model_dump() for doc in get_slo_documents()}