Dopo un lungo periodo di gestazione, finalmente e’ venuto alla luce questo post, che personalmente reputo molto interessante (ma va??).
Come introdotto dal titolo, espongo uno scenario di uso che mostra come poter integrare Subversion con lo sviluppo e il mantenimento della nostra web application. Nel dettaglio, con web application intendo un applicativo PHP installato in diversi server di produzione: quindi, un punto di sviluppo, tanti punti di utilizzo.
Bene, ipotizziamo ora il workflow per l’installazione per un nuovo cliente: connessione remota verso il server, quindi decompressione (se abbiamo una tarball o un archivio compresso) oppure copia (nel caso di singoli files), niente di trascendentale, quindi; il discorso si complica nel caso in cui ci accorgiamo che il nostro prodotto contiene un bug, oppure se abbiamo apportato modifiche interessanti allo stesso, e in questo caso dobbiamo operare a mano nelle n installazioni, con il rischio di sbagliare/dimenticarsi qualcosa.
E’ qui che Subversion viene in nostro aiuto per realizzare una specie di sistema di installazione/aggiornamento automatizzata di tipo “push” (spero che il termine sia giusto).
Prerequisiti:
0) un server con il client Subversion installato ed utilizzabile dall’utente di Apache, nel mio caso www-data;
1) un repository Subversion raggiungibile dal server;
2) un linguaggio di scripting presente nel repository, utilizzabile per scrivere il post-commit hook, nel mio esempio Python;
Semplificazioni:
0) il repository risiede nel mio PC, e ci accedo tramite il protocollo file://;
1) i server remoti, nel dettaglio tre, sono rappresentati da tre diverse directory nella DocumentRoot di Apache;
Ecco una piccola descrizione di cio’ che ho realizzato e di quello che vedrete negli snippets successivi.
Io ho sviluppato una web application general purpose, molto flessibile e adattabile a molti clienti, ed essendo un bravo programmatore utilizzo gia’ subversion per mantenere i miei sorgenti. Aggiungo quindi una specie di installer per l’applicazione, in pratica una pagina PHP che invoca il checkout del progetto dal repository principale.
Ecco il codice dell’installer.
[The requested file http://mcalamelli.netsons.org/files/svnwebapp/installer.txt could not be found]
Che cosa succede quando invochiamo l’esecuzione dell’installer (preventivamente copiato nel server)?
Il client svn sl server preleva il progetto dal repository e crea, con i giusti permessi (quelli del webserver), la copia locale dei files.
Cominciamo con gli snippets!
Ecco il contenuto della directory che ospita il progetto iniziale della web application
massi@aspire:~$ cd Projects/svnwebapp/ massi@aspire:~/Projects/svnwebapp$ ls -l totale 8 -rw-r--r-- 1 massi massi 104 2007-11-11 22:35 index.php -rw-r--r-- 1 massi massi 30 2007-11-02 06:48 updater.php massi@aspire:~/Projects/svnwebapp$
Creiamo ora il repository svn
massi@aspire:~$ svnadmin create /home/massi/svn/svnwebapp massi@aspire:~$
Effettuiamo ora l’import della web application nel repository appena creato
massi@aspire:~$ cd Projects/ massi@aspire:~/Projects$ svn import -m "Import iniziale" svnwebapp file:///home/massi/svn/svnwebapp Aggiungo svnwebapp/updater.php Aggiungo svnwebapp/index.php Commit della Revisione 1 eseguito. massi@aspire:~/Projects$
Ora ci spostiamo nella root del nostro webserver locale, ed eseguiamo il checkout del progetto per continuare a svilupparlo, sotto svn.
massi@aspire:~$ cd /var/www/ massi@aspire:/var/www$ sudo svn co file:///home/massi/svn/svnwebapp A svnwebapp/updater.php A svnwebapp/index.php Estratta revisione 1. massi@aspire:/var/www$
Guardiamo cosa e’ successo in /var/www
massi@aspire:~$ ls /var/www/svnwebapp/ index.php updater.php massi@aspire:~$
Bene, la directory e’ stata creata, cosi’ come i files della web application.
Ora eseguiamola!
massi@aspire:~$ lynx --source http://localhost/svnwebapp <html> <head> </head> <body> Versione PHP installata: 5.2.3-1ubuntu6 </body> </html> massi@aspire:~$
Per curiosita’ diamo una occhiata a questo complicatissimo script (index.php).
[The requested file http://mcalamelli.netsons.org/files/svnwebapp/index.txt could not be found]
Ora che abbiamo testato le funzionalita’ di svn per la gestione “locale” della web application, creiamo i nostri tre server simulati (con gli opportuni permessi), copiamo in ognuno di essi l’installer e lanciamo quest’ultimo per creare le applicazioni.
massi@aspire:~$ cd /var/www massi@aspire:/var/www$ sudo mkdir fakesrv{1,2,3} massi@aspire:/var/www$ sudo chown www-data:www-data fakesrv{1,2,3} massi@aspire:/var/www$ ls fakesrv1 fakesrv2 fakesrv3 index.html svnwebapp massi@aspire:/var/www$ cd massi@aspire:~$ sudo cp svnwebapp_installer.php /var/www/fakesrv1/ massi@aspire:~$ sudo cp svnwebapp_installer.php /var/www/fakesrv2/ massi@aspire:~$ sudo cp svnwebapp_installer.php /var/www/fakesrv3/ massi@aspire:~$ lynx --source http://localhost/fakesrv1/svnwebapp_installer.php massi@aspire:~$ lynx --source http://localhost/fakesrv2/svnwebapp_installer.php massi@aspire:~$ lynx --source http://localhost/fakesrv3/svnwebapp_installer.php
Giusto per scrupolo vediamo cosa e’ successo dentro a fakesrv1.
massi@aspire:/var/www$ ls -lR fakesrv1 fakesrv1: totale 4 drwxr-xr-x 3 www-data www-data 136 2007-11-26 13:34 svnwebapp -rw-r--r-- 1 root root 59 2007-11-26 13:34 svnwebapp_installer.php fakesrv1/svnwebapp: totale 8 -rw-r--r-- 1 www-data www-data 169 2007-11-26 13:34 index.php -rw-r--r-- 1 www-data www-data 30 2007-11-26 13:34 updater.php massi@aspire:/var/www$
Tramite lynx verifichiamo che tutto funzioni.
massi@aspire:~$ lynx --source http://localhost/fakesrv1/svnwebapp <html> <head> </head> <body> Versione PHP installata: 5.2.3-1ubuntu6 </body> </html> massi@aspire:~$
Tralascio gli snipper delle verifiche per gli altri due “server”, tutto funziona ovviamente allo stesso modo.
Riassumiamo quello che e’ successo finora: tramite l’installer ho potuto replicare la mia web application nei server dei miei ipotetici tre clienti, attingendo il codice direttamente dal repository SVN, che contiene l’ultima release del progetto.
Ora pero’ mi sono accorto che la mia web application manca di un requisito fondamentale, e cioe’ una stringa di testo con il mio indirizzo email, percio’ sono costretto ad aggiornare le varie installazioni!
Vediamo quindi in che modo il mio sistema di installer diventa comodissimo in caso di aggiornamenti: aggiungiamo un post-commit hook al repository.
Ecco il contenuto della directory del repository.
massi@aspire:~$ ls -l svn/svnwebapp totale 8 drwxr-xr-x 2 massi massi 128 2007-11-11 23:20 conf drwxr-xr-x 2 massi massi 48 2007-11-11 23:20 dav drwxr-sr-x 5 massi massi 256 2007-11-12 00:12 db -r--r--r-- 1 massi massi 2 2007-11-11 23:20 format drwxr-xr-x 2 massi massi 392 2007-11-11 23:58 hooks drwxr-xr-x 2 massi massi 104 2007-11-11 23:20 locks -rw-r--r-- 1 massi massi 229 2007-11-11 23:20 README.txt
La directory che ci interessa e’, ovviamente, hooks.
massi@aspire:~$ ls -l svn/svnwebapp/hooks/ totale 40 -rwxr-xr-x 1 massi massi 290 2007-11-11 23:58 post-commit -rw-r--r-- 1 massi massi 1996 2007-11-11 23:20 post-commit.tmpl -rw-r--r-- 1 massi massi 1673 2007-11-11 23:20 post-lock.tmpl -rw-r--r-- 1 massi massi 2290 2007-11-11 23:20 post-revprop-change.tmpl -rw-r--r-- 1 massi massi 1602 2007-11-11 23:20 post-unlock.tmpl -rw-r--r-- 1 massi massi 2969 2007-11-11 23:20 pre-commit.tmpl -rw-r--r-- 1 massi massi 2038 2007-11-11 23:20 pre-lock.tmpl -rw-r--r-- 1 massi massi 2764 2007-11-11 23:20 pre-revprop-change.tmpl -rw-r--r-- 1 massi massi 1979 2007-11-11 23:20 pre-unlock.tmpl -rw-r--r-- 1 massi massi 2137 2007-11-11 23:20 start-commit.tmpl massi@aspire:~$
Come si vede, e’ presente il mio file post-commit , al quale ho dato di permessi di esecuzione.
Vediamone il contenuto.
[The requested file http://mcalamelli.netsons.org/files/svnwebapp/post-commit.txt could not be found]
Come si puo’ vedere, e’ un semplicissimo script Python che viene eseguito ad ogni commit (da qui’ il nome post-commit): il codice mi sembra piuttosto chiaro, data una lista di URL, quelli relativi alle varie installazioni della web application, un ciclo sulla lista effettua il collegamento alla pagina updater.php di ogni installazione.
Il codice dell’updater e’ molto simile a quello dell’installer, addirittura piu’ semplice.
[The requested file http://mcalamelli.netsons.org/files/svnwebapp/updater.txt could not be found]
Ok, direi che siamo pronti a testare il tutto. Apriamo il file index.php con il nostro editor preferito, apportiamo la modifica di cui sopra e effettuiamo il commit.
massi@aspire:/var/www/svnwebapp$ sudo vi index.php massi@aspire:/var/www/svnwebapp$ sudo svn commit -m 'Aggiunto autore' Trasmetto index.php Trasmissione dati . Commit della Revisione 2 eseguito. massi@aspire:/var/www/svnwebapp$
Ora la prova del 9, verifichiamo i tre server.
massi@aspire:~$ lynx --source http://localhost/fakesrv1/svnwebapp <html> <head> </head> <body> Versione PHP installata: 5.2.3-1ubuntu6<br> ---<br> Autore: Massimiliano Calamelli<br> Email: mcalamelli@gmail.com</body> </html> massi@aspire:~$ lynx --source http://localhost/fakesrv2/svnwebapp <html> <head> </head> <body> Versione PHP installata: 5.2.3-1ubuntu6<br> ---<br> Autore: Massimiliano Calamelli<br> Email: mcalamelli@gmail.com</body> </html> massi@aspire:~$ lynx --source http://localhost/fakesrv3/svnwebapp <html> <head> </head> <body> Versione PHP installata: 5.2.3-1ubuntu6<br> ---<br> Autore: Massimiliano Calamelli<br> Email: mcalamelli@gmail.com</body> </html>
Perfetto, tutto mi sembra ok, direi che il sistema ha funzionato!
Ovviamente sono conscio del fatto che il tutto e’ realizzato in un ambiente molto differente dalla realta’, ma mi sento di poter affermare che con poche modifiche il tutto possa funzionare anche nel mondo reale; alcuni perfezionamenti che mi vengono in mente sono questi:
post-commit hook : l’elenco degli host da aggiornare potrebbe essere letto da un file, e non hard-coded all’interno dello script, in modo da poter escludere piu’ facilmente host che per svariati motivi non devono essere aggiornati. Inoltre un controllo sul risultato della connessione tramite urllib2 sarebbe auspicabile, magari con una notifica via mail dell’insuccesso dell’operazione per il/i determinati hosts;
updater.php : la pagina in questione andrebbe in qualche modo protetta, cosi’ da impedire eventuali chiamate non autorizzate.
Che dire, e’ stato veramente interessante realizzare un sistema del genere, anche se molto semplificato rispetto ad un uso reale, un motivo in piu’ per studiarsi i sistemi di controllo versione: io ho usato SVN come RCS e Python per il post-commit hook, ma nulla vieta di realizzare un sistema simile con CVS e un qualsiasi altro file eseguiibile che si chiami post-commit.
Ogni bravo programmatore dovrebbe SEMPRE usare un sistema di controllo versione.
Grazie a Fullo e Jaures per le preziose verifiche.
Alla prox
[tags]subversion, php, python, post-commit hooks, web development[/tags]
2 risposte a “Quando Subversion incontra lo sviluppo web”
Ciao,
complimenti, ottimo trick.
Forse ti converrebbe però mettere nel file di update un svn export in modo da non importare nell’ambiente di produzione i file .svn che Subversion crea..
o ancora meglio un file di installazione che crea la working copy( con svn co come hai descritto) e un file di “upgrade” che fa un svn update, no?
Ciao!
Davvero un’ottima idea.
Oltretutto il concetto è utilizzabile anche in ambiente windows :D