Archivio della categoria: Development

Dedicata allo svilluppo del mondo Open Source.

Linux, spazio su disco esaurito (ma sono gli iNodes)

In questi giorni si è presentato un problema sul server Linux di non facile risoluzione. L’errore che appariva era “spazio esaurito sul device” (No space left on device) ma non era lo spazio, bensì gli iNodes (grazie!) che potete verificare col comando:
df -i

Nella root / avevo il 100% utilizzato senza più un iNodes libero e il problema stava nel fatto che ogni comando dava errore proprio per la mancanza di inodes disponibili. Cosa avesse causato il problema subito facevo fatica a comprenderlo e così la prima cosa da fare è cancellare qualche files “a mano”. Ho iniziato dai log in /var/log/ cancellando ricorsivamente tutti i file .gz. Ho liberato circa 300 inodes e questo mi ha permesso di eseguire un’altra operazione: spostare una directory temporaneamente.

Con questo utile comando ho identificato una directory particolarmente piena di files da spostare per liberare ulteriore spazio (es. in /var/lib):
find /var/lib -xdev -printf '%h\n' | sort | uniq -c | sort -k 1 -n
(il comando restituisce un elenco con numero file per ogni sottodirectory)

Per liberare qualche iNode ho spostato una directory in home che risiede su un’altra partizione (gli iNodes sono riferiti ad ogni singola partizione, su /home ero solo al 3%) e poi ho creato un link simbolico (l’ho fatto per /var/lib/dpkg/info che conteneva oltre 6000 files):
mv var/lib/dpkg/info /home/jazzo/dpkg_info/

Liberato un po’ di “spazio” son riuscito finalmente a lavorare e ad approfondire il problema.
Dopo un po’ di ricerche ho scoperto che erano ancora presenti tutte le versioni del kernel dal momento dell’installazione.
Per conoscere l’elenco di tutte le versioni presenti nel sistema:
dpkg --get-selections | grep linux-image

Schermata 2015-09-17 alle 17.49.35

Ho rimosso una ad una le vecchie versioni con questo comando (lasciando solo le ultime 2):

apt-get remove --purge linux-image-3.13.0-36-generic

Ogni versione occupava circa 150Mb e 5.000 iNodes.
A questo punto ho lanciato l’autoremove e si son liberati oltre 300.000 iNodes!
apt-get autoremove

Questa la situazione prima:
Schermata 2015-09-17 alle 17.58.10
e questa dopo!
Schermata 2015-09-17 alle 17.58.23

E così ora le versioni le cancellerò di volta in volta, senza dar sempre per scontato che lo spazio sia infinito!

MediaWiki, bloccare accesso alle Special Pages (Pagine speciali)

Schermata 2013-09-20 alle 12.17.42

Se utilizzate il wiki in ambiente privato (quindi con accesso consentito solo agli utenti registrati) avrete notato che le Pagine Speciali sono accessibili da chiunque, anche agli utenti non registrati. Queste pagine contengono una serie di informazioni (tra cui elenco utenti, categorie, ecc.) molto importanti e sensibili che è bene proteggere!

Per fare questo basta aggiungere questo piccolo code snippet di MarkAHershberger nel vostro file di configurazione LocalSettings.php. Se come me utilizzate il wiki in ambiente privato però sarà necessario comunque abilitare agli utenti l’accesso alla Login Page, fondamentale direi. A questo punto resta da aggiungere una sola riga al suddetto codice.

Ecco il codice completo da utilizzare:

function disableAllSpecialPages(&$list) {
global $wgUser;
if(!$wgUser-> isLoggedIn()) {
$list = array();
// Enable Login page
$list['Userlogin'] = "LoginForm";
}
return true;
}
$wgHooks['SpecialPage_initList'][]='disableAllSpecialPages';

Testato e verificato sulla versione 1.21.2.

Conversione codifica di un file (da UTF-8/UTF-16 a cinese GB18030)

200px-Unicode_logo.svg

Mi è arrivato un file direttamente dalla Cina per la traduzione di un sito web. Lì tutto gira in UTF-8 quindi anche il file in questione (caricato dinamicamente via php) deve essere in UTF-8. Come fare?

Per prima cosa bisogna capire con precisione che tipo di encoding ha il file in questione. Mi sono documentato un po’ e per OSX molti dicono che il comando “file -I” non funziona, o meglio non bene. E’ vero: nel mio caso il file cinese aveva codifica GB18030 (Chinese) e il comando “file -I” mi ha restituito erroneamente iso-8859-1:

# file -I lang-cn.php_cn
lang-cn.php_cn: text/x-php; charset=iso-8859-1

