Bezpiecznie zamknij maszynę wirtualną przy ponownym uruchomieniu hosta

8

Używam Windows 7 w Virtualbox na Ubuntu 11.10. Wszystko dziala. Używam go podczas uruchamiania, ale mam problem z ponownym uruchomieniem.

Kiedy piszę, sudo reboot nowstan wirtualnego systemu Windows 7 nie jest zapisywany. Po ponownym uruchomieniu Virtualbox uruchamia się, ale zamiast działającego systemu Windows pojawia się menu rozruchu awaryjnego systemu Windows 7, a system Windows uruchamia się ponownie.

Czy istnieje opcja, że ​​Ubuntu może wysłać sygnał do wirtualnego urządzenia, aby bezpiecznie zamknąć instancję przed ponownym uruchomieniem hosta?

zabiera
źródło

Odpowiedzi:

6

Jeśli naprawdę potrzebujesz zamknąć system podczas pracy maszyny wirtualnej w Virtual Box, możesz zdefiniować własny skrypt ręcznego zamykania, w którym umieścisz polecenie zapisania stanu komputera przed rozpoczęciem procesu zamykania:

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

Alternatywnie możesz również wygenerować skrypt, który zawsze uruchamia się przy wyłączaniu .

Takkat
źródło
4

Jeśli korzystasz z sudo rebootprogramów, otrzymujesz sygnał zabicia kończący je automatycznie, bez dawania aplikacji czasu na działanie w takiej sytuacji. To nie jest błąd, zawsze działał w ten sam sposób i takie jest oczekiwane zachowanie.

Jest to podobne pytanie, gdzie można zobaczyć, które polecenia są podane po naciśnięciu shutdown, reboot, suspenditd przycisk w menu użytkownika, takie rozwiązanie powinno zapytać, co zrobić, gdy próbuje zamknąć okno z działającej aplikacji i jego korzystne (w Twoja sprawa) do sudo shutdownpodejścia. Spójrz

Bruno Pereira
źródło
Czy ponowne uruchomienie ostatnio stało się bardziej uprzejme? Strona rebootpodręcznika dla 12.10 mówi: „Gdy zostanie wywołana z --force lub w trybie 0 lub 6, to narzędzie wywołuje samo wywołanie systemowe reboot (2) i bezpośrednio ponownie uruchamia system. W przeciwnym razie po prostu wywołuje narzędzie shutdown (8) z odpowiednie argumenty. ”; a strona podręcznika man shutdownmówi: „Po upływie CZASU zamknięcie wysyła żądanie do demona init (8), aby doprowadzić system do odpowiedniego poziomu uruchamiania”.
echristopherson
4

Poleciłbym bardziej wyrafinowane podejście, w tym pracę upstart, skrypt start i stop. Jako przykład używam systemu Windows XP, ponieważ mój katalog domowy pozwala na użycie tomberta ... który należy odpowiednio zmienić. Ma tę zaletę, że wszystko, co robisz (restart, zamknięcie, naciśnięcie przycisku zasilania), dobrze radzi sobie z maszyną wirtualną .

Najpierw zadanie upstart, umieść w /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

Zadanie upstart uruchamia maszynę wirtualną na poziomie 2 (który jest w trybie graficznym), aw moim przypadku zwiększa priorytet o nice. Aby ładnie zamknąć maszynę wirtualną, muszę „wyłączyć” zakończenie upstart za pomocą kill signal SIGCONTinstrukcji. To powoduje, że maszyna wirtualna najpierw działa (unikając domyślnej SIGTERM). Po 120 sekundach i tak SIGKILLzostanie wysłany. Zamiast tego uruchamiam winxpvm-stop.shskrypt.

Uwaga dodatkowa 1: Sekcje start on started runlevel [2]i stop on starting runlevel [!2]nie działają. Należy szczególnie wspomnieć o pracy rc.

Uwaga dodatkowa 2: Co jest mylące również z podręcznika dla początkujących: Sekcja kill signalokreśla sygnał wysłany po 5 sekundach. W tym przykładzie ustawiłem go z SIGTERM(domyślnie) na SIGCONT - ale nie mogłem zmienić limitu 5 sekund. Sekcja kill timeoutokreśla limit czasu, po którym SIGKILLjest wysyłany - którego sygnału nie można zmienić. Ulepszeniem byłoby zatem zdefiniowanie nowych zwrotek term signali term timeout.

Oto skrypt startowy 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

