Lavorando su un applicazione, mi è capitata la situazione di dover fare il deploy di un applicazione java su una macchina di test con windows, di cui non abbiamo accesso ftp, ma di cui abbiamo accesso tramite Desktop Remoto(la macchina fra l’altro è raggiungibile solo tramite tunneling sul server Proxy). Per trasferire i file dalla macchina di sviluppo alla macchina di test, si usa un server web sulla macchina Temp accessibile in ftp dalla macchina di sviluppo, e in http dalla macchina di test. Per trasferire i file dalla macchina di test a quella di sviluppo si usa il server web dell’applicazione di cui facevamo il deploy, facendo il tunneling della porta http usata .
Dalla macchina di test avevamo accesso anche al db Oracle di TEST e di PROD. Le operazioni più frequenti erano l’import e l’export e l’esecuzione di script.
Mi sono ritrovato a dover fare manualmente queste operazioni:
- Zippare il war della macchina di sviluppo, trasferirlo sulla macchina Proxy. Collegarsi in desktop remoto alla macchina di test, scaricare il war, fermare tomcat, estrarlo sotto la cartella di tomcat e copiare due file specifici per il deploy sulla macchina di test e far ripartire tomcat
- Fare il dump del db di sviluppo, zipparlo e trasferirlo sulla macchina Proxy. Collegarsi in desktop remoto alla macchina di test, scaricare il dump, estrarlo, fare la drop di tutti gli oggetti dell’user in cui mettere il dump e importarlo
- Collegarsi in desktop remoto alla macchina di test, fare il dump del db di TEST o PROD, zipparlo e metterlo sotto una cartella del web server. Scaricarlo dalla macchina di sviluppo, fare la drop di tutti gli oggetti dell’user in cui mettere il dump e importarlo.
Senza contare ovviamente l’uso del tunneling con putty (ma quello è quasi sempre attivo per altri motivi)
Tutte operazioni abbastanza lunghe, dato che il war e il dump da zippare occupano parecchi minuti e il tempo di download e di upload occupavano altrettanto. Inoltre alcune operazioni erano soggette a errore (se faccio l’export nel db di PROD invece che di TEST? se prendo il dump sbagliato? se mi dimentico di copiare i file specifici di tomcat per l’ambiente?).
Quindi ho deciso di automatizzare questo tipo di operazioni, per semplificare il deploy, e si è rivelata una scelta vincente. Potevo scegliere fra usare ant (o ancora meglio GANT, la versione Groovizzata di ANT), ma ho deciso di addentrarmi nel magico e incantato mondo dei BATCH SCRIPT di WINDOWS!!!
Per l’accesso al db ho usato sqlplus e i comandi exp e imp messo a disposizione dall’Oracle Client.
Per il download http ho usato wget, un programma linux che qualche santo uomo ha portato su Windows (non ho trovato alternative windows-like).
Per la compressione ho usato 7Zip, che ha un eseguibile da riga di comando, e offriva una compressione migliore (anche se un po’ più lente) del dump.
Per l’sftp ho usato winscp , che permette di definire degli script per l’upload e il download di file (a me nel caso serviva solo l’upload) .
Questa è la struttura delle directory:
- deploy (andrà a contenere i file temporanei, dump, compressi, etc.)
- deploy/batch (contiene i file batch)
- deploy/batch/7zip (contiene l'eseguibile 7za.exe)
- deploy/batch/sql (contiene gli script sql)
- deploy/batch/wget (contiene l'eseguibile di wget e le sue librerie)
- deploy/batch/winscp (contiene l'eseguibile di winscp)
- deploy/batch/winscp_script (contiene gli script ftp per winscp)
- deploy/batch/file_war(contiene i file da sostituire nella web-app dopo il deploy)
Gli script sql sono:
- add_grant_dba.sql (serve per ripristinare le grant dba)
- remove_grant_dba.sql (serve per rimuovere le grant dba, dato che l’user sul db di TEST e PROD non ha la grant dba
- statistiche.sql (serve per far far girare l’analyze table su tutte le tabelle dell’user dopo l’import)
declare
Cursor cTables is
select *
from user_tables;
begin
For rTable in cTables Loop
dbms_output.put_line ('analyze table ' || rTable.table_name);
execute immediate 'analyze table ' || rTable.table_name || ' compute statistics';
End Loop;
end;
/
exit;
- DropUserObjects.sql (serve per fare la drop degli obje ct dell’user prima dell’import)
declare
Cursor cConstraints is
Select *
from user_constraints
where constraint_type = 'R';
Cursor cObjects is
Select *
From user_objects
Where object_type not in ('PACKAGE BODY', 'INDEX', 'LOB');
procedure dropConstraints is
begin
For rConstraints in cConstraints loop
begin
execute immediate
'alter table ' || rConstraints.table_name || ' drop constraint ' || rConstraints.constraint_name
;
exception
When Others Then
dbms_output.put_line(
'alter table '
|| rConstraints.table_name
|| ' drop constraint '
|| rConstraints.constraint_name);
end;
End loop;
end;
procedure dropObjects is
begin
For rObjects in cObjects loop
begin
execute immediate 'drop ' || rObjects.object_type || ' ' || rObjects.object_name;
exception
When Others Then
dbms_output.put_line(
'Errore drop ' || rObjects.object_type || ' ' || rObjects.object_name
);
end;
End loop;
end;
begin
dropConstraints;
dropObjects;
end;
/
exit;
Ecco un esempio di script sftp
# per rispondere negativamente in automatico a tutte le richieste(e non bloccare il batch)
option batch on
# Disable overwrite confirmations that conflict with the previous
option confirm off
# Connessione al db. Senza l'hostkey vi chiederà se accettare l'hostkey, e dato il comando option batch on la risposta sarà no e non vi collegherete. Ricordarsi di mettere l'hostkey tra "". L’hostkey si può ricavare collegandosi con winscp(da interfaccia grafica) e cercare nelle informazioni di sessione
open sftp://user:password@example.com:22 -hostkey="ssh-rsa 1024 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"
# Posizionarsi sulla cartella voluta
cd /web/download
# Remove il file
rm dbDump.7z
# Forzare il trasferimento binario
option transfer binary
# Fare l'upload del file
put ..\dbDump.7z
# Disconnettersi
close
# Uscire da winscp. Se si vuole che lo script batch si blocchi a questo punto, commentare questa riga per far bloccare lo script
exit
Ed ecco qualche esempio di file batch sulla macchina di sviluppo:
upload_war.bat
::@echo off
del ..\war.7z
7zip\7za.exe a -t7z ../war.7z "C:\Program Files\Apache Software Foundation\Tomcat 5.0\webapps\myWebApp\"
winscp\winscp418.exe /console /script=winscp_script/upload_war.txt
ECHO
upload_db.bat
::@echo off
sqlplus -S user_dba/user_dba_pwd@db @sql\add_grant_dba.sql
sqlplus -S user/user_pwd@db @sql\remove_grant_dba.sql
exp user/user_pwd@db file=../dbDump
sqlplus -S user_dba/user_dba_pwd@db @sql\add_grant_dba.sql
del ..\dbDump.7z
7zip\7za a -t7z ../dbDump.7z "../dbDump.DMP"
winscp\winscp418.exe /console /script="winscpscript/upload_dump_db.txt"
import_db.bat
wget\wget.exe -r -O..\dbDumpTest.7z http://localhost:8090/myApp/download/dbDumpTest.7z
7zip\7za.exe e -y ../dbDumpTest.7z -o../
sqlplus -S user/user_pwd@db @sql\DropUserObjects.sql
imp user/user_pwd@dbfile=../dbDumpTest fromuser=user touser=user
sqlplus -S user/user_pwd@db @sql\statistiche.sql
echo a
Ed ecco qualche esempio di file batch sulla macchina di test:
replace_war.bat
del ..\myApp.7z
wget\wget.exe -r -O..\myApp.7z http://proxy/myApp.7z
net stop Tomcat5
rd /S /Q "C:\Programmi\Apache Software Foundation\Tomcat 5.0\webapps\myApp_old"
rd /S /Q "C:\Programmi\Apache Software Foundation\Tomcat 5.0\work\Catalina\localhost\myApp"
ren "C:\Programmi\Apache Software Foundation\Tomcat 5.0\webapps\myApp" myApp_old
7zip\7za.exe x -y ../myApp.7z -o"C:\Programmi\Apache Software Foundation\Tomcat 5.0\webapps"
copy /Y file_war\config.xml "C:\Programmi\Apache Software Foundation\Tomcat 5.0\webapps\myApp\WEB-INF\conf\"
copy /Y file_war\log4j.properties "C:\Programmi\Apache Software Foundation\Tomcat 5.0\webapps\myApp\WEB-INF\classes"
net start Tomcat5
echo
export_db_test.bat
exp user/user_pwd@db file=../dbTest CONSISTENT=Y
del ..\dbTest.7z
7zip\7za a -t7z ../dbTest.7z "../dbTest.DMP"
md "C:\Programmi\Apache Software Foundation\Tomcat 5.0\webapps\myApp\download\"
copy /Y ..\sismiDbaProd.7z "C:\Programmi\Apache Software Foundation\Tomcat 5.0\webapps\dbTest\download\"
Le operazioni fondamentali sono descritte in questa guida, sta poi allo sviluppatore combinarle per i propri scopi.
E’ qualche mese oramai che uso questi script e si sono rivelati molto utili, mi hanno fatto risparmiare moltissimo tempo ed errori. Script che automatizzano questo tipo di procedure sono fondamentali in un moderno metodo di lavoro. Per la parte java l’ottimo sarebbe avere un server di continous integration con deploy automatico sulla macchina di test (e manuale su prod o altri ambienti). In questo caso sarebbe stato complicato causa il non accesso diretto alla macchina, ma con un meccanismo di polling e timestamp penso si possa fare senza problemi.
thebol