Ho cercato sull’App Store e ho trovato l’app ezText la quale mi ha restituito la codifica corretta: GB18030 (Chinese).
A questo punto la stessa App vi permette di effettuare la conversione su una diversa codifica ma anche qui non mi ha convinto fino in fondo. Il passaggio da GB18030 a UTF-8 mi modificava anche i caratteri normali (non solo gli ideogrammi cinesi).
Per questo scopo ho trovato perfetto il comando “iconv” da Terminale, mi è bastato inviare il comando:

iconv -f GB18030 -t UTF-8 nome-file_GB18030 > nome-file_UTF8

Conversione perfetta!

Deploy di un progetto su Git via FTP

Git-Icon-1788C

Git è eccezionale, una volta scoperto difficilmente si torna indietro.
Tutti i miei progetti infatti ora sono su Git e per la maggior parte di essi il relativo ambiente di produzione risiede su Hosting Linux “normali”, quelli in cui il provider fornisce come unica possibilità di aggiornamento dei file il servizio FTP. Così, dopo aver terminato lo sviluppo di nuove features, mi ritrovo spesso con diversi commit eseguiti e per aggiornare l’ambiente in produzione avevo 2 possibilità:

  1. effettuare l’upload dell’intero progetto sovrascrivendo tutti i file
  2. creare un file di tutti i file modificati (estrandoli da tutti i commit) per poi aggiornarli via FTP

La prima soluzione è sicuramente la più veloce ma spesso risulta lunga e si va ad utilizzare banda inutilmente perchè la maggior parte dei file non dovrebbe essere aggiornata (parliamo di tutti quelli non modificati). La seconda soluzione richiedeva un lavoro da certosino che poi ho scoperto di poter eseguire tramite alcuni comandi Git. Da qui ho pensato di realizzare uno script shell per ottimizzare le operazioni di deploy in produzione: Git-Deploy-by-FTP.

E’ il mio primo shell script e l’ho condiviso via GitHub, sicuramente può essere migliorato! 😉
L’ambiente su cui sviluppo e su cui ho testato il corretto funzionamento è OSX.

Come funziona?

Questo script può essere richiamato da riga di comando e devono essere passati alcuni parametri che vedremo successivamente.
Le operazioni che esegue possono essere sostanzialmente riassunte in:

  • crea un git clone del repository e su questa copia lavora
  • effettua un git diff per estrarre tutti i file modificati/eliminati/aggiunti basandosi su 2 commit che definiamo “deploy” e “production
  • esegue l’aggiornamento di tutti i file (eliminandoli dove necessario) dell’ambiente di produzione via FTP (tramite CURL)

Ho preferito far lavorare lo script su un clone in modo da poter stare tranquilli su eventuali problemi dovuti ad interruzione delle procedure. Lavorando su una copia del repository infatti in qualsiasi momento posso interrompere la procedura senza creare problemi al repository principale.

I due commit “deploy” e “production” sono identificati dal loro SHA. Il primo (deploy) rappresenta lo stato dei file nel commit che vorrei mandare in produzione, il secondo (production) identifica l’ultimo commit mandato in produzione. Il comando git diff esegue le operazioni anche a ritroso, quindi potrei anche effettuare un downgrade del software anzichè un upgrade.

L’aggiornamento dei file avviene tramite comando CURL che effettua il login via FTP e invia i comandi necessari.

Configurazione

Ho pensato ad un sistema flessibile che mi permettesse di gestire più progetti tramite un unico script. L’idea quindi è quella di poter scrivere diversi file di configurazione e richiamare quello interessato tramite parametro da riga di comando (vedi sotto). Nello script trovate un file di esempio di configurazione: dp-sample-config.
Create una copia del file e rinominatelo secondo questo criterio: .dp-config-ProjectName
dove ProjectName identifica un vostro progetto. In questo modo potrete avere diversi file di configurazione, uno per ogni progetto. I file di configurazione devono necessariamente risiedere nella stessa directory dello script (iniziando col . però dovrebbero rimanere nascosti).

Le variabili da valorizzare obbligatoriamente in ogni file sono quelle nella sezione “SETTINGS”:

  • EXPORTED_DIR – è la directory temporanea utilizzata per creare il repo clone di cui sopra
  • PROJECT_REPO_DIR – è la directory in cui si trova il repository da utilizzare
  • FTP_SERVER – il nome del server FTP dell’ambiente in produzione
  • FTP_PATH – il path dell’ambiente in produzione del suddetto server FTP
  • FTP_USERNAME – FTP username per connettersi al server
  • FTP_PASSWORD – FTP password per connettersi al server

