jueves, 10 de diciembre de 2009

BarCamp Valencia 2ª Edición

Weno, como ya hice en la anterior ocasión, simplemente comentar que ya está próxima la fecha de la 2ª BarCamp en Valencia.

La primera fué todo un éxito así que imagino que esta seguirá en la misma linea, aunque el listón está alto ;).

La información se puede seguir en:
http://blackshell.usebox.net/archivo/1277.php

y en la web del evento:
http://barcampvalencia.com/2009/12/07/segunda-edicion-de-barcamp-valencia/

viernes, 20 de noviembre de 2009

Error con instalador de Fedora12 - Anaconda12.46 (UnicodeDecodeError)

Al instalar, la primera copia de Fedora 12, me encontré con un error durante la instalación, del cual hice un volcado en otra máquina para poder ver un poco los logs generados, dejo aquí un pequeño estracto de la salida:

anaconda 12.46 exception report
Traceback (most recent call first):
File "/usr/lib/python2.6/site-packages/scdate/core/zonetab.py", line 81, in
translated = reduce(lambda x, y: x.replace(y, "/"),
File "/usr/lib/python2.6/site-packages/scdate/core/zonetab.py", line 83, in __translate_tz
translated)
File "/usr/lib/python2.6/site-packages/scdate/core/zonetab.py", line 105, in _set_tz
self.__translate_tz()
File "/usr/lib/python2.6/site-packages/scdate/core/zonetab.py", line 51, in __init__
self.tz = tz.replace ('_', ' ')
File "/usr/lib/python2.6/site-packages/scdate/core/zonetab.py", line 196, in readZoneTab
entry = ZoneTabEntry (code, lat, long, tz, comments)
File "/usr/lib/python2.6/site-packages/scdate/core/zonetab.py", line 131, in __init__
self.readZoneTab (fn)
File "/usr/lib/anaconda/textw/timezone_text.py", line 39, in getTimezoneList
zt = zonetab.ZoneTab()
File "/usr/lib/anaconda/textw/timezone_text.py", line 67, in __call__
timezones = self.getTimezoneList()
File "/usr/lib/anaconda/text.py", line 480, in run
rc = win(self.screen, instance)
File "/usr/bin/anaconda", line 968, in
anaconda.intf.run(anaconda)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 2: ordinal not in range(128)


Tras ver el log completo, me incline a pensar que se debía a la elección de idioma, así que realice las siguientes pruebas:

IDIOMA------------------------------------TECLADO---------------------------RESULTADO
ingles----------------------------------------cualquiera--------------------------OK
cualquiera menos ingles----------cualquiera--------------------------FALLO

Al intentar reproducir el error para mirar un poco más, con una copia posterior (bajada un día más tarde ;)) me instaló perfectamente, así que he preferido pensar que mi copia estaba mal, antes de marearme más.

Me autoconvenceré de que estas cosas pasan ;)

He visto que hay mas gente a la que le ha ocurrido esto con versiones beta de fedora12, pero en mi caso ocurrió con una estable.

Solucionado y marchando "ok" de momento.

Flash+Firefox en Fedora12 x86_64

Esto ya es la segunda vez que me ocurre así que documentado aquí me será mas facil de encontrar para la tercera ;), y es que es el mismo proceso que con Fedora11.

En la web de Adobe, la versión de flash player que está disponible es para 32bits, así que para poder tenerlo en 64 bits, hay que realizar lo siguiente:
(Existen varios procesos expuestos por la web, aunque este es el mas sencillo)

1.- Descargar

#wget http://download.macromedia.com/pub/labs/flashplayer10/libflashplayer-10.0.32.18.linux-x86_64.so.tar.gz

2.-Descomprimir

#cd /usr/lib64/mozilla/plugins/

#tar -zxvf libflashplayer-10.0.32.18.linux-x86_64.so.tar.gz

#rm -f libflashplayer-10.0.32.18.linux-x86_64.so.tar.gz


NOTA:

Al arrancar nuestro Firefox, será capaz de cargar los Flash, pero......

El funcionamiento es cuanto menos "experimental", así que debéis estar preparados para cuelgues inesperados, en la reproducción de los flash que siempre vienen a producirse con más de un flash en marcha.

Aún no tengo idea de porque ocurre, así que soy todo oídos.

Actualización 15/02/2010

La url actual es:
http://download.macromedia.com/pub/labs/flashplayer10/flashplayer10_1_p2_linux_121709.tar.gz

lunes, 16 de noviembre de 2009

Notas sobre LVM - Recordando.

La verdad es que me ha pasado varias veces que he querido consultar sobre este tema, sobre todo por trabajo ;) y no he encontrado mis notas, así que lo mejor será tenerlas aquí que así seguro que las encontraré la próxima vez.

Esquema:

-Los discos o particiones seran asignados como Volumenes Fisicos (PV)

-Uno o varios (PV) seran asignados a un Grupo de Volumenes (VG), el (VG) podrá
crecer en la medida que tenga espacio libre en los (PV) que tiene asignados.

-Un (VG), tendrá uno o varios Volumenes Lógicos (LVM) los cuales son nuestras tradicionales particiones.(/home, /etc....). Los (LV), podran crecer en la medida que quede espacio en su (VG)

Monitorizacion:

PV-Physical Volume
(Vemos a que VG estan asignados nuestros discos (PV) y cuanto espacio tenemos sin asignar en (PV))

pvs Display information about physical volumes
lvm> pvs

PV VG Fmt Attr PSize PFree

/dev/sdb1 vg_disco1 lvm2 a- 465,76G 0

/dev/sdc1 vg_disco2 lvm2 a- 465,76G 0



pvscan List all physical volumes
lvm> pvscan

PV /dev/sdc1 VG vg_disco2 lvm2 [465,76 GB / 0 free]

PV /dev/sdb1 VG vg_disco1 lvm2 [465,76 GB / 0 free]

Total: 2 [931,52 GB] / in use: 2 [931,52 GB] / in no VG: 0 [0 ]


VG-Volume Group
(Vemos cuantos VG tenemos asi como cuantos PV los formar y cuantos LV tiene cada uno. Ademas vemos el espacio libre en el VG)

vgs Display information about volume groups

lvm> vgs

VG #PV #LV #SN Attr VSize VFree

vg_disco1 1 2 0 wz--n- 465,76G 0

vg_disco2 1 2 0 wz--n- 465,76G 0


vgscan Search for all volume groups

lvm> vgscan

Reading all physical volumes. This may take a while...

Found volume group "vg_disco2" using metadata type lvm2

