Fechar com segurança a máquina virtualbox na reinicialização do host

8

Estou executando o Windows 7 dentro do Virtualbox no Ubuntu 11.10. Tudo funciona bem. Estou executando na inicialização, mas tenho um problema com a reinicialização.

Quando digito sudo reboot now , o estado do Windows 7 virtual não é salvo. Após a reinicialização, o VirtualBox é iniciado, mas em vez do Windows em execução, recebo o menu de inicialização de falha do Windows 7 e o Windows está sendo inicializado novamente.

Existe uma opção que o Ubuntu poderia enviar algum sinal para a caixa virtual para fechar a instância com segurança antes da reinicialização do host?

    
por takeshin 04.02.2012 / 09:20

5 respostas

6

Caso você realmente precise desligar enquanto uma máquina virtual no Virtual Box estiver em execução, você pode definir seu próprio script para um desligamento manual em que você coloca um comando para salvar o estado da máquina antes do início do processo de desligamento:

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

Alternativamente, você também pode gerar um script que sempre é executado no desligamento .

    
por Takkat 04.02.2012 / 10:08
4

Se você usar sudo reboot , os programas receberão o sinal kill, terminando-os automaticamente, sem dar um tempo de aplicação para agir em tal situação. Isso não é um bug, sempre funcionou da mesma maneira e esse é o comportamento esperado.

Existe uma pergunta semelhante em que você pode ver quais comandos são fornecidos quando você pressiona o botão shutdown , reboot , suspend , etc no menu do usuário, essa solução deve perguntar o que fazer ao tentar feche uma janela com um aplicativo em execução e é preferível (no seu caso) à abordagem sudo shutdown . Dê uma olhada

por Bruno Pereira 04.02.2012 / 09:40
4

Eu recomendaria uma abordagem mais sofisticada, incluindo um trabalho inicial, um script de início e parada. Como exemplo, estou usando o Windows XP, já que meu diretório pessoal permite usar tombert ... que você deve alterar de acordo. Tem a vantagem de fazer o que fizer (reiniciar, desligar, pressionar o botão liga / desliga) e manipular sua máquina virtual bem .

Primeiro o trabalho inicial, coloque em /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

O job upstart inicia a máquina virtual no nível de execução 2 (que está no modo gráfico) e, no meu caso, aumenta a prioridade com nice . Para desligar a máquina virtual, preciso "desabilitar" a terminação inicial usando a instrução kill signal SIGCONT . Isso deixa a máquina virtual em execução no início (evitando o padrão SIGTERM ). Após 120 segundos, o SIGKILL é enviado de qualquer forma. Em vez disso, estou executando o script winxpvm-stop.sh .

Side-Note 1: As sub-rotinas start on started runlevel [2] e stop on starting runlevel [!2] não funcionam. É preciso mencionar especificamente o trabalho rc .

Side-Note 2: O que também é confuso no manual do upstart: A estrofe kill signal especifica o sinal enviado após 5 segundos. Neste exemplo, eu o configurei de SIGTERM (padrão) para SIGCONT - mas o tempo limite de 5 segundos não consegui mudar. A sub-rotina kill timeout especifica o tempo limite após o qual o SIGKILL é enviado - qual sinal não é possível alterar. Uma melhoria, portanto, seria definir novas estrofes term signal e term timeout .

Aqui o script de início 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

Como todas as configurações, etc., são feitas no modo de usuário (como meu login é tombert ), mesmo quando executado como root, altero a conta para tombert . O usuário, claro, poderia ser alterado na configuração inicial, mas essa solução me deixa a opção de iniciar / parar a máquina virtual "manualmente" no console.

O mais interessante é o script de desligamento em 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

Primeiro, faço o mesmo que no script de início - estou mudando o usuário do root para minha conta tombert . Agora vamos ver a função dostop . Primeiro, estou verificando se a máquina virtual está funcionando. Então eu estou tentando desligar "suavemente" enviando um desligamento diretamente para o WinXP usando guestcontrol . Aqui você deve fornecer as credenciais para a conta do WinXP, que no meu caso é tombert e uma senha. O Windows shutdown fechará todos os aplicativos e desligará o sistema operacional (normalmente). Em seguida, vamos verificar o estado da máquina virtual continuamente usando showvminfo . Fazendo isso pelo menos 60 vezes com tempo limite de 1 segundo (faça o que achar apropriado) deve deixar a máquina virtual com tempo suficiente para desligar normalmente. Note que a chamada para showvminfo também leva um pouco menos de um segundo (pelo menos no meu computador), então isso dá ~ 120 segundos no meu caso. Se tudo travar, poderemos desligar com força usando a instrução poweroff .

Você também deve ver o acpipowerbutton , mas não usado. Isso ocorre porque não funciona de forma confiável. Se você estiver conectado ao Windows ou, pior ainda, vários usuários, o Windows mostrará uma caixa de diálogo de confirmação de desligamento evitando que o sistema seja desligado. Essa também é a razão pela qual o acpibutton no /etc/default/virtualbox não funcionará 100% confiável. Além disso, o poweroff forçará o desligamento da máquina virtual - da mesma forma que um botão liga / desliga pressionado por muito tempo. Portanto, é melhor definir isso como vazio:

Trecho de / 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=""

Para torná-lo perfeito, talvez você queira alterar o comportamento do botão liga / desliga:

Trecho de /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
...
...

Existe um pequeno inconveniente. Quando a máquina virtual ainda está inicializando e o serviço de controle de convidados não está ativo (na máquina virtual), ele não receberá o comando de desligamento. Um caso raro ... mas pense nisso.

É isso, espero que ajude.

    
por tombert 07.04.2013 / 03:45
2

Siga esta resposta para alterar a política do sistema para reinicializar

Você não pode simplificar isso em reboot . Os scripts AFAIK init.d não funcionarão porque leva muito tempo, mas você pode executar o comando da seguinte forma:

VBoxManage controlvm <vm> savestate&&reboot

onde <vm> é o nome da Máquina Virtual

    
por Amith KK 04.02.2012 / 10:13
1

Você pode enviar uma solicitação de desligamento para a máquina virtual com:

VBoxManage controlvm <vm_name> acpipowerbutton

Mas se você fizer isso em um script de inicialização, o script não deve sair até que o desligamento seja concluído. Podemos detectar isso consultando o arquivo de unidade da VM (.vdi) com lsof ou fuser em um loop. Ou como uma alternativa barata, sleep 20 pode ser suficiente.

Aqui está o que estou usando atualmente no bloco close do meu script de inicialização:

# 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

Perto do topo do arquivo que eu defini:

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

Isso pode não fechar o aplicativo VirtualBox em si, mas espera que a VM conclua o desligamento. Além disso, ele não funciona se a máquina virtual ainda estiver no processo de inicialização (muitos sistemas operacionais ignoram o botão de desligamento durante essa fase) ou se você estiver emulando um sistema antigo sem suporte a ACPI.

    
por joeytwiddle 20.03.2013 / 09:25