qontract-reconcile 0.10.0__py3-none-any.whl → 0.10.1.dev1203__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 (844) hide show
  1. qontract_reconcile-0.10.1.dev1203.dist-info/METADATA +500 -0
  2. qontract_reconcile-0.10.1.dev1203.dist-info/RECORD +771 -0
  3. {qontract_reconcile-0.10.0.dist-info → qontract_reconcile-0.10.1.dev1203.dist-info}/WHEEL +1 -2
  4. {qontract_reconcile-0.10.0.dist-info → qontract_reconcile-0.10.1.dev1203.dist-info}/entry_points.txt +4 -2
  5. reconcile/acs_notifiers.py +126 -0
  6. reconcile/acs_policies.py +243 -0
  7. reconcile/acs_rbac.py +596 -0
  8. reconcile/aus/advanced_upgrade_service.py +621 -8
  9. reconcile/aus/aus_label_source.py +115 -0
  10. reconcile/aus/base.py +1053 -353
  11. reconcile/{utils → aus}/cluster_version_data.py +27 -12
  12. reconcile/aus/healthchecks.py +77 -0
  13. reconcile/aus/metrics.py +158 -0
  14. reconcile/aus/models.py +245 -5
  15. reconcile/aus/node_pool_spec.py +35 -0
  16. reconcile/aus/ocm_addons_upgrade_scheduler_org.py +225 -110
  17. reconcile/aus/ocm_upgrade_scheduler.py +76 -71
  18. reconcile/aus/ocm_upgrade_scheduler_org.py +81 -23
  19. reconcile/aus/version_gate_approver.py +204 -0
  20. reconcile/aus/version_gates/__init__.py +12 -0
  21. reconcile/aus/version_gates/handler.py +33 -0
  22. reconcile/aus/version_gates/ingress_gate_handler.py +32 -0
  23. reconcile/aus/version_gates/ocp_gate_handler.py +26 -0
  24. reconcile/aus/version_gates/sts_version_gate_handler.py +100 -0
  25. reconcile/aws_account_manager/README.md +5 -0
  26. reconcile/aws_account_manager/integration.py +373 -0
  27. reconcile/aws_account_manager/merge_request_manager.py +114 -0
  28. reconcile/aws_account_manager/metrics.py +39 -0
  29. reconcile/aws_account_manager/reconciler.py +403 -0
  30. reconcile/aws_account_manager/utils.py +41 -0
  31. reconcile/aws_ami_cleanup/integration.py +273 -0
  32. reconcile/aws_ami_share.py +18 -14
  33. reconcile/aws_cloudwatch_log_retention/integration.py +253 -0
  34. reconcile/aws_iam_keys.py +1 -1
  35. reconcile/aws_iam_password_reset.py +56 -20
  36. reconcile/aws_saml_idp/integration.py +204 -0
  37. reconcile/aws_saml_roles/integration.py +322 -0
  38. reconcile/aws_support_cases_sos.py +2 -2
  39. reconcile/aws_version_sync/integration.py +430 -0
  40. reconcile/aws_version_sync/merge_request_manager/merge_request.py +156 -0
  41. reconcile/aws_version_sync/merge_request_manager/merge_request_manager.py +160 -0
  42. reconcile/aws_version_sync/utils.py +64 -0
  43. reconcile/blackbox_exporter_endpoint_monitoring.py +2 -5
  44. reconcile/change_owners/README.md +34 -0
  45. reconcile/change_owners/approver.py +7 -9
  46. reconcile/change_owners/bundle.py +134 -9
  47. reconcile/change_owners/change_log_tracking.py +236 -0
  48. reconcile/change_owners/change_owners.py +204 -194
  49. reconcile/change_owners/change_types.py +183 -265
  50. reconcile/change_owners/changes.py +488 -0
  51. reconcile/change_owners/decision.py +120 -41
  52. reconcile/change_owners/diff.py +63 -92
  53. reconcile/change_owners/implicit_ownership.py +19 -16
  54. reconcile/change_owners/self_service_roles.py +158 -35
  55. reconcile/change_owners/tester.py +20 -18
  56. reconcile/checkpoint.py +4 -6
  57. reconcile/cli.py +1523 -242
  58. reconcile/closedbox_endpoint_monitoring_base.py +10 -17
  59. reconcile/cluster_auth_rhidp/integration.py +257 -0
  60. reconcile/cluster_deployment_mapper.py +2 -5
  61. reconcile/cna/assets/asset.py +4 -7
  62. reconcile/cna/assets/null.py +2 -5
  63. reconcile/cna/integration.py +2 -3
  64. reconcile/cna/state.py +6 -9
  65. reconcile/dashdotdb_base.py +31 -10
  66. reconcile/dashdotdb_cso.py +3 -6
  67. reconcile/dashdotdb_dora.py +530 -0
  68. reconcile/dashdotdb_dvo.py +10 -13
  69. reconcile/dashdotdb_slo.py +75 -19
  70. reconcile/database_access_manager.py +753 -0
  71. reconcile/deadmanssnitch.py +207 -0
  72. reconcile/dynatrace_token_provider/dependencies.py +69 -0
  73. reconcile/dynatrace_token_provider/integration.py +656 -0
  74. reconcile/dynatrace_token_provider/metrics.py +62 -0
  75. reconcile/dynatrace_token_provider/model.py +14 -0
  76. reconcile/dynatrace_token_provider/ocm.py +140 -0
  77. reconcile/dynatrace_token_provider/validate.py +48 -0
  78. reconcile/endpoints_discovery/integration.py +348 -0
  79. reconcile/endpoints_discovery/merge_request.py +96 -0
  80. reconcile/endpoints_discovery/merge_request_manager.py +178 -0
  81. reconcile/external_resources/aws.py +204 -0
  82. reconcile/external_resources/factories.py +163 -0
  83. reconcile/external_resources/integration.py +194 -0
  84. reconcile/external_resources/integration_secrets_sync.py +47 -0
  85. reconcile/external_resources/manager.py +405 -0
  86. reconcile/external_resources/meta.py +17 -0
  87. reconcile/external_resources/metrics.py +95 -0
  88. reconcile/external_resources/model.py +350 -0
  89. reconcile/external_resources/reconciler.py +265 -0
  90. reconcile/external_resources/secrets_sync.py +465 -0
  91. reconcile/external_resources/state.py +258 -0
  92. reconcile/gabi_authorized_users.py +19 -11
  93. reconcile/gcr_mirror.py +43 -34
  94. reconcile/github_org.py +4 -6
  95. reconcile/github_owners.py +1 -1
  96. reconcile/github_repo_invites.py +2 -5
  97. reconcile/gitlab_fork_compliance.py +14 -13
  98. reconcile/gitlab_housekeeping.py +185 -91
  99. reconcile/gitlab_labeler.py +15 -14
  100. reconcile/gitlab_members.py +126 -120
  101. reconcile/gitlab_owners.py +53 -66
  102. reconcile/gitlab_permissions.py +167 -6
  103. reconcile/glitchtip/README.md +150 -0
  104. reconcile/glitchtip/integration.py +99 -51
  105. reconcile/glitchtip/reconciler.py +99 -70
  106. reconcile/glitchtip_project_alerts/__init__.py +0 -0
  107. reconcile/glitchtip_project_alerts/integration.py +333 -0
  108. reconcile/glitchtip_project_dsn/integration.py +43 -43
  109. reconcile/gql_definitions/acs/__init__.py +0 -0
  110. reconcile/gql_definitions/acs/acs_instances.py +83 -0
  111. reconcile/gql_definitions/acs/acs_policies.py +239 -0
  112. reconcile/gql_definitions/acs/acs_rbac.py +111 -0
  113. reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +46 -8
  114. reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +38 -8
  115. reconcile/gql_definitions/app_interface_metrics_exporter/__init__.py +0 -0
  116. reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +61 -0
  117. reconcile/gql_definitions/aws_account_manager/__init__.py +0 -0
  118. reconcile/gql_definitions/aws_account_manager/aws_accounts.py +177 -0
  119. reconcile/gql_definitions/aws_ami_cleanup/__init__.py +0 -0
  120. reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +161 -0
  121. reconcile/gql_definitions/aws_saml_idp/__init__.py +0 -0
  122. reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +117 -0
  123. reconcile/gql_definitions/aws_saml_roles/__init__.py +0 -0
  124. reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +117 -0
  125. reconcile/gql_definitions/aws_saml_roles/roles.py +97 -0
  126. reconcile/gql_definitions/aws_version_sync/__init__.py +0 -0
  127. reconcile/gql_definitions/aws_version_sync/clusters.py +83 -0
  128. reconcile/gql_definitions/aws_version_sync/namespaces.py +143 -0
  129. reconcile/gql_definitions/change_owners/queries/change_types.py +16 -29
  130. reconcile/gql_definitions/change_owners/queries/self_service_roles.py +45 -11
  131. reconcile/gql_definitions/cluster_auth_rhidp/__init__.py +0 -0
  132. reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +128 -0
  133. reconcile/gql_definitions/cna/queries/cna_provisioners.py +6 -8
  134. reconcile/gql_definitions/cna/queries/cna_resources.py +3 -5
  135. reconcile/gql_definitions/common/alerting_services_settings.py +2 -2
  136. reconcile/gql_definitions/common/app_code_component_repos.py +9 -5
  137. reconcile/gql_definitions/{glitchtip/glitchtip_settings.py → common/app_interface_custom_messages.py} +14 -16
  138. reconcile/gql_definitions/common/app_interface_dms_settings.py +86 -0
  139. reconcile/gql_definitions/common/app_interface_repo_settings.py +2 -2
  140. reconcile/gql_definitions/common/app_interface_state_settings.py +3 -5
  141. reconcile/gql_definitions/common/app_interface_vault_settings.py +3 -5
  142. reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +120 -0
  143. reconcile/gql_definitions/common/apps.py +72 -0
  144. reconcile/gql_definitions/common/aws_vpc_requests.py +109 -0
  145. reconcile/gql_definitions/common/aws_vpcs.py +84 -0
  146. reconcile/gql_definitions/common/clusters.py +120 -254
  147. reconcile/gql_definitions/common/clusters_minimal.py +11 -35
  148. reconcile/gql_definitions/common/clusters_with_dms.py +72 -0
  149. reconcile/gql_definitions/common/clusters_with_peering.py +70 -98
  150. reconcile/gql_definitions/common/github_orgs.py +2 -2
  151. reconcile/gql_definitions/common/jira_settings.py +68 -0
  152. reconcile/gql_definitions/common/jiralert_settings.py +68 -0
  153. reconcile/gql_definitions/common/namespaces.py +74 -32
  154. reconcile/gql_definitions/common/namespaces_minimal.py +4 -10
  155. reconcile/gql_definitions/common/ocm_env_telemeter.py +95 -0
  156. reconcile/gql_definitions/common/ocm_environments.py +4 -2
  157. reconcile/gql_definitions/common/pagerduty_instances.py +5 -5
  158. reconcile/gql_definitions/common/pgp_reencryption_settings.py +5 -11
  159. reconcile/gql_definitions/common/pipeline_providers.py +45 -90
  160. reconcile/gql_definitions/common/quay_instances.py +64 -0
  161. reconcile/gql_definitions/common/quay_orgs.py +68 -0
  162. reconcile/gql_definitions/common/reserved_networks.py +94 -0
  163. reconcile/gql_definitions/common/saas_files.py +133 -95
  164. reconcile/gql_definitions/common/saas_target_namespaces.py +41 -26
  165. reconcile/gql_definitions/common/saasherder_settings.py +2 -2
  166. reconcile/gql_definitions/common/slack_workspaces.py +62 -0
  167. reconcile/gql_definitions/common/smtp_client_settings.py +2 -2
  168. reconcile/gql_definitions/common/state_aws_account.py +77 -0
  169. reconcile/gql_definitions/common/users.py +3 -2
  170. reconcile/gql_definitions/cost_report/__init__.py +0 -0
  171. reconcile/gql_definitions/cost_report/app_names.py +68 -0
  172. reconcile/gql_definitions/cost_report/cost_namespaces.py +86 -0
  173. reconcile/gql_definitions/cost_report/settings.py +77 -0
  174. reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +42 -12
  175. reconcile/gql_definitions/dynatrace_token_provider/__init__.py +0 -0
  176. reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +79 -0
  177. reconcile/gql_definitions/dynatrace_token_provider/token_specs.py +84 -0
  178. reconcile/gql_definitions/endpoints_discovery/__init__.py +0 -0
  179. reconcile/gql_definitions/endpoints_discovery/namespaces.py +127 -0
  180. reconcile/gql_definitions/external_resources/__init__.py +0 -0
  181. reconcile/gql_definitions/external_resources/aws_accounts.py +73 -0
  182. reconcile/gql_definitions/external_resources/external_resources_modules.py +78 -0
  183. reconcile/gql_definitions/external_resources/external_resources_namespaces.py +1111 -0
  184. reconcile/gql_definitions/external_resources/external_resources_settings.py +98 -0
  185. reconcile/gql_definitions/fragments/aus_organization.py +34 -39
  186. reconcile/gql_definitions/fragments/aws_account_common.py +62 -0
  187. reconcile/gql_definitions/fragments/aws_account_managed.py +57 -0
  188. reconcile/gql_definitions/fragments/aws_account_sso.py +35 -0
  189. reconcile/gql_definitions/fragments/aws_infra_management_account.py +2 -2
  190. reconcile/gql_definitions/fragments/aws_vpc.py +47 -0
  191. reconcile/gql_definitions/fragments/aws_vpc_request.py +65 -0
  192. reconcile/gql_definitions/fragments/aws_vpc_request_subnet.py +29 -0
  193. reconcile/gql_definitions/fragments/deplopy_resources.py +7 -7
  194. reconcile/gql_definitions/fragments/disable.py +28 -0
  195. reconcile/gql_definitions/fragments/jumphost_common_fields.py +2 -2
  196. reconcile/gql_definitions/fragments/membership_source.py +47 -0
  197. reconcile/gql_definitions/fragments/minimal_ocm_organization.py +29 -0
  198. reconcile/gql_definitions/fragments/oc_connection_cluster.py +4 -9
  199. reconcile/gql_definitions/fragments/ocm_environment.py +5 -5
  200. reconcile/gql_definitions/fragments/pipeline_provider_retention.py +30 -0
  201. reconcile/gql_definitions/fragments/prometheus_instance.py +48 -0
  202. reconcile/gql_definitions/fragments/resource_limits_requirements.py +29 -0
  203. reconcile/gql_definitions/fragments/{resource_requirements.py → resource_requests_requirements.py} +3 -3
  204. reconcile/gql_definitions/fragments/resource_values.py +2 -2
  205. reconcile/gql_definitions/fragments/saas_target_namespace.py +55 -12
  206. reconcile/gql_definitions/fragments/serviceaccount_token.py +38 -0
  207. reconcile/gql_definitions/fragments/terraform_state.py +36 -0
  208. reconcile/gql_definitions/fragments/upgrade_policy.py +5 -3
  209. reconcile/gql_definitions/fragments/user.py +3 -2
  210. reconcile/gql_definitions/fragments/vault_secret.py +2 -2
  211. reconcile/gql_definitions/gitlab_members/gitlab_instances.py +6 -2
  212. reconcile/gql_definitions/gitlab_members/permissions.py +3 -5
  213. reconcile/gql_definitions/glitchtip/glitchtip_instance.py +16 -2
  214. reconcile/gql_definitions/glitchtip/glitchtip_project.py +22 -23
  215. reconcile/gql_definitions/glitchtip_project_alerts/__init__.py +0 -0
  216. reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +173 -0
  217. reconcile/gql_definitions/integrations/integrations.py +62 -45
  218. reconcile/gql_definitions/introspection.json +51176 -0
  219. reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +13 -5
  220. reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +79 -0
  221. reconcile/gql_definitions/jira/__init__.py +0 -0
  222. reconcile/gql_definitions/jira/jira_servers.py +80 -0
  223. reconcile/gql_definitions/jira_permissions_validator/__init__.py +0 -0
  224. reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +131 -0
  225. reconcile/gql_definitions/jumphosts/jumphosts.py +3 -5
  226. reconcile/gql_definitions/ldap_groups/__init__.py +0 -0
  227. reconcile/gql_definitions/ldap_groups/roles.py +111 -0
  228. reconcile/gql_definitions/ldap_groups/settings.py +79 -0
  229. reconcile/gql_definitions/maintenance/__init__.py +0 -0
  230. reconcile/gql_definitions/maintenance/maintenances.py +101 -0
  231. reconcile/gql_definitions/membershipsources/__init__.py +0 -0
  232. reconcile/gql_definitions/membershipsources/roles.py +112 -0
  233. reconcile/gql_definitions/ocm_labels/__init__.py +0 -0
  234. reconcile/gql_definitions/ocm_labels/clusters.py +112 -0
  235. reconcile/gql_definitions/ocm_labels/organizations.py +78 -0
  236. reconcile/gql_definitions/ocm_subscription_labels/__init__.py +0 -0
  237. reconcile/gql_definitions/openshift_cluster_bots/__init__.py +0 -0
  238. reconcile/gql_definitions/openshift_cluster_bots/clusters.py +126 -0
  239. reconcile/gql_definitions/openshift_groups/managed_groups.py +2 -2
  240. reconcile/gql_definitions/openshift_groups/managed_roles.py +3 -2
  241. reconcile/gql_definitions/openshift_serviceaccount_tokens/__init__.py +0 -0
  242. reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +132 -0
  243. reconcile/gql_definitions/quay_membership/quay_membership.py +3 -5
  244. reconcile/gql_definitions/rhidp/__init__.py +0 -0
  245. reconcile/gql_definitions/rhidp/organizations.py +96 -0
  246. reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +2 -2
  247. reconcile/gql_definitions/service_dependencies/service_dependencies.py +9 -31
  248. reconcile/gql_definitions/sharding/aws_accounts.py +2 -2
  249. reconcile/gql_definitions/sharding/ocm_organization.py +63 -0
  250. reconcile/gql_definitions/skupper_network/site_controller_template.py +2 -2
  251. reconcile/gql_definitions/skupper_network/skupper_networks.py +12 -38
  252. reconcile/gql_definitions/slack_usergroups/clusters.py +2 -2
  253. reconcile/gql_definitions/slack_usergroups/permissions.py +8 -15
  254. reconcile/gql_definitions/slack_usergroups/users.py +3 -2
  255. reconcile/gql_definitions/slo_documents/__init__.py +0 -0
  256. reconcile/gql_definitions/slo_documents/slo_documents.py +142 -0
  257. reconcile/gql_definitions/status_board/__init__.py +0 -0
  258. reconcile/gql_definitions/status_board/status_board.py +163 -0
  259. reconcile/gql_definitions/statuspage/statuspages.py +56 -7
  260. reconcile/gql_definitions/templating/__init__.py +0 -0
  261. reconcile/gql_definitions/templating/template_collection.py +130 -0
  262. reconcile/gql_definitions/templating/templates.py +108 -0
  263. reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +4 -8
  264. reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +8 -8
  265. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +6 -8
  266. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +45 -56
  267. reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +4 -8
  268. reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +4 -8
  269. reconcile/gql_definitions/terraform_init/__init__.py +0 -0
  270. reconcile/gql_definitions/terraform_init/aws_accounts.py +93 -0
  271. reconcile/gql_definitions/terraform_repo/__init__.py +0 -0
  272. reconcile/gql_definitions/terraform_repo/terraform_repo.py +141 -0
  273. reconcile/gql_definitions/terraform_resources/database_access_manager.py +158 -0
  274. reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +153 -162
  275. reconcile/gql_definitions/terraform_tgw_attachments/__init__.py +0 -0
  276. reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +119 -0
  277. reconcile/gql_definitions/unleash_feature_toggles/__init__.py +0 -0
  278. reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +113 -0
  279. reconcile/gql_definitions/vault_instances/vault_instances.py +17 -50
  280. reconcile/gql_definitions/vault_policies/vault_policies.py +2 -2
  281. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +49 -12
  282. reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +7 -2
  283. reconcile/integrations_manager.py +25 -13
  284. reconcile/jenkins/types.py +5 -1
  285. reconcile/jenkins_base.py +36 -0
  286. reconcile/jenkins_job_builder.py +10 -48
  287. reconcile/jenkins_job_builds_cleaner.py +40 -25
  288. reconcile/jenkins_job_cleaner.py +1 -3
  289. reconcile/jenkins_roles.py +22 -26
  290. reconcile/jenkins_webhooks.py +9 -6
  291. reconcile/jenkins_worker_fleets.py +11 -6
  292. reconcile/jira_permissions_validator.py +340 -0
  293. reconcile/jira_watcher.py +3 -5
  294. reconcile/ldap_groups/__init__.py +0 -0
  295. reconcile/ldap_groups/integration.py +279 -0
  296. reconcile/ldap_users.py +3 -0
  297. reconcile/ocm/types.py +39 -59
  298. reconcile/ocm_additional_routers.py +0 -1
  299. reconcile/ocm_addons_upgrade_tests_trigger.py +10 -15
  300. reconcile/ocm_aws_infrastructure_access.py +30 -32
  301. reconcile/ocm_clusters.py +217 -130
  302. reconcile/ocm_external_configuration_labels.py +15 -0
  303. reconcile/ocm_github_idp.py +1 -1
  304. reconcile/ocm_groups.py +25 -5
  305. reconcile/ocm_internal_notifications/__init__.py +0 -0
  306. reconcile/ocm_internal_notifications/integration.py +119 -0
  307. reconcile/ocm_labels/__init__.py +0 -0
  308. reconcile/ocm_labels/integration.py +409 -0
  309. reconcile/ocm_machine_pools.py +517 -108
  310. reconcile/ocm_upgrade_scheduler_org_updater.py +15 -11
  311. reconcile/openshift_base.py +609 -207
  312. reconcile/openshift_cluster_bots.py +344 -0
  313. reconcile/openshift_clusterrolebindings.py +15 -15
  314. reconcile/openshift_groups.py +42 -45
  315. reconcile/openshift_limitranges.py +1 -0
  316. reconcile/openshift_namespace_labels.py +22 -28
  317. reconcile/openshift_namespaces.py +22 -22
  318. reconcile/openshift_network_policies.py +4 -8
  319. reconcile/openshift_prometheus_rules.py +43 -0
  320. reconcile/openshift_resourcequotas.py +2 -16
  321. reconcile/openshift_resources.py +12 -10
  322. reconcile/openshift_resources_base.py +304 -328
  323. reconcile/openshift_rolebindings.py +18 -20
  324. reconcile/openshift_saas_deploy.py +105 -21
  325. reconcile/openshift_saas_deploy_change_tester.py +30 -35
  326. reconcile/openshift_saas_deploy_trigger_base.py +39 -36
  327. reconcile/openshift_saas_deploy_trigger_cleaner.py +41 -27
  328. reconcile/openshift_saas_deploy_trigger_configs.py +1 -2
  329. reconcile/openshift_saas_deploy_trigger_images.py +1 -2
  330. reconcile/openshift_saas_deploy_trigger_moving_commits.py +1 -2
  331. reconcile/openshift_saas_deploy_trigger_upstream_jobs.py +1 -2
  332. reconcile/openshift_serviceaccount_tokens.py +138 -74
  333. reconcile/openshift_tekton_resources.py +89 -24
  334. reconcile/openshift_upgrade_watcher.py +110 -62
  335. reconcile/openshift_users.py +16 -15
  336. reconcile/openshift_vault_secrets.py +11 -6
  337. reconcile/oum/__init__.py +0 -0
  338. reconcile/oum/base.py +387 -0
  339. reconcile/oum/labelset.py +55 -0
  340. reconcile/oum/metrics.py +71 -0
  341. reconcile/oum/models.py +69 -0
  342. reconcile/oum/providers.py +59 -0
  343. reconcile/oum/standalone.py +196 -0
  344. reconcile/prometheus_rules_tester/integration.py +31 -23
  345. reconcile/quay_base.py +4 -1
  346. reconcile/quay_membership.py +1 -2
  347. reconcile/quay_mirror.py +111 -61
  348. reconcile/quay_mirror_org.py +34 -21
  349. reconcile/quay_permissions.py +7 -3
  350. reconcile/quay_repos.py +24 -32
  351. reconcile/queries.py +263 -198
  352. reconcile/query_validator.py +3 -5
  353. reconcile/resource_scraper.py +3 -4
  354. reconcile/{template_tester.py → resource_template_tester.py} +3 -3
  355. reconcile/rhidp/__init__.py +0 -0
  356. reconcile/rhidp/common.py +214 -0
  357. reconcile/rhidp/metrics.py +20 -0
  358. reconcile/rhidp/ocm_oidc_idp/__init__.py +0 -0
  359. reconcile/rhidp/ocm_oidc_idp/base.py +221 -0
  360. reconcile/rhidp/ocm_oidc_idp/integration.py +56 -0
  361. reconcile/rhidp/ocm_oidc_idp/metrics.py +22 -0
  362. reconcile/rhidp/sso_client/__init__.py +0 -0
  363. reconcile/rhidp/sso_client/base.py +266 -0
  364. reconcile/rhidp/sso_client/integration.py +60 -0
  365. reconcile/rhidp/sso_client/metrics.py +39 -0
  366. reconcile/run_integration.py +293 -0
  367. reconcile/saas_auto_promotions_manager/integration.py +69 -24
  368. reconcile/saas_auto_promotions_manager/merge_request_manager/batcher.py +208 -0
  369. reconcile/saas_auto_promotions_manager/merge_request_manager/desired_state.py +28 -0
  370. reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request.py +3 -4
  371. reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager_v2.py +172 -0
  372. reconcile/saas_auto_promotions_manager/merge_request_manager/metrics.py +42 -0
  373. reconcile/saas_auto_promotions_manager/merge_request_manager/mr_parser.py +226 -0
  374. reconcile/saas_auto_promotions_manager/merge_request_manager/open_merge_requests.py +23 -0
  375. reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +108 -32
  376. reconcile/saas_auto_promotions_manager/meta.py +4 -0
  377. reconcile/saas_auto_promotions_manager/publisher.py +32 -4
  378. reconcile/saas_auto_promotions_manager/s3_exporter.py +77 -0
  379. reconcile/saas_auto_promotions_manager/subscriber.py +110 -23
  380. reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py +48 -41
  381. reconcile/saas_file_validator.py +16 -6
  382. reconcile/sendgrid_teammates.py +27 -12
  383. reconcile/service_dependencies.py +0 -3
  384. reconcile/signalfx_endpoint_monitoring.py +2 -5
  385. reconcile/skupper_network/integration.py +10 -11
  386. reconcile/skupper_network/models.py +3 -5
  387. reconcile/skupper_network/reconciler.py +28 -35
  388. reconcile/skupper_network/site_controller.py +8 -8
  389. reconcile/slack_base.py +4 -7
  390. reconcile/slack_usergroups.py +249 -171
  391. reconcile/sql_query.py +324 -171
  392. reconcile/status.py +0 -1
  393. reconcile/status_board.py +275 -0
  394. reconcile/statuspage/__init__.py +0 -5
  395. reconcile/statuspage/atlassian.py +219 -80
  396. reconcile/statuspage/integration.py +9 -97
  397. reconcile/statuspage/integrations/__init__.py +0 -0
  398. reconcile/statuspage/integrations/components.py +77 -0
  399. reconcile/statuspage/integrations/maintenances.py +111 -0
  400. reconcile/statuspage/page.py +107 -72
  401. reconcile/statuspage/state.py +6 -11
  402. reconcile/statuspage/status.py +8 -12
  403. reconcile/templates/rosa-classic-cluster-creation.sh.j2 +60 -0
  404. reconcile/templates/rosa-hcp-cluster-creation.sh.j2 +61 -0
  405. reconcile/templating/__init__.py +0 -0
  406. reconcile/templating/lib/__init__.py +0 -0
  407. reconcile/templating/lib/merge_request_manager.py +180 -0
  408. reconcile/templating/lib/model.py +20 -0
  409. reconcile/templating/lib/rendering.py +191 -0
  410. reconcile/templating/renderer.py +410 -0
  411. reconcile/templating/validator.py +153 -0
  412. reconcile/terraform_aws_route53.py +13 -10
  413. reconcile/terraform_cloudflare_dns.py +92 -122
  414. reconcile/terraform_cloudflare_resources.py +15 -13
  415. reconcile/terraform_cloudflare_users.py +27 -27
  416. reconcile/terraform_init/__init__.py +0 -0
  417. reconcile/terraform_init/integration.py +165 -0
  418. reconcile/terraform_init/merge_request.py +57 -0
  419. reconcile/terraform_init/merge_request_manager.py +102 -0
  420. reconcile/terraform_repo.py +403 -0
  421. reconcile/terraform_resources.py +266 -168
  422. reconcile/terraform_tgw_attachments.py +417 -167
  423. reconcile/terraform_users.py +40 -17
  424. reconcile/terraform_vpc_peerings.py +310 -142
  425. reconcile/terraform_vpc_resources/__init__.py +0 -0
  426. reconcile/terraform_vpc_resources/integration.py +220 -0
  427. reconcile/terraform_vpc_resources/merge_request.py +57 -0
  428. reconcile/terraform_vpc_resources/merge_request_manager.py +107 -0
  429. reconcile/typed_queries/alerting_services_settings.py +1 -2
  430. reconcile/typed_queries/app_interface_custom_messages.py +24 -0
  431. reconcile/typed_queries/app_interface_deadmanssnitch_settings.py +17 -0
  432. reconcile/typed_queries/app_interface_metrics_exporter/__init__.py +0 -0
  433. reconcile/typed_queries/app_interface_metrics_exporter/onboarding_status.py +13 -0
  434. reconcile/typed_queries/app_interface_repo_url.py +1 -2
  435. reconcile/typed_queries/app_interface_state_settings.py +1 -3
  436. reconcile/typed_queries/app_interface_vault_settings.py +1 -2
  437. reconcile/typed_queries/app_quay_repos_escalation_policies.py +14 -0
  438. reconcile/typed_queries/apps.py +11 -0
  439. reconcile/typed_queries/aws_vpc_requests.py +9 -0
  440. reconcile/typed_queries/aws_vpcs.py +12 -0
  441. reconcile/typed_queries/cloudflare.py +10 -0
  442. reconcile/typed_queries/clusters.py +7 -5
  443. reconcile/typed_queries/clusters_minimal.py +6 -5
  444. reconcile/typed_queries/clusters_with_dms.py +16 -0
  445. reconcile/typed_queries/cost_report/__init__.py +0 -0
  446. reconcile/typed_queries/cost_report/app_names.py +22 -0
  447. reconcile/typed_queries/cost_report/cost_namespaces.py +43 -0
  448. reconcile/typed_queries/cost_report/settings.py +15 -0
  449. reconcile/typed_queries/dynatrace.py +10 -0
  450. reconcile/typed_queries/dynatrace_environments.py +14 -0
  451. reconcile/typed_queries/dynatrace_token_provider_token_specs.py +14 -0
  452. reconcile/typed_queries/external_resources.py +46 -0
  453. reconcile/typed_queries/get_state_aws_account.py +20 -0
  454. reconcile/typed_queries/glitchtip.py +10 -0
  455. reconcile/typed_queries/jenkins.py +25 -0
  456. reconcile/typed_queries/jira.py +7 -0
  457. reconcile/typed_queries/jira_settings.py +16 -0
  458. reconcile/typed_queries/jiralert_settings.py +22 -0
  459. reconcile/typed_queries/ocm.py +8 -0
  460. reconcile/typed_queries/pagerduty_instances.py +2 -7
  461. reconcile/typed_queries/quay.py +23 -0
  462. reconcile/typed_queries/repos.py +20 -8
  463. reconcile/typed_queries/reserved_networks.py +12 -0
  464. reconcile/typed_queries/saas_files.py +221 -167
  465. reconcile/typed_queries/slack.py +7 -0
  466. reconcile/typed_queries/slo_documents.py +12 -0
  467. reconcile/typed_queries/status_board.py +58 -0
  468. reconcile/typed_queries/tekton_pipeline_providers.py +1 -2
  469. reconcile/typed_queries/terraform_namespaces.py +1 -2
  470. reconcile/typed_queries/terraform_tgw_attachments/__init__.py +0 -0
  471. reconcile/typed_queries/terraform_tgw_attachments/aws_accounts.py +16 -0
  472. reconcile/typed_queries/unleash.py +10 -0
  473. reconcile/typed_queries/users.py +11 -0
  474. reconcile/typed_queries/vault.py +10 -0
  475. reconcile/unleash_feature_toggles/__init__.py +0 -0
  476. reconcile/unleash_feature_toggles/integration.py +287 -0
  477. reconcile/utils/acs/__init__.py +0 -0
  478. reconcile/utils/acs/base.py +81 -0
  479. reconcile/utils/acs/notifiers.py +143 -0
  480. reconcile/utils/acs/policies.py +163 -0
  481. reconcile/utils/acs/rbac.py +277 -0
  482. reconcile/utils/aggregated_list.py +11 -9
  483. reconcile/utils/amtool.py +6 -4
  484. reconcile/utils/aws_api.py +279 -66
  485. reconcile/utils/aws_api_typed/__init__.py +0 -0
  486. reconcile/utils/aws_api_typed/account.py +23 -0
  487. reconcile/utils/aws_api_typed/api.py +273 -0
  488. reconcile/utils/aws_api_typed/dynamodb.py +16 -0
  489. reconcile/utils/aws_api_typed/iam.py +67 -0
  490. reconcile/utils/aws_api_typed/organization.py +152 -0
  491. reconcile/utils/aws_api_typed/s3.py +26 -0
  492. reconcile/utils/aws_api_typed/service_quotas.py +79 -0
  493. reconcile/utils/aws_api_typed/sts.py +36 -0
  494. reconcile/utils/aws_api_typed/support.py +79 -0
  495. reconcile/utils/aws_helper.py +42 -3
  496. reconcile/utils/batches.py +11 -0
  497. reconcile/utils/binary.py +7 -9
  498. reconcile/utils/cloud_resource_best_practice/__init__.py +0 -0
  499. reconcile/utils/cloud_resource_best_practice/aws_rds.py +66 -0
  500. reconcile/utils/clusterhealth/__init__.py +0 -0
  501. reconcile/utils/clusterhealth/providerbase.py +39 -0
  502. reconcile/utils/clusterhealth/telemeter.py +39 -0
  503. reconcile/utils/config.py +3 -4
  504. reconcile/utils/deadmanssnitch_api.py +86 -0
  505. reconcile/utils/differ.py +205 -0
  506. reconcile/utils/disabled_integrations.py +4 -6
  507. reconcile/utils/dynatrace/__init__.py +0 -0
  508. reconcile/utils/dynatrace/client.py +93 -0
  509. reconcile/utils/early_exit_cache.py +289 -0
  510. reconcile/utils/elasticsearch_exceptions.py +5 -0
  511. reconcile/utils/environ.py +2 -2
  512. reconcile/utils/exceptions.py +4 -0
  513. reconcile/utils/expiration.py +4 -8
  514. reconcile/utils/extended_early_exit.py +210 -0
  515. reconcile/utils/external_resource_spec.py +34 -12
  516. reconcile/utils/external_resources.py +48 -20
  517. reconcile/utils/filtering.py +16 -0
  518. reconcile/utils/git.py +49 -16
  519. reconcile/utils/github_api.py +10 -9
  520. reconcile/utils/gitlab_api.py +333 -190
  521. reconcile/utils/glitchtip/client.py +97 -100
  522. reconcile/utils/glitchtip/models.py +89 -11
  523. reconcile/utils/gql.py +157 -58
  524. reconcile/utils/grouping.py +17 -0
  525. reconcile/utils/helm.py +89 -18
  526. reconcile/utils/helpers.py +51 -0
  527. reconcile/utils/imap_client.py +5 -6
  528. reconcile/utils/internal_groups/__init__.py +0 -0
  529. reconcile/utils/internal_groups/client.py +160 -0
  530. reconcile/utils/internal_groups/models.py +71 -0
  531. reconcile/utils/jenkins_api.py +10 -34
  532. reconcile/utils/jinja2/__init__.py +0 -0
  533. reconcile/utils/{jinja2_ext.py → jinja2/extensions.py} +6 -4
  534. reconcile/utils/jinja2/filters.py +142 -0
  535. reconcile/utils/jinja2/utils.py +278 -0
  536. reconcile/utils/jira_client.py +165 -8
  537. reconcile/utils/jjb_client.py +47 -35
  538. reconcile/utils/jobcontroller/__init__.py +0 -0
  539. reconcile/utils/jobcontroller/controller.py +413 -0
  540. reconcile/utils/jobcontroller/models.py +195 -0
  541. reconcile/utils/jsonpath.py +4 -5
  542. reconcile/utils/jump_host.py +13 -12
  543. reconcile/utils/keycloak.py +106 -0
  544. reconcile/utils/ldap_client.py +35 -6
  545. reconcile/utils/lean_terraform_client.py +115 -6
  546. reconcile/utils/membershipsources/__init__.py +0 -0
  547. reconcile/utils/membershipsources/app_interface_resolver.py +60 -0
  548. reconcile/utils/membershipsources/models.py +91 -0
  549. reconcile/utils/membershipsources/resolver.py +110 -0
  550. reconcile/utils/merge_request_manager/__init__.py +0 -0
  551. reconcile/utils/merge_request_manager/merge_request_manager.py +99 -0
  552. reconcile/utils/merge_request_manager/parser.py +67 -0
  553. reconcile/utils/metrics.py +511 -1
  554. reconcile/utils/models.py +123 -0
  555. reconcile/utils/mr/README.md +198 -0
  556. reconcile/utils/mr/__init__.py +14 -10
  557. reconcile/utils/mr/app_interface_reporter.py +2 -2
  558. reconcile/utils/mr/aws_access.py +4 -4
  559. reconcile/utils/mr/base.py +51 -31
  560. reconcile/utils/mr/clusters_updates.py +10 -7
  561. reconcile/utils/mr/glitchtip_access_reporter.py +2 -4
  562. reconcile/utils/mr/labels.py +14 -1
  563. reconcile/utils/mr/notificator.py +1 -3
  564. reconcile/utils/mr/ocm_update_recommended_version.py +1 -2
  565. reconcile/utils/mr/ocm_upgrade_scheduler_org_updates.py +7 -3
  566. reconcile/utils/mr/promote_qontract.py +203 -0
  567. reconcile/utils/mr/user_maintenance.py +24 -4
  568. reconcile/utils/oauth2_backend_application_session.py +132 -0
  569. reconcile/utils/oc.py +194 -170
  570. reconcile/utils/oc_connection_parameters.py +40 -51
  571. reconcile/utils/oc_filters.py +11 -13
  572. reconcile/utils/oc_map.py +14 -35
  573. reconcile/utils/ocm/__init__.py +30 -1
  574. reconcile/utils/ocm/addons.py +228 -0
  575. reconcile/utils/ocm/base.py +618 -5
  576. reconcile/utils/ocm/cluster_groups.py +5 -56
  577. reconcile/utils/ocm/clusters.py +111 -99
  578. reconcile/utils/ocm/identity_providers.py +66 -0
  579. reconcile/utils/ocm/label_sources.py +75 -0
  580. reconcile/utils/ocm/labels.py +139 -54
  581. reconcile/utils/ocm/manifests.py +39 -0
  582. reconcile/utils/ocm/ocm.py +182 -928
  583. reconcile/utils/ocm/products.py +758 -0
  584. reconcile/utils/ocm/search_filters.py +20 -28
  585. reconcile/utils/ocm/service_log.py +32 -79
  586. reconcile/utils/ocm/sre_capability_labels.py +51 -0
  587. reconcile/utils/ocm/status_board.py +66 -0
  588. reconcile/utils/ocm/subscriptions.py +49 -59
  589. reconcile/utils/ocm/syncsets.py +39 -0
  590. reconcile/utils/ocm/upgrades.py +181 -0
  591. reconcile/utils/ocm_base_client.py +71 -36
  592. reconcile/utils/openshift_resource.py +113 -67
  593. reconcile/utils/output.py +18 -11
  594. reconcile/utils/pagerduty_api.py +16 -10
  595. reconcile/utils/parse_dhms_duration.py +13 -1
  596. reconcile/utils/prometheus.py +123 -0
  597. reconcile/utils/promotion_state.py +56 -19
  598. reconcile/utils/promtool.py +5 -8
  599. reconcile/utils/quay_api.py +13 -25
  600. reconcile/utils/raw_github_api.py +3 -5
  601. reconcile/utils/repo_owners.py +2 -8
  602. reconcile/utils/rest_api_base.py +126 -0
  603. reconcile/utils/rosa/__init__.py +0 -0
  604. reconcile/utils/rosa/rosa_cli.py +310 -0
  605. reconcile/utils/rosa/session.py +201 -0
  606. reconcile/utils/ruamel.py +16 -0
  607. reconcile/utils/runtime/__init__.py +0 -1
  608. reconcile/utils/runtime/desired_state_diff.py +9 -20
  609. reconcile/utils/runtime/environment.py +33 -8
  610. reconcile/utils/runtime/integration.py +28 -12
  611. reconcile/utils/runtime/meta.py +1 -3
  612. reconcile/utils/runtime/runner.py +8 -11
  613. reconcile/utils/runtime/sharding.py +93 -36
  614. reconcile/utils/saasherder/__init__.py +1 -1
  615. reconcile/utils/saasherder/interfaces.py +143 -138
  616. reconcile/utils/saasherder/models.py +201 -43
  617. reconcile/utils/saasherder/saasherder.py +508 -378
  618. reconcile/utils/secret_reader.py +22 -27
  619. reconcile/utils/semver_helper.py +15 -1
  620. reconcile/utils/slack_api.py +124 -36
  621. reconcile/utils/smtp_client.py +1 -2
  622. reconcile/utils/sqs_gateway.py +10 -6
  623. reconcile/utils/state.py +276 -127
  624. reconcile/utils/terraform/config_client.py +6 -7
  625. reconcile/utils/terraform_client.py +284 -125
  626. reconcile/utils/terrascript/cloudflare_client.py +38 -17
  627. reconcile/utils/terrascript/cloudflare_resources.py +67 -18
  628. reconcile/utils/terrascript/models.py +2 -3
  629. reconcile/utils/terrascript/resources.py +1 -2
  630. reconcile/utils/terrascript_aws_client.py +1292 -540
  631. reconcile/utils/three_way_diff_strategy.py +157 -0
  632. reconcile/utils/unleash/__init__.py +11 -0
  633. reconcile/utils/{unleash.py → unleash/client.py} +35 -29
  634. reconcile/utils/unleash/server.py +145 -0
  635. reconcile/utils/vault.py +42 -32
  636. reconcile/utils/vaultsecretref.py +2 -4
  637. reconcile/utils/vcs.py +250 -0
  638. reconcile/vault_replication.py +38 -31
  639. reconcile/vpc_peerings_validator.py +82 -13
  640. tools/app_interface_metrics_exporter.py +70 -0
  641. tools/app_interface_reporter.py +44 -157
  642. tools/cli_commands/container_images_report.py +154 -0
  643. tools/cli_commands/cost_report/__init__.py +0 -0
  644. tools/cli_commands/cost_report/aws.py +137 -0
  645. tools/cli_commands/cost_report/cost_management_api.py +155 -0
  646. tools/cli_commands/cost_report/model.py +49 -0
  647. tools/cli_commands/cost_report/openshift.py +166 -0
  648. tools/cli_commands/cost_report/openshift_cost_optimization.py +187 -0
  649. tools/cli_commands/cost_report/response.py +124 -0
  650. tools/cli_commands/cost_report/util.py +72 -0
  651. tools/cli_commands/cost_report/view.py +524 -0
  652. tools/cli_commands/erv2.py +620 -0
  653. tools/cli_commands/gpg_encrypt.py +5 -8
  654. tools/cli_commands/systems_and_tools.py +489 -0
  655. tools/glitchtip_access_revalidation.py +1 -1
  656. tools/qontract_cli.py +2301 -673
  657. tools/saas_metrics_exporter/__init__.py +0 -0
  658. tools/saas_metrics_exporter/commit_distance/__init__.py +0 -0
  659. tools/saas_metrics_exporter/commit_distance/channel.py +63 -0
  660. tools/saas_metrics_exporter/commit_distance/commit_distance.py +103 -0
  661. tools/saas_metrics_exporter/commit_distance/metrics.py +19 -0
  662. tools/saas_metrics_exporter/main.py +99 -0
  663. tools/saas_promotion_state/__init__.py +0 -0
  664. tools/saas_promotion_state/saas_promotion_state.py +105 -0
  665. tools/sd_app_sre_alert_report.py +145 -0
  666. tools/template_validation.py +107 -0
  667. e2e_tests/cli.py +0 -83
  668. e2e_tests/create_namespace.py +0 -43
  669. e2e_tests/dedicated_admin_rolebindings.py +0 -44
  670. e2e_tests/dedicated_admin_test_base.py +0 -39
  671. e2e_tests/default_network_policies.py +0 -47
  672. e2e_tests/default_project_labels.py +0 -52
  673. e2e_tests/network_policy_test_base.py +0 -17
  674. e2e_tests/test_base.py +0 -56
  675. qontract_reconcile-0.10.0.dist-info/LICENSE +0 -201
  676. qontract_reconcile-0.10.0.dist-info/METADATA +0 -63
  677. qontract_reconcile-0.10.0.dist-info/RECORD +0 -586
  678. qontract_reconcile-0.10.0.dist-info/top_level.txt +0 -4
  679. reconcile/ecr_mirror.py +0 -152
  680. reconcile/github_scanner.py +0 -74
  681. reconcile/gitlab_integrations.py +0 -63
  682. reconcile/gql_definitions/ocm_oidc_idp/clusters.py +0 -195
  683. reconcile/gql_definitions/ocp_release_mirror/ocp_release_mirror.py +0 -287
  684. reconcile/integrations_validator.py +0 -18
  685. reconcile/jenkins_plugins.py +0 -129
  686. reconcile/kafka_clusters.py +0 -208
  687. reconcile/ocm_cluster_admin.py +0 -42
  688. reconcile/ocm_oidc_idp.py +0 -198
  689. reconcile/ocp_release_mirror.py +0 -373
  690. reconcile/prometheus_rules_tester_old.py +0 -436
  691. reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager.py +0 -279
  692. reconcile/saas_auto_promotions_manager/utils/vcs.py +0 -141
  693. reconcile/sentry_config.py +0 -613
  694. reconcile/sentry_helper.py +0 -69
  695. reconcile/test/conftest.py +0 -187
  696. reconcile/test/fixtures.py +0 -24
  697. reconcile/test/saas_auto_promotions_manager/conftest.py +0 -69
  698. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py +0 -110
  699. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/data_keys.py +0 -10
  700. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_housekeeping.py +0 -200
  701. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_merge_request_manager.py +0 -151
  702. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py +0 -63
  703. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/data_keys.py +0 -4
  704. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_multiple_namespaces.py +0 -46
  705. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_namespace.py +0 -94
  706. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_target.py +0 -44
  707. reconcile/test/saas_auto_promotions_manager/subscriber/conftest.py +0 -74
  708. reconcile/test/saas_auto_promotions_manager/subscriber/data_keys.py +0 -11
  709. reconcile/test/saas_auto_promotions_manager/subscriber/test_content_hash.py +0 -155
  710. reconcile/test/saas_auto_promotions_manager/subscriber/test_diff.py +0 -173
  711. reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_channels_config_hash.py +0 -226
  712. reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_channels_moving_ref.py +0 -224
  713. reconcile/test/saas_auto_promotions_manager/subscriber/test_single_channel_with_single_publisher.py +0 -350
  714. reconcile/test/saas_auto_promotions_manager/test_integration_test.py +0 -129
  715. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_multiple_publishers_for_single_channel.py +0 -70
  716. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_use_target_config_hash.py +0 -63
  717. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_with_auto_promote.py +0 -74
  718. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_without_auto_promote.py +0 -65
  719. reconcile/test/test_aggregated_list.py +0 -237
  720. reconcile/test/test_amtool.py +0 -37
  721. reconcile/test/test_auto_promoter.py +0 -295
  722. reconcile/test/test_aws_ami_share.py +0 -68
  723. reconcile/test/test_aws_iam_keys.py +0 -70
  724. reconcile/test/test_aws_iam_password_reset.py +0 -35
  725. reconcile/test/test_aws_support_cases_sos.py +0 -23
  726. reconcile/test/test_checkpoint.py +0 -178
  727. reconcile/test/test_cli.py +0 -41
  728. reconcile/test/test_closedbox_endpoint_monitoring.py +0 -207
  729. reconcile/test/test_gabi_authorized_users.py +0 -72
  730. reconcile/test/test_github_org.py +0 -154
  731. reconcile/test/test_github_repo_invites.py +0 -123
  732. reconcile/test/test_gitlab_housekeeping.py +0 -88
  733. reconcile/test/test_gitlab_labeler.py +0 -129
  734. reconcile/test/test_gitlab_members.py +0 -283
  735. reconcile/test/test_instrumented_wrappers.py +0 -18
  736. reconcile/test/test_integrations_manager.py +0 -995
  737. reconcile/test/test_jenkins_worker_fleets.py +0 -55
  738. reconcile/test/test_jump_host.py +0 -117
  739. reconcile/test/test_ldap_users.py +0 -123
  740. reconcile/test/test_make.py +0 -28
  741. reconcile/test/test_ocm_additional_routers.py +0 -134
  742. reconcile/test/test_ocm_addons_upgrade_scheduler_org.py +0 -149
  743. reconcile/test/test_ocm_clusters.py +0 -598
  744. reconcile/test/test_ocm_clusters_manifest_updates.py +0 -89
  745. reconcile/test/test_ocm_oidc_idp.py +0 -315
  746. reconcile/test/test_ocm_update_recommended_version.py +0 -145
  747. reconcile/test/test_ocm_upgrade_scheduler.py +0 -614
  748. reconcile/test/test_ocm_upgrade_scheduler_org_updater.py +0 -129
  749. reconcile/test/test_openshift_base.py +0 -730
  750. reconcile/test/test_openshift_namespace_labels.py +0 -345
  751. reconcile/test/test_openshift_namespaces.py +0 -256
  752. reconcile/test/test_openshift_resource.py +0 -415
  753. reconcile/test/test_openshift_resources_base.py +0 -440
  754. reconcile/test/test_openshift_saas_deploy_change_tester.py +0 -310
  755. reconcile/test/test_openshift_tekton_resources.py +0 -253
  756. reconcile/test/test_openshift_upgrade_watcher.py +0 -146
  757. reconcile/test/test_prometheus_rules_tester.py +0 -151
  758. reconcile/test/test_prometheus_rules_tester_old.py +0 -77
  759. reconcile/test/test_quay_membership.py +0 -86
  760. reconcile/test/test_quay_mirror.py +0 -109
  761. reconcile/test/test_quay_mirror_org.py +0 -70
  762. reconcile/test/test_quay_repos.py +0 -59
  763. reconcile/test/test_queries.py +0 -53
  764. reconcile/test/test_repo_owners.py +0 -47
  765. reconcile/test/test_requests_sender.py +0 -139
  766. reconcile/test/test_saasherder.py +0 -1074
  767. reconcile/test/test_saasherder_allowed_secret_paths.py +0 -127
  768. reconcile/test/test_secret_reader.py +0 -153
  769. reconcile/test/test_slack_base.py +0 -185
  770. reconcile/test/test_slack_usergroups.py +0 -744
  771. reconcile/test/test_sql_query.py +0 -19
  772. reconcile/test/test_terraform_cloudflare_dns.py +0 -117
  773. reconcile/test/test_terraform_cloudflare_resources.py +0 -106
  774. reconcile/test/test_terraform_cloudflare_users.py +0 -749
  775. reconcile/test/test_terraform_resources.py +0 -257
  776. reconcile/test/test_terraform_tgw_attachments.py +0 -631
  777. reconcile/test/test_terraform_users.py +0 -57
  778. reconcile/test/test_terraform_vpc_peerings.py +0 -499
  779. reconcile/test/test_terraform_vpc_peerings_build_desired_state.py +0 -1061
  780. reconcile/test/test_unleash.py +0 -138
  781. reconcile/test/test_utils_aws_api.py +0 -240
  782. reconcile/test/test_utils_aws_helper.py +0 -80
  783. reconcile/test/test_utils_cluster_version_data.py +0 -177
  784. reconcile/test/test_utils_data_structures.py +0 -13
  785. reconcile/test/test_utils_disabled_integrations.py +0 -86
  786. reconcile/test/test_utils_expiration.py +0 -109
  787. reconcile/test/test_utils_external_resource_spec.py +0 -383
  788. reconcile/test/test_utils_external_resources.py +0 -247
  789. reconcile/test/test_utils_github_api.py +0 -73
  790. reconcile/test/test_utils_gitlab_api.py +0 -20
  791. reconcile/test/test_utils_gpg.py +0 -69
  792. reconcile/test/test_utils_gql.py +0 -81
  793. reconcile/test/test_utils_helm.py +0 -306
  794. reconcile/test/test_utils_helpers.py +0 -55
  795. reconcile/test/test_utils_imap_client.py +0 -65
  796. reconcile/test/test_utils_jjb_client.py +0 -52
  797. reconcile/test/test_utils_jsonpath.py +0 -286
  798. reconcile/test/test_utils_ldap_client.py +0 -51
  799. reconcile/test/test_utils_mr.py +0 -226
  800. reconcile/test/test_utils_mr_clusters_updates.py +0 -77
  801. reconcile/test/test_utils_oc.py +0 -984
  802. reconcile/test/test_utils_ocm.py +0 -110
  803. reconcile/test/test_utils_pagerduty_api.py +0 -251
  804. reconcile/test/test_utils_parse_dhms_duration.py +0 -34
  805. reconcile/test/test_utils_password_validator.py +0 -155
  806. reconcile/test/test_utils_quay_api.py +0 -86
  807. reconcile/test/test_utils_semver_helper.py +0 -19
  808. reconcile/test/test_utils_sharding.py +0 -56
  809. reconcile/test/test_utils_slack_api.py +0 -439
  810. reconcile/test/test_utils_smtp_client.py +0 -73
  811. reconcile/test/test_utils_state.py +0 -256
  812. reconcile/test/test_utils_terraform.py +0 -13
  813. reconcile/test/test_utils_terraform_client.py +0 -585
  814. reconcile/test/test_utils_terraform_config_client.py +0 -219
  815. reconcile/test/test_utils_terrascript_aws_client.py +0 -277
  816. reconcile/test/test_utils_terrascript_cloudflare_client.py +0 -597
  817. reconcile/test/test_utils_terrascript_cloudflare_resources.py +0 -26
  818. reconcile/test/test_vault_replication.py +0 -515
  819. reconcile/test/test_vault_utils.py +0 -47
  820. reconcile/test/test_version_bump.py +0 -18
  821. reconcile/test/test_vpc_peerings_validator.py +0 -103
  822. reconcile/test/test_wrong_region.py +0 -78
  823. reconcile/typed_queries/glitchtip_settings.py +0 -18
  824. reconcile/typed_queries/ocp_release_mirror.py +0 -11
  825. reconcile/unleash_watcher.py +0 -120
  826. reconcile/utils/git_secrets.py +0 -63
  827. reconcile/utils/mr/auto_promoter.py +0 -218
  828. reconcile/utils/sentry_client.py +0 -383
  829. release/test_version.py +0 -50
  830. release/version.py +0 -100
  831. tools/test/test_qontract_cli.py +0 -60
  832. tools/test/test_sre_checkpoints.py +0 -79
  833. /e2e_tests/__init__.py → /reconcile/aus/upgrades.py +0 -0
  834. /reconcile/{gql_definitions/ocp_release_mirror → aws_account_manager}/__init__.py +0 -0
  835. /reconcile/{test → aws_ami_cleanup}/__init__.py +0 -0
  836. /reconcile/{test/saas_auto_promotions_manager → aws_cloudwatch_log_retention}/__init__.py +0 -0
  837. /reconcile/{test/saas_auto_promotions_manager/merge_request_manager → aws_saml_idp}/__init__.py +0 -0
  838. /reconcile/{test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager → aws_saml_roles}/__init__.py +0 -0
  839. /reconcile/{test/saas_auto_promotions_manager/merge_request_manager/renderer → aws_version_sync}/__init__.py +0 -0
  840. /reconcile/{test/saas_auto_promotions_manager/subscriber → aws_version_sync/merge_request_manager}/__init__.py +0 -0
  841. /reconcile/{test/saas_auto_promotions_manager/utils → cluster_auth_rhidp}/__init__.py +0 -0
  842. /reconcile/{test/saas_auto_promotions_manager/utils/saas_files_inventory → dynatrace_token_provider}/__init__.py +0 -0
  843. {release → reconcile/endpoints_discovery}/__init__.py +0 -0
  844. {tools/test → reconcile/external_resources}/__init__.py +0 -0