Found volume group "vg_disco1" using metadata type lvm2



LV-Logical Volume
(Vemos los LV que tenemos en cada VG y su tamaño)

lvscan List all logical volumes in all volume groups

lvm> lvscan

ACTIVE '/dev/vg_disco2/LVdatos' [270,45 GB] inherit

ACTIVE '/dev/vg_disco2/LVtrabajo' [195,31 GB] inherit

ACTIVE '/dev/vg_disco1/LVdescargas' [195,31 GB] inherit

ACTIVE '/dev/vg_disco1/LVmultimedia' [270,45 GB] inherit


lvs Display information about logical volumes

lvm> lvs

LV VG Attr LSize Origin Snap% Move Log Copy% Convert

LVdescargas vg_disco1 -wi-ao 195,31G

LVmultimedia vg_disco1 -wi-ao 270,45G

LVdatos vg_disco2 -wi-ao 270,45G

LVtrabajo vg_disco2 -wi-ao 195,31G



Para una informacion mas detallada de nuestros LV:

lvm> lvdisplay

--- Logical volume ---

LV Name /dev/vg_disco2/LVdatos

VG Name vg_disco2

LV UUID nXbOdP-CIBc-XibZ-Wvzm-MbOf-HB3V-tzrPml

LV Write Access read/write

LV Status available

# open 1

LV Size 270,45 GB

Current LE 69234

Segments 1

Allocation inherit

Read ahead sectors auto

- currently set to 256

Block device 253:4

...



También es útil conocer cuales de nuestros disco están siendo usados:

lvm> lvmdiskscan

...

/dev/sdb1 [ 465,76 GB] LVM physical volume


/dev/sdc1 [ 465,76 GB] LVM physical volume

0 disks

24 partitions

0 LVM physical volume whole disks

2 LVM physical volumes



Evidentemente el comando mas interesante lo dejo para el final ;)

#lvm

lvm>help


Este comando sin comentarios.

Con esto espero no olvidarlo más, que ya tendría delito.

sábado, 7 de noviembre de 2009

Fedora 12 Release Party - Valencia

La verdad es que hace ya bastante tiempo que no escribía por aquí. No se si por falta de tiempo, ganas, ideas, ilusión, o... por una mezcla de todas ;)

Se que no es muy original retomar esto de escribir citando a otro pero me parece importante e interesante el tema, así que aquí va....

Juan J, Martinez ha organizado una "Fedora 12 Release Party" en Valencia, para reunir a usuarios de Fedora.

Los datos los tenéis en los enlaces, igual que el cartel del anuncio.

Si no sale ningún imprevisto nos vemos en la "Release Party" ;)

Suerte con el evento Juanjo.

domingo, 20 de septiembre de 2009

Certificados exportados desde Windows.

Hace unos días por necesidades del trabajo, necesite instalarme unos certificados, que habian sido generados y exportados desde una maquina Windows.

La verdad es nunca me habia puesto a trastear con certificados, así que al ver que no podía usarlos, empezaron mis problemillas.

Los formatos no coincidian con los que se suponía.

Para poder exportar el certificado de usuario junto con su clave, el cual esta en formato "pfx"
Lanzamos lo siguiente:

[root@gollum satec]# openssl pkcs12 -in manuel.pfx -out EXPORTADO.TXT -chain -nodes

Tras esto, copiamos el fichero exportado como:
manuel.crt y manuel.key

En cada uno de estos ficheros, editandolos con "vi", dejaremos solo la parte del certificado en el fichero crt y la parte de la firma en el fichero key

CRT
-----BEGIN CERTIFICATE-----
.....
-----END CERTIFICATE-----

KEY
-----BEGIN RSA PRIVATE KEY-----
.....
-----END RSA PRIVATE KEY-----


Con esto tenemos el certificado de cliente, listo para usar.
Ahora vamos a adecuar los certificados raices que estan en formato "pb7"

[root@gollum satec]# openssl pkcs7 -inform DER -outform PEM -in Certificados\ Raices.p7b -out certname.pem -print_certs

Esto nos deja el fichero con los certificados raices listo.

Estos ficheros ya los podemos usar en una máquina Linux.

miércoles, 9 de septiembre de 2009

Optimización MySql

Hace ya bastante tiempo comente acerca de un problema de rendimiento con MySql y las SlowQuerys
Bueno pues como la historia siempre se repite (o eso dicen), ha vuelto a ocurrir, pero esta vez hasta que se ha descubierto, que el problema era el mismo, se han probado y profundizado en aspectos que mejoran el rendimiento de MySql

Esto es lo que voy a comentar brevemente.

1.- Lo primero ha sido garantizar que este error no se produce otra vez y para eso he creado un mini script que me vacíe la tabla en cuestión, citada en el post anterior.



NUM_ROWS=`mysql -u root -pXXXXX NOMBRE_BBDD -e"SELECT COUNT(*) FROM NOMBRE_TABLA;"`

#Quitamos 9 caracteres "COUNT(*) " que aparecen en la salida de mysql

NUM_ROWS=`echo${NUM_ROWS:8}`


if [ $NUM_ROWS -gt 2500000 ]; then

echo `date`

echo "El tamano es excesivo, $NUM_ROWS de entradas, hay que vaciar la tabla
NOMBRE_TABLA"

RESULT=`mysql -u root -pXXXXX NOMBRE_BBDD -e"TRUNCATE TABLE NOMBRE_TABLA;"`

echo $RESULT

fi



2.- Thread_cache_size y Thread_cache_concurrency

Esta es la primera parte de la "optimización" que se ha realizado.

Parece que Linux no gestiona bien la creacion de threads, por lo que crear nuevos supone un coste muy elevado.


Cuando tenemos muchas conexiones nuevas a BBDD, es necesario crear estos threads, mientras que si almacenamos los que van quedando libres al desconectarse un usuario, la reasignación de estos es mucho menos costosa, con lo que mejoramos el rendimiento.


Para decidir el valor optimo, podemos empezar por el recomendado "8", he ir ajustándolo de la siguiente manera.



mysql> show status like '%Thread%';
.... | Threads_created | 214 | ....



mysql> show status like '%Conn%';
... | Connections | 14250 | ...



Threads_created/connections


Si este valor se aproxima a "1", significa que creamos tantos threads como conexiones tenemos, por lo que habria que aumentar el tamaño de la cache de threads.


Si este valor se aprixima a "0" significa que apenas creamos threads nuevos con lo que el tamaño de cache es correcto.




3.-Key_buffer_size


