qontract-reconcile 0.9.1rc298__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 (843) 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.9.1rc298.dist-info → qontract_reconcile-0.10.1.dev1203.dist-info}/WHEEL +1 -2
  4. {qontract_reconcile-0.9.1rc298.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.9.1rc298.dist-info/METADATA +0 -63
  676. qontract_reconcile-0.9.1rc298.dist-info/RECORD +0 -585
  677. qontract_reconcile-0.9.1rc298.dist-info/top_level.txt +0 -4
  678. reconcile/ecr_mirror.py +0 -152
  679. reconcile/github_scanner.py +0 -74
  680. reconcile/gitlab_integrations.py +0 -63
  681. reconcile/gql_definitions/ocm_oidc_idp/clusters.py +0 -195
  682. reconcile/gql_definitions/ocp_release_mirror/ocp_release_mirror.py +0 -287
  683. reconcile/integrations_validator.py +0 -18
  684. reconcile/jenkins_plugins.py +0 -129
  685. reconcile/kafka_clusters.py +0 -208
  686. reconcile/ocm_cluster_admin.py +0 -42
  687. reconcile/ocm_oidc_idp.py +0 -198
  688. reconcile/ocp_release_mirror.py +0 -373
  689. reconcile/prometheus_rules_tester_old.py +0 -436
  690. reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager.py +0 -279
  691. reconcile/saas_auto_promotions_manager/utils/vcs.py +0 -141
  692. reconcile/sentry_config.py +0 -613
  693. reconcile/sentry_helper.py +0 -69
  694. reconcile/test/conftest.py +0 -187
  695. reconcile/test/fixtures.py +0 -24
  696. reconcile/test/saas_auto_promotions_manager/conftest.py +0 -69
  697. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py +0 -110
  698. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/data_keys.py +0 -10
  699. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_housekeeping.py +0 -200
  700. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_merge_request_manager.py +0 -151
  701. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py +0 -63
  702. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/data_keys.py +0 -4
  703. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_multiple_namespaces.py +0 -46
  704. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_namespace.py +0 -94
  705. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_target.py +0 -44
  706. reconcile/test/saas_auto_promotions_manager/subscriber/conftest.py +0 -74
  707. reconcile/test/saas_auto_promotions_manager/subscriber/data_keys.py +0 -11
  708. reconcile/test/saas_auto_promotions_manager/subscriber/test_content_hash.py +0 -155
  709. reconcile/test/saas_auto_promotions_manager/subscriber/test_diff.py +0 -173
  710. reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_channels_config_hash.py +0 -226
  711. reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_channels_moving_ref.py +0 -224
  712. reconcile/test/saas_auto_promotions_manager/subscriber/test_single_channel_with_single_publisher.py +0 -350
  713. reconcile/test/saas_auto_promotions_manager/test_integration_test.py +0 -129
  714. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_multiple_publishers_for_single_channel.py +0 -70
  715. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_use_target_config_hash.py +0 -63
  716. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_with_auto_promote.py +0 -74
  717. reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_without_auto_promote.py +0 -65
  718. reconcile/test/test_aggregated_list.py +0 -237
  719. reconcile/test/test_amtool.py +0 -37
  720. reconcile/test/test_auto_promoter.py +0 -295
  721. reconcile/test/test_aws_ami_share.py +0 -68
  722. reconcile/test/test_aws_iam_keys.py +0 -70
  723. reconcile/test/test_aws_iam_password_reset.py +0 -35
  724. reconcile/test/test_aws_support_cases_sos.py +0 -23
  725. reconcile/test/test_checkpoint.py +0 -178
  726. reconcile/test/test_cli.py +0 -41
  727. reconcile/test/test_closedbox_endpoint_monitoring.py +0 -207
  728. reconcile/test/test_gabi_authorized_users.py +0 -72
  729. reconcile/test/test_github_org.py +0 -154
  730. reconcile/test/test_github_repo_invites.py +0 -123
  731. reconcile/test/test_gitlab_housekeeping.py +0 -88
  732. reconcile/test/test_gitlab_labeler.py +0 -129
  733. reconcile/test/test_gitlab_members.py +0 -283
  734. reconcile/test/test_instrumented_wrappers.py +0 -18
  735. reconcile/test/test_integrations_manager.py +0 -995
  736. reconcile/test/test_jenkins_worker_fleets.py +0 -55
  737. reconcile/test/test_jump_host.py +0 -117
  738. reconcile/test/test_ldap_users.py +0 -123
  739. reconcile/test/test_make.py +0 -28
  740. reconcile/test/test_ocm_additional_routers.py +0 -134
  741. reconcile/test/test_ocm_addons_upgrade_scheduler_org.py +0 -149
  742. reconcile/test/test_ocm_clusters.py +0 -598
  743. reconcile/test/test_ocm_clusters_manifest_updates.py +0 -89
  744. reconcile/test/test_ocm_oidc_idp.py +0 -315
  745. reconcile/test/test_ocm_update_recommended_version.py +0 -145
  746. reconcile/test/test_ocm_upgrade_scheduler.py +0 -614
  747. reconcile/test/test_ocm_upgrade_scheduler_org_updater.py +0 -129
  748. reconcile/test/test_openshift_base.py +0 -730
  749. reconcile/test/test_openshift_namespace_labels.py +0 -345
  750. reconcile/test/test_openshift_namespaces.py +0 -256
  751. reconcile/test/test_openshift_resource.py +0 -415
  752. reconcile/test/test_openshift_resources_base.py +0 -440
  753. reconcile/test/test_openshift_saas_deploy_change_tester.py +0 -310
  754. reconcile/test/test_openshift_tekton_resources.py +0 -253
  755. reconcile/test/test_openshift_upgrade_watcher.py +0 -146
  756. reconcile/test/test_prometheus_rules_tester.py +0 -151
  757. reconcile/test/test_prometheus_rules_tester_old.py +0 -77
  758. reconcile/test/test_quay_membership.py +0 -86
  759. reconcile/test/test_quay_mirror.py +0 -109
  760. reconcile/test/test_quay_mirror_org.py +0 -70
  761. reconcile/test/test_quay_repos.py +0 -59
  762. reconcile/test/test_queries.py +0 -53
  763. reconcile/test/test_repo_owners.py +0 -47
  764. reconcile/test/test_requests_sender.py +0 -139
  765. reconcile/test/test_saasherder.py +0 -1074
  766. reconcile/test/test_saasherder_allowed_secret_paths.py +0 -127
  767. reconcile/test/test_secret_reader.py +0 -153
  768. reconcile/test/test_slack_base.py +0 -185
  769. reconcile/test/test_slack_usergroups.py +0 -744
  770. reconcile/test/test_sql_query.py +0 -19
  771. reconcile/test/test_terraform_cloudflare_dns.py +0 -117
  772. reconcile/test/test_terraform_cloudflare_resources.py +0 -106
  773. reconcile/test/test_terraform_cloudflare_users.py +0 -749
  774. reconcile/test/test_terraform_resources.py +0 -257
  775. reconcile/test/test_terraform_tgw_attachments.py +0 -631
  776. reconcile/test/test_terraform_users.py +0 -57
  777. reconcile/test/test_terraform_vpc_peerings.py +0 -499
  778. reconcile/test/test_terraform_vpc_peerings_build_desired_state.py +0 -1061
  779. reconcile/test/test_unleash.py +0 -138
  780. reconcile/test/test_utils_aws_api.py +0 -240
  781. reconcile/test/test_utils_aws_helper.py +0 -80
  782. reconcile/test/test_utils_cluster_version_data.py +0 -177
  783. reconcile/test/test_utils_data_structures.py +0 -13
  784. reconcile/test/test_utils_disabled_integrations.py +0 -86
  785. reconcile/test/test_utils_expiration.py +0 -109
  786. reconcile/test/test_utils_external_resource_spec.py +0 -383
  787. reconcile/test/test_utils_external_resources.py +0 -247
  788. reconcile/test/test_utils_github_api.py +0 -73
  789. reconcile/test/test_utils_gitlab_api.py +0 -20
  790. reconcile/test/test_utils_gpg.py +0 -69
  791. reconcile/test/test_utils_gql.py +0 -81
  792. reconcile/test/test_utils_helm.py +0 -306
  793. reconcile/test/test_utils_helpers.py +0 -55
  794. reconcile/test/test_utils_imap_client.py +0 -65
  795. reconcile/test/test_utils_jjb_client.py +0 -52
  796. reconcile/test/test_utils_jsonpath.py +0 -286
  797. reconcile/test/test_utils_ldap_client.py +0 -51
  798. reconcile/test/test_utils_mr.py +0 -226
  799. reconcile/test/test_utils_mr_clusters_updates.py +0 -77
  800. reconcile/test/test_utils_oc.py +0 -984
  801. reconcile/test/test_utils_ocm.py +0 -110
  802. reconcile/test/test_utils_pagerduty_api.py +0 -251
  803. reconcile/test/test_utils_parse_dhms_duration.py +0 -34
  804. reconcile/test/test_utils_password_validator.py +0 -155
  805. reconcile/test/test_utils_quay_api.py +0 -86
  806. reconcile/test/test_utils_semver_helper.py +0 -19
  807. reconcile/test/test_utils_sharding.py +0 -56
  808. reconcile/test/test_utils_slack_api.py +0 -439
  809. reconcile/test/test_utils_smtp_client.py +0 -73
  810. reconcile/test/test_utils_state.py +0 -256
  811. reconcile/test/test_utils_terraform.py +0 -13
  812. reconcile/test/test_utils_terraform_client.py +0 -585
  813. reconcile/test/test_utils_terraform_config_client.py +0 -219
  814. reconcile/test/test_utils_terrascript_aws_client.py +0 -277
  815. reconcile/test/test_utils_terrascript_cloudflare_client.py +0 -597
  816. reconcile/test/test_utils_terrascript_cloudflare_resources.py +0 -26
  817. reconcile/test/test_vault_replication.py +0 -515
  818. reconcile/test/test_vault_utils.py +0 -47
  819. reconcile/test/test_version_bump.py +0 -18
  820. reconcile/test/test_vpc_peerings_validator.py +0 -103
  821. reconcile/test/test_wrong_region.py +0 -78
  822. reconcile/typed_queries/glitchtip_settings.py +0 -18
  823. reconcile/typed_queries/ocp_release_mirror.py +0 -11
  824. reconcile/unleash_watcher.py +0 -120
  825. reconcile/utils/git_secrets.py +0 -63
  826. reconcile/utils/mr/auto_promoter.py +0 -218
  827. reconcile/utils/sentry_client.py +0 -383
  828. release/test_version.py +0 -50
  829. release/version.py +0 -100
  830. tools/test/test_qontract_cli.py +0 -60
  831. tools/test/test_sre_checkpoints.py +0 -79
  832. /e2e_tests/__init__.py → /reconcile/aus/upgrades.py +0 -0
  833. /reconcile/{gql_definitions/ocp_release_mirror → aws_account_manager}/__init__.py +0 -0
  834. /reconcile/{test → aws_ami_cleanup}/__init__.py +0 -0
  835. /reconcile/{test/saas_auto_promotions_manager → aws_cloudwatch_log_retention}/__init__.py +0 -0
  836. /reconcile/{test/saas_auto_promotions_manager/merge_request_manager → aws_saml_idp}/__init__.py +0 -0
  837. /reconcile/{test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager → aws_saml_roles}/__init__.py +0 -0
  838. /reconcile/{test/saas_auto_promotions_manager/merge_request_manager/renderer → aws_version_sync}/__init__.py +0 -0
  839. /reconcile/{test/saas_auto_promotions_manager/subscriber → aws_version_sync/merge_request_manager}/__init__.py +0 -0
  840. /reconcile/{test/saas_auto_promotions_manager/utils → cluster_auth_rhidp}/__init__.py +0 -0
  841. /reconcile/{test/saas_auto_promotions_manager/utils/saas_files_inventory → dynatrace_token_provider}/__init__.py +0 -0
  842. {release → reconcile/endpoints_discovery}/__init__.py +0 -0
  843. {tools/test → reconcile/external_resources}/__init__.py +0 -0
@@ -1,35 +1,39 @@
1
1
  import json
2
2
  import logging
3
+ import re
3
4
  import shutil
5
+ import tempfile
4
6
  from collections import defaultdict
5
7
  from collections.abc import (
8
+ Generator,
6
9
  Iterable,
7
10
  Mapping,
8
11
  )
12
+ from contextlib import contextmanager
9
13
  from dataclasses import dataclass
10
14
  from datetime import (
11
15
  datetime,
12
16
  timedelta,
13
17
  )
18
+ from subprocess import CalledProcessError
14
19
  from threading import Lock
15
20
  from typing import (
21
+ IO,
16
22
  Any,
17
- Optional,
18
23
  cast,
19
24
  )
20
25
 
21
26
  from botocore.errorfactory import ClientError
22
- from python_terraform import (
23
- IsFlagged,
24
- Terraform,
25
- TerraformCommandError,
26
- )
27
+ from packaging import version as pkg_version
27
28
  from sretoolbox.utils import (
28
29
  retry,
29
30
  threaded,
30
31
  )
31
32
 
32
33
  import reconcile.utils.lean_terraform_client as lean_tf
34
+ from reconcile.typed_queries.app_interface_custom_messages import (
35
+ get_app_interface_custom_message,
36
+ )
33
37
  from reconcile.utils.aws_api import AWSApi
34
38
  from reconcile.utils.aws_helper import get_region_from_availability_zone
35
39
  from reconcile.utils.external_resource_spec import (
@@ -37,8 +41,15 @@ from reconcile.utils.external_resource_spec import (
37
41
  ExternalResourceSpecInventory,
38
42
  )
39
43
 
40
- ALLOWED_TF_SHOW_FORMAT_VERSION = "0.1"
44
+ ALLOWED_TF_SHOW_FORMAT_VERSION = "1.2"
41
45
  DATE_FORMAT = "%Y-%m-%d"
46
+ PROVIDER_LOG_REGEX = (
47
+ r""".*\s(?:\[INFO]|\[WARN]|\[ERROR])\s.+\s(?:\[WARN]|\[ERROR])\s.*"""
48
+ )
49
+ PROVIDER_LOG_IGNORE_REGEX = (
50
+ r""".*(?:ObjectLockConfigurationNotFoundError|WaitForState).*"""
51
+ )
52
+ TERRAFORM_LOG_LEVEL = "TRACE" # can change to INFO after tf 0.15
42
53
 
43
54
 
44
55
  @dataclass
@@ -47,6 +58,20 @@ class AccountUser:
47
58
  user: str
48
59
 
49
60
 
61
+ @dataclass(frozen=True, eq=True)
62
+ class TerraformSpec:
63
+ name: str
64
+ working_dir: str
65
+
66
+
67
+ class TerraformCommandError(CalledProcessError):
68
+ pass
69
+
70
+
71
+ class RdsUpgradeValidationError(Exception):
72
+ pass
73
+
74
+
50
75
  class DeletionApprovalExpirationValueError(Exception):
51
76
  pass
52
77
 
@@ -60,7 +85,7 @@ class TerraformClient: # pylint: disable=too-many-public-methods
60
85
  accounts: Iterable[Mapping[str, Any]],
61
86
  working_dirs: Mapping[str, str],
62
87
  thread_pool_size: int,
63
- aws_api: Optional[AWSApi] = None,
88
+ aws_api: AWSApi | None = None,
64
89
  init_users=False,
65
90
  ):
66
91
  self.integration = integration
@@ -72,27 +97,32 @@ class TerraformClient: # pylint: disable=too-many-public-methods
72
97
  self.thread_pool_size = thread_pool_size
73
98
  self._aws_api = aws_api
74
99
  self._log_lock = Lock()
75
- self.should_apply = False
100
+ self.apply_count = 0
76
101
 
102
+ self.specs: list[TerraformSpec] = []
77
103
  self.init_specs()
104
+ self.outputs: dict = {}
78
105
  self.init_outputs()
79
106
 
80
107
  self.OUTPUT_TYPE_SECRETS = "Secrets"
81
108
  self.OUTPUT_TYPE_PASSWORDS = "enc-passwords"
82
109
  self.OUTPUT_TYPE_CONSOLEURLS = "console-urls"
83
110
 
111
+ self.users: dict = {}
84
112
  if init_users:
85
113
  self.init_existing_users()
86
114
 
87
115
  def init_existing_users(self):
88
- all_users = {}
89
- for account, output in self.outputs.items():
90
- users = []
91
- user_passwords = self.format_output(output, self.OUTPUT_TYPE_PASSWORDS)
92
- for user_name in user_passwords:
93
- users.append(user_name)
94
- all_users[account] = users
95
- self.users = all_users
116
+ self.users = {
117
+ account: list(self.format_output(output, self.OUTPUT_TYPE_PASSWORDS).keys())
118
+ for account, output in self.outputs.items()
119
+ }
120
+
121
+ def increment_apply_count(self):
122
+ self.apply_count += 1
123
+
124
+ def should_apply(self) -> bool:
125
+ return self.apply_count > 0
96
126
 
97
127
  def get_new_users(self):
98
128
  new_users = []
@@ -103,37 +133,54 @@ class TerraformClient: # pylint: disable=too-many-public-methods
103
133
  for user_name, enc_password in user_passwords.items():
104
134
  if AccountUser(account, user_name) not in self.created_users:
105
135
  continue
106
- new_users.append(
107
- (account, console_urls[account], user_name, enc_password)
108
- )
136
+ new_users.append((
137
+ account,
138
+ console_urls[account],
139
+ user_name,
140
+ enc_password,
141
+ ))
109
142
  return new_users
110
143
 
111
144
  def init_specs(self):
112
- wd_specs = [{"name": name, "wd": wd} for name, wd in self.working_dirs.items()]
113
- results = threaded.run(self.terraform_init, wd_specs, self.thread_pool_size)
114
- self.specs = [{"name": name, "tf": tf} for name, tf in results]
145
+ self.specs = [
146
+ TerraformSpec(name=name, working_dir=wd)
147
+ for name, wd in self.working_dirs.items()
148
+ ]
149
+ for spec in self.specs:
150
+ self.terraform_init(spec)
151
+
152
+ @contextmanager
153
+ def _terraform_log_file(
154
+ self, working_dir: str
155
+ ) -> Generator[tuple[IO, dict[str, str]], None, None]:
156
+ with tempfile.NamedTemporaryFile(dir=working_dir) as f:
157
+ env = {
158
+ "TF_LOG": TERRAFORM_LOG_LEVEL,
159
+ "TF_LOG_PATH": f.name,
160
+ }
161
+ yield f, env
115
162
 
116
163
  @retry(exceptions=TerraformCommandError)
117
- def terraform_init(self, init_spec):
118
- name = init_spec["name"]
119
- wd = init_spec["wd"]
120
- tf = Terraform(working_dir=wd)
121
- return_code, stdout, stderr = tf.init()
122
- error = self.check_output(name, "init", return_code, stdout, stderr)
164
+ def terraform_init(self, spec: TerraformSpec):
165
+ with self._terraform_log_file(spec.working_dir) as (f, env):
166
+ return_code, stdout, stderr = lean_tf.init(spec.working_dir, env=env)
167
+ log = f.read().decode("utf-8")
168
+ error = self.check_output(spec.name, "init", return_code, stdout, stderr, log)
123
169
  if error:
124
- raise TerraformCommandError(return_code, "init", out=stdout, err=stderr)
125
- return name, tf
170
+ raise TerraformCommandError(
171
+ return_code, "init", output=stdout, stderr=stderr
172
+ )
126
173
 
127
174
  def init_outputs(self):
128
175
  results = threaded.run(self.terraform_output, self.specs, self.thread_pool_size)
129
176
  self.outputs = dict(results)
130
177
 
131
178
  @retry(exceptions=TerraformCommandError)
132
- def terraform_output(self, spec):
133
- name = spec["name"]
134
- tf = spec["tf"]
135
- return_code, stdout, stderr = tf.output_cmd(json=IsFlagged)
136
- error = self.check_output(name, "output", return_code, stdout, stderr)
179
+ def terraform_output(self, spec: TerraformSpec):
180
+ with self._terraform_log_file(spec.working_dir) as (f, env):
181
+ return_code, stdout, stderr = lean_tf.output(spec.working_dir, env=env)
182
+ log = f.read().decode("utf-8")
183
+ error = self.check_output(spec.name, "output", return_code, stdout, stderr, log)
137
184
  no_output_error = (
138
185
  "The module root could not be found. There is nothing to output."
139
186
  )
@@ -142,9 +189,9 @@ class TerraformClient: # pylint: disable=too-many-public-methods
142
189
  stdout = "{}"
143
190
  else:
144
191
  raise TerraformCommandError(
145
- return_code, "output", out=stdout, err=stderr
192
+ return_code, "output", output=stdout, stderr=stderr
146
193
  )
147
- return name, json.loads(stdout)
194
+ return spec.name, json.loads(stdout)
148
195
 
149
196
  # terraform plan
150
197
  def plan(self, enable_deletion):
@@ -166,18 +213,31 @@ class TerraformClient: # pylint: disable=too-many-public-methods
166
213
  self.created_users.extend(created_users)
167
214
  return disabled_deletions_detected, errors
168
215
 
169
- @retry()
216
+ def safe_plan(self, enable_deletion: bool) -> None:
217
+ """Raises exception if errors are detected at plan step"""
218
+ disable_deletions_detected, errors = self.plan(enable_deletion)
219
+
220
+ if errors:
221
+ raise RuntimeError("Terraform plan has errors")
222
+ if disable_deletions_detected:
223
+ raise RuntimeError("Terraform plan has disabled deletions detected")
224
+
225
+ @retry(no_retry_exceptions=RdsUpgradeValidationError)
170
226
  def terraform_plan(
171
- self, plan_spec: dict, enable_deletion: bool
227
+ self, spec: TerraformSpec, enable_deletion: bool
172
228
  ) -> tuple[bool, list[AccountUser], bool]:
173
- name = plan_spec["name"]
174
- tf = plan_spec["tf"]
175
- return_code, stdout, stderr = tf.plan(
176
- detailed_exitcode=False, parallelism=self.parallelism, out=name
177
- )
178
- error = self.check_output(name, "plan", return_code, stdout, stderr)
229
+ with self._terraform_log_file(spec.working_dir) as (f, env):
230
+ return_code, stdout, stderr = lean_tf.plan(
231
+ spec.working_dir,
232
+ spec.name,
233
+ env=env,
234
+ )
235
+ log = f.read().decode("utf-8")
236
+ error = self.check_output(spec.name, "plan", return_code, stdout, stderr, log)
237
+ if error:
238
+ return False, [], error
179
239
  disabled_deletion_detected, created_users = self.log_plan_diff(
180
- name, tf, enable_deletion
240
+ spec, enable_deletion
181
241
  )
182
242
  return disabled_deletion_detected, created_users, error
183
243
 
@@ -216,11 +276,11 @@ class TerraformClient: # pylint: disable=too-many-public-methods
216
276
 
217
277
  def log_plan_diff(
218
278
  self,
219
- name: str,
220
- tf: Terraform,
279
+ spec: TerraformSpec,
221
280
  enable_deletion: bool,
222
281
  ) -> tuple[bool, list]:
223
282
  disabled_deletion_detected = False
283
+ name = spec.name
224
284
  account_enable_deletion = self.accounts[name].get("enableDeletion") or False
225
285
  # deletions are allowed
226
286
  # if enableDeletion is true for an account
@@ -228,7 +288,7 @@ class TerraformClient: # pylint: disable=too-many-public-methods
228
288
  deletions_allowed = enable_deletion or account_enable_deletion
229
289
  created_users: list[AccountUser] = []
230
290
 
231
- output = self.terraform_show(name, tf.working_dir)
291
+ output = lean_tf.show_json(spec.working_dir, name)
232
292
  format_version = output.get("format_version")
233
293
  if format_version != ALLOWED_TF_SHOW_FORMAT_VERSION:
234
294
  raise NotImplementedError("terraform show untested format version")
@@ -245,7 +305,7 @@ class TerraformClient: # pylint: disable=too-many-public-methods
245
305
  after = output_change.get("after")
246
306
  if before != after:
247
307
  logging.info(["update", name, "output", output_name])
248
- self.should_apply = True
308
+ self.increment_apply_count()
249
309
 
250
310
  # A way to detect deleted outputs is by comparing
251
311
  # the prior state with the output changes.
@@ -258,7 +318,7 @@ class TerraformClient: # pylint: disable=too-many-public-methods
258
318
  deleted_outputs = [po for po in prior_outputs if po not in output_changes]
259
319
  for output_name in deleted_outputs:
260
320
  logging.info(["delete", name, "output", output_name])
261
- self.should_apply = True
321
+ self.increment_apply_count()
262
322
 
263
323
  resource_changes = output.get("resource_changes")
264
324
  if resource_changes is None:
@@ -267,6 +327,7 @@ class TerraformClient: # pylint: disable=too-many-public-methods
267
327
  always_enabled_deletions = {
268
328
  "random_id",
269
329
  "aws_lb_target_group_attachment",
330
+ "aws_iam_user_policy",
270
331
  "cloudflare_record", # This is because a zone can contain up to one thousand records and it's not practical to require adding each record to deletionApprovals
271
332
  }
272
333
 
@@ -274,14 +335,30 @@ class TerraformClient: # pylint: disable=too-many-public-methods
274
335
  for resource_change in resource_changes:
275
336
  resource_type = resource_change["type"]
276
337
  resource_name = resource_change["name"]
338
+ resource_address = resource_change["address"]
339
+ resource_previous_address = resource_change.get("previous_address")
277
340
  resource_change = resource_change["change"]
278
341
  actions = resource_change["actions"]
279
342
  for action in actions:
343
+ if resource_previous_address:
344
+ # the resource is being moved/renamed in the TF state
345
+ with self._log_lock:
346
+ logging.info([
347
+ "move/rename",
348
+ name,
349
+ resource_previous_address,
350
+ resource_address,
351
+ ])
352
+
280
353
  if action == "no-op":
281
354
  logging.debug([action, name, resource_type, resource_name])
282
- continue
355
+ if resource_previous_address:
356
+ # apply resource renaming with no-op
357
+ self.increment_apply_count()
358
+ else:
359
+ continue
283
360
  if action == "update" and resource_type == "aws_db_instance":
284
- self._validate_db_upgrade(name, resource_name, resource_change)
361
+ self.validate_db_upgrade(name, resource_name, resource_change)
285
362
  # Ignore RDS modifications that are going to occur during the next
286
363
  # maintenance window. This can be up to 7 days away and will cause
287
364
  # unnecessary Terraform state updates until they complete.
@@ -294,16 +371,14 @@ class TerraformClient: # pylint: disable=too-many-public-methods
294
371
  )
