VirtualBox

First Steps

Mounting Shared Folders

Guest Additions need to be installed on the client. Then:

mount -t vboxsf [-o OPTIONS] SHARENAME MOUNTPOINT

Block Device to VM

Use Case: Install any OS on a USB drive:

  • sudo fdisk -l to find the drive, e.g. /dev/sdd
  • Create a VM with this drive
  • mount an iso into the VM’s CD drive
  • install on the drive using the VM
  • profit

vbox_blockdevice_vm.sh

bash vbox_blockdevice_vm.sh /dev/sdd ~/isos/xubuntu-14.04.4-desktop-amd64.iso

Static IP on Linux Host

Goal: make virtual machine (guest) available on your LAN

I own this place

Change VM and router (dhcp server, dns server) settings, aka. “I own this place”.

  • the good: any PC on your LAN can access the VM under its name
  • the bad: you need full control over dhcp and dns in your network
  1. change network settings of VM
    • Bridged
    • choose host interface that’s connected to the LAN
    • (if you did this before, click “settings symbol” and set old MAC address (see ifconfig of guest))
  2. set “static” IP address
    • go to your DHCP server
    • set reserved IP for guest’s MAC address
    • (set name for guest’s “static” IP address)
  3. boot VM, start ethernet with dhcp
    • e.g. via /etc/network/interfaces
    • ifdown eth0
    • ifup eth0

I don’t need no host names

Change VM only.

  • the good: easy setup
  • the bad: machines other that the host can access the guest only via its IP address
  1. do I own this place, step 1
  2. set static IP-address on guest in same subnet as host
  3. adapt /etc/hosts on host

IP Address in /etc/issue

cat<<'EOF' > /etc/issue.template
Ubuntu 12.04.1 LTS \n \l
username: root
password: toor
ip address: IP_ADDRESS
EOF

cp /etc/rc.local /var/backup/
# note the interface eth0 in the following block
cat<<'EOF' > /etc/rc.local
ip_address=`ifconfig eth0 | awk '/inet addr/ {print $2}' | cut -f2 -d:`
sed -e "s/IP_ADDRESS/$ip_address/" /etc/issue.template > /etc/issue
exit 0
EOF

Headless Guest

Import an OVA and make a snapshot:

# list import options
vboxmanage import --dry-run ubuntu_server_12.04.1_x64.ova
# import
vboxmanage import ubuntu_server_12.04.1_x64.ova --vsys 0 --unit 4 --ignore --unit 5 --ignore --unit 7 --ignore --cpus 4 --memory 2048
vboxmanage showvminfo ubuntu_server_12.04.1_x64
# snapshot
vboxmanage snapshot ubuntu_server_12.04.1_x64 take "initial" --description "vanilla directly after ova import"

Clone a machine:

# linked clone
vboxmanage clonevm "ubuntu_server_12.04.1_x64" --snapshot "initial" --mode "machine" --options "link" --name "salt-master" --register

Start / Stop:

vboxmanage startvm salt-master --type headless
vboxmanage controlvm salt-master poweroff

Enable NAT, forward SSH and make a shortcut:

vboxmanage modifyvm salt-master --nic1 nat

add_public_forward() {
  box=$1
  host_port=$2
  guest_port=$3
  name="public-${local_port}-${guest_port}"
  vboxmanage modifyvm $box --natpf1 "$name,tcp,,$host_port,,$guest_port"
}
remove_public_forward() {
  box=$1
  host_port=$2
  guest_port=$3
  name="public-${local_port}-${guest_port}"
  vboxmanage modifyvm $box --natpf1 delete $name
}
add_local_forward() {
  box=$1
  host_port=$2
  guest_port=$3
  name="local-${local_port}-${guest_port}"
  vboxmanage modifyvm $box --natpf1 "$name,tcp,127.0.0.1,$host_port,,$guest_port"
}
remove_local_forward() {
  box=$1
  host_port=$2
  guest_port=$3
  name="local-${local_port}-${guest_port}"
  vboxmanage modifyvm $box --natpf1 delete $name
}
list_forwards() {
  box=$1
  vboxmanage showvminfo $box | grep Rule
}

add_local_forward salt-master 2222 22
# undo: remove_local_forward salt-master 2222 22

# ssh config
cat <<EOF >> ~/.ssh/config
Host salt-master
  Hostname 127.0.0.1
  Port $local_port
  User root
EOF

Enable remote desktop (optional):

vboxmanage modifyvm salt-master --vrde on
vboxmanage modifyvm salt-master --vrdeauthtype external
username=felix
password=changeme
vboxmanage setextradata salt-master "VBoxAuthSimple/users/$username" $(vboxmanage internalcommands passwordhash "$password" | awk '{ print $3; }')
# undo on the fly: vboxmanage controlvm salt-master vrde off
# undo when down: vboxmanage modifyvm salt-master --vrde off

