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
@@ -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):