ha-handler/lib/ha_handler/drbd/watcher.ex

74 lines
1.9 KiB
Elixir

defmodule HAHandler.DRBD.Watcher do
# TODO: add support for SSH public keys authentication.
use GenServer
require Logger
def start_link(opts) do
GenServer.start_link(__MODULE__, opts)
end
defp connect(hostname, password) do
case :inet.gethostbyname(to_charlist(hostname), :inet6) do
{:ok, {:hostent, _name, _aliases, _addrtype, _length, [addr]}} ->
SSHEx.connect(
ip: addr,
user: 'root',
password: password,
silently_accept_hosts: true
)
err ->
err
end
end
@impl true
def init(opts) do
state = %{
backend: nil,
last_reconnect: nil,
hostname: Keyword.get(opts, :hostname),
password: Keyword.get(opts, :password),
}
# This action will be processed once the GenServer is fully
# started/operational. This process handle connection failures by itself,
# as we don't want to crash loop into supervisor logic (which is only there
# to handle unexpected failure).
send self(), :reconnect
{:ok, state}
end
@impl true
def handle_info(:reconnect, state = %{hostname: hostname, password: password}) do
case connect(hostname, password) do
{:ok, pid} ->
{:noreply, %{state | backend: pid}}
{:error, err} ->
# Nothing to do, as the next request will trigger the reconnect logic
# (see :execute call).
{:noreply, state}
end
end
@impl true
def handle_call({:execute, cmd}, _from, %{backend: backend} = state) do
case SSHEx.run(backend, cmd) do
{:ok, _output, _status} = reply->
{:reply, reply, state}
{:error, :closed} = reply ->
# Asynchroneously tries to reopen the connection to the backend.
send self(), :reconnect
{:reply, reply, state}
{:error, _err} = reply ->
# Do not take action on unknown error.
{:reply, reply, state}
end
end
end