Zamykanie wszystkich maszyn wirtualnych VirtualBox (włóczęgów) za pomocą jednego łatwego w użyciu polecenia bash (które można umieścić w pliku bash)

70

Używam włóczęgi do rozwoju. Zapomniałem zamknąć kilka maszyn wirtualnych. Kiedy idę się wylogować z komputera hosta, proces zamykania systemu Ubuntu wydaje się zawiesić.

Czy może istnieć sposób na napisanie skryptu zamknięcia wszystkich włóczęgów z odrobiną linii poleceń? Coś takiego jak poniżej, ale coś, co, cóż, działa.

for f in $HOME/vagrant;
do;
  cd $f
  vagrant halt
done;
Stóg
źródło
Nie znam włóczęgi, ale wydaje się, że jest powiązany z VMWare, a nie VirtualBox. Czy faktycznie używasz VirtualBox?
terdon
@terdon: Vagrant początkowo obsługiwał Vbox. Myślę, że teraz obsługują inne typy formatów VM (rozumiem VMWare)
Sylvain Pineau
@SylvainPineau ah, OK. Właśnie rzuciłem okiem na ich stronę i zobaczyłem link „Integracja VMWare” i założyłem. Dziękuję za wyjaśnienie.
terdon
1
Rzuciłbym okiem na ten skrypt . Pełny post na blogu jest tutaj . Nie testowano
Sylvain Pineau
Richard, proszę, nie edytuj odpowiedzi w swoim pytaniu. Możesz odpowiedzieć na własne pytanie w osobnej odpowiedzi. Dałem ci głos za dobre pytanie.
don.joey

Odpowiedzi:

91

Do skryptowej kontroli maszyn Virtual Box możemy użyć poleceń VBoxManage :

  • Wyświetl listę uruchomionych maszyn (zwraca nazwę i identyfikator UUID):

    VBoxManage list runningvms
    
  • Przestań uruchamiać maszyny wirtualne, „hibernując” je (zalecane, aby uniknąć utraty danych)

    VBoxManage controlvm <name|uuid> savestate
    
  • Wyłącz uruchamianie maszyn wirtualnych (niezalecane, ponieważ możemy utracić dane gościa)

    VBoxManage controlvm <name|uuid> poweroff
    
  • Użyj ACPI w systemie operacyjnym gościa obsługującym ACPI (lepiej niż w poweroffprzypadku płynnego zamykania gości)

    VBoxManage controlvm <name|uuid> acpipowerbutton
    

Zobacz także: Jak bezpiecznie zamknąć system operacyjny gościa w VirtualBox przy użyciu wiersza polecenia

Aktualizacja z OP

Na podstawie tej wybranej poprawnej odpowiedzi poniżej dodałem ten skrypt bash „ $HOME/bin/stop-vagrant.sh”. Więc teraz mam coś, co może bezpiecznie rozpocząć zatrzymywanie wszystkich wirtualnych maszyn wirtualnych, o których mogłem włączyć, ale o których zapomniałem podczas sesji.

vboxmanage list runningvms | sed -r 's/.*\{(.*)\}/\1/' | xargs -L1 -I {} VBoxManage controlvm {} savestate

Wyjaśnienie polecenia:

vboxmanage list runningvms | - pobiera listę wszystkich uruchomionych vms pod VirtualBox

sed -r 's/.*\{(.*)\}/\1/' | - usuwa ciąg znaków do numeru identyfikacyjnego

xargs -L1 -I {} VBoxManage controlvm {} savestate - uruchamia polecenie zapisu stanu na każdym otwartym oknie.

Na xargs

  • -L1 - bierz jedną linię na raz
  • -I {} - używa {} jako symbol zastępczy dla następnego polecenia
Takkat
źródło
Whoo Hoo! Biorąc pod uwagę powyższe porady, ten wiersz poleceń działa magicznie: lista vboxmanage runningvms | sed -r 's /.* \ {(. *) \} / \ 1 /' | xargs -L1 -I {} VBoxManage controlvm {} savestate
Rick
1
Uwaga, -ropcja jest unikalna dla GNU Sed.
George V. Reilly,
Najlepszy magiczny jednowarstwowy, jaki widziałem od jakiegoś czasu! Dobra robota! : D
tftd
1
W OSX / macOS musisz użyć -Ezamiast -r. To flaga używająca rozszerzonych wyrażeń regularnych.
JayD3e,
22

Druga odpowiedź jest świetna do obsługi Virtualbox, ale Vagrant posiada własne mechanizmy do obsługi maszyn wirtualnych i, jak wspomniano w jednym z komentarzy, obsługuje więcej niż tylko VirtualBox, tylko VMWare w tej chwili, ale kto wie później!

Wydaje mi się, że to działa:

vagrant global-status | awk '/running/{print $1}' | xargs -r -d '\n' -n 1 -- vagrant suspend

Uwaga:

Działa to z wersjami Vagrant po 1.6, w przypadku starszych wersji prawdopodobnie powinieneś zaktualizować, ale jeśli nie możesz, jedna z innych opcji skupiających się na Virtualbox może być lepsza.

ThomasRedstone
źródło
4
jest to oczywiście odpowiedź o wiele lepsza (tm). @Richard powinien zamiast tego rozważyć przyjęcie tego
nhed
global-statusRozkaz został wprowadzony w Vagrant 1,6 . Użytkownicy starszych wersji Vagrant, szczególnie ci, którzy zainstalowali go za pośrednictwem apt-geti nadal mogą korzystać z 1.4.3, będą musieli zaktualizować swoją instalację Vagrant, zanim będą mogli używać tego polecenia.
Curtis Gibby
1
BSD xargsnie obsługuje -r, dlatego możesz zainstalować gxargsza pomocą brewi używać go zamiast tego.
kenorb
11

