mercoledì 17 giugno 2015

Monitorix - uno snello sistema di monitoring risorse per Linux


Oggi presento Monitorix, un sistema di monitoraggio delle risorse del sistema per Linux. E' strutturato in due parti:
- un demone che colleziona i dati storicizzandoli;
- un webserver con uno script cgi che permette la visualizzazione dei dati raccolti in formato grafico.

L'installazione è molto semplice, sul sito si trovano le istruzioni. Riporto i passi per l'installazione su Debian / Ubuntu:

1. Modificare il file /etc/apt/sources.list aggiungendo
deb http://apt.izzysoft.de/ubuntu generic universe

2. Scaricare la chiave GPG del repository
wget http://apt.izzysoft.de/izzysoft.asc

3. Aggiungere la chiave
sudo apt-key add izzysoft.asc
4. Installare monitorix
sudo apt-get update
sudo apt-get install monitorix

A questo punto, ci si può godere il risultato collegandosi all'indirizzo ip del server sul quale monitorix è installato, oppure in locale: porta 8080, sottocartella monitorix/
http://localhost:8080/monitorix/



venerdì 5 giugno 2015

Caricamento automatico delle classi in Php

In principio fu l'include (o il require) di tanti file php che contenevano funzioni. 
Poi vennero le classi, incluse a mano una per una.
Ed ora? Adesso il Php è un linguaggio molto più maturo, dotato di namespace, che permettono a classi con lo stesso nome di coesistere (con namespace diversi) all'interno dello stesso progetto. In questo modo, includere una libreria di terze parti progettata a namespace non comporta più problemi di omonimia di classi.
Altra caratteristica utilissima, novità rispetto al passato, è l'autocaricamento delle classi. Onde evitare una lunghissima lista di inclusioni, una per ogni classe, è stata introdotta la funzionalità di autoload.
Come funziona? Semplice: utilizzando la funzione spl_autoload_register() spiegheremo all'interprete Php come comportarsi in caso di classi "che non conosce", ovvero che non sono state esplicitamente incluse nello script. Per maggiori informazioni, consiglio il sito ufficiale.
Vediamo un semplice esempio:
//Autoloading classes
spl_autoload_register(function($className)
{
     //Obtain the pure class name
     $pureClassName = getRealClassName($className);
     //Build the path
     $namespace = getNameSpace($className);
     if(file_exists($namespace.'/'.$pureClassName.'.php')) {
         include_once($namespace.'/'.$pureClassName.'.php');
     }
});

function getRealClassName($fullClassName) {
     //Explode class name
     $classNameArray = explode('\\',$fullClassName);
     //Obtain the pure class name
     return end($classNameArray);
}
    
function getNameSpace($fullClassName) {
     //Explode class name
     $classNameArray = explode('\\',$fullClassName);
     //Remove the pure class name
     array_pop($classNameArray);
     //Remove the main namespace (first)
     array_shift($classNameArray); 
     //Build the path
     $namespace = implode('/', $classNameArray);
     return $namespace;
}
Breve spiegazione: nel caso il Php non trovi una classe, tenta una inclusione automatica, cercando il file posizionato nel percorso indicato dal namespace (stessa struttura delle cartelle quindi) e chiamato come il nome della classe, con estensione php. Le due funzioni getRealClassName() e getNameSpace() sono semplici funzioni che interpretano il nome della classe separando namespace dal nome "proprio" della classe stessa. Unica cosa degna di nota, viene eliminato il primo ramo del namespace, che solitamente è il nome del progetto.
Quindi, riassumendo, un comando simile:
new \ProjectName\Core\Othernamespace\Classname()
Causerà una include automatica del percorso
Core/Othernamespace/Classname.php

venerdì 22 maggio 2015

Impostare la replicazione Mysql - procedura passo passo

Se gestite un server MySql in azienda, e volete dormire sonni tranquilli, è ovviamente fondamentale la schedulazione di un backup serale. Questo spesso non è sufficiente: il downtime per il ripristino in caso di guasto può essere troppo lungo, o addirittura può essere concreto il rischio di perdere dati di una buona metà giornata di lavoro.

Per dormire sonni tranquilli, basta affidarsi alla MySql Replication. Come funziona? Semplice, gli attori in gioco sono minimo due:
- un server MySql Master (master_host)
- uno o più server MySql Slave (slave_host)
Una magia rende possibile l'allineamento dei due server: ogni operazione eseguita sul master viene a sua volta eseguita anche sullo slave. Risultato: due server con dati identici (a meno di un leggero scostamento temporale nelle operazioni tra master e slave).
Di seguito la procedura che ho seguito, passo passo, per l'impostazione del sistema.

