Безопасно закройте виртуальную машину при перезагрузке хоста

8

Я использую Windows 7 внутри Virtualbox на Ubuntu 11.10. Все отлично работает Я запускаю его при запуске, но у меня проблема с перезагрузкой.

Когда я печатаю, sudo reboot nowсостояние виртуальной Windows 7 не сохраняется. После перезагрузки запускается виртуальная коробка, но вместо работающей Windows я получаю меню аварийной загрузки Windows 7, и окна снова загружаются.

Есть ли возможность, что Ubuntu может послать некоторый сигнал в виртуальный ящик, чтобы безопасно закрыть экземпляр перед перезагрузкой хоста?

takeshin
источник

Ответы:

6

В случае, если вам действительно необходимо завершить работу во время работы виртуальной машины в Virtual Box, вы можете определить свой собственный сценарий для ручного выключения, в котором вы помещаете команду для сохранения состояния машины перед началом процесса выключения:

VBoxManage controlvm <name> savestate # <name> is the name of your VM
gnome-session-quit --power-off # this example displays the power-off dialog for >11.10

В качестве альтернативы вы также можете сгенерировать скрипт, который всегда запускается при выключении .

Takkat
источник
4

Если вы используете sudo rebootпрограммы, им выдается сигнал уничтожения, который автоматически завершает их, не давая приложению времени действовать в такой ситуации. Это не ошибка, она всегда работала одинаково, и это ожидаемое поведение.

Существует аналогичный вопрос , где вы можете увидеть , какие команды даются при нажатии кнопки shutdown, reboot, suspendи т.д. кнопки в меню пользователя, такое решение должно спросить, что делать при попытке закрыть окно с запущенным приложением и его предпочтительней (в ваш случай) к sudo shutdownподходу. Посмотри

Бруно Перейра
источник
Перезагрузка в последнее время стала более вежливой? Страница man для reboot12.10 сообщает: «При вызове с помощью --force или при уровне запуска 0 или 6 этот инструмент вызывает сам системный вызов reboot (2) и напрямую перезагружает систему. В противном случае это просто вызывает инструмент shutdown (8) с соответствующие аргументы. "; и на странице руководства shutdownговорится: «По истечении ВРЕМЕНИ shutdown отправляет запрос демону init (8) о переводе системы на соответствующий уровень выполнения».
Эхристоферсон
4

Я бы порекомендовал более сложный подход, включающий в себя выскочившую работу, скрипт запуска и остановки. В качестве примера я использую Windows XP, так как мой домашний каталог позволяет использовать tombert ... который вы должны изменить соответствующим образом. Он обладает тем преимуществом, что вы делаете (перезагрузка, выключение, нажатие кнопки питания), он прекрасно справляется с вашей виртуальной машиной .

Сначала начальную работу поместите в /etc/init/winxpvm.conf:

description "WinXP VirtualBox job"
author "Thomas Perschak"

## 0: system halt
## 1: single-user mode
## 2: graphical multi-user plus networking
## 6: system reboot
start on started rc RUNLEVEL=[2]
stop on starting rc RUNLEVEL=[!2]

## upstart config
kill timeout 120
kill signal SIGCONT
nice -10

## start WinXP VirtualBox
exec /home/tombert/scripts/winxpvm-start.sh

## stop WinXP VirtualBox
pre-stop exec /home/tombert/scripts/winxpvm-stop.sh

Задание upstart запускает виртуальную машину на уровне выполнения 2 (который находится в графическом режиме), и в моем случае это увеличивает приоритет на nice. Для того, чтобы приятно завершить работу виртуальной машины, мне нужно «отключить» завершение загрузки, используя kill signal SIGCONTинструкцию. Это оставляет виртуальную машину работающей сначала (избегая значения по умолчанию SIGTERM). Через 120 секунд SIGKILLотправка в любом случае. Вместо этого я запускаю winxpvm-stop.shсценарий.

Примечание 1: строфы start on started runlevel [2]и stop on starting runlevel [!2]не работают. Нужно особо упомянуть работу rc.

Дополнительное примечание 2. Что сбивает с толку и из руководства по выскочкам: В kill signalстрофе указывается сигнал, отправляемый через 5 секунд. В этом примере я установил его SIGTERM(по умолчанию) на SIGCONT - но тайм-аут на 5 секунд я не смог изменить. В kill timeoutразделе указывается тайм-аут, после которого SIGKILLотправляется сигнал, который нельзя изменить. Поэтому улучшение должно заключаться в определении новых строф term signalи term timeout.

Вот стартовый скрипт winxpvm-start.sh:

#! /bin/bash -e

function dostart()
{
    echo -n "Running WinXP ... "
    vboxheadless --startvm WinXP
    echo "now closed"
}
export -f dostart

if [ $(whoami) != "tombert" ]; then
    su -c dostart tombert
else
    dostart
fi

Поскольку все настройки и т. Д. Выполняются в пользовательском режиме (так как мой логин - tombert ), даже при запуске от имени root я изменяю учетную запись на tombert . Конечно, пользователь может быть изменен в конфигурации upstart, но это решение дает мне возможность запускать / останавливать виртуальную машину «вручную» с консоли.

Более интересным является скрипт завершения работы в winxpvm-stop.sh:

#! /bin/bash

