主机重启时安全关闭虚拟机

主机重启时安全关闭虚拟机

我在 Ubuntu 11.10 上的 Virtualbox 中运行 Windows 7。一切正常。我在启动时运行它,但重新启动时出现问题。

当我输入时,sudo reboot now虚拟 Windows 7 的状态未保存。重启后,virtualbox 启动,但我看到的不是正在运行的 Windows,而是 Windows 7 崩溃的启动菜单,并且 Windows 再次启动。

是否有一个选项可以让 Ubuntu 发送一些信号到虚拟机以便在主机重启之前安全地关闭实例?

答案1

如果您确实需要在 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

或者你也可以生成一个脚本总是在关机时运行

答案2

如果您使用的sudo reboot程序被发出终止信号,则会自动结束它们,而不会给应用程序时间来处理这种情况。这不是一个错误,它总是以同样的方式工作,这是预期的行为。

有一个类似的问题,您可以看到当您按下用户菜单上的shutdownrebootsuspend等按钮时会给出哪些命令,这样的解决方案应该会询问您在尝试关闭正在运行的应用程序的窗口时该怎么做,以及该方法的可取之处(就您而言)sudo shutdown。看看

答案3

我建议采用更复杂的方法,包括一个 upstart 作业、一个启动和停止脚本。例如,我使用 Windows XP,因为我的主目录允许使用汤伯特...您应该进行相应的更改。它的优点是无论你做什么(重启、关机、按电源按钮),它都能很好地处理你的虚拟机

首先将 upstart 作业放入 /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。为了顺利关闭虚拟机,我需要使用 语句“禁用”upstart 终止kill signal SIGCONT。这首先使虚拟机保持运行状态(避免默认的SIGTERM)。120 秒后,SIGKILL无论如何都会发送。相反,我正在运行winxpvm-stop.sh脚本。

附注 1:start on started runlevel [2]和节stop on starting runlevel [!2]不起作用。必须特别提及工作rc

旁注 2:upstart 手册中还有一点也令人困惑:kill signal节指定了 5 秒后发送的信号。在此示例中,我将其从SIGTERM(默认)设置为 SIGCONT - 但 5 秒超时我无法更改。节kill timeout指定了发送的超时时间SIGKILL- 无法更改该信号。因此,改进方法是定义新的节term signalterm 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

由于所有设置等都是在用户模式下完成的(因为我的登录名是汤伯特),即使以 root 身份运行,我也将帐户更改为汤伯特。当然可以在 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 更改为我的帐户汤伯特。现在让我们看看函数dostop。首先,我检查虚拟机是否正在运行。然后,我尝试通过使用直接向 WinXP 发送关机来“软”关机guestcontrol。在这里,您必须提供 WinXP 帐户的凭据,在我的情况下是汤伯特和密码。Windowsshutdown将正常关闭所有应用程序并关闭操作系统(正常情况下)。然后让我们使用 连续检查虚拟机状态showvminfo。执行此操作至少 60 次,超时 1 秒(在此处执行您认为合适的任何操作)应该会给虚拟机足够的时间正常关闭。请注意,调用showvminfo也需要不到一秒的时间(至少在我的计算机上),因此在我的情况下,这会让它大约 120 秒。如果一切都崩溃了,我们可以使用语句强制关闭poweroff

您还应该看到acpipowerbutton,但未使用。这是因为它不可靠。如果您登录到 Windows,或者更糟的是多个用户登录,Windows 将显示确认关机对话框,阻止系统关机。这也是为什么 中的acpibutton不能/etc/default/virtualbox100% 可靠地工作的原因。此外,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
...
...

还有一个小缺点。当虚拟机仍在启动且客户机控制服务未启动(在虚拟机中)时,它将不会收到关机命令。这种情况很少见……但请仔细考虑一下。

就是这样,希望有帮助。

答案4

您可以使用以下命令向虚拟机发送关机请求:

VBoxManage controlvm <vm_name> acpipowerbutton

但是,如果您在 init 脚本中执行此操作,则脚本应该在关闭完成之前不会退出。我们可以通过循环轮询虚拟机的驱动器文件 (.vdi) 来检测这一点lsoffuser或者作为一种廉价的解决方法,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 的旧系统,则此方法无效。

相关内容