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