Scripting. Alertes. Accés a BD i enviament de mails des de bash

De Wikijoan
Dreceres ràpides: navegació, cerca

Contingut

Introducció

En aquesta pràctica anem a descriure un mètode general que utilitzarem diverses vegades al llarg del curs. Com a administradors de sistema, al llarg del curs programarem scripts bash que ens ajudaran a automatitzar i monitoritzar diversos procediments i tasques. En el cas de què es detecti algun problema, malfuncionament, risc,... l'administrador s'ha d'assabentar ràpidament del problema. Considerem vàries causístiques:

  1. Des de bash, recuperar informació de la base de dades d'incidències. (veure més avall la definició d'aquesta base de dades).
  2. Des de bash, ficar una incidència directament a la base de dades
  3. Des de bash, minitoritzar l'espai de disc d'una màquina
  4. Des de bash, monitoritzar que els recursos de xarxa estiguin disponibles
  5. Des de bash, enviar avisos/alertes per mail a l'administrador de sistemes.

Nocions de Bash Script:

(hi ha molta documentació i tutorials a Internet)

Desenvolupament

Accés a bases de dades des de bash

Primer de tot necessitarem accedir a una base de dades. En el cas de què encara no tinguis instal.lat un servidor mysql (que necessitaràs en l'assignatura de IAW), el que necessites ara és instal.lar un client de mysql, no pas el servidor:

$ sudo apt-get install mysql-client-5.1
o millor
$ sudo apt-get install mysql-client

Per tant encara no tens un servidor de bases de dades mysql, però sí que tens un client mysql per accedir a bases de dades remotes:

$ man mysql

NAME
       mysql - the MySQL command-line tool

La base de dades que farem servir per fer proves és una petita base de dades de gestió d'incidències, que existeix en la màquina 192.168.0.15. L'alumne no té accés a la màquina, però sí que té accés a la base de dades com es comentarà.

Primer de tot es mostra el script de la base de dades (molt simple), i on s'han ficat 4 incidències d'exemple:

CREATE DATABASE incidencies DEFAULT CHARACTER SET utf8;

USE incidencies;

DROP TABLE ACCIO;
DROP TABLE INCIDENCIA;

CREATE TABLE INCIDENCIA (
id_incidencia smallint primary key,
tipus varchar(20) not null,
aula varchar(3) not null,
descripcio varchar(100),
estat varchar(20),
CONSTRAINT chk_tipus CHECK (tipus IN ('ordinador', 'xarxa','projector','software')),
CONSTRAINT chk_estat CHECK (estat IN ('obert', 'en procés','tancat'))
);

CREATE TABLE ACCIO (
id_accio smallint primary key,
id_incidencia smallint references INCIDENCIA,
descripcio varchar(100)
);
ALTER TABLE ACCIO ADD FOREIGN KEY REFERENCES INCIDENCIA(id_incidencia) ON DELETE CASCADE;


INSERT INTO INCIDENCIA VALUES (1, 'ordinador', 'A35', 'no va la pantalla de la màquina 16', 'obert');
INSERT INTO INCIDENCIA VALUES (2, 'ordinador', 'A35', 'No es pot veure youtube en la màquina 14. Actualitzar drivers', 'obert');
INSERT INTO INCIDENCIA VALUES (3, 'xarxa', 'A35', 'roseta trencada', 'obert');
INSERT INTO INCIDENCIA VALUES (4, 'projector', 'A45', 'No va', 'obert');

INSERT INTO ACCIO VALUES (1,1,'ja s''ha ficat la pantalla');
UPDATE INCIDENCIA SET estat='tancat' WHERE id_incidencia = 1;
INSERT INTO ACCIO VALUES (2,2,'ja m''ho miraré'); 
UPDATE INCIDENCIA SET estat='en procés' WHERE id_incidencia = 2;
INSERT INTO ACCIO VALUES (3,3,'He avisat el tècnic');
UPDATE INCIDENCIA SET estat='en procés' WHERE id_incidencia = 3;
INSERT INTO ACCIO VALUES (4,3,'El tècnic ja ho ha arreglat');
UPDATE INCIDENCIA SET estat='tancat' WHERE id_incidencia = 3;
INSERT INTO ACCIO VALUES (5,4,'Que algú s''ho miri si us plau');

#incidències obertes
select I.id_incidencia, tipus, aula, I.descripcio, estat from INCIDENCIA I, ACCIO A where I.id_incidencia=A.id_incidencia and estat IN ('obert','en procés');
#aules amb incidències obertes
select aula from INCIDENCIA I, ACCIO A where I.id_incidencia=A.id_incidencia and estat IN ('obert','en procés');
# número d'incidències obertes
select count(*) as num from INCIDENCIA I, ACCIO A where I.id_incidencia=A.id_incidencia and estat IN ('obert','en procés');

Per tal de què l'usuari de l'aula 35 tingui accés a aquesta base de dades, en el servidor el professor crearà un usuari amb permisos sobre la base de dades incidencies:

mysql> CREATE USER alumne IDENTIFIED BY 'keiL2lai';
mysql> GRANT ALL ON incidencies.* TO alumne@localhost identified by "keiL2lai";
mysql> GRANT ALL ON incidencies.* TO alumne@"%" identified by "keiL2lai";
mysql> flush privileges;

NOTA per al professor: recordar de comentar en el fitxer principal de configuració del mysql,/etc/mysql/my.cnf, la línia:

bind-address            = 127.0.0.1

NOTA: el password keiL2lai s'havia generat amb pwgen. La idea és que sigui un password fort, però alhora fàcil de llegir i de memoritzar. El pots llegir com queildoslai (keiL2lai). Pren-te mig minut per memoritzar-lo, el farem servir al llarg del curs.

Totes aquestes operacions les fa el professor en el servidor Mysql (l'alumne no ho ha de fer)

Ara l'alumne ja pot accedir a la base de dades incidencies des de l'aula A35:

$ mysql -h 192.168.0.15 -u alumne -pkeiL2lai -D incidencies
mysql> show tables;

o bé
$ mysql -h 192.168.0.15 -u alumne -p -D incidencies
password:
mysql>

o bé
$ mysql -h 192.168.0.15 -u alumne -p incidencies
password:
mysql>

compte!!. Si fico:

$ mysql -h 192.168.0.15 -u alumne -p keiL2lai

no funciona (es pensa que hi ha una bd que es diu keiL2lai). Si vull especificar el password, és sense espai. -D és l'opció per defecte.

script script.sh

Aquest script és una demostració de com podem accedir a la informació que hi ha dins la base de dades d'incidències:

#!/bin/sh
#### Definim els paràmetres de la connexió a la bd
SQL_HOST=192.168.0.15
SQL_USER="alumne"
SQL_PASSWORD="keiL2lai"
SQL_DATABASE="incidencies"
#### Muntem els paràmetres de la connexió.
SQL_ARGS="-h $SQL_HOST -u $SQL_USER -p$SQL_PASSWORD -D $SQL_DATABASE -s -e"
#### Muntem la sentència SQL i la llencem:
echo "Número d'incidències obertes:"
mysql $SQL_ARGS "select count(*) as num from INCIDENCIA I, ACCIO A where I.id_incidencia=A.id_incidencia and estat IN ('obert','en procés');"

# millor: veure http://es.w3support.net/index.php?db=so&id=327777
num_incidencies=$(mysql $SQL_ARGS "select count(*) as num from INCIDENCIA I, ACCIO A where I.id_incidencia=A.id_incidencia and estat IN ('obert','en procés');")
echo $num_incidencies

# una mica de bash
if [ $num_incidencies -ge 10 ];
then 
   echo "Moltes incidències! A la feina!"
else 
   echo "Poques incidències"
fi

echo "Aules on hi ha incidències:"
llista_aules=$(mysql $SQL_ARGS "select aula from INCIDENCIA I, ACCIO A where I.id_incidencia=A.id_incidencia and estat IN ('obert','en procés');")
echo $llista_aules

#o millor fer un retorn de carro
llista_aules=$(mysql $SQL_ARGS "select CONCAT(aula,'\n') from INCIDENCIA I, ACCIO A where I.id_incidencia=A.id_incidencia and estat IN ('obert','en procés');")
echo $llista_aules

Inserir una incidència a la base de dades des de bash

Es presenten dos petits scripts des dels quals es pot omplir la base de dades d'incidències (taula INCIDENCIA i taula ACCIO). Passem com a paràmetres del script les dades amb què omplirem les taules. Fixem-nos com ho hem de fer si el que volem és passar una cadena de text, per exemple el camp INCIDENCIA.descripcio, i concretament com s'ha de fer si aquesta cadena conté un apòstrof.

script inserir_incidencia.sh:

#!/bin/sh

#passem els valors de la incidència com a arguments. Per ex
# ./inserir_incidencia.sh 5 xarxa A45 "no hi ha internet" "obert" 

#### Definim els paràmetres de la connexió a la bd
SQL_HOST=192.168.0.15
SQL_USER="alumne"
SQL_PASSWORD="keiL2lai"
SQL_DATABASE="incidencies"
#### Muntem els paràmetres de la connexió.
SQL_ARGS="-h $SQL_HOST -u $SQL_USER -p$SQL_PASSWORD -D $SQL_DATABASE -s -e "
#### Muntem el insert
SQL="INSERT INTO INCIDENCIA VALUES ($1,'$2','$3','$4','$5');"
#echo $SQL_ARGS
#echo $SQL
mysql $SQL_ARGS "$SQL"

script inserir_accio.sh:

#!/bin/sh

#passem els valors de la incidència com a arguments. Per ex
#./inserir_accio.sh 6 5 "que algu s''ho miri si us plau"

#### Definim els paràmetres de la connexió a la bd
SQL_HOST=192.168.0.15
SQL_USER="alumne"
SQL_PASSWORD="keiL2lai"
SQL_DATABASE="incidencies"
#### Muntem els paràmetres de la connexió.
SQL_ARGS="-h $SQL_HOST -u $SQL_USER -p$SQL_PASSWORD -D $SQL_DATABASE -s -e "
#### Muntem el insert
SQL="INSERT INTO ACCIO VALUES ($1,$2,'$3');"
#echo $SQL_ARGS
#echo $SQL
mysql $SQL_ARGS "$SQL"

Tenim dos scripts: un per omplir la taula INCIDENCIA i un altre per omplir la taula ACCIO. Tanmateix, podríem ajuntar-ho amb un de sol si el primer paràmetre que escolta el script és a quina taula va dirigit el INSERT, i ho controlem amb un if.

En aquest cas simple, l'usuari haurà de tenir el compte de quin és el id_incidencia i id_accio que s'han d'introduir. Un exemple d'invocació d'aquests scripts seria per exemple:

$ ./inserir_incidencia.sh 5 xarxa A45 "no hi ha internet" "obert"
$ ./inserir_accio.sh 6 5 "que algu s''ho miri si us plau"

La idea que es persegueix en aquesta petita pràctica és que si la nostra organització té un gestor d'incidències com ara Mantis BT (www.mantisbt.org/‎), la manera de omplir les incidències i gestionar-les no és exclusivament a través de la seva interfície web, sinó directament amb comandes SQL o des d'altres scripts com el que acabem de mostrar.

Encriptar mínimament el password

imaginem que el nostre password és nk38. Una manera d'ofuscar-lo és mitjançant la comanda tr:

$ man tr

NAME
       tr - translate or delete characters
MYPASS=$(echo "qAnBghkkkJhgf5434fd88sd" | tr -s "k" | tr -s "8" | tr -d "qsdBgf" | tr -d "AhJ" | tr -d "544")
echo $MYPASS

Per entedre-ho et serà útil aquest petit exemple:

$ echo "holaaaaa" | tr -s "a"
hola

$ echo "holaaaaa" | tr -d "oa"
hl

script2.sh:

#!/bin/bash
MYPASS=$(echo "qAnBghkkkJhgf5434fd88sd" | tr -s "k" | tr -s "8" | tr -d "qsdBgf" | tr -d "AhJ" | tr -d "544")

mysql -u root -p$MYPASS -e 'show databases;'

Una altra possibilitat és utilitzar la codificació base64:

$ echo "nk38" | base64
bmszOAo=

script3.sh:

#!/bin/bash
# use base64 encoding
MYENCPASS="bmszOAo="
MYPASS=`echo "$MYENCPASS" | base64 --decode`

mysql -u root -p$MYPASS -e 'show databases;'

No ens enganyem, aquestes són maneres d'ofuscar el password, però una persona amb accés al codi del script pot esbrinar el nostre password. (Aquest mètode serviria per que no ens veiés la clau un company que estigui a la nostra esquena). Al cap i a la fi hem de confiar en el sistema de fitxers i donar permisos de 700 al fitxer per tal que només el pugui veure, modificar o executar el propietari o el root.


A vegades volem donar dades a un script de forma interactiva, per exemple el login i el password per connectar-nos a una base de dades. En aquest cas es tracta de què quan donem el password, no aparegui per pantalla. Ho farem amb stty -echo:

$ man stty

NAME
       stty - change and print terminal line settings

script4.sh

#!/bin/bash
read -p "Username: " uname
UNAME=$uname
stty -echo
read -p "Password: " passw
PASSW=$passw
stty echo
echo

mysql -h localhost -u $UNAME -p$PASSW -s -e "SELECT CURDATE();"

Exercici: amb les tècniques que acabes de veure, ofuscar el password de l'alumne: keiL2lai

Enviar mails des de la consola amb Postfix i Gmail SMTP

NOTA. Aquest mètode ha funcionat a la primera en un ordinador net i des de casa. De totes maneres, altres proves que s'havien fet (per ex utilitzant exim4) havia donat problemes. No importa el tutorial que es segueixi, ha de funcionar si es té clar que s'està fent i es sap interpretar els missatges d'error que dóna el log.

Seguim:

Més informació:

$ sudo apt-get install postfix mailutils libsasl2-2 ca-certificates libsasl2-modules

Concretament mailutils ens instala la utilitat mail que és la que farem servir per enviar mails. De res ens serveix tenir la utilitat mail si no sabem on s'ha de redirigir aquest mail. És per això necessari un MTA (Mail Transfer Agent), en aquest cas postfix (un altre MTA és exim4).

Si és la primera vegada que instal.les postfix, es llença el procés de configuració que preguntarà determinades qüestions.

el teu FQDN (Fully Qualified Domain Name): pots posar alguna cosa com mail.example.com.

El fitxer de configuració que es grava és: /etc/postfix/main.cf. Podem tornar a llençar en qualsevol moment l'assistent de configuració:

$ sudo dpkg-reconfigure postfix

i les següents línies han de quedar d'aquesta manera (si no hi són les afegeixes):

$ sudo joe /etc/postfix/main.cf


relayhost = [smtp.gmail.com]:587
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_tls_CAfile = /etc/postfix/cacert.pem
smtp_use_tls = yes

Hem d'autenticar-nos a Gmail amb uom d'usuari i password vàlids:

$ sudo joe /etc/postfix/sasl_passwd

[smtp.gmail.com]:587    USERNAME@gmail.com:PASSWORD

i donar els permisos al fitxer i actualitzar postfix per tal de què utilitzi aquest fitxer:

$ sudo chmod 400 /etc/postfix/sasl_passwd
$ sudo postmap /etc/postfix/sasl_passwd

Gmail requereix autenticació SSL, i per tant hem de validar els certificats:

$ cat /etc/ssl/certs/Thawte_Premium_Server_CA.pem | sudo tee -a /etc/postfix/cacert.pem

Reload el fitxer de configuració:

$ sudo /etc/init.d/postfix reload

i ara ja podem enviar un mail:

$ echo "Test mail from postfix" | mail -s "Test Postfix" joanqc@gmail.com

Si el que volem és enviar per mail el contingut d'un fitxer farem:

$ cat ~/logs/ping_printers.log | mail -s "ping printers" joanqc@gmail.com

Anem a la safata d'entrada del destinatari per comprovar que hem rebut el correu. Funciona.

Anem a mirar els logs:

$ cat /var/log/mail.log 
Oct 29 09:36:57 musica postfix/master[3672]: daemon started -- version 2.9.6, configuration /etc/postfix
Oct 29 09:41:28 musica postfix/master[3672]: reload -- version 2.9.6, configuration /etc/postfix
Oct 29 09:42:01 musica postfix/pickup[3798]: 3FEF48615C5: uid=1000 from=<joan>
Oct 29 09:42:01 musica postfix/cleanup[3805]: 3FEF48615C5: message-id=<20131029084201.3FEF48615C5@musica>
Oct 29 09:42:01 musica postfix/qmgr[3799]: 3FEF48615C5: from=<joan@mail.example.com>, size=344, nrcpt=1 (queue active)
Oct 29 09:42:05 musica postfix/smtp[3807]: 3FEF48615C5: to=<joanqc@gmail.com>, relay=smtp.gmail.com[173.194.66.109]:587, delay=4, delays=0.12/0.17/1.4/2.2, dsn=2.0.0, status=sent (250 2.0.0 OK 1383036125 fb4sm2524267wib.8 - gsmtp)
Oct 29 09:42:05 musica postfix/qmgr[3799]: 3FEF48615C5: removed

Si alguna cosa no ha funcionat, ha de quedar registrat al log. Pot haver-hi un problema amb els certificats, amb permisos dels fitxers, amb nom d'usuari no vàlid,...

update abril 2014

Quan envio un mail em dóna l'error:

$ echo "Test mail from postfix" | mail -s "Test Postfix" joanqc@gmail.com
postdrop: warning: unable to look up public/pickup: No such file or directory

La solució és fàcil, està explicat a:

I installed postfix and got this error: postdrop: warning: unable to look up public/pickup: No such file or directory. Turns out that sendmail was previously installed and that was messing things up. I had to stop sendmail and make the appropriate directory and restart postfix. Specifically: 

$ sudo mkfifo /var/spool/postfix/public/pickup 
$ ps aux | grep mail 
$ sudo /etc/init.d/postfix restart

i ja funciona:

$ echo "Test mail from postfix" | mail -s "Test Postfix" joanqc@gmail.com

Cas d'ús. Monitoritzar recursos de xarxa. Escombrada de IP's

Suposem que som els administradors de sistema, i som els responsables del manteniment de les impressores de xarxa. Què podem fer abans de que els usuaris ens diguin no puc imprimir!? La idea que anirem incidint en l'assignatura és intentar avançar-nos al problema abans que les coses passin. Si podem detectar que una impressora de xarxa no funciona abans de què l'usuari ho detecti, millor que millor. Ens evitarem problemes amb els usuaris, aquests milloraran la seva productivitat, i nosaltres guanyarem crèdit com a administradors de sistema.

Per implementar-ho bàsicament seria el script que presentem a continuació. Per tal de què el script estigui ben fet, faltaria:

script escombrat_ip.sh:

#!/bin/bash

fitxer_log="ping"
tdate=`date +%d%m%y`

IP_BASE=192.168.10.
for i in {115..125}
do
IP="$IP_BASE$i"
echo "*** ping a la màquina $IP ***" >> /home/joan/logs/"$fitxer_log"_$tdate.log
ping -c 2 $IP >> /home/joan/logs/"$fitxer_log"_$tdate.log
done

Resultat del log:

...
--- 192.168.10.117 ping statistics ---
2 packets transmitted, 1 received, 50% packet loss, time 1001ms
rtt min/avg/max/mdev = 352.670/352.670/352.670/0.000 ms
*** ping a la màquina 192.168.10.118 ***
PING 192.168.10.118 (192.168.10.118) 56(84) bytes of data.
64 bytes from 192.168.10.118: icmp_req=1 ttl=63 time=7.31 ms
64 bytes from 192.168.10.118: icmp_req=2 ttl=63 time=2.68 ms

--- 192.168.10.118 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 2.688/5.003/7.318/2.315 ms
*** ping a la màquina 192.168.10.119 ***
PING 192.168.10.119 (192.168.10.119) 56(84) bytes of data.

--- 192.168.10.119 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1007ms

*** ping a la màquina 192.168.10.120 ***
PING 192.168.10.120 (192.168.10.120) 56(84) bytes of data.

--- 192.168.10.120 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1008ms
...

Cas d'ús. Monitoritzar l'espai de disc

Volem monitoritzar l'espai de disc i fer una alerta en el cas de què l'espai de disc arribi a un % establert.

$ man df
NAME
       df - report file system disk space usage

$ df -T -h

script5.sh:

#!/bin/bash

fitxer_log="ping_espai_disc"
tdate=`date +%d%m%y`

echo "*** percentatge d'espai de disc ***" >> /home/joan/logs/"$fitxer_log"_$tdate.log
df -T -h >> /home/joan/logs/"$fitxer_log"_$tdate.log

#enviem un mail
cat /home/joan/logs/"$fitxer_log"_$tdate.log | mail -s "log ping i espai disc" joanqc@gmail.com

La sortida que obtenim en el fitxer log (i el que rebem pel mail) és similar a:

*** percentatge d'espai de disc ***
S. fitxers   Tipus    Mida En ús Lliure %Ús Muntat a
/dev/sda1     ext4     36G  6,3G   28G  19% /
none      devtmpfs    497M  288K  497M   1% /dev
none         tmpfs    502M  312K  501M   1% /dev/shm
none         tmpfs    502M   96K  502M   1% /var/run
none         tmpfs    502M     0  502M   0% /var/lock
none         tmpfs    502M     0  502M   0% /lib/init/rw

Cron (automatitzar les tasques)

Automatitzar_les_còpies_de_seguretat#cron

Finalment, ara falta posar aquest script per tal que s'executi cada setmana (o cada dia, o cada hora, o cada mes,...). En l'anterior enllaça està explicat l'ús del dimoni cron i del fitxer de configuració crontab.

Hauràs de configurar l'anterior script per tal de què s'executi cada setmana en horari de classe.

Tasques a realitzar

L'alumne haurà de realitzar els exercicis proposats en aquesta pràctica. Per tal de què quedi constància del treball, a més l'alumne haurà de realitzar les següents tasques:

Entrega

Posa tota la documentació generada en un fitxer. En aquest fitxer ha de quedar reflexat els problemes i entrebancs que has tingut, així com els èxits. Si has fet alguna part opcional, comenta-ho i ensenya-ho al professor. Si consideres oportú alguna captura de pantalla, també la pots incloure.

Ho envies tot al Moodle en un fitxer comprimit.

Recorda la normativa per entregar les pràctiques al Moodle: ASIX-M11-SAD#Normativa_d.27entrega_de_les_pr.C3.A0ctiques_al_Moodle


creat per Joan Quintana Compte, setembre 2011

Eines de l'usuari
Espais de noms
Variants
Accions
Navegació
Institut Jaume Balmes
Màquines recreatives
CNC
Informàtica musical
joanillo.org Planet
Eines