From 34e984d56390af8aa0338094a82ccdfe79c73611 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Fri, 17 Apr 2026 20:13:14 -0400 Subject: [PATCH] Add vm-info script to gather VM info --- README.md | 31 +++++++++++++++++++ bin/vm-info | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100755 bin/vm-info diff --git a/README.md b/README.md index a256ea6..a21cb93 100644 --- a/README.md +++ b/README.md @@ -105,3 +105,34 @@ cp /var/www/malp/systemd/* /usr/lib/systemd/system systemctl enable --now malpd.socket systemctl enable --now malpd.service ``` + +### Virtual Machine Info + +#### Generate SSH Key + +On server host OS, generate an SSH key that will be used to gather information +from each running VM. +Leave the passphrase empty so it can be used non-interactively. + +``` +ssh-keygen -f /root/.ssh/malp-vm-key +``` + +#### malp user + +On each VM to gather status information, add a `malp` user with: + +``` +useradd -m malp +``` + +Add a /home/malp/.ssh/authorized_keys file with content such as (replacing the +SSH key beginning with `ssh-ed25519`...): + +``` +command="/path/to/malp/bin/vm-info",no-port-forwarding,no-x11-forwarding,no-agent-forwarding,no-pty ssh-ed25519 AAAAC3Nza...user@example.com +``` + +#### vm-info script + +Make the `bin/vm-info` script available on each VM (via scp/rsync, NFS, etc...) diff --git a/bin/vm-info b/bin/vm-info new file mode 100755 index 0000000..309624b --- /dev/null +++ b/bin/vm-info @@ -0,0 +1,85 @@ +#!/usr/bin/env ruby + +require "json" + +def read_os_id + return nil unless File.exist?("/etc/os-release") + File.readlines("/etc/os-release").each do |line| + if line =~ /^ID=(.+)$/ + return $1.strip.delete('"').downcase + end + end + nil +end + +def read_os_name + return nil unless File.exist?("/etc/os-release") + File.readlines("/etc/os-release").each do |line| + if line =~ /^PRETTY_NAME="(.+)"$/ + return $1.strip.delete('"').downcase + end + end + nil +end + +def ubuntu_updates + out = `apt-get -s -o Debug::NoLocking=true upgrade 2>/dev/null` + count = 0 + out.each_line do |line| + count += 1 if line.start_with?("Inst ") + end + count +end + +def ubuntu_reboot_pending + File.exist?("/var/run/reboot-required") +end + +def alma_updates + out = `dnf -q check-update 2>/dev/null` + status = $?.exitstatus + return 0 if status == 0 + return nil unless status == 100 + count = 0 + out.each_line do |line| + line = line.strip + next if line.empty? + next if line.start_with?("Obsoleting", "Last metadata") + count += 1 if line.split(/\s+/).size >= 3 + end + count +end + +def alma_reboot_pending + `dnf needs-restarting -r >/dev/null 2>&1` + $?.exitstatus == 1 +end + +def df + df_out = `df -k /` + if df_out =~ /^\S+\s+(\d+)\s+(\d+)/ + total, used = $1.to_i, $2.to_i + [total, used] + end +end + +result = {} +if os = read_os_id + result["os"] = os +end +if os_name = read_os_name + result["os_name"] = os_name +end +case os +when "ubuntu", "debian" + result["updates"] = ubuntu_updates + result["reboot_pending"] = ubuntu_reboot_pending +when "almalinux", "rocky", "rhel", "centos", "fedora" + result["updates"] = alma_updates + result["reboot_pending"] = alma_reboot_pending +end +if df_info = df + result["df"] = df_info +end + +puts JSON.generate(result)