Fase 1: impostazione del server Master

E' fondamentale spiegare al server MySql principale che farà da Master. Per fare questo occorre agire sul file di configurazione my.cnf (o my.ini) aggiungendo le seguenti direttive nella sezione [mysqld]
[mysqld]
log-bin=mysql-bin
server-id=1
Il parametro server-id può essere un numero qualsiasi tra 1 e (232-1) e deve essere univoco tra i vari server MySql della rete Master Slave che si vuole creare. Il mio consiglio è quello di andare in ordine crescente: 1 per il master, dal 2 in poi per gli slave.
Importante: dopo questa modifica, riavviare il servizio MySql. Da questo momento ogni operazione eseguita sul server sarà salvata in un log.

Fase 2: dump del database del server Master

Si suppone ovviamente che il server MySql che farà da master sia un server che possiede già dei dati al suo interno. Il che significa che è necessario sincronizzare i dati tra master e slave. Per fare ciò, ci viene in aiuto il comando mysqldump
mysqldump -h master_host -u root - p --all-databases --master-data -e > dump.sql
Il comando eseguirà il dump creando il file dump.sql. Apriamo a questo punto il file con un editor di testi e segnamoci, da una parte, i comandi relativi al master_log_file e master_log_pos. Ad esempio, nel mio caso:
MASTER_LOG_FILE='mysql-bin.000016', MASTER_LOG_POS=458850265;
Come ho scritto, segnamo a parte le informazioni relative al log file e alla posizione del log. La posizione del log indicherà allo slave la posizione di partenza del dump importato.

Fase 3: creazione di un utente specifico per la replicazione

Questa fase non è obbligatoria ma altamente consigliata. Semplicemente è necessario creare un utente per la replicazione sul server master:
CREATE USER 'repl'@'%' IDENTIFIED BY 'slavepass';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';

Fase 4: impostazione del server slave

Sul server slave, è necessario inserire nel file di configurazione, nella sezione [mysqld], la direttiva
[mysqld]
server-id=2
o comunque un numero diverso da altri server Mysql e soprattutto differente dall'id del master. Riavviare il servizio MySql del server slave.

Fase 5: importazione del dump sul server slave

E' necessario in questa fase importare il dump precedentemente creato. Dalla shell eseguire:
mysql -h slave_host -u root -p < dump.sql
Ed attendere il completamento dell'operazione.

Fase 6: impostazione delle informazioni del master sul server slave

In questa fase, il server slave viene informato su quale sarà il suo master di riferimento. Avendo sotto mano la posizione del log e il nome del log del master segnato in precedenza, è necessario eseguire sul server slave:
CHANGE MASTER TO
MASTER_HOST='master_host',
MASTER_USER='repl',
MASTER_PASSWORD='slavepass',
MASTER_LOG_FILE='mysql-bin.000016',
MASTER_LOG_POS=458850265

Fase 7: avvio della replicazione sul server slave

Con un semplice
START SLAVE;
si iniziano le danze. E' possibile a questo punto controllare lo stato della replicazione eseguendo sul server slave
SHOW SLAVE STATUS;

[Immagine via clusterdb.com]

giovedì 14 maggio 2015

JarvisPHP - Il tuo maggiordomo personale in Php!


JarvisPhp è la mia ultima creazione. In breve si tratta di un sistema REST API scritto in Php che permette una interazione diretta con l'utente attraverso dei comandi. Questi comandi possono essere vocali, pronunciati e riconosciuti da un STT (Speech to text) come ad esempio una applicazione Android mediante le funzioni Android STT,  e successivamente inviati (in stringa) alle API di JarvisPHP.
Lo scenario è il seguente: l'utente (il padrone di casa) parla attraverso un auricolare bluetooth collegato con uno smartphone, premendo il bottone dell'auricolare. Il comando viene interpretato dal riconoscitore vocale della app ed inviato a JarvisPHP, che tenta di comprenderlo ed eseguire qualche azione.
JarvisPHP è stato pensato per un Raspberry PI vista la sua comodità e dimensione, ma può essere usato su qualsiasi sistema *nix.


Download

E' possibile scaricare l'ultima versione di JarvisPHP su Github a questo indirizzo:
https://github.com/bianchins/JarvisPHP


Documentazione

Potete fare riferimento al wiki per tutta la documentazione:
https://github.com/bianchins/JarvisPHP/wiki/


