Quantcast
Viewing latest article 3
Browse Latest Browse All 10

Creazione di una rete di controllo per macchine virtuali,che permetta di raggiungerle dall’host con il loro hostname

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

 

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.
:)


Viewing latest article 3
Browse Latest Browse All 10

Trending Articles