Nel file troverete anche altri parametri secondari che potrete configurare in un secondo momento dopo averne capito il loro utilizzo.

Usage (come usare lo script)

Lo script dp.sh può essere richiamato da riga di comando passando alcuni parametri di cui 2 obbligatori:

  • -p, –project Imposta il nome del progetto di cui si vuole effettuare il deploy
  • -d, –deploy Imposta il commit di cui si vuole effettuare il deploy
  • –not-simulate Con questo parametro lo script eseguirà il deploy realmente, viceversa effettuerà solo una simulazione

Il parametro -p (o –project) deve essere seguito dal ProjectName di cui sopra.
Il parametro -d (o –deploy) deve essere seguito dal SHA del commit di cui si vuole effettuare il deploy.
Dopo aver verificato tramite simulazione che tutto è corretto potrete aggiungere il parametro –not-simulate per effettuare realmente il deploy. Questo parametro è stato aggiunto per ovvi motivi di sicurezza, meglio una simulazione in più che qualche file errato in produzione!

Ora un esempio di comando:
# dp.sh --project progetto1 --deploy bb5c8d9

Questo comando per prima cosa cercherà il file di configurazione .dp-config-progetto1 da cui prelevare le suddette variabili. Successivamente effettuerà una simulazione del deploy del commit bb5c8d9 in ambiente di produzione. Aggiungendo come ultimo parametro –not-simulate i file verranno realmente inviati via FTP al server.

Tag “production”

Ho cercato una soluzione che mi permettesse di tenere traccia dell’ultimo deploy effettuato in modo da sapere sempre in che commit si trova l’ambiente di produzione. Per fare questo utilizzo un tag chiamato “production” sul repository principale. Prima di effettuare il “git diff” di cui sopra lo script interroga il repository per ottenere il commit relativo al tag “production”.

In fase di chiusura delle operazioni, solo nel caso in cui non sia stata effettuata una simulazione, lo script sposta il tag “production” sul nuovo commit di cui si è appena effettuato il deploy. Questa è l’unica operazione che viene eseguita sul repository principale e non sulla copia clonata.

ToDo list

Lo script al momento funziona bene quando i commits “deploy” e “production” sono sullo stesso branch. Nel caso si trovino su due branch diversi è bene verificare con attenzione cosa accade (simulate!).
Una nuova feature da implementare è sicuramente la gestione dei sub-moduli che al momento vengono ignorati dalla procedura.

Buon deploy! 😉

 

 

 

 

 

 

 

 

Da SVN a GIT

Git-Icon-1788C

Oggi ho trasferito l’ultimo repository SVN su GIT.
E’ arrivato quindi il momento di salutare SVN! Quando passai da CVS a SVN fu un salto di qualità, tutto appariva più semplice ma “meccanicamente” i due funzionavano allo stesso modo. Grazie quindi SVN!

Il passaggio a GIT invece all’inizio è stato davvero duro, è completamente diverso. Tutte le certezze acquisite negli anni su SVN crollarono, senza considerare poi che con qualche operazione “azzardata” cancellai anche i primi commit! Più volte ho pensato di tornare indietro. Entrare nei meccanismi di GIT non è facile e soprattutto tocca tornare a studiare. Però poi, quando entri “nella testa” di GIT (o meglio, di Linus Torvalds che l’ha creato nel 2005), entri in un altro mondo e non torneresti più indietro!

Su SVN prima di fare un commit ci pensi giorni, controlli e verifichi ogni cosa più volte perchè un commit non è cosa da poco. Su GIT ne fai uno ogni 2 ore. Lo stesso vale per i branch: crearne uno su SVN vuol dire che si sta iniziando qualcosa di grosso, una nuova release strutturalmente diversa. In GIT un branch lo apri anche solo per fixare un bug.

In GIT il repository è sempre con te, c’è tutta la storia. Ogni commit, tag, branch è lì con te, in locale. Ovviamente però anche GIT offre la possibilità di gestire un repo in remoto ma è soltanto una copia di ciò che hai in locale. Semplicemente un altro repo GIT che ti permette di lavorare su un progetto insieme ad altri.

Poi con GIT ti avvicini a GitHub e scopri un mondo nuovo, inizi a gestire le varie librerie come sub-moduli. Crei forks personali dei vari moduli sul tuo GitHub e li tieni allineati con l’origine. Quando impari ad usare i moduli ti rendi conto che GIT ha una marcia in più.

Ovviamente han pensato anche ad una procedura di importazione da SVN a GIT che funziona una meraviglia!

Gmail Imap RFC822.SIZE fail (zero)

Gmail_logo.png

I’m working on my BackUp Gmail App for OSX and I got a very strange issue.

