Add Linux fresh setup toolkit
lint / shell-yaml-ansible (push) Failing after 16s

This commit is contained in:
Mateusz Suski
2026-06-06 00:23:11 +00:00
parent 8cb92de06f
commit 4e739c5c99
25 changed files with 1646 additions and 0 deletions
@@ -0,0 +1,20 @@
# shellcheck shell=bash
require_supported_ubuntu() {
if [[ ! -r /etc/os-release ]] || ! command -v dpkg >/dev/null 2>&1; then
printf 'CRITICAL: Ubuntu release detection requires /etc/os-release and dpkg\n' >&2
exit 2
fi
# shellcheck disable=SC1091
source /etc/os-release
if [[ "${ID:-}" != "ubuntu" ]]; then
printf 'CRITICAL: this toolkit supports Ubuntu only; detected %s\n' "${ID:-unknown}" >&2
exit 2
fi
if ! dpkg --compare-versions "${VERSION_ID:-0}" ge "24.04"; then
printf 'CRITICAL: Ubuntu 24.04 or newer is required; detected %s\n' \
"${VERSION_ID:-unknown}" >&2
exit 2
fi
}
+124
View File
@@ -0,0 +1,124 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
section() {
printf '\n== %s ==\n' "$1"
}
run_optional() {
local description="$1"
shift
if "$@"; then
return 0
fi
printf 'WARNING: %s failed\n' "$description"
return 0
}
section "Operating system"
if [[ -r /etc/os-release ]]; then
run_optional "OS release report" cat /etc/os-release
else
printf 'WARNING: /etc/os-release is unavailable\n'
fi
run_optional "kernel report" uname -a
section "Host"
run_optional "hostname report" hostname
run_optional "uptime report" uptime
section "CPU and virtualization"
if command -v lscpu >/dev/null 2>&1; then
run_optional "CPU report" lscpu
printf '\nVirtualization flags:\n'
lscpu | grep -E 'Virtualization|Hypervisor vendor' || \
printf 'INFO: no virtualization summary reported by lscpu\n'
else
printf 'WARNING: lscpu is unavailable\n'
fi
if grep -Eqm1 '(^|[[:space:]])(vmx|svm)([[:space:]]|$)' /proc/cpuinfo; then
printf 'OK: CPU virtualization flags detected\n'
else
printf 'WARNING: CPU virtualization flags were not detected\n'
fi
section "Memory"
if command -v free >/dev/null 2>&1; then
run_optional "memory report" free -h
else
run_optional "memory report" cat /proc/meminfo
fi
section "Disks"
if command -v lsblk >/dev/null 2>&1; then
run_optional "block device report" lsblk -o NAME,TYPE,SIZE,FSTYPE,MOUNTPOINTS,MODEL
else
printf 'WARNING: lsblk is unavailable\n'
fi
run_optional "filesystem report" df -hT
section "Network"
if command -v ip >/dev/null 2>&1; then
run_optional "network interface report" ip -brief address
run_optional "route report" ip route
else
printf 'WARNING: ip is unavailable\n'
fi
section "Firmware and Secure Boot"
if [[ -d /sys/firmware/efi ]]; then
printf 'OK: boot mode is UEFI\n'
else
printf 'INFO: boot mode appears to be legacy BIOS\n'
fi
if command -v mokutil >/dev/null 2>&1; then
run_optional "Secure Boot report" mokutil --sb-state
else
printf 'INFO: mokutil is unavailable; Secure Boot state not queried\n'
fi
section "IOMMU"
if [[ -r /proc/cmdline ]]; then
printf 'Kernel command line:\n'
cat /proc/cmdline
if grep -Eq '(^|[[:space:]])(intel_iommu=on|amd_iommu=on|iommu=)' /proc/cmdline; then
printf 'OK: IOMMU-related kernel arguments detected\n'
else
printf 'INFO: no explicit IOMMU kernel argument detected\n'
fi
fi
if command -v dmesg >/dev/null 2>&1; then
dmesg 2>/dev/null | grep -Ei 'DMAR|IOMMU|AMD-Vi' | tail -n 30 || \
printf 'INFO: no readable IOMMU hints found in dmesg\n'
fi
section "NVIDIA hardware"
if command -v lspci >/dev/null 2>&1; then
lspci -nn | grep -i nvidia || printf 'INFO: no NVIDIA PCI devices detected\n'
else
printf 'INFO: lspci is unavailable\n'
fi
section "Existing platform components"
for command_name in docker virsh cockpit-bridge; do
if command -v "$command_name" >/dev/null 2>&1; then
printf 'OK: %s is installed at %s\n' "$command_name" "$(command -v "$command_name")"
else
printf 'INFO: %s is not installed\n' "$command_name"
fi
done
if command -v systemctl >/dev/null 2>&1; then
for unit in docker.service libvirtd.service cockpit.socket; do
if systemctl cat "$unit" >/dev/null 2>&1; then
state="$(systemctl is-active "$unit" 2>/dev/null || true)"
printf 'INFO: %-20s state=%s\n' "$unit" "${state:-unknown}"
else
printf 'INFO: %s is not installed\n' "$unit"
fi
done
fi
printf '\nOK: preflight completed without modifying the host\n'
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=00-platform-guard.inc
source "$SCRIPT_DIR/00-platform-guard.inc"
packages=(
curl wget git vim nano tmux byobu htop btop glances
jq unzip zip rsync tree ncdu duf
lsof strace tcpdump nmap dnsutils net-tools iperf3 ethtool
smartmontools nvme-cli lm-sensors pciutils usbutils hwinfo
sysstat iotop iftop nload
ca-certificates gnupg software-properties-common apt-transport-https
needrestart unattended-upgrades logrotate
)
if ((EUID != 0)); then
printf 'CRITICAL: base package setup must run as root\n' >&2
exit 2
fi
require_supported_ubuntu
if ! command -v apt-get >/dev/null 2>&1; then
printf 'CRITICAL: apt-get is required\n' >&2
exit 2
fi
printf 'INFO: refreshing APT metadata\n'
apt-get update
printf 'INFO: installing baseline operational packages\n'
DEBIAN_FRONTEND=noninteractive apt-get install -y "${packages[@]}"
if command -v systemctl >/dev/null 2>&1; then
systemctl enable --now sysstat
else
printf 'WARNING: systemctl is unavailable; sysstat was not enabled\n'
fi
printf 'OK: baseline operational packages are installed\n'
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=00-platform-guard.inc
source "$SCRIPT_DIR/00-platform-guard.inc"
SOURCE_FILE="$SCRIPT_DIR/../files/bashrc.d/ailab.sh"
PROFILE_DIR="/root/.bashrc.d"
PROFILE_FILE="$PROFILE_DIR/ailab.sh"
BASHRC="/root/.bashrc"
SOURCE_LINE='[[ -f /root/.bashrc.d/ailab.sh ]] && source /root/.bashrc.d/ailab.sh'
backup_file() {
local path="$1"
local backup
backup="${path}.$(date '+%Y%m%d-%H%M%S').bak"
install -m 0644 "$path" "$backup"
printf 'INFO: backed up %s to %s\n' "$path" "$backup"
}
if ((EUID != 0)); then
printf 'CRITICAL: shell profile setup must run as root\n' >&2
exit 2
fi
require_supported_ubuntu
if [[ ! -r "$SOURCE_FILE" ]]; then
printf 'CRITICAL: shell profile source is missing: %s\n' "$SOURCE_FILE" >&2
exit 2
fi
install -d -m 0755 "$PROFILE_DIR"
if [[ ! -f "$PROFILE_FILE" ]] || ! cmp -s "$SOURCE_FILE" "$PROFILE_FILE"; then
if [[ -f "$PROFILE_FILE" ]]; then
backup_file "$PROFILE_FILE"
fi
install -m 0644 "$SOURCE_FILE" "$PROFILE_FILE"
printf 'OK: installed %s\n' "$PROFILE_FILE"
else
printf 'OK: shell profile is already current\n'
fi
if [[ ! -f "$BASHRC" ]]; then
install -m 0644 /dev/null "$BASHRC"
fi
source_count="$(grep -Fxc "$SOURCE_LINE" "$BASHRC" || true)"
if [[ "$source_count" != "1" ]]; then
tmp_bashrc="$(mktemp)"
trap 'rm -f "$tmp_bashrc"' EXIT
grep -Fvx "$SOURCE_LINE" "$BASHRC" >"$tmp_bashrc" || true
printf '\n%s\n' "$SOURCE_LINE" >>"$tmp_bashrc"
backup_file "$BASHRC"
install -m 0644 "$tmp_bashrc" "$BASHRC"
printf 'OK: configured %s to source the AI lab profile exactly once\n' "$BASHRC"
else
printf 'OK: %s already sources the AI lab profile exactly once\n' "$BASHRC"
fi
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=00-platform-guard.inc
source "$SCRIPT_DIR/00-platform-guard.inc"
required_packages=(
cockpit cockpit-system cockpit-storaged cockpit-networkmanager
cockpit-packagekit cockpit-machines cockpit-sosreport cockpit-pcp
)
if ((EUID != 0)); then
printf 'CRITICAL: Cockpit setup must run as root\n' >&2
exit 2
fi
require_supported_ubuntu
if ! command -v apt-get >/dev/null 2>&1; then
printf 'CRITICAL: apt-get is required\n' >&2
exit 2
fi
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y "${required_packages[@]}"
if apt-cache show cockpit-files >/dev/null 2>&1; then
DEBIAN_FRONTEND=noninteractive apt-get install -y cockpit-files
printf 'OK: installed optional cockpit-files package\n'
else
printf 'WARNING: cockpit-files is unavailable; continuing without it\n'
fi
systemctl enable --now cockpit.socket
printf 'OK: Cockpit is enabled at https://%s:9090\n' "$(hostname)"
+136
View File
@@ -0,0 +1,136 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=00-platform-guard.inc
source "$SCRIPT_DIR/00-platform-guard.inc"
SOURCE_CONFIG="$SCRIPT_DIR/../files/docker/daemon.json"
DOCKER_CONFIG="/etc/docker/daemon.json"
temporary_files=()
cleanup() {
local path
for path in "${temporary_files[@]}"; do
rm -f "$path"
done
}
trap cleanup EXIT
backup_file() {
local path="$1"
local backup
backup="${path}.$(date '+%Y%m%d-%H%M%S').bak"
install -m 0644 "$path" "$backup"
printf 'INFO: backed up %s to %s\n' "$path" "$backup"
}
if ((EUID != 0)); then
printf 'CRITICAL: Docker setup must run as root\n' >&2
exit 2
fi
require_supported_ubuntu
for command_name in apt-get apt-cache; do
if ! command -v "$command_name" >/dev/null 2>&1; then
printf 'CRITICAL: required command is missing: %s\n' "$command_name" >&2
exit 2
fi
done
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y ca-certificates curl gnupg jq
if apt-cache show docker.io >/dev/null 2>&1; then
packages=(docker.io)
if apt-cache show docker-compose-v2 >/dev/null 2>&1; then
packages+=(docker-compose-v2)
else
printf 'WARNING: docker-compose-v2 is unavailable from Ubuntu repositories\n'
fi
else
printf 'WARNING: docker.io is unavailable; configuring Docker official repository\n'
install -d -m 0755 /etc/apt/keyrings
tmp_key="$(mktemp)"
temporary_files+=("$tmp_key")
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| gpg --dearmor --yes -o "$tmp_key"
if [[ ! -f /etc/apt/keyrings/docker.gpg ]] || \
! cmp -s "$tmp_key" /etc/apt/keyrings/docker.gpg; then
if [[ -f /etc/apt/keyrings/docker.gpg ]]; then
backup_file /etc/apt/keyrings/docker.gpg
fi
install -m 0644 "$tmp_key" /etc/apt/keyrings/docker.gpg
fi
# shellcheck disable=SC1091
source /etc/os-release
architecture="$(dpkg --print-architecture)"
tmp_repository="$(mktemp)"
temporary_files+=("$tmp_repository")
printf 'deb [arch=%s signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu %s stable\n' \
"$architecture" "${VERSION_CODENAME:?}" \
>"$tmp_repository"
if [[ ! -f /etc/apt/sources.list.d/docker.list ]] || \
! cmp -s "$tmp_repository" /etc/apt/sources.list.d/docker.list; then
if [[ -f /etc/apt/sources.list.d/docker.list ]]; then
backup_file /etc/apt/sources.list.d/docker.list
fi
install -m 0644 "$tmp_repository" /etc/apt/sources.list.d/docker.list
fi
apt-get update
packages=(docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin)
fi
DEBIAN_FRONTEND=noninteractive apt-get install -y "${packages[@]}"
install -d -m 0755 /etc/docker
if [[ ! -r "$SOURCE_CONFIG" ]]; then
printf 'CRITICAL: Docker configuration template is missing: %s\n' "$SOURCE_CONFIG" >&2
exit 2
fi
jq empty "$SOURCE_CONFIG"
tmp_config="$(mktemp)"
temporary_files+=("$tmp_config")
if [[ -f "$DOCKER_CONFIG" ]]; then
if ! jq empty "$DOCKER_CONFIG" >/dev/null 2>&1; then
printf 'CRITICAL: %s is invalid JSON; refusing to overwrite it\n' "$DOCKER_CONFIG" >&2
exit 1
fi
jq '. + {
"log-driver": "json-file",
"log-opts": ((."log-opts" // {}) + {"max-size": "50m", "max-file": "5"})
}' "$DOCKER_CONFIG" >"$tmp_config"
else
install -m 0644 "$SOURCE_CONFIG" "$tmp_config"
fi
jq empty "$tmp_config"
config_changed=0
if [[ ! -f "$DOCKER_CONFIG" ]] || ! cmp -s "$tmp_config" "$DOCKER_CONFIG"; then
if [[ -f "$DOCKER_CONFIG" ]]; then
backup_file "$DOCKER_CONFIG"
fi
install -m 0644 "$tmp_config" "$DOCKER_CONFIG"
config_changed=1
printf 'OK: installed Docker daemon log limits\n'
else
printf 'OK: Docker daemon configuration is already current\n'
fi
systemctl enable --now docker
if ((config_changed == 1)); then
systemctl restart docker
fi
docker version
if docker compose version >/dev/null 2>&1; then
docker compose version
else
printf 'WARNING: Docker Compose v2 is unavailable\n'
fi
printf 'OK: Docker setup completed\n'
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=00-platform-guard.inc
source "$SCRIPT_DIR/00-platform-guard.inc"
packages=(
qemu-system-x86 qemu-utils libvirt-daemon-system libvirt-clients
virtinst virt-manager bridge-utils ovmf swtpm swtpm-tools dnsmasq-base
)
if ((EUID != 0)); then
printf 'CRITICAL: libvirt setup must run as root\n' >&2
exit 2
fi
require_supported_ubuntu
if ! command -v apt-get >/dev/null 2>&1; then
printf 'CRITICAL: apt-get is required\n' >&2
exit 2
fi
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y "${packages[@]}"
systemctl enable --now libvirtd
printf '\n== Virtual machines ==\n'
virsh list --all || printf 'WARNING: unable to list virtual machines\n'
printf '\n== Virtual networks ==\n'
virsh net-list --all || printf 'WARNING: unable to list virtual networks\n'
printf 'OK: libvirt/KVM setup completed\n'
+88
View File
@@ -0,0 +1,88 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=00-platform-guard.inc
source "$SCRIPT_DIR/00-platform-guard.inc"
driver_version=""
usage() {
cat <<'EOF'
Usage: sudo ./06-nvidia-tools.sh [--install-driver VERSION]
Without --install-driver, only non-driver diagnostic tools are installed.
EOF
}
while (($# > 0)); do
case "$1" in
--install-driver)
if (($# < 2)); then
printf 'CRITICAL: --install-driver requires a VERSION\n' >&2
exit 2
fi
driver_version="$2"
if [[ ! "$driver_version" =~ ^[0-9]+$ ]]; then
printf 'CRITICAL: NVIDIA driver VERSION must contain digits only\n' >&2
exit 2
fi
shift
;;
-h|--help)
usage
exit 0
;;
*)
printf 'CRITICAL: unknown option: %s\n' "$1" >&2
exit 2
;;
esac
shift
done
if ((EUID != 0)); then
printf 'CRITICAL: NVIDIA tooling setup must run as root\n' >&2
exit 2
fi
require_supported_ubuntu
if ! command -v apt-get >/dev/null 2>&1; then
printf 'CRITICAL: apt-get is required\n' >&2
exit 2
fi
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y nvtop clinfo pciutils
printf '\n== NVIDIA PCI devices ==\n'
lspci -nn | grep -i nvidia || printf 'INFO: no NVIDIA PCI devices detected\n'
printf '\n== NVIDIA runtime ==\n'
if command -v nvidia-smi >/dev/null 2>&1; then
nvidia-smi || printf 'WARNING: nvidia-smi returned an error\n'
else
printf 'INFO: nvidia-smi is not installed\n'
fi
printf '\n== DKMS ==\n'
if command -v dkms >/dev/null 2>&1; then
dkms status || printf 'WARNING: dkms status returned an error\n'
else
printf 'INFO: dkms is not installed\n'
fi
if [[ -n "$driver_version" ]]; then
driver_package="nvidia-driver-$driver_version"
if ! apt-cache show "$driver_package" >/dev/null 2>&1; then
printf 'CRITICAL: requested NVIDIA driver package is unavailable: %s\n' \
"$driver_package" >&2
exit 1
fi
DEBIAN_FRONTEND=noninteractive apt-get install -y "$driver_package"
printf 'WARNING: NVIDIA driver %s was installed; reboot before validation\n' \
"$driver_version"
else
printf 'OK: NVIDIA diagnostic tools installed; no driver was installed\n'
fi
+67
View File
@@ -0,0 +1,67 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=00-platform-guard.inc
source "$SCRIPT_DIR/00-platform-guard.inc"
JOURNAL_SOURCE="$SCRIPT_DIR/../files/systemd/journald-ailab-limits.conf"
JOURNAL_DEST="/etc/systemd/journald.conf.d/ailab-limits.conf"
SYSCTL_SOURCE="$SCRIPT_DIR/../files/sysctl/99-ailab.conf"
SYSCTL_DEST="/etc/sysctl.d/99-ailab.conf"
install_config() {
local source_path="$1"
local destination_path="$2"
local mode="$3"
local backup
install -d -m 0755 "$(dirname "$destination_path")"
if [[ -f "$destination_path" ]] && cmp -s "$source_path" "$destination_path"; then
printf 'OK: %s is already current\n' "$destination_path"
return 0
fi
if [[ -f "$destination_path" ]]; then
backup="${destination_path}.$(date '+%Y%m%d-%H%M%S').bak"
install -m "$mode" "$destination_path" "$backup"
printf 'INFO: backed up %s to %s\n' "$destination_path" "$backup"
fi
install -m "$mode" "$source_path" "$destination_path"
printf 'OK: installed %s\n' "$destination_path"
}
if ((EUID != 0)); then
printf 'CRITICAL: tuning setup must run as root\n' >&2
exit 2
fi
require_supported_ubuntu
for source_path in "$JOURNAL_SOURCE" "$SYSCTL_SOURCE"; do
if [[ ! -r "$source_path" ]]; then
printf 'CRITICAL: required configuration is missing: %s\n' "$source_path" >&2
exit 2
fi
done
if ! command -v sysctl >/dev/null 2>&1 || ! command -v systemctl >/dev/null 2>&1; then
printf 'CRITICAL: sysctl and systemctl are required\n' >&2
exit 2
fi
if ! command -v sensors-detect >/dev/null 2>&1 || \
! systemctl cat sysstat.service >/dev/null 2>&1; then
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y lm-sensors sysstat
fi
install_config "$JOURNAL_SOURCE" "$JOURNAL_DEST" 0644
install_config "$SYSCTL_SOURCE" "$SYSCTL_DEST" 0644
sysctl --system
systemctl restart systemd-journald
systemctl enable --now sysstat
if command -v sensors-detect >/dev/null 2>&1; then
sensors-detect --auto || printf 'WARNING: sensors-detect did not complete successfully\n'
fi
printf 'OK: host tuning completed\n'
+61
View File
@@ -0,0 +1,61 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=00-platform-guard.inc
source "$SCRIPT_DIR/00-platform-guard.inc"
enable_ufw=0
usage() {
cat <<'EOF'
Usage: sudo ./08-security-baseline.sh [--enable-ufw]
Installs fail2ban and UFW. UFW is enabled only with the explicit flag.
EOF
}
while (($# > 0)); do
case "$1" in
--enable-ufw)
enable_ufw=1
;;
-h|--help)
usage
exit 0
;;
*)
printf 'CRITICAL: unknown option: %s\n' "$1" >&2
exit 2
;;
esac
shift
done
if ((EUID != 0)); then
printf 'CRITICAL: security baseline setup must run as root\n' >&2
exit 2
fi
require_supported_ubuntu
if ! command -v apt-get >/dev/null 2>&1; then
printf 'CRITICAL: apt-get is required\n' >&2
exit 2
fi
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y fail2ban ufw
systemctl enable --now fail2ban
if ((enable_ufw == 1)); then
printf 'WARNING: UFW was explicitly requested; SSH and Cockpit rules will be added before enablement\n'
ufw allow OpenSSH
ufw allow 9090/tcp comment 'Cockpit'
ufw --force enable
else
printf 'WARNING: UFW is installed but was not enabled; use --enable-ufw after reviewing access requirements\n'
fi
ufw status verbose || printf 'WARNING: unable to read UFW status\n'
printf 'OK: security baseline completed\n'
+69
View File
@@ -0,0 +1,69 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
section() {
printf '\n== %s ==\n' "$1"
}
run_optional() {
local description="$1"
shift
if "$@"; then
return 0
fi
printf 'WARNING: %s failed\n' "$description"
return 0
}
section "Failed systemd units"
if command -v systemctl >/dev/null 2>&1; then
run_optional "failed systemd unit report" systemctl --failed --no-pager
section "Selected service status"
for unit in cockpit.socket docker.service libvirtd.service fail2ban.service; do
if systemctl cat "$unit" >/dev/null 2>&1; then
run_optional "$unit status" systemctl status "$unit" --no-pager
else
printf 'INFO: %s is not installed\n' "$unit"
fi
done
else
printf 'WARNING: systemctl is unavailable\n'
fi
section "Docker"
if command -v docker >/dev/null 2>&1; then
run_optional "Docker container list" docker ps
else
printf 'INFO: Docker is not installed\n'
fi
section "Libvirt"
if command -v virsh >/dev/null 2>&1; then
run_optional "libvirt guest list" virsh list --all
else
printf 'INFO: virsh is not installed\n'
fi
section "NVIDIA"
if command -v nvidia-smi >/dev/null 2>&1; then
run_optional "NVIDIA status" nvidia-smi
else
printf 'INFO: nvidia-smi is not installed\n'
fi
section "Filesystems"
run_optional "filesystem report" df -hT
section "Listening ports"
if command -v ss >/dev/null 2>&1; then
run_optional "listening port report" ss -tulpn
else
printf 'WARNING: ss is unavailable\n'
fi
printf '\nOK: postcheck completed; review warnings above\n'
exit 0