Start virtual machine at reboot

Hello!
I am currently facing a problem concerning the autostart at reboot of my virtual machine.
The virtual machine was created in advance and all installations are already successfully done.
Means I can run a script saved in /bin folder and I am able to reach the vm via remote-access.
The start-command and stop-command also work pretty well.

The problem now is that it tells me "unknown command: faststart" when rebooting.
As I'm quite new to rc.d scripting, I don't understand the code of rc.subr and as a result I have no idea how to tell my script to use the prefix start and how.
Would be great if anyone could help me there, although it might be a stupid question. Thanks in advance!
Code:
#!/bin/sh
# PROVIDE: samplevm
# REQUIRE: DAEMON NETWORKING dmesg
# BEFORE: LOGIN TcSystemService
# KEYWORD: nojail shutdown
. /etc/rc.subr
name="samplevm"
rcvar="${name}_enable"
command="/usr/local/sbin/${name}"
start_cmd="${command} start > /dev/null 2>&1 &"
stop_cmd="${command} stop > /dev/null 2>&1 &"
status_cmd="${command} status"
load_rc_config "${name}"
set -e
set -u
usage() {
    cat >&2 << EOF
USAGE: ${0##*/} [COMMAND]
Control the virtual machine environment named '${name}'
COMMANDS:
    start       Start the VM
    stop        Shutdown the running VM
    help        Print this help message
EXAMPLES
# run the virtual machine
${0##*/} start
# shutdown the virtual machine
${0##*/} stop
EOF
}
        
# Cleanup any resources used by the VM after shutdown
cleanup() {
    # do not trap during cleanup procedure
    trap '' EXIT
    set +e
    set +u
    pfctl -a "bhf/bhyve/${vm_name}" -f /dev/null > /dev/null 2>&1
    if test -e "${temp_firewall_rules}"; then
        rm "${temp_firewall_rules}"
    fi
}

prepare_host() {
    # Ensure that kernel modul vmm.ko is loaded
    kldload -n vmm.ko
    # accept incoming VNC connections
    temp_firewall_rules="/etc/pf.conf.d/${vm_name}"
    printf "pass in quick proto tcp to port %s\n" "${vm_vnc_port}" > "${temp_firewall_rules}"
    pfctl -a bhf/bhyve/"${vm_name}" -f "${temp_firewall_rules}"
}
run_vm(){
    trap 'cleanup' EXIT
    prepare_host
    while true; do


# destroy former VM instance to ensure we start
# with a clean VM configuration
    if test -e /dev/vmm/vms/samplevm; then
        bhyvectl --vm=${name} --destroy
        echo "current VM was beeing destroyed in order to restart"
    fi
#check if mountpoint exists
    if !(zfs list -H -o mountpoint | grep -q ${vm_path}); then
        echo "create mountpoint for ${name}"
        zfs create -p -o mountpoint=${vm_path} zroot${vm_path}
    else 
        echo "mountpoint exists"
    fi
#create a disk for the virtual machine, size of 40GB is necessarily needed for Windows 10 installation
    if !(zfs list | grep -q "zroot${vm_path}/disk0"); then
        echo "create new disk: disk0"
        zfs create -V 50G zroot${vm_path}/disk0
    else
        if !(zfs get volsize zroot${vm_path}/disk0 | grep -q "50G"); then
        echo "adjust size of disk0 to 50GB"
            zfs set volsize=50G zroot${vm_path}/disk0
        fi
        echo "use existing disk0"
    fi
# create an interface for the virtual machine 
    if !(ifconfig | grep -q tap0); then
        echo "create new tap: tap0"
        ifconfig tap create
        if !(grep "cloned_interfaces" /etc/rc.conf | grep -q "tap0"); then
            echo "save persistant configurations for tap0 in rc.conf"
            sysrc cloned_interfaces+="tap0"
        fi
    else 
        echo "tap0 exists and is saved"
    fi
# create a bridge if not already existing
    if !(ifconfig | grep -q bridge0); then
        echo "create new bridge"
        ifconfig bridge create
    else 
        echo "bridge0 exists"
    fi
    # set configuration in rc.conf
    if !(grep "cloned_interfaces" /etc/rc.conf | grep -q "bridge0"); then
        echo "save persistant configurations for bridge0 in rc.conf"
        sysrc cloned_interfaces+="bridge0"
    fi
    if !(grep -q "ifconfig_bridge0" /etc/rc.conf); then
        echo "save persistant bridge settings in rc.conf"
        sysrc ifconfig_bridge0="addm igb1 addm tap0"
    fi
    
# set ppt driver (PCI PassThrough)
    if (pciconf -l | grep -q "igb2@pci0:3:0:0:"); then 
        devctl set driver -f pci0:3:0:0 ppt
        echo "pass through driver is set to igb2"
    elif (pciconf -l | grep -q "ppt0@pci0:3:0:0:"); then
        echo "pass through driver was already set to igb2"
    fi 
    if !(grep -q "3/0/0" /boot/loader.conf); then
        echo "pptdevs="3/0/0"" >> /boot/loader.conf
        echo "ppt configuration set persistantly in boot/loader.conf"
    else 
        echo "configurations for pptdev for igb2 persistantly saved"
    fi
    if !(test -e ${vm_path}/BHYVE_BHF_UEFI_VARS.fd); then
        if test -d ${vm_path}; then
            echo "copy VARS-file in samplevm directory"
            cp /usr/local/share/uefi-firmware/BHYVE_BHF_UEFI_VARS.fd ${vm_path}/;
        else
            echo "create samplevm-directory and copy VARS-file"
            mkdir -m a+rwx ${vm_path}
            cp /usr/local/share/uefi-firmware/BHYVE_BHF_UEFI_VARS.fd ${vm_path}/;
        fi 
    elif (test -e /vms/samplevm/BHYVE_BHF_UEFI_VARS.fd); then
        echo "VARS file and directory exist"
    fi
# start a windows 10  VM instance
    bhyve \
        -c sockets=1,cores=1,threads=1 \
        -m 2G \
        -s 0,hostbridge \
        -s 10,nvme,/dev/zvol/zroot/vms/samplevm/disk0 \
        -s 20,virtio-net,tap0 \
        -s 21,passthru,3/0/0 \
        -s 30,xhci,tablet \
        -s 31,lpc \
        -l com1,stdio \
        -l bootrom,/usr/local/share/uefi-firmware/BHYVE_BHF_UEFI.fd,${vm_path}/BHYVE_BHF_UEFI_VARS.fd \
        -H -P -A -S ${name}
done
}
shutdown_vm() {
    trap '' EXIT
    set +e
    set +u
    kill "${_pid}"
}
get_bhyve_pid() {
    printf "%s" "$(pgrep -f "bhyve: ${name}")"
}
# root permissions are required to run VMs
    if test "$(id -u)" -ne 0; then
        printf "file must be run as root\n"
        exit 1
    fi
# Default values for VM configuration
readonly vm_vnc_port="5900"
readonly vm_path="/vms/samplevm"
readonly _cmd="${1?Error: No COMMAND specified$(usage)}"
_pid="$(get_bhyve_pid)"
case "${_cmd}" in
    start)
        if test -z "${_pid:+x}"; then
            run_vm
        else
            printf "%s is already running with pid: %s\n" "${name}" "${_pid}"
            exit 1
        fi
        ;;
    stop)
        if ! test -z "${_pid:+x}"; then
            shutdown_vm
        fi
        ;;
    status)
        if ! test -z "${_pid:+x}"; then
            printf "'%s' is running with pid: %s\n" "${name}" "${_pid}"
        else
            printf "'%s' is not running.\n" "${name}"
        fi
        ;;
    -h | --help | help)
        usage
        ;;
    *)
        usage
        printf "Unknown COMMAND: '%s'\n" "${_cmd}"
        exit 1
        ;;