Esta variable indica el tamaño del buffer donde se almacenaran los indices de las tablas MyIsam.

A mas indices cacheados mas accesos en las consultas se servirán desde RAM y menos desde disco, con al aumento de rendimiento que esto supone.

Aquí ya que aún no lo hemos ajustado no voy a profundizar mucho más simplemente comentar que.



key_read_request (indices servidos desde RAM)

key_reads (indices servidos desde disco)


Con estas dos variables podemos ver lo siguiente.



key_read_request 10000

key_reads = 100


key_read_request/key_reads=100



Por lo que estamos obteniendo una proporción de 100 a 1, es decir por cada 100 indices servidos desde RAM 1 es servido desde disco.



Esta es la relación mínima que se cita en la documentación que he encontrado aunque también hablan de valores de 1000 a 1, por lo que cuanto más alto mejor.



Bueno con los ajustes necesarios de estas variables deberíamos notar una mejora de rendimiento en nuestros servidores.

lunes, 31 de agosto de 2009

Vacaciones - Dia D, hora H ;)

La verdad es que hace bastante que no escribo en el blog pero es que este año a sido un poco especial el tema de las vacaciones y es que un viaje bien preparado lleva bastante trabajo.

Este año he salido a conocer la costa de normandia, teniendo como centro del viaje todo lo acontecido en la WW2.
La idea era ver y tratar de entender lo que ocurrió, por lo que antes del viaje traté de documentarme lo mejor que pude.

Museos, memoriales, cementerios, baterías, bunkers, pueblos, ciudades y claro las 5 playas.

La verdad es que no te haces a la idea de lo que supuso ni del esfuerzo realizado hasta que no ves las dimensiones de las playas y demás construcciones.

Estas son algunas de las fotos de los sitios mas conocidos que hemos visto (Cementerio Americano, Pointe du Hoc y Saint Mere Eglise, respectivamente.)


Weno tras despejar la cabeza con este cambio de aires que falta me hacia ;) ahora toca unos días de reposo para cargar bien las pilas.

Y... como todo lo bueno se acaba, a estas vacaciones ya se les empieza a ver el final.

domingo, 26 de julio de 2009

Final BarCamp Valencia 2009

Weno, todo lo bueno tiene que acabar ;)

El Sabado 25/08/09 se realizo la BarCamp Valencia 09, y la verdad, la experiencia me pareció genial, en todos los aspectos.

* Las ponencias de mucho nivel, aunque y aquí está mi único pero ;) quizás había mucho ponente profesional y poco "amateur". Pero claro, tal y como se comentó en los descansos, si ante este evento se ofrecen ponentes profesionales, ha participar es una oportunidad que no se puede dejar pasar.
El "pero", claro es a nivel "romántico"

* Los descansos, casi mejor ;) aún si cabe. Las charlas fueron de lo más instructivas, y los ponentes de lo más accesibles. Genial!!!

* La organización perfecta sin más. Además se sorteó todo el material cedido por los patrocinadores, aunque no me toco nada como de costumbre ;)

* En cuanto al sitio, me pareció bueno, las instalaciones muy bien y el tema de aparcamiento estupendo.

* En cuanto a la "oferta gastronómica" ;)) más bien escasa, dos bares abiertos (escondiditos) y un mercadona.

Las fotos del evento están colgadas aquí
Las transparencias de las ponencias aquí

En definitiva un 10 al evento.
Esperemos que se repita pronto.

viernes, 10 de julio de 2009

Problema DNS

Hace unos tres días vengo teniendo problemas con mi servicio de Internet (ONO).

La verdad es que desde el primer dia estube completamente seguro de que era debido a los servidores DNS de mi proveedor, pero no habia tenido tiempo de comprobarlo ;) (El veranito es lo que tiene)

Esta noche después de ver la peli de rigor he intentado consultar el correo y ha sido la gota que colma el vaso, así que me he puesto a mirar el tema.

Tenía configurado en /etc/resolv.conf

nameserver 62.42.230.24

nameserver 62.42.63.52



Y... la sorpresita de rigor el primer DNS no responde al ping ;(
Despues de mirar en internet he obtenido una lista de 4 DNS de ONO

62.42.63.51

62.42.63.52

62.42.230.23

62.42.230.24



Los dos últimos no funcionaban así que he editado mis DNS para dejar:


nameserver 62.42.63.52

nameserver 62.42.63.51

nameserver 62.42.230.24



Problema resuelto.

viernes, 3 de julio de 2009

Copias Subversion - Paralelizando procesos

Hace unos días comenté algo acerca del procesamiento paralelo en bash.


Hoy he tenido que hacer un pequeño script para realizar unos dump de subversion, y al medir tiempos por temas de ventanas de copias, me he encontrado con que el proceso de realizar las copias de todos mis repos consumía un tiempo de aproximadamente 2.30h, lo cual me ha dejado un poco mosca al irme a casa.


No se pero se me había metido en la cabeza que podía ser más rápido, y una cosa a llevado a la otra y al final he acabado pensando en la posibilidad de lanzar estos scripts en paralelo, lo cual tiene gracia ya que la máquina en cuestión tiene un solo core ;) (Por lo que la ganancia sería 0) pero bueno me ha dado por darle vueltas al tema.


Así que me he puesto y al final he hecho otro script, en el que si tengo presente el número de cores disponibles.


No he podido probarlo, pero intentaré hacerlo en breve montando alguna maquena en VirtualBox. (Cuando tenga tiempo y ganas ;))


Estos son los scripts que repito. No se si funciona el segundo de ellos, pero como ejemplo del anterior post creo que es valido.


Script sin paralelización:

#Definimos el array que contendrá los repos

typeset -a A_REPOS

#Obtenemos el numero de repos (Directorios, sin el directorio de copias ni el "." o el "..")

let NUM_REPOS=`ls -l|grep "drwx"|grep -v "DUMP_BACKS"|tr -s ' ' |cut -d ' ' -f 9|tr -s '.'|cut -d '.' -f 1|wc -l`

#Obtenemos una lista de los repos

REPOS=`ls -l|grep "drwx"|grep -v "DUMP_BACKS"|tr -s ' ' |cut -d ' ' -f 9|tr -s '.'|cut -d '.' -f 1`

let num=1


#Llenamos el array con los elementos de la lista de repos

while [ $num -le $NUM_REPOS ]; do

A_REPOS[$num]=`echo $REPOS|tr -s ' ' |cut -d ' ' -f $num`

let num=num+1

done


num=1

#Para cada posicion del array lanzamos un dump

while [ $num -le $NUM_REPOS ]; do