This is the Imap transaction on Gmail server:


>> TAG02 UID FETCH 77480:77490 (UID RFC822.SIZE RFC822 X-GM-MSGID)


<< * 22136 FETCH (X-GM-MSGID 1384367682512034576 UID 77480 RFC822.SIZE 0 RFC822 {11012}
Delivered-To: *****@gmail.com
....
....
....
)
TAG21 OK Success

Look at the RFC822.SIZE, it’s 0 (zero)!
But it isn’t really zero because then it starts the RFC822, and it’s complete (11012 bytes).

When I create the backups I got it always at the same time, all the emails after Nov 2011 until Feb 2012 have this issue.
Maybe Gmail had problems in this period?
Anybody knows it?

Updated on 30 May 2013

I posted this issue on the Imap-protocol mailing list and today I received a reply from Jamie Nicolson (Google).
As you can read in this reply it is a temporary Gmail bug: “it affected messages during a certain timeframe in the past … We’re hoping to clean this up”.

 

 

Migrare WordPress su nuovo dominio

Wordpress logo

Migrare un sito in WordPress da un dominio ad un altro potrebbe apparire un’operazione semplice ma in realtà le cose sono complesse. WordPress memorizza in diversi punti nel database alcuni parametri associati al dominio stesso o al percorso locale in cui WP stesso è installato. Tutti questi riferimenti risultano spesso annidati in array serializzati e memorizzati in campi di database. Un’eventuale modifica “a mano” via phpMyAdmin quindi risulterebbe abbastanza scomoda e assai lunga.

Allora ho creato uno script (parser_WP.php) in PHP che modifica ogni riferimento presente nel database in modo da agevolare le operazioni.

Ricapitolando quindi, per migrare un sito WordPress su un dominio diverso, dovete:

  1. Copiare tutti i file e cartelle da un server ad un altro (via FTP, a partire dalla root)
  2. Creare un dump del database
  3. Creare un database vuoto sul nuovo dominio
  4. Importare il dump precedentemente creato
  5. Copiare lo script di cui sopra nella root del nuovo dominio e lanciarlo via browser (dopo aver configurato i dati di accesso al database)

Le modifiche da apportare al database sono di 2 tipi: sul dominio e sul path.
Aprendo lo script noterete che nelle prime righe vi sono 2 variabili da impostare:

$lookFor = "domain-1.com";
$replace = "domain-2.com";

Sostituite domain-1 con il nome del vecchio dominio e domain-2 col nome del nuovo dominio.

WordPress però, come dicevamo, memorizza anche il path assoluto in cui è installato. Dovrete quindi lanciare nuovamente lo script sostituendo le 2 variabili con i path: vecchio e nuovo. Ad esempio:

$lookFor = "/home/myOLDuser/";
$replace = "/home/myNEWuser";

Lanciate nuovamente il file. In questo secondo caso il risultato restituito (lo script restituisce il numero di valori modificati) sarà molto basso rispetto al primo (anche se questo varia a seconda dei plugin, widget, ecc. installati).

Fatto, ricordatevi di rimuovere lo script php dalla root!!

PHP: Nascondere errori “DEPRECATED” via .htaccess

logo-PHP

Sto installando un’applicazione in ambiente di prova, giusto per guardamela un po’ e per approfondire un po’ le funzionalità implementate. Peccato che l’applicativo in oggetto su PHP 5.3 genera una marea di errori di “DEPRECATED” dovuti alla funzione eregi ormai dichiarata obsoleta dal PHP 5.3 in avanti. Per velocizzare il tutto ho pensato di non visualizzare tali errori.

Le alternative sono diverse ma preferisco sempre aggiungere l’impostazione tramite file .htaccess in modo da “non sporcare” il codice sorgente. Ho quindi aggiunto un file .htaccess nella root del progetto aggiungendo questa riga:

php_value error_reporting 22527

Il livello 22527 corrisponde a  “E_ALL & ~E_DEPRECATED“, appunto tutti gli errori tranne i deprecated. Nel file .htaccess non è possibile inserire il testo, si può solo configurare tramite bitmask corrispondente calcolata sulla base delle costanti predefinite per error_reporting.

Se non siete ferrati sull’argomento bitwise operators o non avete voglia e tempo potete rapidamente calcolarvelo tramite queste 2 righe in PHP, la prima imposta il valore che desiderate (utilizzando le costanti e gli operatori bitwise) la seconda stampa a video la bitmask corrispondente (un numero intero) che poi potrete utilizzare per configurare il tutto tramite file .htaccess:

error_reporting( E_ALL & ~E_DEPRECATED );
echo error_reporting(); die;