X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fconfig%2Ftransfer_task.ex;h=a0d7b7d71b7952f7fadfc8f2b7c799f7bbea9394;hb=bc3db724030707e9903d161a70b10fe217a83212;hp=00c8790f868516083b9437b378801bfcf578c691;hpb=32a643a159df2b2af4263ebfb7f7c9fd245d3a6a;p=akkoma diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index 00c8790f8..a0d7b7d71 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -1,79 +1,184 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors +# Copyright © 2017-2020 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Config.TransferTask do use Task + alias Pleroma.Config alias Pleroma.ConfigDB alias Pleroma.Repo require Logger - def start_link(_) do - load_and_update_env() - if Pleroma.Config.get(:env) == :test, do: Ecto.Adapters.SQL.Sandbox.checkin(Repo) + @type env() :: :test | :benchmark | :dev | :prod + + @reboot_time_keys [ + {:pleroma, :hackney_pools}, + {:pleroma, :chat}, + {:pleroma, Oban}, + {:pleroma, :rate_limit}, + {:pleroma, :markup}, + {:pleroma, :streamer}, + {:pleroma, :pools}, + {:pleroma, :connections_pool} + ] + + @reboot_time_subkeys [ + {:pleroma, Pleroma.Captcha, [:seconds_valid]}, + {:pleroma, Pleroma.Upload, [:proxy_remote]}, + {:pleroma, :instance, [:upload_limit]}, + {:pleroma, :gopher, [:enabled]} + ] + + def start_link(restart_pleroma? \\ true) do + load_and_update_env([], restart_pleroma?) + if Config.get(:env) == :test, do: Ecto.Adapters.SQL.Sandbox.checkin(Repo) :ignore end - def load_and_update_env do - with true <- Pleroma.Config.get(:configurable_from_database), - true <- Ecto.Adapters.SQL.table_exists?(Repo, "config"), - started_applications <- Application.started_applications() do + @spec load_and_update_env([ConfigDB.t()], boolean()) :: :ok + def load_and_update_env(deleted_settings \\ [], restart_pleroma? \\ true) do + with {_, true} <- {:configurable, Config.get(:configurable_from_database)} do # We need to restart applications for loaded settings take effect - ConfigDB - |> Repo.all() - |> Enum.map(&update_env(&1)) - |> Enum.uniq() + + {logger, other} = + (Repo.all(ConfigDB) ++ deleted_settings) + |> Enum.map(&merge_with_default/1) + |> Enum.split_with(fn {group, _, _, _} -> group in [:logger, :quack] end) + + logger + |> Enum.sort() + |> Enum.each(&configure/1) + + started_applications = Application.started_applications() + # TODO: some problem with prometheus after restart! - |> Enum.reject(&(&1 in [:pleroma, nil, :prometheus])) - |> Enum.each(&restart(started_applications, &1)) + reject = [nil, :prometheus, :postgrex] + + reject = + if restart_pleroma? do + reject + else + [:pleroma | reject] + end + + other + |> Enum.map(&update/1) + |> Enum.uniq() + |> Enum.reject(&(&1 in reject)) + |> maybe_set_pleroma_last() + |> Enum.each(&restart(started_applications, &1, Config.get(:env))) + + :ok + else + {:configurable, false} -> Restarter.Pleroma.rebooted() end end - defp update_env(setting) do - try do - key = ConfigDB.from_string(setting.key) - group = ConfigDB.from_string(setting.group) - value = ConfigDB.from_binary(setting.value) + defp maybe_set_pleroma_last(apps) do + # to be ensured that pleroma will be restarted last + if :pleroma in apps do + apps + |> List.delete(:pleroma) + |> List.insert_at(-1, :pleroma) + else + Restarter.Pleroma.rebooted() + apps + end + end - default = Pleroma.Config.Holder.config(group, key) + defp merge_with_default(%{group: group, key: key, value: value} = setting) do + default = Config.Holder.default_config(group, key) - merged_value = - if can_be_merged?(default, value) do - ConfigDB.merge_group(group, key, default, value) - else - value - end + merged = + cond do + Ecto.get_meta(setting, :state) == :deleted -> default + can_be_merged?(default, value) -> ConfigDB.merge_group(group, key, default, value) + true -> value + end - :ok = Application.put_env(group, key, merged_value) + {group, key, value, merged} + end - if group != :logger do - group - else - # change logger configuration in runtime, without restart - if Keyword.keyword?(merged_value) and - key not in [:compile_time_application, :backends, :compile_time_purge_matching] do - Logger.configure_backend(key, merged_value) - else - Logger.configure([{key, merged_value}]) - end + # change logger configuration in runtime, without restart + defp configure({:quack, key, _, merged}) do + Logger.configure_backend(Quack.Logger, [{key, merged}]) + :ok = update_env(:quack, key, merged) + end - nil + defp configure({_, :backends, _, merged}) do + # removing current backends + Enum.each(Application.get_env(:logger, :backends), &Logger.remove_backend/1) + + Enum.each(merged, &Logger.add_backend/1) + + :ok = update_env(:logger, :backends, merged) + end + + defp configure({_, key, _, merged}) when key in [:console, :ex_syslogger] do + merged = + if key == :console do + put_in(merged[:format], merged[:format] <> "\n") + else + merged end + + backend = + if key == :ex_syslogger, + do: {ExSyslogger, :ex_syslogger}, + else: key + + Logger.configure_backend(backend, merged) + :ok = update_env(:logger, key, merged) + end + + defp configure({_, key, _, merged}) do + Logger.configure([{key, merged}]) + :ok = update_env(:logger, key, merged) + end + + defp update({group, key, value, merged}) do + try do + :ok = update_env(group, key, merged) + + if group != :pleroma or pleroma_need_restart?(group, key, value), do: group rescue - e -> - Logger.warn( - "updating env causes error, group: #{inspect(setting.group)}, key: #{ - inspect(setting.key) - }, value: #{inspect(ConfigDB.from_binary(setting.value))}, error: #{inspect(e)}" - ) + error -> + error_msg = + "updating env causes error, group: #{inspect(group)}, key: #{inspect(key)}, value: #{ + inspect(value) + } error: #{inspect(error)}" + + Logger.warn(error_msg) nil end end - defp restart(started_applications, app) do + defp update_env(group, key, nil), do: Application.delete_env(group, key) + defp update_env(group, key, value), do: Application.put_env(group, key, value) + + @spec pleroma_need_restart?(atom(), atom(), any()) :: boolean() + def pleroma_need_restart?(group, key, value) do + group_and_key_need_reboot?(group, key) or group_and_subkey_need_reboot?(group, key, value) + end + + defp group_and_key_need_reboot?(group, key) do + Enum.any?(@reboot_time_keys, fn {g, k} -> g == group and k == key end) + end + + defp group_and_subkey_need_reboot?(group, key, value) do + Keyword.keyword?(value) and + Enum.any?(@reboot_time_subkeys, fn {g, k, subkeys} -> + g == group and k == key and + Enum.any?(Keyword.keys(value), &(&1 in subkeys)) + end) + end + + defp restart(_, :pleroma, env), do: Restarter.Pleroma.restart_after_boot(env) + + defp restart(started_applications, app, _) do with {^app, _, _} <- List.keyfind(started_applications, app, 0), :ok <- Application.stop(app) do :ok = Application.start(app)