#echo ${A_REPOS[$num]}

svnadmin dump ${A_REPOS[$num]}|gzip -9 > ${A_REPOS[$num]}".gz"

let num=num+1

done


Script con paralelización:

#Definimos el array que contendrá los repos

typeset -a A_REPOS

#Obtenemos el numero de repos (Directorios, sin el directorio de copias ni el "." o el "..")

let NUM_REPOS=`ls -l|grep "drwx"|grep -v "DUMP_BACKS"|tr -s ' ' |cut -d ' ' -f 9|tr -s '.'|cut -d '.' -f 1|wc -l`

#Obtenemos una lista de los repos

REPOS=`ls -l|grep "drwx"|grep -v "DUMP_BACKS"|tr -s ' ' |cut -d ' ' -f 9|tr -s '.'|cut -d '.' -f 1`

let num=1

#Definimos el numero de procesadores de muestra maquina

let PMAX=(`ls -ld /sys/devices/system/cpu/cpu*|wc -l`)-1

#definimos un array con el numero de cores

typeset REPOS_CORE[$PMAX]


#Llenamos el array con los elementos de la lista de repos

while [ $num -le $NUM_REPOS ]; do

A_REPOS[$num]=`echo $REPOS|tr -s ' ' |cut -d ' ' -f $num`

let num=num+1

done


num=1

pos=1

while [ $num -le $NUM_REPOS ]; do

#Llenamos un array con tantos elementos como procesadores
REPOS_CORE[$pos]=${A_REPOS[$num]}

#Cuando esta lleno lanzamos los procesos y colocamos la posicion a 1 para volver a llenarlo
if [ $pos -eq $PMAX ] then

for i in REPO_CORE; do

svnadmin dump $i|gzip -9 > $i."gz" &

pos=0

wait

done

fi

let num=num+1

let pos=pos+1

done


Los colores indican las diferencias entre uno y otro.

Básicamente cuando tenemos el array con los nombres de los repos, vamos llenando otro hasta tener tantos elementos como cores, en ese momento lanzamos todos los dump y colocamos la posición, a 0 para que se coloque a 1, y repetir el proceso.

De este modo conseguimos lanzar varios dump al mismo tiempo, con lo que con el tiempo del mayor, realizaremos los demás. (Creo)

NOTA: Repito y no me cansaré de hacerlo ;), que el segundo script NO ESTÁ TESTEADO, básicamente es una idea que pienso que puede funcionar.

miércoles, 1 de julio de 2009

Nuevo Evento - BarcampValencia - Desconferencia


Weno este post es para contribuir de alguna manera, (con que sume algún asistente me vale)
al evento que se va a celebrar por primera vez en Valencia. BarcampValencia.
La "desconferencia", responde al lema de "Web 2.0, Open Source y Social Media"

La idea me parece genial, creo que es uno de los proyectos que más ilusión me hacen en bastante tiempo, no se quizas esperaba algo así sin saberlo ;) así que ahí queda esto a ver si alguien se anima.

Ah.... y por supuesto felicitar y desear toda la suerte posible a los organizadores, que se lo han currado muchisimo.

La URL del evento es: http://barcampvalencia.com/





martes, 30 de junio de 2009

Adaptando Nueva Plantilla

Weno, estos dias voy a ir adaptando una nueva plantilla para el blog espero que sea la definitiva aunque no creo. ;)
Estará adaptada lo antes posible.

martes, 23 de junio de 2009

Bash Script con varios nucleos - Parelelizando

Hace unos dias lei un árticulo sobre este tema en LinuxMagazine el cual me pareció de lo más interesante.
La verdad es que hasta ese momento no se me había pasado por la cabeza la posibilidad de explotar la potencia de varios cores en un script bash.

Cuando paralelizar script?
Este es para mi el punto mas importante a tener en cuenta, ya que aunque podríamos vernos tentados a paralelizar a diestro y siniestro, no siempre nos aportará beneficios, es más en determinadas ocasiones supondrá una pérdida de rendimiento.
No es mi intención explicar el concepto de procesamiento paralelo, simplemente mencionar que a menos que el proceso que estemos ejecutando suponga una carga muy alta para un core, no es recomendable, ya que el coste de cambiar de core será mayor que la ganancia obtenida.
Una manera de saber si para nuestro proceso es "rentable" o no, sería ver la salida del comando sar.

En mi caso tengo ejecutandose un find en la maquina:

#find / -name "*".jpg"*"

En una segunda consola miro el consumo de cpu:

#sar -u -P ALL 1 0

Obteniendo salidas como esta:
00:36:34 CPU %user %nice %system %iowait %steal %idle
00:36:35 all 0,95 0,00 1,65 22,22 0,00 75,18
00:36:35 0 1,96 0,00 3,92 76,47 0,00 17,65
00:36:35 1 0,95 0,00 2,86 15,24 0,00 80,95
00:36:35 2 0,89 0,00 0,89 0,00 0,00 98,21
00:36:35 3 0,00 0,00 0,00 0,00 0,00 100,00


Como podemos observar, el procesador "0" esta trabajando mucho más que el resto y sería un candidato para el tema que nos ocupa de ser porque el consumo se debe a operaciones I/O, lo cual hace que no sea buena idea, ya que no es trabajo propiamente del procesador. Otro caso seria si la mayor parte del trabajo fuera en la columna "user" Dicho esto, una vez hayamos decidido si es o no oportuno, comenzamos a paralelizar nuestro script.


1.- Este ejemplo es el más agresivo ya que podría provocar un incremento de procesos en la máquina y un consumo de memoria capaz de dejarla frita.
Para cada orden de nuestro bucle se inicia un proceso distinto, y luego se espera q que todos los procesos hayan finalizado.

funcion(){
for i in XXX do
loquesea $i &
done
wait
}

2.- Este ejemplo intenta distribuir argumentos para la ejecución de procesos, según el número de procesadores de nuestra máquina.(Para que el número total de procesos no aumente demasiado)
Este procesamiento es adecuado siempre que el consumo de cpu sea similar entre procesos ya que si no, podría darse el caso de que todos los procesos con consumo alto recayeran sobre la misma cpu, con lo que no habríamos conseguida nada
Este problema lo tendremos siempre que no hagamos una selección de procesadores en función de su carga.

#Definimos nuestro numero de procesadores

let PMAX=(`ls -ld /sys/devices/system/cpu/cpu*|wc -l`)-1

