Development Environment (Vagrant)
Create Rocky Linux 9 virtual machine for Warewulf testbed using Vagrant
Host system requirements
- CPU supports H/W virtualization. 
- KVM kernel module available and loaded. 
CPU H/W Virtualization support
Check CPU virtualization capability using following command.
If your system has Intel CPU, you will see Intel VT here, and if your system has AMD CPU, you will see AMD-V here.
lscpu | grep Virtualization
Virtualization:                  AMD-V
Virtualization type:             full
KVM kernel module
lsmod | grep kvm
ccp                   118784  1 kvm_amd
kvm                  1105920  1 kvm_amd
irqbypass              16384  1 kvm
Setup development environment on Rocky Linux 9
Install QEMU, libvirt
# Install packages
sudo dnf install -y libvirt qemu-kvm \
    libguestfs virtio-win guestfs-tools libguestfs-inspect-icons virt-win-reg \
    virt-install virt-top
# Enable and start libvirtd
sudo systemctl enable --now libvirtd
# Add user to libvirt group
sudo usermod -aG libvirt rocky
Install Cockpit (Optional)
# Install packages
sudo dnf install -y cockpit cockpit-machines
# Enable and start cockpit (http://localhost:9090)
sudo systemctl enable --now cockpit.socket
Install Vagrant, vagrant-libvirt plug-in and vagrant-reload plug-in
sudo dnf config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
sudo dnf install -y vagrant
sudo dnf group install -y "Development tools"
sudo dnf config-manager --set-enabled crb
sudo dnf install -y libvirt-devel
vagrant plugin install vagrant-libvirt
vagrant plugin install vagrant-reload
Vagrant box and Vagrantfile for Warewulf sandbox
Create Rocky Linux 9.2 vagrant box
cat << 'EOF' > box-metadata.json
{
"name" : "rockylinux/9",
"description" : "Rocky Linux 9 2.0.0",
"versions" : [
    {
    "version" : "2.0.0-20230513.0",
    "providers" : [
        {
        "name" : "libvirt",
        "url" : "https://dl.rockylinux.org/pub/rocky/9.2/images/x86_64/Rocky-9-Vagrant-Libvirt-9.2-20230513.0.x86_64.box"
        }
    ]
    }
]
}
EOF
vagrant box add box-metadata.json
Vagrantfile
mkdir -p ~/warewulf-sandbox
cd ~/warewulf-sandbox
cat << 'EOF' > Vagrantfile
Vagrant.configure("2") do |config|
    number_of_node = ENV["NODES"] || 2
    branch = ENV["BRANCH"] || "v4.5.7"
    config.vm.define :head do |head|
        head.vm.box = "rockylinux/9"
        head.vm.box_version = "2.0.0-20230513.0"
        head.vm.hostname = "warewulf"
        head.vm.network "private_network",
            ip: "192.168.200.254",
            netmask: "255.255.255.0",
            libvirt__network_name: "pxe",
            libvirt__dhcp_enabled: false
        head.vm.synced_folder ".", "/vagrant", type: "nfs", nfs_version: 4, nfs_udp: false
        head.vm.provider :libvirt do |libvirt|
            libvirt.cpu_mode = "host-passthrough"
            libvirt.memory = '8192'
            libvirt.cpus = '2'
            libvirt.machine_virtual_size = 40
        end
        head.vm.provision "shell", inline: <<-SHELL
            dnf install -y cloud-utils-growpart
            growpart /dev/vda 5
            xfs_growfs /dev/vda5
        SHELL
        head.vm.provision "shell", inline: <<-SHELL
            dnf groupinstall -y "Development Tools"
            dnf install -y epel-release
            dnf config-manager --set-enabled crb
            dnf install -y golang tftp-server dhcp-server nfs-utils gpgme-devel libassuan-devel
            cd /tmp
            git clone https://github.com/warewulf/warewulf.git
            cd warewulf
            git checkout v4.5.7
            make clean defaults \
                PREFIX=/usr \
                BINDIR=/usr/bin \
                SYSCONFDIR=/etc \
                DATADIR=/usr/share \
                LOCALSTATEDIR=/var/lib \
                SHAREDSTATEDIR=/var/lib \
                MANDIR=/usr/share/man \
                INFODIR=/usr/share/info \
                DOCDIR=/usr/share/doc \
                SRVDIR=/var/lib \
                TFTPDIR=/var/lib/tftpboot \
                SYSTEMDDIR=/usr/lib/systemd/system \
                BASHCOMPDIR=/etc/bash_completion.d/ \
                FIREWALLDDIR=/usr/lib/firewalld/services \
                WWCLIENTDIR=/warewulf
            make all
            make install
            systemctl disable --now firewalld
            sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
        SHELL
        head.vm.provision "reload"
        head.vm.provision "shell", inline: <<-SHELL
            cat << 'CONF' | sudo tee /etc/warewulf/warewulf.conf
WW_INTERNAL: 45
ipaddr: 192.168.200.254
netmask: 255.255.255.0
network: 192.168.200.0
warewulf:
  port: 9873
  secure: false
  update interval: 60
  autobuild overlays: true
  host overlay: true
  syslog: false
dhcp:
  enabled: true
  range start: 192.168.200.50
  range end: 192.168.200.99
  systemd name: dhcpd
tftp:
  enabled: true
  systemd name: tftp
nfs:
  enabled: true
  export paths:
  - path: /home
    export options: rw,sync
    mount options: defaults
    mount: true
  - path: /opt
    export options: ro,sync,no_root_squash
    mount options: defaults
    mount: false
  systemd name: nfs-server
CONF
            sed -i 's@ExecStart=/usr/bin/wwctl server start@ExecStart=/usr/bin/wwctl server start -d -v@' /usr/lib/systemd/system/warewulfd.service
            systemctl enable --now warewulfd
            wwctl configure --all
            wwctl container import docker://ghcr.io/warewulf/warewulf-rockylinux:9 rocky-9
            wwctl profile set --yes --container rocky-9 "default"
            wwctl profile set --yes --netdev eth1 --netmask 255.255.255.0 --gateway 192.168.200.254 "default"
            wwctl node add n0001.cluster -I 192.168.200.101 --discoverable true
            wwctl node add n0002.cluster -I 192.168.200.102 --discoverable true
        SHELL
    end
    (1..number_of_node).each do |i|
        config.vm.define :"n000#{i}", autostart: false do |node|
            node.vm.hostname = "n000#{i}"
            node.vm.network "private_network",
            libvirt__network_name: "pxe"
            node.vm.provider :libvirt do |compute|
                compute.cpu_mode = 'host-passthrough'
                compute.memory = '8192'
                compute.cpus = '2'
                boot_network = {'network' => 'pxe'}
                compute.boot boot_network
            end
        end
    end
end
EOF
Spin up head node
vagrant up
Spin up compute nodes
vagrant up n0001
# Wait until n0001 becomes ready
vagrant up n0002