Check ports openend by us:

netstat -anp | grep 222
netstat -anp | grep 3389

For inter-machine networking, add internal network named close-circle on NIC 2 and enable dhcp server:

# for each VM
box=salt-master
vboxmanage modifyvm $box --nic2 intnet
vboxmanage modifyvm $box --intnet2 close-circle

vboxmanage dhcpserver add --netname close-circle --ip 10.1.1.254 --netmask 255.255.255.0 --lowerip 10.1.1.1 --upperip 10.1.1.99 --enable
vboxmanage list dhcpservers

Resize Disk

Resize the VDI image:

vboxmanage modifyhd <hd-name-vdi> --resize 40000

Add Live CD image, e.g. crunchbang:

thunar-volman-settings  # disable automatic mounting, which would interfere with the resize
gparted
If it is a VMDK image:
If you have Snapshots:
Navigate to snapshot: Right click ‣ Clone

File ‣ Virtual Media Manager ‣ Copy as VDI

Nice post about cloning snapshots: https://forums.virtualbox.org/viewtopic.php?f=1&t=791#p106206

Compact Disk

live CD boot, then:

apt-get install zerofree || apt-get update && apt-get install zerofree
zerofree /dev/sda1

shutdown, then:

vboxmanage modifyhd foo.vdi --compact

vboxmanage Cheat Sheet

vboxmanage list vms

Change default storage location:

vboxmanage setproperty machinefolder ~/VMs

New Box from VDI:

box=
vboxmanage list ostypes
os_type=
# create
vboxmanage createvm --name $box --ostype $os_type --register

# DELETE == undo create
vboxmanage unregistervm $box --delete

# add storage controller
vboxmanage storagectl $box --name "SATA Controller" --add sata --controller IntelAHCI

# attach image
image=
vboxmanage storageattach $box --storagectl "SATA Controller" --port 0 --device 0 --type hdd --medium $image

# set mem to 8GB
vboxmanage modifyvm $box --memory 8192

Snapshot:

vboxmanage snapshot $box take "foo" --description "bar"

Links:

USB-Stick to Virtual Machine

Let /dev/sdc be a USB Drive that should run in a VM. Run the following once:

# make an iso
dd if=/dev/sdc of=~/my_image.iso

# mount the iso as block device
sudo losetup /dev/loop0 ~/my_image.iso

# make a vmdk for it
vboxmanage internalcommands createrawvmdk -filename ~/VMs/my_image.vmdk -rawdisk /dev/loop0

# create VM
vboxmanage createvm --name loop0vm --register
vboxmanage storagectl loop0vm --name sata --add sata --controller IntelAhci --portcount 1
vboxmanage storageattach loop0vm --storagectl sata --port 0 --device 0 --type hdd --medium ~/VMs/loop0vm.vmdk
vboxmanage startvm loop0vm --type gui
vboxmanage setextradata loop0vm VBoxInternal/CPUM/CMPXCHG16B 1

You can now start the machine. After rebooting the host, you need to re-mount the file as block device before starting the VM:

sudo losetup /dev/loop0 ~/my_image.iso

Windows 8 Guest Screen Resolution

This works without installing Guest Additions:

vboxmanage setextradata $box CustomVideoMode1 1920x1080x32

Thanks go to http://superuser.com/questions/497173/windows-8-screen-resolution-in-virtualbox

Xen Partition Image to Virtualbox

Jiffybox uses Xen. Backups contain raw partition images.

Those are not disk images, so there is no partition table, no bootloader and no mbr.

To boot those, you can either

  1. create a separate boot image or
  2. create an image containing everything.

The benefit of a) is speed. Only the boot image needs to be created, so this is the way to go to quickly run a backup image.

On the other hand b) is more convenient, because you get a single VDI that Just Works. The problem is that you need to copy the whole partition to a new image.

Use Loopbacks and raw images

Unpack the tarfile. This might take a while:

tarfile=
tar xf $tarfile

Prep stuff:

mkdir {boot,root}

Prepare the boot image:

dd if=/dev/zero of=boot.img count=1 bs=10MiB
echo 'n
p
1
2048

a
1
w
' | fdisk boot.img

file boot.img

Install grub. Using kpartx is important here, so Grub thinks it installs to a real device. I tried “losetup -P” to no avail.

sudo kpartx -av boot.img
# sets up /dev/loop0 and /dev/mapper/loop0p1
sudo mkfs.ext2 -L boot /dev/mapper/loop0p1
sudo mount /dev/mapper/loop0p1 boot
sudo grub-install --target=i386-pc --recheck --boot-directory=boot/boot /dev/loop0