@@ -0,0 +1,275 @@
1
+ import logging
2
+ from abc import (
3
+ ABC,
4
+ abstractmethod,
5
+ )
6
+ from collections.abc import Iterable, Mapping
7
+ from typing import (
8
+ Any,
9
+ Optional,
10
+ )
11
+
12
+ from pydantic import BaseModel
13
+
14
+ from reconcile.gql_definitions.status_board.status_board import StatusBoardV1
15
+ from reconcile.typed_queries.status_board import (
16
+ get_selected_app_names,
17
+ get_status_board,
18
+ )
19
+ from reconcile.utils.differ import diff_mappings
20
+ from reconcile.utils.ocm.status_board import (
21
+ create_application,
22
+ create_product,
23
+ delete_application,
24
+ delete_product,
25
+ get_managed_products,
26
+ get_product_applications,
27
+ )
28
+ from reconcile.utils.ocm_base_client import (
29
+ OCMBaseClient,
30
+ init_ocm_base_client,
31
+ )
32
+ from reconcile.utils.runtime.integration import QontractReconcileIntegration
33
+
34
+ QONTRACT_INTEGRATION = "status-board-exporter"
35
+
36
+
37
+ class AbstractStatusBoard(ABC, BaseModel):
38
+ """Abstract class for upgrade policies
39
+ Used to create and delete upgrade policies in OCM."""
40
+
41
+ id: str | None
42
+ name: str
43
+ fullname: str
44
+ metadata: dict[str, Any] | None
45
+
46
+ @abstractmethod
47
+ def create(self, ocm: OCMBaseClient) -> None:
48
+ pass
49
+
50
+ @abstractmethod
51
+ def delete(self, ocm: OCMBaseClient) -> None:
52
+ pass
53
+
54
+ @abstractmethod
55
+ def summarize(self) -> str:
56
+ pass
57
+
58
+ @staticmethod
59
+ @abstractmethod
60
+ def get_priority() -> int:
61
+ pass
62
+
63
+
64
+ class Product(AbstractStatusBoard):
65
+ applications: list["Application"] | None
66
+
67
+ def create(self, ocm: OCMBaseClient) -> None:
68
+ spec = self.dict(by_alias=True)
69
+ spec.pop("applications")
70
+ spec.pop("id")
71
+ self.id = create_product(ocm, spec)
72
+
73
+ def delete(self, ocm: OCMBaseClient) -> None:
74
+ if not self.id:
75
+ logging.error(f'Trying to delete Product "{self.name}" without id')
76
+ return
77
+ delete_product(ocm, self.id)
78
+
79
+ def summarize(self) -> str:
80
+ return f'Product: "{self.name}"'
81
+
82
+ @staticmethod
83
+ def get_priority() -> int:
84
+ return 0
85
+
86
+
87
+ class Application(AbstractStatusBoard):
88
+ product: Optional["Product"]
89
+
90
+ def create(self, ocm: OCMBaseClient) -> None:
91
+ spec = self.dict(by_alias=True)
92
+ spec.pop("id")
93
+ product = spec.pop("product")
94
+ product_id = product.get("id")
95
+ if product_id:
96
+ spec["product"] = {"id": product_id}
97
+ self.id = create_application(ocm, spec)
98
+ else:
99
+ logging.warning("Missing product id for application")
100
+
101
+ def delete(self, ocm: OCMBaseClient) -> None:
102
+ if not self.id:
103
+ logging.error(f'Trying to delete Application "{self.name}" without id')
104
+ return
105
+ delete_application(ocm, self.id)
106
+
107
+ def summarize(self) -> str:
108
+ return f'Application: "{self.name}" "{self.fullname}"'
109
+
110
+ @staticmethod
111
+ def get_priority() -> int:
112
+ return 1
113
+
114
+
115
+ class StatusBoardHandler(BaseModel):
116
+ action: str
117
+ status_board_object: AbstractStatusBoard
118
+
119
+ def act(self, dry_run: bool, ocm: OCMBaseClient) -> None:
120
+ logging.info(f"{self.action} - {self.status_board_object.summarize()}")
121
+ if dry_run:
122
+ return
123
+
124
+ match self.action:
125
+ case "delete":
126
+ self.status_board_object.delete(ocm)
127
+ case "create":
128
+ self.status_board_object.create(ocm)
129
+
130
+
131
+ class StatusBoardExporterIntegration(QontractReconcileIntegration):
132
+ @property
133
+ def name(self) -> str:
134
+ return QONTRACT_INTEGRATION
135
+
136
+ @staticmethod
137
+ def get_product_apps(sb: StatusBoardV1) -> dict[str, set[str]]:
138
+ global_selectors = (
139
+ sb.global_app_selectors.exclude or [] if sb.global_app_selectors else []
140
+ )
141
+ return {
142
+ p.product_environment.product.name: get_selected_app_names(
143
+ global_selectors, p
144
+ )
145
+ for p in sb.products
146
+ }
147
+
148
+ @staticmethod
149
+ def get_current_products_applications(ocm_api: OCMBaseClient) -> list[Product]:
150
+ products_raw = get_managed_products(ocm_api)
151
+ products = [Product(**p) for p in products_raw]
152
+
153
+ for p in products:
154
+ if not p.id:
155
+ logging.error(f'Product "{p.name}" has no id')
156
+ continue
157
+ p.applications = [
158
+ Application(**a) for a in get_product_applications(ocm_api, p.id)
159
+ ]
160
+
161
+ return products
162
+
163
+ @staticmethod
164
+ def get_diff(
165
+ desired_product_apps: Mapping[str, set[str]],
166
+ current_products_applications: Iterable[Product],
167
+ ) -> list[StatusBoardHandler]:
168
+ def create_app(app_name: str, product: Product) -> Application:
169
+ return Application(
170
+ name=app_name,
171
+ fullname=f"{product.name}/{app_name}",
172
+ product=product,
173
+ )
174
+
175
+ return_list: list[StatusBoardHandler] = []
176
+ current_products = {p.name: p for p in current_products_applications}
177
+
178
+ current_as_mapping: Mapping[str, set[str]] = {
179
+ c.name: {a.name for a in c.applications or []}
180
+ for c in current_products_applications
181
+ }
182
+
183
+ diff_result = diff_mappings(
184
+ current_as_mapping,
185
+ desired_product_apps,
186
+ )
187
+
188
+ for product_name in diff_result.add:
189
+ product = Product(name=product_name, fullname=product_name, applications=[])
190
+ return_list.append(
191
+ StatusBoardHandler(
192
+ action="create",
193
+ status_board_object=product,
194
+ )
195
+ )
196
+ # new product, so it misses also the applications
197
+ for app_name in desired_product_apps[product_name]:
198
+ return_list.append(
199
+ StatusBoardHandler(
200
+ action="create",
201
+ status_board_object=create_app(app_name, product),
202
+ )
203
+ )
204
+
205
+ # existing product, only add/remove applications
206
+ for product_name, apps in diff_result.change.items():
207
+ product = current_products[product_name]
208
+ for app_name in apps.desired - apps.current:
209
+ return_list.append(
210
+ StatusBoardHandler(
211
+ action="create",
212
+ status_board_object=create_app(app_name, product),
213
+ )
214
+ )
215
+ to_delete = apps.current - apps.desired
216
+ for application in product.applications or []:
217
+ if application.name in to_delete:
218
+ return_list.append(
219
+ StatusBoardHandler(
220
+ action="delete",
221
+ status_board_object=application,
222
+ )
223
+ )
224
+
225
+ # product is deleted entirely
226
+ for product_name in diff_result.delete:
227
+ for application in current_products[product_name].applications or []:
228
+ return_list.append(
229
+ StatusBoardHandler(action="delete", status_board_object=application)
230
+ )
231
+ return_list.append(
232
+ StatusBoardHandler(
233
+ action="delete", status_board_object=current_products[product_name]
234
+ )
235
+ )
236
+ return return_list
237
+
238
+ @staticmethod
239
+ def apply_diff(
240
+ dry_run: bool, ocm_api: OCMBaseClient, diff: list[StatusBoardHandler]
241
+ ) -> None:
242
+ creations: list[StatusBoardHandler] = []
243
+ deletions: list[StatusBoardHandler] = []
244
+
245
+ for o in diff:
246
+ match o.action:
247
+ case "create":
248
+ creations.append(o)
249
+ case "delete":
250
+ deletions.append(o)
251
+
252
+ # Products need to be created before Applications
253
+ creations.sort(key=lambda x: x.status_board_object.get_priority())
254
+
255
+ # Applications need to be deleted before Products
256
+ deletions.sort(key=lambda x: x.status_board_object.get_priority(), reverse=True)
257
+
258
+ for d in creations + deletions:
259
+ d.act(dry_run, ocm_api)
260
+
261
+ def run(self, dry_run: bool) -> None:
262
+ # update cyclic reference
263
+ Product.update_forward_refs()
264
+
265
+ for sb in get_status_board():
266
+ ocm_api = init_ocm_base_client(sb.ocm, self.secret_reader)
267
+ desired_product_apps: dict[str, set[str]] = self.get_product_apps(sb)
268
+
269
+ current_products_applications = self.get_current_products_applications(
270
+ ocm_api
271
+ )
272
+
273
+ diff = self.get_diff(desired_product_apps, current_products_applications)
274
+
275
+ self.apply_diff(dry_run, ocm_api, diff)
@@ -1,5 +0,0 @@
1
- from reconcile.statuspage import atlassian
2
- from reconcile.statuspage.page import register_provider
3
-
4
- # Status page providers are registered here to prevent all kinds of cyclic imports.
5
- register_provider(atlassian.PROVIDER_NAME, atlassian.init_provider_for_page)
@@ -1,24 +1,26 @@
1
1
  import logging