funcion(){

procesadores=0

#Recorremos la entrada de parametros a procesar

for i in XXX do

#Cada parametro lo añadimos al vector final

items[$procesadores]="${items[procesadores]} \"$i\""

shift

#Modificamos la posicion actual entre 0 y PMAX-1

let procesadores=$((procesadores+1)%PMAX)

done

#Con todos los argumentos en nuestro vector, lanzamos PAMX procesos, con la ejecucion

#de estos parametros

for (procesadores=0 procesadoresdo"<"PMAX procesadores++)

ejecucionXXX

done

wait

martes, 2 de junio de 2009

Lectura recomendada - La ética del hackers y el espíritu de la era de la información


Acabo de terminar el libro con el que estaba enfrascado estos últimos días.

Aunque no soy quien para andar recomendando libros, creo que siempre está bien leer un poco de todo, y si alguien piensa que merece la pena pues mejor ;)


El libro "La ética del hackers y el espíritu de la era de la información" de Pekka Himanen, es un mezcla entre sociología, filosofía, economía y ética. Una mezcla explosiva pero interesante.


Es un libro corto (200pag. y 50pag de notas.) pero denso.

Weno no es mi intención hacer comentario alguno sobre el contenido del libro ni criticas tampoco, para eso ya hay gente mucho mejor que yo ;), así que para terminar... que me ha sorprendido muy gratamente. Recomendado queda.

martes, 26 de mayo de 2009

Nuevo animalito - HTC MAGIC

Weno hace un par de horas me han traído mi nuevo teléfono, y es que la operadora ha tenido a bien ofrecerme el terminal que me interesaba.

Ahora solo falta ir dándole vueltas para ver que se le puede sacar al "bicho".

A ver si cumple con lo que se espera de el. ;)










......... De momento pinta bien la cosa ;))




De más está comentar que ahora estoy como un "xiquillete" con juguete nuevo ;)

lunes, 18 de mayo de 2009

SSL - "Sin" y "Con" certificado. Renegociando la conexión

Hace ya un par de meses, por requisitos de una aplcación, me vi en la tesitura de configurar
apache para poder ofrecer una parte de los contenidos de una web por ssl sin certificado
de cliente y el resto mediante ssl pero con certificado de cliente.

Al final todo quedo en nada ya que la primera parte del contenido se acabo ofreciendo
sin ssl, pero como suele ocurrir en estos casos, el trabajo ya estaba hecho ;) así que ahí
van los resultados.

El problema con el que me encrontre es que la directiva "SSLVerifyClient" encargada de
solicitar el certificado al cliente, es aplicable y cito textualmente de la página de
apache a... ("server config, virtual host, directory, .htaccess")

Esto evidentemente te lleva a pensar en una solución por ejemplo, de este tipo:


VirtualHost..........
.....
"<"locationmatch sitio="">
SSLVerifyClient none
"<"/locationmatch>

"<"locationmatch sitio="">
SSLVerifyClient require
"<"/locationmatch>
......




Donde para el patron "/sitio/" solicitamos el certificado del cliente y para el resto no.

Hay que decir, que probamos "mil" conbinaciones más, que no vienen al caso con valores
optional para la directiva SSLVerifyClient.

El proble es que si bien esta directiva es aplicable, lo que no indican es que la
renegociación de certificados no funciona correctamente en mod_ssl. Me explico.......

En el saludo inicial de la conexión, ya sea porque esta definido a nivel del servidor o a
nivel del VirtualHost, apache solicita o no el certificado, pero luego es incapaz de
renegociar esa conexión, para cambiar y usar o dejar de usar este certificado.
Con lo que una vez solicitado o no, esto ya no varia para la conexión.

(He leido referencias a un bug de mod_ssl, aunque no se si es cierto o si simplemente
no esta contemplado en la implementación)

Por este motivo y tras abrir el pertinente caso de soporte (Donde tanto yo como los distintos
técnicos de soporte de los niveles por donde paso la incidencia), decidimos que la
opción viable en este caso era forzar el establecimiento de una conexión nueva en cada caso.

(Es decir dos VH distintos con dos puertos distintos;))

Esto se tradujo en algo de este tipo:

#En este primer VH cuando encontramos el patron para el que no queremos solicitar certificado
#saltamos directamente al destino.
#Cuando encontramos el patron para el que si queremos solicitar certificado, reescrivimos la url
#para saltar al segundo VH



"<"virtualhost xx.xx.xx.xx:443>
DocumentRoot /../sitio1
ServerName sitio1.es
DirectoryIndex index.html index.htm index.php
Options None
AllowCONNECT 443 444

"<"ifmodule>
RewriteEngine On
RewriteRule ^/$ /paso1/ [R,NE]
"<"/ifmodule>

"<"directory>
Order deny,allow
Allow from all
"<"/directory>

ProxyRequests Off
ProxyVia On
ProxyPreserveHost On

SSLVerifyDepth 10
ProxyPass /paso1/ https://maquina_destino:443/paso1/
ProxyPassReverse /paso1/ https://maquina_destino:443/paso1/

RewriteRule /paso2/ https://sitio2.es:444/paso2/

SSLEngine on
SSLVerifyClient none
SSLProxyEngine on

......

"<"/virtualhost>


#########################################

#En el segundo VH cuando encontramos el patron que nos indica que queremos certificado de cliente
#que es el que nos ha traido a este VH, saltamos al destino.

"<"virtualhost 444>
DocumentRoot /../sitio2
ServerName sitio2.es
ErrorLog logs/sitio2_ssl-error-log
TransferLog logs/sitio2_ssl_access_log
LogLevel warn
DirectoryIndex index.html index.htm index.php
Options None
AllowCONNECT 443 444

"<"ifmodule>
RewriteEngine On
RewriteRule ^/$ /sitio2/ [R,NE]
"<"/ifmodule>

"<"directory>
Order deny,allow
Allow from all
"<"/directory>

ProxyRequests Off
ProxyVia On
ProxyPreserveHost On

SSLVerifyDepth 10
ProxyPass /sitio2/ https://maquina_destino:443/sitio2/
ProxyPassReverse /sitio2/ https://maquina_destino:443/sitio2/

SSLEngine on
SSLVerifyClient require
SSLProxyEngine on

.....

"<"/virtualhost>



Al final tras todas las pruebas realizadas, decidimos que esta era la opción más adecuada para
solucionar el problema.
No se si será la opción más "limpia" pero se ajustaba perfectamente al problema que queria
resolver. ;)

lunes, 20 de abril de 2009

Centralizando Tareas - Cron

He estado dándole vueltas a la idea de centralizar las tareas programadas, ya que el número de máquinas aumenta de manera casi exponencial y al final esto se hace imposible de administrar.

