2023-06-09 19:13:27 +00:00
|
|
|
defmodule PrymnWeb.ServerLive.Show do
|
|
|
|
use PrymnWeb, :live_view
|
|
|
|
|
2023-11-14 15:23:50 +00:00
|
|
|
require Logger
|
2023-08-25 21:51:04 +00:00
|
|
|
alias Prymn.{Agents, Servers}
|
2023-06-09 19:13:27 +00:00
|
|
|
|
|
|
|
@impl true
|
|
|
|
def mount(_params, _session, socket) do
|
|
|
|
{:ok, socket}
|
|
|
|
end
|
|
|
|
|
|
|
|
@impl true
|
|
|
|
def handle_params(%{"id" => id}, _, socket) do
|
|
|
|
server = Servers.get_server!(id)
|
2023-08-25 21:51:04 +00:00
|
|
|
|
2023-08-28 20:32:42 +00:00
|
|
|
if connected?(socket) and server.status == :registered do
|
|
|
|
Agents.subscribe_to_health(server.public_ip)
|
|
|
|
Agents.start_connection(server.public_ip)
|
2023-11-14 15:23:50 +00:00
|
|
|
send(self(), :get_sys_info)
|
2023-08-25 21:51:04 +00:00
|
|
|
end
|
2023-06-09 19:13:27 +00:00
|
|
|
|
2023-08-28 20:32:42 +00:00
|
|
|
health = Agents.get_health(server.public_ip)
|
|
|
|
|
2023-06-09 19:13:27 +00:00
|
|
|
{:noreply,
|
|
|
|
socket
|
2023-11-16 21:45:36 +00:00
|
|
|
|> assign(:health, health || %{message: "Connecting...", tasks: []})
|
2023-06-09 19:13:27 +00:00
|
|
|
|> assign(:page_title, server.name)
|
2023-07-09 16:41:41 +00:00
|
|
|
|> assign(:server, server)
|
2023-11-14 15:23:50 +00:00
|
|
|
|> assign(:dry_run, false)
|
|
|
|
|> assign(:update_output, [])
|
|
|
|
|> assign(:sys_info, nil)
|
|
|
|
# TODO: Do not assign this to the socket - instead generate it in the HTML
|
2023-07-09 16:41:41 +00:00
|
|
|
|> assign(:registration_command, Servers.create_setup_command(server))}
|
2023-06-09 19:13:27 +00:00
|
|
|
end
|
2023-08-25 21:51:04 +00:00
|
|
|
|
|
|
|
@impl true
|
2023-11-14 15:23:50 +00:00
|
|
|
def handle_info(:get_sys_info, socket) do
|
|
|
|
status = get_in(socket.assigns, [:health, Access.key(:status)])
|
|
|
|
host_address = get_in(socket.assigns, [:server, Access.key(:public_ip)])
|
|
|
|
pid = self()
|
|
|
|
|
|
|
|
if host_address != nil and status == :connected do
|
|
|
|
Task.start_link(fn ->
|
|
|
|
{:ok, sys_info} = Agents.get_sys_info(host_address)
|
|
|
|
send(pid, sys_info)
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
# 10 seconds is >5 which is gun's timeout duration (which might have a race
|
|
|
|
# condition if they are equal)
|
|
|
|
Process.send_after(self(), :get_sys_info, :timer.seconds(10))
|
|
|
|
|
|
|
|
{:noreply, socket}
|
|
|
|
end
|
|
|
|
|
2023-08-25 21:51:04 +00:00
|
|
|
def handle_info(%PrymnProto.Prymn.SysInfoResponse{} = response, socket) do
|
2023-11-14 15:23:50 +00:00
|
|
|
# TODO: GRPC calls should be done through wrapper functions. Necessary
|
|
|
|
# calculations should be done then and there.
|
2023-08-25 21:51:04 +00:00
|
|
|
{:noreply,
|
|
|
|
socket
|
2023-11-14 15:23:50 +00:00
|
|
|
|> assign(:sys_info, response)
|
|
|
|
|> assign(:updates_available, response.updates_available)
|
2023-08-25 21:51:04 +00:00
|
|
|
|> assign(:cpus, response.cpus)}
|
|
|
|
end
|
|
|
|
|
2023-11-14 15:23:50 +00:00
|
|
|
def handle_info(%PrymnProto.Prymn.SysUpdateResponse{} = response, socket) do
|
|
|
|
output = String.split(response.output, "\n")
|
|
|
|
socket = assign(socket, :update_output, output)
|
|
|
|
{:noreply, socket}
|
|
|
|
end
|
|
|
|
|
2023-08-28 20:32:42 +00:00
|
|
|
def handle_info(%Agents.Health{} = health, socket) do
|
|
|
|
{:noreply, assign(socket, :health, health)}
|
|
|
|
end
|
|
|
|
|
2023-11-14 15:23:50 +00:00
|
|
|
@impl true
|
|
|
|
def handle_event("system_update", _params, socket) do
|
|
|
|
host_address = get_in(socket.assigns, [:server, Access.key(:public_ip)])
|
|
|
|
server_name = get_in(socket.assigns, [:server, Access.key(:name)])
|
|
|
|
|
|
|
|
socket =
|
|
|
|
if host_address do
|
|
|
|
Agents.sys_update(host_address, socket.assigns.dry_run)
|
|
|
|
put_flash(socket, :info, "Started a system update on server #{server_name}.")
|
|
|
|
else
|
|
|
|
put_flash(
|
|
|
|
socket,
|
|
|
|
:error,
|
|
|
|
"Could not perform the update. Your server does not seem to have an address"
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
{:noreply, socket}
|
|
|
|
end
|
|
|
|
|
|
|
|
def handle_event("change_dry_run", %{"dry_run" => enabled}, socket) do
|
|
|
|
enabled = (enabled == "true" && true) || false
|
|
|
|
{:noreply, assign(socket, :dry_run, enabled)}
|
|
|
|
end
|
|
|
|
|
|
|
|
defp calculate_cpu_usage(cpus) do
|
|
|
|
(Enum.reduce(cpus, 0, fn x, acc -> x.usage + acc end) / Enum.count(cpus))
|
|
|
|
|> Float.round(2)
|
|
|
|
end
|
|
|
|
|
2023-08-25 21:51:04 +00:00
|
|
|
defp bytes_to_gigabytes(bytes) do
|
|
|
|
Float.round(bytes / Integer.pow(1024, 3), 2)
|
|
|
|
end
|
|
|
|
|
2023-08-28 20:32:42 +00:00
|
|
|
defp calculate_disk_used_percent(disks) do
|
|
|
|
alias PrymnProto.Prymn.SysInfoResponse.Disk
|
|
|
|
|
|
|
|
{used, total} =
|
|
|
|
Enum.reduce(disks, {0, 0}, fn %Disk{} = disk, {used, total} ->
|
|
|
|
{used + disk.total_bytes - disk.avail_bytes, total + disk.total_bytes}
|
|
|
|
end)
|
|
|
|
|
|
|
|
Float.round(100 * used / total, 2)
|
|
|
|
end
|
2023-06-09 19:13:27 +00:00
|
|
|
end
|