function dostop()
{
    ## check if WinXP is running
    vboxmanage showvminfo WinXP --machinereadable | grep -q 'VMState="running"' &> /dev/null
    if [ $? -ne 0 ]; then
        echo "WinXP not running"
        exit
    fi
    ## try gracefully shutdown
    echo -n "Shutting down WinXP ... "
    #vboxmanage controlvm WinXP acpipowerbutton
    vboxmanage guestcontrol WinXP execute --image "%SystemRoot%\system32\shutdown.exe" --username tombert --password <mypassword> --wait-exit -- "-s" "-f" "-t" "0" &> /dev/null
    ## check vm status
    INDEX=60
    while [ $INDEX -gt 0 ]; do
        echo -n "$INDEX "
        vboxmanage showvminfo WinXP --machinereadable | grep -q 'VMState="running"' &> /dev/null
        if [ $? -ne 0 ]; then
            echo "gracefully done"
            break
        fi
        sleep 1
        let INDEX+=-1
    done
    ## close forcefully
    if [ $INDEX -eq 0 ]; then
        vboxmanage controlvm WinXP poweroff &> /dev/null
        echo "forcefully done"
    fi
}
export -f dostop

if [ $(whoami) != "tombert" ]; then
    su -c dostop tombert
else
    dostop
fi

Сначала я делаю то же самое, что и в стартовом скрипте - меняю пользователя с root на мой аккаунт tombert . Теперь давайте посмотрим на функцию dostop. Сначала я проверяю, работает ли виртуальная машина. Затем я пытаюсь «мягко» завершить работу, отправив отключение непосредственно в WinXP с помощью guestcontrol. Здесь вы должны предоставить учетные данные для учетной записи WinXP, которая в моем случае является Tombert и пароль. Windows shutdownбудет корректно закрывать все приложения и выключать операционную систему (обычно). Затем давайте постоянно проверяем состояние виртуальной машины showvminfo. Выполнение этого как минимум 60 раз с 1-секундным таймаутом (делайте все, что вы считаете подходящим здесь) должно дать виртуальной машине достаточно времени для корректного завершения работы. Обратите внимание, что призыв кshowvminfoтакже занимает чуть меньше секунды (по крайней мере, на моем компьютере), так что в моем случае это дает ~ 120 секунд. Если все тормозит, мы можем принудительно отключиться, используя poweroffинструкцию.

Вы также должны увидеть acpipowerbutton, но не используется. Это потому, что это не работает надежно. Если вы вошли в Windows или, что еще хуже, с несколькими пользователями, Windows покажет диалоговое окно подтверждения отключения, предотвращающее отключение системы. Это также причина, почему acpibuttonв /etc/default/virtualboxне будет работать на 100% надежно. Также poweroffпринудительно отключит виртуальную машину - так же, как и при длительном нажатии кнопки питания. Поэтому лучше установить это значение пустым:

Выдержка из / etc / default / virtualbox:

# SHUTDOWN_USERS="foo bar"  
#   check for running VMs of user 'foo' and user 'bar'
#   'all' checks for all active users
# SHUTDOWN=poweroff
# SHUTDOWN=acpibutton
# SHUTDOWN=savestate
#   select one of these shutdown methods for running VMs
#   acpibutton and savestate causes the init script to wait
#   30 seconds for the VMs to shutdown
SHUTDOWN_USERS=""
SHUTDOWN=""

Чтобы сделать его идеальным, вы можете изменить поведение кнопки питания:

Выдержка из /etc/acpi/powerbtn.sh:

#!/bin/sh
# /etc/acpi/powerbtn.sh
# Initiates a shutdown when the power putton has been
# pressed.

# @backup
# plain shutdown
/sbin/shutdown -h now "Power button pressed"

# fini
exit 0
...
...

Остался один маленький недостаток. Когда виртуальная машина все еще загружается, а служба гостевого управления не запущена (на виртуальной машине), она не получит команду выключения. Редкий случай ... но подумай об этом.

Вот и все, надеюсь, это поможет.

tombert
источник
Работает как шарм (гостевая система Windows XP), за исключением того, что кажется, что он выбрасывает VERR_INVALID_PARAMETERна стороне хоста, если я вошел в систему через RDC как пользователь, указанный в сценарии, и впоследствии гость продолжает работать.
Эхристоферсон
Я пробовал как с родным RDC, так и с RDC поверх VirtualBox. Нет такой ошибки. Вероятно, связано с virtualbox.org/ticket/8197
Томберт
2

Следуйте этому ответу, чтобы изменить системную политику для перезагрузки

Вы не можете упростить это в reboot. init.dСценарии AFAIK не будут работать, потому что это занимает слишком много времени, но вы можете выполнить команду следующим образом:

VBoxManage controlvm <vm> savestate&&reboot

где <vm>имя виртуальной машины

Амит КК
источник
1

Вы можете отправить запрос на выключение виртуальной машины с помощью:

VBoxManage controlvm <vm_name> acpipowerbutton

Но если вы сделаете это в сценарии инициализации, сценарий не должен завершиться до завершения работы. Мы можем обнаружить это путем опроса файла диска виртуальной машины (.vdi) с помощью lsofили fuserв цикле. Или, как дешевый обходной путь, sleep 20может быть достаточно.

Вот что я сейчас использую в блоке закрытия моего скрипта инициализации:

# This always returns 0, even if an error is displayed!
su - "$DAEMONUSER" VBoxManage controlvm "$VMNAME" acpipowerbutton

# Wait until the disk file is no longer open...
for attempt in `seq 1 20`
do
    fuser "$VMDISKIMAGE" >/dev/null 2>&1 || break
    sleep 2
done

return 0    # A better script would return success/fail

В верхней части файла я определил:

VMDISKIMAGE="/home/$DAEMONUSER/VirtualBox VMs/$VMNAME/$VMNAME.vdi"

Это может фактически не закрывать само приложение VirtualBox, но оно ожидает завершения работы виртуальной машины. Также это не работает, если виртуальная машина все еще находится в процессе загрузки (многие операционные системы игнорируют кнопку выключения питания на этом этапе), или если вы эмулируете старую систему без поддержки ACPI.

joeytwiddle
источник