Mon CV

Une machine virtuelle sous VirtualBox en LaunchDaemon sur Mac, accessible via phpVirtualBox (1/3)

17 mai 2013

La virtualisation est aujourd’hui assez largement répandue. Des solutions assez fiables existent. Sur Mac on connait notamment Parallels Desktop et VMWare Fusion. Côté libre, VirtualBox est aussi une référence, même si il est moins à la pointe, et il rempli pleinement la fonction pour des besoins plus ponctuels.

Pour certaines utilisations on a parfois besoin (ou envie) que sa machine virtuelle

  • démarre en même temps que l’ordinateur,
  • et idéalement, en tâche de fond comme service “headless”, de sorte que même si l’on n’a pas de session utilisateur ouverte, la machine virtuelle soit active.

C’est notamment utile si on souhaite utiliser VirtualBox pour virtualiser un OS serveur.

J’ai trouvé plusieurs méthodes sur le web. La plus courante consiste à utiliser la commande “/usr/bin/VBoxHeadless” pour lancer votre machine virtuelle, dans un launchdameon. Le problème c’est que cette commande ne gère pas la fermeture de votre machine virtuelle en réagissant au SIGTERM. Du coup, si vous redémarrez votre ordinateur, la machine virtuelle ne sera pas correctement fermée, provoquant crash et autre corruptions de fichiers. Evidemment on peut manuellement fermer le système virtuel avant d’éteindre l’ordinateur … mais pour une configuration qui demande le moins d’intervention d’un utilisateur, ce n’est pas top !

Pour compléter, j’ai cherché à activé phpVirtualBox, histoire d’avoir un accès via un navigateur à mes machines virtuelles.

Pour ce premier billet je vous propose de décomposer la méthode utilisée pour lancer une machine virtuelle en tâche de fond sur Mac.

Etape 1 : Préparer votre machine virtuelle

  • Téléchargez et installez la dernière version de VirtualBox correspondant à votre système :
    https://www.virtualbox.org/wiki/Downloads.
  • Téléchargez et installez la version de VirtualBox Extension Pack correspondant à votre système :
    https://www.virtualbox.org/wiki/Downloads.
  • Installer l’OS que vous souhaitez comme machine virtuelle sous VirtualBox.
  • Faites tous les tests nécessaires pour avoir une configuration stable et pleinement fonctionnelle.
  • Installez un outil permettant de prendre le contrôle de votre machine virtuelle à distance et sans écran (par exemple Team Viewer, SparkAngel ou plus simplement RealVNC) et testez la prise de contrôle.
  • Eteignez votre machine virtuelle.

Etape 2 : Préparer le Mac que vous allez utiliser pour héberger votre machine virtuelle en mode headless

  • Téléchargez et installez la dernière version de VirtualBox correspondant à votre système :
    https://www.virtualbox.org/wiki/Downloads.
  • Téléchargez et installez la version de VirtualBox Extension Pack correspondant à votre système :
    https://www.virtualbox.org/wiki/Downloads.
  • Déplacez sur ce Mac le dossier contenant votre machine virtuelle (dossier contenant un fichier .vbox + le disque virtuel que vous avez créé pour cette machine, par défaut au format .vdi).
  • Double-cliquez sur le fichier .vbox de votre machine virtuelle. Cette manipulation va ajouter à VirtualBox votre machine virtuelle. Si vous déplacez ensuite le dossier contenant votre machine virtuelle, pensez à la supprimer de VirtualBox, puis la relancer en ouvrant le fichier .vbox pour recréer les bonnes liaisons.
  • Notez de côté le nom de votre machine virtuelle, car vous en aurez ensuite besoin.
  • Faites un test en lançant depuis votre application VirtualBox votre machine virtuelle, puis éteignez-là et fermez VirtualBox.

Etape 3 : créer un script de démarrage et d’extinction des machines virtuelles qui récupère SIGTERM

Comme je l’ai dit plus haut, le lancement en mode headless d’une machine virtuelle via une ligne de commande ne pose pas de problème. Il suffit de faire un

/usr/bin/VBoxHeadless -s NAMEVM

en remplaçant ‘NAMEVM’ par le nom de votre machine virtuelle. Normalement, cela lance le démarrage de votre machine virtuelle, et vous devriez pouvoir y accéder à distance (puis la fermer correctement).

Une fois ce test effectué, nous allons à proprement parler mettre en place le script de démarrage suivant :

#!/bin/bash
# Expects VM name to be passed as parameter

trap shutdown SIGTERM

function displayhelp()
{
echo
echo Usage:
echo
echo -e $0 vmname\|'\x22'vmname \(long name\)'\x22'
echo -e'\t'Starts VM named '\x22'vmname'\x22' \(use quotes to enclose names with spaces\)
echo
echo -e $0 -o\|--off vmname\|'\x22'vmname \(long name\)'\x22'
echo -e '\t'Powers off VM named '\x22'vmname'\x22' \(use quotes to enclose names with spaces\)
echo  
}

function shutdown()
{
echo `date` "Received SIGTERM, powering off VBox: $VM"
/usr/bin/VBoxManage controlvm $VM savestate

# poweroff is bad 
# savestate is soft but works 
# acpipowerbutton doesn't always work

echo `date` "Powered off VBox: $VM"
echo
exit 0
}

function startup()
{
echo `date`'' "Starting VBox: $VM" 
# /usr/bin/VBoxHeadless --startvm $VM & ## Etrangement non fonctionnel sur mon mac
/usr/bin/VBoxHeadless -s $VM &
echo `date`   Running VBox: $VM
echo
wait $!
echo `date` Daemon exited: $0 $1 $2
}
echo 
echo `date` Daemon launched: $0 $1 $2

case $2 in
-o|--off) VM=$2; shutdown $VM;;
esac

case $1 in
-o|--off) VM=$2; shutdown $VM;;
-h|--help) displayhelp;;
*) VM=$1; echo VM: $VM; startup $VM;;   
esac

Enregistrez ce script là où vous le souhaitez (chez moi /VirtualBox-VMs/AUTORUN_VBOX/daemonVM.sh). Si vous le souhaitez vous pouvez le faire via un éditeur de texte ou via le Terminal avec nano :

nano /VirtualBox-VMs/AUTORUN_VBOX/daemonVM.sh

Pour rendre ce script exécutable, il faut évidemment ajuster les droits CHMOD :

sudo chmod g+x /VirtualBox-VMs/AUTORUN_VBOX/daemonVM.sh

Vous n’avez besoin que d’un seul script pour l’ensemble de vos machines virtuelles. Pour l’utiliser, comme /usr/bin/VBoxHeadless, il faut appeler le script en mettant en paramètre le nom de votre machine virtuelle, exemple :

/VirtualBox-VMs/AUTORUN_VBOX/daemonVM.sh WindowsXP

Vous pouvez évidemment faire un test d’accès à votre machine virtuelle, et l’éteindre correctement !

4. Mettre en place l’entrée launchdaemon pour un lancement en tâche de fond au démarrage de l’ordinateur

Pour que votre machine virtuelle démarre en tâche de fond, sans nécessité qu’une session soit ouverte sur le Mac hôte, nous allons créer une entrée launchdaemon. Vous pouvez le faire avec Lingon ou manuellement :

  • Créer le fichier .plist nécessaire, dans /Library/LaunchDaemons. Pour moi ce sera me.yvangodard.serveur.virtualbox.windowsxp.plist. Pour créer ce fichier vous pouvez utiliser votre éditeur favori ou le faire via le Terminal avec un petit  :
    nano /Library/LaunchDaemons/me.yvangodard.serveur.virtualbox.windowsxp.plist

    Entrer ensuite le contenu du fichier,

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    	<key>Label</key>
    	<string>me.yvangodard.reseauenscene.virtualbox.windowsxp</string>
    	<key>ProgramArguments</key>
    	<array>
    		<string>/bin/sh</string>
    		<string>/VirtualBox-VMs/AUTORUN_VBOX/daemonVM.sh</string>
    		<string>WindowsXP</string>
    	</array>
    	<key>RunAtLoad</key>
    	<true/>
    	<key>StandardErrorPath</key>
    	<string>/VirtualBox-VMs/WindowsXP/Logs/VBoxVM-error.log</string>
    	<key>StandardOutPath</key>
    	<string>/VirtualBox-VMs/WindowsXP/Logs/VBoxVM.log</string>
    	<key>TimeOut</key>
    	<integer>600</integer>
    	<key>UserName</key>
    	<string>localadmin</string>
    </dict>
    </plist>

    Pensez à personnaliser la commande “/VirtualBox-VMs/AUTORUN_VBOX/daemonVM.sh” en fonction de l’emplacement et du nom que vous avez choisi pour ce script à l’étape précédente.
    Remplacez aussi “WindowsXP” par le nom de votre machine virtuelle.
    Il faut aussi, à la fin du fichier .plist penser à entrer le nom de l’utilisateur qui a les droits pour lancer la machine virtuelle (ici “localadmin”).
    Pour être cohérents, il faut aussi une concordance entre le nom de votre fichier plist (ici me.yvangodard.reseauenscene.virtualbox.windowsxp.plist) et l’entrée “Label” du fichier (ici c’est donc me.yvangodard.reseauenscene.virtualbox.windowsxp).
    Enfin, les emplacements des journaux (log) sont aussi à adapter selon votre configuration.

  • Charger manuellement ce fichier plist à l’aide de la commande launchctl (il sera ensuite chargé à chaque démarrage de l’ordinateur).
    sudo launchctl load /Library/LaunchDaemons/me.yvangodard.reseauenscene.virtualbox.windowsxp.plist

5. Résoudre les petits problèmes …

Pour des raisons que je n’ai pas complètement identifiées encore, le chargement de la commande :

/VirtualBox-VMs/AUTORUN_VBOX/daemonVM.sh WindowsXP

via le LaunchDaemon (cf. étape 4) ne fonctionnait pas à chaque démarrage de la machine.

Au final, j’ai créé un autre script contenant

#!/bin/sh
sleep 90
/VirtualBox-VMs/AUTORUN_VBOX/daemonVM.sh WindowsXP
exit 0

Enregistrez ce script là où vous le souhaitez (chez moi /VirtualBox-VMs/AUTORUN_VBOX/VMStartWindowsXP.sh). Si vous le souhaitez vous pouvez le faire via un éditeur de texte ou via le Terminal avec nano :

nano /VirtualBox-VMs/AUTORUN_VBOX/VMStartWindowsXP.sh

Pour rendre ce script exécutable, il faut évidemment ajuster les droits CHMOD :

sudo chmod g+x /VirtualBox-VMs/AUTORUN_VBOX/VMStartWindowsXP.sh

Dans ce script j’ai déporté l’appel de la commande “/VirtualBox-VMs/AUTORUN_VBOX/daemonVM.sh WindowsXP” mais j’ai ajouté une temporisation en amont (ici 90 secondes) qui a réglé mes problèmes de crash aléatoires.

Au final j’ai donc du modifier mon LaunchDaemon. Il faut d’abort éteindre la machine virtuelle, en prenant le contrôle à distance, puis unloader le LaunchDaemon

sudo launchctl unload /Library/LaunchDaemons/me.yvangodard.reseauenscene.virtualbox.windowsxp.plist

modifier le fichier “me.yvangodard.reseauenscene.virtualbox.windowsxp.plist” ainsi :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>me.yvangodard.reseauenscene.virtualbox.windowsxp</string>
	<key>ProgramArguments</key>
	<array>
		<string>/bin/sh</string>
		<string>/VirtualBox-VMs/AUTORUN_VBOX/VMStartWindowsXP.sh</string>
	</array>
	<key>RunAtLoad</key>
	<true/>
	<key>StandardErrorPath</key>
	<string>/VirtualBox-VMs/WindowsXP/Logs/VBoxVM-error.log</string>
	<key>StandardOutPath</key>
	<string>/VirtualBox-VMs/WindowsXP/Logs/VBoxVM.log</string>
	<key>TimeOut</key>
	<integer>600</integer>
	<key>UserName</key>
	<string>localadmin</string>
</dict>
</plist>

Puis il faut recharger le Daemon :

sudo launchctl load /Library/LaunchDaemons/me.yvangodard.reseauenscene.virtualbox.windowsxp.plist

 

Et pour finir quelques ressources sur lesquelles je me suis appuyé :

http://alblue.bandlem.com/2009/09/running-headless-vms-under-mac-os-x.html

http://grahamgilbert.com/blog/2012/04/21/headless-virtualbox/

https://forums.virtualbox.org/viewtopic.php?f=8&t=32332

Posted in Apple et MacintoshTags: