Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

202 lines
5.5KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Config.TransferTask do
  5. use Task
  6. alias Pleroma.Config
  7. alias Pleroma.ConfigDB
  8. alias Pleroma.Repo
  9. require Logger
  10. @type env() :: :test | :benchmark | :dev | :prod
  11. @reboot_time_keys [
  12. {:pleroma, :hackney_pools},
  13. {:pleroma, :chat},
  14. {:pleroma, Oban},
  15. {:pleroma, :rate_limit},
  16. {:pleroma, :markup},
  17. {:pleroma, :streamer},
  18. {:pleroma, :pools},
  19. {:pleroma, :connections_pool}
  20. ]
  21. @reboot_time_subkeys [
  22. {:pleroma, Pleroma.Captcha, [:seconds_valid]},
  23. {:pleroma, Pleroma.Upload, [:proxy_remote]},
  24. {:pleroma, :instance, [:upload_limit]},
  25. {:pleroma, :gopher, [:enabled]}
  26. ]
  27. def start_link(restart_pleroma? \\ true) do
  28. load_and_update_env([], restart_pleroma?)
  29. if Config.get(:env) == :test, do: Ecto.Adapters.SQL.Sandbox.checkin(Repo)
  30. :ignore
  31. end
  32. @spec load_and_update_env([ConfigDB.t()], boolean()) :: :ok
  33. def load_and_update_env(deleted_settings \\ [], restart_pleroma? \\ true) do
  34. with {_, true} <- {:configurable, Config.get(:configurable_from_database)} do
  35. # We need to restart applications for loaded settings take effect
  36. {logger, other} =
  37. (Repo.all(ConfigDB) ++ deleted_settings)
  38. |> Enum.map(&merge_with_default/1)
  39. |> Enum.split_with(fn {group, _, _, _} -> group in [:logger, :quack] end)
  40. logger
  41. |> Enum.sort()
  42. |> Enum.each(&configure/1)
  43. started_applications = Application.started_applications()
  44. # TODO: some problem with prometheus after restart!
  45. reject = [nil, :prometheus, :postgrex]
  46. reject =
  47. if restart_pleroma? do
  48. reject
  49. else
  50. [:pleroma | reject]
  51. end
  52. other
  53. |> Enum.map(&update/1)
  54. |> Enum.uniq()
  55. |> Enum.reject(&(&1 in reject))
  56. |> maybe_set_pleroma_last()
  57. |> Enum.each(&restart(started_applications, &1, Config.get(:env)))
  58. :ok
  59. else
  60. {:configurable, false} -> Restarter.Pleroma.rebooted()
  61. end
  62. end
  63. defp maybe_set_pleroma_last(apps) do
  64. # to be ensured that pleroma will be restarted last
  65. if :pleroma in apps do
  66. apps
  67. |> List.delete(:pleroma)
  68. |> List.insert_at(-1, :pleroma)
  69. else
  70. Restarter.Pleroma.rebooted()
  71. apps
  72. end
  73. end
  74. defp merge_with_default(%{group: group, key: key, value: value} = setting) do
  75. default = Config.Holder.default_config(group, key)
  76. merged =
  77. cond do
  78. Ecto.get_meta(setting, :state) == :deleted -> default
  79. can_be_merged?(default, value) -> ConfigDB.merge_group(group, key, default, value)
  80. true -> value
  81. end
  82. {group, key, value, merged}
  83. end
  84. # change logger configuration in runtime, without restart
  85. defp configure({:quack, key, _, merged}) do
  86. Logger.configure_backend(Quack.Logger, [{key, merged}])
  87. :ok = update_env(:quack, key, merged)
  88. end
  89. defp configure({_, :backends, _, merged}) do
  90. # removing current backends
  91. Enum.each(Application.get_env(:logger, :backends), &Logger.remove_backend/1)
  92. Enum.each(merged, &Logger.add_backend/1)
  93. :ok = update_env(:logger, :backends, merged)
  94. end
  95. defp configure({_, key, _, merged}) when key in [:console, :ex_syslogger] do
  96. merged =
  97. if key == :console do
  98. put_in(merged[:format], merged[:format] <> "\n")
  99. else
  100. merged
  101. end
  102. backend =
  103. if key == :ex_syslogger,
  104. do: {ExSyslogger, :ex_syslogger},
  105. else: key
  106. Logger.configure_backend(backend, merged)
  107. :ok = update_env(:logger, key, merged)
  108. end
  109. defp configure({_, key, _, merged}) do
  110. Logger.configure([{key, merged}])
  111. :ok = update_env(:logger, key, merged)
  112. end
  113. defp update({group, key, value, merged}) do
  114. try do
  115. :ok = update_env(group, key, merged)
  116. if group != :pleroma or pleroma_need_restart?(group, key, value), do: group
  117. rescue
  118. error ->
  119. error_msg =
  120. "updating env causes error, group: #{inspect(group)}, key: #{inspect(key)}, value: #{
  121. inspect(value)
  122. } error: #{inspect(error)}"
  123. Logger.warn(error_msg)
  124. nil
  125. end
  126. end
  127. defp update_env(group, key, nil), do: Application.delete_env(group, key)
  128. defp update_env(group, key, value), do: Application.put_env(group, key, value)
  129. @spec pleroma_need_restart?(atom(), atom(), any()) :: boolean()
  130. def pleroma_need_restart?(group, key, value) do
  131. group_and_key_need_reboot?(group, key) or group_and_subkey_need_reboot?(group, key, value)
  132. end
  133. defp group_and_key_need_reboot?(group, key) do
  134. Enum.any?(@reboot_time_keys, fn {g, k} -> g == group and k == key end)
  135. end
  136. defp group_and_subkey_need_reboot?(group, key, value) do
  137. Keyword.keyword?(value) and
  138. Enum.any?(@reboot_time_subkeys, fn {g, k, subkeys} ->
  139. g == group and k == key and
  140. Enum.any?(Keyword.keys(value), &(&1 in subkeys))
  141. end)
  142. end
  143. defp restart(_, :pleroma, env), do: Restarter.Pleroma.restart_after_boot(env)
  144. defp restart(started_applications, app, _) do
  145. with {^app, _, _} <- List.keyfind(started_applications, app, 0),
  146. :ok <- Application.stop(app) do
  147. :ok = Application.start(app)
  148. else
  149. nil ->
  150. Logger.warn("#{app} is not started.")
  151. error ->
  152. error
  153. |> inspect()
  154. |> Logger.warn()
  155. end
  156. end
  157. defp can_be_merged?(val1, val2) when is_list(val1) and is_list(val2) do
  158. Keyword.keyword?(val1) and Keyword.keyword?(val2)
  159. end
  160. defp can_be_merged?(_val1, _val2), do: false
  161. end