125 lines
4 KiB
Elixir
125 lines
4 KiB
Elixir
defmodule ToweropsWeb.AgentLive.Show do
|
|
@moduledoc false
|
|
use ToweropsWeb, :live_view
|
|
|
|
import ToweropsWeb.AgentLive.Helpers
|
|
|
|
alias Towerops.Agents
|
|
alias Towerops.Agents.ReleaseChecker
|
|
|
|
@impl true
|
|
def mount(%{"id" => id}, _session, socket) do
|
|
organization = socket.assigns.current_scope.organization
|
|
agent_token = Agents.get_agent_token!(id)
|
|
current_user = socket.assigns.current_scope.user
|
|
|
|
# Verify access: agent must belong to this org, or superadmin can view any agent
|
|
has_access =
|
|
agent_token.organization_id == organization.id ||
|
|
current_user.is_superuser
|
|
|
|
if !has_access do
|
|
raise Ecto.NoResultsError, queryable: Towerops.Agents.AgentToken
|
|
end
|
|
|
|
# device this agent is responsible for)
|
|
polling_targets = Agents.list_agent_polling_targets(agent_token.id)
|
|
|
|
# Get direct assignments
|
|
direct_assignments = Agents.count_assigned_devices(agent_token.id)
|
|
|
|
{:ok,
|
|
socket
|
|
|> assign(:page_title, agent_token.name)
|
|
|> assign(:timezone, socket.assigns.current_scope.timezone)
|
|
|> assign(:agent_token, agent_token)
|
|
|> assign(:polling_targets, polling_targets)
|
|
|> assign(:direct_assignments, direct_assignments)
|
|
|> assign(:active_tab, "overview")}
|
|
end
|
|
|
|
@impl true
|
|
def handle_params(_params, _url, socket) do
|
|
{:noreply, socket}
|
|
end
|
|
|
|
@impl true
|
|
def handle_event("switch_tab", %{"tab" => tab}, socket) do
|
|
{:noreply, assign(socket, :active_tab, tab)}
|
|
end
|
|
|
|
def handle_event("restart_agent", _params, socket) do
|
|
if socket.assigns.current_scope.user.is_superuser do
|
|
Agents.restart_agent(socket.assigns.agent_token.id)
|
|
|
|
{:noreply, put_flash(socket, :info, t("Restart command sent to agent"))}
|
|
else
|
|
{:noreply, socket}
|
|
end
|
|
end
|
|
|
|
def handle_event("update_agent", _params, socket) do
|
|
if socket.assigns.current_scope.user.is_superuser do
|
|
agent_token = socket.assigns.agent_token
|
|
arch = get_in(agent_token.metadata, ["arch"]) || "x86_64"
|
|
|
|
{:noreply, send_update_command(socket, agent_token, arch)}
|
|
else
|
|
{:noreply, socket}
|
|
end
|
|
end
|
|
|
|
defp send_update_command(socket, agent_token, arch) do
|
|
with {:ok, release} <- ReleaseChecker.get_latest_release(),
|
|
{:ok, asset} <- ReleaseChecker.asset_for_arch(release.assets, arch) do
|
|
Agents.update_agent(agent_token.id, asset.url, asset.checksum)
|
|
put_flash(socket, :info, t("Update command sent to agent (v%{version})", version: release.version))
|
|
else
|
|
{:error, :no_matching_asset} ->
|
|
put_flash(socket, :error, t("No binary available for architecture: %{arch}", arch: arch))
|
|
|
|
{:error, _reason} ->
|
|
put_flash(socket, :error, t("Failed to fetch latest release"))
|
|
end
|
|
end
|
|
|
|
defp assignment_source(device, agent_token_id) do
|
|
cond do
|
|
directly_assigned?(device, agent_token_id) ->
|
|
{:direct, "Directly assigned"}
|
|
|
|
site_assigned?(device, agent_token_id) ->
|
|
{:site, "From site: #{device.site.name}"}
|
|
|
|
organization_assigned?(device, agent_token_id) ->
|
|
{:organization, "From organization"}
|
|
|
|
true ->
|
|
{:unknown, "Unknown"}
|
|
end
|
|
end
|
|
|
|
defp directly_assigned?(device, agent_token_id) do
|
|
Enum.any?(device.agent_assignments || [], fn a ->
|
|
a.agent_token_id == agent_token_id and a.enabled
|
|
end)
|
|
end
|
|
|
|
defp site_assigned?(device, agent_token_id) do
|
|
device.site && device.site.agent_token_id == agent_token_id
|
|
end
|
|
|
|
defp organization_assigned?(device, agent_token_id) do
|
|
device.site && device.site.organization &&
|
|
device.site.organization.default_agent_token_id == agent_token_id
|
|
end
|
|
|
|
defp source_badge_class(source) do
|
|
case source do
|
|
:direct -> "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300"
|
|
:site -> "bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300"
|
|
:organization -> "bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-300"
|
|
:unknown -> "bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300"
|
|
end
|
|
end
|
|
end
|