2
+ import time
3
+ from datetime import datetime
2
4
  from typing import (
3
5
  Any,
4
- Optional,
5
- Protocol,
6
+ Self,
6
7
  )
7
8
 
8
- import statuspageio # type: ignore
9
+ import requests
9
10
  from pydantic import BaseModel
11
+ from requests import Response
12
+ from sretoolbox.utils import retry
10
13
 
11
14
  from reconcile.gql_definitions.statuspage.statuspages import StatusPageV1
12
15
  from reconcile.statuspage.page import (
13
16
  StatusComponent,
17
+ StatusMaintenance,
18
+ StatusMaintenanceAnnouncement,
14
19
  StatusPage,
15
- StatusPageProvider,
16
20
  )
17
21
  from reconcile.statuspage.state import ComponentBindingState
18
22
  from reconcile.statuspage.status import ManualStatusProvider
19
23
 
20
- PROVIDER_NAME = "atlassian"
21
-
22
24
 
23
25
  class AtlassianRawComponent(BaseModel):
24
26
  """
@@ -27,66 +29,118 @@ class AtlassianRawComponent(BaseModel):
27
29
 
28
30
  id: str
29
31
  name: str
30
- description: Optional[str]
32
+ description: str | None
31
33
  position: int
32
34
  status: str
33
- automation_email: Optional[str]
34
- group_id: Optional[str]
35
- group: Optional[bool]
35
+ automation_email: str | None
36
+ group_id: str | None
37
+ group: bool | None
36
38
 
37
39
 
38
- class AtlassianAPI(Protocol):
39
- def list_components(self) -> list[AtlassianRawComponent]:
40
- ...
40
+ class AtlassianRawMaintenanceUpdate(BaseModel):
41
+ """
42
+ atlassian status page REST schema for maintenance updates
43
+ """
41
44
 
42
- def update_component(self, id: str, data: dict[str, Any]) -> None:
43
- ...
45
+ body: str
44
46
 
45
- def create_component(self, data: dict[str, Any]) -> str:
46
- ...
47
47
 
48
- def delete_component(self, id: str) -> None:
49
- ...
48
+ class AtlassianRawMaintenance(BaseModel):
49
+ """
50
+ atlassian status page REST schema for maintenance
51
+ """
50
52
 
53
+ id: str
54
+ name: str
55
+ scheduled_for: str
56
+ scheduled_until: str
57
+ incident_updates: list[AtlassianRawMaintenanceUpdate]
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
51
62
 
52
- class LegacyLibAtlassianAPI:
63
+
64
+ class AtlassianAPI:
53
65
  """
