Add helpers for configuration reload

parent 438c770c
......@@ -20,10 +20,10 @@ test:
$(REBAR3) cover -v
config/prod-sys.config: config/sys.config.example
[ -f $@ ] && diff $^ $@ || true
[ -f $@ ] && diff -u $@ $^ || true
cp -i -b $^ $@
config/prod-vm.args: config/vm.args.example
[ -f $@ ] && diff $^ $@ || true
[ -f $@ ] && diff -u $@ $^ || true
cp -i -b $^ $@
@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}/ $@
......@@ -48,6 +48,11 @@ install: user $(LOGDIR)
fi
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:
# TODO: ensure service is stopped
rm $(SERVICE)
......
......@@ -22,7 +22,7 @@ Features
* 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)
* 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
* 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
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.
How to start - docker
How to start - Docker
---------------------
### To run with default settings
......@@ -213,16 +213,20 @@ Default port is 1443 and default secret is `d0d6e111bada5511fcce9584deadbeef`.
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
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
To change default settings, change `mtproto_proxy` section of `prod-sys.config` as:
......
......@@ -24,6 +24,7 @@ LimitNOFILE=40960
AmbientCapabilities=CAP_NET_BIND_SERVICE
ExecStart=/opt/mtp_proxy/bin/mtp_proxy foreground
ExecStop=/opt/mtp_proxy/bin/mtp_proxy stop
ExecReload=/opt/mtp_proxy/bin/mtp_proxy rpcterms mtproto_proxy_app reload_config
TimeoutStopSec=15s
[Install]
......
......@@ -9,7 +9,13 @@
%% Application callbacks
-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).
......@@ -22,7 +28,7 @@
listen_ip => string()}.
%%====================================================================
%% API
%% Application behaviour API
%%====================================================================
start(_StartType, _StartArgs) ->
Res = {ok, _} = mtproto_proxy_sup:start_link(),
......@@ -49,6 +55,41 @@ config_change(Changed, New, Removed) ->
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
-spec mtp_listeners() -> [tuple()].
......@@ -200,3 +241,21 @@ report(Fmt, Args) ->
io:format(Fmt ++ "\n", Args),
?log(info, Fmt, Args).
-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