Mount the raw partition:

raw=$(ls -S *.raw | head -n1)  # the big one
ls -l $raw
sudo losetup /dev/loop1 $raw
sudo mount /dev/loop1 root/

Configure the boot image. First, convert legacy Grub’s menu.lst to Grub 2 grub.cfg. Then tell grub to look at the second drive, i.e. hd0 and sdb respectively:

sudo grub-menulst2cfg root/boot/grub/menu.lst boot/boot/grub/grub.cfg
sudo sed -i -e 's;(hd0);(hd1);' boot/boot/grub/grub.cfg
sudo sed -i -e 's;root=/dev/xvda;root=/dev/sdb;' boot/boot/grub/grub.cfg

Create a VM using both images:

box=foo
vboxmanage createvm --name $box --register
vboxmanage storagectl $box --name sata --add sata --controller IntelAhci --portcount 2

vboxmanage internalcommands createrawvmdk -filename raw-boot.vmdk -rawdisk /dev/loop0
vboxmanage internalcommands createrawvmdk -filename raw-root.vmdk -rawdisk /dev/loop1
vboxmanage storageattach $box --storagectl sata --type hdd --device 0 --port 0 --medium raw-boot.vmdk
vboxmanage storageattach $box --storagectl sata --type hdd --device 0 --port 1 --medium raw-root.vmdk

Tweak VM (NAT, RAM, CPU):

vboxmanage modifyvm $box --nic1 nat
vboxmanage modifyvm $box --natpf1 "guestssh,tcp,,2222,,22"
vboxmanage modifyvm $box --memory 2048
vboxmanage modifyvm $box --cpus 3

We could package the boot image as a VDI:

vboxmanage convertfromraw boot.img boot.vdi --format VDI
vboxmanage storageattach $box --storagectl sata --port 0 --device 0 --type hdd --medium boot.vdi
# let the media registry forget about the raw boot image
vboxmanage closemedium raw-boot.vmdk

Test it. If it does not work, iterate:

vboxmanage storageattach $box --storagectl sata --port 0 --device 0 --type hdd --medium none
vboxmanage closemedium boot.vdi --delete
vboxmanage convertfromraw boot.img boot.vdi --format VDI
vboxmanage storageattach $box --storagectl sata --port 0 --device 0 --type hdd --medium boot.vdi

Complete VDI

Thanks to https://blog.filippo.io/converting-a-partition-image-to-a-bootable-disk-image/

Note that this involves a lot of copying:

  1. from raw to partition in new image
  2. from new image to vdi

Tools i did not have before following Filippo’s post:

sudo apt-get install pv

And here’s the paste:

dd if=/dev/zero of=new.img count=1 bs=1MiB
raw=$(ls -S *.raw | head -n1)  # the big one
pv $raw >> new.img

echo 'n
p
1
2048

a
w
' | fdisk new.img


sudo kpartx -av new.img
mkdir new
sudo mount /dev/mapper/loop0p1 new
sudo grub-install --target=i386-pc --recheck --boot-directory=new/boot /dev/loop0

sudo grub-menulst2cfg new/boot/grub/menu.lst new/boot/grub/grub.cfg
sudo sed -i -e 's;(hd0);(hd0,1);' new/boot/grub/grub.cfg
sudo sed -i -e 's;root=/dev/xvda;root=/dev/sda1;' new/boot/grub/grub.cfg
sudo kpartx -dv new.img

Try it raw:

box=bar
vboxmanage createvm --name $box --register
vboxmanage storagectl $box --name sata --add sata --controller IntelAhci --portcount 1

vboxmanage internalcommands createrawvmdk -filename raw-new.vmdk -rawdisk /dev/loop0
vboxmanage storageattach $box --storagectl sata --type hdd --device 0 --port 0 --medium raw-new.vmdk

vboxmanage modifyvm $box --nic1 nat
vboxmanage modifyvm $box --natpf1 "guestssh,tcp,,2223,,22"
vboxmanage modifyvm $box --memory 2048
vboxmanage modifyvm $box -ioapic on
vboxmanage modifyvm $box --cpus 3

vboxmanage startvm $box --type headless

OK, convert to VDI:

vboxmanage controlvm $box acpipowerbutton
vboxmanage convertfromraw boot.img boot.vdi --format VDI

Troubleshooting

Could not find an open hard disk with UUID

https://www.virtualbox.org/ticket/8595

Transcript:

  • Close out of VirtualBox
  • Open the .vbox file for the VM in a text editor. Look for a section towards the end of the file labeled <Image uuid=”[the UUID from the error message]”> and delete the whole <AttachedDevice> section around it.
  • Reopen VirtualBox
  • Open the Settings for the VM and reattach the hard disk file.