Add helpers for configuration reload

parent 438c770c
...@@ -20,10 +20,10 @@ test: ...@@ -20,10 +20,10 @@ test:
$(REBAR3) cover -v $(REBAR3) cover -v
config/prod-sys.config: config/sys.config.example config/prod-sys.config: config/sys.config.example
[ -f $@ ] && diff $^ $@ || true [ -f $@ ] && diff -u $@ $^ || true
cp -i -b $^ $@ cp -i -b $^ $@
config/prod-vm.args: config/vm.args.example config/prod-vm.args: config/vm.args.example
[ -f $@ ] && diff $^ $@ || true [ -f $@ ] && diff -u $@ $^ || true
cp -i -b $^ $@ cp -i -b $^ $@
@IP=$(shell curl -s -4 -m 10 http://ip.seriyps.ru || curl -s -4 -m 10 https://digitalresistance.dog/myIp) \ @IP=$(shell curl -s -4 -m 10 http://ip.seriyps.ru || curl -s -4 -m 10 https://digitalresistance.dog/myIp) \
&& sed -i s/@0\.0\.0\.0/@$${IP}/ $@ && sed -i s/@0\.0\.0\.0/@$${IP}/ $@
...@@ -48,6 +48,11 @@ install: user $(LOGDIR) ...@@ -48,6 +48,11 @@ install: user $(LOGDIR)
fi fi
systemctl daemon-reload systemctl daemon-reload
.PHONY: update-sysconfig
update-sysconfig: config/prod-sys.config $(prefix)/mtp_proxy
REL_VSN=$(shell awk '{print $$2}' $(prefix)/mtp_proxy/releases/start_erl.data) && \
install -m 644 config/prod-sys.config "$(prefix)/mtp_proxy/releases/$${REL_VSN}/sys.config"
uninstall: uninstall:
# TODO: ensure service is stopped # TODO: ensure service is stopped
rm $(SERVICE) rm $(SERVICE)
......
...@@ -22,7 +22,7 @@ Features ...@@ -22,7 +22,7 @@ Features
* Protection from [replay attacks](https://habr.com/ru/post/452144/) used to detect proxies in some countries * Protection from [replay attacks](https://habr.com/ru/post/452144/) used to detect proxies in some countries
* Automatic telegram configuration reload (no need for restarts once per day) * Automatic telegram configuration reload (no need for restarts once per day)
* IPv6 for client connections * IPv6 for client connections
* Most of the configuration options can be updated without service restart * All configuration options can be updated without service restart
* Small codebase compared to official one, code is covered by automated tests * Small codebase compared to official one, code is covered by automated tests
* A lots of metrics could be exported (optional) * A lots of metrics could be exported (optional)
...@@ -46,7 +46,7 @@ curl -L -o mtp_install.sh https://git.io/fj5ru && bash mtp_install.sh -p 443 -s ...@@ -46,7 +46,7 @@ curl -L -o mtp_install.sh https://git.io/fj5ru && bash mtp_install.sh -p 443 -s
It does the same as described in [How to start OS-install - detailed](#how-to-start-os-install---detailed), but It does the same as described in [How to start OS-install - detailed](#how-to-start-os-install---detailed), but
generates config-file for you automatically. generates config-file for you automatically.
How to start - docker How to start - Docker
--------------------- ---------------------
### To run with default settings ### To run with default settings
...@@ -213,16 +213,20 @@ Default port is 1443 and default secret is `d0d6e111bada5511fcce9584deadbeef`. ...@@ -213,16 +213,20 @@ Default port is 1443 and default secret is `d0d6e111bada5511fcce9584deadbeef`.
Secret key and proxy URLs will be printed on start. Secret key and proxy URLs will be printed on start.
The easiest way to update config right now is to edit `config/prod-sys.config`
and then re-install proxy by ### Apply config changes without restart
It's possible to reload config file without service restart (but if you want to update
ad_tag on existing port, all clients of this port will be disconnected).
This method doesn't work for Docker!
To do that, make changes in `config/prod-sys.config` and run following command:
```bash ```bash
sudo make uninstall && make && sudo make install sudo make update-sysconfig && sudo systemctl reload mtproto-proxy
``` ```
There are other ways as well. It's even possible to update configuration options
without service restart / without downtime, but it's a bit trickier.
### Change default port / secret / ad tag ### Change default port / secret / ad tag
To change default settings, change `mtproto_proxy` section of `prod-sys.config` as: To change default settings, change `mtproto_proxy` section of `prod-sys.config` as:
......
...@@ -24,6 +24,7 @@ LimitNOFILE=40960 ...@@ -24,6 +24,7 @@ LimitNOFILE=40960
AmbientCapabilities=CAP_NET_BIND_SERVICE AmbientCapabilities=CAP_NET_BIND_SERVICE
ExecStart=/opt/mtp_proxy/bin/mtp_proxy foreground ExecStart=/opt/mtp_proxy/bin/mtp_proxy foreground
ExecStop=/opt/mtp_proxy/bin/mtp_proxy stop ExecStop=/opt/mtp_proxy/bin/mtp_proxy stop
ExecReload=/opt/mtp_proxy/bin/mtp_proxy rpcterms mtproto_proxy_app reload_config
TimeoutStopSec=15s TimeoutStopSec=15s
[Install] [Install]
......
...@@ -9,7 +9,13 @@ ...@@ -9,7 +9,13 @@
%% Application callbacks %% Application callbacks
-export([start/2, prep_stop/1, stop/1, config_change/3]). -export([start/2, prep_stop/1, stop/1, config_change/3]).
-export([mtp_listeners/0, running_ports/0, start_proxy/1, build_urls/4, get_port_secret/1]). %% Helpers
-export([mtp_listeners/0,
reload_config/0,
running_ports/0,
start_proxy/1,
build_urls/4,
get_port_secret/1]).
-define(APP, mtproto_proxy). -define(APP, mtproto_proxy).
...@@ -22,7 +28,7 @@ ...@@ -22,7 +28,7 @@
listen_ip => string()}. listen_ip => string()}.
%%==================================================================== %%====================================================================
%% API %% Application behaviour API
%%==================================================================== %%====================================================================
start(_StartType, _StartArgs) -> start(_StartType, _StartArgs) ->
Res = {ok, _} = mtproto_proxy_sup:start_link(), Res = {ok, _} = mtproto_proxy_sup:start_link(),
...@@ -49,6 +55,41 @@ config_change(Changed, New, Removed) -> ...@@ -49,6 +55,41 @@ config_change(Changed, New, Removed) ->
ok = lists:foreach(fun({K, V}) -> config_changed(new, K, V) end, New). ok = lists:foreach(fun({K, V}) -> config_changed(new, K, V) end, New).
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% Other APIs
%% XXX: this is ad-hoc helper function; it is simplified version of code from OTP application_controller.erl
reload_config() ->
PreEnv = application:get_all_env(?APP),
NewConfig = read_sys_config(),
[application:set_env(?APP, K, V) || {K, V} <- NewConfig],
NewEnv = application:get_all_env(?APP),
%% TODO: "Removed" will always be empty; to handle it properly we should merge env
%% from .app file with NewConfig
{Changed, New, Removed} = diff_env(NewEnv, PreEnv),
?log(info, "Updating config; changed=~p, new=~p, deleted=~p", [Changed, New, Removed]),
config_change(Changed, New, Removed).
read_sys_config() ->
{ok, [[File]]} = init:get_argument(config),
{ok, [Data]} = file:consult(File),
proplists:get_value(?APP, Data, []).
diff_env(NewEnv, OldEnv) ->
NewEnvMap = maps:from_list(NewEnv),
OldEnvMap = maps:from_list(OldEnv),
NewKeySet = ordsets:from_list(maps:keys(NewEnvMap)),
OldKeySet = ordsets:from_list(maps:keys(OldEnvMap)),
DelKeys = ordsets:subtract(OldKeySet, NewKeySet),
AddKeys = ordsets:subtract(NewKeySet, OldKeySet),
ChangedKeys =
lists:filter(
fun(K) ->
maps:get(K, NewEnvMap) =/= maps:get(K, OldEnvMap)
end, ordsets:intersection(OldKeySet, NewKeySet)),
{[{K, maps:get(K, NewEnvMap)} || K <- ChangedKeys],
[{K, maps:get(K, NewEnvMap)} || K <- AddKeys],
DelKeys}.
%% @doc List of ranch listeners running mtproto_proxy %% @doc List of ranch listeners running mtproto_proxy
-spec mtp_listeners() -> [tuple()]. -spec mtp_listeners() -> [tuple()].
...@@ -200,3 +241,21 @@ report(Fmt, Args) -> ...@@ -200,3 +241,21 @@ report(Fmt, Args) ->
io:format(Fmt ++ "\n", Args), io:format(Fmt ++ "\n", Args),
?log(info, Fmt, Args). ?log(info, Fmt, Args).
-endif. -endif.
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
env_diff_test() ->
Pre = [{a, 1},
{b, 2},
{c, 3}],
Post = [{b, 2},
{c, 4},
{d, 5}],
?assertEqual(
{[{c, 4}],
[{d, 5}],
[a]},
diff_env(Post, Pre)).
-endif.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment