Skip to content
Commitpedia
Log in Join & edit

virsh status report: VMs, state, resources and IPs in one table

A read-only bash script that prints a libvirt/KVM host report: virtual networks, storage pools, and every VM with its state, vCPUs, memory, autostart flag and IP addresses.

Not checked by a trusted editor yet Last edited Outdated?

Edit history of virsh status report: VMs, state, resources and IPs in one table: 1 recorded edit
Edit history · 1 edit
Type
Script
Edits
1
Editors
1
First issued
15 Oct 2026
Last edit
15 Oct 2026
Language
bash
Licence
CC0-1.0

What this changes

Read-only: it lists networks, storage pools and domains through virsh and prints them; no VM or setting is changed.

How to undo it

Nothing to undo.

Run this on a KVM host to get a quick overview before maintenance or when someone asks “what is running on this box?”. It only uses read-only virsh commands (uri, net-list, pool-list, list, dominfo, domstate, domifaddr), so it is safe to run at any time.

Script

#!/usr/bin/env bash
# virsh-report.sh - read-only status report for a libvirt/KVM host
# License: CC0-1.0
set -euo pipefail

URI="${LIBVIRT_DEFAULT_URI:-qemu:///system}"

usage() {
  echo "Usage: $0 [-c URI]"
  echo "  -c URI   libvirt connection URI (default: $URI)"
}

while getopts ":c:h" opt; do
  case "$opt" in
    c) URI="$OPTARG" ;;
    h) usage; exit 0 ;;
    *) usage >&2; exit 2 ;;
  esac
done

if ! command -v virsh >/dev/null 2>&1; then
  echo "virsh not found. Install the libvirt client tools first." >&2
  exit 1
fi

v() { virsh -c "$URI" "$@"; }

if ! v uri >/dev/null 2>&1; then
  echo "Cannot connect to $URI (is libvirtd running, and do you have permission?)" >&2
  exit 1
fi

echo "== Host: $(hostname)  URI: $(v uri)  Date: $(date '+%Y-%m-%d %H:%M:%S')"
echo
echo "== Virtual networks"
v net-list --all
echo "== Storage pools"
v pool-list --all --details
echo "== Domains"
printf '%-24s %-12s %5s %10s %-9s %s\n' NAME STATE VCPUS MEM_MIB AUTOSTART IP_ADDRESSES

mapfile -t domains < <(v list --all --name | sed '/^$/d')

if [ "${#domains[@]}" -eq 0 ]; then
  echo "(no domains defined)"
  exit 0
fi

running=0
stopped=0
for dom in "${domains[@]}"; do
  info="$(v dominfo "$dom")"
  state="$(v domstate "$dom" | head -n 1)"
  vcpus="$(awk -F: '/^CPU\(s\)/ {gsub(/ /,"",$2); print $2}' <<<"$info")"
  mem_kib="$(awk -F: '/^Max memory/ {gsub(/[^0-9]/,"",$2); print $2}' <<<"$info")"
  autostart="$(awk -F: '/^Autostart/ {gsub(/ /,"",$2); print $2}' <<<"$info")"
  ips="-"
  if [ "$state" = "running" ]; then
    running=$((running + 1))
    ips="$(v domifaddr "$dom" 2>/dev/null | awk 'NR>2 && $4 {print $4}' | paste -sd, -)"
    [ -n "$ips" ] || ips="unknown"
  else
    stopped=$((stopped + 1))
  fi
  printf '%-24s %-12s %5s %10s %-9s %s\n' \
    "$dom" "$state" "${vcpus:-?}" "$(( ${mem_kib:-0} / 1024 ))" "${autostart:-?}" "$ips"
done

echo
echo "Total: ${#domains[@]} domains, $running running, $stopped not running"

Usage

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
chmod +x virsh-report.sh
sudo ./virsh-report.sh
./virsh-report.sh -c qemu:///session
./virsh-report.sh > /tmp/kvm-report-$(date +%F).txt

Notes

  • The default connection is LIBVIRT_DEFAULT_URI if set, otherwise qemu:///system, which usually needs root or libvirt group membership.
  • Memory is the domain’s maximum memory from virsh dominfo, converted from KiB to MiB.
  • IP addresses come from virsh domifaddr, whose default source is the libvirt DHCP lease table. VMs on a host bridge or with static IPs may show unknown; on those, domifaddr --source agent works if the QEMU guest agent runs in the guest.
  • The script parses human-readable virsh output, which is stable in practice but not a formal API. For monitoring systems, consider virsh domstats or the libvirt API bindings instead.

Official documentation

See also

Repos in the wild

History

Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.

  1. Commitpedia +3,685 chars

Report a problem

Something wrong, unsafe or copied? Tell the editors.
What is wrong?