esac

run_rc_command "$1"
 
Thank you for your reply!
I already use those two, but I found a possible solution for problem meanwhile. I just had to add
faststart)
vm_run
;;
so that the faststart could be recognized. Although I'm still not sure if this is a good way to solve the problem with the autostart...
 
Fyi, a short rc script,
 
Although I'm still not sure if this is a good way to solve the problem with the autostart...
That entire case "${_cmd}" in thing needs to go, that's not how it's supposed to work.

There are a couple of 'standard' functions already defined, you just need to overrule those. So define a function samplevm_start,samplevm_stop and samplevm_status. You don't need anything that calls these, the backend scripts already call the right function, no need to do this yourself. If you want to add some additional functions, you set extra_commands="faststart" and define a samplevm_faststart function. Then you can do service samplevm faststart.

Don't do this:
Code:
# Default values for VM configuration
readonly vm_vnc_port="5900"
readonly vm_path="/vms/samplevm"
Do this instead:
Code:
: ${samplevm_enable:="NO"}
: ${samplevm_vncport:="5900"}
: ${samplevm_path:="/vms/samplevm"}
Now you have some sane defaults and you can set them in rc.conf:
Code:
samplevm_enable="YES"
samplevm_vncport="5901"
samplevm_path="/some/where/else"
If they're not set in rc.conf the default values will be used (in this case 5900 and /vms/samplevm). The *_enable should always default to "NO", in other words, services have to be explicitly enabled in rc.conf and should never automatically start.
 
Thank you all for your replies! I changed the readonly variables as you told me, that's quite nice.
All commands, start, faststart, stop and status, work, as soon as i call them in the shell.
At reboot I get the error message: '/usr/local/etc/rc.d/samplevm: bhyve: not found' and '/usr/local/etc/rc.d/samplevm: rcvars: parameter not set'
It can't be a coding problem can it? Because the virtual machine starts without problems with the start and faststart command...
Are there any installations or configurations I forgot to set in the script?
 
Back
Top