He probado varias, aplicaciones para este propósito y la conclusión final es que me aportan más trabajo que beneficio, ya que todas ellas gestionan mas cosas de las que necesito y su puesta en marcha y curva de aprendizaje es demasiado costosa.

Por este motivo me he decidido a centralizarlo del modo mas simple, pero que se ajusta a mis propósitos.
Desde el propio cron con conexiones SSH, de este modo, puedo administrar o ver en que máquina se ejecuta que, y por quien, de un simple vistazo a su cron.

La idea es la siguiente, una máquina, hará la función de "maestro" y las demás serán "esclavas" de esta, de este modo solo habrá que revisar y actualizar el cron de la máquina "maestro", ya que esta lanzará mediante ssh con claves publicas /privadas, los scripts que se ejecutaran en las demas máquinas.

1.- Garantizar el acceso mediante ssh.
Hay que garantizar el acceso por ssh de la máquina maestro a las demás, para cada usuario. Esto esta explicado en un post anterior. Aquí

2.- Editar el cron de la máquina "maestro"

El cron queda de la manera siguiente:

###Maquina Pruebas 1


#user1


31 14 * * * /usr/bin/ssh user1@192.168.1.143 '/etc/local/script_pru1'


#Root


35 14 * * * /usr/bin/ssh root@192.168.1.143 '/etc/local/script_pru2'



Desglosamos mediante comentarios, la máquina "esclavo" afectada y para que usuario (Simplemente a nivel organizativo).
Tras esto editamos la linea de cron propiamente dicha, en la que definimos los patrones de tiempo que correspondan, y lanzamos el cliente ssh de nuestra máquina "maestro" con usuario y host destino ("esclavo"), y con ('') definimos el script remoto que vamos a ejecutar.




Desventaja - 1

Es evidente pensar que depender de una única máquina para gestionar las tareas programadas es un inconveniente, ya que tenemos un cuello de botella, en cuanto a alta disponivilidad se refiere.

Solución.

Una posible solución es esta:
Montando un cluster RH, podemos definir un servicio adicional "cron", el cual al bascular entre nodos, migre el demonio "crond" y ejecute un script que monte un directorio en almacenamiento compartido en /var/spool/cron, de este modo tendremos dos maquinas operativas para servir de gestor de crons. El orden seria , primero el montaje del directorio y luego levantar el servicio crond. Este proceso se puede realizar siguiendo el siguiente post. Aquí

Desventaja - 2

Otro problema es el coste de trabajo, que supone habilitar el acceso por ssh de la máquina "maestro" a las demas "esclavos"
Este problema no es "solucionable" pero el beneficio obtenido de centralizar los procesos es evidente ya que el tiempo invertido será recuperado con creces al aumentar la simplicidad de administración

miércoles, 8 de abril de 2009

REXEC sobre Centos4

Bueno aunque se que esto no es lo más recomendable por motivos evidentes de seguridad, en ocasiones nos encontramos con la necesidad de montar servicios "R" por especificaciones de fabricantes.
Aquí intento comentar un modo de hacerlo e intentar que sea un poco más seguro.

Instalacion de "rexecd"

Rexec forma parte de los servicios ofrecidos a través de "rsh-server"
yum install rsh-server.i386

Editar el fichero de configuración de Rexec

vi /etc/xinetd.d/rexec

En el cambiamos la opción de disable a "no", para habilitar el servicio bajo xinetd

# default: off

# description:

# Rexecd is the server for the rexec program. The server provides remote

# execution facilities with authentication based on user names and

# passwords.

service exec

{

socket_type = stream

wait = no

user = root

log_on_success += USERID

log_on_failure += USERID

server = /usr/sbin/in.rexecd

disable = "no"

}



una vez hecho esto, para permitir el uso a root debemos modificar el fichero
/etc/securetty

Y añadir al final la aplicación que queremos permitir en este caso, rexec

......

......

......

rexec


Tras esto rebotamos el servicio de xinetd y listo, el rexec con todos sus "problemas de seguridad" está operativo.

Para intentar securizar el servicio dentro de lo posible, podríamos entre otras cosas, implementar algo bajo iptables como lo que sigue.

#!/bin/bash

#

#Borramos todas las reglas existentes, comenzamos en un estado limpio

#

iptables -F

#

# Politicas por defecto INPUT, FORWARD y OUTPUT

#

iptables -P INPUT ACCEPT

iptables -P FORWARD ACCEPT

iptables -P OUTPUT ACCEPT

#

#Permitimos rexec desde la maquina autorizada

iptables -A INPUT -p tcp -s x.x.x.x/24 --dport 512 -i eth0 -j ACCEPT

#

#Denegamos el resto de accesos rexec para todas las maquinas

#

iptables -A INPUT -p tcp --dport 512 -i eth0 -j DROP

#

#Salvamos las politicas

#

/sbin/service iptables save

#

#Listamos las reglas cargadas

#

iptables -L -v



Solo me queda recomendar encarecidamente no usar este tipo de servicios a menos que no sea estrictamente necesario.

sábado, 4 de abril de 2009

HTTP - URL's "escapadas" - Alternativas

Este post es una nota mental para no olvidar algunas de las alternativas que he encontrado para evitar el problema de las URL's escapadas en Apache.
Este problema se produce cuando la URL recibida contiene caracteres especiales, que son interpretados y cambiados por su código ASCII, al realizar un "RewriteRule" la lista la podemos consultar por ejemplo en:


http://www.w3schools.com/TAGS/ref_urlencode.asp

Alternativa1
La primera alternativa para este problema, nos la proporciona el mismo "mod_rewrite", y es su flag [NE], el cual evita que estos caracteres sean "escapados"

Ejem.

RewriteRule /ejemplo/(.*) http://www.XXX.es/ejemplo2/$1 [NE]

En este ejemplo cualquier cosa que tenga un patrón de URL que comience por "/ejemplo" será traducido a "http://www.XXX.es/ejemplo2", pasando la ultima parte de la URL contenida en (.*) a la variable "$1"

El problema que presenta esta solución es que este flag está disponible desde la versión 1.3.20 de Apache y en maquinas muy antiguas esto es un inconveniente.

Alternativa2
La segunda alternativa, también es propia de "mod_rewrite", solo que está disponible desde mediados de la versión 1.2 y para todas las versiones 1.3.X y 2.X
La directiva "RewriteMap", es la que nos proporciona esta solución. Esta directiva tiene cuatro funciones internas, las cuales nos permiten saltar entre mayúsculas y minúsculas y escapes o unescapes, las URL's

