dotfiles/app/lib/prymn/agents/health.ex
2024-02-01 17:34:26 +02:00

108 lines
2.8 KiB
Elixir

defmodule Prymn.Agents.Health do
@moduledoc """
The Health struct keeps simple health information of whether or not the
target host machine is up to date, has any tasks running, its resources are
getting depleted, or if it's unable be reached.
"""
defstruct [:host, :version, :status, tasks: [], message: "Unknown"]
alias PrymnProto.Prymn.HealthResponse
@type t :: %{
host: String.t(),
version: String.t(),
status: atom(),
message: String.t()
}
def start() do
:ets.new(__MODULE__, [:set, :public, :named_table, read_concurrency: true])
end
def subscribe(host) do
Phoenix.PubSub.subscribe(Prymn.PubSub, "health:#{host}")
end
def broadcast!(%__MODULE__{host: host} = health) do
Phoenix.PubSub.broadcast!(Prymn.PubSub, "health:#{host}", health)
end
def update_and_broadcast(nil) do
nil
end
def update_and_broadcast(%__MODULE__{host: host} = health) do
:ets.insert(__MODULE__, {host, health})
broadcast!(health)
end
def delete(host_address) do
:ets.delete(__MODULE__, host_address)
end
def lookup(host_address, opts \\ []) do
default = Keyword.get(opts, :default, false)
case :ets.lookup(__MODULE__, host_address) do
[{^host_address, value}] -> value
[] when default -> %__MODULE__{host: host_address}
[] -> nil
end
end
def new(agent_id, %{"cpu_status" => cpu, "memory_status" => memory, "disk_status" => disk}) do
%__MODULE__{host: agent_id, version: "0.1.0"}
|> do_cpu(cpu)
|> do_memory(memory)
|> do_disks(disk)
end
defp do_cpu(health, cpu) do
%__MODULE__{health | message: "Connected", status: :connected}
end
defp do_memory(health, memory) do
health
end
defp do_disks(health, disks) do
health
end
def make_timed_out(%__MODULE__{} = health) do
%__MODULE__{health | status: :unreachable, message: "Connect timed out"}
end
def make_disconnected(%__MODULE__{} = health) do
%__MODULE__{health | status: :disconnected, message: "Disconnected"}
end
def make_from_proto(%HealthResponse{system: system, version: version, tasks: tasks}, host) do
%__MODULE__{host: host, status: :connected}
|> do_version(version)
|> do_system(system)
|> do_tasks(tasks)
end
defp do_version(health, version) do
%__MODULE__{health | version: version}
end
defp do_system(health, system) do
case system.status do
"normal" -> %__MODULE__{health | message: "Connected"}
status -> %__MODULE__{health | message: "Alert: #{status}"}
end
end
defp do_tasks(health, tasks) do
tasks =
Enum.map(tasks, fn {task_key, task_value} ->
progress = Float.round(task_value.progress, 2)
{task_key, %{task_value | progress: "#{progress}%"}}
end)
%__MODULE__{health | tasks: tasks}
end
end