soapi
Cluster@OVH: Basculare gli IP Failover di OVH via API
Nei cluster tradizionali con IP condiviso una macchina per diventare primaria deve assicurarsi che la secondaria sia offline e poi autoassegnarsi l’IP.
In OVH questa cosa non è sufficiente poichè spesso le macchine sono in classi C differenti e separate da router. E’ necessario quindi comunicare ad OVH che vogliamo “oscillare” un IP failover da un server ad un altro così che OVH possa aggiornare le regole di routing interne.
Normalmente questa operazione viene fatta dall’interfaccia web del manager OVH, ma è possibile farla anche tramite le API che OVH mette a disposizione con il protocollo SOAP.
Requisiti
Le api vengon utilizzate via SOAP e quindi quasi tutti i linguaggi di programmazione che dispongono di una libreria client SOAP possono essere utilizzati.
Nel mio piccolo ho provato python 2.4 con la libreria SOAPpy e PHP 5.1.6 con il SoapClient integrato ed ho riscontrato problemi con entrambe.
Sembra che il SoapClient di PHP abbia un bug critico che gli impedisce di funzionare con il wsdl di OVH. Il bug sembra corretto in PHP 5.2.6 che però non posso utilizzare.
Procedo quindi con python così da non interferire con PHP che è già presente nel sistema e configurato correttamente.
Questi i pacchetti presenti nella mia Centos 5.3:
SOAPpy-0.11.6-5.el5 e python-2.4.3-24.el5
Esempio e Problema
Prendendo ad esempio il generatore di codice client di OVH generiamo il codice python per vedere l’elenco dei failover associati
#!/usr/bin/python import pprint from SOAPpy import WSDL soap = WSDL.Proxy('https://www.ovh.com/soapi/soapi-re-1.3.wsdl') #login session = soap.login('###NIC###-ovh', '###PASS###', 'it', 0) print "login successfull" #dedicatedFailoverList result = soap.dedicatedFailoverList(session, '###NOMEDEDICATO###') print "dedicatedFailoverList successfull" pp = pprint.PrettyPrinter(indent=4) pp.pprint(result) # your code here ... #logout soap.logout(session) print "logout successfull"
ottenendo però questo risultato inaspettato:
login successfull Traceback (most recent call last): File "./example.py", line 13, in ? result = soap.dedicatedFailoverList(session, '###NOMEDEDICATO###') File "/usr/lib/python2.4/site-packages/SOAPpy/Client.py", line 453, in __call__ return self.__r_call(*args, **kw) File "/usr/lib/python2.4/site-packages/SOAPpy/Client.py", line 475, in __r_call self.__hd, self.__ma) File "/usr/lib/python2.4/site-packages/SOAPpy/Client.py", line 379, in __call p, attrs = parseSOAPRPC(r, attrs = 1) File "/usr/lib/python2.4/site-packages/SOAPpy/Parser.py", line 1006, in parseSOAPRPC t = _parseSOAP(xml_str, rules = rules) File "/usr/lib/python2.4/site-packages/SOAPpy/Parser.py", line 985, in _parseSOAP parser.parse(inpsrc) File "/usr/lib/python2.4/site-packages/_xmlplus/sax/expatreader.py", line 109, in parse xmlreader.IncrementalParser.parse(self, source) File "/usr/lib/python2.4/site-packages/_xmlplus/sax/xmlreader.py", line 123, in parse self.feed(buffer) File "/usr/lib/python2.4/site-packages/_xmlplus/sax/expatreader.py", line 216, in feed self._parser.Parse(data, isFinal) File "/usr/lib/python2.4/site-packages/_xmlplus/sax/expatreader.py", line 363, in end_element_ns self._cont_handler.endElementNS(pair, None) File "/usr/lib/python2.4/site-packages/SOAPpy/Parser.py", line 234, in endElementNS kind = (self._prem[kind[:i]], kind[i + 1:]) KeyError: u'typens'
Segnalando il problema a bugkillers@ml.ovh.net mi viene risposto velocemente che si tratta di un bug della libreria SOAP di Python (SOAPpy) presente fino alla versione 0.20 compresa. Da notare che mentre scrivo l’ultima release di SOAPpy è la 0.19 e risale al 2005. Si trovano alcuni rpm della 0.20 che probabilmente si riferiscono alla rc1 rilasciata nel 2007 ma anche questi contengono il bug di cui sopra!
L’unica è quindi utilizzare la versione di sviluppo che scarichiamo e della quale facciamo un tarball:
svn export https://pywebsvcs.svn.sourceforge.net/svnroot/pywebsvcs/trunk/SOAPpy/ SOAPpy-0.12.0 tar -zcf SOAPpy-0.12.0-dev.tar.gz SOAPpy-0.12.0 rm -rf SOAPpy-0.12.0 mv SOAPpy-0.12.0-dev.tar.gz /usr/src/redhat/SOURCES
A questo punto inseriamo il file spec appositamente creato e facciamo il build dei pacchetti (sorgente e binario) e installiamo il pacchetto appena creato.
cd /usr/src/redhat/SPECS wget http://digg.it/wp-content/uploads/2009/06/SOAPpy-0.12.0.spec rpmbuild --define="dist .el5" --define "centos 5" -ba SOAPpy-0.12.0.spec rpm -Uvh /usr/src/redhat/RPMS/noarch/SOAPpy-0.12.0-dev.el5.noarch.rpm
Il pacchetto risultante lo trovate qui: SOAPpy-0.12.0-dev.el5.noarch.rpm
Altri problemi
Un ulteriore inconveniente del metodo API utilizzabile è che per basculare un IP dobbiamo prima sapere a quale server è assegnato in questo momento.
La mia necessità, invece, è quella che un server, in autonomia e senza conoscenze esterne possa richiedere un IP failover ed ottenerlo.
Per far questo quindi ho creato uno script che una volta loggato sulle API richiede l’elenco dei dedicati associati al cliente e cerca l’IP specificato in tutti i server. Se lo trova già associato al server giusto non fa nulla, se invece lo trova associtato ad un altro server effettua la chiamata per oscillarlo verso se stesso.
Conclusioni
Lo script creato lo trovate qui: getfailover.py
E’ abbastanza spartano ma per ora fa quello che mi serve. Utilizzo questo script in combinazione con heartbeat per permettere al mio cluster OVH di oscillare automaticamente in caso di problemi.
Pagine
Articoli recenti
Archivi
- Luglio 2009 (1)
- Giugno 2009 (3)
- Maggio 2009 (2)
- Aprile 2009 (8)
- Marzo 2009 (1)