Feche com segurança a máquina de caixa virtual na reinicialização do host

8

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

Quando digito, sudo reboot nowo 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 travada do Windows 7 e o Windows é inicializado novamente.

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

leva
fonte

Respostas:

6

Caso você realmente precise desligar enquanto uma máquina virtual em Virtual Box estiver em execução, você poderá 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

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

Takkat
fonte
4

Se você usar sudo rebootprogramas, recebe o sinal de interrupção finalizando-os automaticamente, sem dar tempo ao aplicativo para agir em tal situação. Isso não é um bug, sempre funcionou da mesma maneira e esse é o comportamento esperado.

Há uma pergunta semelhante, onde você pode ver quais comandos são dados quando você pressiona o shutdown, reboot, suspend, etc botão no menu do usuário, essa solução deve perguntar-lhe o que fazer ao tentar fechar uma janela com um aplicativo em execução e sua preferência (em seu caso) à sudo shutdownabordagem. Dar uma olhada

Bruno Pereira
fonte
A reinicialização recentemente se tornou mais educada? A página de manual do reboot12.10 diz "Quando chamada com --force ou quando no nível de execução 0 ou 6, esta ferramenta chama a própria chamada de sistema reboot (2) e reinicia diretamente o sistema. Caso contrário, isso simplesmente chama a ferramenta shutdown (8) com os argumentos apropriados. "; e a página do manual shutdowndiz "Depois que o TIME terminar, o shutdown envia uma solicitação ao daemon init (8) para trazer o sistema para o nível de execução apropriado".
Echristopherson
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, pois meu diretório pessoal permite usar tombert ..., que você deve alterar de acordo. Ele tem a vantagem de tudo o que você faz (reinicialização, desligamento, pressionamento do botão liga / desliga) e lida com sua máquina virtual .

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 trabalho inicial 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 bem a máquina virtual, preciso "desativar" a terminação inicial usando a kill signal SIGCONTinstrução Isso deixa a máquina virtual em execução no início (evitando o padrão SIGTERM). Após 120 segundos, o SIGKILLenvio é assim mesmo. Em vez disso, estou executando o winxpvm-stop.shscript.

Nota lateral 1: As estrofes start on started runlevel [2]e stop on starting runlevel [!2]não funcionam. É preciso mencionar especificamente o trabalho rc.

Nota lateral 2: O que é confuso também no manual inicial: A kill signalestrofe especifica o sinal enviado após 5 segundos. Neste exemplo, defini-o de SIGTERM(padrão) para SIGCONT - mas o tempo limite de 5 segundos não foi possível alterar. A kill timeoutestrofe especifica o tempo limite após o qual o SIGKILLenvio é enviado - qual sinal não pode ser alterado. Uma melhoria, portanto, seria definir novas estrofes term signale 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, mudo a conta para tombert . Obviamente, o usuário pode 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 no 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 inicial - estou mudando o usuário da raiz para a minha conta tombert . Agora vamos olhar para a função dostop. Primeiro, estou verificando se a máquina virtual está em execução. Então, eu estou tentando "suavemente" o desligamento enviando um desligamento diretamente para o WinXP usando guestcontrol. Aqui você deve fornecer as credenciais da conta WinXP, que no meu caso é tombert e uma senha. O Windows shutdownirá fechar todos os aplicativos normalmente e desligar o sistema operacional (normalmente). Em seguida, vamos verificar o estado da máquina virtual continuamente usando showvminfo. Fazer isso pelo menos 60 vezes com 1 segundo de tempo limite (faça o que você achar apropriado aqui) deve deixar a máquina virtual tempo suficiente para desligar normalmente. Observe que a chamada parashowvminfotambém demora um pouco menos de um segundo (pelo menos no meu computador), o que gera aproximadamente 120 segundos no meu caso. Se tudo frear, podemos desligar à força usando a poweroffdeclaração.

Você também deve ver o acpipowerbutton, mas não utilizado. Isso ocorre porque não funciona de maneira confiável. Se você estiver conectado ao Windows, ou ainda pior, vários usuários, o Windows mostrará uma caixa de diálogo de encerramento de confirmação, impedindo o desligamento do sistema. Esta também é a razão pela qual o acpibuttonin /etc/default/virtualboxnão funcionará 100% confiável. Além disso, o poweroffdesligamento forçado da máquina virtual é o mesmo que pressionar um botão liga / desliga 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, convém 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
...
...

Ainda existe uma pequena desvantagem. Quando a máquina virtual ainda estiver inicializando e o serviço de controle de convidados não estiver ativo (na máquina virtual), ele não receberá o comando shutdown. Um caso raro ... mas pense nisso.

É isso, espero que ajude.

Tombert
fonte
Funciona como um encanto (convidado do Windows XP), exceto que parece jogar fora VERR_INVALID_PARAMETERno host se eu estiver conectado via RDC como o usuário fornecido no script e, subsequentemente, o convidado continuar executando.
echristopherson
Eu tentei com o RDC nativo e com o RDC em cima do VirtualBox. Não existe esse erro. Provavelmente relacionado com virtualbox.org/ticket/8197
tombert
2

Siga esta resposta para alterar a política do sistema para reinicialização

Você não pode simplificar isso reboot. Os init.dscripts do AFAIK não funcionarão porque leva muito tempo, mas você pode executar o comando assim:

VBoxManage controlvm <vm> savestate&&reboot

onde <vm>é o nome da máquina virtual

Amith KK
fonte
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 init, o script não deverá sair até que o desligamento seja concluído. Podemos detectar isso pesquisando o arquivo de unidade da VM (.vdi) com lsofou fuserem um loop. Ou, como solução alternativa barata, sleep 20pode ser suficiente.

Aqui está o que estou usando atualmente no bloco próximo do meu script init:

# 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, eu defini:

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

Na verdade, isso pode não fechar o aplicativo VirtualBox, mas aguarda a VM concluir o desligamento. Também não funcionará se a máquina virtual ainda estiver em processo de inicialização (muitos sistemas operacionais ignoram o botão de desligar durante esta fase) ou se você estiver emulando um sistema antigo sem suporte a ACPI.

joeytwiddle
fonte