feat(nodes): capture extended machine inventory
This commit is contained in:
@@ -84,8 +84,12 @@ func migrate(ctx context.Context, database *sql.DB) error {
|
||||
ssh_password TEXT NOT NULL DEFAULT '',
|
||||
package_manager TEXT NOT NULL DEFAULT '',
|
||||
architecture TEXT NOT NULL DEFAULT '',
|
||||
host_model TEXT NOT NULL DEFAULT '',
|
||||
kernel_version TEXT NOT NULL DEFAULT '',
|
||||
cpu_model TEXT NOT NULL DEFAULT '',
|
||||
gpu_model TEXT NOT NULL DEFAULT '',
|
||||
default_shell TEXT NOT NULL DEFAULT '',
|
||||
package_count INTEGER NOT NULL DEFAULT 0,
|
||||
memory_total_mb INTEGER NOT NULL DEFAULT 0,
|
||||
disk_total_gb INTEGER NOT NULL DEFAULT 0,
|
||||
cpu_usage REAL NOT NULL DEFAULT 0,
|
||||
@@ -145,8 +149,12 @@ func migrate(ctx context.Context, database *sql.DB) error {
|
||||
`ALTER TABLE nodes ADD COLUMN tag TEXT NOT NULL DEFAULT '';`,
|
||||
`ALTER TABLE nodes ADD COLUMN package_manager TEXT NOT NULL DEFAULT '';`,
|
||||
`ALTER TABLE nodes ADD COLUMN architecture TEXT NOT NULL DEFAULT '';`,
|
||||
`ALTER TABLE nodes ADD COLUMN host_model TEXT NOT NULL DEFAULT '';`,
|
||||
`ALTER TABLE nodes ADD COLUMN kernel_version TEXT NOT NULL DEFAULT '';`,
|
||||
`ALTER TABLE nodes ADD COLUMN cpu_model TEXT NOT NULL DEFAULT '';`,
|
||||
`ALTER TABLE nodes ADD COLUMN gpu_model TEXT NOT NULL DEFAULT '';`,
|
||||
`ALTER TABLE nodes ADD COLUMN default_shell TEXT NOT NULL DEFAULT '';`,
|
||||
`ALTER TABLE nodes ADD COLUMN package_count INTEGER NOT NULL DEFAULT 0;`,
|
||||
`ALTER TABLE nodes ADD COLUMN memory_total_mb INTEGER NOT NULL DEFAULT 0;`,
|
||||
`ALTER TABLE nodes ADD COLUMN disk_total_gb INTEGER NOT NULL DEFAULT 0;`,
|
||||
`ALTER TABLE automation_jobs ADD COLUMN tag TEXT NOT NULL DEFAULT '';`,
|
||||
|
||||
@@ -55,8 +55,12 @@ type Node struct {
|
||||
SSHPassword string
|
||||
PackageManager string
|
||||
Architecture string
|
||||
HostModel string
|
||||
KernelVersion string
|
||||
CPUModel string
|
||||
GPUModel string
|
||||
DefaultShell string
|
||||
PackageCount int64
|
||||
MemoryTotalMB int64
|
||||
DiskTotalGB int64
|
||||
CPUUsage float64
|
||||
|
||||
@@ -25,7 +25,7 @@ func NewNodeService(database *sql.DB, crypto *CryptoService) *NodeService {
|
||||
func (s *NodeService) ListNodes(ctx context.Context, orgID int64) ([]models.Node, error) {
|
||||
rows, err := s.db.QueryContext(ctx, `
|
||||
SELECT n.id, n.organization_id, n.group_id, COALESCE(g.name, ''), n.tag, n.name, n.distro, n.hostname, n.ip_address, n.mac_address,
|
||||
n.ssh_port, n.ssh_username, n.ssh_password, n.package_manager, n.architecture, n.kernel_version, n.cpu_model, n.memory_total_mb, n.disk_total_gb,
|
||||
n.ssh_port, n.ssh_username, n.ssh_password, n.package_manager, n.architecture, n.host_model, n.kernel_version, n.cpu_model, n.gpu_model, n.default_shell, n.package_count, n.memory_total_mb, n.disk_total_gb,
|
||||
n.cpu_usage, n.ram_usage, n.disk_usage,
|
||||
n.uptime_seconds, n.last_seen_at, n.auto_updates_enabled, n.notes, n.created_at, n.updated_at
|
||||
FROM nodes n
|
||||
@@ -44,7 +44,7 @@ func (s *NodeService) ListNodes(ctx context.Context, orgID int64) ([]models.Node
|
||||
func (s *NodeService) ListNodesByGroup(ctx context.Context, orgID, groupID int64) ([]models.Node, error) {
|
||||
rows, err := s.db.QueryContext(ctx, `
|
||||
SELECT n.id, n.organization_id, n.group_id, COALESCE(g.name, ''), n.tag, n.name, n.distro, n.hostname, n.ip_address, n.mac_address,
|
||||
n.ssh_port, n.ssh_username, n.ssh_password, n.package_manager, n.architecture, n.kernel_version, n.cpu_model, n.memory_total_mb, n.disk_total_gb,
|
||||
n.ssh_port, n.ssh_username, n.ssh_password, n.package_manager, n.architecture, n.host_model, n.kernel_version, n.cpu_model, n.gpu_model, n.default_shell, n.package_count, n.memory_total_mb, n.disk_total_gb,
|
||||
n.cpu_usage, n.ram_usage, n.disk_usage,
|
||||
n.uptime_seconds, n.last_seen_at, n.auto_updates_enabled, n.notes, n.created_at, n.updated_at
|
||||
FROM nodes n
|
||||
@@ -63,7 +63,7 @@ func (s *NodeService) ListNodesByGroup(ctx context.Context, orgID, groupID int64
|
||||
func (s *NodeService) ListNodesByTag(ctx context.Context, orgID int64, tag string) ([]models.Node, error) {
|
||||
rows, err := s.db.QueryContext(ctx, `
|
||||
SELECT n.id, n.organization_id, n.group_id, COALESCE(g.name, ''), n.tag, n.name, n.distro, n.hostname, n.ip_address, n.mac_address,
|
||||
n.ssh_port, n.ssh_username, n.ssh_password, n.package_manager, n.architecture, n.kernel_version, n.cpu_model, n.memory_total_mb, n.disk_total_gb,
|
||||
n.ssh_port, n.ssh_username, n.ssh_password, n.package_manager, n.architecture, n.host_model, n.kernel_version, n.cpu_model, n.gpu_model, n.default_shell, n.package_count, n.memory_total_mb, n.disk_total_gb,
|
||||
n.cpu_usage, n.ram_usage, n.disk_usage,
|
||||
n.uptime_seconds, n.last_seen_at, n.auto_updates_enabled, n.notes, n.created_at, n.updated_at
|
||||
FROM nodes n
|
||||
@@ -86,7 +86,7 @@ func (s *NodeService) scanNodes(rows *sql.Rows) ([]models.Node, error) {
|
||||
if err := rows.Scan(
|
||||
&node.ID, &node.OrganizationID, &node.GroupID, &node.GroupName, &node.Tag, &node.Name, &node.Distro, &node.Hostname,
|
||||
&node.IPAddress, &node.MACAddress, &node.SSHPort, &node.SSHUsername, &node.SSHPassword,
|
||||
&node.PackageManager, &node.Architecture, &node.KernelVersion, &node.CPUModel, &node.MemoryTotalMB, &node.DiskTotalGB,
|
||||
&node.PackageManager, &node.Architecture, &node.HostModel, &node.KernelVersion, &node.CPUModel, &node.GPUModel, &node.DefaultShell, &node.PackageCount, &node.MemoryTotalMB, &node.DiskTotalGB,
|
||||
&node.CPUUsage, &node.RAMUsage, &node.DiskUsage, &node.UptimeSeconds, &node.LastSeenAt,
|
||||
&node.AutoUpdatesEnabled, &node.Notes, &node.CreatedAt, &node.UpdatedAt,
|
||||
); err != nil {
|
||||
@@ -107,7 +107,7 @@ func (s *NodeService) GetNode(ctx context.Context, orgID, nodeID int64) (*models
|
||||
node := &models.Node{}
|
||||
err := s.db.QueryRowContext(ctx, `
|
||||
SELECT n.id, n.organization_id, n.group_id, COALESCE(g.name, ''), n.tag, n.name, n.distro, n.hostname, n.ip_address, n.mac_address,
|
||||
n.ssh_port, n.ssh_username, n.ssh_password, n.package_manager, n.architecture, n.kernel_version, n.cpu_model, n.memory_total_mb, n.disk_total_gb,
|
||||
n.ssh_port, n.ssh_username, n.ssh_password, n.package_manager, n.architecture, n.host_model, n.kernel_version, n.cpu_model, n.gpu_model, n.default_shell, n.package_count, n.memory_total_mb, n.disk_total_gb,
|
||||
n.cpu_usage, n.ram_usage, n.disk_usage,
|
||||
n.uptime_seconds, n.last_seen_at, n.auto_updates_enabled, n.notes, n.created_at, n.updated_at
|
||||
FROM nodes n
|
||||
@@ -116,7 +116,7 @@ func (s *NodeService) GetNode(ctx context.Context, orgID, nodeID int64) (*models
|
||||
`, orgID, nodeID).Scan(
|
||||
&node.ID, &node.OrganizationID, &node.GroupID, &node.GroupName, &node.Tag, &node.Name, &node.Distro, &node.Hostname,
|
||||
&node.IPAddress, &node.MACAddress, &node.SSHPort, &node.SSHUsername, &node.SSHPassword,
|
||||
&node.PackageManager, &node.Architecture, &node.KernelVersion, &node.CPUModel, &node.MemoryTotalMB, &node.DiskTotalGB,
|
||||
&node.PackageManager, &node.Architecture, &node.HostModel, &node.KernelVersion, &node.CPUModel, &node.GPUModel, &node.DefaultShell, &node.PackageCount, &node.MemoryTotalMB, &node.DiskTotalGB,
|
||||
&node.CPUUsage, &node.RAMUsage, &node.DiskUsage, &node.UptimeSeconds, &node.LastSeenAt,
|
||||
&node.AutoUpdatesEnabled, &node.Notes, &node.CreatedAt, &node.UpdatedAt,
|
||||
)
|
||||
@@ -147,11 +147,11 @@ func (s *NodeService) SaveNode(ctx context.Context, node *models.Node) error {
|
||||
result, err := s.db.ExecContext(ctx, `
|
||||
INSERT INTO nodes (
|
||||
organization_id, group_id, tag, name, distro, hostname, ip_address, mac_address,
|
||||
ssh_port, ssh_username, ssh_password, package_manager, architecture, kernel_version, cpu_model, memory_total_mb, disk_total_gb,
|
||||
ssh_port, ssh_username, ssh_password, package_manager, architecture, host_model, kernel_version, cpu_model, gpu_model, default_shell, package_count, memory_total_mb, disk_total_gb,
|
||||
auto_updates_enabled, notes
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`, node.OrganizationID, node.GroupID, node.Tag, node.Name, node.Distro, node.Hostname, node.IPAddress,
|
||||
node.MACAddress, node.SSHPort, node.SSHUsername, encryptedPassword, node.PackageManager, node.Architecture, node.KernelVersion, node.CPUModel, node.MemoryTotalMB, node.DiskTotalGB, node.AutoUpdatesEnabled, node.Notes)
|
||||
node.MACAddress, node.SSHPort, node.SSHUsername, encryptedPassword, node.PackageManager, node.Architecture, node.HostModel, node.KernelVersion, node.CPUModel, node.GPUModel, node.DefaultShell, node.PackageCount, node.MemoryTotalMB, node.DiskTotalGB, node.AutoUpdatesEnabled, node.Notes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -162,12 +162,12 @@ func (s *NodeService) SaveNode(ctx context.Context, node *models.Node) error {
|
||||
_, err := s.db.ExecContext(ctx, `
|
||||
UPDATE nodes
|
||||
SET group_id = ?, tag = ?, name = ?, distro = ?, hostname = ?, ip_address = ?, mac_address = ?,
|
||||
ssh_port = ?, ssh_username = ?, ssh_password = ?, package_manager = ?, architecture = ?, kernel_version = ?, cpu_model = ?, memory_total_mb = ?, disk_total_gb = ?,
|
||||
ssh_port = ?, ssh_username = ?, ssh_password = ?, package_manager = ?, architecture = ?, host_model = ?, kernel_version = ?, cpu_model = ?, gpu_model = ?, default_shell = ?, package_count = ?, memory_total_mb = ?, disk_total_gb = ?,
|
||||
auto_updates_enabled = ?, notes = ?,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = ? AND organization_id = ?
|
||||
`, node.GroupID, node.Tag, node.Name, node.Distro, node.Hostname, node.IPAddress, node.MACAddress,
|
||||
node.SSHPort, node.SSHUsername, encryptedPassword, node.PackageManager, node.Architecture, node.KernelVersion, node.CPUModel, node.MemoryTotalMB, node.DiskTotalGB, node.AutoUpdatesEnabled, node.Notes,
|
||||
node.SSHPort, node.SSHUsername, encryptedPassword, node.PackageManager, node.Architecture, node.HostModel, node.KernelVersion, node.CPUModel, node.GPUModel, node.DefaultShell, node.PackageCount, node.MemoryTotalMB, node.DiskTotalGB, node.AutoUpdatesEnabled, node.Notes,
|
||||
node.ID, node.OrganizationID)
|
||||
return err
|
||||
}
|
||||
@@ -286,9 +286,20 @@ func (s *NodeService) RefreshNodeInventory(ctx context.Context, node *models.Nod
|
||||
`if [ -r /etc/os-release ]; then . /etc/os-release; echo DISTRO="${PRETTY_NAME:-$ID}"; else echo DISTRO="$(uname -s)"; fi`,
|
||||
`echo HOSTNAME="$(hostname 2>/dev/null || uname -n)"`,
|
||||
`echo ARCH="$(uname -m 2>/dev/null)"`,
|
||||
`HOST_MODEL="$(cat /sys/devices/virtual/dmi/id/product_name 2>/dev/null || hostnamectl 2>/dev/null | awk -F: '/Chassis|Hardware Model/ {gsub(/^[ \t]+/, "", $2); print $2; exit}')"; echo HOST_MODEL="${HOST_MODEL}"`,
|
||||
`echo KERNEL="$(uname -r 2>/dev/null)"`,
|
||||
`if command -v apt >/dev/null 2>&1; then echo PKG_MGR=apt; elif command -v dnf >/dev/null 2>&1; then echo PKG_MGR=dnf; elif command -v yum >/dev/null 2>&1; then echo PKG_MGR=yum; elif command -v pacman >/dev/null 2>&1; then echo PKG_MGR=pacman; elif command -v zypper >/dev/null 2>&1; then echo PKG_MGR=zypper; elif command -v apk >/dev/null 2>&1; then echo PKG_MGR=apk; elif command -v nix-env >/dev/null 2>&1; then echo PKG_MGR=nix; elif command -v emerge >/dev/null 2>&1; then echo PKG_MGR=emerge; else echo PKG_MGR=unknown; fi`,
|
||||
`CPU_MODEL="$( (command -v lscpu >/dev/null 2>&1 && lscpu | awk -F: '/Model name/ {gsub(/^[ \t]+/, "", $2); print $2; exit}') || awk -F: '/model name/ {gsub(/^[ \t]+/, "", $2); print $2; exit}' /proc/cpuinfo )"; echo CPU_MODEL="${CPU_MODEL}"`,
|
||||
`GPU_MODEL="$( (command -v lspci >/dev/null 2>&1 && lspci | awk -F': ' '/VGA compatible controller|3D controller|Display controller/ {print $2; exit}') || true )"; echo GPU_MODEL="${GPU_MODEL}"`,
|
||||
`DEFAULT_SHELL="${SHELL:-$(getent passwd "$(id -un 2>/dev/null)" 2>/dev/null | cut -d: -f7)}"; echo DEFAULT_SHELL="${DEFAULT_SHELL}"`,
|
||||
`PACKAGE_COUNT="$(
|
||||
if command -v dpkg-query >/dev/null 2>&1; then dpkg-query -f '.' -W 2>/dev/null | wc -c;
|
||||
elif command -v rpm >/dev/null 2>&1; then rpm -qa 2>/dev/null | wc -l;
|
||||
elif command -v pacman >/dev/null 2>&1; then pacman -Qq 2>/dev/null | wc -l;
|
||||
elif command -v apk >/dev/null 2>&1; then apk info 2>/dev/null | wc -l;
|
||||
elif command -v nix-store >/dev/null 2>&1; then nix-store --gc --print-live 2>/dev/null | wc -l;
|
||||
else printf 0; fi
|
||||
)"; echo PACKAGE_COUNT="${PACKAGE_COUNT:-0}"`,
|
||||
`MEMORY_MB="$(awk '/MemTotal/ {printf "%d", $2/1024}' /proc/meminfo 2>/dev/null)"; echo MEMORY_MB="${MEMORY_MB:-0}"`,
|
||||
`DISK_GB="$(df -BG / 2>/dev/null | awk 'NR==2 {gsub(/G/, "", $2); print $2}')"; echo DISK_GB="${DISK_GB:-0}"`,
|
||||
}, " ; "))
|
||||
@@ -308,15 +319,23 @@ func (s *NodeService) RefreshNodeInventory(ctx context.Context, node *models.Nod
|
||||
|
||||
var memoryMB int64
|
||||
var diskGB int64
|
||||
var packageCount int64
|
||||
fmt.Sscanf(values["MEMORY_MB"], "%d", &memoryMB)
|
||||
fmt.Sscanf(values["DISK_GB"], "%d", &diskGB)
|
||||
fmt.Sscanf(values["PACKAGE_COUNT"], "%d", &packageCount)
|
||||
|
||||
node.Distro = fallbackInventoryValue(values["DISTRO"], node.Distro, "Linux")
|
||||
node.Hostname = fallbackInventoryValue(values["HOSTNAME"], node.Hostname, node.IPAddress)
|
||||
node.PackageManager = fallbackInventoryValue(values["PKG_MGR"], node.PackageManager, "")
|
||||
node.Architecture = fallbackInventoryValue(values["ARCH"], node.Architecture, "")
|
||||
node.HostModel = fallbackInventoryValue(values["HOST_MODEL"], node.HostModel, "")
|
||||
node.KernelVersion = fallbackInventoryValue(values["KERNEL"], node.KernelVersion, "")
|
||||
node.CPUModel = fallbackInventoryValue(values["CPU_MODEL"], node.CPUModel, "")
|
||||
node.GPUModel = fallbackInventoryValue(values["GPU_MODEL"], node.GPUModel, "")
|
||||
node.DefaultShell = fallbackInventoryValue(values["DEFAULT_SHELL"], node.DefaultShell, "")
|
||||
if packageCount > 0 {
|
||||
node.PackageCount = packageCount
|
||||
}
|
||||
if memoryMB > 0 {
|
||||
node.MemoryTotalMB = memoryMB
|
||||
}
|
||||
@@ -326,10 +345,10 @@ func (s *NodeService) RefreshNodeInventory(ctx context.Context, node *models.Nod
|
||||
|
||||
_, err = s.db.ExecContext(ctx, `
|
||||
UPDATE nodes
|
||||
SET distro = ?, hostname = ?, package_manager = ?, architecture = ?, kernel_version = ?, cpu_model = ?, memory_total_mb = ?, disk_total_gb = ?,
|
||||
SET distro = ?, hostname = ?, package_manager = ?, architecture = ?, host_model = ?, kernel_version = ?, cpu_model = ?, gpu_model = ?, default_shell = ?, package_count = ?, memory_total_mb = ?, disk_total_gb = ?,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = ? AND organization_id = ?
|
||||
`, node.Distro, node.Hostname, node.PackageManager, node.Architecture, node.KernelVersion, node.CPUModel, node.MemoryTotalMB, node.DiskTotalGB, node.ID, node.OrganizationID)
|
||||
`, node.Distro, node.Hostname, node.PackageManager, node.Architecture, node.HostModel, node.KernelVersion, node.CPUModel, node.GPUModel, node.DefaultShell, node.PackageCount, node.MemoryTotalMB, node.DiskTotalGB, node.ID, node.OrganizationID)
|
||||
if err != nil {
|
||||
return output, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user