54
- This API class wraps the statuspageio python library for basic component operations.
55
- This class is named Legacy for a couple reasons:
56
- * the underlying library is not maintained anymore
57
- * the library has no type annotated
58
- * the library does not support pagination which becomes important for this API
59
- Therefore this lib will be replaced by a think wrapper based on uplink in an upcoming PR.
66
+ This API class wraps the statuspageio REST API for basic component operations.
60
67
  """
61
68
 
62
69
  def __init__(self, page_id: str, api_url: str, token: str):
63
70
  self.page_id = page_id
64
71
  self.api_url = api_url
65
72
  self.token = token
66
- self._client = statuspageio.Client(
67
- api_key=self.token, page_id=self.page_id, organization_id="unset"
73
+ self.auth_headers = {"Authorization": f"OAuth {self.token}"}
74
+
75
+ @retry(max_attempts=10)
76
+ def _do_get(self, url: str, params: dict[str, Any]) -> Response:
77
+ response = requests.get(
78
+ url, params=params, headers=self.auth_headers, timeout=30
68
79
  )
80
+ response.raise_for_status()
81
+ return response
82
+
83
+ def _list_items(self, url: str) -> list[Any]:
84
+ all_items: list[Any] = []
85
+ page = 1
86
+ per_page = 100
87
+ while True:
88
+ params = {"page": page, "per_page": per_page}
89
+ response = self._do_get(url, params=params)
90
+ items = response.json()
91
+ all_items += items
92
+ if len(items) < per_page:
93
+ break
94
+ page += 1
95
+ # https://developer.statuspage.io/#section/Rate-Limiting
96
+ # Each API token is limited to 1 request / second as measured on a 60 second rolling window
97
+ time.sleep(1)
98
+
99
+ return all_items
69
100
 
70
101
  def list_components(self) -> list[AtlassianRawComponent]:
71
- return [
72
- AtlassianRawComponent(
73
- **c.toDict(),
74
- )
75
- for c in self._client.components.list()
76
- ]
102
+ url = f"{self.api_url}/v1/pages/{self.page_id}/components"
103
+ all_components = self._list_items(url)
104
+ return [AtlassianRawComponent(**c) for c in all_components]
77
105
 
78
106
  def update_component(self, id: str, data: dict[str, Any]) -> None:
79
- self._client.components.update(id, **data)
107
+ url = f"{self.api_url}/v1/pages/{self.page_id}/components/{id}"
108
+ requests.patch(
109
+ url, json={"component": data}, headers=self.auth_headers
110
+ ).raise_for_status()
80
111
 
81
112
  def create_component(self, data: dict[str, Any]) -> str:
82
- result = self._client.components.create(**data)
83
- return result["id"]
113
+ url = f"{self.api_url}/v1/pages/{self.page_id}/components"
114
+ response = requests.post(
115
+ url, json={"component": data}, headers=self.auth_headers
116
+ )
117
+ response.raise_for_status()
118
+ return response.json()["id"]
84
119
 
85
120
  def delete_component(self, id: str) -> None:
86
- self._client.components.delete(id)
121
+ url = f"{self.api_url}/v1/pages/{self.page_id}/components/{id}"
122
+ requests.delete(url, headers=self.auth_headers).raise_for_status()
123
+
124
+ def list_scheduled_maintenances(self) -> list[AtlassianRawMaintenance]:
125
+ url = f"{self.api_url}/v1/pages/{self.page_id}/incidents/scheduled"
126
+ all_scheduled_incidents = self._list_items(url)
127
+ return [AtlassianRawMaintenance(**i) for i in all_scheduled_incidents]
128
+
129
+ def list_active_maintenances(self) -> list[AtlassianRawMaintenance]:
130
+ url = f"{self.api_url}/v1/pages/{self.page_id}/incidents/active_maintenance"
131
+ all_active_incidents = self._list_items(url)
132
+ return [AtlassianRawMaintenance(**i) for i in all_active_incidents]
133
+
134
+ def create_incident(self, data: dict[str, Any]) -> str:
135
+ url = f"{self.api_url}/v1/pages/{self.page_id}/incidents"
136
+ response = requests.post(
137
+ url, json={"incident": data}, headers=self.auth_headers
138
+ )
139
+ response.raise_for_status()
140
+ return response.json()["id"]
87
141
 
88
142
 
89
- class AtlassianStatusPageProvider(StatusPageProvider):
143
+ class AtlassianStatusPageProvider:
90
144
  """