Ejem.

RewriteMap fescape int:escape RewriteMap funescape int:unescape RewriteRule /ejemplo/(.*) http://www.XXX/ejemplo2/${escape:{unescape:$1}} [R]

ó

RewriteRule /ejemplo/(.*) http://www.XXX/ejemplo2/${unescape:$1} [R]

En este ejemplo, definimos las funciones "fescape" y "funescape" como funciones internas de escape y unescape, de "RewriteMap". Posteriormente, aplicamos estas funciones a nuestra variable "$1", dentro del "RewriteRule". Se pueden aplicar en el orden que se necesite, como se ve en las dos lineas de RewriteRule anteriores.

El problema de esta solución, es que según Apache, estas funciones son aplicadas a la URI, nunca a la sentencia de Query String, posterior a un "?"

Ejem. http://www.XXX.es/XXX?="QueryString"
Nota: Las comillas de este ejemplo no se verían afectadas.


Alternativa3
La siguiente alternativa, pasa por crear un pequeño script que nos genere la URL correcta, sin que esta sea "escapada"
Para este propósito basta con una directiva que apunte a nuestro script:

ScriptAlias /ejemplo /path/script_url

En nuestro script usaremos las variables:

PATH_INFO: Contiene la URI que recibe Apache antes de ser escapada QUERY_STRING: Contiene la Query String que recibe Apache antes de ser escapada

En perl:
my $url = "http://www.XXX.es"$ENV{PATH_INFO}."?".$ENV{QUERY_STRING};

Tras esto construimos una página mediante prints, con un meta que contenga como url la que hemos construido. Este Post es simplemente para ver que existen distintas formas para este proceso, y que cada una de ellas tienes sus diferencias, es cuestión de elegir ;)

sábado, 28 de marzo de 2009

Reconstruyendo BBDD yum

Esta mañana me he puesto a trabajar en el portatil, y me he llevado una desagradable sorpresita.

No se debido a que, pero mi BD de yum estaba corronpida, y claro acostumbrarse a yum es muy sencillo pero acostumbrarse a no tenerlo eso es mas complicado ;)

[root@gollum ~]#yum list
Loaded plugins: refresh-packagekit
rpmdb: Thread/process 3137/139866601236208 failed: Thread died in Berkeley DB library
error: db4 error(-30975) de dbenv->failchk: DB_RUNRECOVERY: Fatal error, run database recovery
....

Lo primero que he intentado por supuesto ha sido limpiar la BD a ver si colaba, pero la verdad tenia pocas espectativas de exito.

[root@gollum ~]# yum clean all
Loaded plugins: refresh-packagekit
rpmdb: Thread/process 3137/139866601236208 failed: Thread died in Berkeley DB library
error: db4 error(-30975) de dbenv->failchk: DB_RUNRECOVERY: Fatal error, run database recovery
error: no se pudo abrir índice Packages utilizando db3 - (-30975)

......

Por este motivo y anque parezca un poco drastico, decidi reconstruir por completo la BBDD, eliminandola previamente.

[root@gollum ~]# rm -f /var/lib/rpm/__db*
[root@gollum ~]# rpm --rebuilddb
[root@gollum ~]# yum list
Loaded plugins: refresh-packagekit
Installed Packages

....

Este proceso viene a tardar unos 5 minutos.

Actualización:
Acabo de ver que este error le ha acurrido a más gente, sobre las mismas fechas. Si no recuerdo mal, en mi última actualización del sistema, se actualizó yum (Era algo del entorno gráfico), quiza sea debido a esta update, que se haya corrompido la BBDD.
http://forums.fedoraforum.org/showthread.php?p=1186925

jueves, 19 de marzo de 2009

Vaciando Papelera de Reciclaje "vacia"

Hace unos días, me ocurrió algo bastante curioso con la papelera de marras.
Resulta que haciendo limpieza de algunas unidades de disco USB, deje rastros en la papelera....
Al cabo de unos días intente vaciar la papelera y exactamente un directorio, se negaba a ser borrado.
Después de echar un vistazo vi que el directorio de la papelera está situado en
"$HOME/.local/share/Trash", aquí hay dos directorios "files" y "info", efectivamente los datos a borrar estaban aquí por lo que el comportamiento lógico es eliminarlos desde consola.
"rm -Rf $HOME/.local/share/Trash/files/*"
"rm -Rf $HOME/.local/share/Trash/info/*"

Cual fue mi sorpresa, que no solo no se habian borrado, sino que además, ahora no tenia permisos para acceder a ellos desde el entorno grafico, y además en la ruta mencionada antes ya no existian. La cara que se me quedó fue para grabarla ;)
Estube dando vueltas varios dias hasta que en uno de los intentos me di cuenta que al intentar restaurar, la ruta de origen hacia referencia a una unidad externa, por lo que evidentemente la conecte para dar un vistazo, y ahí estaban, colgando del raiz hay un directorio ".Trah" con "files" e "info" dentro, entonces si me dejo restaurar y posteriormente eliminar definitivamente.
Por esto deduzco que existe una papelera diferente para cada volumen, lo que aun no tengo claro es donde guardaba la informacion de este directorio borrado, si la unidad estaba desmontada y desconectada fisicamente. ;)

viernes, 13 de marzo de 2009

Monitorización - Python


Hace ya tiempo que me picaba el gusanillo de volver a "jugar" tecleando un poco de código de vez en cuando, pero sin pasarse que es adictivo ;))



Así que he decidido instalarme Eclipse, por eso de tener una interfaz mas amigable, y empezar otra vez, por lo menos para desoxidar.
Después de esto vino el gran dilema, ¿En que lenguaje?........
Las opciones pasaban entre C y C++ que era lo que más conocía o Java(El cual aborrecí en mis tiempos de facultad ;)), fue entonces cuando pensando que hacer me vino a la cabeza "python", que era totalmente nuevo para mi y del que había oído hablar maravillas, así que la decisión estaba tomada.
Bueno lo primero que he hecho es un pequeño script para monitorizar el estado de una máquina, es una tontería pero para ir soltándose no está mal, así que por si a alguien le sirve ahí lo dejo.

#!/usr/bin/python

# -*- coding: utf-8 -*-
"""
Copyright: Manolo Alambra Giner
Licencia: Affero GPL V3

Script para monitorizar sistemas.

Uso:
----

Ejecute en una línea de comandos:

$ python monitoriza.py

"""

import commands
import os
import sys
import subprocess