Architettura del sistema

Come può JarvisPHP eseguire una azione? Come riesce ad interagire con l'ambiente? Semplicemente, utilizza dei plugins per eseguire il comando che ha interpretato. Per esempio, chiedendo "Chi sei?" il sistema attiverà il plugin "Info plugin" che risponderà "Il mio nome è...".
Un plugin (è semplicissimo scrivere un proprio plugin, basta seguire queste istruzioni) può fare qualsiasi cosa: per esempio, interagire con l'interfaccia GPIO di un Raspberry Pi (http://www.raspberrypi.org), suonare musica, interrogare API pubbliche meteo, leggere email, connettersi a facebook e leggere le notifiche, e così via.

sabato 10 gennaio 2015

Summernote - un editor WYSIWYG per Bootstrap

Oggi presento Summernote, un editor WYSIWYG per Bootstrap molto ben fatto. Tra le caratteristiche che lo rendono un ottimo prodotto (a mio parere) sono la facilità di installazione, la gestione del menù personalizzata e la possibilità di mostrare il sorgente del testo immesso.

Installazione

Si può installare direttamente dai sorgenti oppure tramite bower:
bower install summernote

Dipendenze

Utilizza ovviamente Bootstrap (e jQuery), assieme a font-awesome. Questo significa che è necessario includere i seguenti file (se non sono già inclusi nella pagina html):
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css" rel="stylesheet"></link>

<!-- include summernote css/js-->
<link href="summernote.css" rel="stylesheet"></link>
<script src="summernote.min.js"></script>

Inserimento del codice html e javascript

Un semplice <div> verrà trasformato in un editor Summernote con poche righe di codice javascript:
<div id="summernote">Hello Summernote</div>
<script>
$(document).ready(function() {
  $('#summernote').summernote();
});
</script>

Risultato


:-)

venerdì 9 gennaio 2015

Il meteo con Php e le API di Yahoo Weather

A tempo perso sto preparando una sveglia con Raspberry PI, che al momento di suonare si colleghi ad un sistema meteo, scarichi le informazioni e le pronunci tramite un sintetizzatore vocale.


Il primo passo è quindi quello di sviluppare un sistema che possa comprendere le condizioni meteo esterne. Ho trovato il servizio di API Yahoo Weather e me ne sono innamorato!
Di seguito è mostrato il codice dello script php che ho sviluppato: utilizza le funzioni curl per interfacciarsi con le API che rispondono in JSON, ho mappato i codici delle condizioni meteo in italiano (come da documentazione ufficiale) e ho scovato su stackoverflow una funzione per tradurre la direzione del vento da gradi alle classiche direzioni da rosa dei venti.
<?php

//Tradotto in php dall'originale 
//http://stackoverflow.com/questions/7490660/converting-wind-direction-in-angles-to-text-words
function degToCompass($num) {
    $val=floor(($num/22.5)+.5);
    $arr=["N","NNE","NE","ENE","E","ESE", "SE", "SSE","S","SSW","SW","WSW","W","WNW","NW","NNW"];
    return $arr[($val % 16)];
}


$condizioni = array(
"0"=>  "tornado",
"1"=>  "tempesta tropicale",
"2"=>  "uragano",
"3"=>  "forti temporali",
"4"=>  "temporali",
"5"=>  "pioggia mista a neve",
"6"=>  "pioggia mista a nevischio",
"7"=>  "neve mista a nevischio",
"8"=>  "pioviggine gelata",
"9"=>  "pioggerella",
"10"=>  "pioggia gelata",
"11"=>  "rovesci",
"12"=>  "rovesci",
"13"=>  "raffiche di neve",
"14"=>  "rovesci di neve leggeri",
"15"=>  "soffia neve",
"16"=>  "neve",
"17"=>  "grandinare",
"18"=>  "nevischio",
"19"=>  "polvere",
"20"=>  "nebbioso",
"21"=>  "foschia",
"22"=>  "foschia",
"23"=>  "ventoso",
"24"=>  "ventoso",
"25"=>  "freddo",
"26"=>    "nuvoloso",
"27"=>  "Sereno",
"28"=>  "Sereno",
"29"=>  "parzialmente nuvoloso",
"30"=>  "parzialmente nuvoloso",
"31"=>  "Sereno",
"32"=>  "soleggiato",
"33"=>  "Sereno",
"34"=>  "Sereno",
"35"=>  "pioggia mista e grandine",
"36"=>  "caldo",
"37"=>  "isolati temporali",
"38"=>  "temporali sparsi",
"39"=>  "temporali sparsi",
"40"=>  "Rovesci sparsi",
"41"=>  "tormenta di neve",
"42"=>  "rovesci di neve sparsi",
"43"=>  "tormenta di neve",
"44"=>  "parzialmente nuvoloso",
"45"=>  "rovesci temporaleschi",
"46"=>  "rovesci di neve",
"47"=>  "Temporali isolati",
"3200"=>  "non disponibile"
);

