В ходе эксплуатации этой замечательной среды виртуализации для ковыряния во внутренностях операционных систем, выяснилось, что внутри VirtualBox сокрыто множество полезностей для этого. Спешу ими поделиться.
Замечу, что сказанное в основном рекомендации касаются Unix-подобных операционных систем.
Несколько шорткатов VBoxManage
Для начала несколько полезных команд, которые лень запоминать.
Посмотреть список всех зарегестрированных и запущенных в данный момент виртуалок можно так:
# VBoxManage list vms
# VBoxManage list runningvms
Конфигурацию виртуальной машины показывает подкоманда showvminfo:
# VBoxManage showvminfo <VM-name>
Запустить виртуальную машину можно с помощью команды VBoxHeadless - при этом не создается отдельного окна, соответственно ее можно запустить в ssh-сессии сидя через GPRS-модем:
# nohup VBoxHeadless -s <VM-name> &
Чтобы получить доступ к консоли виртуальной машины потребуется пакет Extension Pack, настроить порт VRDP, после чего можно будет подключиться обычный rdesktop:
# VBoxManage modifyvm <VM-name> --vrde on --vrdeport <Номер порта>
Включить/отключить линк на 1-м сетевом интерфейсе можно например так:
# VBoxManage controlvm setlinkstate1 on|off
Чтобы подключить ISO-диск, сначала нужно выяснить полный путь до порта, к которому он будет подключен в выводе подкоманды showvminfo:
IDE контроллер (1, 0): /home/myaut/shared/ISO/linux/CentOS-5.6-x86_64-LiveCD.iso
Если соответствующего контролера нет, его можно создать через подкоманду storagectl. Подключим другой ISO-диск к этому порту:
# VBoxManage storageattach CentOS-MPI1 --storagectl 'IDE контроллер' \
--port 1 --device 0
--type dvddrive
\
--medium '/home/myaut/shared/ISO/linux/CentOS-5.8-x86_64-bin-DVD-1of2.iso'
Посылаем NMI или комбинацию SysRq в виртуальную машину
Когда внутри виртуальной машины что-то зависает, самый быстрый и простой способ - ее перезагрузить. Но для меня такой вариант явно не подходит: например в Solaris попасть в отладчик ядра можно только инициировав немаскируемое прерывание (NMI). В VirtualBox это можно сделать так:
# VBoxManage debugvm <VM-name> injectnmi
Для того, чтобы NMI в Solaris вызывал панику или вход в отладчик ядра, нужно использовать следующие параметры ядра (один из двух), указанные в /etc/system:
set pcplusmp:apic_kmdb_on_nmi=1
set pcplusmp:apic_panic_on_nmi=1
Замечу, что данная опция работает только с контроллером прерываний APIC, к тому же обслуживаемый драйвером pcplusmp. Кроме него есть драйвер apix, соответственно его и нужно указывать в /etc/system перед двоеточием.
В Linux много полезных действий выполняется через комбинацию клавиш Alt-SysRq-<буква>, например клавиша T покажет дамп стека ядра для всех процессов (например это полезно чтобы отловить процессы "повисшие" на NFS), а C - вызовет дамп ядра через Kdump. Подробнее об этих комбинациях расскажет википедия: http://en.wikipedia.org/wiki/Magic_SysRq_key
Беда в том, что если в качестве хоста выступает тоже Linux-система, сломаем мы ее, а не виртуалку. Поэтому посылать SysRq-комбинацию мы будем через интерфейс VBoxManage:
# VBoxManage controlvm <VM-name> keyboardputscancode 1d 38 54 2e d4 b8 9d
# VBoxManage controlvm <VM-name> keyboardputscancode 1d 38 54 ae d4 b8 9d
Здесь в качестве примера дается crashdump ядра (комбинация 2e в середине означает нажатие кнопки C, а ae - ее отжатие).
Подробнее о скан-кодах в Linux можно посмотреть здесь: http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html
Создаем сырой диск
Как правило образы виртуальных машин размещаются на файловой системе в виде файлов *.vdi и тому подобных. А что если мы хотим поместить их на сырой диск или том LVM или ZFS? Для этого нужно создать специальный VMDK-файл и сделать это можно например так:
# VBoxManage internalcommands createrawvmdk -filename raw.vmdk \
-rawdisk /dev/zvol/dsk/devpool/dc/illumos-2013/media/volume
Замечу, что в VMDK-файл попадает также и информация о геометрии диска, поэтому при увеличении размера тома, придется пересоздать VMDK-файл. Такой способ также будет полезен и при использовании загрузочных флешек.
Если необходимо превратить сырой диск обратно в файловый образ, это можно сделать с помощью команды convertfromraw:
# VBoxManage convertfromraw /dev/zvol/dsk/devpool/dc/illumos-2013/media/volume \
illumosraw.vdi --format VDI
Работаем с последовательным портом
В отличие от глупой и неудобной Windows, которая без графического интерфейса даже в конфигурации Server Core никак, Unix-way системы можно заставить использовать в качестве основного интерфейса (т.н. системной консоли) - последовательный порт. Это требует конфигурации загрузчика Grub, в частности для GRUB1 эта конфигурация выглядит так:
serial --unit=0 --speed=115200
terminal serial
Со стороны самих операционных систем конфигурация последовательного порта как системной консоли выглядит следующим образом. В Linux нужно указать в коммандной строке ядра следующий параметр:
console=ttyS0,115200n8
Кроме этого, нужно заставить init запустить на этом терминале соответствующие службы - с помощью одной из *getty-команд. Например в Debian 5 это делается раскомментированием следующей строчки в /etc/inittab:
T0:23:respawn:/sbin/getty -L ttyS0 115200 vt100
В Solaris нужно в параметрах ядра указать также параметр console:
-B console=ttya
если параметры, заданные через опцию -B уже присутствуют, то console=ttya нужно добавить через запятую.
А в файле /boot/solaris/bootenv.rc (на файловой системе ZFS соответственно /rpool/boot/solaris/bootenv.rc) указать следующие строчки:
setprop ttya-mode '115200,8,n,1,-'
setprop console 'ttya'
setprop input-device 'ttya'
setprop output-device 'ttya'
Никаких действий с службами производить не нужно, т.к. сервис console-login всегда стартует с терминалом /dev/console, который мы переназначили на ttya
Теперь время сконфигурировать терминал со стороны VirtualBox:
# VBoxManage modifyvm <VM-name> --uart1 0x03f8 4
# VBoxManage modifyvm <VM-name> --uartmode1 server /tmp/linux-serial
В режиме server VirtualBox создает Unix-сокет, который позволяет общаться с ним. Проблема в том, что нельзя просто взять и сказать screen /tmp/linux-serial. Поможет нам в этой проблеме замечательная утилита socat (ссылка: http://www.dest-unreach.org/socat/). Первый вариант ее использования - создавать виртуальные pty-терминалы и соответственно наш любимый :
#!/bin/bash
SOCKET=$1
PTYLINK=$1-pty
[ "$1" ] || { echo "usage: $0 PIPE"; exit 1; }
while [ ! -e $SOCKET ]
do
echo "Polling for $SOCKET"
sleep 1
done
if [ ! -e $PTYLINK ]
then
socat UNIX-CONNECT:$SOCKET PTY,link=$PTYLINK &
fi
screen $PTYLINK
Второй вариант заключается в использовании непосредственно возможностей socat для общения со стандартным вводом-выводом, хотя в этом случае выход из пайпа возможен только после выключения виртуальной машины или kill'а процесса socat.
#!/bin/sh
[ "$1" ] || { echo "usage: $0 PIPE"; exit 1; }
while [ ! -e $1 ]
do
echo "Polling for $1"
sleep 1
done
trap "stty sane" 0 1 2 3 15
socat unix-connect:$1 stdio,raw,echo=0,icanon=0
Кроме этого возможно например использовать socat в режиме TCP-LISTEN сервера, и вообще подключаться извне через утилиту telnet к виртуальной машине.