91
145
  The provider implements CRUD operations for Atlassian status pages.
92
146
  It also takes care of a mixed set of components on a page, where some
@@ -123,13 +177,13 @@ class AtlassianStatusPageProvider(StatusPageProvider):
123
177
  self._group_name_to_id = {g.name: g.id for g in self._components if g.group}
124
178
  self._group_id_to_name = {g.id: g.name for g in self._components if g.group}
125
179
 
126
- def get_component_by_id(self, id: str) -> Optional[StatusComponent]:
180
+ def get_component_by_id(self, id: str) -> StatusComponent | None:
127
181
  raw = self.get_raw_component_by_id(id)
128
182
  if raw:
129
183
  return self._bound_raw_component_to_status_component(raw)
130
184
  return None
131
185
 
132
- def get_raw_component_by_id(self, id: str) -> Optional[AtlassianRawComponent]:
186
+ def get_raw_component_by_id(self, id: str) -> AtlassianRawComponent | None:
133
187
  return self._components_by_id.get(id)
134
188
 
135
189
  def get_current_page(self) -> StatusPage:
@@ -146,34 +200,41 @@ class AtlassianStatusPageProvider(StatusPageProvider):
146
200
  components=[c for c in components if c is not None],
147
201
  )
148
202
 
203
+ def _raw_component_to_status_component(
204
+ self, raw_component: AtlassianRawComponent, name_override: str | None = None
205
+ ) -> StatusComponent:
206
+ group_name = (
207
+ self._group_id_to_name.get(raw_component.group_id)
208
+ if raw_component.group_id
209
+ else None
210
+ )
211
+ return StatusComponent(
212
+ name=name_override or raw_component.name,
213
+ display_name=raw_component.name,
214
+ description=raw_component.description,
215
+ group_name=group_name,
216
+ status_provider_configs=[
217
+ ManualStatusProvider(
218
+ component_status=raw_component.status,
219
+ )
220
+ ],
221
+ )
222
+
149
223
  def _bound_raw_component_to_status_component(
150
224
  self, raw_component: AtlassianRawComponent
151
- ) -> Optional[StatusComponent]:
225
+ ) -> StatusComponent | None:
152
226
  bound_component_name = self._binding_state.get_name_for_component_id(
153
227
  raw_component.id
154
228
  )
