Pages

Thursday, July 17, 2008

Actions handler via filesystem monitoring

Avendo avuto la necessità di eseguire degli script bash che eseguono il riavvio di servers Weblogic senza avere a disposizione una shell da cui lanciarli abbiamo pensato le più disparate possibilità, ivi compreso smanettare tutto il giorno sulla console di Weblogic, progettare applicazioni standalone jmx, pagine jsp apposite.. oggi pomeriggio mi sono reso conto che in realtà tutto ciò che serve è un crontab funzionante.
Basta creare uno script shell lanciato ripetutamente da quel crontab (tipo ogni minuto) e che controlla l'esistenza di determinati files per lanciare azioni ad essi associate (e cancellare il file che ha scatenato l'azione).
Durante qualche ritaglio di tempo nelle pause ecco cos'è uscito fuori:
#!/bin/bash                  

#ACTIONSDIR="/tmp/actions"
ACTIONSDIR="/nodel/actions"
ACTIONSCRIPTSDIR="$ACTIONSDIR/scripts"
ACTIONS="restart-admin restart-batch crontab"

function doAction() {
action="$1"
actionfile="$ACTIONSDIR/$action"
actionscript="$ACTIONSCRIPTSDIR/${action}.sh"
if [ -r $actionfile.lock ]; then return; fi
echo "`date`: running action $action with script file $actionscript" > $actionfile.lock
echo "doing action $action (script file: $actionscript)"
chmod +x $actionscript
$actionscript $action $actionfile
rm $actionfile
rm $actionfile.lock
}

function createDir() {
dirToCreate=$1
if [ -d $dirToCreate ]; then
return
fi
mkdir -p $dirToCreate
}

createDir $ACTIONSDIR
createDir $ACTIONSCRIPTSDIR

for action in $ACTIONS; do
actionfile=$ACTIONSDIR/$action
if [ -r $actionfile ]; then
doAction $action &
fi
done



Un paio di commenti:
  • Per aggiungere/rimuovere azioni basta modificare la variabile ACTIONS e aggiungere gli script nella directory adeguata (specificata da ACTIONSCRIPTSDIR)
  • gli script vengono lanciati in maniera asincrona dal loop principale, ma in maniera sincrona nel doAction, in modo tale da cancellare il file di lancio solo dopo il termine dello script. Un file di lock impedisce di rilanciare l'azione se è ancora in esecuzione.
  • Il file di lancio viene passato come argomento (insieme al nome dell'azione) allo script. Questo permette di inserire un target come "crontab", che potrebbe essere usato per aggiornare il crontab appunto leggendo dal file di lancio il nuovo cron da installare.

Saturday, July 12, 2008

Fast Scripting Tool

Spesso per risolvere determinati problemi d'ordine quotidiano mi capita di creare piccolo script shell appositi, da buon maniaco della linea di comando.
La procedura per creare uno script può risultare relativamente noiosa: creare un file con touch, renderlo eseguibile con chmod, modificarlo col proprio editor preferito, specificare in cima l'interprete ("#!/bin/bash" di solito)... ed è sempre la stessa solfa, piuttosto pallosa.
Soluzione: mi sono scritto uno script bash per creare altri script bash.
Ho anche fatto in modo di parametrizzarlo: il primo parametro è lo script da creare, il secondo l'interprete (opzionale, se non specificato di default va su "/bin/bash".
Ecco lo script, da piazzare magari in /usr/local/bin in modo da averlo nel path:
#!/bin/bash
function usage() {
echo "Usage: `basename $0` filename [interpreter path]"
exit 0
}


if test "x$1" == "x"; then
usage
fi

INTERPRETER="/bin/bash"

if test "x$2" != "x"; then
if ! [ -r $2 ]; then
echo "Error! Interpreter \"$2\"not found"
usage
else
INTERPRETER="$2"
fi
fi

cat >$1 <<EOF
#!$INTERPRETER

EOF

chmod +x $1
vim $1 +2




L'ultima riga in particolare apre vim, specificandogli anche su che riga piazzarsi.. per la precisione dopo la seconda, subito dopo la dichiarazione dell'interprete (così non si fa neanche la fatica di premere freccia-giù :P)

Friday, July 11, 2008

Paginazione in Oracle

A differenza di database come MySQL, in oracle la paginazione dei dati non è così elementare..
Esiste un campo interno ROWNUM che in effetti numera le righe del risultato di una query.
Il problema però è che la numerazione inizia dopo l'invocazione di rownum, non prima, ergo un'espressione come:
select * from ourTable where rownum>2;

non può funzionare, perchè la prima riga (rownum=1) non verrà mai visualizzata, e di conseguenza rownum non verrà mai incrementato.
La soluzione è effettuare tre nested query: la prima con la query alla tabella da noi desiderata, la seconda che limita la finestra all'offset superiore della paginazione, la terza che forza il limite inferiore, trattando rownum come una normale colonna di una tabella.
Ecco come:
select * from
(select ourTable.*, rownum rowN from
(select * from ourTable
where ourCondition=true
order by ourColumn)
where rownum <= maxPageOffset)
where rowN >= minPageOffset;

Reprise

Essì prima o poi sarebbe anche il caso di tornare a scrivere qualcosa...