#######################################
##Definicion de las funciones empleadas
#######################################
def MandaMail():
# Obtiene el texto de la Monitorizacion
f = open("/tmp/monitoriza_temp", "r")
mssg = f.read()
f.close()
#Genera y manda el mail
SENDMAIL = "/usr/sbin/sendmail"
p = os.popen("%s -t" % SENDMAIL, "w")
p.write("To: maalgi@ono.com\n")
p.write("Subject: Monitorizacion\n")
p.write("\n")
p.write(mssg)
sts = p.close()



#Obtiene la Swap libre y la ocupada y determina si se esta usando o no mas del 50%
def ObtConSwap():
result1=commands.getoutput('cat /proc/meminfo|grep "SwapTotal:"|tr -s "'" "'"|cut -d "'" "'" -f 2')
result2=commands.getoutput('cat /proc/meminfo|grep "SwapFree:"|tr -s "'" "'"|cut -d "'" "'" -f 2')
result3=int(result1)-int(result2)
if int(result3)>int(result1)/2:
cont=0
else:
cont=1
return cont


#Devuelve 1 si encuentra un valor superior a 90 sino devuelve 0
#Al final del comando con sed eliminamos el ultimo caracter que era un '%' por ''
def ObtOcuPart():
cont=0
result=commands.getoutput('df -h|tr -s "'" "'"|cut -d "'" "'" -f 5|grep %|sed -e "'"1d"'"|sed "'"s/.$//g"'"')
ruta="/tmp/monitoriza_temp2"
wfich(str(result),ruta)
f=open(ruta,"r")
for linea in f.readlines():
if linea[:-1]!="":
if int(linea[:-1])>90:
cont=1
return cont

#Obtiene la media tiempo ocioso de la CPU para 10 iteraciones
#Con sed eliminamos las 2 primeras lineas
def ObtConCPU():
iter=10
result=commands.getoutput('vmstat 5 '+str(iter)+'|sed -e "'"1,2d"'"|tr -s "'" "'"|cut -d "'" "'" -f 16')
ruta="/tmp/monitoriza_temp2"
wfich(str(result),ruta)
f=open(ruta,"r")
s=0
for linea in f.readlines():
if linea!="":
s=int(s)+int(linea)
result1=int(s)/int(iter)
f.close()
commands.getoutput('rm -f'+ruta)
return result1

#Obtiene el numero de interfaces con errores
def ObtEstInterfaces():
result=commands.getoutput('/sbin/ifconfig -a|grep errors|tr -s "'" "'"|cut -d "'" "'" -f 4|grep -v errors:0|wc -l')
return result

#Obtiene el numero de interfaces con colisiones
def ObtEstInterfaces2():
result=commands.getoutput('/sbin/ifconfig -a|grep collisions|tr -s "'" "'"|cut -d "'" "'" -f 2|grep -v collisions:0|wc -l')
return result

#Obtiene el nombre de la maquina
def ObtNom():
result=commands.getoutput('uname -a')
return result

#Obtiene la fecha y hora de la maquina
def ObtFecha():
result=commands.getoutput('date')
return result

#Obtiene el % de memoria usada
def checkmem():
result1 = commands.getoutput('free|grep Mem:|tr -s "'" "'" |cut -d "'" "'" -f 2')
result2 = commands.getoutput('free|grep Mem:|tr -s "'" "'" |cut -d "'" "'" -f 3')
result3=int(result2)*100/int(result1)
return result3

#Escribe machacando el contenido en un fichero
def wfich(linea,fichero):
fich_maquinas=open(fichero, "w")
fich_maquinas.write(linea)
fich_maquinas.close()

#Escribe anyadiendo el contenido al final de en un fichero
def afich(linea,fichero):
fich_maquinas=open(fichero, "a")
fich_maquinas.write(linea)
fich_maquinas.close()


###################################
##Comienza el main de la aplicacion
###################################

#Ruta del fichero temporal a generar con los resultados de la monitorizacion
ruta1="/tmp/monitoriza_temp"

#Escribe a fichero la fecha de la monitorizacion, iniciando el fichero, creandolo o machacandolo
fech=ObtFecha()
fech1=str(fech)+'\n\n'
wfich(str(fech1),ruta1)

#Escribe a fichero el nombre de la maquina, iniciando el fichero para anyadir al final
nom=ObtNom()
nom1=str(nom)+'\n\n'
afich(str(nom1),ruta1)

#Si el consumo de memoria RAM es superior al 85% escribe un aviso si es menor otro
mem=checkmem()
if int(mem)>85:
afich('ERROR - Ocupacion de memoria ELEVADA ->'+str(mem)+'%\n\n',ruta1)
else:
afich('OK - Ocupacion de memoria Correcta ->'+str(mem)+'%\n\n',ruta1)


#Si el numero de interfaces con errores es superior a 0 escribe un aviso si es =0 escribe otro
inter=ObtEstInterfaces()
if int(inter)>0:
afich('ERROR - Existen errores en algunas interfaces\n\n',ruta1)
else:
afich('OK - Todas las interfaces sin errores\n\n',ruta1)

#Si el numero de interfaces con colisiones es superior a 0 escribe un aviso si es =0 escribe otro
inter=ObtEstInterfaces2()
if int(inter)>0:
afich('ERROR - Existen colisiones en algunas interfaces\n\n',ruta1)
else:
afich('OK - Todas las interfaces sin colisiones\n\n',ruta1)

#Si el consumo de CPU es mayor de 75 escribe un aviso si no lo da como correcto
id=ObtConCPU()
if int(id)<75:
afich('ERROR - El consumo de CPU es demasiado elevado ->'+str(id)+'% id\n\n',ruta1)
else:
afich('OK - El consumo de CPU es correcto ->'+str(id)+'% id\n\n',ruta1)

#Si la ocupacion de una particion supera el 90% deja un aviso sino lo da como correcto
part=ObtOcuPart()
if int(part)==1:
afich('ERROR - Hay particiones con una ocupacion mayor al 90%\n\n',ruta1)
else:
if int(part)==0:
afich('OK - Ocupacion de las particiones correcta\n\n',ruta1)
else:
afich('Error al monitotizar las particiones\n\n',ruta1)

#Determina si se esta usando mas del 50% de la Swap
sw=ObtConSwap()
if sw==0:
afich('ERROR - Mas del 50% de la Swap esta siendo usada\n\n',ruta1)
else:
if sw==1:
afich('OK - El uso de la Swap es correcto menor al 50%\n\n',ruta1)
else:
afich('Error al monitotizar la Swap\n\n',ruta1)

#Enviamos los resultados por mail
MandaMail()