Skip to content

Commit

Permalink
fix: move environment variables extraction to supervisor
Browse files Browse the repository at this point in the history
This will make connection variables persistent between process restarts.
  • Loading branch information
hauleth committed Jan 16, 2020
1 parent 434c42a commit d889d67
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 75 deletions.
40 changes: 7 additions & 33 deletions src/systemd_socket.erl
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@
-behaviour(gen_server).

-define(NAME, ?MODULE).
-define(NOTIFY_SOCKET, "NOTIFY_SOCKET").

-include_lib("kernel/include/logger.hrl").
-include_lib("kernel/include/file.hrl").

-export([send/1]).

-export([start_link/0,
-export([start_link/1,
init/1,
handle_call/3,
handle_cast/2,
Expand All @@ -25,30 +23,13 @@ send(Message) ->

% # Behaviour implementation

start_link() ->
gen_server:start_link({local, ?NAME}, ?MODULE, [], []).
start_link(Address) ->
gen_server:start_link({local, ?NAME}, ?MODULE, Address, []).

init(_Arg) ->
State = case has_env(?NOTIFY_SOCKET) of
false ->
[];
[$@ | AbstractPath] ->
Address = {local, [0 | AbstractPath]},
{ok, Socket} = gen_udp:open(0, [local]),
{Socket, Address};
Path ->
case file:read_file_info(Path) of
{error, _Error} ->
[];
{ok, #file_info{access=Access}}
when Access =:= write; Access =:= read_write ->
Address = {local, Path},
{ok, Socket} = gen_udp:open(0, [local]),
{Socket, Address}
end
end,
os:unsetenv(?NOTIFY_SOCKET),
{ok, State}.
init([]) -> {ok, []};
init(Address) ->
{ok, Socket} = gen_udp:open(0, [local]),
{ok, {Socket, Address}}.

handle_call({send, Message}, _Ref, {Socket, Address}=State) ->
ok = gen_udp:send(Socket, Address, 0, [Message, $\n]),
Expand All @@ -61,10 +42,3 @@ handle_cast(_Msg, State) ->

handle_info(_Msg, State) ->
{noreply, State}.

has_env(Name) ->
case os:getenv(Name) of
false -> false;
"" -> false;
Value -> Value
end.
64 changes: 60 additions & 4 deletions src/systemd_sup.erl
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,74 @@

-export([start_link/1, init/1]).

-define(PID, "WATCHDOG_PID").
-define(TIMEOUT, "WATCHDOG_USEC").
-define(NOTIFY_SOCKET, "NOTIFY_SOCKET").

-include_lib("kernel/include/file.hrl").

start_link(Opts) ->
supervisor:start_link(?MODULE, Opts).

init(_Opts) ->
SupFlags = #{
strategy => one_for_one
},
Pid = os:getpid(),

SocketServer = #{id => socket,
start => {systemd_socket, start_link, []}
start => {systemd_socket, start_link, [notify_socket()]}
},
Watchdog = #{id => watchdog,
start => {systemd_watchdog, start_link, []}
},
Watchdog = case {watchdog_pid(), watchdog_timeout()} of
{Pid, TimeoutUS} when TimeoutUS > 0 ->
Timeout = erlang:convert_time_unit(TimeoutUS,
microsecond,
millisecond),
#{id => watchdog,
start => {systemd_watchdog, start_link, [Timeout]}
};
_ ->
#{id => watchdog,
start => {systemd_watchdog, start_link, [infinity]}
}
end,

{ok, {SupFlags, [SocketServer, Watchdog]}}.

watchdog_pid() ->
Return = case os:getenv(?PID) of
false -> os:getpid();
Env -> Env
end,
os:unsetenv(?PID),
Return.

watchdog_timeout() ->
Return = case os:getenv(?TIMEOUT) of
false -> -1;
Env ->
case string:to_integer(Env) of
{Timeout, ""} -> Timeout;
_ -> -1
end
end,
os:unsetenv(?TIMEOUT),
Return.

