Skip to content

Manual VM Creation

Extreme Circumstances Only

Where full hardware virtualization and manual input are needed to test (e.g. secure boot requiring manual steps). Explicit reasons for using this test framework MUST BE clearly documented in molecule.yml.

These cannot be automated and should always be flag protected. Test should pass without flag to ensure molecule test --all executes without failure.

System Images Used

Create VM

Use vagrant-like configuration to maintain similarities with other VM tests. Always use absolute paths as some options do not resolve paths.

Create and list VM

mkdir /home/${USER}/VirtualBox VMs/debian-12-efi-template
vboxmanage list ostypes
vboxmanage createvm \
  --basefolder '/home/${USER}/VirtualBox VMs/debian-12-efi-template' \
  --ostype debian12_64 \
  --default \
  --register \
  --name 'debian-12-efi-template'
vboxmanage list vms
export UUID={UUID}  # Always reference with UUID.
vboxmanage showvminfo ${UUID}

Use bridged networking (if needed)

vboxmanage modifyvm ${UUID} --nic1 bridged
vboxmanage modifyvm ${UUID} --bridgeadapter1 {DEVICE}  # Host linux device.
Reference:

Enable UEFI and load certificates

# enable EFI. alternatives: efi, efi32.
vboxmanage modifyvm ${UUID} --cpus 2 --memory 4096 --firmware efi64
vboxmanage modifynvram $UUID inituefivarstore  # Reset NVRAM state.
# Load default MS KEK/DB signatures for secure boot.
vboxmanage modifynvram $UUID enrollmssignatures
# Enable default platform keys for secure boot.
vboxmanage modifynvram $UUID enrollorclpk
Reference:

Secure Boot Toggle

Secure boot state cannot be changed with mokutil in VM; explicitly set state to disabled for base testing and enable when needing to test final state.

vboxmanage modifynvram $UUID secureboot --disable

Attach Storage

vboxmanage createmedium \
  disk --size 6000 \
  --format vdi \
  --filename '/home/${USER}/VirtualBox VMs/debian-12-efi-template/disk.vdi'
vboxmanage storageattach ${UUID} \
  --storagectl 'SATA' \
  --device 0 \
  --port 1 \
  --type hdd \
  --medium '/home/${USER}/VirtualBox VMs/debian-12-efi-template/disk.vdi'
vboxmanage storageattach ${UUID} \
  --storagectl 'SATA' \
  --port 2 \
  --type dvddrive \
  --medium '/home/${USER}/debian-12.8.0-amd64-netinst.iso'

Start VM

vboxmanage startvm ${UUID}
Reference:

Base OS Install

  • Hostname: debian
  • Domain: {EMPTY}
  • users (password):
    • root (vagrant)
    • vagrant (vagrant)
  • guided partition:
    • whole disk
    • one partition
    • overwrite
  • packages:
    • ssh
    • standard system utilities

Reboot once complete.

Install vagrant SSH keys

wget https://raw.githubusercontent.com/hashicorp/vagrant/refs/heads/main/keys/vagrant.pub -O /root/.ssh/authorized_keys
Reference:

Zero disk and clear history

Enables high compression when imaged and a clean system state.

apt get clean
dd if=/dev/zero of=/EMPTY bs=1M
rm -f /EMPTY
cat /dev/null > ~/.bash_history && history -c && exit
Reference:

Shutdown and Image VM

VBoxManage controlvm ${UUID} acpipowerbutton
# Backup virtualbox image pristine w/ disk.
vboxmanage export ${UUID} --output exported-debian-12-efi.ovf --ovf20
Reference:

Manually export image and import into vagrant

Export machine for vagrant use. Does not enable automatic VM load unless image is also published.

vagrant package --base ${UUID} --output ucs.box  # Template VM UUID.
# Use 'vagrant-debian' in molecule tests.
vagrant box add ucs.box --name vagrant-debian

Manual VM Molecule Setup

Standard Molecule setup for manual VM (see Molecule).

Copy vagrant SSH keys

Vagrant SSH keys are published here.

  • molecule/id.{pub,key} for use in all molecule tests.
  • molecule/{TEST}/id.{pub,key} for specific molecule tests.

Set restricted permissions

Molecule will fail SSH connections and not mention permissions issues.

chmod 0400 id.*

molecule.yml (1)

  1. 0644 {USER}:{USER}
provisioner:
  inventory:
    group_vars:
      all:
        ansible_ssh_user: 'root'  # Molecule users logged in user by default.
        ansible_ssh_private_key_file:
          '{{ lookup("env", "MOLECULE_PROJECT_DIRECTORY") }}/molecule/id.key'
        # For key only in test location.
        # ansible_ssh_private_key_file:
        #   '{{ lookup("env", "MOLECULE_EPHEMERAL_DIRECTORY") }}/id.key'
platforms:
  - name: '192.168.1.10'  # VM IP.

create.yml (1)

This is an exact copy of default create with provisioning disabled.

  1. 0644 {USER}:{USER}

---
- name: 'Create'
  hosts: 'localhost'
  connection: 'local'
  gather_facts: false
  tasks:
    - name: 'Create | molecule inventory'
      ansible.builtin.debug:
        msg: skipping provisioning

    - name: 'Create | populate instance config'
      ansible.builtin.set_fact:
        instance_conf_dict: {'instance': '{{ item.name }}'}
      loop: '{{ molecule_yml.platforms }}'
      register: instance_config_dict
Reference: