Dovendo gestire più di un testbed formato da macchine virtuali di numero, tipologia e topologie diverse, mi sono imbattuto in alcuni problemi. I sistemi che utilizzo sono macchine virtuali KVM e VDE per gestire la rete. Per gestirli ovviamente utilizzo Virtualbricks poiché mi semplifica, e non di poco, la vita.
Il problema
Il problema che voglio affrontare in questo articolo è un problema di semplificazione all’accesso da remoto alle varie macchine virtuali, ovvero: come fare ad accedere, utilizzando SSH, alle varie macchine virtuali utilizzando come nome degli host i nomi delle macchine virtuali che ho impostato su Virtualbricks? E soprattutto questo meccanismo può essere automatizzato, in modo che ogni macchina virtuale, appena viene lanciata, istruisca la macchina host su quale è la combinazione hostname – IP corretta per comunicare con essa?
Il primo passo: l’assegnamento degli indirizzi IP
Data la dinamicità della topologia, impostare indirizzi IP statici è di poca utilità, occorre quindi utilizzare un server DHCP per assegnare gli indirizzi, il che vuol dire che i SO delle macchine virtuali devono essere configurati per prendere l’IP automaticamente via DHCP al boot, e questo è il primo passo.
Secondo passo: il server DHCP
Il secondo passo è l’installazione del server DHCP sulla macchina host. La scelta è caduta su dnsmasq che, tra le altre cose, permette anche di associare uno script che viene lanciato subito dopo la ricezione di una richiesta DHCP al server, il che ci sarà molto utile più avanti. Per quanto riguarda il file di configurazione, esso sarà molto semplice:
interface=tap0
dhcp-range=10.0.0.100,10.0.0.200,255.255.255.0,12h
dhcp-script=/bin/add_hosts.sh
La prima riga specifica su che interfaccia si vuole restare in ascolto, il perché essa sia “tap0″ verrà spiegato più avanti. La seconda è il range di indirizzi IP e la netmask che si vuole utilizzare. Infine viene specificato lo script che deve essere lanciato.
Terzo passo: la topologia
- Image may be NSFW.
Clik here to view. - Topologia da Realizzare
Come indicato dalla figura, la topologia è composta da 5 componenti: tre VM, un VDE Switch e una interfaccia di tap. Quest’ultima in particolare è una interfaccia di rete simulata che funziona come punto di interconnessione tra la rete virtuale e la macchina host. Utilzzandola e assegnandole un indirizzo IP (come se fosse una normale scheda di rete) la macchina host diverrà parte integrante della rete e sarà connessa direttamente alle macchine virtuali. L’interfaccia di tap (e di conseguenza la macchina host nella rete) in questo esempio ha indirizzo 10.0.0.1.
Quarto passo: dove salvare le informazioni su come raggiungere le macchine virtuali?
Le informazioni che devo salvare sono due: hostname e indirizzo IP. Qual’è il posto migliore per salvare questo tipo di informazioni, in modo che siano prioritarie rispetto ai DNS? Ovviamente la risposta è il file /etc/hosts.
Quinto passo: che parametri vengono passati allo script dal server DHCP?
I parametri che il server DHCP invia allo script che è stato configurato per essere eseguito all’arrivo di una richiesta sono 4: il comando (add se è arrivata una richiesta di assegnazione, old se la richiesta per il dato mac address è già stata servita una volta, del per il release), il mac address, l’indirizzo IP assegnato ed l’hostname. Quest’ultimo purtroppo non è sempre inviato da tutti i client DHCP, per questo ho trovato un modo alternativo per recuperare l’hostname nei casi in cui non sia fornito.
Sesto passo: script per il salvataggio delle informazioni
E questa è la parte un po’ più complicata. Ecco a voi lo script che aggiunge automaticamente al file hosts le coppie hostname – indirizzo IP delle varie VM:
#!/usr/bin/python # script created by Francesco Apollonio and released under GNU General Public License version 2 # http://www.ldlabs.org/ # script that add a VM who requests an IP address using the dhcpd to local hosts file import sys import subprocess import string import time debug_file="/var/log/add_hosts.log" def debug(message): message = time.strftime("%d %b %Y %H:%M:%S") + " " + message print message fd = open(debug_file, "a") fd.write(message + "\n") fd.close() text="" for arg in sys.argv: text = text +" "+arg debug(text) action=sys.argv[1] ip=sys.argv[3] mac=sys.argv[2] hosts="/etc/hosts" # if del action is called exit from this script if action == "del": fd=open(hosts, "r") hosts_lines=fd.readlines() fd.close() fd=open(hosts, "w") for line in hosts_lines: if ip not in line: fd.write(line) debug( "Ok, %s deleted from %s file" % (name, hosts)) sys.exit(0) # add address to local hosts file if len(sys.argv) == 5: name = sys.argv[4] debug("host name from parameters: "+name) else: command = "ps ax | grep /usr/bin/kvm" process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True) found = None for line in process.stdout.readlines(): pid=line.split(" ") pid = pid[1] fd_c = open("/proc/"+pid+"/cmdline", "r") lines=fd_c.readlines() fd_c.close() if len(lines)>0: line=lines[0] line=string.replace(line, "-", " -") line=string.replace(line, "\x00", " ") else: continue if mac in line and "add_host" not in line: found = line break if found is None: debug("Ops, no VM with %s found" % mac) sys.exit(1) parms = found.split(" -")[1:] name=False for par in parms: if par.strip().startswith("name"): name = par.strip().split(" ")[1] if name is False: debug("Ops, VM name not found") sys.exit(2) fd=open(hosts, "r") hosts_lines=fd.readlines() fd.close() already=False for line in hosts_lines: if name in line: already=line break change=False if already is not False: if ip in line: debug("Ok, VM already in hosts file") sys.exit(0) else: change=True if change is False: fd=open(hosts, "a") fd.write(ip + "\t\t" + name +"\n") else: fd=open(hosts, "w") for line in hosts_lines: if name in line: line = ip + "\t\t" + name + "\n" fd.write(line) fd.close() debug( "Ok, %s added to %s file" % (name, hosts))
Il funzionamento è abbastanza semplice. In caso di comando “add” o “old” ricevuto dal server DHCP, lo script prima controlla se l’hostname è stato fornito dalla richiesta DHCP, e in questo caso procede direttamente al salvataggio. Se invece l’hostname non è stato fornito, lo script scansiona la lista dei processi KVM che sono in esecuzione. Poi si procura la command line completa con le quali le macchine virtuali sono state eseguite leggendola dall’apposito file nella cartella /proc (in una prima versione usavo direttamente l’output di ps per ottenere queste informazioni, ma, in determinate circostanze, la command line veniva tagliata, rendendo inutilizzabile lo script, per questo ho optato per recuperare le informazioni da /proc). Una volta ottenuta la command line il gioco è fatto: estraggo il nome della macchina virtuale impostato in Virtualbricks, apro il file hosts controllo che non ci sia già una voce per la macchina virtuale che ha richiesto l’indirizzo; se esiste allora semplicemente aggiorno l’indirizzo IP, se invece non esiste aggiungo una nuova voce.
Per quanto riguarda “del”, invece, apro il file hosts e se vi è l’indirizzo ip specificato, elimino la linea che lo contiene.
Parte sette: conclusioni e sviluppi futuri
Bene l’architettura funziona più che bene (la utilizzo quotidianamente). Questa è ovviamente solo una applicazione per poter creare una “rete di controllo” che permetta una più semplice gestione di un numero variabile di macchine virtuali. Per i prossimi sviluppi restate in ascolto Image may be NSFW.
Clik here to view.