#!/bin/bash # ============================================================================== # FINGERPRINT LIBRARY: Hardware Inventory Collection # ============================================================================== # Part of unified bootstrap system for homelab infrastructure # Collects comprehensive hardware facts and generates structured YAML output # compatible with gather_hardware_facts.yml playbook format. # ============================================================================== # Source detection library if not already loaded if ! type -t detect_os_family &>/dev/null; then SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=./detection.sh source "${SCRIPT_DIR}/detection.sh" fi # --- HARDWARE FACT COLLECTION --- collect_cpu_facts() { # Collect CPU information in structured format # Returns JSON-like structured data local cpu_model=$(grep "model name" /proc/cpuinfo | head -n1 | cut -d: -f2 | xargs) local cpu_cores=$(nproc 2>/dev/null || echo "unknown") local cpu_vendor=$(detect_cpu_vendor) local cpu_gen=$(detect_cpu_generation) local cpu_arch=$(uname -m) # Get CPU frequency (current) local cpu_freq_mhz=$(grep "cpu MHz" /proc/cpuinfo | head -n1 | awk '{print $4}' | cut -d. -f1) # Get CPU max frequency if available local cpu_max_freq="unknown" if [ -f /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq ]; then local freq_khz=$(cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq) cpu_max_freq=$((freq_khz / 1000)) fi cat </dev/null; then local block_devices=$(lsblk -d -n -o NAME,SIZE,TYPE | grep disk | awk '{printf " - { name: \"%s\", size: \"%s\" }\n", $1, $2}') if [ -n "$block_devices" ]; then cat </dev/null | awk '/^default/ {print $3; exit}') cat </dev/null | grep "link/ether" | awk '{print $2}') cat </dev/null || echo "unknown") cat </dev/null; then local nvidia_driver=$(nvidia-smi --query-gpu=driver_version --format=csv,noheader 2>/dev/null | head -n1) local nvidia_cuda=$(nvidia-smi --query-gpu=compute_cap --format=csv,noheader 2>/dev/null | head -n1) cat </dev/null || echo "$hostname") if [ -f /etc/os-release ]; then . /etc/os-release local os_name="$NAME" local os_version_id="$VERSION_ID" fi cat </dev/null && echo "true" || echo "false") local virt_type=$(systemd-detect-virt 2>/dev/null || echo "none") cat </dev/null; then local pve_version=$(pveversion | head -n1 | awk '{print $2}') cat <&2 # Memory requirements case "$hw_type" in proxmox) if [ "$mem_gb" -lt 8 ]; then echo " - \"WARNING: Proxmox host has ${mem_gb}GB RAM (minimum 8GB recommended)\"" >&2 ((violations++)) fi ;; docker-vm|physical-docker) if [ "$mem_gb" -lt 4 ]; then echo " - \"WARNING: Docker host has ${mem_gb}GB RAM (minimum 4GB recommended)\"" >&2 ((violations++)) fi ;; esac # Disk space if [ "$disk_gb" -lt 20 ]; then echo " - \"WARNING: Low disk space (${disk_gb}GB) - minimum 20GB recommended\"" >&2 ((violations++)) fi # CPU cores if [ "$cpu_cores" -lt 2 ]; then echo " - \"WARNING: Single CPU core detected - minimum 2 recommended\"" >&2 ((violations++)) fi if [ $violations -eq 0 ]; then echo " - \"OK: Hardware meets minimum standards\"" >&2 fi return $violations } # --- STRUCTURED OUTPUT --- generate_hardware_facts_yaml() { # Generate complete hardware facts in YAML format # Compatible with gather_hardware_facts.yml output local hostname=$(hostname) cat < "$output_file" echo "$output_file" } # --- ANSIBLE INVENTORY GENERATION --- generate_ansible_inventory_snippet() { # Generate Ansible inventory entry for this host # Can be appended to discovered-hosts.yml local hostname=$(hostname) local current_ip=$(get_current_ip) local hw_type=$(detect_hardware_type) local os_family=$(detect_os_family) # Determine inventory group local inventory_group="docker_hosts" case "$hw_type" in proxmox) inventory_group="proxmox_cluster" ;; docker-vm) inventory_group="swarm_managers" # Or swarm_workers, requires manual classification ;; pi) inventory_group="control_nodes" ;; ai-workstation) inventory_group="ai_nodes" ;; esac cat < "$inventory_file" </dev/null; then echo "Host $hostname already in discovered inventory, skipping" >&2 return 0 fi # Append generate_ansible_inventory_snippet >> "$inventory_file" echo "" >> "$inventory_file" echo "$inventory_file" } # --- OUTPUT FORMAT OPTIONS --- generate_json_output() { # Generate JSON format instead of YAML (for monitoring integration) # Converts YAML facts to JSON local hostname=$(hostname) local current_ip=$(get_current_ip) local hw_type=$(detect_hardware_type) local os_family=$(detect_os_family) local cpu_cores=$(nproc) local mem_gb=$(grep MemTotal /proc/meminfo | awk '{print int($2/1024/1024)}') local disk_gb=$(df -BG / | awk 'NR==2 {print $2}' | sed 's/G//') cat <&2 <