155
229
  if bound_component_name:
156
- group_name = (
157
- self._group_id_to_name.get(raw_component.group_id)
158
- if raw_component.group_id
159
- else None
160
- )
161
- return StatusComponent(
162
- name=bound_component_name,
163
- display_name=raw_component.name,
164
- description=raw_component.description,
165
- group_name=group_name,
166
- status_provider_configs=[
167
- ManualStatusProvider(
168
- component_status=raw_component.status,
169
- )
170
- ],
230
+ return self._raw_component_to_status_component(
231
+ raw_component, name_override=bound_component_name
171
232
  )
172
233
  return None
173
234
 
174
235
  def lookup_component(
175
236
  self, desired_component: StatusComponent
176
- ) -> tuple[Optional[AtlassianRawComponent], bool]:
237
+ ) -> tuple[AtlassianRawComponent | None, bool]:
177
238
  """
178
239
  Finds the component on the page that matches the desired component. This
179
240
  is either done explicitely by using binding information if available or
@@ -207,7 +268,7 @@ class AtlassianStatusPageProvider(StatusPageProvider):
207
268
  return component, bound
208
269
 
209
270
  def should_apply(
210
- self, desired: StatusComponent, current: Optional[AtlassianRawComponent]
271
+ self, desired: StatusComponent, current: AtlassianRawComponent | None
211
272
  ) -> bool:
212
273
  """