$BASE_URL = "http://query.yahooapis.com/v1/public/yql";

$yql_query = 'select * from weather.forecast where woeid in (select woeid from geo.places(1) where text="Rimini, Italy") and u="c"';
$yql_query_url = $BASE_URL . "?q=" . urlencode($yql_query) . "&format=json";

$session = curl_init($yql_query_url);
curl_setopt($session, CURLOPT_RETURNTRANSFER,true);
$json = curl_exec($session);
$phpObj =  json_decode($json);
echo "\nMeteo per Rimini\n";
echo "----------------\n";
echo "Temperatura:      ";
echo $phpObj->query->results->channel->item->condition->temp."° C\n";
echo "Condizioni meteo: ";
echo $condizioni[$phpObj->query->results->channel->item->condition->code]."\n";
echo "Alba:             ";
echo $phpObj->query->results->channel->astronomy->sunrise."\n";
echo "Tramonto:         ";
echo $phpObj->query->results->channel->astronomy->sunset."\n";
echo "Umidità:          ";
echo $phpObj->query->results->channel->atmosphere->humidity."%\n";
echo "Pressione:        ";
echo $phpObj->query->results->channel->atmosphere->pressure." millibar\n";
echo "Previsioni:       ";
echo $condizioni[$phpObj->query->results->channel->item->forecast[0]->code];
echo ", t. max ".$phpObj->query->results->channel->item->forecast[0]->high;
echo "° C, t. min ".$phpObj->query->results->channel->item->forecast[0]->low." °C \n";

echo "Vento:            ";
echo $phpObj->query->results->channel->wind->speed." km/h ";
echo degToCompass($phpObj->query->results->channel->wind->direction)."\n";

giovedì 23 ottobre 2014

Estendere un disco LVM in Ubuntu Server 14.04 su Aruba Cloud

Una delle comodità dei server in cloud è la possibilità di aggiungere risorse man mano che servono. Mentre per CPU e Ram è sufficiente operare sul pannello di controllo dell'infrastruttura cloud, per l'aumento dello spazio disco bisogna eseguire qualche operazione in più. Per quale motivo? Perché lo spazio aggiuntivo, impostato dal configuratore, estende il disco fisicamente, ma non la partizione del sistema operativo. E senza queste operazioni ci si ritroverà un disco più grande, ma la partizione (attiva) del sistema operativo delle dimensioni precedenti!

Avendo alcuni server su Aruba Cloud, ho avuto la necessità di estendere il disco di una macchina virtuale con sistema operativo Ubuntu Server 14.04. Le istruzioni che mostrerò sono però valide anche per altri sistemi operativi linux, in particolare tutti quelli che supportano LVM.

Il primo passo sarà quello di spegnere la macchina virtuale ed agire sul pannello di controllo del cloud, aggiungendo spazio al disco principale. Nel mio caso sono voluto passare da 10 GB a 30 GB.
Si può ora riattivare la macchina virtuale. I passi sono semplici:

1. controllare mediante il comando parted l'effettivo spazio libero non allocato, digitandovi il comando print free ed analizzando il risultato. Ciò che ci interessa, è la riga "Free Space" di 21.5 GB (nel mio caso).
Per uscire, basta digitare "q".
root@CloudServer:~# parted
GNU Parted 2.3
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) print free                                                       
Model: VMware Virtual disk (scsi)
Disk /dev/sda: 32.2GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number  Start   End     Size    Type      File system  Flags
        32.3kB  1049kB  1016kB            Free Space
 1      1049kB  256MB   255MB   primary   ext2         boot
        256MB   257MB   1048kB            Free Space
 2      257MB   10.7GB  10.5GB  extended
 5      257MB   10.7GB  10.5GB  logical                lvm
        10.7GB  32.2GB  21.5GB            Free Space
2. creare una nuova partizione con il comando
root@CloudServer:~# cfdisk
selezionare la riga dello spazio libero interessato, selezionare New, poi scegliere partizione Logica [Edit: un utente mi ha giustamente fatto notare che a questo punto, è necessario specificarne il formato, ossia 8E]. Infine selezionare Write per salvare le modifiche e infine Quit per uscire. Nel mio caso è stato necessario riavviare la macchina virtuale, quindi consiglio di farlo.