295
372
  continue
296
373
  with self._log_lock:
297
- logging.info(
298
- [
299
- action,
300
- name,
301
- resource_type,
302
- resource_name,
303
- self._resource_diff_changed_fields(action, resource_change),
304
- ]
305
- )
306
- self.should_apply = True
374
+ logging.info([
375
+ action,
376
+ name,
377
+ resource_type,
378
+ resource_name,
379
+ self._resource_diff_changed_fields(action, resource_change),
380
+ ])
381
+ self.increment_apply_count()
307
382
  if action == "create":
308
383
  if resource_type == "aws_iam_user_login_profile":
309
384
  created_users.append(AccountUser(name, resource_name))
@@ -315,11 +390,13 @@ class TerraformClient: # pylint: disable=too-many-public-methods
315
390
  name, resource_type, resource_name
316
391
  ):
317
392
  disabled_deletion_detected = True
318
- logging.error(
319
- "'delete' action is not enabled. "
320
- + "Please run the integration manually "
321
- + "with the '--enable-deletion' flag."
393
+ instructions = (
394
+ get_app_interface_custom_message(
395
+ "disabled-deletion-instructions"
396
+ )
397
+ or ""
322
398
  )
399
+ logging.error(f"'delete' action is not enabled. {instructions}")
323
400
  if resource_type == "aws_db_instance":
324
401
  deletion_protected = resource_change["before"].get(
325
402
  "deletion_protection"
@@ -351,7 +428,7 @@ class TerraformClient: # pylint: disable=too-many-public-methods
351
428
  f"[{account_name}] expiration not does not match "
352
429
  f"date format {DATE_FORMAT}. details: "
353
430
  f"type: {da['type']}, name: {da['name']}"
354
- )
431
+ ) from None
355
432
  if (
356
433
  resource_type == da["type"]
357
434
  and resource_name == da["name"]
@@ -361,28 +438,20 @@ class TerraformClient: # pylint: disable=too-many-public-methods
361
438
 
362
439
  return False
363
440
 
364
- @staticmethod
365
- def terraform_show(name, working_dir):
366
- return lean_tf.show_json(working_dir, name)
367
-
368
441
  # terraform apply
369
442
  def apply(self):
370
- errors = False
371
-
372
- results = threaded.run(self.terraform_apply, self.specs, self.thread_pool_size)
373
-
374
- for error in results:
375
- if error:
376
- errors = True
377
- return errors
378
-
379
- def terraform_apply(self, apply_spec):
380
- name = apply_spec["name"]
381
- tf = apply_spec["tf"]
382
- # adding var=None to allow applying the saved plan
383
- # https://github.com/beelit94/python-terraform/issues/67
384
- return_code, stdout, stderr = tf.apply(dir_or_plan=name, var=None)
385
- error = self.check_output(name, "apply", return_code, stdout, stderr)
443
+ errors = threaded.run(self.terraform_apply, self.specs, self.thread_pool_size)
444
+ return any(errors)
445
+
446
+ def terraform_apply(self, spec: TerraformSpec):
447
+ with self._terraform_log_file(spec.working_dir) as (f, env):
448
+ return_code, stdout, stderr = lean_tf.apply(
449
+ spec.working_dir,
450
+ spec.name,
451
+ env=env,
452
+ )
453
+ log = f.read().decode("utf-8")
454
+ error = self.check_output(spec.name, "apply", return_code, stdout, stderr, log)
386
455
  return error
387
456
 
388
457
  def get_terraform_output_secrets(self) -> dict[str, dict[str, dict[str, str]]]:
@@ -411,9 +480,9 @@ class TerraformClient: # pylint: disable=too-many-public-methods
411
480
  replica_source_name = f'{replica_src}-{tf_resource.get("provider")}'
412
481
  # Creating a dict that is convenient to use inside the
413
482
  # loop processing the formatted_output
414
- replicas_info[spec.provisioner_name][
415
- spec.output_prefix
416
- ] = replica_source_name
483
+ replicas_info[spec.provisioner_name][spec.output_prefix] = (
484
+ replica_source_name
485
+ )
417
486
 
418
487
  return replicas_info
419
488
 
@@ -423,12 +492,8 @@ class TerraformClient: # pylint: disable=too-many-public-methods
423
492
  if output is None:
424
493
  return data
425
494
 
426
- enc_pass_pfx = "{}_{}".format(
427
- self.integration_prefix, self.OUTPUT_TYPE_PASSWORDS
428
- )
429
- console_urls_pfx = "{}_{}".format(
430
- self.integration_prefix, self.OUTPUT_TYPE_CONSOLEURLS
431
- )
495
+ enc_pass_pfx = f"{self.integration_prefix}_{self.OUTPUT_TYPE_PASSWORDS}"
496
+ console_urls_pfx = f"{self.integration_prefix}_{self.OUTPUT_TYPE_CONSOLEURLS}"
432
497
  for k, v in output.items():
433
498
  # the integration creates outputs of the form
434
499
  # 0.11: output_secret_name[secret_key] = secret_value
@@ -474,11 +539,11 @@ class TerraformClient: # pylint: disable=too-many-public-methods
474
539
  data[resource_name] = {}
475
540
  data[resource_name][field_key] = field_value
476
541
 
477
- if len(data) == 1 and type in (
542
+ if len(data) == 1 and type in {
478
543
  self.OUTPUT_TYPE_PASSWORDS,
479
544
  self.OUTPUT_TYPE_CONSOLEURLS,
480
- ):
481
- return data[list(data.keys())[0]]
545
+ }:
546
+ return data[next(iter(data.keys()))]
482
547
  return data
483
548
 
484
549
  def populate_terraform_output_secrets(
@@ -541,7 +606,7 @@ class TerraformClient: # pylint: disable=too-many-public-methods
541
606
  secret_copy["db.password"] = replica_src_password
542
607
 
543
608
  # clean metadata
544
- for key in secret.keys():
609
+ for key in secret:
545
610
  if integration_prefix in key:
546
611
  secret_copy.pop(key)
547
612
 
@@ -552,22 +617,29 @@ class TerraformClient: # pylint: disable=too-many-public-methods
552
617
  name: str,
553
618
  cmd: str,
554
619
  return_code: int,
555
- stdout: list[str],
556
- stderr: list[str],
620
+ stdout: str,
621
+ stderr: str,
622
+ log: str,
557
623
  ) -> bool:
558
- error_occured = False
624
+ error_occured = return_code != 0
559
625
  line_format = "[{} - {}] {}"
560
- stdout, stderr = self.split_to_lines(stdout, stderr)
626
+ stdout, stderr, log = self.split_to_lines(stdout, stderr, log)
627
+ provider_log_re = re.compile(PROVIDER_LOG_REGEX)
628
+ provider_log_ignore_re = re.compile(PROVIDER_LOG_IGNORE_REGEX)
561
629
  with self._log_lock:
562
630
  for line in stdout:
563
631
  logging.debug(line_format.format(name, cmd, line))
564
- if return_code == 0:
632
+ if error_occured:
565
633
  for line in stderr:
566
- logging.warning(line_format.format(name, cmd, line))
634
+ logging.error(line_format.format(name, cmd, line))
567
635
  else:
568
636
  for line in stderr:
569
- logging.error(line_format.format(name, cmd, line))
570
- error_occured = True
637
+ logging.warning(line_format.format(name, cmd, line))
638
+ for line in log:
639
+ if provider_log_re.match(line) and not provider_log_ignore_re.match(
640
+ line
641
+ ):
642
+ logging.warning(line_format.format(name, cmd, line))
571
643
  return error_occured
572
644
 
573
645
  @staticmethod
@@ -683,7 +755,7 @@ class TerraformClient: # pylint: disable=too-many-public-methods
683
755
  return not set(changed_resource_arguments) - set(changed_values)
684
756
  return False
685
757
 
686
- def _validate_db_upgrade(
758
+ def validate_db_upgrade(
687
759
  self, account_name: str, resource_name: str, resource_change: Mapping[str, Any]
688
760
  ):
689
761
  """
@@ -711,23 +783,110 @@ class TerraformClient: # pylint: disable=too-many-public-methods
711
783
  valid_upgrade_target = self._aws_api.get_db_valid_upgrade_target(
712
784
  account_name, engine, before_version, region_name=region_name
713
785
  )
714
- found = False
715
- for t in valid_upgrade_target:
716
- if t["EngineVersion"] == after_version:
717
- found = True
718
- if t["IsMajorVersionUpgrade"] and not after.get(
719
- "allow_major_version_upgrade", False
720
- ):
721
- raise ValueError(
722
- "allow_major_version_upgrade is not enabled for upgrading RDS instance: "
723
- f"{resource_name} to a new major version."
724
- )
725
-
726
- if not found:
727
- raise ValueError(
786
+ target = next(
787
+ (
788
+ t
789
+ for t in valid_upgrade_target
790
+ if t["EngineVersion"] == after_version
791
+ ),
792
+ None,
793
+ )
794
+ if target is None:
795
+ raise RdsUpgradeValidationError(
728
796
  f"Cannot upgrade RDS instance: {resource_name} "
729
797
  f"from {before_version} to {after_version}"
730
798
  )
799
+ allow_major_version_upgrade = after.get(
800
+ "allow_major_version_upgrade",
801
+ False,
802
+ )
803
+ if target["IsMajorVersionUpgrade"] and not allow_major_version_upgrade:
804
+ raise RdsUpgradeValidationError(
805
+ "allow_major_version_upgrade is not enabled for upgrading RDS instance: "
806
+ f"{resource_name} to a new major version."
807
+ )
808
+
809
+ blue_green_update = after.get("blue_green_update", [])
810
+ if blue_green_update and blue_green_update[0]["enabled"]:
811
+ changed_fields = self._resource_diff_changed_fields(
812
+ "update", resource_change
813
+ )
814
+ replica = before["replicas"] != [] or before["replicate_source_db"]
815
+ self.validate_blue_green_update_requirements(
816
+ account_name,
817
+ resource_name,
818
+ engine,
819
+ before_version,
820
+ replica,
821
+ before["parameter_group_name"],
822
+ region_name,
823
+ changed_fields=changed_fields,
824
+ )
825
+
826
+ def validate_blue_green_update_requirements(
827
+ self,
828
+ account_name: str,
829
+ resource_name: str,
830
+ engine: str,
831
+ version: str,
832
+ replica: bool,
833
+ parameter_group: str,
834
+ region_name: str,
835
+ changed_fields: set[str],
836
+ ) -> None:
837
+ min_supported_versions = {
838
+ "mysql": [pkg_version.parse("5.7"), pkg_version.parse("8.0.15")],
839
+ "postgres": [
840
+ pkg_version.parse("11.21"),
841
+ pkg_version.parse("12.16"),
842
+ pkg_version.parse("13.12"),
843
+ pkg_version.parse("14.9"),
844
+ pkg_version.parse("15.4"),
845
+ pkg_version.parse("16.1"),
846
+ ],
847
+ }
848
+
849
+ def is_supported(engine, version):
850
+ parsed_version = pkg_version.parse(version)
851
+ if engine == "mysql":
852
+ return any(
853
+ parsed_version >= min_version
854
+ for min_version in min_supported_versions["mysql"]
855
+ )
856
+ elif engine == "postgres":
857
+ return any(
858
+ parsed_version >= min_version
859
+ for min_version in min_supported_versions["postgres"]
860
+ )
861
+ return False
862
+
863
+ if not is_supported(engine, version):
864
+ raise RdsUpgradeValidationError(
865
+ f"Cannot upgrade RDS instance: {resource_name}. "
866
+ f"Engine version {version} is not supported for blue/green updates."
867
+ )
868
+
869
+ if replica:
870
+ raise RdsUpgradeValidationError(
871
+ f"Cannot upgrade RDS instance: {resource_name}. "
872
+ "Blue/green updates are not supported for instances with read replicas."
873
+ )
874
+
875
+ if engine == "postgres" and self._aws_api is not None:
876
+ pg_details = self._aws_api.describe_db_parameter_group(
877
+ account_name, parameter_group, region_name
878
+ )
879
+ if pg_details.get("rds.logical_replication") != "1":
880
+ raise RdsUpgradeValidationError(
881
+ f"Cannot upgrade RDS instance: {resource_name}. "
882
+ f"Blue/green updates require logical replication to be enabled in the Parameter group {parameter_group}."
883
+ )
884
+
885
+ if "storage_type" in changed_fields or "allocated_storage" in changed_fields:
886
+ raise RdsUpgradeValidationError(
887
+ f"Cannot upgrade RDS instance: {resource_name}. "
888
+ f"Blue/green updates are not supported when 'storage_type' or 'allocated_storage' has changed."
889
+ )
731
890
 
732
891
 
733
892
  class TerraformPlanFailed(Exception):