Ponieważ wszystkie ustawienia itp. Są wykonywane w trybie użytkownika (ponieważ mój login to tombert ), nawet po uruchomieniu jako root zmieniam konto na tombert . Użytkownik może oczywiście zostać zmieniony w konfiguracji upstart, ale to rozwiązanie pozostawia mi opcję uruchamiania / zatrzymywania maszyny wirtualnej „ręcznie” z konsoli.

Bardziej interesujący jest skrypt zamykający w 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

Najpierw robię to samo, co w skrypcie startowym - zmieniam użytkownika z root na moje konto tombert . Teraz spójrzmy na funkcję dostop. Najpierw sprawdzam, czy maszyna wirtualna w ogóle działa. Następnie próbuję „miękko” zamknąć system, wysyłając go bezpośrednio do WinXP przy użyciu guestcontrol. Tutaj musisz podać poświadczenia konta WinXP, które w moim przypadku to tombert i hasło. Windows shutdownz wdziękiem zamknie wszystkie aplikacje i wyłączy system operacyjny (normalnie). Następnie pozwala stale sprawdzać stan maszyny wirtualnej za pomocą showvminfo. Wykonanie tego co najmniej 60 razy z 1-sekundowym limitem czasu (rób wszystko, co uważasz, że jest to właściwe) powinno pozostawić maszynie wirtualnej wystarczająco dużo czasu, aby mogła się bezpiecznie zamknąć. Pamiętaj, że połączenie zshowvminfozajmuje również trochę mniej niż sekundę (przynajmniej na moim komputerze), więc w moim przypadku daje to ~ 120 sekund. Jeśli wszystko zahamuje, możemy wymusić wyłączenie przy użyciu poweroffoświadczenia.

Powinieneś także zobaczyć acpipowerbutton, ale nieużywany. Jest tak, ponieważ nie działa niezawodnie. Jeśli jesteś zalogowany do systemu Windows lub nawet gorzej wielu użytkowników, system Windows wyświetli okno dialogowe potwierdzenia zamknięcia, uniemożliwiające zamknięcie systemu. Jest to również powód, dla którego acpibuttonw /etc/default/virtualboxnie będzie działać w 100% niezawodny. Również poweroffsilnie wyłączy maszynę wirtualną - tak samo jak długo naciśnij przycisk zasilania. Dlatego najlepiej ustawić to na puste:

Fragment z / 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=""

Aby było idealnie, możesz zmienić zachowanie przycisku zasilania:

Fragment /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
...
...

Pozostaje jedna mała wada. Gdy maszyna wirtualna nadal się uruchamia, a usługa kontroli gościa nie jest uruchomiona (na maszynie wirtualnej), nie otrzyma polecenia zamknięcia. Rzadki przypadek ... ale pomyśl o tym.

To wszystko, mam nadzieję, że to pomoże.

tombert
źródło
Działa jak urok (gość Windows XP), ale wydaje się, że wyrzuca VERR_INVALID_PARAMETERpo stronie hosta, jeśli jestem zalogowany za pośrednictwem RDC jako użytkownik podany w skrypcie, a następnie gość nadal działa.
echristopherson
Próbowałem zarówno z natywnym RDC, jak i RDC na VirtualBox. Nie ma takiego błędu. Prawdopodobnie związany z virtualbox.org/ticket/8197
tombert 29.04.13
2

Postępuj zgodnie z odpowiedzią, aby zmienić zasady systemowe dotyczące ponownego uruchamiania

Nie możesz tego usprawnić reboot. init.dSkrypty AFAIK nie będą działać, ponieważ zajmuje to zbyt dużo czasu, ale możesz uruchomić następującą komendę:

VBoxManage controlvm <vm> savestate&&reboot

gdzie <vm>jest nazwa maszyny wirtualnej

Amith KK
źródło
1

Możesz wysłać żądanie zamknięcia do maszyny wirtualnej za pomocą:

VBoxManage controlvm <vm_name> acpipowerbutton

Ale jeśli zrobisz to w skrypcie inicjującym, skrypt nie powinien wyjść, dopóki zamknięcie nie zostanie zakończone. Możemy to wykryć, odpytując plik dysku maszyny wirtualnej (.vdi) za pomocą lsoflub fuserw pętli. Lub jako tanie obejście, sleep 20może wystarczyć.

Oto, czego obecnie używam w zamkniętym bloku skryptu inicjującego:

# 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

W górnej części pliku zdefiniowałem:

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

To może nie zamknąć aplikacji VirtualBox, ale czeka na zakończenie maszyny wirtualnej. Nie działa również, jeśli maszyna wirtualna jest w trakcie uruchamiania (wiele systemów operacyjnych ignoruje przycisk wyłączania podczas tej fazy) lub jeśli emulujesz stary system bez obsługi ACPI.

joeytwiddle
źródło