3. controllare l'avvenuta creazione della partizione, nel mio caso /dev/sda6
root@CloudServer:~# fdisk -l /dev/sda

Disk /dev/sda: 32.2 GB, 32212254720 bytes
255 heads, 63 sectors/track, 3916 cylinders, total 62914560 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000bc621

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048      499711      248832   83  Linux
/dev/sda2          501758    62914559    31206401    5  Extended
/dev/sda5          501760    20969471    10233856   8e  Linux LVM
/dev/sda6        20969535    62914559    20972512+  83  Linux

4. creare il volume fisico per sda6
root@CloudServer:~# pvcreate /dev/sda6
  Physical volume "/dev/sda6" successfully created

5. controllare i volumi fisici
root@CloudServer:~# pvdisplay
  --- Physical volume ---
  PV Name               /dev/sda5
  VG Name               vg
  PV Size               9.76 GiB / not usable 2.00 MiB
  Allocatable           yes (but full)
  PE Size               4.00 MiB
  Total PE              2498
  Free PE               0
  Allocated PE          2498
  PV UUID               5fDfUK-6RjG-nFMX-iNgM-44rF-7zz0-4JIr9Y
   
  "/dev/sda6" is a new physical volume of "20.00 GiB"
  --- NEW Physical volume ---
  PV Name               /dev/sda6
  VG Name               
  PV Size               20.00 GiB
  Allocatable           NO
  PE Size               0   
  Total PE              0
  Free PE               0
  Allocated PE          0
  PV UUID               hu4B6U-WDfx-zocW-13uX-BiwJ-2CoM-LHKhT9

6.  estendere il nuovo volume creato (sda6) dandogli lo stesso VG name del volume principale (sda5), nel mio caso vg
root@CloudServer:~# vgextend vg /dev/sda6
  Volume group "vg" successfully extended

7. controllare il nome del volume logico da estendere (nel mio caso /dev/vg/lv_root)
root@CloudServer:~# lvdisplay
  --- Logical volume ---
  LV Path                /dev/vg/lv_swap
  LV Name                lv_swap
  VG Name                vg
  LV UUID                CohmrO-3wcX-zLMV-exxT-gUDu-dAxo-vJhfD4
  LV Write Access        read/write
  LV Creation host, time ubuntu, 2014-07-18 10:33:32 +0200
  LV Status              available
  # open                 2
  LV Size                952.00 MiB
  Current LE             238
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           252:0
   
  --- Logical volume ---
  LV Path                /dev/vg/lv_root
  LV Name                lv_root
  VG Name                vg
  LV UUID                VxYaWt-nPDZ-zTos-Bhbk-0dyz-vlX4-5P06Qc
  LV Write Access        read/write
  LV Creation host, time ubuntu, 2014-07-18 10:33:44 +0200
  LV Status              available
  # open                 1
  LV Size                8.83 GiB
  Current LE             2260
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           252:1

8. estendere il volume logico
root@CloudServer:~# lvextend -l+100%FREE /dev/vg/lv_root
  Extending logical volume lv_root to 28.82 GiB
  Logical volume lv_root successfully resized

9. estendere il file system
root@CloudServer:~# resize2fs /dev/mapper/vg-lv_root 
resize2fs 1.42.9 (4-Feb-2014)
Filesystem at /dev/mapper/vg-lv_root is mounted on /; on-line resizing required
old_desc_blocks = 1, new_desc_blocks = 2
The filesystem on /dev/mapper/vg-lv_root is now 7556096 blocks long.

10. controllare lo spazio libero per assicurarsi che tutto sia andato a buon fine
root@CloudServer:~# df -h
Filesystem              Size  Used Avail Use% Mounted on
/dev/mapper/vg-lv_root   29G  1.7G   26G   6% /
none                    4.0K     0  4.0K   0% /sys/fs/cgroup
udev                    991M  4.0K  991M   1% /dev
tmpfs                   201M  532K  200M   1% /run
none                    5.0M     0  5.0M   0% /run/lock
none                   1002M     0 1002M   0% /run/shm
none                    100M     0  100M   0% /run/user
/dev/sda1               236M   39M  185M  18% /boot

Ho liberamente adattato le istruzioni che si possono trovare a questo indirizzo per farli funzionare correttamente con il template Ubuntu 14.04 di Aruba Cloud.