Mój mechanizm tego:

vagrant global-status | grep virtualbox | cut -c 1-9 | while read line; do echo $line; vagrant halt $line; done;

  • status globalny wyświetla wszystkie pola
  • filtruj, że dla wierszy zawierających virtualbox(Filtruje tekst pomocy, zepsuje się, jeśli używasz innego dostawcy)
  • Filtruj, aby wyświetlać tylko pierwsze 9 znaków (globalny unikalny identyfikator)
  • Chociaż nadal możemy odczytać wiersz z tego wejścia, przeczytaj go jako zmienną $ line, a następnie:
    • Wydrukuj tę linię $
    • biegnij vagrant halt $linezatrzymując włóczęgę dla tego globalnego unikalnego identyfikatora

Jest to lepsze niż powyższa metoda Virtualbox, ponieważ uruchomi ona również wszelkie mechanizmy zamykania skonfigurowane przez włóczęgów.

Aquarion
źródło
3
To polecenie działa również w przypadku hostów OS X. Inne zawodzą z powodu różnic w obsłudze argumentów wiersza polecenia między wersjami OSX i Linux sedoraz awk. Dzięki!
Andrew Андрей Листочкин
@ AndrewАндрейЛисточкин Potwierdź - działa dobrze na OS X 10. Chociaż nie testuje się na innym systemie operacyjnym.
setevoy
2
Powyższe polecenie próbuje zatrzymać wszystkie pola, bez względu na to, czy są uruchomione, czy nie, dlatego wykonanie polecenia zajmuje dużo czasu. Dla mnie, ponieważ używam tylko virtualboksa, zmieniłem grep „virtualbox” na „running”, aby uzyskać tylko te działające.
Alex2php,
To dobra odpowiedź, ale możesz chcieć użyć vagrant suspendzamiast vagrant haltzapisać stan i zawiesić, aby przyspieszyć w dół i w górę.
David Thomas
To prawda, a jeśli to działa, to świetnie. Miałem ogromne problemy z mierzeniem czasu w zawieszonych maszynach wirtualnych pod Virtualbox, więc nie poleciłbym tego.
Aquarion
5

W przypadku, gdy inne osoby przejdą do tego pytania: Osoby korzystające z VirtualBox już mogą się tym zająć, obejmują tylko edycję pliku:

# Contents of /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

## My original values
# SHUTDOWN_USERS=""
# SHUTDOWN=poweroff

## My current values
SHUTDOWN_USERS="all"
SHUTDOWN=savestate

Plusem jest to, że nie trzeba edytować / tworzyć żadnego wylogowania ani init.dstriptizu, aby uruchomić polecenia zamieszczone w innych odpowiedziach. Minusem jest to, że to rozwiązanie jest specyficzne dla VirtualBox.

Testowany na Ubuntu 14.10 z VirtualBox 4.3.18.

Wszystkie kredyty trafiają do tego postu .

Armando Pérez Marqués
źródło
5

Łącząc niektóre z pozostałych odpowiedzi, spowoduje to zamknięcie wszystkich działających wirtualnych skrzynek Vibrant:

vagrant global-status | awk '/virtualbox running/{ print $1 }' | xargs vagrant halt
Ryan
źródło
To zadziałało dla mnie!
Dayron Gallardo
3

Po prostu używam vagrant halt. Jeśli uruchomisz go bez dalszego argumentu, zatrzyma wszystkie maszyny zdefiniowane w Vagrantfile.

nomen
źródło
1

Jeśli piszesz skrypty do analizowania komend Vagrant, zaleca się analizowanie danych wyjściowych przyjaznych dla maszyny ( --machine-readable), co jest bardziej spójne.

Format to:

timestamp,target,type,data...

dzięki czemu możesz zaimportować go jako plik CSV, ponieważ jest on oddzielony przecinkami.

W przypadku powłoki prawdopodobnie trudniej jest ją przeanalizować, na przykład:

for id in $(vagrant global-status --machine-readable | cut -d, -f5 | grep -B3 running | egrep -o "[0-9a-f]{7}"); do
    vagrant suspend $id;
done

Patrz: Vagrant - Dane wyjściowe do odczytu maszynowego


Jednak łatwiej mi parsować standardowe wyjście, np

while read id name provider state path; do
  [ "$state" = "running" ] && vagrant suspend $id;
done < <(vagrant global-status)

Btw. Teoretycznie vagrantpolecenie powinno zaakceptować wyrażenie regularne dla listy maszyn wirtualnych do zawieszenia zgodnie z tym postem GH , na przykład:

vagrant suspend '*'

ale to nie działa i jest błąd # 7221, który czeka na naprawę.


Powiązane bilety GitHub:

kenorb
źródło
0

To może, ale nie musi, działać ;-) Działa dla mnie

vagrant_halt_all.sh

#!/usr/bin/env bash
if [ -z "$1" ]
then
  OPTS=""
else
  # force close if any arg passed
  OPTS="-f"
fi

for i in $(vagrant global-status | grep running | awk '{print $1}'); do 
  DIR=$(vagrant global-status | grep running | awk '{print $5}')
  cd "$DIR";
  OUT=$(vagrant halt);
  echo "attempted to halt $i: $OUT"
done
Brad parki
źródło