notify_socket() ->
State = case os:getenv(?NOTIFY_SOCKET) of
false ->
[];
[$@ | AbstractPath] ->
{local, [0 | AbstractPath]};
Path ->
case file:read_file_info(Path) of
{error, _Error} ->
[];
{ok, #file_info{access=Access}}
when Access =:= write; Access =:= read_write ->
{local, Path}
end
end,
os:unsetenv(?NOTIFY_SOCKET),
State.
38 changes: 3 additions & 35 deletions src/systemd_watchdog.erl
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,16 @@
-include_lib("kernel/include/logger.hrl").
-include("systemd.hrl").

-define(PID, "WATCHDOG_PID").
-define(TIMEOUT, "WATCHDOG_USEC").

-export([start_link/0,
-export([start_link/1,
init/1,
handle_call/3,
handle_cast/2,
handle_info/2]).

-record(state, {timeout, enabled=true}).

start_link() ->
Pid = os:getpid(),
case {watchdog_pid(), watchdog_timeout()} of
{Pid, TimeoutUS} when TimeoutUS > 0 ->
Timeout = erlang:convert_time_unit(TimeoutUS,
microsecond,
millisecond),
gen_server:start_link({local, ?WATCHDOG}, ?MODULE, Timeout, []);
_ ->
gen_server:start_link({local, ?WATCHDOG}, ?MODULE, infinity, [])
end.
start_link(Timeout) ->
gen_server:start_link({local, ?WATCHDOG}, ?MODULE, Timeout, []).

init(Timeout) ->
State = #state{timeout=Timeout},
Expand Down Expand Up @@ -70,23 +58,3 @@ notify(#state{enabled=true, timeout=Timeout}) when is_integer(Timeout) andalso T
erlang:send_after(Timeout div Scale, self(), keepalive);
notify(_State) ->
ok.

watchdog_pid() ->
Return = case os:getenv(?PID) of
false -> os:getpid();
Env -> Env
end,
os:unsetenv(?PID),
Return.

watchdog_timeout() ->
Return = case os:getenv(?TIMEOUT) of
false -> -1;
Env ->
case string:to_integer(Env) of
{Timeout, ""} -> Timeout;
_ -> -1
end
end,
os:unsetenv(?TIMEOUT),
Return.
27 changes: 24 additions & 3 deletions test/systemd_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ notify(init, Config) ->
notify(_, Config) -> Config.

notify(Config) ->
Pid = ?config(mock_pid, Config),

systemd:notify(ready),
systemd:notify(stopping),
systemd:notify(reloading),
Expand All @@ -46,16 +48,21 @@ notify(Config) ->

ct:sleep(10),

Messages = mock_systemd:messages(?config(mock_pid, Config)),

?assertEqual(["READY=1\n",
"STOPPING=1\n",
"RELOADING=1\n",
"STATUS=example status\n",
"ERRNO=10\n",
"BUSERROR=test.example.bus.service.Error\n",
"CUSTOM=message\n",
"FORMATTED=deadbeef\n"], Messages),
"FORMATTED=deadbeef\n"], mock_systemd:messages(Pid)),

ct:log("Connection address persists between process restarts"),
gen_server:stop(systemd_socket, error, 100),
ct:sleep(10),
systemd:notify(ready),
ct:sleep(10),
?assertEqual(["READY=1\n"], mock_systemd:messages(Pid)),
ok.

watchdog(init, Config) -> Config;
Expand Down Expand Up @@ -179,6 +186,20 @@ watchdog(Config) ->

ok = stop(Config),

% -------------------------------------------------------------------------
ct:log("Watchdog process send messages after restart"),
os:putenv("WATCHDOG_PID", os:getpid()),
os:putenv("WATCHDOG_USEC", TimeoutList),
ok = start_with_socket(Socket),
ct:sleep(10),

?assertEqual(["WATCHDOG=1\n"], mock_systemd:messages(Pid)),
gen_server:stop(systemd_watchdog, error, 100),
ct:sleep(10),
?assertEqual(["WATCHDOG=1\n"], mock_systemd:messages(Pid)),

ok = stop(Config),

ok.

listen_fds(init, Config) -> Config;
Expand Down

0 comments on commit d889d67

Please sign in to comment.