213
274
  Verifies if the desired component should be applied to the status page
@@ -240,8 +301,15 @@ class AtlassianStatusPageProvider(StatusPageProvider):
240
301
 
241
302
  # component status
242
303
  desired_component_status = desired.desired_component_status()
243
- status_update_required = desired_component_status is not None and (
244
- not current or desired_component_status != current.status
304
+ active_maintenance_affecting_component = [
305
+ m
306
+ for m in self.active_maintenances
307
+ if desired.display_name in [c.name for c in m.components]
308
+ ]
309
+ status_update_required = (
310
+ desired_component_status is not None
311
+ and (not current or desired_component_status != current.status)
312
+ and not active_maintenance_affecting_component
245
313
  )
246
314
 
247
315
  # shortcut execution if there is nothing to do
@@ -265,7 +333,7 @@ class AtlassianStatusPageProvider(StatusPageProvider):
265
333
  component_id=current_component.id,
266
334
  )
267
335
 
268
- # validte the component and check if the current state needs to be updated
336
+ # validate the component and check if the current state needs to be updated
269
337
  needs_update = self.should_apply(desired, current_component)
270
338
  if not needs_update:
271
339
  return
@@ -288,7 +356,13 @@ class AtlassianStatusPageProvider(StatusPageProvider):
288
356
  # resolve status
289
357
  desired_component_status = desired.desired_component_status()
290
358
  if desired_component_status:
291
- component_update["status"] = desired_component_status
359
+ active_maintenance_affecting_component = [
360
+ m
361
+ for m in self.active_maintenances
362
+ if desired.display_name in [c.name for c in m.components]
363
+ ]
364
+ if not active_maintenance_affecting_component:
365
+ component_update["status"] = desired_component_status
292
366
 
293
367
  if current_component:
294
368
  logging.info(f"update component {desired.name}: {component_update}")
@@ -333,21 +407,86 @@ class AtlassianStatusPageProvider(StatusPageProvider):
333
407
  if not dry_run:
334
408
  self._binding_state.bind_component(component_name, component_id)
335
409
 
410
+ def _raw_maintenance_to_status_maintenance(
411
+ self,
412
+ raw_maintenance: AtlassianRawMaintenance,
413
+ name_override: str | None = None,
414
+ ) -> StatusMaintenance:
415
+ return StatusMaintenance(
416
+ name=name_override or raw_maintenance.name,
417
+ message=raw_maintenance.incident_updates[0].body,
418
+ schedule_start=datetime.fromisoformat(raw_maintenance.scheduled_for),
419
+ schedule_end=datetime.fromisoformat(raw_maintenance.scheduled_until),
420
+ components=[
421
+ self._raw_component_to_status_component(c)
422
+ for c in raw_maintenance.components
423
+ ],
424
+ announcements=StatusMaintenanceAnnouncement(
425
+ remind_subscribers=raw_maintenance.scheduled_remind_prior,
426
+ notify_subscribers_on_start=raw_maintenance.auto_transition_deliver_notifications_at_start,
427
+ notify_subscribers_on_completion=raw_maintenance.auto_transition_deliver_notifications_at_end,
428
+ ),
429
+ )
336
430
 
337
- def init_provider_for_page(
338
- page: StatusPageV1,
339
- token: str,
340
- component_binding_state: ComponentBindingState,
341
- ) -> AtlassianStatusPageProvider:
342
- """
343
- Initializes the provider for atlassian status page.
344
- """
345
- return AtlassianStatusPageProvider(
346
- page_name=page.name,
347
- api=LegacyLibAtlassianAPI(
348
- page_id=page.page_id,
349
- api_url=page.api_url,
350
- token=token,
351
- ),
352
- component_binding_state=component_binding_state,
353
- )
431
+ @classmethod
432
+ def init_from_page(
433
+ cls,
434
+ page: StatusPageV1,
435
+ token: str,
436
+ component_binding_state: ComponentBindingState,
437
+ ) -> Self:
438
+ """
439
+ Initializes the provider for atlassian status page.
440
+ """
441
+ return cls(
442
+ page_name=page.name,
443
+ api=AtlassianAPI(
444
+ page_id=page.page_id,
445
+ api_url=page.api_url,
446
+ token=token,
447
+ ),
448
+ component_binding_state=component_binding_state,
449
+ )
450
+
451
+ @property
452
+ def scheduled_maintenances(self) -> list[StatusMaintenance]:
453
+ return [
454
+ self._raw_maintenance_to_status_maintenance(m)
455
+ for m in self._api.list_scheduled_maintenances()
456
+ ]
457
+
458
+ @property
459
+ def active_maintenances(self) -> list[StatusMaintenance]:
460
+ return [
461
+ self._raw_maintenance_to_status_maintenance(m)
462
+ for m in self._api.list_active_maintenances()
463
+ ]
464
+
465
+ def create_maintenance(self, maintenance: StatusMaintenance) -> None:
466
+ component_ids: list[str] = []
467
+ for sc in maintenance.components:
468
+ current_component, _ = self.lookup_component(sc)
469
+ if current_component:
470
+ component_ids.append(current_component.id)
471
+ data = {
472
+ "name": maintenance.name,
473
+ "status": "scheduled",
474
+ "scheduled_for": maintenance.schedule_start.isoformat(),
475
+ "scheduled_until": maintenance.schedule_end.isoformat(),
476
+ "body": maintenance.message,
477
+ "scheduled_remind_prior": maintenance.announcements.remind_subscribers,
478
+ "scheduled_auto_transition": True,
479
+ "scheduled_auto_in_progress": True,
480
+ "scheduled_auto_completed": True,
481
+ "component_ids": component_ids,
482
+ "auto_transition_to_maintenance_state": True,
483
+ "auto_transition_to_operational_state": True,
484
+ "auto_transition_deliver_notifications_at_start": maintenance.announcements.notify_subscribers_on_start,
485
+ "auto_transition_deliver_notifications_at_end": maintenance.announcements.notify_subscribers_on_completion,
486
+ }
487
+ incident_id = self._api.create_incident(data)
488
+ self._bind_component(
489
+ dry_run=False,
490
+ component_name=maintenance.name,
491
+ component_id=incident_id,
492
+ )