Planeta Sysadmin

de sysadmins para sysadmins

August 18, 2017

Poesía Binaria

Trasteando con juguetes nuevos. Primeros pasos con el ESP8266

ESP8266
Esta pequeña placa de apenas 24x14mm contiene un microcontrolador y chip WiFi a/b/g (esas de 2.4GHz) y una memoria. Además de algunos leds, una antena y un oscilador. Cuesta muy poco dinero (apenas unos 3€ comprándolo en algunas tiendas de España y mucho menos si se compra directamente a China). Y encima consume muy poco, alrededor de 0.5W a pleno rendimiento y muchísimo menos en alguno de sus modos de sueño y bajo consumo. Lo que hace que este circuito sea idóneo para trabajar con pilas o baterías, miniaturizar nuestros proyectos y automatismos así como conectarlos a Internet o a una red local.

Así de primeras, se me ocurren algunos proyectos, unos de ellos perversos y otros más normales. Entre ellos sistemas de automatización doméstica, lo típico encender y apagar enchufes desde el móvil, o programar para que se enciendan y apaguen y verificar el estado de los aparatos; estaciones meteorológicas a las que podemos acoplar decenas de sensores diferentes, avisadores de correo en el buzón, pequeños detectores de humo para zonas de no fumadores o para detectar que alguien se acerca a la puerta de la habitación; así como un pequeño keylogger que podemos camuflar dentro de un teclado, dispositivo USB que podrá hacer estragos y camuflar dentro de un ratón o para suplantar una WiFi y que los usuarios se conecten a ti (aunque no creo que soporte mucho ancho de banda con sacar la información que queremos y desconectar vamos sobrados).

Es cierto que hay versiones y chips más autónomos como es el caso del NodeMCU, que puedes programarlo en LUA o Python; o por ejemplo versiones más nuevas como el ESP8866-12 (para mis experimentos estoy utilizando el ESP8266-01), cuando yo lo compré me salía un poco más barato el ESP8266-01, además, lo quiero para un proyecto en el que cuanto más pequeño, mejor.

Estrenando el juguete

Pero por ahora estoy como un chaval con un juguete nuevo y quiero experimentar con él. Empezar a cacharrear y a descubrir sus posibilidades. Así que vamos a empezar conectándolo al ordenador a ver qué pasa. En principio, yo he utilizado un adaptador USB a puerto serie para poder enviar y recibir de la placa. Este adaptador (otros no lo hacen) tiene dos salidas VCC. Una a 5V proporcionada por el USB y otra a 3.3V después de pasar por un regulador de tensión. Y, como el ESP8266 trabaja a 3.3V, pongo una resistencia de 1KΩ entra la patilla de transmisión del adaptador y la patilla de recepción del ESP8266. En algunos adaptadores no hace falta, pero yo, sin esa resistencia no puedo comunicarme bien con el chip. No se me ha quemado, como dicen en muchos sitios, pero pasa de mi olímpicamente.
Adaptador USB a UART RS323

Aprovechar el adaptador USB de Arduino

Es otra opción si, como yo, eres de los que te pones a hacer este tipo de cosas a las 3 de la mañana y no tienes un adaptador a mano. Si tienes un Arduino cerca puedes probar hacer lo siguiente:

Así estarás utilizando la propia placa Arduino como conversor USB-TTL para nuestro ESP8266 ya que hemos puesto RESET a VCC, el chip Atmega no va a entrar en funcionamiento y todo lo que hablemos por el puerto serie lo estaremos aprovechando para nuestro ESP8266. Eso sí, dependiendo de la placa, la resistencia de 1KΩ ya no es necesaria. Además, yo en enlazado el RX de Arduino con el RX de la ESP8266 y el TX de uno con el TX del otro, mientras que con al conversor USB hacía lo contrario. Eso es por cómo está la placa etiquetada, si hacemos caso a las flechitas que hay dibujadas todo se entiende mejor.

Hablando con nuestro nuevo amigo

Lo tenemos todo listo para empezar a hacer algo con el chip. Así que vamos a hablar con él a través del puerto serie. Como está pensado para comunicarnos con otro microcontrolador (éste que se encargue de la comunicación y otro que haga el trabajo sucio), podemos enviarle comandos al chip y éste nos devolverá un resultado de la ejecución de dichos comandos. Así que lo podemos conectar sin problema a un Arduino (o un circuito basado en ATmega/ATtiny), un Raspberry PI, microcontroladores PIC o incluso una placa controladora de un móvil viejo si tenemos ganas de cacharrear. Aunque, por supuesto, el ESP8266 puede funcionar de manera autónoma.

El idioma que habla es el de los módems de toda la vida, tanto los de cable telefónico como los GSM. Bueno, no lo hablan todos los dispositivos, pero sí muchos de ellos, el lenguaje de comandos Hayes. Para mi gusto es un lenguaje muy imperativo (AT, viene de ATención) y serán comandos muy simples, y siempre con una respuesta cubriendo así todas las opciones que tiene nuestro chip. Así que vamos a conectar a un puerto USB nuestro ESP8266 y abrir un emulador de terminal. Podemos utilizar el mismo que viene con Arduino, aunque a mí me gusta más CuteCom. Aunque puedes utilizar GNU Screen si lo prefieres.
La conexión por defecto suele ser a 115200 baudios sin paridad y con CRLF como fin de línea (aunque a mí me funciona sólo con LF).

Hay algunos comandos que soportan las terminaciones _CUR y _DEF. Estas definiciones suelen afectar a la memoria interna del chip, ya que guardan valores de configuración. Estos pueden ser tratados sólo para la sesión actual (_CUR), por lo tanto cuando reiniciemos se perderá esa información; o pueden ser grabados de forma definitiva en el chip y recordados en futuras sesiones (_DEF). Esto nos permitirá por ejemplo conectar automáticamente con un punto de acceso o recordar la velocidad de conexión del puerto serie entre otras cosas.

Voy a hacer un resumen aquí de algunos comandos que podemos utilizar:

Comprobar el estado del chip

Sólo para saber que la comunicación se establece y que el chip está bien inicializado.

AT
OK

Si obtenemos un error aquí, puede deberse a:
  • La inicialización no ha sido correcta. Se ha encontrado un problema al ejecutar el programa y todas las demás acciones se cancelan.
  • La corriente de entrada no es estable. Tal vez haya habido alguna variación en la entrada y ha provocado un mal funcionamiento.
  • El voltaje no es estable o tiene valores muy grandes o muy pequeños. Igual que antes, eso puede provocar un mal funcionamiento. Si le metemos 9V al chip sí que nos lo podemos cargar, pero si le introducimos 5V no se garantiza que el funcionamiento sea correcto. Lo mismo si le aplicamos menos de 3V.
  • Error en el programa. Normalmente el firmware original está muy probado pero puede tener errores. Asimismo si probamos con otro firmware pueden pasar muchas cosas. ¡Pero estamos aquí para jugar y experimentar!
  • La velocidad de nuestro terminal no es correcta. Es decir, que o nuestro ESP8266 o nuestro ordenador estén hablando a diferentes velocidades, lo que puede trabar la comunicación.
  • ¡Cualquier cosa! En el mundo del HW y el SW todo puede fallar. Y te agradecería que pusieras un comentario para completar esta respuesta.
  • Tu ESP8266 está muerto, Jim. Porque todo puede pasar.
  • Tu conversor USB está muerto o, al menos, moribundo. Porque no siempre va a tener la culpa el mismo.
  • Revisa tus cables. Me ha pasado muchas veces, cuando tienes muchos cables juntos, algunos valen, otros no valen, estás con la protoboard y no hacen buen contacto o realmente tus ojos te han traicionado. Si estás con una placa soldada revisa también tus soldaduras, puede que haya un problema. Si es problema de contactos tal vez sí hagan contacto pero no sea muy firme y fluctúe la corriente.

Reset del dispositivo

Cuando queremos reinicializar el chip cancelando conexiones y empezar de nuevo (también podríamos quitarle corriente y volver a aplicársela).

AT+RST
OK
ets Jan  8 2013,rst cause:2, boot mode:(3,6)
load 0x40100000, len 1856, room 16
tail 0
chksum 0x63
load 0x3ffe8000, len 776, room 8
tail 0
chksum 0x02
load 0x3ffe8310, len 552, room 8
tail 0
chksum 0x79
csum 0x79
2nd boot version : 1.5
SPI Speed      : 40MHz
SPI Mode       : DIO
SPI Flash Size & Map: 8Mbit(512KB+512KB)
jump to run user1 @ 1000
….
….
….
Ai-Thinker Technology Co. Ltd.
ready

Restaurar valores de fábrica

Si queremos restaurar la configuración del chip como venía cuando lo compramos podemos ejecutar:

AT+RESTORE

El chip se reiniciará cuando termine de reponer todos los valores.

Versión del firmware

Nos dará información básica de la versión, y su fecha. Nos ayudará para saber si podemos ejecutar ciertos comandos o saber si tenemos ciertas características. Podremos actualizar nuestro chip en el futuro si queremos.

AT+GMR
AT version:1.1.0.0(May 11 2016 18:09:56)
SDK version:1.5.4(baaeaebb)
Ai-Thinker Technology Co. Ltd.
Jun 13 2016 11:29:20
OK

Echo de comandos

Si queremos que al enviar un comando nos diga qué comando hemos enviado o no. Por ejemplo, si lo utilizamos con un Arduino, puede ser incómodo enviar un comando y recibir la respuesta de nuevo. Nos puede dificultar un poco el parseo de la misma.

ATE1
OK <---- Activa echo
ATE0
OK <---- DESactiva echo
[/simterm]
Velocidad de conexión
Lo ideal es dejarlo como está 115200 baudios no es mala velocidad. Sobre todo si este chip se va a encargar de gestionar la red y otro sólo se limitará a controlar, o queremos el puerto serie para depuración o enviar algún comando. Aunque puede ser que el chip con el que vamos a conectar nuestro ESP8266 no sea capaz de ir tan rápido. Por ejemplo muchos Arduinos Duemilanove no van a más de 57600 y eso puede ser un problema. Así que no nos queda otra que cambiar la velocidad de nuestro chip.
Las velocidades válidas que he podido ver son: 9600, 19200, 38400, 74880, 115200, 230400, 460800 y 921600 aunque puede que con otro firmware más nuevo haya más velocidades soportadas.
[simterm]
AT+IPR=9600

La salida, debería ser un OK, aunque dado que hay un cambio de velocidad no vamos a ser capaces de captar ese OK. A partir de este momento podremos conectar a 9600 baudios.
Si lo vamos a conectar con un Arduino la velocidad de 9600 puede ser más que suficiente si sólo vamos a enviar/recibir datos de control. Por ejemplo, estados de dispositivo, temperaturas, etc y luego que el ESP8266 se encargue de generar una respuesta web por ejemplo y la envíe por la red.

Antiguamente había un comando AT+CIOBAUD con el que podíamos consultar la velocidad actual. Aunque no tiene mucho sentido ya que hemos tenido que establecer dicha velocidad para hacer la conexión. Así que con AT+IPR sólo podemos definir una velocidad nueva.
Atención. AT+IPR define la velocidad que le digamos. Eso es, que si no es una velocidad estándar, lo va a aceptar y el chip empezará a funcionar o malfuncionar a esa velocidad y puede que no podamos acceder a él hasta que flasheemos de nuevo el firmware. No es un brickeo completo, pero un pequeño error nos puede amargar un buen rato de trabajo.

Dato que este comando es peligroso, en versiones más nuevas del firmware se incluye AT+UART_CUR y AT+UART_DEF en donde podemos modificar los bits de parada, comprobación de paridad y algunas cosas más.

Cambiar modo WiFi

El WiFi del ESP8266 puede funcionar de varias maneras:

  1. STA – Modo estación. Es decir, el chip se conecta a un punto de acceso.
  2. AP – Punto de acceso. Para que los dispositivos se conecten a nosotros.
  3. STA+AP – Lo mejor de los dos mundos.

Ahora bien, podemos consultar cómo está funcionando el dispositivo y también definir el modo de funcionamiento. Este modo se mantendrá después del reset. Incluso tras la perdida de energía.

AT+CWMODE_CUR?
+CWMODE_CUR:1
AT+CWMODE_CUR=3
OK
AT+CWMODE_CUR?
+CWMODE_CUR:3

Listar redes WiFi disponibles

Sólo podremos listar las redes visibles si estamos en modo STA o STA+AP. Si sólo estamos como AP nos devolverá ERROR.

AT+CWLAP
+CWLAP:(4,”dlink-EFFB”,-88,”1c:2f:2b:64:ea:2b”,2,18,0)
+CWLAP:(3,”vodafone218A”,-90,”58:2a:f7:a9:31:90″,4,20,0)
+CWLAP:(0,”WLAN_TA1″,-91,”d4:a0:2a:cd:8e:f8″,5,13,0)
+CWLAP:(4,”Jazztel_A5B717″,-80,”9c:97:26:a5:c7:17″,6,16,0)
OK

Veremos una lista de las redes (así conocéis a mis vecinos un poco. Además vemos más información como:
  • Seguridad de la red:
    • 0 – Open. Red abierta.
    • 1 – WEP
    • 2 – WPA_PSK
    • 3 – WPA2_PSK
    • 4 – WPA_WPA2_PSK
  • SSID. O nombre de la red.
  • RSSI. Fuerza de la señal.
  • MAC. Dirección MAC del punto de acceso.
  • CH. Canal.
  • freq. offset. Offset del punto de acceso en KHz
  • freq. calibration. Calibración para el offset anterior.

Si queremos personalizar esta salida podremos utilizar algo como:

AT+CWLAPOPT=1,127
OK

En este caso ordenará las redes de la salida por su intensidad de señal (el primer valor, 0 si no queremos ordenarlas). Y mostrará todos los datos (el segundo valor es una máscara de bits que activa o desactiva cada uno de los valores de la salida).
Por ejemplo AT+CWLAPOPT=1,7 ordenará las redes por SSID y mostrará los valores de seguridad, ssid e intensidad de señal solamente.

Conectarse a una red WiFi

¡Vamos a hacer algo de provecho! Conectémonos a una red. Primero, elegiremos si vamos a tener activo DHCP o no, para que nuestro dispositivo coja una dirección IP automáticamente (Si el router no lo soporta, olvidémonos):

AT+CWDHCP_CUR=1,0
OK

Con esto decimos que en el modo 1 (Station) ponemos DHCP a 0. Si quisiéramos hacerlo con el modo AP sería el modo 0. Y si queremos activar o desactivar ambos modos a la vez, pondremos modo2.
AT+CWJAP=”MiRed”,”MiPassword”
WIFI CONNECTED
AT+CWJAP?
+CWJAP:”MiRed”,”xx:xx:xx:xx:xx:xx”,9,-73

Si utilizamos DHCP, ya tenemos que tener dirección IP. Pero si queremos configurar una IP estática haremos:

AT+CIPSTA_CUR=”192.168.0.19″,”192.168.0.1″,”255.255.255.0″

Donde la primera dirección es la dirección IP del dispositivo, el segundo es la puerta de enlace y el tercero la máscara de subred. Los dos últimos valores no es obligatorio especificarlos para el ESP8266, pero tal vez sí lo sea para tu red. Y luego cuando consultemos nuestra dirección IP:
AT+CIPSTA_CUR?
+CIPSTA_CUR:ip:”192.168.0.19″
+CIPSTA_CUR:gateway:”192.168.0.1″
+CIPSTA_CUR:netmask:”255.255.255.0″
OK

Las DNS a utilizar se obtienen o bien del router (por DHCP) o se establece OpenDNS (208.67.222.222). En versiones antiguas como la mía no se permite cambiar esta información, aunque en versiones nuevas se puede hacer AT+CIPDNS=1,dns_server

Y cuando queramos desconectar…

AT+CWQAP
OK

Otra forma de mirar la IP es utilizar:

AT+CIFSR
+CIFSR:APIP,”192.168.4.1″
+CIFSR:APMAC,”62:01:94:0b:0a:1a”
+CIFSR:STAIP,”192.168.0.19″
+CIFSR:STAMAC,”60:01:94:0b:0a:1a”

Resolver un dominio

Un dominio debe ser resuelto a una dirección IP antes de conectarnos hacia él. Aunque podemos conectarnos a través del nombre de dominio, para probar que todo está bien podemos pedir la información de la resolución del nombre. Internamente se contactará con el servidor de nombres para obtener el valor:

AT+CIPDOMAIN=”google.com”
+CIPDOMAIN:216.58.214.174
OK

Ping a un servidor

Con esto sabemos cuánto tarda en responder un host. Lo podemos hacer tanto por IP como por dominio:

AT+PING=”google.com”
+14
OK

Google ha tardado en contestar 14ms.

Conectar con un servidor web

Vamos a poner vamos comandos con el fin de descargar contenido de un servidor web.

  • Primero con CIPMUX diremos que vamos a soportar múltiples conexiones, Porque nosotros lo valemos.
  • Luego iniciamos una conexión (le damos 2 como identificador, por ejemplo)
  • Tras ello iniciamos un envío de datos por la conexión 2 de 61 bytes
  • Una vez aceptada, enviamos la información.
  • Ahora recibimos la información del servidor.

La conexión la vamos a hacer al servicio ifconfig.me, para saber cuál es nuestra IP remota en Internet. Veamos los comandos

AT+CIPSTART=2,”TCP”,”ifconfig.me”,80
2,CONNECT
OK
AT+CIPSEND=2,61
OK
GET / HTTP/1.1
Host: ifconfig.me
User-Agent: curl/1.2.3
Recv 61 bytes
SEND OK
+IPD,2,193,153.121.72.211,80:HTTP/1.1 200 OK
Date: Tue, 25 Jul 2017 19:26:52 GMT
Server: Apache
Vary: Accept-Encoding
Connection: close
Transfer-Encoding: chunked
Content-Type: text/plain
32.111.222.123
2,CLOSED

Como la conexión se cierra sola no hacemos nada más, pero si queremos cerrarla manualmente podemos hacer:
AT+CIPCLOSE=2
OK

Si queremos hacerlo rápido, ya que muchos servidores HTTP requieren velocidad a la hora de pedirles información porque tienen timeouts muy ajustados, podemos hacer un script como este:
1
2
3
4
5
echo -e "AT+CIPSTART=2,"TCP","ifconfig.me",80\r" >/dev/ttyACM0;
sleep 3;
echo -e "AT+CIPSEND=2,61\r" > /dev/ttyACM0 ;
sleep 1;
echo -e "GET / HTTP/1.1\r\nHost: ifconfig.me\r\nUser-Agent: curl/1.2.3\r\n\r\n" > /dev/ttyACM0 ;

Como vemos, en la línea de CIPSTART especificamos el ID de conexión, el tipo de conexión que puede ser TCP, UDP o SSL (bien por la seguridad, aunque la pondremos algo a prueba), el host o IP con el que contactar y el puerto. Y luego para CIPSEND especificaremos el ID de conexión y el tamaño de los datos a enviar, cuando recibamos el OK con el prompt (petición de información) procedemos a enviar los datos en bruto. Se leerán tantos bytes como hayamos puesto en el tamaño.

Actualización del Firmware por WiFi

Este chip soporta auto-actualización del propio software del chip si lo conectamos a una red inalámbrica de la siguiente manera:

AT+CIUPDATE
+CIPUPDATE:1
+CIPUPDATE:2
+CIPUPDATE:3
+CIPUPDATE:4

Tarda un rato en actualizar y tal vez tengamos un problema en nuestros dispositivos por temas de memoria. Sobre todo porque el chip viene con poco espacio de almacenamiento y los nuevos firmwares son mucho más grandes.:
  1. Encontrar el servidor
  2. Conectar
  3. Descargar el software
  4. Actualizar!!

¿Hay más?

Por supuesto tenemos más comandos soportados en viejas y nuevas versiones del firmware. He sacado sobre todo comandos de conexión a un punto de acceso y conexión como cliente aunque también podemos ser un punto de acceso y crear un servidor. Además de los modos de sueño y bajo consumo de los que quiero investigar un poco más. Aunque lo dejo para futuros posts. De todas formas, podemos ver la referencia de comandos AT del ESP8266.

El primero de muchos

Este cacharro me ha encantado, así que le dedicaré algunos posts más a los nuevos descubrimientos que haga con él. Lo próximo será programarlo y tengo muchas ideas para poner en práctica.

The post Trasteando con juguetes nuevos. Primeros pasos con el ESP8266 appeared first on Poesía Binaria.

by Gaspar Fernández at August 18, 2017 08:05 AM

August 16, 2017

www.rootzilopochtli.com

Notas del Curso de Docker: Principiante

El fin de semana pasado, tuve la fortuna de poder asistir al meetup de Docker, donde nos dieron un curso de Docker para principiantes. A pesar de las dificultades presentadas, ya que al ser un curso totalmente gratuito, a base del esfuerzo de la comunidad se logró bastante bien.

En este primer post, les compartiré mis notas del curso.

En el #SysArmyMxTalks previo, el buen Iván Chavero, nos habló de los fundamentos de los contenedores, si quieren revisar el material, lo encuentran en los enlaces:

Durante el curso, nos dieron una breve introducción a docker, además de ver un fragmento del vídeo de la presentación de Jessie Frazell:

Ver en Youtube

Después de esto, iniciamos con la parte práctica:

Comandos básicos

1. Después de instalar docker, es necesario habilitarlo e iniciarlo

user@computer:$ sudo systemctl status docker
[sudo] password for alex.callejas:
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: dis
Active: inactive (dead)
Docs: http://docs.docker.com
$ sudo systemctl enable docker
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.
$ sudo systemctl start docker

2. Para correr un contenedor mediante docker con nginx, ejecutamos

user@computer:$ sudo docker run nginx
Unable to find image 'nginx:latest' locally
Trying to pull repository registry.fedoraproject.org/nginx ...
Trying to pull repository registry.access.redhat.com/nginx ...
Trying to pull repository docker.io/library/nginx ...
sha256:788fa27763db6d69ad3444e8ba72f947df9e7e163bad7c1f5614f8fd27a311c3: Pulling from docker.io/library/nginx
94ed0c431eb5: Pull complete
9406c100a1c3: Pull complete
aa74daafd50c: Pull complete
Digest: sha256:788fa27763db6d69ad3444e8ba72f947df9e7e163bad7c1f5614f8fd27a311c3
Status: Downloaded newer image for docker.io/nginx:latest
$

Como es una imagen que no tenemos en un repositorio local, la descarga del repositorio oficial de docker.

3. Si abrimos una terminal alterna, podemos observar que el contenedor se esta ejecutando

user@computer:$ sudo docker ps
[sudo] password for alex.callejas:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2127ad18758a nginx "nginx -g 'daemon ..." 30 seconds ago Up 29 seconds 80/tcp cocky_joliot
$

Se observa que, por default, docker nombra el contenedor como cocky_joliot, esto es debido a que si no especificamos un nombre del contenedor, docker por convención utilizará un adjetivo y el apellido de algún científico (según el código fuente de docker)

4. También podemos ejecutar un contenedor de forma interactiva con una TTY

user@computer:$ sudo docker run ubuntu bash
Unable to find image 'ubuntu:latest' locally
Trying to pull repository registry.fedoraproject.org/ubuntu ...
Trying to pull repository registry.access.redhat.com/ubuntu ...
Trying to pull repository docker.io/library/ubuntu ...
sha256:34471448724419596ca4e890496d375801de21b0e67b81a77fd6155ce001edad: Pulling from docker.io/library/ubuntu
d5c6f90da05d: Pull complete
1300883d87d5: Pull complete
c220aa3cfc1b: Pull complete
2e9398f099dc: Pull complete
dc27a084064f: Pull complete
Digest: sha256:34471448724419596ca4e890496d375801de21b0e67b81a77fd6155ce001edad
Status: Downloaded newer image for docker.io/ubuntu:latest
$ sudo docker run -it ubuntu bash
root@a656df585428:/#
root@a656df585428:/# ps
PID TTY TIME CMD
1 ? 00:00:00 bash
11 ? 00:00:00 ps
root@51728d60a8a8:/# pwd
/
root@51728d60a8a8:/# ls
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr
root@51728d60a8a8:/# exit
exit
$

Se observa que, dentro del contenedor, solamente existe el proceso de bash que ejecutamos, además de contar con toda la estructura de directorios del sistema.

5. En la terminal alterna, podemos observar la ejecución del contenedor

user@computer:$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a656df585428 ubuntu "bash" 45 seconds ago Exited (0) 28 seconds agonifty_payne
2127ad18758a nginx "nginx -g 'daemon ..." 3 minutes ago Exited (0) 2 minutes ago cocky_joliot
$

Con la opción -a, podemos ver todos los contenedores que hemos ejecutado, por default solo se muestran los que se encuentran en ejecución actualmente.

6. Si queremos eliminar un contenedor, utilizamos su CONTAINER ID, de la salida del ps ejecutando

user@computer:$ sudo docker rm 2127ad18758a
2127ad18758a
$ sudo docker rm a656df585428
a656df585428
$

Al revisar en la terminal alterna, ya no se observa dicho contenedor

user@computer:$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$

7. Se le puede indicar al contenedor que se ejecute en background y que utilice un puerto local en particular

user@computer:$ sudo docker run -d -p 80:80 nginx
c81ee76d8cd0b3180b4d543c9d266d13dc1302d396207412eab80d10b091d269
$

Se observa en la terminal alterna, que el proceso se ejecute en el puerto asignado

user@computer:$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c81ee76d8cd0 nginx "nginx -g 'daemon ..." 5 seconds ago Up 4 seconds 0.0.0.0:80->80/tcp tender_montalcini
$

Podemos revisar con el navegador o con curl que el contenedor nos muestre la página de prueba de nginx en el puerto local configurado

Para detener el contenedor, sin eliminarlo, utilizamos su CONTAINER ID o su nombre

user@computer:$ sudo docker stop tender_montalcini
tender_montalcini
$

8. Si lo deseamos, podemos ejecutar un contenedor con un nombre en particular

user@computer:$ sudo docker run --name test -d -p 80:80 nginx
a13f3e75ea522646ca6b1b6a926cdf680b636924bdbf2c2942b7249acff0e513
$

Lo revisamos en la terminal alterna

user@computer:$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a13f3e75ea52 nginx "nginx -g 'daemon ..." 3 seconds ago Up 3 seconds 0.0.0.0:80->80/tcp test
$

También podemos obtener estadísticas ejecutando

user@computer:$ sudo docker stats

CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
a13f3e75ea52 0.01% 1.969 MiB / 7.493 GiB 0.03% 7.68 kB / 936 B 0 B / 0 B 2

Estas se muestran en tiempo real.

9. Con el contenedor ejecutándose, también podemos indicarle que corra algún comando en particular, por ejemplo

user@computer:$ sudo docker exec -it test bash
[sudo] password for alex.callejas:
root@a13f3e75ea52:/#
root@a13f3e75ea52:/# ps
bash: ps: command not found
root@a13f3e75ea52:/# exit
exit
$

En este caso en particular, le indicamos que ejecutara, de forma interactiva bash, sin embargo se observa que la imagen del contenedor no tiene el comando ps. Esto puede ser debido a que cuando se creo la imagen, no se le incluyó dicho comando o comandos; esto se puede realizar para que la imagen del contenedor tenga una característica de seguridad en caso de ser necesario.

El proceso para generar la imagen de esta forma se profundizará en una sesión posterior.

10. Para revisar la configuración general del contenedor, ejecutamos

user@computer:$ sudo docker inspect test
[
{
"Id": "a13f3e75ea522646ca6b1b6a926cdf680b636924bdbf2c2942b7249acff0e513",
"Created": "2017-08-12T15:37:29.101171417Z",
"Path": "nginx",
"Args": [
"-g",
"daemon off;"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 6912,
"ExitCode": 0,
"Error": "",
"StartedAt": "2017-08-12T15:37:29.606735048Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:b8efb18f159bd948486f18bd8940b56fd2298b438229f5bd2bcf4cedcf037448",
"ResolvConfPath": "/var/lib/docker/containers/a13f3e75ea522646ca6b1b6a926cdf680b636924bdbf2c2942b7249acff0e513/resolv.conf",
...

Salida completa de la inspección: inspect_test.txt

También podemos obtener información de la inspección en formato de Go

user@computer:$ sudo docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' test
172.17.0.2
$ sudo docker inspect --format='{{range .NetworkSettings.Networks}}{{.Gateway}}{{end}}' test
172.17.0.1
$

11. Para listar las imágenes que hemos utilizado, ejecutamos

user@computer:$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/ubuntu latest ccc7a11d65b1 43 hours ago 120 MB
docker.io/nginx latest b8efb18f159b 2 weeks ago 107 MB
$

Creación de imágenes

12. La primer opción, aunque no la mejor nos comentaron, es utilizar una imagen básica de algún Sistema Operativo y adecuarla a nuestras necesidades. Por ejemplo, si queremos una imagen de vim, primeramente ejecutamos de forma interactiva una imagen base, para nuestro caso, de fedora e instalamos el paquete de forma tradicional

user@computer:$ sudo docker run -it fedora bash
[root@057ce3fd873e /]# dnf install vim
Fedora 25 - x86_64 2.7 MB/s | 50 MB 00:18
Fedora 25 - x86_64 - Updates 3.8 MB/s | 25 MB 00:06
Last metadata expiration check: 0:00:06 ago on Sat Aug 12 15:51:37 2017.
Dependencies resolved.
=======================================================================================
Package Arch Version Repository Size
=======================================================================================
Installing:
gpm-libs x86_64 1.20.7-9.fc24 fedora 36 k
perl-Carp noarch 1.40-365.fc25 fedora 29 k
perl-Exporter noarch 5.72-366.fc25 fedora 33 k
perl-libs x86_64 4:5.24.2-387.fc25 updates 1.5 M
vim-common x86_64 2:8.0.823-1.fc25 updates 6.7 M
vim-enhanced x86_64 2:8.0.823-1.fc25 updates 1.3 M
vim-filesystem x86_64 2:8.0.823-1.fc25 updates 35 k
which x86_64 2.21-1.fc25 fedora 46 k

Transaction Summary
=======================================================================================
Install 8 Packages

Total download size: 9.6 M
Installed size: 37 M
Is this ok [y/N]: y
Downloading Packages:
(1/8): which-2.21-1.fc25.x86_64.rpm 71 kB/s | 46 kB 00:00
(2/8): gpm-libs-1.20.7-9.fc24.x86_64.rpm 56 kB/s | 36 kB 00:00
(3/8): perl-libs-5.24.2-387.fc25.x86_64.rpm 1.0 MB/s | 1.5 MB 00:01
(4/8): perl-Carp-1.40-365.fc25.noarch.rpm 213 kB/s | 29 kB 00:00
(5/8): perl-Exporter-5.72-366.fc25.noarch.rpm 244 kB/s | 33 kB 00:00
(6/8): vim-enhanced-8.0.823-1.fc25.x86_64.rpm 524 kB/s | 1.3 MB 00:02
(7/8): vim-filesystem-8.0.823-1.fc25.x86_64.rpm 249 kB/s | 35 kB 00:00
(8/8): vim-common-8.0.823-1.fc25.x86_64.rpm 1.3 MB/s | 6.7 MB 00:05
---------------------------------------------------------------------------------------
Total 1.3 MB/s | 9.6 MB 00:07
warning: /var/cache/dnf/updates-87ad44ec2dc11249/packages/vim-enhanced-8.0.823-1.fc25.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID fdb19c98: NOKEY
Importing GPG key 0xFDB19C98:
Userid : "Fedora 25 Primary (25) <fedora-25-primary@fedoraproject.org>"
Fingerprint: C437 DCCD 558A 66A3 7D6F 4372 4089 D8F2 FDB1 9C98
From : /etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-25-x86_64
Is this ok [y/N]: y
Key imported successfully
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Installing : perl-Carp-1.40-365.fc25.noarch 1/8
Installing : perl-Exporter-5.72-366.fc25.noarch 2/8
Installing : perl-libs-4:5.24.2-387.fc25.x86_64 3/8
Installing : vim-filesystem-2:8.0.823-1.fc25.x86_64 4/8
Installing : vim-common-2:8.0.823-1.fc25.x86_64 5/8
Installing : which-2.21-1.fc25.x86_64 6/8
Installing : gpm-libs-1.20.7-9.fc24.x86_64 7/8
Installing : vim-enhanced-2:8.0.823-1.fc25.x86_64 8/8
Verifying : vim-enhanced-2:8.0.823-1.fc25.x86_64 1/8
Verifying : gpm-libs-1.20.7-9.fc24.x86_64 2/8
Verifying : which-2.21-1.fc25.x86_64 3/8
Verifying : vim-common-2:8.0.823-1.fc25.x86_64 4/8
Verifying : perl-libs-4:5.24.2-387.fc25.x86_64 5/8
Verifying : perl-Carp-1.40-365.fc25.noarch 6/8
Verifying : perl-Exporter-5.72-366.fc25.noarch 7/8
Verifying : vim-filesystem-2:8.0.823-1.fc25.x86_64 8/8

Installed:
gpm-libs.x86_64 1.20.7-9.fc24 perl-Carp.noarch 1.40-365.fc25
perl-Exporter.noarch 5.72-366.fc25 perl-libs.x86_64 4:5.24.2-387.fc25
vim-common.x86_64 2:8.0.823-1.fc25 vim-enhanced.x86_64 2:8.0.823-1.fc25
vim-filesystem.x86_64 2:8.0.823-1.fc25 which.x86_64 2.21-1.fc25

Complete!
[root@057ce3fd873e /]# exit
exit
$

Identificamos el nombre del contenedor, con ayuda de la terminal alterna

user@computer:$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
057ce3fd873e fedora "bash" 2 minutes ago Exited (0) About a minute ago infallible_fermat
a13f3e75ea52 nginx "nginx -g 'daemon ..." 16 minutes ago Up 16 minutes 0.0.0.0:80->80/tcp test
$

Y hacemos commit al cambio en la imagen, identificándola con un mensaje descriptivo y un nuevo nombre

user@computer:$ sudo docker commit -m "testvim" infallible_fermat imagenvim
sha256:663643920fdd5323b62b0e088a3233a4c95affd91b98b23e5ec25e8cddfd12c3
$

Al revisar las imágenes observamos

user@computer:$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
imagenvim latest 663643920fdd 12 seconds ago 452 MB
docker.io/ubuntu latest ccc7a11d65b1 43 hours ago 120 MB
docker.io/nginx latest b8efb18f159b 2 weeks ago 107 MB
registry.fedoraproject.org/fedora latest 7f17e6b4a386 6 weeks ago 232 MB
$

Existe una importante diferencia en el tamaño de la imagen base contra la imagen que creamos, esto depende de los paquetes que instalamos.

Al ejecutar vim dentro del contenedor, funciona correctamente

user@computer:$ sudo docker run -it imagenvim
[root@c4e11a2ac378 /]# vim

~
~
~
~
~ VIM - Vi IMproved
~
~ version 8.0.885
~ by Bram Moolenaar et al.
~ Modified by <bugzilla@redhat.com>
~ Vim is open source and freely distributable
~
~ Become a registered Vim user!
~ type :help register<Enter> for information
~
~ type :q<Enter> to exit
~ type :help<Enter> or <F1> for on-line help
~ type :help version8<Enter> for version info
~
~

:q!

[root@c4e11a2ac378 /]# exit
exit
$

Podemos revisar la diferencia de imágenes usando el id del contenedor:

user@computer:$ sudo docker ps -a
[sudo] password for alex.callejas:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c4e11a2ac378 imagenvim "bash" 41 minutes ago Exited (0) 40 minutes ago clever_meitner
057ce3fd873e fedora "bash" 44 minutes ago Exited (0) 42 minutes ago infallible_fermat
$
$ sudo docker diff c4e11a2ac378
C /root
C /root/.bash_history
A /root/.viminfo
$ sudo docker diff 057ce3fd873e
C /etc
C /etc/ld.so.cache
C /etc/pki/nssdb
C /etc/pki/nssdb/cert9.db
C /etc/pki/nssdb/key4.db
C /etc/profile.d
A /etc/profile.d/vim.csh
A /etc/profile.d/vim.sh
A /etc/profile.d/which2.csh
A /etc/profile.d/which2.sh
A /etc/vimrc
C /root
A /root/.bash_history
D /root/.pki
...

Salida completa de la diferencia: diff_imagenvim.txt

13. La otra forma de crear una imagen, es generando un archivo Dockerfile con las instrucciones de personalización del contenedor. Utilizando el mismo ejemplo, creamos el archivo Dockerfile (por convención, así debe llamarse) con la información necesaria

user@computer:$ vim Dockerfile
FROM fedora
RUN dnf update -y && dnf install -y vim
$

Y ejecutamos la construcción de la imagen

user@computer:$ sudo docker build -t imagenvim:2 .
Sending build context to Docker daemon 2.048 kB
Step 1/2 : FROM fedora
---> 7f17e6b4a386
Step 2/2 : RUN dnf update -y && dnf install -y vim
---> Running in 8b8e9e66ca8a
Last metadata expiration check: 0:00:18 ago on Sat Aug 12 16:01:33 2017.
Dependencies resolved.
================================================================================
Package Arch Version Repository Size
================================================================================
Upgrading:
curl x86_64 7.51.0-8.fc25 updates 307 k
dbus x86_64 1:1.11.16-1.fc25 updates 255 k
dbus-libs x86_64 1:1.11.16-1.fc25 updates 175 k
emacs-filesystem noarch 1:25.2-3.fc25 updates 66 k
expat x86_64 2.2.3-1.fc25 updates 86 k
file-libs x86_64 5.29-7.fc25 updates 497 k
glibc x86_64 2.24-9.fc25 updates 3.3 M
glibc-common x86_64 2.24-9.fc25 updates 879 k
glibc-langpack-en x86_64 2.24-9.fc25 updates 282 k
gnutls x86_64 3.5.14-1.fc25 updates 754 k
krb5-libs x86_64 1.14.4-8.fc25 updates 741 k
libcrypt-nss x86_64 2.24-9.fc25 updates 44 k
libcurl x86_64 7.51.0-8.fc25 updates 267 k
libdb x86_64 5.3.28-24.fc25 updates 750 k
libdb-utils x86_64 5.3.28-24.fc25 updates 139 k
libgcc x86_64 6.4.1-1.fc25 updates 95 k
libgcrypt x86_64 1.7.8-1.fc25 updates 435 k
libidn2 x86_64 2.0.3-1.fc25 updates 97 k
libsolv x86_64 0.6.28-5.fc25 updates 366 k
libsss_idmap x86_64 1.15.3-1.fc25 updates 83 k
libsss_nss_idmap x86_64 1.15.3-1.fc25 updates 81 k
nspr x86_64 4.15.0-1.fc25 updates 137 k
nss x86_64 3.31.0-1.1.fc25 updates 862 k
nss-softokn x86_64 3.31.0-1.0.fc25 updates 385 k
nss-softokn-freebl x86_64 3.31.0-1.0.fc25 updates 224 k
nss-sysinit x86_64 3.31.0-1.1.fc25 updates 61 k
nss-tools x86_64 3.31.0-1.1.fc25 updates 504 k
nss-util x86_64 3.31.0-1.0.fc25 updates 87 k
openldap x86_64 2.4.44-11.fc25 updates 352 k
pcre x86_64 8.41-1.fc25 updates 199 k
sqlite-libs x86_64 3.14.2-2.fc25 updates 454 k
sssd-client x86_64 1.15.3-1.fc25 updates 134 k
systemd x86_64 231-17.fc25 updates 2.8 M
systemd-libs x86_64 231-17.fc25 updates 421 k
systemd-pam x86_64 231-17.fc25 updates 178 k
tar x86_64 2:1.29-4.fc25 updates 814 k
vim-minimal x86_64 2:8.0.823-1.fc25 updates 525 k

Transaction Summary
================================================================================
Upgrade 37 Packages

Total download size: 18 M
Downloading Packages:
/usr/share/doc/file-libs/ChangeLog: No such file or directory
cannot reconstruct rpm from disk files
...

Verifying : vim-filesystem-2:8.0.823-1.fc25.x86_64 8/8

Installed:
gpm-libs.x86_64 1.20.7-9.fc24 perl-Carp.noarch 1.40-365.fc25
perl-Exporter.noarch 5.72-366.fc25 perl-libs.x86_64 4:5.24.2-387.fc25
vim-common.x86_64 2:8.0.823-1.fc25 vim-enhanced.x86_64 2:8.0.823-1.fc25
vim-filesystem.x86_64 2:8.0.823-1.fc25 which.x86_64 2.21-1.fc25

Complete!
---> 6306acd85190
Removing intermediate container 8b8e9e66ca8a
Successfully built 6306acd85190
$

Salida completa de la construcción de la imagen: build_imagenvim2.txt

Al ejecutar vim dentro del contenedor, funciona correctamente

user@computer:$ sudo docker run -it imagenvim:2
[root@aa039e84b63b /]# vim
~
~
~
~
~ VIM - Vi IMproved
~
~ version 8.0.885
~ by Bram Moolenaar et al.
~ Modified by <bugzilla@redhat.com>
~ Vim is open source and freely distributable
~
~ Become a registered Vim user!
~ type :help register<Enter> for information
~
~ type :q<Enter> to exit
~ type :help<Enter> or <F1> for on-line help
~ type :help version8<Enter> for version info
~
~

:q!

[root@aa039e84b63b /]#
[root@aa039e84b63b /]# uname -a
Linux aa039e84b63b 4.11.11-300.fc26.x86_64 #1 SMP Mon Jul 17 16:32:11 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
[root@aa039e84b63b /]# exit
exit
$

Al listar las imágenes, observamos

user@computer:$ sudo docker images
[sudo] password for alex.callejas:
REPOSITORY TAG IMAGE ID CREATED SIZE
imagenvim 2 6306acd85190 26 minutes ago 519 MB
imagenvim latest 663643920fdd 35 minutes ago 452 MB
docker.io/ubuntu latest ccc7a11d65b1 44 hours ago 120 MB
docker.io/nginx latest b8efb18f159b 2 weeks ago 107 MB
registry.fedoraproject.org/fedora latest 7f17e6b4a386 6 weeks ago 232 MB
$

A esta nueva imagen, le podemos asignar una etiqueta diferente para poder diferenciarla

user@computer:$ sudo docker tag imagenvim:2 axl/imagenvim2
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
axl/imagenvim2 latest 6306acd85190 28 minutes ago 519 MB
imagenvim 2 6306acd85190 28 minutes ago 519 MB
imagenvim latest 663643920fdd 37 minutes ago 452 MB
docker.io/ubuntu latest ccc7a11d65b1 44 hours ago 120 MB
docker.io/nginx latest b8efb18f159b 2 weeks ago 107 MB
registry.fedoraproject.org/fedora latest 7f17e6b4a386 6 weeks ago 232 MB
$

Podemos, además, guardar esta imagen como archivo

user@computer:$ sudo docker save -o imagenvim2 axl/imagenvim2
$ ls
Dockerfile imagenvim2
$ sudo file imagenvim2
imagenvim: POSIX tar archive
$ du -sh imagenvim2
509M imagenvim2
$

Con lo cual, podríamos portar la imagen a algún lugar, incluso por USB y exportarla. Para este ejemplo, primero eliminamos la imagen

user@computer:$ sudo docker rmi axl/imagenvim2
Untagged: axl/imagenvim2:latest
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
imagenvim 2 6306acd85190 2 days ago 519 MB
imagenvim latest 663643920fdd 2 days ago 452 MB
docker.io/ubuntu latest ccc7a11d65b1 4 days ago 120 MB
docker.io/nginx latest b8efb18f159b 2 weeks ago 107 MB
registry.fedoraproject.org/fedora latest 7f17e6b4a386 6 weeks ago 232 MB
$

Para cargar esta imagen en algún otro equipo, después de transferir dicha imagen, utilizamos el comando

user@computer:$ sudo docker load -i imagenvim2
Loaded image: axl/imagenvim2:latest
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
cosasaxl latest 2b76fbb9ebba 2 days ago 147 MB
axl/imagenvim2 latest 6306acd85190 2 days ago 519 MB
docker.io/ubuntu latest ccc7a11d65b1 4 days ago 120 MB
docker.io/nginx latest b8efb18f159b 2 weeks ago 107 MB
docker.io/debian latest a20fd0d59cf1 3 weeks ago 100 MB
registry.fedoraproject.org/fedora latest 7f17e6b4a386 6 weeks ago 232 MB
$

Volúmenes

La información de los contenedores es efímera, pero si requerimos que se monte algún directorio en particular o que los datos sean persistentes, utilizamos volúmenes.

14. Si requerimos que nuestro contenedor incluya algún directorio en particular, ejecutamos

user@computer:$ sudo docker run -it -v /directorio ubuntu bash
[sudo] password for alex.callejas:
root@46e6e1cc5fc1:/# ls
bin boot dev directorio etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@46e6e1cc5fc1:/# ls directorio/
root@46e6e1cc5fc1:/# touch directorio/hola
root@46e6e1cc5fc1:/# ls directorio/
hola
root@46e6e1cc5fc1:/# mkdir -p directorio/test
root@46e6e1cc5fc1:/# touch directorio/test/hola
root@46e6e1cc5fc1:/#
root@46e6e1cc5fc1:/# ls -l directorio/*
-rw-r--r--. 1 root root 0 Aug 12 02:24 directorio/hola

directorio/test:
total 0
-rw-r--r--. 1 root root 0 Aug 12 02:25 hola
root@46e6e1cc5fc1:/# exit
exit
$

En la terminal alterna, inspeccionamos el contenedor, para revisar los montajes

user@computer:$ sudo docker ps
[sudo] password for alex.callejas:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
540ee1c3cc95 ubuntu "bash" 25 seconds ago Up 24 seconds gracious_lamarr
$ sudo docker inspect --format='{{range .Mounts}}{{.Destination}}{{end}}' gracious_lamarr
/directorio
$ sudo docker inspect --format='{{range .Mounts}}{{.Source}}{{end}}' gracious_lamarr
/var/lib/docker/volumes/4f3eb21be35f9b49ecc082592a47587253785ead6937f6352e434db2b8d6a323/_data
$

Por default, docker crea un directorio en el host para poder montarlo en el contenedor. Esto lo podemos revisar,como root, directamente en el host

user@computer:$ # ls -ld /var/lib/docker/volumes/4f3eb21be35f9b49ecc082592a47587253785ead6937f6352e434db2b8d6a323/_data
drwxr-xr-x. 2 root root 4096 Aug 12 21:32 /var/lib/docker/volumes/4f3eb21be35f9b49ecc082592a47587253785ead6937f6352e434db2b8d6a323/_data
# ls /var/lib/docker/volumes/4f3eb21be35f9b49ecc082592a47587253785ead6937f6352e434db2b8d6a323/_data
hola test
# ls /var/lib/docker/volumes/4f3eb21be35f9b49ecc082592a47587253785ead6937f6352e434db2b8d6a323/_data/*
/var/lib/docker/volumes/4f3eb21be35f9b49ecc082592a47587253785ead6937f6352e434db2b8d6a323/_data/hola

/var/lib/docker/volumes/4f3eb21be35f9b49ecc082592a47587253785ead6937f6352e434db2b8d6a323/_data/test:
hola
#

15. Si queremos que el contenedor utilice algún directorio del host en particular, ejecutamos

user@computer:$ mkdir directorio
$ ls
directorio Dockerfile imagenvim2
$ sudo docker run -it -v $PWD/directorio:/directorio ubuntu bash
root@4230a22ebcd5:/# ls
bin boot dev directorio etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@4230a22ebcd5:/# ls directorio/
ls: cannot open directory 'directorio/': Permission denied
root@4230a22ebcd5:/# touch directorio/hola
touch: cannot touch 'directorio/hola': Permission denied
root@4230a22ebcd5:/#

Se montó correctamente el directorio dentro del contenedor, pero no tenemos permiso de escritura debido a que el daemon de docker lo monta como root, como se observo en la inspección anterior. Para poder escribir, necesitamos indicarle al contenedor los permisos que requerimos, ejecutando

user@computer:$ sudo docker run -it -v $PWD/test:/prueba:ro ubuntu bash
root@59c188463618:/# ls
bin boot dev etc home lib lib64 media mnt opt proc prueba root run sbin srv sys tmp usr var
root@59c188463618:/# ls prueba/
ls: cannot open directory 'prueba/': Permission denied
root@59c188463618:/# cd prueba
root@59c188463618:/prueba# ls
ls: cannot open directory '.': Permission denied
root@59c188463618:/prueba# touch hola
touch: cannot touch 'hola': Read-only file system
root@59c188463618:/prueba# exit
exit
$

En la inspección se observa

user@computer:$ sudo docker inspect --format='{{range .Mounts}}{{.Source}}{{end}}' dazzling_franklin
/home/alex.callejas/Devel/docker/test
$ sudo docker inspect --format='{{range .Mounts}}{{.Destination}}{{end}}' dazzling_franklin
/prueba
$ sudo docker inspect --format='{{range .Mounts}}{{.Mode}}{{end}}' dazzling_franklin
rw
$ sudo docker inspect --format='{{range .Mounts}}{{.RW}}{{end}}' dazzling_franklin
true
$

16. Los volúmenes los podemos crear antes de usarlos, ejecutando

user@computer:$ sudo docker volume create --name myvol
myvol
$ sudo docker volume ls
DRIVER VOLUME NAME
local 4f3eb21be35f9b49ecc082592a47587253785ead6937f6352e434db2b8d6a323
local 5e76c5028ea86b1671837372c914d1603944dbf7d4676d0ee49740920756da24
local a909d99c5b8cab582d7c7a5c8e8dc21ed75f0a0ff8df15040906ab34fc67f142
local d840fde43be8d06fa06448478755f414de20c00705d27928ac5a8e0bba140d02
local myvol
$

Para asignarlo al contenedor, ejecutamos

user@computer:$ sudo docker run -it -v myvol:/stuff ubuntu bash
root@6b2116af2431:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv stuff sys tmp usr var
root@6b2116af2431:/# cd stuff/
root@6b2116af2431:/stuff# touch test{1..7}
root@6b2116af2431:/stuff# ls
test1 test2 test3 test4 test5 test6 test7
root@6b2116af2431:/stuff#

En la inspección observamos donde se creo el volumen y los archivos creados

user@computer:$ sudo docker inspect distracted_franklin | grep Mounts -A 11
"Mounts": [
{
"Type": "volume",
"Name": "myvol",
"Source": "/var/lib/docker/volumes/myvol/_data",
"Destination": "/stuff",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
],
$
# ls /var/lib/docker/volumes/myvol/_data
test1 test2 test3 test4 test5 test6 test7
#

17. Para eliminar el volumen, después de eliminar el contenedor, ejecutamos

user@computer:$ sudo docker volume rm myvol
myvol
$ sudo docker volume ls
DRIVER VOLUME NAME
local 4f3eb21be35f9b49ecc082592a47587253785ead6937f6352e434db2b8d6a323
local 5e76c5028ea86b1671837372c914d1603944dbf7d4676d0ee49740920756da24
local a909d99c5b8cab582d7c7a5c8e8dc21ed75f0a0ff8df15040906ab34fc67f142
local d840fde43be8d06fa06448478755f414de20c00705d27928ac5a8e0bba140d02
$

18. Si se requiere copiar archivos del host al contenedor, la mejor práctica es realizarlo desde su creación mediante Dockerfile, suponiendo que en el host tenemos un directorio archivos que deseamos tener en el contenedor dentro del directorio stuff, ejecutamos

user@computer:$ ls archivos/
notas1.txt notas2.txt
$ cat Dockerfile
FROM debian
RUN apt-get update && apt-get install vim -qqy
COPY ./archivos/ /stuff
$ sudo docker build -t cosasaxl .
[sudo] password for alex.callejas:
Sending build context to Docker daemon 556 kB
Step 1/3 : FROM debian
---> a20fd0d59cf1
Step 2/3 : RUN apt-get update && apt-get install vim -qqy
---> Running in d095c62569fa
Ign:1 http://deb.debian.org/debian stretch InRelease
Get:2 http://deb.debian.org/debian stretch-updates InRelease [88.5 kB]
Get:3 http://security.debian.org stretch/updates InRelease [62.9 kB]
Get:4 http://deb.debian.org/debian stretch Release [118 kB]
Get:5 http://deb.debian.org/debian stretch Release.gpg [2373 B]
Get:6 http://security.debian.org stretch/updates/main amd64 Packages [169 kB]
Get:7 http://deb.debian.org/debian stretch/main amd64 Packages [9497 kB]
Fetched 9938 kB in 5s (1799 kB/s)
Reading package lists...
debconf: delaying package configuration, since apt-utils is not installed
...
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/editor (editor) in auto mode
---> 56193462f153
Removing intermediate container d095c62569fa
Step 3/3 : COPY ./archivos/ /stuff
---> 83e969244bce
Removing intermediate container 0a687e1b1998
Successfully built 83e969244bce
$ sudo docker run -it cosasaxl bash
root@7f3d34dfa53a:/# ls
bin   dev  home  lib32 libx32 mnt  proc  run srv sys  usr
boot  etc  lib lib64 media opt  root  sbin  stuff tmp  var
root@7f3d34dfa53a:/# ls stuff/
notas1.txt notas2.txt
root@7f3d34dfa53a:/# exit
exit
$

19. Suponiendo que necesitamos que el contenedor ejecute un script al arrancarlo, lo construimos con la opción ENTRYPOINT 

user@computer:$ cat entrypoint.sh
#!/bin/bash
ls -la
echo "Hola desde entrypoint"
$ cat Dockerfile
FROM debian
RUN apt-get update && apt-get install vim -qqy
COPY ./archivos/ /stuff
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT /entrypoint.sh
$ ls
archivos Dockerfile entrypoint.sh
$ sudo docker build -t cosasaxl .
[sudo] password for alex.callejas:
Sending build context to Docker daemon 557.1 kB
Step 1/5 : FROM debian
---> a20fd0d59cf1
Step 2/5 : RUN apt-get update && apt-get install vim -qqy
---> Using cache
---> 56193462f153
Step 3/5 : COPY ./archivos/ /stuff
---> Using cache
---> 83e969244bce
Step 4/5 : COPY entrypoint.sh /entrypoint.sh
---> e403afe2511c
Removing intermediate container b0c28c21c8ff
Step 5/5 : ENTRYPOINT /entrypoint.sh
---> Running in 4ad3f139001d
---> 2b76fbb9ebba
Removing intermediate container 4ad3f139001d
Successfully built 2b76fbb9ebba
$ sudo docker run -it cosasaxl bash
total 68
drwxr-xr-x. 1 root root 4096 Aug 12 17:18 .
drwxr-xr-x. 1 root root 4096 Aug 12 17:18 ..
-rwxr-xr-x. 1 root root 0 Aug 12 17:18 .dockerenv
lrwxrwxrwx. 1 root root 7 Jul 23 00:00 bin -> usr/bin
drwxr-xr-x. 2 root root 4096 Jul 13 13:04 boot
drwxr-xr-x. 5 root root 360 Aug 12 17:18 dev
-rwxrwxr-x. 1 root root 49 Aug 12 17:14 entrypoint.sh
drwxr-xr-x. 1 root root 4096 Aug 12 17:18 etc
drwxr-xr-x. 2 root root 4096 Jul 13 13:04 home
lrwxrwxrwx. 1 root root 7 Jul 23 00:00 lib -> usr/lib
lrwxrwxrwx. 1 root root 9 Jul 23 00:00 lib32 -> usr/lib32
lrwxrwxrwx. 1 root root 9 Jul 23 00:00 lib64 -> usr/lib64
lrwxrwxrwx. 1 root root 10 Jul 23 00:00 libx32 -> usr/libx32
drwxr-xr-x. 2 root root 4096 Jul 23 00:00 media
drwxr-xr-x. 2 root root 4096 Jul 23 00:00 mnt
drwxr-xr-x. 2 root root 4096 Jul 23 00:00 opt
dr-xr-xr-x. 337 root root 0 Aug 12 17:18 proc
drwx------. 2 root root 4096 Jul 23 00:00 root
drwxr-xr-x. 4 root root 4096 Jul 23 00:00 run
lrwxrwxrwx. 1 root root 8 Jul 23 00:00 sbin -> usr/sbin
drwxr-xr-x. 2 root root 4096 Jul 23 00:00 srv
drwxr-xr-x. 2 root root 4096 Aug 12 17:09 stuff
dr-xr-xr-x. 13 root root 0 Aug 12 14:27 sys
drwxrwxrwt. 1 root root 4096 Aug 12 17:09 tmp
drwxr-xr-x. 1 root root 4096 Jul 23 00:00 usr
drwxr-xr-x. 1 root root 4096 Jul 23 00:00 var
Hola desde entrypoint
$

En un siguiente post, cuando nos den la segunda parte del curso: Intermedio, les compartiré de igual forma mis notas.

P.D.: Hace ya algún tiempo, aquí en el blog, había publicado una muy buena introducción a docker [ver] 😉

Espero les sirva…

by Alex Callejas at August 16, 2017 04:41 PM

August 11, 2017

Poesía Binaria

Programando ATtinys para miniaturizar nuestros proyectos electrónicos

Programar ATTinys
Un Arduino, ¡es muy grande! Es una placa que luego no sabes dónde meter, un circuito integrado que ocupa mucho y en algunas ocasiones no usamos la miad de las entradas y salidas. Así que, para pequeños montajes que requieran algo de lógica de programación o comunicación que debamos meter en una pequeña placa sin complicarnos mucho la vida, y hemos trabajado antes con la plataforma Arduino. Un buen siguiente paso es comprar un pequeño ATtiny, un circuito integrado que cuesta alrededor de 2€. Ya que tiramos de ATtiny, vamos a dedicarnos al ATtiny84 y ATtiny85 que son los más grandes de la gama.

ATtiny85


Este circuito cuenta con:

  • 8 patillas
  • Funciona desde 1.8V a 5V
  • 300uA a 1MHz y 1.8V
  • Frecuencia de operación de 20MHz como máximo si utilizamos un oscilador externo. Aunque puede funcionar entre 1MHz y 8MHz con el propio oscilador interno. Ideal para operaciones de bajo consumo.
  • 8KB de memoria Flash para nuestros programas.
  • 512bytes de EEPROM para almacenar constantes o valores de forma permanente. EEPROM es una memoria de escritura limitada, así que no es conveniente para almacenar datos que vayan cambiando mucho.
  • 0.5Kb de SRAM. Como memoria temporal para nuestros programas.
  • 6 canales GPIO, para interactuar con el exterior.
  • 4 de ellos soportan entrada analógica a través de un conversor analógico-digital de 10bit.
  • 5 de ellos soportan PWM

Y muchas más cosas que iremos descubriendo y experimentando.

ATtiny84


Este circuito cuenta con:

  • 14 patillas
  • Funciona desde 1.8V a 5V
  • 300uA a 1MHz y 1.8V
  • Frecuencia de operación de 20MHz como máximo si utilizamos un oscilador externo. Aunque puede funcionar entre 1MHz y 8MHz con el propio oscilador interno. Ideal para operaciones de bajo consumo.
  • 8KB de memoria Flash para nuestros programas.
  • 512bytes de EEPROM para almacenar constantes o valores de forma permanente. EEPROM es una memoria de escritura limitada, así que no es conveniente para almacenar datos que vayan cambiando mucho.
  • 0.5Kb de SRAM. Como memoria temporal para nuestros programas.
  • 12 canales GPIO, para interactuar con el exterior.
  • 8 de ellos soportan entrada analógica a través de un conversor analógico-digital de 10bit.
  • 4 de ellos soportan PWM

Configurando el entorno Arduino

El método más sencillo para hacer la programación es con el entorno Arduino, que a estas alturas de 2017 va por la versión 1.8.3 y tiene muchas cosas más que cuando empecé. Así que vamos a configurar nuestro entorno para que soporte los chips ATtiny. Para ello vamos a Archivo / Preferencias y en la línea Gestor de URLs adicionales de tarjetas pegamos la siguiente dirección: https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json:

Ahora bien. Para relizar la programación del circuito integrado, voy a utilizar mi propia placa Arduino. Por lo tanto voy a instalar un programador en mi Arduino que se encargará de escribir la memoria del ATtiny. Para ello, seleccionamos nuestro Arduino, el puerto donde está conectado y seleccionamos Archivo / Ejemplos / ArduinoISP. Una vez abierto el programa lo subimos a nuestra placa Arduino.

Seguidamente vamos a Herramientas / Placa / Gestor de tarjetas, nos aparecerá una ventana como la siguiente, donde podemos escribir attiny en la barra de búsqueda. Nos aparecerá la configuración para incluir estos circuitos integrados a nuestro entorno Arduino. Así que seleccionamos la última versión y pulsamos Instalar:

Ahora podremos seleccionar nuestro ATtiny en Herramientas / Placa / ATtiny. Para este ejemplo vamos a programar un ATtiny85, aunque colocando los cables correctamente podremos programar también los ATtiny84 o incluso los Atmega.

Ahora seleccionamos el resto de opciones dentro de herramientas:

  • Procesador. Donde especificamos el chip que vamos a programar.
  • Clock. Donde decimos la velocidad de reloj. Estos ATtiny tienen un reloj interno que puede ir hasta los 8MHz, aunque parece que con algunos modelos puede llegar hasta 16MHz, aunque a mayor frecuencia, mayor consumo eléctrico. Además, estos chips soportan una fuente de reloj externa hasta 20MHz.
  • Puerto. Mi USB está en /dev/ttyUSBx (con la placa Duemilanove) o en /dev/ttyACMx (con Arduino Uno), usando GNU/Linux. O tal vez en otros sistemas COM3/COM4… ya depende de cómo esté enchufado el dispositivo.
  • Programador: Arduiono as ISP. Le estamos diciendo que el propio Arduino va a actuar como programador del chip.

Montando el circuito para programar nuestro ATtiny

Debemos montar algo así:

En este circuito conectamos los pins:

Arduino PIN 10 –> ATTiny Reset PIN
Arduino PIN 11 –> ATTiny PIN 0
Arduino PIN 12 –> ATTiny PIN 1
Arduino PIN 13 –> ATTiny PIN 2
Arduino GND PIN –> ATTiny PIN GND PIN
Arduino +5V PIN –> ATTiny PIN VCC PIN


Los diodos led, los he conectado como indicación (no es necesario tenerlos, y me podéis matar por no colocar resistencias, pero están muy chulos):

  • PIN 9 – Es el heartbeat. Indica que nuestra placa Arduino como programador funciona y está lista
  • PIN 8 – Error.
  • PIN 7 – El programador se está comunicando con el ATtiny

NOTA: En las placas Leonardo, Yun y seguro que algunas otras utilizan el puerto ICSP para realizar la programación del chip. Como se indica a continuación (aunque no lo he probado. Si alguien se atreve que me deje un comentario):

Arduino PIN 10 –> ATTiny Reset PIN
Arduino ICSP MOSI PIN –> ATTiny PIN 0
Arduino ICSP MISO PIN –> ATTiny PIN 1
Arduino ICSP SCK PIN –> ATTiny PIN 2
Arduino GND PIN –> ATTiny PIN GND PIN
Arduino +5V PIN –> ATTiny PIN VCC PIN

El condensador entre RESET y GND evita que Arduino se reinicie actuando como ISP. De todas formas muchas veces no es necesario poner el condensador. Depende de la placa que estemos usando. Si no tenéis ninguno a mano, intentadlo sin él.

Programando el chip

Lo primero será cargar un programa, como por ejemplo el Blinking Led, ese ejemplo típico, aunque por defecto el led suele estar conectado al Pin13, y en Attiny no tenemos tantos, así que podemos conectarlo al 0 o al 1 para hacer la prueba. O si no, podemos utilizar mi versión modificada que utiliza la salida analógica, ya que el Pin 0 del Attiny85 soporta PWM, vamos a hacer algo con él:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#define MY_PIN 0
#define ESPERA 40
#define INCREMENTO 20

int level = 0;
int direction= INCREMENTO;

void setup() {
  pinMode(MY_PIN, OUTPUT);
}

void loop() {
  level+=direction;
 
  if (level > 255 || level < 0)
  {
    direction*=-1;
    level+=direction;
  }
  analogWrite(MY_PIN, level);  
  delay(ESPERA);
}

Programando ATtiny84

Para programar este circuito, tendremos que conectar nuestra placa Arduino al chip. Para ello, debemos conectar VCC, GND y reset a los sitios correspondientes, y luego los pins MOSI, MISO y SCK. De la siguiente forma:

Arduino PIN 10 –> ATTiny Reset PIN
Arduino PIN 11 –> ATTiny PIN 7
Arduino PIN 12 –> ATTiny PIN 8
Arduino PIN 13 –> ATTiny PIN 9
Arduino GND PIN –> ATTiny PIN GND PIN
Arduino +5V PIN –> ATTiny PIN VCC PIN

Ahora, con nuestro ATtiny conectado, le damos a Subir y listo! Se compilará y se subirá a nuestra placa.

Foto principal: Uwe Herman (Flickr CC)

The post Programando ATtinys para miniaturizar nuestros proyectos electrónicos appeared first on Poesía Binaria.

by Gaspar Fernández at August 11, 2017 08:16 AM

August 09, 2017

blog de Rodolfo Pilas

Carguemos las pilas

Creo que he llegado a una nueva marca sin publicaciones en el blog desde abril pasado.

Una de las razónes es Deployando.Me el podcast de tecnología para sysadmin y devops que trato de mantener en forma períodica ¿ya lo escucharon?

Otra de las razones son nuevos proyectos laborales, viajes al exterior para distintas tareas profesionales y un montón de etcéteras que puedo encontrar, pues razones hay muchas pero…

el que no publica soy yo, y no es porque falte material o falte qué compartir.

Entonces, va este artículo como auto-compromiso de seguir publicando.

by pilasguru at August 09, 2017 01:42 PM

www.rootzilopochtli.com

Nuevo logo del blog!

… En ese momento nació Huitzilopochtli, se vistió sus atavíos, su escudo de plumas de águila, sus dardos, su lanza-dardos azul el llamado lanza-dardos de turquesa. Se pintó su rostro con franjas diagonales, con el color llamado “pintura de niño”. Sobre su cabeza colocó plumas finas, se puso sus orejeras.

Y uno de sus pies, el izquierdo era enjuto, llevaba una sandalia cubierta de plumas, y sus dos piernas y sus dos brazos los llevaba pintados de azul. Y el llamado Tochancalqui puso fuego a la serpiente hecha de teas llamada Xiuhcóatl, que obedecía a Huitzilopochtli. Luego con ella hirió a Coyolxauhqui, le cortó la cabeza, la cual vino a quedar abandonada en la ladera de Coatépetl….

Relato del nacimiento de Huitzilopochtli – Códex Florentinus


Desde hace mucho tiempo, quería refrescar la imagen del blog, al principio utilizaba como logo la moneda azteca de Piratas del Caribe, porque en ese momento no encontré una imagen que representará lo que quería hacer con el blog, el rumbo que quería que tomara. Además que en ese tiempo fue la única imagen que sentía que unía mi pasión por el software libre con la mitología mexica.

El nombre rootzilopochtli surge en una plática en un war room, cuyo cliente no quiero recordar 🙂 , donde los diferentes administradores (bases de datos, redes, storage, backups) debatían sobre quién de ellos era el más importante, en cierto momento de la plática, cuando entendí de lo que hablaban, sugirieron cierto sacrificio del usuario en cuestión, a lo que les comenté:

– Si van a ofrecer al usuario en sacrificio, deberían hacerlo hacía Huitzilopochtli, el dios supremo de Tenochtitlan, patrono de la guerra, el fuego y el sol. Guía, protector y patrono de los aztecas

A partir de ese día, el SysAdmin es conocido como rootzilopochtli, guardián de la palabra, señor y dador de vida a las aplicaciones, quien rige el uso correcto del sistema 😉

Después de mucho tiempo, de tratar de hacer un diseño propio con este concepto, desistí y encontré a la mejor diseñadora de elementos prehispánicos que existe en la actualidad, conocida en twitter como @monarobot. Ella es una artista conocida en el medio por el diseño de los Pokemayans, la versión maya de los Pokémon, esta es una muestra de su increíble trabajo:

Para el icono/logo, lo que le pedí fue tener su versión de Xiuhcóatl, el arma más poderosa de los dioses mexicas empuñada por el dios de la guerra Huitzilopochtli con la cual mató a 400 de sus hermanos con suma facilidad. Mítica serpiente de fuego, serpiente brillante, serpiente solar:

Y con su único estilo creo el diseño que engalana e identifica desde hoy al blog:

 

Espero les guste…

 

by Alex Callejas at August 09, 2017 01:15 AM

August 08, 2017

Poesía Binaria

Píldora: Modificar a mano la velocidad de los ventiladores de nuestro ordenador

Velocidad de los ventiladores

Normalmente el control de los ventiladores que hace automáticamente el sistema está bien. Cuando la CPU se calienta mucho los ventiladores aumentan su velocidad y ésta disminuye cuando se enfrían. El objetivo es mantener el procesador a una temperatura estable y que no se rompan los componentes. Porque seguro que más de uno nos hemos cargado algún aparato cuando se ha sobrecalentado.

El caso es que no siempre está bien el control automático. Bien porque alguna vez se le puede ir la olla, por tema de drivers en ocasiones un ventilador se vuelve loco; puede haberse roto el sensor de temperatura, porque todo se puede romper, y nosotros nos resistimos a cambiar el equipo; estamos experimentando rompiendo cosas, queremos ponerlo a tope un rato para aumentar el rendimiento general a pesar de que haya mayor consumo energético, o puede que lo principal sea dejarnos dormir y no nos importa que se caliente la CPU un poco.

He de decir, que los ventiladores que podemos controlar son los que están conectados a un dispositivo capaz de gestionar una señal PWM. Sí, como la de Arduino, es la misma tecnología, enviamos pulsos a un ventilador para que varíe su velocidad. Y podemos encontrar varios puertos PWM para ventiladores en nuestras placas base, aunque en los portátiles normalmente tenemos sólo uno; en los ordenadores de sobremesa podemos encontrar más ventiladores y ahí está mucho más chulo hacerlo.

Ya lo tenemos hecho!!

Existe un software llamado fancontrol que lo hace por nosotros. Le decimos temperaturas y velocidades de ventilador y automáticamente cada cierto tiempo hará un sondeo en los sensores de temperatura y actuará en consecuencia.

Pero, ¿cómo se hace a mano?

Pero, ¿y si queremos cambiar la velocidad del ventilador a mano? Por ejemplo, para hacer algo rápido, porque no siempre podemos o queremos instalar un paquete en un equipo. Y, como la magia de GNU/Linux está en que casi casi todo son ficheros nos aprovecharemos de eso.

Antes de nada, debemos saber que todo esto depende mucho del driver que utilice nuestro sistema para gestionar esta capacidad. Es decir, el circuito que controla la velocidad de los ventiladores necesita un módulo específico en el kernel y puede que éste cambie un poco la forma de acceso, suele ser parecida, pero a lo mejor cambian un poco los nombres. También puede que no tengamos dicho soporte en nuestro kernel, o que nuestra placa base sea incapaz de hacerlo… todo puede pasar, pero para eso estamos, para investigar 🙂

Buscar ficheros importantes

Me voy a basar en la forma de encontrar la temperatura actual (los sensores) y modificar la velocidad de los ventiladores. Así que vamos a ello. En los kernels más antiguos podíamos encontrar todo esto dentro de /proc/acpi/ aunque en los núcleos más modernos lo encontramos en /sys/devices/. Así que, hagamos las búsquedas, pondré los resultados que salen en mi equipo principal, no tiene por qué coincidir con el tuyo, pero sí puede ser parecido.

El primer fichero será temp1_input que nos dice la temperatura del sensor, seguramente sea el sensor de la CPU, aunque podemos tener más sensores repartidos por la placa base. (Generalmente podremos acceder desde /sys/class/hwmon/, en mi sistema tengo enlaces desde /sys/class/hwmon/hwmonX que apuntan a las rutas a continuación; pero otras veces no)

find /sys/ -name ‘temp1_input’
/sys/devices/platform/asus-nb-wmi/hwmon/hwmon2/temp1_input
/sys/devices/platform/coretemp.0/hwmon/hwmon1/temp1_input
/sys/devices/virtual/hwmon/hwmon0/temp1_input

Podemos encontrar varios ficheros parecidos, correspondientes a cada uno de los drivers y a veces puede coincidir que el mismo sensor sea leído por dos drivers distintos. Estos ficheros, al final, podemos leerlos con cat. Por ejemplo:
cat /sys/devices/platform/coretemp.0/hwmon/hwmon1/temp1_input
52000

Pues eso, 52ºC

Generalmente estos ficheros suelen tener en el mismo directorio los ficheros temp1_label, temp1_max, temp1_crit especificando, qué sensor es, su temperatura máxima y crítica respectivamente. Y todos los valores podemos verlos con cat, aunque puede que en algunos sistemas necesitemos privilegios de root.

Si queremos, también podemos mirar en el mismo directorio qué más hay, puede que encontremos más sensores, temp2_input, temp3_input, etc.

Ventiladores

Dentro de /sys/class/hwmon/hwmonX/ también puede que encontremos ficheros llamados fan1_input, fan1_label (que nos dirá qué ventilador es), pwm1 o de forma general, dependiendo de la cantidad que haya fanX_input y pwmX. De todoas formas, si queremos buscarlos, aquí os dejo el comando:

find /sys/ -name ‘pwm*’
/sys/devices/platform/asus-nb-wmi/hwmon/hwmon2/pwm1
/sys/devices/platform/asus-nb-wmi/hwmon/hwmon2/pwm1_enable
/sys/class/pwm

Qué podemos hacer

Hemos visto que podemos ver la temperatura del sensor haciendo cat al fichero. También podemos ver información de los ventiladores:

cat /sys/devices/platform/asus-nb-wmi/hwmon/hwmon2/fan1_input
1400
cat /sys/devices/platform/asus-nb-wmi/hwmon/hwmon2/fan1_label
cpu_fan

En este caso vemos la velocidad en revoluciones por minuto (rpm) del ventilador, y también a qué corresponde el ventilador, que es el ventilador de la CPU.

Ahora vemos qué hacen los ficheros PWM

cat /sys/devices/platform/asus-nb-wmi/hwmon/hwmon2/pwm1_enable
2
cat /sys/devices/platform/asus-nb-wmi/hwmon/hwmon2/pwm1
85

El primero es el modo de funcionamiento, puede ser 1 (manual) o 2 (automático). Se puede utilizar el 0 pero suele ser lo mismo que el 2. Además, no hace falta establecer este valor antes de cambiar a modo maunal. Lo veremos en un ejemplo más adelante.
El segundo es la velocidad del ventilador expresado con el valor del byte que controla el PWM. Es decir, un valor entre 0 y 255 donde 0 es el mínimo (ventilador parado, y por tanto, muy peligroso) y 255 es el máximo, por lo que nuestro ordenador puede parecer un cohete espacial. Ahora, si queremos dar una velocidad a mano al motor haremos:

echo “120” > /sys/devices/platform/asus-nb-wmi/hwmon/hwmon2/pwm1

Si somos root, pero si lo hacemos desde un usuario, podremos hacer:
echo “120” | sudo tee /sys/devices/platform/asus-nb-wmi/hwmon/hwmon2/pwm1

De esta forma se establecerán los valores de pwm1_enable a 1 (no tenemos que hacer nada para ir a modo manual) y el valor de pwm1 será de 120. Además, escucharemos el ventilador de nuestro ordenador más rápido. Eso sí, tenemos que tener cuidado cuando demos una velocidad manual, ya que el modo automático lo hemos desactivado y puede que el sistema requiera más frío del que le estamos dando y se caliente demasiado. ¡Un gran poder conlleva una gran responsabilidad!

Si queremos volver al modo de ventilador automático, basta con hacer:

echo 2 | sudo tee /sys/devices/platform/asus-nb-wmi/hwmon/hwmon2/pwm1_enable

The post Píldora: Modificar a mano la velocidad de los ventiladores de nuestro ordenador appeared first on Poesía Binaria.

by Gaspar Fernández at August 08, 2017 04:59 PM

August 05, 2017

Blog Bitix

Sustituir caldera de gas por un termo eléctrico Fleck Duo 7 50

Tener una caldera es cara, bien por el coste fijo del gas tanto por el alquiler del contador como por el precio de la disponibilidad pero también por las revisiones obligatorias que hay que hacerles por motivos de seguridad. Con motivo de que me tocaba hacer la revisión de la caldera me he decidido a hacer la sustitución por un termo eléctrico, finalmente elegí un Fleck Duo 7 de 50 litros.

Fleck

Como cada 5 años me ha tocado hacer la revisión de la instalación de gas de la casa. Además, como hacía tiempo que no la realizaba como defecto me apuntaron que debía hacer en un periodo de menos de dos meses la revisión de la caldera de gas. La revisión de la instalación de gas en la zona que vivo se debe realizar cada cinco años y la revisión de la caldera cada dos. Los costes de ambas corren a cargo del usuario, salvo que tengas contratado un servicio de mantenimiento que incluso sale más caro, siendo para la revisión de la cadera de unos 60€ y la de la revisión de la caldera de 85€. Hacía tiempo que estaba pensando en sustituir la caldera por un termo eléctrico y estas revisiones junto con sus costes han sido la oportunidad para decidirme a hacer el cambio.

Una de las primeros puntos a tener en cuenta son las diferencias entre una caldera de gas y un termo eléctrico. La más obvia es que las calderas funciona con gas y los termos eléctricos con electricidad por lo que con estos últimos no es necesario tener un contrato de suministro de gas con sus costes mínimos de disponibilidad fijos, alquiler de contador y revisiones. Las calderas requieren de revisiones y cumplir la normativa vigente en una nueva instalación, por ejemplo, requiriendo que la salida de humos se realice directamente a la calle o que la caldera sea estanca con lo que si se realiza una sustitución de caldera puede que haya que adecuar la casa a la normativa pudiendo requerir picar la fachada para la salida de humos en vez de aprovechar la propia salida de humos del edificio. La obra de albañilería y manipulación de instalación de gas debe hacerla siempre un técnico certificado con lo que hay que añadir a los costes la mano de obra de estos obreros.

Los termos no necesitan de revisiones al utilizar electricidad, no usan un elemento tan peligroso como el gas y no generar gases que son tóxicos si no se evacuan adecuadamente. Otra de las diferencias es que la caldera de gas proporciona agua caliente sanitaria en cantidad ilimitada en poco tiempo y los termos limitada dependiendo de su capacidad pero ya 50 litros son suficientes para dos duchas. Como los termos en su depósito suelen mantener el agua caliente proporcionan agua caliente de forma inmediata. Otra diferencia importante es que las calderas proporciona agua caliente para la calefacción y los termos solo para agua sanitaria como la ducha o para fregar platos, aunque la calefacción solo es necesaria en invierno y un calefactor eléctrico puede suplir la carencia. Los termos eléctricos son mucho más baratos y su instalación es mucho más sencilla, una caldera básica cuesta unos 1000€ y a partir de ahí las hay más caras incluso 2000€. Un termo de la gama alta cuesta únicamente unos 300€ y uno más barato y sencillo unos 100€.

Caldera de gas

Uno de los problemas que tenía con la cadera es que en algunos momentos se apagaba por algún motivo que desconozco con lo que durante un periodo de 10 segundos el agua sale fría con las molestias que ocasiona si te te pilla en el aclarado y en invierno. Con el termo no hay estas pérdidas de temperatura mientras tenga en el depósito suficiente agua caliente.

El sustituir la caldera de gas por un termo me evitará los costes de las revisiones de la instalación del gas y de la caldera que en unos 6 años ya habrá cubierto el coste del termo eléctrico. Además me evitará los costes fijos del gas como el alquiler del contador y la disponibilidad de unos 5€ al mes que compensarán el gasto en electricidad que necesite el termo. Otro de mis motivos de dar de baja el gas y solo necesitar electricidad es que cambiándome a una compañía que proporcione energía de fuentes 100% renovable evitaré usar gas aunque esta sea más energía barata que la electricidad y más eficiente para calentar agua el coste global incluyendo costes de aparatos, fijos y revisiones es más cara. Si la factura me sale algo más cara, que no creo por los costes fijos del gas, asumiré el coste pero tendré la satisfacción de usar sólo energía renovable.

Caldera de gas

Termo eléctrico

Ya decidido a cambiar la caldera por un termo empecé a informarme de los modelos de termos y que diferenciaba uno más caro de uno más barato. Los termos eléctricos por el hecho de almacenar agua de forma constante en un depósito sufren de corrosión por el agua y la cal que esta lleva por lo que los fabricantes para proteger a los termos proporcionan al calderín un recubrimiento especial más resistente y para evitar la corrosión incluyen un ánodo de magnesio también llamado ánodo de sacrificio para que la corrosión ataque al ánodo en vez de al calderín.

Dependiendo de la zona de residencia el agua llevará más cal o menos o será más dura o menos, en las zonas mediterráneas el agua es más dura y en la zona norte más blanda con lo que en estas últimas los termos sufrirá menos de corrosión, hay que tener en cuenta la dureza del agua donde vivimos para elegir el termo adecuado, si esta es dura daremos preferencia a termos con ánodos de magnesio grandes revisándolas anualmente y buscaremos alguno con resistencias envainadas y más protegidas de la cal. Dependiendo del modelo y precio el ánodo de magnesio será más grande, se aconseja realizar una revisión del mismo anualmente sobre todo si estamos en una zona con agua dura. Algunos termos incorporan un ánodo electrónico que no necesitan tanto mantenimiento y genera una corriente que impide o disminuye la corrosión al igual que el ánodo de magnesio.

También hay que elegir la capacidad del depósito del termo, los hay de 15 litros, de 30, de 50, de 80, de 100, de 150 y más. Para una vivienda para el uso de agua sanitaria para ducharse 30 litros son suficientes para una persona, o 50 litros para una ducha más larga o más personas. También hay que tener en cuenta las medidas para que encaje en el hueco que deja la caldera, tanto en altura, anchura y profundidad.

Mapa de dureza del agua

Fleck Duo 7 50

Pasando a elegir entre los muchos de modelos de termos que hay me fije entre tres modelos el Cointra TDG-50, el Fagor CB-50ECO y el Fleck Duo7 50. El Cointra tiene ánodos de magnesio pero son de gran tamaño y además incorpora dos. Del Fagor CB-50 ECO me gustaba que poseía las resistencias envainadas y un ánodo electrónico que induce una corriente dentro del agua para evitar la corrosión del calderín. Del Felck Duo7 50 me gustaba que poseía dos depósitos y es algo más eficiente que los otros aunque este posee las resistencias sumergidas.

Todos estos termos poseen un tamaño similar al de una caldera por lo que en cuanto a espacio no requieren tener nada en cuenta. El Fagor y Fleck tiene unas medidas diferentes en cuanto a anchura, altura y profundidad , el Fagor es más alto y con más profundidad y el Fleck es el termo con menos profundidad pero es un poco más ancho que el Fagor. El Fagor y Fleck poseen un display digital con el que seleccionar la temperatura del agua, el display del Fleck bastante más avanzado indicando el tiempo restante hasta alcanzar la temperatura deseada, una estimación del número de duchas que restantes y si hay agua caliente para una ducha. Una cosa que no muestra el display es cuando las resistencias están encendidas al mantener la temperatura a los grados deseados.

Finalmente me decidí por el termo Feck Duo7 50 es un termo de gama alta y su precio es de los más altos entre los modelos de termos con la misma capacidad pero su precio como comentaba anteriormente es muy inferior a cualquier modelo de caldera. Donde vivo el agua es de buena calidad y blanda con lo que las resistencias no lo he considerado muy importante que estuviesen envainadas. El display es bastante bueno pudiendo elegir la temperatura del agua, informa del tiempo restante hasta alcanzarla y la temperatura del agua actual. Este modelo de termo eléctrico una de las varias cosas buenas que tiene es que es muy plano tiendo únicamente 27 centímetros de fondo con lo que es posible ganar un espacio que antes estaba ocupado por la caldera como ha sido en mi caso. Se puede colocar en vertical u horizontal. Posee ánodo electrónico asi como también ánodos de magnesio, función antilegionela, antihelada, un display digital que indica el tiempo restante hasta alcanzar la temperatura programada y la temperatura actual, función de ahorro de energía según hábitos de uso y dos depósitos independientes para mayor eficiencia calificada como B. Los controles son táctiles, intuitivos y con la rueda circular se controla la temperatura.

El termo Fleck Duo 7 50 consume como máximo 1500W, yo tengo una potencia contratada de las más bajas de 2200W, quizá no pueda poner la lavadora, vitrocerámica y aspiradora simultáneamente pero organizándose un poco no hay mayor problema para que no salte la luz. Aún no lo he probado con el termo encendido y a la vez la vitrocerámica que son de los aparatos eléctricos que más consumen.

Caja Fleck Duo 7 50

En el manual de Fleck Duo 7 50 se explican mejor las funciones que posee, una de ellas es que aprende los hábitos de consumo y se adecua a ellos para ahorrar energía. También posee una configuración manual con la que se establece la temperatura deseada y el termo la mantiene a esa temperatura. El termo es bastante eficiente por sus dos depósitos independientes y a lo largo del día manteniendo el agua a una temperatura de unos 45º el termo se enciende no más de tres veces al día y solo durante unos minutos.

Incluye dos tacos y tornillos de unos 8 centímetros de largo y 8 milímetros de diámetro y una plantilla de montaje que tiene el tamaño real del termo para calcular la posición deseada antes de taladrar la pared. Los tacos incluidos en la caja no son muy buenos y cuando los puse los anclajes quedaban algo separados de la pared. Al final en vez de usar los tacos incluidos use un taco químico y unas varillas roscadas de 10mm para anclar los soportes y colgar el termo. Con las varillas, taco químico, roscas y arandelas el termo queda mejor asegurado. Al ser el termo bastante plano la carga que ejerce sobre la pared es más vertical.

Válvula de seguridad por presión, tacos, tornillos, casquillos electrolíticos y plantilla montaje
Soportes incluidos en la caja, el soporte queda en diagonal Soportes con taco químico y varilla roscada

Instalación termo eléctrico

Antes de empezar la instalación del termo solicite la baja del suministro del gas, en unas dos semanas mi compañía me notificó que ya me lo habían dado de baja y comprobé ya que la caldera no encendía por falta de gas. La baja de gas implica la eliminación del contador, una posterior solicitud de alta conlleva unos 60€ por el concepto de enganche. En cualquier caso no hay que manipular la instalación del gas hasta que llega a la ventana, en todo caso cerrar las llaves de paso y colocar un tapón en el tubo del gas de la caldera que queda sin uso para que no le entre suciedad. La instalación del termo se puede realizar en el mismo lugar en el que estuviese la caldera aunque para evitar pérdidas de calor se recomienda que esté los más cerca de la ducha. Como en mi caso la caldera proporcionaba agua caliente también para la calefacción los tubos del circuito cerrado de la calefacción quedarán sin uso, he vaciado el circuito y para que no les entre suciedad los he tapado con un tapón de metal. La entrada del agua y la salida del agua caliente que usa el termo son las mismas que usaba la caldera aunque para las conexiones hay que utilizar alguna llave de paso para cortar si es necesario la entrada del agua o vaciar el termo, unos codos de fontanería apropiados según las anchuras de los latiguillos y entrada de agua y unos latiguillos de 30cm para unir el termo con los tubos del agua.

También he tenido que adaptar la conexión eléctrica ya que de construción a la caldera le llegaban directamente los cables. He puesto un enchufe de tipo schuko de superficie, todavía me queda poner una canaleta para los cables. Con un poco de yeso a las salidas de los tubos para embellecer la pared que ahora se ve más.

Instalación termo eléctrico

El termo Fleck me costó 315€ comprándolo en Bricomart, si lo hubiese comprador en internet ya sea en Amazon o en la tienda de Droitek me podría haber salido por unos 50€ más barato, unos 265€ con gastos de envío incluido. Desde luego no lo compraría en El Corte Inglés ya que el modelo Fleck en concreto costaba unos 400€ lo que es significativamente superior. Al final por no tener que esperar a que llegase y estar presente en casa para recogerlo lo compré en Bricomart. En Amazon algunos vendedores ofrecen algo mejor precio.

Con el grifo monomando que tengo la temperatura del agua caliente se puede regular perfectamente pero si quieres tener mayor control existen los grifos termoestático que regulan el caudal de agua caliente y fría automáticamente para que en la salida el agua esté a la temperatura deseada.

Grifo monomando

Me he duchado con el agua en el termo a 55, 50 y 45 grados y con con una distancia en mi casa desde el termo hasta el baño de unos 15 metros de tubería y el agua en la ducha sale bastante caliente, lo suficiente para ducharse en verano y haciendo que el monomando que tengo no esté completamente abierto en el agua caliente. 50 litros dan más que suficiente para dos duchas sin agobios por ahorrar agua. Para disponer de más cantidad de agua caliente basta con subir la temperatura del agua en el termo.

by pico.dev at August 05, 2017 04:00 PM

August 03, 2017

Poesía Binaria

Knock, knock, knockin’ on server’s ports – Port knocking con ejemplos


¡Tenía muchas ganas de escribir este post! De hecho, hay muchas personas a las que les he hablado de la técnica port knocking y me he tenido que poner a buscar un ejemplo que me convenciera por Internet. ¡Ya no tengo excusa! Y, como siempre, intentaré incluir varios ejemplos para copiar y pegar sin miedo explicados para no perder detalle.

¿Qué es el port knocking?

Imaginad que en mi servidor tengo activo un servicio privado, al que no quiero que nadie acceda, sólo yo. Por ejemplo, puede ser un sistema de administración remota, monitorización, logs, rescate, o simplemente cosas que no quiero que sean públicas. Y, claro, cuanto más tiempo esté un servicio expuesto a Internet, más probabilidades de ser vulnerado.
Por ejemplo, si tenemos un servidor SSH corriendo, normalmente veremos el puerto 22 abierto, y cualquiera que nos haga un scan de puertos podrá verlo (¿quién va a querer hacerme un scan de puertos?):

nmap servidor.com
Starting Nmap 7.01 ( https://servidor.com ) at 2017-08-01 00:24 CEST
Nmap scan report for totaki.com (123.231.32.132)
Host is up (0.055s latency).
rDNS record for 123.231.32.132: servidor.com
Not shown: 997 closed ports
PORT    STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
443/tcp  open  https

Está bien, una de las formas de ocultar un servidor SSH es cambiar el puerto, y entonces un análisis rápido no lo verá. De todas formas es un puerto abierto y, tarde o temprano, esas cosas salen a la luz. Así que si abres tu puerto 753 como servidor SSH, cualquiera se podrá conectar a él y basta hacer un netcat al puerto y ver cómo se presenta:

nc -t servidor_oculto.com 753
SSH-2.0-OpenSSH_6.7p1

¡Listo! Sabemos que es un SSH, vamos a atacar, intentando identificarnos como los usuarios típicos: root, admin y demás, ¡Y conocemos la versión! Con lo malo que es eso para mantener un sistema medianamente seguro. Aunque bueno, aquí tienes una guía para endurecer un servidor SSH y hacerlo más seguro. No obstante, también podríamos tener un servicio corriendo que fuera algo más inseguro con una autentificación algo más floja.

Así que vamos a hacer un sistema de cerradura, como los de las cajas fuertes de las películas, en los que tenemos que girar la rueda varias veces siguiendo una combinación hasta que la podemos abrir o como cuando llamamos a la puerta con una combinación de golpes y esperas perfecta para que sepan que somos nosotros. De hecho port knocking lo podemos traducir como golpeo de puertos, es decir, intentaremos conectar con varios puertos y, el firewall de nuestro servidor mágicamente nos reconocerá y nos abrirá el puerto sólo para nosotros y así poder conectarnos.

Entonces, imaginemos que mi combinación es 1111, 3333, 2222 (lo pongo así para que veamos que no es necesario que los números de puerto estén ordenados), para abrir el puerto 22 de SSH necesitaré hacer intentos de conexión a los puertos 1111, 3333 y 2222. Estos puertos están cerrados, por lo que no conectarán, y el servidor parece que pasa de nosotros porque no hace nada, pero, tras los intentos de acceso a dichos puertos, podremos establecer una conexión con el puerto 22.

¿Podemos considerarnos paranoicos con este sistema de seguridad? Puede, y a muchos sysadmins les encanta. Al menos nos proporciona ocultación de los servicios críticos, así como de sus protocolos. Aunque, como todo, tiene sus riesgos.

No estoy inventando nada


Antes de continuar, tengo que decir que esta técnica es muy antigua. En junio de 2003, Martin Krzywinski publicó en Sys Admin Magazine un artículo bautizando de paso a esta técnica con un nombre chulo. Pero claro, eso no quiere decir que no se hubiera hecho antes.

Beneficios de esta técnica

Incluyo algunos puntos (no todos) que vienen en el artículo original de Krzywinski:

  • Lo principal es que es un método de autentificación silencioso. Como dije antes, el sistema parece que pasa de ti. Además, los puertos a los que accederemos están previamente cerrados, por lo que con un escaneo de puertos no sabremos los puertos que hay que golpear, y mucho menos el orden.
  • Si encima disponemos de un sistema que detecte y bloquee los escaneos de puertos, podríamos evitar que si nuestra clave de golpeo es de tres puertos, pudieran acceder al sistema tras hacer 3 escaneos. Además de que podríamos configurar el tiempo entre golpeos por lo que si tardas mucho en golpear tienes que empezar de nuevo. Aunque algunas implementaciones modernas de esta técnica pueden también evitar que un escaneo cuente como knock (hará knock cuando llegue al puerto deseado pero invalidará el knock cuando pruebe el siguiente puerto).
  • No tenemos que cambiar nada en el software servidor que escucha en el puerto que vamos a abrir. Es más, esta configuración es totalmente independiente.
  • Elimina entradas en los logs de sistema. ¡Cuántas líneas logea el demonio SSH con intentos de acceso! Con este sistema, la mayoría de intentos de acceso a un servidor SSH no llegarán a afectarnos lo más mínimo. El puerto del servicio está cerrado así que el propio firewall se deshará de todos.

Desventajas e inconvenientes

  • No es conveniente proteger puertos como el 80 (http) o el 25 (smtp), porque los clientes no se van a poner a hacer el proceso de knocking cada vez que quieran algo de esos servidores. Esto está pensado para servicios que deben ser privados.
  • Si tenemos servicios abiertos al público en el mismo servidor. Alguien podría utilizar un problema, bug, puerta trasera, etc. para entrar en el servidor y podría echar por tierra la seguridad que queremos tener con los servicios privados. Esto no es específicamente de la técnica, es un problema general de todos los sysadmins.
  • Tenemos que tener cuidado con los servicios de automatización del firewall. Yo utilizaré iptables, así que si utilizamos UFW o APF, puede que éstos no se lleven bien y tendremos que trabajar un poco más para que todo funcione en sintonía.
  • Es algo más que debemos mantener. Tanto si lo hacemos con scripts de iptables como si lo hacemos con un demonio. Como administradores del sistema tendremos que asegurarnos de que el sistema está vivo y no falla. Sólo imagina que si el sistema que controla el port knocking falla, nos quedaremos sin acceso al servicio que hemos ocultado.
  • Tenemos una contraseña para abrir el puerto. Podríamos hacer un script que haga el knocking automáticamente, y ese script nos lo querremos llevar con nosotros a cualquier lado. Y ya estamos liberando información privada si lo subimos a un servidor o lo anotamos, etc.
  • Si muchos usuarios tienen la clave del knocking e intentan acceder al servidor, la información temporal que tiene que almacenar el firewall puede crecer mucho. No es preocupante si es un gran servidor, pero la memoria se evapora.
  • Este método permite la entrada a la IP que haga el juego completo de knocks. Es decir, si estamos haciéndolo a una máquina en Internet y varias personas compartimos conexión cualquiera en nuestra red local podría entrar. Eso también podría ser una ventaja… según se mire.

Ejemplo con iptables

Entonces, lo que queremos es que nuestro servidor tenga el puerto 22 (ssh) cerrado (cojo el 22, pero podría ser cualquier otro). Y cuando intente conectar con los puertos 1111, 3333 y 2222, puertos que están cerrados y los intentos de conexión no harán nada, veremos el puerto 22 abierto para poder conectar por ssh. Así que vamos a definir los diferentes estados por los que pasará mi sistema:

Estado Descripción
Inicial Configuración básica del firewall
WAITING Esperando golpeos. Desde este estado repartimos los paquetes entrantes a los demás estados
KNOCK1 Entra el primer toque
KNOCK2 Entra el segundo toque
KNOCK3 Entra el tercer toque
ACCESSGRANTED Esperando conexión con el puerto abierto

También vamos a suponer que tenemos un servidor web instalado, por lo que el puerto 80 deberá estar abierto (en la práctica deberíamos también abrir el 443). Si tienes otro firewall o un script de firewall, tal vez esto tengas que solucionarlo ahí.

Crearemos los estados en iptables:

iptables -N WAITING
iptables -N KNOCK1
iptables -N KNOCK2
iptables -N KNOCK3
iptables -N ACCESSGRANTED

Esto es lo que vamos a hacer lo siguiente en el servidor.

¿Qué haremos con el tráfico normal del servidor?

Asumo que el servidor SSH ya está instalado y funcionando.
Es decir, vamos a definir las directivas del tráfico que aceptará nuestro servidor (lo que empieza por # se ejecutará como root directamente. Si no somos root, tal vez podríamos usar sudo).

Lo primero que hacemos es aceptar todo el tráfico entrante y saliente (INPUT y OUTPUT, algunos también necesitaréis activar FORWARD), seguidamente con -F limpiamos las reglas de iptables hasta el momento (cuidado si tienes firewalls ya).

iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -F

La siguiente línea hace que las conexiones ya establecidas sigan su curso. Es decir, tanto las conexiones al servidor web como las conexiones que ya tenemos establecidas en el puerto 22, que no tengan ningún problema para continuar.

iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Lo siguiente es aceptar todo lo que venga de localhost. Normalmente podemos tener varios servicios en la misma máquina que conectan con ellos mismos, y son todos privados, por lo que éstos no tienen que tener impedimentos.

iptables -A INPUT -i lo -j ACCEPT

Con estas líneas, rechazamos los paquetes ICMP, por ejemplo el PING. Esto no es esencial, pero muchos lo hacen, y desde aquí quiero demostrar que podemos hacer que ciertas conexiones continúen o al contrario, que se detengan.
Como hacemos en la siguiente línea, que es aceptar todo lo que provenga del puerto 80 tcp. Es decir, nuestro servidor web.
# iptables -A INPUT -p icmp -j DROP
# iptables -A INPUT -p tcp –dport 80 -j ACCEPT
[/simterm]

Todas las conexiones que hayan llegado hasta aquí, las vamos a pasar al estado WAITING

iptables -A INPUT -j WAITING

Configuramos los estados knockX y AccessGranted

Estos estados “knock” también pueden ser considerados puertas, como si un usuario tuviera que pasarlas todas para ver la libertad. Éstos serán KNOCK1, KNOCK2, KNOCK3. Empezamos por el primer intento. Estamos esperando un knock al puerto tcp 1111, conexión que tenemos que tirar porque ahí no hay servicio y no queremos que el puerto figure como cerrado. Eso sí, vamos a ponerle un flag “PASSED1” para que cuando entre el siguiente paquete sepa que tiene que este paso ya está hecho y entre directamente en KNOCK2.
La primera línea sólo nos sirve para enviar un log (que podemos ver con dmesg. El ejemplo de dmesg está al final del post).
En la tercera línea me encargo de tirar todos los demás paquetes que vengan. Sin flag ni nada, esos no han pasado la prueba.

En este post hablo de poner un flag a la IP, para indicar que se ha pasado la prueba. En realidad, iptables lo que hace es meter una IP en una lista. Al final estamos hablando de lo mismo, pero de forma más eficiente. En lugar de crear un texto que diga PASSED1 asociado a una IP, lo que hacemos es crear una lista llamada PASSED1 y meter ahí la IP, el momento en el que entró el último paquete y alguna información más. Si queremos, podemos ver el contenido de las listas haciendo:

cat /proc/net/xt_recent/PASSED1
src=12.124.229.34 ttl: 51 last_seen: 4306420264 oldest_pkt: 1 4306420264
src=21.123.219.55 ttl: 51 last_seen: 4306420224 oldest_pkt: 1 4306420224
iptables -A KNOCK1 -j LOG --log-level 4 --log-prefix “Knock 1: ”
iptables -A KNOCK1 -p tcp --dport 1111 -m recent --name PASSED1 --set -j DROP
iptables -A KNOCK1 -j DROP

Vamos, al KNOCK2, al que entraremos cuando recibamos el segundo knock. Éste será parecido al primero, sólo que antes de nada tendremos que borrar el flag PASSED1. Esto lo hacemos para que cuando un usuario haga mal el golpeo, es decir, después del 1111, golpee el 5555 y luego el 3333 ya no cuente, así si hacen varios escaneos que no bloqueamos el usuario no entrará. Por lo demás, hacemos que cuando se acceda al puerto 3333 pongamos la etiqueta “PASSED2” para que, como antes, cuando llegue un paquete nuevo al estado WAITING, éste sepa que tendrá que ir directamente al estado KNOCK3 porque KNOCK2 ya lo ha pasado y además, el paquete lo tiramos, porque en el puerto 3333 no hay nada. Por lo demás, saltaremos al estado KNOCK1 para ver si la conexión pasa el primer toque.

iptables -A KNOCK2 -m recent --name PASSED1 --remove
iptables -A KNOCK2 -j LOG --log-level 4 --log-prefix “Knock 2: ”
iptables -A KNOCK2 -p tcp --dport 3333 -m recent --name PASSED2 --set -j DROP
iptables -A KNOCK2 -j KNOCK1

Este estado sí que es mucho más parecido al anterior y, con esto, ya nos da una pista para que nuestro sistema pueda tener tres, cuatro o cinco knocks. Cuantos más knocks, más difícil será entrar, será un modo más paranoico, y nuestro firewall será más complicado (recordad que esto requerirá un mantenimiento y, si hay muchos usuarios que quieren entrar, todo será más complicado). Lo único que cambian son los números. Es decir, en el estado KNOCK3 entramos porque el flag PASSED2 está activo (es decir, hemos superado el paso2 y por eso estamos en knock3), luego logeamos diciendo que estamos en knock3 y si alguien intenta conectar por el puerto 2222, colocaremos el flag PASSED3. Sencillo, ¿no?

iptables -A KNOCK3 -m recent --name PASSED2 --remove
iptables -A KNOCK3 -j LOG --log-level 4 --log-prefix “Knock 3: ”
iptables -A KNOCK3 -p tcp --dport 2222 -m recent --name PASSED3 --set -j DROP
iptables -A KNOCK3 -j KNOCK1

Y… una vez superados los tres knocks, es decir, la conexión tiene el flag PASSED3, el acceso ya está permitido y ahora aceptaremos las conexiones al puerto 22.

iptables -A ACCESSGRANTED -m recent --name PASSED3 --remove
iptables -A ACCESSGRANTED -j LOG --log-level 4 --log-prefix “Access Granted: ”
iptables -A ACCESSGRANTED -p tcp --dport 22 -j ACCEPT
iptables -A ACCESSGRANTED -j KNOCK1

Colocando cada paquete en su estado

Una vez que tenemos los estados KNOCKX y ACCESSGRANTED configurados, necesitamos que el estado WAITING, que será al estado que saltemos cuando llega un nuevo paquete (y éste ha sido previamente filtrado), reparta los paquetes que lleguen entre los diferentes estados en función de los flags que hemos ido definiendo. Es decir:

  • Si no tenemos flags, saltamos a KNOCK1, porque tal vez sea una conexión con el puerto 1111, si no lo es, no haremos nada.
  • Si la IP tiene el flag PASSED1, saltaremos a KNOCK2 y esperaremos el segundo toque.
  • Si la IP tiene el flag PASSED2, saltaremos a KNOCK3 y esperaremos el tercer toque.
  • Si la IP tiene el flag PASSED3, saltaremos a ACCESSGRANTED y esperaremos una conexión por el puerto 22.

Además, desde aquí podemos asignar tiempos. Es decir, si la IP tiene el flag PASSED1 y además han pasado menos de 10 segundos desde que entró en la lista, entramos a KNOCK2. Con esto limitamos el tiempo que tiene el usuario para poder completar cada paso y entrar en el sistema.

iptables -A WAITING -m recent --rcheck --seconds 30 --name PASSED3 -j ACCESSGRANTED
iptables -A WAITING -m recent --rcheck --seconds 10 --name PASSED2 -j KNOCK3
iptables -A WAITING -m recent --rcheck --seconds 10 --name PASSED1 -j KNOCK2

Todo el tráfico restante, lo mandamos a KNOCK1

iptables -A WAITING -j KNOCK1

El script completo

A mí me encanta poder copiar y pegar de las webs, al menos para probar las cosas de un tirón. Así que, os pongo el script completo aquí.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#!/bin/bash

# Creamos objetivos de iptables
iptables -N WAITING
iptables -N KNOCK1
iptables -N KNOCK2
iptables -N KNOCK3
iptables -N ACCESSGRANTED

# Establecemos una política básica de permisos
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -F
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
# Ignoramos ping, bueno, paquetes ICMP en general. Sólo para probar, mejor será que se lo dejemos a nuestro firewall que tendrá mejores reglas para esto.
iptables -A INPUT -p icmp -j DROP
# Aceptamos conexiones por el puerto 80
iptables -A INPUT -p tcp --dport 80 -j ACCEPT

# Todos los paquetes que hayan llegado hasta aquí, saltarán a WAITING
iptables -A INPUT -j WAITING

### Estado KNOCK1 - En espera del primer golpe
iptables -A KNOCK1 -j LOG --log-level 4 --log-prefix "Knock 1: "
iptables -A KNOCK1 -p tcp --dport 1111 -m recent --name PASSED1 --set -j DROP
iptables -A KNOCK1 -j DROP

### Estado KNOCK2 - A la caza del segundo golpe
iptables -A KNOCK2 -m recent --name PASSED1 --remove
iptables -A KNOCK2 -j LOG --log-level 4 --log-prefix "Knock 2: "
iptables -A KNOCK2 -p tcp --dport 3333 -m recent --name PASSED2 --set -j DROP
iptables -A KNOCK2 -j KNOCK1

### Estado KNOCK3 - El último paso hacia la libertad
iptables -A KNOCK3 -m recent --name PASSED2 --remove
iptables -A KNOCK3 -j LOG --log-level 4 --log-prefix "Knock 3: "
iptables -A KNOCK3 -p tcp --dport 2222 -m recent --name PASSED3 --set -j DROP
iptables -A KNOCK3 -j KNOCK1

### Estado ACCESSGRANTED - Tenemos acceso al puerto 22
iptables -A ACCESSGRANTED -m recent --name PASSED3 --remove
iptables -A ACCESSGRANTED -j LOG --log-level 4 --log-prefix "Access Granted: "
iptables -A ACCESSGRANTED -p tcp --dport 22 -j ACCEPT
iptables -A ACCESSGRANTED -j KNOCK1

# Ahora establecemos las políticas por las que entramos en cada estado
iptables -A WAITING -m recent --rcheck --seconds 30 --name PASSED3 -j ACCESSGRANTED
iptables -A WAITING -m recent --rcheck --seconds 10 --name PASSED2 -j KNOCK3
iptables -A WAITING -m recent --rcheck --seconds 10 --name PASSED1 -j KNOCK2
iptables -A WAITING -j KNOCK1

Cómo hacer el golpeo de puertos

En el lado del cliente, en nuestro ordenador, sólo tendríamos que intentar acceder a los puertos, con el programa que queramos, incluso con un navegador web si queremos (puede ser muy lento). Eso sí, como los puertos no tienen ningún servicio y cuando intentamos establecer una conexión parece que el servidor nos ignora tendremos que tener muy en cuenta los timeouts. Es decir, tenemos que poner un timeout pequeño, por ejemplo de un segundo o menos. Eso sí, la conexión con el servidor debe ser más o menos buena para que los paquetes lleguen en un tiempo razonable. Así que podríamos intentarlo incluso con curl:

curl -m 1 http://servidor.com:1111
curl: (28) Connection timed out after 1001 milliseconds
curl -m 1 http://servidor.com:3333
curl: (28) Connection timed out after 1001 milliseconds
curl -m 1 http://servidor.com:2222
curl: (28) Connection timed out after 1001 milliseconds
ssh usuario@servidor.com
Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-83-generic x86_64)

Aunque, ya puestos, intentémoslo con netcat, que será más sencillo:

nc -w 1 servidor.com 1111
nc -w 1 servidor.com 3333
nc -w 1 servidor.com 2222
ssh usuario@servidor.com
Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-83-generic x86_64)

Y también con el mismo nmap, desactivando el ping al host:

nmap -Pn --host_timeout 500 --max-retries 0 -p 1111 servidor.com
nmap -Pn --host_timeout 500 --max-retries 0 -p 3333 servidor.com
nmap -Pn --host_timeout 500 --max-retries 0 -p 2222 servidor.com
ssh usuario@servidor.com
Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-83-generic x86_64)

Por si fuera poco, lo podemos automatizar con un pequeño bucle en una sola línea de nuestro shell favorito:

for port in 1111 3333 2222; do nc -w 1 servidor.com $port; done
ssh usuario@servidor.com
Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-83-generic x86_64)

Utilizando un demonio (knockd)

Aunque existen varios sistemas, uno de los demonios que más me ha convencido, y más utilizado para estas cosas es knockd. El problema de tener un demonio corriendo es que si el demonio se cae estamos perdidos… ¡pero perdidos de verdad! Porque no vamos a poder entrar en nuestro servidor. Hay proveedores, como por ejemplo DigitalOcean que te permiten acceder a través de web a tu servidor sin necesidad de SSH aunque en ocasiones esto debe estar prohibido por exigencia de nuestros clientes o de normativas de seguridad.

De todas formas, el hecho de utilizar un demonio muy conocido y muy antiguo para eso (la primera versión es de 2004) es que está muy probado y podemos considerarlo estable. Además está hecho en C, por lo que la huella en memoria y la CPU utilizada serán ínfimas (que esté hecho en C no tiene nada que ver, podemos hacer programas muy poco eficientes, pero programarlo en python, por ejemplo ralentizaría mucho el sistema en caso de que entren muchas conexiones a la vez); y utiliza la biblioteca pcap, que también es muy robusta y está muy probada.

Cabe comentar que el uso del demonio facilita muchísimo la tarea de implementar el port knocking, ya que es mucho más intuitivo y no hay que andar pensando en los estados de los diferentes paquetes ni preocuparse en exceso por los firewalls. Además, como el resultado final es la ejecución de un comando, es decir, el programa detecta los knocks y en consecuencia ejecuta una orden, podemos personalizar dicha orden para que sea lo más amigable posible con nuestro firewall o script controlador o si, por ejemplo, queremos o necesitamos logear este tipo de actividad, no sólo haciendo caso al propio log de knockd.

Para esta guía he utilizado una Debian, de todas formas en otra distribución no debería ser muy complicado instalarlo y configurarlo (los ficheros de configuración serán iguales).

sudo apt-get install knockd

Lo primero es editar el archivo /etc/default/knockd, en el que debemos poner a 1 START_KNOCKD y en KNOCKD_OPTS definir el interfaz de red sobre el que nos vamos a centrar. En mi caso, eth0. Por lo que el archivo quedaría así:

################################################
#
# knockd’s default file, for generic sys config
#
################################################

# control if we start knockd at init or not
# 1 = start
# anything else = don’t start
#
# PLEASE EDIT /etc/knockd.conf BEFORE ENABLING
START_KNOCKD=1

# command line options
KNOCKD_OPTS=”-i eth0″

Seguidamente, editamos /etc/knockd.conf, vamos a hacer algunos cambios en el fichero para hacer las cosas más fáciles:

[options]
UseSyslog

[openSSH]
sequence = 1111,3333,2222
seq_timeout = 5
command = /sbin/iptables -I INPUT -s %IP% -p tcp –dport 22 -j ACCEPT
tcpflags = syn

[closeSSH]
sequence = 3333,2222,1111
seq_timeout = 5
command = /sbin/iptables -D INPUT -s %IP% -p tcp –dport 22 -j ACCEPT
tcpflags = syn

Ahora, configuramos iptables, en mi caso, aunque podríamos hacerlo perfectamente desde nuestro firewall o script de firewall siempre y cuando adaptemos bien las reglas. Sería una configuración parecida a la configuración inicial anterior en la que aceptamos los paquetes de las conexiones ya establecidas, aceptamos los paquetes que vienen de localhost y lo que venga del puerto 80, si queremos. Eso sí, en lugar de enviar los paquetes enviados a WAITING, directamente los tiramos (drop).

iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -F
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p icmp -j DROP
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -j DROP

En este caso, knockd será el que controle si se están haciendo los knocks y la forma de entrar en el servidor será muy parecida. Eso sí, con esta configuración necesitamos hacer los knocks a los puertos 1111, 3333, 2222 para abrir el puerto 22 y luego 3333, 2222, 1111 para cerrarlo. El puerto se mantendrá abierto hasta que lo cerremos. Por un lado está bien, porque no tendremos que repetir los knocks para abrir otra sesión (por ejemplo si queremos abrir dos sesiones), pero por otro… personalmente soy muy despistado y se me puede olvidar cerrar el puerto.

Knockd por tiempo, como hacíamos con iptables

Como soy muy despistado, con knockd también podemos replicar el comportamiento anterior de iptables, es decir, el puerto se abrirá durante un tiempo y se cerrará automáticamente. Para eso, entraremos en el archivio /etc/knockd.conf y pondremos lo siguiente:

[options]
UseSyslog

[opencloseSSH]
sequence = 1111, 3333, 2222
seq_timeout = 15
tcpflags = syn
start_command = /usr/sbin/iptables -I INPUT -s %IP% -p tcp –syn –dport 22 -j ACCEPT
cmd_timeout = 10
stop_command = /usr/sbin/iptables -D INPUT -s %IP% -p tcp –syn –dport 22 -j ACCEPT

De esta manera con nuestra secuencia de puertos de antes se abrirá el puerto 22 por unos segundos y luego se cerrará pasados unos segundos. Y también tenemos un log de todo esto, tanto en el ejemplo anterior como en este podremos ver en el syslog (/var/log/syslog) lo siguiente:

Aug 3 12:43:06 ubuntu-512mb-fra1-01 knockd: xxx.xxx.xxx.xxx: openSSH: Stage 1
Jul 30 12:43:07 ubuntu-512mb-fra1-01 knockd: xxx.xxx.xxx.xxx: openSSH: Stage 2
Jul 30 12:43:08 ubuntu-512mb-fra1-01 knockd: xxx.xxx.xxx.xxx: openSSH: Stage 3
Jul 30 12:43:08 ubuntu-512mb-fra1-01 knockd: xxx.xxx.xxx.xxx: openSSH: OPEN SESAME
Jul 30 12:43:08 ubuntu-512mb-fra1-01 knockd: openSSH: running command: /sbin/iptables -I INPUT -s xxx.xxx.xxx.xxx -p tcp –dport 22 -j ACCEPT

Y listo. Ya tenemos la puerta abierta. Lo bueno de este demonio es que podemos configurar varios locks y los servicios que queramos en cada uno de ellos o incluso… enviar mensajes a los servidores utilizando los knocks, los start_command y stop_command pueden, perfectamente, ser scripts que hagan cualquier cosa y no sólo abrir o cerrar puertos.

Secuencias de knock preconfiguradas

¡El comportamiento más peliculero de knockd! Vamos, contraseñas de knock que van cambiando cada vez que se abren o se cierran las puertas. Imaginad que vamos a utilizar varias secuencias para abrir un puerto, así que vamos a crear un fichero /etc/ssh_knock_seq que contenga lo siguiente:

1111,3333,2222
1111,2222,3333,
1234,5678,9101,
1213,1415,1617

Es muy importante el espacio al principio de la línea, ya que knockd escribirá un # en el primer carácter de cada secuencia que vaya utilizando (por eficiencia, es mucho más rápido cambiar un carácter que insertarlo, ya que implica un desplazamiento de todos los contenidos), por lo que perderíamos el primer número si no ponemos un espacio.

Ahora, en /etc/knockd.conf hacemos lo siguiente:

[options]
UseSyslog

[openSSH]
one_time_sequences = /etc/ssh_knock_seq
seq_timeout = 5
command = /sbin/iptables -I INPUT -s %IP% -p tcp –dport 22 -j ACCEPT
tcpflags = syn

La primera vez que hagamos la secuencia de knocks debemos hacerla a los puertos 1111, 3333 y 2222; la segunda vez a los puertos 1111, 2222 y 3333 y así sucesivamente. Lo bueno es que las secuencias cambian, así que si alguien está sniffando el tráfico de red y vea que estás hacieno knocks a puertos e intente hacer lo mismo después, no le va a servir porque la secuencia ha cambiado. Lo malo es que si hay más de un administrador del sistema que tiene que entrar, es un poco rollo saber por qué combinación vamos.

Complicando un poco los knocks

Este cliente, al funcionar capturando el tráfico de la red, puede ver directamente los paquetes TCP que se envían, y podemos reaccionar ante diferentes flags del paquete: syn, ack, fin, rst… Para no entrar en mucha profundidad, normalmente cuando se inicia una conexión TCP. Un cliente envía SYN al servidor, y el servidor responde SYN-ACK, luego el cliente le responde ACK, cuando alguien corta la comunicación le dice al otro FIN, para reiniciar la conexión se envía RST y, bueno, hay algunos más. El caso es que normalmente cuando hacemos knocks enviamos un SYN, pero, ¿y si hacemos que el servidor requiera knocks con ACK? Es raro, más paranoico y enrevesado, además puede requerir privilegios de administración en los clientes y no sé yo si a muchos firewalls les gustará que les mandes un ACK sin conocer de nada al host con el que hables (el SYN solo es como un saludo). Pero bueno, podemos decirle a knockd en tcpflags que escuche solo a ACK o a FIN y sólo reaccionará ante esos estímulos. Está muy chulo para probar.

Para hacer los knocks, recomiendo la herramienta hping3 que podemos utilizarla así:

hping3 -c 1 -A miservidor.com -p 1111
hping3 -c 1 -A miservidor.com -p 3333
hping3 -c 1 -A miservidor.com -p 2222

Y, por supuesto, podemos utilizarla en un script como el de antes.

Envío de knocks con cliente

knockd proporciona un cliente llamado knock (sin la d) con el que podemos enviar los knocks todos seguidos y sin scripts como hacíamos antes:

knock miservidor.com 1111 3333 2222

Anexos

Quiero incluir algunas cosillas más, para tener toda la información en este post. Con algunas cosas que no tienen mucho que ver, pero ayudan a comprenderlo todo.

Ejemplo de dmesg

El kernel está todo el rato escribiendo mensajes con lo que sucede. Y el caso de iptables, ya que actúa en el kernel no es menos. Cuando desde iptables enviamos al log un mensaje podremos consultarlo haciendo:

iptables | tail

Con tail sacamos las últimas líneas del buffer de mensajes del kernel, porque suele ser muy largo y seguramente algo que sucedió hace mucho tiempo no nos interesa.
De todas formas, las fechas y horas están expresadas en el tiempo transcurrido tras el arranque de la máquina y no es un formato muy agradable porque usa números muy largos. Podemos expresarlo en formato humano con este post o con el argumento -T. Aunque a mí me gusta mucho la salida producida por:

dmesg -HTxL

Que escribe los mensajes de manera legible y nos deja hacer búsquedas (como less), el tiempo en formato humano, nos da información sobre el tipo de mensaje y encima lo muestra en colores.

Ejemplo de iptables centrado en interfaz

No voy a extenderme mucho, pero si queremos que una regla de iptables se aplique a los paquetes que viajan por una interfaz de red determinada debemos incluir “-i [interfaz]”. Al final se quedaría algo así:

iptables -A KNOCK1 -i eth0 -p tcp --dport 1111 -m recent --name PASSED1 --set -j DROP

ACCEPT, REJECT y DROP

Está claro que ACCEPT directamente acepta el paquete y si va para alguna aplicación, ésta lo recibe y lo procesa. Vamos, el uso normal. Pero cuando especificamos REJECT, estamos rechazando el paquete, y para rechazarlo tenemos que responder algo. DROP, en cambio ignora el paquete, lo tira en saco roto y que se pierda en la inmensidad de la red.
Es como cuando mantienes una conversación con alguien, si aceptas su mensaje haces algo al respecto. Te dicen “Hola” y respondes: “Buenos días, ¿cómo estás?”. Si rechazas los mensajes (reject), te dicen “Hola” y contestas: “¡No hablo contigo!” y pones carita de enfado. Eso implica un esfuerzo, intención de contestar y en general gasto de recursos. Pero si ignoras a alguien, te dirán “Hola” y no contestas, pero tú estás a lo tuyo, lo mismo has movido un poco la oreja o has girado ligeramente la cabeza cuando lo has escuchado, pero tu “amigo” ya puede esperar tu respuesta, que lo hará hasta que se cumpla su timeout.

Foto principal: Mahkeo

The post Knock, knock, knockin’ on server’s ports – Port knocking con ejemplos appeared first on Poesía Binaria.

by Gaspar Fernández at August 03, 2017 05:58 PM

# rm-rf.es

Cómo activar/desactivar la función de MAC aleatoria en Network Manager

Network Manager cuenta con una funcionalidad que permite que la interfaz WiFi o Ethernet muestre una MAC aleatoria cada vez que se establece una conexión (MAC address randomization). Esta funcionalidad viene activa por defecto creo que desde Fedora 24 (y en cualquier distribución con Network Manager 1.4.0 ó superior). Su integración en NM tiene como objetivo mejorar la privacidad del usuario en redes no confiables.

Para deshabilitar la funcionalidad, se debe establecer la siguiente directiva en el archivo de configuración global de Network Manager, /etc/NetworkManager/NetworkManager.conf o en uno dedicado (por cuestiones de organización) /etc/NetworkManager/conf.d/90-disable-randomization.conf

[device-mac-randomization]
wifi.scan-rand-mac-address=no

Existen varias posibilidades de configuración, desde la de generar una MAC aleatoria para cada conexión hasta la de especificar MACs diferentes según la red a la que nos conectamos:

[device-mac-randomization]
# "yes" is already the default for scanning
wifi.scan-rand-mac-address=yes

[connection-mac-randomization]
ethernet.cloned-mac-address=random
wifi.cloned-mac-address=random

by Alex at August 03, 2017 03:53 PM

enavas.blogspot.com.es

OSBoxes: Repositorio de imágenes de SSOO Linux para VirtualBox y VMWare

OSBoxes es un proyecto que aloja diferentes imágenes de SSOO Linux listas para usar en VirtualBox y VMWare.

Todas las máquinas tienen definido un usuario con un password estándar:

  • Username: osboxes 
  • Password: osboxes.org

Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at August 03, 2017 06:26 AM

Techbench by WZT: Repositorio de descargas de Windows

Techbench by WZT es un proyecto que nos va a permitir descargar sistemas operativos Windows, aplicaciones de Office, paquetes de idioma y máquinas virtuales directamente desde servidores de Microsoft.
Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at August 03, 2017 06:16 AM

August 01, 2017

Entre Dev Y Ops

Podcast 27: Comparando AWS y Azure con Javi Moreno

EDyO Podcast

Antes de irnos de vacaciones hemos querido dejaros una pequeña joya, el episodio 27 de nuestro podcast donde comparamos AWS y Azure con Javi Moreno, Resident Futurist & Evangelist en CAPSiDE.

Si os gusta nuestro trabajo por favor corred la voz, dadnos feedback, y valorad con 5 estrellas iTunes y me gusta en Ivoox.

A continuación podéis encontrar los enlaces comentados en este episodio.

Leer más… (1 min remaining to read)

by David Acacio at August 01, 2017 11:00 AM

blogofsysadmins.com

Actiona, Automatizador visual de tareas

Al más puro estilo de iMacros, Actiona es un programa libre, gratuito y de código abierto para Linux que permite automatizar tareas y mapear teclas y clicks del ratón. Con este programa es posible programar tareas desde cero utilizando su propio lenguaje de script, e incluso convertir esos scripts en archivos ejecutables, convirtiendo así a …

by GhOsTi at August 01, 2017 10:07 AM

July 30, 2017

Blog Bitix

La búsqueda de ejemplares de roble común

Quercus Robur

Hace ya mucho tiempo de pequeño planté alguna semilla de manzana por curiosidad para ver si germinaba, y sí germinó, pero al cabo de unos meses por desconocimiento de la forma de como cuidar una planta, excesivo riego o tierra no adecuada el retoño de manzano pereció. También planté alguna bellota de algún tipo de roble que alguno de mis hermanos trajo a casa, y sí germinó, y al igual que el manzano duró unos cuantos meses pero sucumbió de la misma forma.

Entre las muchas ideas que se le ocurren a uno, algunas las llevamos a cabo, otras nos gustaría hacerlas pero las ignoramos o las postergamos a falta de algo. Una de estas que he tenido ha sido en algún momento plantar árboles pero para lo cual hay que tener una pequeña zona en casa o un balcón luminoso.

Y la verdad es que mirando atrás es algo que podría haber hecho desde algún lustro pero que había olvidado. Quizá ha sido ahora al tener unos cuantos días festivos con más tiempo libre cuando la he vuelto a recordar, quizá también a raíz de que he ganado un espacio en casa que lo puedo usar para este propósito.

Decidido a hacer realidad nuevamente esta idea lo primero que necesito es encontrar ejemplares de roble común o en su nombre científico quercus robur en mi ciudad, un árbol autóctono de la región en la que vivo.

La búsqueda

Puesto a buscar ejemplares de esta especie de árbol desde hace unos días he empezado a fijarme si alguno de los árboles con los que me voy cruzando es un roble común. Hay muchos árboles en la aceras y zonas ajardinadas, muchos aún no se identificar de qué especie pero los robles son fáciles de identificar por sus hojas lobuladas y estos por el momento son los que me interesan.

El primero que encontré fue en un lugar inesperado y volviendo de jugar un partido de futbito cerca de la salida de una parada de metro, la de Ansio. No es un ejemplar muy grande, tendrá pocos años, pero ya tenía algunas bellotas.

Aprovechando el típico paseo andando del fin de semana me he ido fijando y yendo por las zonas donde creía que podría encontrar más. Y sí he encontrado otro cerca de la Universidad de Sarriko, cerca de mi casa, más cerca de lo que esperaba. He pasado muchas veces al lado pero hasta ahora no me había fijado. Con bellotas de muy buen aspecto en las ramas y algunas caídas del año anterior. Las del suelo la mayoría podridas o vacías. Un ejemplar de roble bastante grande aunque sin recibir cuidados y creciendo en total libertad.

Roble en la Universidad de Sarriko

También he encontrado un grupo de ellos en una zona ajardinada de un parque en Deusto pegado a la ría. Unos cinco juntos aunque un par de ellos no se si están en el mejor estado. También tenían algunas bellotas en las ramas y algunas en el césped.

Roble en el parque de Deusto

Pasado el museo Guggenheim enfrente de la nueva biblioteca de la Universidad de Deusto en otra zona ajardinada hay otro grupo de robles comunes con muy buen aspecto de salud. No son tan grandes como el de la Universidad de Sarriko pero al estar en una zona ajardinada están mejor cuidados y se nota que están bien sanos.

Robles en Abandoibarra

Incluso debajo de alguno de ellos hay algunos retoños.

Plántulas en Abandoibarra

Donde esperaba haber encontrado alguno ha sido en el parque de Doña Casilda y sin embargo solo he encontrado uno apartado y no con tan buen aspecto como los anteriores. Aún así, es otro ejemplar y tenía alguna bellota que en julio aún están verdes.

La primera recolección

Con esta primera búsqueda de ejemplares ya tengo identificados casi una decena que en la época en que las bellotas estén completamente desarrolladas hacia finales de septiembre o inicios de octubre me proveerán de las preciadas semillas para intentar hacer germinar algunos ejemplares.

Sin embargo, aprovechando esta ocasión ya he recogido unas cuantas bellotas con buen aspecto del año anterior. Que no son tantas ya que la mayoría están podridas, vacías o son pequeñas.

Bellotas de roble común

Cuando llegue la época de caída de las bellotas recogeré más y seguro que con mejor aspecto y mayor probabilidad de germinar que las que ya tengo. Solo he de tener paciencia y dejar que pase el tiempo. Mientras llega la época adecuada de recolección y aún unos meses más para la germinación aprovecharé para buscar en internet cómo hacer germinar bellotas, que necesita un roble, como cuidarlo sobre todo en el riego necesario.

Esta es de la mejor información que he encontrado hasta el momento:

El siguiente manual es muy interesante ya que en él están detallados brevemente varios árboles de la península ibérica, como son sus hojas y frutos, época de plantación, tipo de suelo que requiere y como realizar una plantación.

Ya iré contando más en un futuro sobre este tema. Generalmente cuando empiezo algo no lo abandono.

by pico.dev at July 30, 2017 11:00 AM

July 29, 2017

Blog Bitix

Desempaquetado maletín herramientas Mannesmann y bandejas melamina Balvi

Tener en casa un pequeño conjunto de herramientas es necesario para realizar pequeñas tareas domésticas, desde quitar un grifo a atornillar algún elemento. Buscando en el gran catálogo del que dispone Amazon en su web quería uno que fuese bastante completo sin ser muy caro y aunque no fuese de calidad profesional cumpliese con las tarea. Hay muchos modelos pero me fijé en uno de Mannesmann modelo M29085. También necesitaba unas bandejas para la cocina y salón.

Maletín herramientas Mannesmann M29085

Este maletín no son herramientas para un profesional por su calidad pero cumplen perfectamente para las tareas domésticas comunes en una casa. La calidad no profesional se nota en que por ejemplo el brazo del martillo es de plástico duro o el cuerpo de la sierra también es de plástico. Sin embargo, el conjunto de herramientas es bastante completo incluyendo desde alicates, llave inglesa, gran número de puntas para tornillos de estrella, planos, llaves de vaso utilizadas para la sujeción de algunos grifos, sierra, martillo, nivel, metro de 3 metros, llave de carraca y múltiples adaptadores, tres llaves allen pequeñas, destornilladores planos y de estrella de diferentes tamaños. El maletín es de fabricación y origen alemán esto no quiere decir ni que sea bueno o malo pero creo que esta gente está bastante dedicada a la fabricación y la herramienta.

Maletín herramientas Mannesmann M29085

El interior del maletín está organizado y todos los elementos permanecen sujetados aunque el maletín se mueva. En las cajas es habitual dar vueltas a los elementos que contiene hasta dar con el que buscamos, en este maletín todos los elementos están fácilmente accesibles y es fácil saber si falta alguno por el hueco que deja.

Juego de herramientas Mannesmann M29085

Las puntas para atornillar se usan con un adaptador y las llaves de vaso se pueden colocar en la llave de carraca y en el elemento similar a un destornillador denominado coupler.

Acoplador, puntas para el acoplador, nivel, metro y llave de carraca

Bandejas melamina Balvi

También necesitaba unas bandejas para llevar platos, cubiertos, vaso, pan o el postre de la cocina al salón y viceversa, de las varias que busqué me gustaron especialmente estas bandejas de melamina. Su diseño, tamaño y ya viéndolas y palpándolas una vez las he recibido aún más. Están fabricadas en melamina que es un material plástico duro, rígido y de aspecto resistente si se las trata adecuadamente aguantan los golpes que no sean fuertes, también son resistentes al calor y no se deforman o comban cosa que ocurre en otros materiales plásticos y la parte trasera tiene unas lineas de refuerzo para dar mayor consistencia a la bandeja. Tienen un tamaño de 45,8 centímetros de ancho por 32,5 cm de alto y unos 2,5 cm sobre la mesa. Otro aspecto importante es que son fáciles de limpiar y son apilables. Tiene 4 diseños diferentes y en varios colores, las fotos que he sacado no le hacen justicia a los colores de las bandejas, en la realidad los colores son más intensos y más parecidos a las fotos de los artículos en Amazon.

Bandejas melamina Balvi

En algún comentario de Amazon un usuario le ponía a estas bandejas una sola estrella porque decía que las cosas resbalaban, la superficie es muy pulida y no tiene rugosidades pero de ahí que las cosas resbalen creo que no salvo que en algún momento no mantengas la horizontalidad de la bandeja al transportar las cosas.

by pico.dev at July 29, 2017 09:00 AM

July 28, 2017

# rm-rf.es

Invalid request scheme for Endpoint Expected http Received https

En un servidor de aplicaciones sobre JAVA, existe la posibilidad de definir y personalizar determinadas restricciones de seguridad (security constraints) con el fin de limitar los privilegios y métodos de acceso a determinadas aplicaciones ó URLs.

Una de estas restricciones se basa en la capa de transporte (transport-guarantee), permitiendo especificar los métodos de comunicación permitidos entre el cliente y el servidor de aplicaciones, o más concretamente en este caso, la aplicación. En otras palabras, podemos obligar a que los datos recibidos por parte del cliente estén cifrados (HTTPS).

Así pues, podemos encontrarnos por ejemplo, con el error del título al intentar acceder a una aplicación utilizando HTTPS cuando está preparada para recibir sólo HTTP (o viceversa):

javax.enterprise.system.container.ejb|_ThreadID=694;_ThreadName=TP-Processor662;
_RequestID=11ba432a-13f8-4e8e-a4ea-dd2a41f07e03;|
Invalid request scheme for Endpoint. Expected http . Received https|#]

En este caso, el frontal web (Apache) estaba accediendo a la aplicación a través de un vhost HTTPS, siendo que la app esperaba recibir tráfico HTTP.

La solución es, configurar la aplicación para permitir tráfico HTTPS, que en este caso es el transport-guarantee del tipo CONFIDENTIAL. En el caso de un glassfish, por ejemplo, especificamos esta configuración en el archivo sun-ejb-jar.xml de la aplicación (dentro de META-INF). O en cualquier caso, donde se estén especificando las restricciones de seguridad de JAVA para el webservice:

<sun-ejb-jar>
        <enterprise-beans>
                <ejb>
                        <ejb-name>FOO</ejb-name>                                         
                        <webservice-endpoint>                           
                                <port-component-name>FOO</port-component-name>
                                <transport-guarantee>CONFIDENTIAL</transport-guarantee>
                        </webservice-endpoint>                                  
                </ejb>  
        </enterprise-beans>
</sun-ejb-jar>

Redespliegue de la aplicación, y listo. El error debería desaparecer.

by Alex at July 28, 2017 07:18 PM

enavas.blogspot.com.es

Instalar VirtualBox en Debian Jessie desde los repositorios de VirtualBox


Para instalar VirtualBox en Debian Jessie desde los repositorios de VirtualBox, lo primero que debemos hacer es añadir el repositorio:
# echo "deb http://download.virtualbox.org/virtualbox/debian jessie contrib" > /etc/apt/sources.list.d/virtualbox.list
A continuación, añadimos la clave pública del repositorio al anillo de claves:
# wget -q https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | sudo apt-key add -
E instalamos el paquete:
# apt-get install virtualbox-5.1
De este modo, podremos mantener VirtualBox actualizado fácilmente.
Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at July 28, 2017 05:50 PM

Poesía Binaria

Controlando un display de 7 segmentos con Arduino y un botón por interrupción.

Arduino 7 segmentosRetomo mis posts sobre Arduino (después de muchísimo tiempo) con un pequeño ejemplo que monté hace unos años, pero el post nunca llegó a salir. Se trata de la utilización de un display de 7 segmentos desde la propia placa Arduino. Estos displays, al final son 7 barras led con las que podemos representar números y letras dependiendo de las que encendemos y las que no. En mi ejemplo, haremos un contador de 0 a 9 controlado por un pulsador.

El display

Para ver más a fondo cómo funciona el display, lo más fácil es ver este dibujo:

Este ejemplo muestra un display de cátodo común, ya que las patillas centrales van a gnd (sólo hay que conectar una) y las demás (a, b, c, d, e, f, g, dp) podrán ir conectadas a VCC. Todo depende de las que queramos encender. En mi caso, alimento cada uno de los leds con unos 3.6V.

También existen displays de ánodo común, como el que utilizo en este proyecto. En este caso conecto el display a VCC (5V) y cada uno de los segmentos van conectados a GND a través de una resistencia.

Conectar el display directamente a Arduino

Es una opción. Nuestro display tiene 7 segmentos, y normalmente los Arduinos (Duemilanove, Uno, Mega…) suelen tener muchos pines de entrada-salida (más de 7) configurables y capaces de soportarlo. Así que perfectamente podemos conectar cada segmento a un pin del Arduino y hacer un programa que escriba valores en dichos pines.

En principio no es mala idea, nosotros controlaremos al 100% la iluminación de los segmentos. Aunque podemos tener varios problemas:

  • Nuestro Arduino se calentará. El display al final pide potencia, y puede que nuestro Arduino trabaje en exceso para entregar la potencia necesaria para iluminar el display. Podemos poner resistencias más grandes, pero el display lucirá menos.
  • Son muchos pines, para controlarlos podemos usar digitalWrite() y es un poco tostón controlar los digitalWrite() de cada número que vamos a representar. Por otro lado podemos hacerlo usando los PORT del Atmega (lo veremos en el ejemplo), pero claro, el PORTD (pines 0-7) no podemos acapararlo entero porque por ejemplo las interrupciones de algunos Arduino (como el mío, un Duemilanove, aunque sea algo viejo) están en los pines 2 y 3 por lo que no podremos utilizarlos. Y el PORTB (pines 8-13) sólo son 6 por lo que no son suficientes. Así que tendremos que pasar parte por un puerto y parte por otro puerto. Pero a fin de cuentas, si queremos hacer algo más con nuestra placa hemos gastado muchos pines para este propósito.
  • Impensable ya pasar el montaje a un circuito a base de ATtiny, por ejemplo.

Por poner un ejemplo más, si queremos utilizar puertos en lugar de digitalWrite(), lo primero es mirar el datasheet del chip que estemos utilizando, en mi caso Atmega168. Tendremos que mirar a qué pines corresponden los puertos. Yo utilizaré el puerto D y el puerto B para conectar el display.

Lo primero será crear un array con los valores de los segmentos que corresponderán a cada dígito. Daremos valores en hexadecimal porque serán más fáciles de manejar cuando tienes algo de vicio, sobre todo cuando debemos mirar el valor en binario de cada uno de los valores. En mi array, como mi display es de ánodo común tengo que mandar ceros a los dígitos que quiero encender. En este caso, sólo será un ejemplo, haremos algo así:

1
int disp[10]={0x81, 0xdd, 0x43, 0x45, 0x1d, 0x25, /**/0x21, 0xcd, 0x01, 0x05};

Con este array, hacemos que la posición 0 contenga 1000 0001 (al 0 sólo le falta un segmento, el último bit no lo usaremos), en la posición 1 tendremos 1101 1101 (el 1 sólo tiene dos segmentos activos), en la posición 2 tendremos 0100 0011 (el dos sólo tiene 2 segmentos desactivados), etc.

Y, para enviar los valores a los puertos podríamos utilizar el desplazamiento binario (shift):

1
2
PORTB = disp[5] >> 3; // A la parte baja del PORTB
PORTD = disp[5] << 4; // A la parte alta del PORTD

Los puertos

Veamos primero un diagrama de los pines del Atmega368, por ejemplo (muy parecido al del Atmega168:

Vemos que hay pines etiquetados como PB0..PB7, PC0..PC6, PD0..PD7. Corresponderán a los puertos B, C y D respectivamente. Si hemos manejado Arduino anteriormente habremos visto cómo digitalRead/digitalWrite nos puede solucionar la vida cuando se trata de leer o escribir el valor de un pin concreto. Aunque lo que yo quiero es definir el valor completo de un puerto. Es decir, enviar, por ejemplo un valor 11011011 de una sola vez a todos los pines del puerto D, por ejemplo.

Para ello, lo primero que tenemos que hacer será definir una máscara de entrada/salida de los pines del puerto, lo que anteriormente hacíamos con pinMode([pin], OUTPUT); pero esta vez lo haremos definiendo en la función setup() o en cualquier otro sitio la variable DDRD dando 1 al bit correspondiente con el pin que queremos que sea de salida (OUTPUT) o 0 si queremos que sea de entrada (INPUT):

1
2
3
DDRD=0xff; // Puerto D entero como salida
DDRD=0xdb; // 11011011
DDRD= 0 | 1 << PD5 | 1 << PD3 | 1 << PD1; // Sólo pins 1, 3 y 5 como salida.

Con la última forma de hacerlo, podemos pensar que se realizan operaciones en el chip e irá más lento, pero al ser PD5, PD3 y PD1 constantes, en tiempo de compilación se procesará el número y el programa real se ejecutará con una sola instrucción, por lo que es tan rápido como el caso que hay justo encima en el que nosotros hemos calculado el número.

Ahora para escribir valores en el puerto puerto, escribiremos la variable PORTD y para leer valores, leeremos la variable PIND.

Decodificador de 7segmentos 7447, 7448

Para arreglar los problemas mencionados anteriormente (potencia y número de pins), vamos a utilizar el circuito integrado 7447, ya que nuestro display es de ánodo común. Si fuera de cátodo común utilizaríamos el 7448. Este es un circuito TTL decodificador de BCD (binary-coded decimal, o decimal codificado en binario) a display de 7 segmentos. Ya que el sistema utilizado es digital no se garantiza que la salida para valores mayores a 9 sea la misma en todos los chips. Dada su tecnología requiere una corriente baja de entrada, de algunos microamperios, y proporciona una corriente de salida del orden de los miliamperios, por lo que puede hacer las veces de amplificador de la señal haciendo que nuestro Atmega no sufra.Haremos las conexiones como en el siguiente diagrama (como en la foto de portada):

Éstos son los materiales utilizados:

  • Arduino Duemilanove
  • Display de 7 segmentos de ánodo común
  • DM74LS74N (decodificador BCD-7 segmentos)
  • 1 diodo led (es para jugar, sólo parpadeará indefinidamente
  • 8 resistencias de 1K
  • 1 resistencia de 10K (para el pulsador)
  • 1 switch

El esquema del proyecto será el siguiente:

Vamos al código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
int num=0;

ISR(INT0_vect)
{
  num++;
  if (num>9)
    num=0;
   
  PORTB=0xf0 & PORTB | 0x0f & num;
}

void setup()
{
  // put your setup code here, to run once:
  DDRB=0xff;
  DDRD= 0;
  pinMode(LED_BUILTIN, OUTPUT);
  PORTB=0xf0 & PORTB | 0x0f & num;

  EICRA=0x03;
  EIMSK=1;
 
  sei();
}

void loop()
{
  digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);                      
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}

Empecemos por setup(). En donde con DDRB preparamos el puerto B como salida y el puerto D como entrada. Como es el puerto entero, le damos un 0 y listo. Preparamos la salida del led, aunque no haría falta especificar el pinMode porque el LED_BUILTIN apunta al pin 13 que es del puerto B que ya está marcado como salida, pero dejo esa línea ahí por si cambiamos el led de sitio. Simplemente es un led que parpadea para demostrar el funcionamiento de la interrupción.

Seguidamente presentamos el número en el display, aunque ya que el display y el led comparten puerto (el puerto B para todos), quise poner la parte alta del puerto B tal cual está (0xf0 & PORTB) y en la parte baja del puerto B pongo el número a representar (0x0f & num).

EICRA y EIMSK son dos valores que tengo que establecer para que mi Atmega escuche a las interrupciones hardware. Esto depende mucho del chip y no en todos los Arduinos funcionará igual y, aunque la plataforma Arduino tiene su propia manera de hacer las interrupciones, he querido poner esta forma aquí.

Por último llamo a sei() para activar el flag de interrupciones de Atmega.

Luego en el loop() sólo me encargaré de actualizar el estado del led, apagarlo y encenderlo sin preocuparme por el pulsador. Por último, tenemos ISR(INT0_vect), una función donde estableceremos las acciones que se llevan a cabo cuando se activa la interrupción. En este caso incrementar el número y enviarlo a PORTB.

The post Controlando un display de 7 segmentos con Arduino y un botón por interrupción. appeared first on Poesía Binaria.

by Gaspar Fernández at July 28, 2017 07:50 AM

July 27, 2017

www.rootzilopochtli.com

Celebremos el 18o Día del SysAdmin

Como ya es toda una costumbre, el próximo 28 de Julio, se celebrará internacionalmente el Día del Administrador de Sistemas. Para esta su 18a edición, con el apoyo de varios patrocinadores a SysArmy México, nos reuniremos para compartir historias y anécdotas al lado de una buena botana y una ronda de retas al estilo de la vieja escuela 😉 , la invitación es extendida a quién guste acompañarnos; a los primeros en llegar, SysArmy México les tiene preparadas varias sorpresas:

La cita es en el Arkeid Bar,  cerca de las 7 PM y hasta que las obligaciones nos lo permitan. La dirección es:

Monterrey 230,
Roma Norte,
Cuauhtémoc, CDMX

La reservación esta a nombre de Wendy Fabela.

Allá nos vemos!! 🙂

by Alex Callejas at July 27, 2017 04:51 PM

bofhers.net

July 24, 2017

Poesía Binaria

Obtener información básica sobre procesos del sistema Linux en C y C++ (parte 3)

procesos del sistema

Cuando te independizas y te vas a vivir a un piso o a una casa te preguntas, ¿cómo serán mis vecinos? Por un lado tendremos al típico que deja la basura en la puerta de su casa durante todo el día y esparce olores al resto de los vecinos; o el que desea compartir la música que escucha con los demás y el que cuando entra al edificio y ve que vas a entrar va corriendo al ascensor para no esperarte… Aunque como procesos en ejecución en un entorno Linux muchas veces queremos saber cómo son nuestros vecinos y, al contrario de lo que puede parecer en una comunidad de vecinos, éstos suelen ser mucho más receptivos y dispuestos a darnos información.

Podemos averiguar cuántos procesos hay en ejecución, la memoria o el tiempo de CPU que consumen, PID, PID del padre, threads, usuario y grupos real, usuario efectivo, puntuación OOM, estado actual y mucho más. Y cómo no, accediendo simplemente a archivos del sistema, lo cual nos proporciona una manera muy fácil para acceder independientemente del lenguaje que utilicemos.

Conceptos básicos

Cada vez que se ejecuta un proceso, el sistema operativo nos deja ver información sobre él a través de un directorio (virtual, no está escrito en disco ni nada) llamado /proc/[PID] donde PID es el identificador del proceso o Process ID y éste es un número entre 1 y el valor que podemos ver en /proc/sys/kernel/pid_max. En mi caso:

cat /proc/sys/kernel/pid_max
32768

Por lo tanto, en mi sistema el número máximo que puede tener un PID y, por tanto, el número máximo de procesos que puede haber al mismo tiempo en el sistema es de 32768. Podemos aumentar este número si queremos escribiendo sobre /proc/sys/kernel/pid_max o con:
sudo sysctl kernel.pid_max=65536

El sistema operativo y las aplicaciones que corren sobre él deberán utilizar dicho PID para referirse a un proceso concreto. Por ejemplo el sistema operativo deberá almacenar información relativa a la ejecución del proceso cada vez que necesite memoria, realice eventos de entrada/salida o simplemente pausar y reanudar su ejecución. Otras aplicaciones deberán utilizar este PID para comunicarse con el proceso (por ejemplo mediante señales) o si queremos saber quién es el que más memoria está comiendo.

Información básica del proceso

Para lo que queremos hacer, tendremos que leer el fichero /proc/PID/statm. Esto lo podemos hacer con la línea de comando, por ejemplo buscaremos el proceso emacs (como hay varios, cogeremos el primero y consultaremos información):

pidof emacs
23406 10997 7345
cat /proc/23406/stat
23406 (emacs) S 30548 23406 30548 34835 30548 4194304 53536 589 224 13 1762 284 0 0 20 0 4 0 161959260 731086848 49501 18446744073709551615 4194304 6539236 140735377727232 140735377722352 139924333532780 0 0 67112960 1535209215 0 0 0 17 1 0 0 52 0 0 8637344 21454848 51675136 140735377731945 140735377731964 140735377731964 140735377735657 0

Y en todos los números que vemos en este momento, vamos a poner un cierto orden definiendo cada uno de ellos y el tipo de variable con el que podemos almacenarlo:
  • pid (número, int) – Identificador del proceso.
  • comm (cadena, char [32]) – Nombre del ejecutable entre paréntesis.
  • state (carácter, char) – R (en ejecición), S (bloqueado), D (bloqueo ininterrumpible), Z (zombie), T (ejecución paso a paso), W (transfiriendo páginas).
  • ppid (número, int) – Pid del padre.
  • pgrp (número, int) – Identificador del grupo de procesos.
  • session (número, int) – Identificador de la sesión.
  • tty_nr (número, int) – Terminal que usa el proceso.
  • tpgid (número, int) – Identificador del grupo de procesos del proceso terminal al que pertenece el proceso actual.
  • flags (número natural, unsigned) – Flags del proceso actual.
  • minflt (número natural largo, unsigned long) – Fallos de página menores, que no han necesitado cargar una página de memoria desde disco.
  • cminflt (número natural largo, unsigned long) – Fallos de página menores que han hecho los procesos hijo del proceso actual.
  • majflt (número natural largo, unsigned long) – Fallos de página mayores, que han necesitado cargar una página de memoria desde disco.
  • cmajflt (número natural largo, unsigned long) – Fallos de página mayores que han hecho los procesos hijo del proceso actual.
  • utime (número natural largo, unsigned long) – Tiempo que este proceso ha estado en ejecución en modo usuario. Se mide en ticks de reloj o jiffies.
  • stime (número natural largo, unsigned long) – Tiempo que este proceso ha estado en modo kernel.
  • cutime (número largo, long) – Tiempo que los hijos de este proceso han estado en ejecución en modo usuario.
  • cstime (número largo, long) – Tiempo que los hijos de este proces han estado en ejecución en modo kernel.
  • priority (número largo, long) – Prioridad del proceso. Depende del planificador de procesos activo.
  • nice (número largo, long) – Es la simpatía del proceso. Este valor va de 19 (prioridad baja o generosidad, porque el proceso intenta no consumir mucho) a -20 (prioridad alta o codicia, porque el proceso intenta acaparar CPU).
  • num_threads (número largo, long) – Número de hilos que tiene este proceso (mínimo 1).
  • itrealvalue (número largo, long) – No se usa desde el kernel 2.6.17, ahora siempre vale 0.
  • start_time (número natura largo largo, unsigned long long) – Momento en el que el proceso empezó. Se mide en ticks de reloj desde el arranque del equipo.
  • vsize (número natural largo, unsigned long) – Tamaño ocupado en memoria virtual en bytes.
  • rss (número largo, long) – Páginas que tiene el proceso en memoria RAM actualmente.
  • rsslim (número natural largo, unsigned long) – Límite en bytes del rss del proceso.
  • startcode (número largo, long) – Dirección de memoria donde empieza el código del programa.
  • endcode (número largo, long) – Dirección de memoria donde acaba el código del programa.
  • startstack (número largo, long) – Dirección de memoria donde empieza la pila (pero como la pila va al revés, será la parte de abajo de la pila.
  • kstkesp (número largo, long) – Posición actual del puntero de pila.
  • kstkeip (número largo, long) – Posición actual del puntero de instrucciones.
  • signal (número largo, long) – Obsoleto, se usa información procedente de /proc/PID/status.
  • blocked (número largo, long) – Obsoleto, se usa información procedente de /proc/PID/status.
  • sigignore (número largo, long) – Obsoleto, se usa información procedente de /proc/PID/status.
  • sigcatch (número largo, long) – Obsoleto, se usa información procedente de /proc/PID/status.
  • wchan (número natural largo, unsigned long) – Canal de espera dentro del kernel.
  • nswap (número natural largo, unsigned long) – Número de páginas en memoria swap.
  • cnswap (número natural largo, unsigned long) – Número de páginas en memoria swap de los procesos hijo.
  • exit_signal (número, int) – Señal que se envierá al padre cuando finalice este proceso.
  • processor (número, int) – ID de CPU donde se ejecutó este proceso por última vez.
  • rt_priority (número sin signo, unsigned) – Un número entre 1 y 99 si es un proceso de tiempo real, 0 si no.
  • policy (número sin signo, unsigned) – Política de planificación.
  • delayacct_blkio_ticks (número natural largo largo, unsigned long long) – Retrasos añadidos en ticks de reloj.
  • guest_time (número natural largo, unsigned long) – Tiempo invertido corriendo una CPU virtual.
  • cguest_time (número largo, long) – Tiempo invertido corriendo una CPU virtual por los procesos hijo.
  • start_data (número natural largo, unsigned long) – Dirección de memoria donde empieza el área de datos.
  • end_data (número natural largo, unsigned long) – Dirección de memoria donde acaba el área de datos.
  • start_brk (número natural largo, unsigned long) – Dirección de posible expansión del segmento de datos.
  • arg_start (número natural largo, unsigned long) – Dirección de memoria donde se encuentran los argumentos del programa (argv).
  • arg_end (número natural largo, unsigned long) – Dirección de memoria donde terminan los argumentos del programa (argv).
  • env_start (número natural largo, unsigned long) – Dirección donde empiezan las variables de entorno del programa.
  • env_end (número natural largo, unsigned long) – Dirección donde terminan las variables de entorno del programa.
  • exit_code (número, int) – Código de salida del thread.

Tenemos mucha información que seguramente no necesitemos, y tenemos que leerla. Afortunadamente, casi todo son números y en C podemos hacer algo rápido con scanf.

Obteniendo datos de un proceso en C

El código es algo largo por la cantidad de datos que leo, y eso que sólo leo hasta el rss y presento en pantalla algunos datos menos. Sólo quiero que tengamos una primera aproximación. Debemos tener en cuenta que aunque accedamos a la información como si fueran ficheros, en realidad no tienen que ver nada con el disco. Ni están en disco, ni gastarán tiempo de entrada/salida. Todo debería ser muy rápido porque al final estamos haciendo un par de llamadas al sistema operativo. Para el ejemplo he utilizado fscanf, porque es muy sencillo hacer la lectura y el parseo, aunque habrá algún que otro detalle (o mejor dicho, problema).

Por otro lado, dado lo pequeños que son los archivos también podemos almacenarlos por completo en un buffer y leer de nuestro buffer por si queremos utilizar otro método de lectura y parseo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <unistd.h>
#include <stdio.h>

int main(int argc, char* argv[])
{
    if (argc<2)
        return perror("Falta un argumento"), 1;

    char statFileName[128];             /* /proc/PIC/stat - I think 512 bytes is far enough */
   
    sprintf(statFileName, "/proc/%s/stat", argv[1]);
    /* Podíamos comprobar que argv[1] es numérico y que es de poco
       tamaño, pero para el ejemplo nos vale. */

    FILE *fd = fopen(statFileName, "r");
    if (fd == NULL)
        return perror("No puedo encontrar el proceso especificado"),1;
    char
    state,
      name[32];
    int
      pid,
      ppid,
      pgrp,
      session,
      tty,
      tpgid,
      nlwp;

    unsigned long
    flags,
      min_flt,
      cmin_flt,
      maj_flt,
      cmaj_flt,
      vsize;

    unsigned long long
    utime,
      stime,
      cutime,
      cstime,
      start_time;

    long
    priority,
      nice,
      alarm,
      rss;
   
    fscanf(fd, "%d %s "
                 "%c "
                 "%d %d %d %d %d "
                 "%lu %lu %lu %lu %lu "
                 "%Lu %Lu %Lu %Lu "
                 "%ld %ld "
                 "%d "
                 "%ld "
                 "%Lu "
                 "%lu "
                 "%ld",
                 &pid,
                 name,
                 &state,
                 &ppid, &pgrp, &session, &tty, &tpgid,
                 &flags, &min_flt, &cmin_flt, &maj_flt, &cmaj_flt,
                 &utime, &stime, &cutime, &cstime,
                 &priority, &nice,
                 &nlwp,
                 &alarm,
                 &start_time,
                 &vsize,
                 &rss);
   
    fclose(fd);

    printf ("PID: %d\n"
                    "CMD: %s\n"
                    "Estado: %c\n"
                    "PPID: %d\n"
                    "Tiempo usuario: %Lu\n"
                    "Tiempo kernel: %Lu\n"
                    "Nice: %ld\n"
                    "Threads: %d\n"
                    "Iniciado en: %Lu\n"
                    "Tamaño: %lu\n",
                    pid, name, state, ppid, utime, stime, nice, nlwp, start_time, vsize);
}

El resultado será algo como:

./procesos 4971
PID: 4971
CMD: (firefox)
Estado: S
PPID: 4776
Tiempo usuario: 642512
Tiempo kernel: 41987
Nice: 0
Threads: 60
Iniciado en: 23836769
Tamaño: 5043314688

Sí, el tamaño es ese, firefox ahora mismo me está cogiendo 5Gb de memoria virtual (seguro que dentro de 5 años leeremos esto y parecerá utópico).

Esta información está muy bien, pero no me dice mucho. Por un lado, el tiempo de usuario y kernel tenemos que traducirlo y hacer algo con él, por ejemplo, calcular el % de CPU utilizado, poner la fecha de inicio y el tamaño en formato humano y vamos a quitar los paréntesis al nombre del proceso añadiendo algo más de control de errores, aunque esto último no es estrictamente necesario).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <sys/sysinfo.h>

/* Presenta un intervalo de tiempo (en segundos) en horas:minutos:segundos */
char* timeInterval(char* buffer, size_t bufferSize, unsigned long seconds);
/* Presenta la fecha en formato humano */
char* humanSize(char* buffer, size_t bufferSize, long double size, short precission);
/* Error fatal! */
void panic(char* error);
/* Obtiene uptime del sistema */
long uptime();

int main(int argc, char* argv[])
{
    if (argc<2)
        panic("Falta un argumento");

    char statFileName[128];             /* /proc/PIC/stat - I think 512 bytes is far enough */
   
    sprintf(statFileName, "/proc/%s/stat", argv[1]);
    /* Podíamos comprobar que argv[1] es numérico y que es de poco
       tamaño, pero para el ejemplo nos vale. */

    FILE *fd = fopen(statFileName, "r");
    if (fd == NULL)
        panic("No puedo encontrar el proceso especificado");
   
    char
    state,
      name[32];
    int
      pid,
      ppid,
      pgrp,
      session,
      tty,
      tpgid,
      nlwp;
    double
        pcpu;

    unsigned long
    flags,
      min_flt,
      cmin_flt,
      maj_flt,
      cmaj_flt,
      vsize;

    unsigned long long
    utime,
      stime,
      cutime,
      cstime,
      start_time;

    long
    priority,
      nice,
      alarm,
      rss;

    char buffer[512];
    fgets(buffer, 512, fd);
    char* cstart=strchr(buffer, '('); /* Cogemos el primer ( de la cadena */
    char* cend  =strrchr(buffer, ')'); /* Cogemos el último ) de la cadena */
    strncpy(name, cstart+1, (cend-cstart<33)?cend-cstart-1:32); /* Necesitamos delimitar el nombre a 32 caracteres (por el tamaño de nuestro buffer */
    if ( (cstart == NULL) || (cend == NULL) )
        panic("No se pudo determinar el nombre del proceso");
   
    sscanf(buffer, "%d", &pid);
    sscanf(cend+2, "%c "                    /* +2 para eliminar el ) y el espacio siguientes */
                 "%d %d %d %d %d "
                 "%lu %lu %lu %lu %lu "
                 "%Lu %Lu %Lu %Lu "
                 "%ld %ld "
                 "%d "
                 "%ld "
                 "%Lu "
                 "%lu "
                 "%ld",
                 &state,
                 &ppid, &pgrp, &session, &tty, &tpgid,
                 &flags, &min_flt, &cmin_flt, &maj_flt, &cmaj_flt,
                 &utime, &stime, &cutime, &cstime,
                 &priority, &nice,
                 &nlwp,
                 &alarm,
                 &start_time,
                 &vsize,
                 &rss);
   
    fclose(fd);

    long ticks_sec = sysconf (_SC_CLK_TCK); /* Ticks de reloj por segundo */
    char utimeStr[32], stimeStr[32], start_timeStr[32], vsizeStr[32], startedStr[32];

    /* Calculamos cuándo se inició el proceso */
    struct tm starttm;
    long now = time(NULL);
    time_t started = now - uptime() + start_time/ticks_sec;
    strftime (startedStr, 32, "%d/%m/%Y %H:%M:%S", localtime_r(&started, &starttm));
    /* Como stat nos da segundos*ticks_sec desde que se arrancó el ordenador tendremos
         que operar con el uptime del ordenador y con la fecha y hora actual para
         averiguarlo. */


    unsigned long long procuptime = uptime() - start_time / ticks_sec;
    unsigned long long total_time =  utime + stime;     /* Tiempo total en ejecución. */
    pcpu = (double)total_time / procuptime;
   
    printf ("PID: %d\n"
                    "CMD: %s\n"
                    "Estado: %c\n"
                    "PPID: %d\n"
                    "Tiempo usuario: %s\n"
                    "Tiempo kernel: %s\n"
                    "Nice: %ld\n"
                    "Threads: %d\n"
                    "Iniciado hace: %s\n"
                    "Iniciado el: %s\n"
                    "Tamaño: %s\n"
                    "%% CPU: %lf\n",
                    pid, name, state, ppid,
                    timeInterval(utimeStr, 32, utime/ticks_sec),
                    timeInterval(stimeStr, 32, stime/ticks_sec),
                    nice, nlwp,
                    timeInterval(start_timeStr, 32, uptime() - start_time/ticks_sec),
                    startedStr,
                    humanSize(vsizeStr, 32, vsize, -1),
                    pcpu);
}

char* timeInterval(char* buffer, size_t bufferSize, unsigned long seconds)
{
    int hours = seconds / 3600,
        rem = seconds % 3600,
        minutes = rem / 60,
        secs = rem % 60;
   
    snprintf (buffer, bufferSize, "%d:%d:%d", hours, minutes, secs);
   
    return buffer;
}

char* humanSize(char* buffer, size_t bufferSize, long double size, short precission)
{
    static const char* units[10]={"bytes","Kb","Mb","Gb","Tb","Pb","Eb","Zb","Yb","Bb"};

    char format[10];

    int i= 0;

    while (size>1024) {
        size = size /1024;
        i++;
    }

    if (precission < 0)
        precission=3;

    snprintf(format, 10, "%%.%dLf%%s", precission);
    snprintf(buffer, bufferSize, format, size, units[i]);

    return buffer;
}

long uptime()
{
    struct sysinfo si;
    if (sysinfo(&si) <0)
        panic("No puedo obtener sysinfo()");
   
    long tmp = si.uptime;
    return tmp;
}

void panic(char* error)
{
    fprintf (stderr, "Error: %s (%d - %s)\n", error, errno, strerror(errno));
    exit(-1);
}

Vaya, ¡qué montón de código! Aunque en parte se parece al anterior. En principio se han añadido funciones para representar el tamaño en memoria en formato humano, para representar fechas e intervalos de manera legible y para calcular el tiempo que lleva encendido el ordenador, o uptime, necesario para algunos cálculos que veremos más adelante.

Veamos el resultado de la ejecución de este programa, con firefox, como antes:

./procesos 4971
PID: 4971
CMD: firefox
Estado: S
PPID: 4776
Tiempo usuario: 11:37:0
Tiempo kernel: 0:32:32
Nice: 0
Threads: 63
Iniciado hace: 24:6:45
Iniciado el: 19/07/2017 21:28:00
Tamaño: 5.088Gb
% CPU: 50.000000

Una pequeña consideración sobre los tiempos de usuario y kernel, así como del tiempo total que lleva el proceso. Por un lado, el uptime del proceso, el tiempo que lleva arrancado es la hora actual menos la hora a la que arrancó el proceso. Es decir, si cargué el programa hace 10 minutos, el programa lleva 10 minutos encendido (es una tontería decirlo así, pero se puede confundir más adelante). Por otro lado tenemos los tiempos de kernel y de usuario, que es el tiempo total que el proceso ha hecho algo realmente; el tiempo de usuario podemos considerarlo computación propia del proceso, cuando está parseando un texto, creando ventanas, botones, ejecutando Javascript, etc; en otro plano tenemos el tiempo de kernel, que es el tiempo que el núcleo del sistema operativo ha gastado en el proceso; es decir, el proceso pedirá cosas al sistema operativo, como la lectura de un archivo, acceso a dispositivos, etc.

Eso sí, puede (y es lo más normal) que la suma de los tiempos de kernel y usuario no sea ni por asomo el uptime del proceso. Y está bien, eso es que el proceso ha habido momentos que no ha estado haciendo nada (ha estado en modo Sleeping) y no ha necesitado CPU.

Y veamos los cálculos que se han hecho:

  • Para expresar el tiempo de usuario en segundos, tenemos que dividirlo por los ticks de reloj por segundo. Suelen ser 100 en la mayoría de los sistemas, es una configuración del kernel, pero podemos averiguarlo consultando sysconf (_SC_CLK_TCK). Luego ese intervalo lo transformaremos en horas:minutos:segundos.
  • Para saber cuánto hace que se inició el proceso. Utilizaremos start_time, pero claro, este valor indica cuántos ticks pasaron desde que se arrancó el ordenador hasta que se inició el proceso. Por un lado sabemos transformar de ticks a segundos. Así que restaremos al uptime actual el start_time en segundos.
  • Para saber el momento en el que se inició el proceso. Teniendo claro el punto anterior, éste es fácil. Sólo que tenemos que saber la fecha y hora actuales, que las sacamos en formato UNIX, así que le restamos el uptime y luego le sumamos el start_time…
  • Porcentaje de CPU. ¡Cuidado! Es el porcentaje de CPU total del proceso durante toda su vida. Consideraremos el porcentaje de CPU como la relación entre el tiempo que ha estado el proceso utilizando la CPU y el tiempo total que lleva el proceso arrancado. Es decir, si el proceso lleva arrancado 10 minutos y la suma de tiempos de usuario y kernel es de 2 minutos. El proceso ha consumido un 20% de CPU. Eso sí, puede ser que la suma de los tiempos de kernel y usuario sea mayor que el tiempo que lleva el proceso arrancado. Esto sucederá en aplicaciones multihilo, ya que los tiempos de kernel y usuario están calculados para un sólo núcleo de CPU. Si el proceso ha utilizado 2 núcleos al 100% durante todo el tiempo de vida del proceso, la suma de los tiempos anteriormente comentados será el doble.

No me convence mucho el % de CPU…

Normal, a mí tampoco. Hasta ahora lo hemos calculado de forma absoluta. Es decir, desde que se inició el proceso hasta ahora. Claro, puede que cuando arrancó el proceso utilizara ocho núcleos durante un minuto (8 minutos de tiempo de kernel+usuario) y haya estado 9 minutos casi sin hacer nada. Si ejecutamos top ni vemos el proceso, pero mi aplicación piensa que el proceso se come un 80% de CPU.

Para hacer el cálculo más preciso debemos centrarnos en un intervalo de tiempo. Así, calcularemos los tiempos de kernel+usuario en un momento del tiempo, esperaremos un par de segundos, y luego calculamos de nuevo, hacemos la diferencia y dividimos por el intervalo. Así que en lugar de sacar el porcentaje de CPU desde el principio, calcularemos el porcentaje de CPU para el intervalo que acaba de suceder. De esta forma tendremos una medida más precisa, y si os fijáis, es lo que hace top, espera un tiempo y vuelve a hacer el cálculo.
Para ello tendremos que volver a leer el archivo y volver a parsear stat, por eso en el siguiente ejemplo vais a ver un struct con toda la información y una función que la extrae (un paso más en el programa):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <sys/sysinfo.h>

struct ProcessInfo
{
        char
    state,
      name[32];
    int
      pid,
      ppid,
      pgrp,
      session,
      tty,
      tpgid,
      nlwp;

    unsigned long
    flags,
      min_flt,
      cmin_flt,
      maj_flt,
      cmaj_flt,
      vsize;

    unsigned long long
    utime,
      stime,
      cutime,
      cstime,
      start_time;

    long
    priority,
      nice,
      alarm,
      rss;
};
/* Presenta un intervalo de tiempo (en segundos) en horas:minutos:segundos */
char* timeInterval(char* buffer, size_t bufferSize, unsigned long seconds);
/* Presenta la fecha en formato humano */
char* humanSize(char* buffer, size_t bufferSize, long double size, short precission);
/* Error fatal! */
void panic(char* error);
/* Obtiene uptime del sistema */
long uptime();

struct ProcessInfo getProcessInfo(int pid);

int main(int argc, char* argv[])
{
    if (argc<2)
        panic("Falta un argumento");

    double pcpu;
   
    struct ProcessInfo pi1 = getProcessInfo(atoi(argv[1]));

    long ticks_sec = sysconf (_SC_CLK_TCK); /* Ticks de reloj por segundo */
    char utimeStr[32], stimeStr[32], start_timeStr[32], vsizeStr[32], startedStr[32];

    /* Calculamos cuándo se inició el proceso */
    struct tm starttm;
    long now = time(NULL);
    time_t started = now - uptime() + pi1.start_time/ticks_sec;
    strftime (startedStr, 32, "%d/%m/%Y %H:%M:%S", localtime_r(&started, &starttm));
    /* Como stat nos da segundos*ticks_sec desde que se arrancó el ordenador tendremos
         que operar con el uptime del ordenador y con la fecha y hora actual para
         averiguarlo. */


    unsigned long long total_time_s =  pi1.utime + pi1.stime;   /* Tiempo total en ejecución. */
    sleep(3);
    struct ProcessInfo pi2 = getProcessInfo(atoi(argv[1]));
    unsigned long long total_time_e =  pi2.utime + pi2.stime;   /* Tiempo total en ejecución. */
   
    pcpu = (double)(total_time_e - total_time_s) / 3;
   
    printf ("PID: %d\n"
                    "CMD: %s\n"
                    "Estado: %c\n"
                    "PPID: %d\n"
                    "Tiempo usuario: %s\n"
                    "Tiempo kernel: %s\n"
                    "Nice: %ld\n"
                    "Threads: %d\n"
                    "Iniciado hace: %s\n"
                    "Iniciado el: %s\n"
                    "Tamaño: %s\n"
                    "%% CPU: %lf\n",
                    pi1.pid, pi1.name, pi1.state, pi1.ppid,
                    timeInterval(utimeStr, 32, pi1.utime/ticks_sec),
                    timeInterval(stimeStr, 32, pi1.stime/ticks_sec),
                    pi1.nice, pi1.nlwp,
                    timeInterval(start_timeStr, 32, uptime() - pi1.start_time/ticks_sec),
                    startedStr,
                    humanSize(vsizeStr, 32, pi1.vsize, -1),
                    pcpu);
}

char* timeInterval(char* buffer, size_t bufferSize, unsigned long seconds)
{
    int hours = seconds / 3600,
        rem = seconds % 3600,
        minutes = rem / 60,
        secs = rem % 60;
   
    snprintf (buffer, bufferSize, "%d:%d:%d", hours, minutes, secs);
   
    return buffer;
}

char* humanSize(char* buffer, size_t bufferSize, long double size, short precission)
{
    static const char* units[10]={"bytes","Kb","Mb","Gb","Tb","Pb","Eb","Zb","Yb","Bb"};

    char format[10];

    int i= 0;

    while (size>1024) {
        size = size /1024;
        i++;
    }

    if (precission < 0)
        precission=3;

    snprintf(format, 10, "%%.%dLf%%s", precission);
    snprintf(buffer, bufferSize, format, size, units[i]);

    return buffer;
}

long uptime()
{
    struct sysinfo si;
    if (sysinfo(&si) <0)
        panic("No puedo obtener sysinfo()");
   
    long tmp = si.uptime;
    return tmp;
}

void panic(char* error)
{
    fprintf (stderr, "Error: %s (%d - %s)\n", error, errno, strerror(errno));
    exit(-1);
}

struct ProcessInfo getProcessInfo(int pid)
{
    char statFileName[128];             /* /proc/PIC/stat - I think 512 bytes is far enough */

    struct ProcessInfo pi;
   
    sprintf(statFileName, "/proc/%d/stat", pid);
    FILE *fd = fopen(statFileName, "r");
    if (fd == NULL)
        panic("No puedo encontrar el proceso especificado");
   

    char buffer[512];
    fgets(buffer, 512, fd);
    char* cstart=strchr(buffer, '('); /* Cogemos el primer ( de la cadena */
    char* cend  =strrchr(buffer, ')'); /* Cogemos el último ) de la cadena */
    size_t namesize = (cend-cstart<33)?cend-cstart-1:32;
    strncpy(pi.name, cstart+1, namesize); /* Necesitamos delimitar el nombre a 32 caracteres (por el tamaño de nuestro buffer */
    pi.name[namesize]='\0';
    if ( (cstart == NULL) || (cend == NULL) )
        panic("No se pudo determinar el nombre del proceso");
   
    sscanf(buffer, "%d", &pi.pid);
    sscanf(cend+2, "%c "                    /* +2 para eliminar el ) y el espacio siguientes */
                 "%d %d %d %d %d "
                 "%lu %lu %lu %lu %lu "
                 "%Lu %Lu %Lu %Lu "
                 "%ld %ld "
                 "%d "
                 "%ld "
                 "%Lu "
                 "%lu "
                 "%ld",
                 &pi.state,
                 &pi.ppid, &pi.pgrp, &pi.session, &pi.tty, &pi.tpgid,
                 &pi.flags, &pi.min_flt, &pi.cmin_flt, &pi.maj_flt, &pi.cmaj_flt,
                 &pi.utime, &pi.stime, &pi.cutime, &pi.cstime,
                 &pi.priority, &pi.nice,
                 &pi.nlwp,
                 &pi.alarm,
                 &pi.start_time,
                 &pi.vsize,
                 &pi.rss);
   
    fclose(fd);
    return pi;
}

Línea de comandos y variables de entorno

¿Qué argumentos se han pasado al programa cuando se ejecutó? Si el programa está hecho en C, éste utilizará los famosos argc y argv para acceder a ellos. Pero, ¿un programa externo podrá acceder a esta información? Es lo que nos muestra ps cuando lo llamamos así (centrados en el PID que estamos consultando en este post):

ps ax -o pid,cmd | grep 4971
4971 /usr/lib/firefox/firefox -ProfileManager
24416 grep --color=auto 4971

Como vemos, yo ejecuté firefox con el argumento -ProfileManager, ¿cómo podemos consultarlo? Esta información está en /proc/PID/cmdline y encontraremos los argumentos separados por el carácter terminador, para que esta información sea mucho más fácil de manejar y procesar internamente. Veamos un ejemplo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>


/* Error fatal! */
void panic(char* error);

int main(int argc, char* argv[])
{
    if (argc<2)
        panic("Falta un argumento");

    char cmdlineFileName[128];              /* /proc/PID/cmdline - I think 128 bytes is far enough */

    sprintf(cmdlineFileName, "/proc/%s/cmdline", argv[1]);
    FILE *fd = fopen(cmdlineFileName, "r");
    if (fd == NULL)
        panic("No puedo encontrar el proceso especificado");
  char *arg = 0;
    size_t argsize = 0;
    while(getdelim(&arg, &argsize, '\0', fd) != -1)
        {
      printf ("Argumento: %s\n", arg);
        }
    if (arg)
        free(arg);

    fclose(fd);
}

void panic(char* error)
{
    fprintf (stderr, "Error: %s (%d - %s)\n", error, errno, strerror(errno));
    exit(-1);
}

Si lo ejecutamos, veremos algo parecido a esto:

./cmdline 4971
Argumento: /usr/lib/firefox/firefox
Argumento: -ProfileManager
./cmdline 2526
Argumento: /usr/sbin/dnsmasq
Argumento: --no-resolv
Argumento: --keep-in-foreground
Argumento: --no-hosts
Argumento: --bind-interfaces
Argumento: --pid-file=/var/run/NetworkManager/dnsmasq.pid
Argumento: --listen-address=127.0.1.1
Argumento: --cache-size=0
Argumento: --conf-file=/dev/null
Argumento: --proxy-dnssec
Argumento: --enable-dbus=org.freedesktop.NetworkManager.dnsmasq
Argumento: --conf-dir=/etc/NetworkManager/dnsmasq.d

Como siempre, el primer argumento coincide con el ejecutable del programa y los siguientes serán los argumentos que hemos pasado para modificar su comportamiento. En este ejemplo los imprimimos directamente en pantalla, pero ya está en vuestra mano otro tipo de análisis: almacenarlo en arrays o en listas enlazadas, buscar un argumento en particular, mirar si se ha colado un password (que hay programadores a los que se les pasa esto…), o lo que queráis.

Del mismo modo, pero cambiando el archivo por /proc/PID/environ podemos extraer el valor de las variables de entorno del programa. Y puede haber información muy interesante acerca de la ejecución bajo un entorno de escritorio, sesión SSH (si se ejecutó en remoto), idioma, directorios, informes de errores y demás. Incluso muchos programas, para ejecutarlos utilizan un script lanzador que establece los valores de ciertas variables antes de lanzar la ejecución del binario y lo podemos ver aquí.

Más información de estado del proceso

¿Queremos más información del proceso? Pues miremos /proc/pid/status. Muy parecido a /proc/pid/stat, con la información en un lenguaje más inteligible, incluso con algunos datos más que pueden resultar interesantes como por ejemplo:

  • Cpus_allowed, Cpus_allowd_list: Para saber las CPUs pueden ejecutar código de este proceso
  • voluntary_ctxt_switches y nonvoluntary_ctxt_switches: Cambios de contexto voluntarios e involuntarios
  • Sig*: información sobre señales (que /proc/PID/stat no nos la daba muy bien.
  • Información sobre memoria tanto residente como virtual. Echad un vistazo al fichero para ver el montón de elementos que podemos consultar.

Otros ficheros de interés

Podremos consultar muchas más cosas del proceso. Basta con hacer ls /proc/PID aunque para ahorrar trabajo os dejo aquí algunos de los más interesantes (también tenemos que tener en cuenta que a medida que salen versiones nuevas del kernel Linux podremos ver más información):

  • /proc/PID/maps : Mapa de memoria. Ahí podemos ver rangos de memoria, tipo de acceso (lectura, escritura, ejecución y si es pública o privada) y si hay un fichero mapeado en esa dirección, o estamos en memoria de datos, o es pila, etc. Si estás estudiando Sistemas Operativos es recomendable echarle un ojo a uno de estos archivos, eso sí, empezad por una aplicación pequeña, porque un firefox, o un libreoffice puede ser muy heavy de analizar.
  • /proc/PID/oom_score : Esto tiene que ver con el Out Of Memory Killer. Mirad este post.
  • /proc/PID/mounts : Dispositivos o discos montados de cara a la aplicación.
  • /proc/PID/limits : Límite de memoria, procesos, ficheros abiertos, bloqueos, tiempo de CPU y más que tiene este proceso.
  • /proc/PID/exe : Éste es el ejecutable que se ha cargado. ¡Éste y no otro! Por si alguien nos intenta engañar ejecutando un ejecutable que no es, que está en otra ruta, es otra versión. Aquí tenemos el ejecutable que podremos leer con:
    readelf -a /proc/PID/exe

En definitiva, encontramos mucha información para analizar los procesos en ejecución. Y, si tienes un proyecto al respecto, déjamelo en los comentarios, que lo enlazaré encantado 🙂

Buscar todos los procesos

Por último, un pequeño código de ejemplo para buscar los PID de todos los procesos en ejecución, y poder analizarlos como hace ps, o top. O incluso para que nosotros hagamos alguna clase de análisis de procesos en tiempo real.
La clave está en listar archivos, tal y como lo haría ls. Sólo que dentro de proc y quedarnos con los que tienen aspecto numérico. En mi caso confío un poco en Linux y espero que si un fichero dentro de proc empieza por un número va a ser un PID. Obviamente en proc no suele haber cosas raras, aunque no podemos descartar que algún módulo del kernel pueda hacer de las suyas y tengamos que verificar que todos los caracteres son numéricos y que se trata de un directorio e incluso buscar la existencia de ciertos archivos dentro:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <errno.h>
#include <ctype.h>
#include <dirent.h>
#include <fcntl.h>

/* Error fatal! */
void panic(char* error);

int main(int argc, char* argv[])
{
    DIR* proc_dir;
    struct dirent *ent;
    unsigned total = 0;
    proc_dir = opendir("/proc");
    while ((ent = readdir(proc_dir)))
      {
        if ((*ent->d_name>'0') && (*ent->d_name<='9')) /* Be sure it's a pid */
          {
        printf("%s\n", ent->d_name);
        ++total;
          }
      }
    closedir(proc_dir);
  printf ("Total de procesos: %u\n", total);
}


void panic(char* error)
{
    fprintf (stderr, "Error: %s (%d - %s)\n", error, errno, strerror(errno));
    exit(-1);
}

Una biblioteca en C++ que tiene muchas cosas ya hechas

Después de toda esta guía, voy con el autobombo. Hace tiempo hice un pequeño archivo .h para C++ moderno que entre otras cosas, analiza procesos y guarda las cosas en estructuras muy apañadas para la ocasión. Encontramos el código en GitHub. Con un ejemplo listo para compilar que aclara muchas cosas.
Foto principal: Daryan Shamkhali

The post Obtener información básica sobre procesos del sistema Linux en C y C++ (parte 3) appeared first on Poesía Binaria.

by Gaspar Fernández at July 24, 2017 08:11 AM

July 23, 2017

Blog Bitix

Ejecutar varias tareas de forma concurrente en Java

Java

En el artículo de iniciación a la programación concurrente en Java explicaba las facilidades que proporciona este lenguaje para la programación de tareas con varios hilos que implica la sincronización y bloqueo mediante varias primitivas como semáforos o locks, ponía el ejemplo y su código de dos de los típicos ejemplos que suelen usarse en las asignaturas de sistemas operativos, el problema de los filósofos y el del barbero.

En el caso de tener varias tareas que tardan unos segundos si las ejecutamos de forma secuencial el tiempo que tardarán será la suma de todas las tareas. Si las tareas no son dependientes, no hace falta esperar a que termine una anterior para comenzar otra, o el problema se puede descomponer en varias partes ejecutándolas de forma concurrente y simultáneamente el tiempo total que tardarán aproximadamente será el tiempo de la tarea más lenta.

En la API de Java además de las primitivas de sincronización se ofrece además algunas clases para manejar hilos y tareas a ejecutar de forma concurrente sin tener que manejar los hilos a bajo nivel. La clase ExecutorService permite crear un pool de threads con un número fijo de ellos, el pool reutilizará cada thread para ir ejecutando las tareas. Crear threads es una operación más o menos costosa con lo que reutilizándolos se aprovecha mejor los recursos del sistema y en un número grande de tareas a ejecutar la mejora en el rendimiento quizá se note. Crear un pool con un número fijo y limitado de threads evita que el sistema se sature o por el contrario esté infrautilizado, configurando el tamaño del pool de threads según las características del sistema que las ejecutará y del tipo de recursos que más utiliza las tareas se obtiene el mejor rendimiento posible.

Con el método Runtime.availableProcessors se obtiene el número de núcleos lógicos del ordenador de los modernos procesadores que utilizan Hyper Threading tanto los de Intel como AMD, si las tareas hacen un uso muy intensivo de CPU y poco de entrada/salida el tamaño del pool de threads óptimo será cercano al número de núcleos del procesador. Por el contrario, si las tareas hacen un uso intensivo de de entrada/salida el tamaño del pool de threads óptimo será mayor ya que estarán la mayor parte del tiempo esperando a que finalicen las lentas operaciones de entrada y salida comparadas con la CPU.

Suponiendo que una aplicación ha de realizar varias consultas a una base de datos para presentar su información al usuario, esas consultas y por la cantidad de información que tiene la base de datos o porque los índices no ayudan tardan en ejecutarse 3 segundos, teniendo que realizar 8 de estas consultas el tiempo total que tardará la aplicación en presentar la información será de 24 segundos (8 tareas x 3 segundos/tarea) ejecutando las consultas de forma secuencial. 24 segundos es un tiempo considerable y el usuario pensará que la aplicación no responde. Ejecutando las tareas con un pool de 8 threads el tiempo total empleado para presentar la información será de 3 segundos y con un pool de 4 threads el tiempo será de 6 segundos, mucho menos que los 24 de forma secuencial.

Este es el código para ejecutar tareas de forma secuencial y de forma concurrente con un pool de threads de tamaño el doble del número de procesadores del sistema midiendo además el tiempo total para comprobar la diferencia de tiempos de ambas opciones.

Ejemplo de ejecución secuencial y concurrente

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando ./gradlew run.

by pico.dev at July 23, 2017 11:00 AM

July 19, 2017

Blog Bitix

4 formas de hacer un bucle for en Java

Java

Hasta Java 5 para hacer un bucle desde 0 a N elementos había que usar una variable para mantener un contador, hacer una comparación para comprobar si se había llegado al límite e incrementar la variable en la siguiente ejecución. El código era bastante verboso y dado que los bucles son una construcción básica de cualquier lenguaje de programación es empleada numerosas veces en cualquier algoritmo. Antes de Java 5 un bucle for de 0 a 5 y de una colección se realizaba de la siguiente manera:

En Java 5 el bucle for se enriqueció notablemente, con el foreach se puede recorrer una colección y cualquier objeto que implemente la interfaz Iterable. Con el bucle foreach una Collection se recorre de la siguiente manera.

Pero esto es para las colecciones si se quiere hacer un bucle un número fijo de veces como en el primer caso de 0 a 5 conociendo que para usar el foreach basta que le indiquemos un objeto que implemente la interfaz Iterable podemos usar la siguiente expresión y su implementación que tiene la ventaja de no tener que incluir la expresión de comparación y el incremento de la variable, la clase Counter implementa la interfaz Iterable y devuelve un Iterator sobre los valores del rango indicado:

En Java 8 con la introducción de los Stream y de IntStream podemos usar el método range y rangeClosed para obtener un Stream de enteros y hacer un bucle con un comportamiento similar a los anteriores.

Los Stream de Java 8 están muy bien para simplificar algunas operaciones complejas pero para un bucle for sencillo tiene sus inconvenientes como ofuscar significativamente el stacktrace en caso de producirse alguna excepción. Se puede usar cualquier opción pero la primera con el tradicional bucle for sea la menos recomendable teniendo a nuestra disposición la clase Counter con Java 5 o los Stream y lambdas con Java 8.

El siguiente programa muestra las cuatro opciones, su salida en la consola sería el siguiente:

4 formas de hacer un bucle en Java

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando ./gradlew run.

by pico.dev at July 19, 2017 08:30 PM

July 14, 2017

Blog Bitix

Iniciación a la programación concurrente en Java

Java proporciona en su API numerosas primitivas para realizar programación concurrente. La programación concurrente permite realizar varias tareas simultáneamente aprovechando los múltiples núcleos de los procesadores modernos con un tiempo de ejecución total para un conjunto de tareas significativamente menor. Dos de los problemas de concurrencia más conocidos son el problema de los filósofos y del barbero que en este artículo muestro como implementar usando varias de las primitivas ofrecidas por Java.

Java

En todo el tiempo que llevo programando en Java no he tenido necesidad de conocer en detalle las primitivas de concurrencia que ofrece el lenguaje y la API. Java desde sus primeras versiones ya ofrecía el soporte básico para la programación concurrente con las clases Thread y Runnable y algunas primitivas de sincronización como la palabra clave reservada syncrhonized, los locks intrínsecos de los objetos y algunos métodos de la clase Thread como sleep, wait y join. Entre la documentación de Java está el siguiente tutorial sobre la concurrencia en Java que es muy recomendable leer.

Las computadoras realizan varias tareas de forma concurrente con la ayuda del sistema operativo que permite compartir el procesador para realizar diferentes tareas (navegar por internet, editar un documento, escuchar música, …) cambiando cada muy poco tiempo (medido en ms) entre procesos, con los procesadores de varios núcleos las tareas se ejecutan silmultáneamente en diferentes núcleos. Los threads en Java se comunican principalmente compartiendo referencias a objetos, este tipo de comunicación es eficiente pero posibilita dos tipos de errores, interferencias entre threads y errores de consistencia, la herramienta para evitarlos es la sincronización. Sin embargo, la sincronización introduce contención cuando dos o más hilos intentan acceder al mismo recurso simultáneamente y provocan una pérdida de rendimiento. El bloqueo mutuo o deadlock, la inanición o starvation y un bloqueo vivo o livelock son problemas de la sincronización. Seguramente te suenen los objetos inmutables, en la programación concurrente son especialmente útiles dado que su estado no cambia y no pueden corromperse ni quedar en un estado inconsistente por la interferencia entre threads evitando de esta manera errores que suelen ser difíciles de depurar por ofrecer un comportamiento errático.

En vez de usar los locks implícitos de los objetos la API de Java para concurrencia ofrece varios tipos más con propiedades adicionales como la habilidad de salir si el intento de adquirir el lock falla. En el paquete java.util.concurrent.locks está listados. Otro tipo de primitivas de sincronización para threads son los Semaphore, CyclicBarrier y CountDownLatch entre otros como Phaser y Exchanger. En el paquete java.util.concurrent.atomic hay varios tipos de datos básicos que realizan sus operaciones de forma atómica como por ejemplo contadores.

Con los Executors y ExecutorService no hace falta que manejemos los hilos a bajo nivel, es posible obtener un pool de threads de una tamaño específico y enviar clases Callable o Runnable que devuelven un resultado para que se ejecuten con un thread del pool cuando esté libre. Con la clase ScheduledExecutorService se programa la ejecución de tareas de forma periódica. En los streams añadidos a Java 8 el procesamiento se puede realizar de forma paralela aprovechando los microprocesadores multinúcleo sin tener que usar de forma explícita ninguna de las utilidades anteriores, internamente usa el Fork/Join.

El soporte para la programación concurrente ofrecido en Java es suficiente para la mayoría de tareas que podamos necesitar y ha mejorado bastante desde las primeras versiones.

El primer ejemplo que muestro es usando concurrencia ejecutar varias tareas y como realizándolas de forma secuencial el tiempo total empleado es la suma del tiempo de las tareas individuales y como usando concurrencia es la suma de la tarea que más tarda. El ejemplo se trata de 8 tareas que de forma secuencial tardan aproximadamente 24 segundos ya que cada tarea emplea 3 segundos, en el caso empleando concurrencia el tiempo es de aproximadamente 6 segundos ya se se emplea en pool de threads de 4 de capacidad con lo que las primeras 4 tareas tardan 3 segundos y el siguiente lote de 4 tareas tarda otros 3 segundos para un total de 6 segundos.

Ejecución secuencial y concurrente de tareas

Dos de los problemas más conocidos en la programación concurrente son el de La cena de los filósofos y el de El barbero durmiente. Usando algunas de las primitivas comentadas en este artículo este sería el código para para resolver ambos problemas en Java.

En este código del problema de los filósofos la clase Table crea los filósofos asignándoles los Fork que tienen que compartir para comer después de estar un tiempo pensando. En la ejecución se observa que el primer filósofo que intenta comer puede hacerlo ya que sus tenedores adyacentes está libres pero posteriormente se observa que en algunas ocasiones algún filósofo no puede hacerlo porque sus tenedores están siendo usados por alguno de sus compañeros adyacentes.

Ejemplo de concurrencia de los filósofos

En el caso de ejemplo del barbero cuando solo hay un barbero los clientes se acumulan ya que estos entran en la tienda a razón de 1 entre 1500 y 3500ms y el barbero tarda afeitar un cliente entre 2000 y 7000ms. Poniendo en la barbería dos barberos los clientes ya no se acumulan en la sala de espera.

Ejemplo de concurrencia del barbero (1 barbero)
Ejemplo de concurrencia del barbero (2 barberos)

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando ./gradlew run.

by pico.dev at July 14, 2017 10:00 PM

enavas.blogspot.com.es

Error al actualizar el paquete openssh mediante Chocolatey

Si habéis instalado el paquete openssh en Windows mediante Chocolatey incluyendo el servicio ssh, al actualizar el paquete obtendréis un error si no indicáis como parámetro que debe actualizarse el servicio ssh también.

Para actualizar correctamente tanto el servicio como el cliente, ejecutaremos el comando choco de la siguiente manera:
C:\WINDOWS\system32>choco upgrade -y openssh --params='/SSHServerFeature'
Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at July 14, 2017 03:11 PM

July 13, 2017

enavas.blogspot.com.es

Copiar nuestra clave pública y privada a un nuevo equipo

Cuando tenemos un par de claves pública/privada que utilizamos para firmar paquetes, cifrar mensajes, etc... podemos exportarlas en el equipo donde se encuentran almacenadas e importarlas en otro equipo de la siguiente manera:

Exportar nuestra clave privada:
$ gpg --export-secret-keys -a keyid > my_private_key.asc
Exportar nuestra clave pública:
$ gpg --export -a keyid > my_public_key.asc
Importar nuestra clave privada:
$ gpg --import my_private_key.asc
Importar nuestra clave pública:
$ gpg --import my_public_key.asc
Donde keyid es el identificador de la clave que queremos exportar/importar. Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at July 13, 2017 11:12 AM

La Consejería de Educación de Extremadura nos obliga a abandonar las Secciones Bilingües

La ORDEN de 20 de abril de 2017 por la que se regula el programa de Secciones Bilingües en centros docentes sostenidos con fondos públicos de la Comunidad Autónoma de Extremadura y se establece el procedimiento para su implantación en las diferentes etapas educativas, junto con la CIRCULAR Nº 5/2017, de 8 de Junio de 2017 de la Secretaría General de Educación, relativa a la obligatoriedad de cursar dos lenguas extranjeras en el programa de secciones bilingües, obliga a que muchos de nuestros hijos abandonen las secciones bilingües.

Hemos enviado sendos escritos vía registro y email, con fecha del 29 de junio de 2017 tanto a la Consejería como a la Dirección Provincial de Cáceres, informando de que:
  • Esta circular y la correspondiente orden, coartan la libre elección de itinerario del alumno, introduciendo la obligación de cursar una segunda lengua extranjera para el alumnado de la Sección Bilingüe. 
  • Esta obligación no se encontraba incluida en las condiciones iniciales firmadas por los padres a la hora de inscribir a la alumna en la Sección Bilingüe.
  • Dicha obligación varía notablemente las condiciones, perjudicando a aquellos alumnos que no hayan cursado esa segunda lengua extranjera en el curso o cursos anterior/es, por no disponer de los conocimientos previos que se deberían haber adquirido previamente.
  • Una modificación como la que se introduce en esta orden, tan sólo debería ser de aplicación para aquellos alumnos que comiencen en el primer curso de la Sección Bilingüe, siendo convenientemente informados.
Y solicitando que se elimine la obligación de cursar una segunda lengua extranjera para todos aquellos alumnos que se encuentren inscritos en la sección Bilingüe y no hayan cursado esa segunda lengua extranjera en el curso o cursos anterior/es, permitiéndoles solicitar otra asignatura optativa disponible en el centro.

Pero ni han respondido ni responderán. Está claro que no importa hacer las cosas bien, ni que un cambio así perjudique a alumnos que no hayan cursado la segunda lengua en el/los curso/s anteriores.

Para justificar su mala instrucción, en el punto 6 de la circular dicen textualmente que "Los centros docentes adoptarán las medidas necesarias para que, si hubiera alumnado en el programa de Sección Bilingüe que no hubiera cursado en el año académico inmediatamente anterior una determinada lengua extranjera, este pueda progresar de forma adecuada".

¿Alguien me podría decir qué significa ésto? ¿Que se aprobará al alumno directamente?, ¿que se bajará el nivel de la clase para adaptarlo a todos los alumnos?, ¿que aquellos alumnos que no hayan cursado en el año inmediatamente anterior la segunda lengua recibirán clases extra? Enfin, que el párrafo anterior no concreta nada acerca de las medidas a adoptar y me da la impresión de que se pasa la pelota directamente al profesor y cada uno que se las apañe como pueda...

Y yo digo, ¿no sería más sencillo y lógico que la orden y la correspondiente circular excluyeran de esta obligatoriedad a alumnos que no hayan cursado la segunda lengua en años académicos anteriores y sólo fuera obligatorio para aquellos que comiencen en el primer curso de la sección bilingüe habiendo sido debidamente informados? ¿O es que sólo importan los titulares?
Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at July 13, 2017 08:11 AM

July 12, 2017

Poesía Binaria

Permitir que nuestros usuarios ejecuten tareas controladas en nombre de otro. #SUID #SGID – Con ejemplos y ataques

Uno de los puntos fuertes de un sistema Unix es su forma de gestionar los privilegios de usuario. Se suele decir que el malware en GNU/Linux sólo afecta al usuario por el que entra (y podrá hacer todo lo que éste pueda hacer), por lo tanto será muy difícil (nada es imposible, y siempre hay bugs) que un programa ejecutado con privilegios de usuario normal afecte al sistema completo.

Eso sí, otro de los puntos fuertes de un sistema tipo Unix, es que nos deja automatizar absolutamente todo. Podemos crear sistemas que trabajen solos, que atiendan a eventos y éstos disparen acciones dentro del sistema, casi sin límite. Como muchas tareas dependen de datos externos, se ejecutan multitud de programas (cada uno de su padre y de su madre), si queremos mantener un sistema seguro, debemos hacer que el usuario que haga esa automatización de tareas sea un usuario con los menores privilegios posibles. Aunque puede que alguna vez necesite ejecutar algo con mayores privilegios, incluso privilegios root.

Una breve introducción (permisos sobre archivos)

En este tipo de sistemas, cuando consultamos los permisos de acceso de un archivo (por ejemplo con ls), veremos algo como esto:

ls -latr test
-rwxr-xr-- 1 gaspy oficina 8608 mar 11 20:40 test

Veremos (de derecha a izquierda) el nombre, la fecha, el tamaño, el grupo, el usuario, número de enlaces y privilegios. Lo que nos interesa son los privilegios. Son 10 caracteres, primero encontramos un carácter que indicará si es un archivo, directorio, enlace, pipe, socket o cualquier otra cosa, y luego tres grupos de tres que pueden ser r (readable), w (writable) y x (executable); es decir, cada grupo puede tener activa la lectura, escritura y la ejecución de forma individual dependiendo de lo que puede hacer con el archivo.
El primer grupo, que en este caso es rwx, corresponde al dueño del fichero, el usuario (u) que aparece al lado, es decir, gaspy. En este caso, el usuario gaspy podrá leer, escribir y ejecutar el fichero.
El segundo grupo, que es r-x (como vemos, no tiene la w), corresponde a los permisos que tendrá cualquier usuario que pertenezca al grupo (g), es decir, cualquier usuario del grupo oficina sólo podrá leer y ejecutar el archivo.
El tercer grupo, r– (no tiene w, ni x), corresponde a los permisos que tendrá cualquier otro usuario del sistema (o), vamos un usuario que no sea el dueño, ni pertenezca al grupo oficina sólo podrá leer el archivo.

Bueno, no digo nada de root porque éste lo puede hacer todo, ya lo dice el dicho: “Cada user en su home y root en la de todos”.

Eso sí, como vemos, cada grupo puede tener cualquier combinación de rwx para un mismo archivo, cada elemento (rwx) corresponde con un bit, lo que hacen que los permisos se representen con 3bits. Además cada grupo puede tener ocho combinaciones diferentes de rwx (—, –x, -w-, -wx, r–, r-x, rw-, rwx) por lo que podemos representarlas por un número entre el 0 y el 7. Por lo tanto, muchas veces podremos representar los permisos con su forma numérica, incluso con 3 números, podríamos representar los permisos de los tres grupos. Por ejemplo, podría ser 754 (ningún número podrá ser mayor a 7).

Para cambiar los permisos de un archivo, podemos hacerlo con chmod:

chmod o+r mi_archivo

Con esta línea, daremos permiso de lectura a cualquier usuario sobre el archivo mi_archivo. También podremos hacer:

chmod 777 test

Ahora estaremos dando permiso de lectura/escritura/ejecución sobre el archivo test a todo el mundo.

SETUID y SETGID

Estos bits indican que vamos a ejecutar dicho archivo como si fuéramos el usuario y/o el grupo dueños del archivo. Por lo tanto podremos hacer cosas que tal vez el usuario normal no puede hacer. Y es común utilizar estos bits para hacer que un usuario ejecute tareas como root o como cualquier otro usuario que especifiquemos. Eso sí, debemos definir bien los permisos.
Vamos a empezar con un ejemplo sencillo, primero vamos a crear un programa en C que ponga en pantalla el usuario actual, en realidad debería indicar el usuario efectivo, este usuario efectivo será el que verifique el sistema operativo para casi todas las tareas. Normalmente coinciden, pero en este tipo de casos se separan los caminos de cada uno y aunque un programa realmente lo lanza un usuario sin privilegios, el usuario efectivo debería ser root.
El programa en C será el siguiente (muy sencillo, sin comprobación de errores y lo llamaremos quiensoy.c):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <pwd.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    struct passwd *pww;

    pww = getpwuid(geteuid());
    printf ("USER: %s\n",  pww->pw_name);

    return 0;
}

Ahora compilamos, y ejecutamos:

gcc -o quiensoy quiensoy.c
./quiensoy
USER: gaspy

Luego le damos privilegios (con el usuario www-data, por ejemplo. Podría ser root si queremos):

sudo chown www-data:www-data quiensoy
sudo chmod u+s quiensoy
./quiensoy
USER: www-data

Dejo aquí un ejemplo con el que podemos ver también el grupo, usuario real y demás.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <sys/types.h>
#include <unistd.h>

int main()
{
    struct passwd *pww;
    struct group *grp;

    pww = getpwuid(geteuid());
    printf ("USER EFECTIVO: %s\n",  pww->pw_name);

    pww = getpwuid(getuid());
    printf ("USER REAL: %s\n",  pww->pw_name);

    grp = getgrgid(getgid());
    printf ("GRUPO REAL: %s\n",  grp->gr_name);

    grp = getgrgid(getegid());
    printf ("GRUPO EFECTIVO: %s\n",  grp->gr_name);

    return 0;
}

Ahora si compilamos, establecemos permisos y damos SGID y SUID veremos lo que pasa:

gcc -o quiensoy quiensoy.c
sudo chown www-data:openvpn quiensoy
sudo chmod u+s quiensoy
sudo chmod g+s quiensoy
./quiensoy
USER EFECTIVO: www-data
USER REAL: gaspy
GRUPO REAL: gaspy
GRUPO EFECTIVO: openvpn

De este modo podremos ejecutar acciones como si fuéramos otro usuario. Aunque tenemos que tener cuidado con lo que dejamos hacer a la gente.

SUID y SGID en scripts

Esto supone una gran brecha de seguridad. Si, por ejemplo el usuario pudiera escribir el script o crear un enlace a un fichero que llame el script, o sustituir algún programa (por ejemplo, un programa que use which para buscar un ejecutable y creemos un equivalente en una ruta a la que sí tengamos acceso… o bueno, se nos pueden ocurrir mil cosas por las cuales esto no sería seguro. Así que muchos sistemas operativos tipo Unix no te van a dejar… bueno sí te van a dejar, pero harán caso omiso del SUID/SGID que le hayamos dado, incluyendo las últimas versiones del kernel Linux. Aunque existe un ataque típico que consiste en aprovecharse del tiempo que tarda el kernel en leer en #! de comienzo del script así como el intérprete y cargar todo en memoria para hacer el cambiazo del script.

De todas formas, si queremos comprometer un sistema es un buen punto para probar, porque podemos alcanzar privilegios de forma muy fácil.

Hasta hace relativamente poco, podíamos utilizar scripts en perl con SUID, pero las últimas versiones ya no lo permiten. Podemos pensar que App Packer para perl nos haría el trabajo sucio, ya que crea un ejecutable directamente con nuestro script. Pero, tras unas comprobaciones de seguridad que hacen los ejecutables no es posible hacerlo. Existe una versión parcheada, pero si no es para experimentar yo no la usaría.

Otra cosa que podemos hacer es utilizar scripts en Python y compilarlos con cython. Si no queremos hacer programas en C, que a veces es la solución más pesada y con un script podemos hacer las cosas mucho más rápido. Los ejecutables quedarán algo grandes, pero es lo que tiene utilizar otro lenguaje y luego traducirlo. Podemos hacer algo como esto:

1
2
3
4
5
6
#!/usr/bin/python3

import os
import pwd

print ("QUIÉN SOY? {}".format(pwd.getpwuid(os.geteuid()).pw_name))

Ahora compilamos, asignamos permisos y demás:

cython --embed -3 quiensoy.py
gcc -I/usr/include/python3.5m quiensoy.c -o quiensoy -lpython3.5m
sudo chown root:root quiensoy
sudo chmod u+s quiensoy
./quiensoy
QUIÉN SOY? root

Envolventes de scripts

No lo recomiendo, para nada. Pero alguna vez, y sobre todo para hacer experimentos, está muy bien. El objetivo es crear un programa en C que ejecute un script y lo haga con privilegios del usuario elegido. Podemos hacerlo de múltiples maneras, ya que es un programa muy pequeño que sólo se encarga de llamar a otro programa:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <unistd.h>
#include <errno.h>
#include <stdio.h>

int main( int argc, char ** argv )
{
              if( setgid(getegid()) ) perror( "setgid" );
              if( setuid(geteuid()) ) perror( "setuid" );

              execl("./miscript", "./miscript", (char *) 0);

              return errno;
}

Pero vamos, no es nada recomendable, un usuario podría llegar a cambiar el contenido de miscript. Por ejemplo, en este programa (vulnerable por definición) podría cambiar la ruta desde la que se ejecuta el programa y así ./miscript seguramente no sea quien creemos que es. O simplemente podemos atacar una llamada de comando falseando la variable $PATH o cualquier otra variable de entorno.

De todas formas utilizar una envoltura de este tipo es prácticamente igual a utilizar sudo, que debidamente configurado y actualizado podría ser incluso más seguro.

Seguridad

¡ Ataques ! ¡ Ataques !
Es cierto que ningún sistema es 100% libre de fallos, y que cuanto menos código o programas ejecutemos con privilegios, mejor para nosotros y nuestra seguridad (menos puntos de rotura del sistema). De todas formas hay varios ataques clásicos y típicos para los programas ejecutados con SETUID/SETGID. En casi todos los sistemas están arreglados pero, tal vez nos encontremos ante un Unix pequeño (sobre todo de sistemas empotrados) o incluso en nuestra facultad tengan un sistema Unix de hace unos cuantos años y tengamos la necesidad de romperlo.

El primero de los ataques es un ataque IFS. Si has curioseado shell scripts, habrás visto que IFS es el Internal Field Separator, es decir, el separador de campos, o palabras, o comandos, etc. Entonces podríamos crear un archivo llamado “bin”, hacerlo ejecutable y poner lo que queramos ejecutar con privilegios. Al mismo tiempo, asignaremos a IFS el valor ‘/‘ (la barra de separación de directorios), para que cuando una envoltura ejecute ./miscript y el script intente procesar el intérprete ejecute en realidad nuestro fichero bin. Afortunadamente no suele funcionar desde hace muchos años, pero claro, siempre hay implementaciones pequeñas para IOT donde puede que funcione.

Otro ataque importante es el de la precarga de bibliotecas. Normalmente como usuarios podemos sustituir las bibliotecas que se cargan cuando ejecutamos un programa. Esto es muy útil para solucionar problemas en ciertos programas (sobre todo si no disponemos del código fuente), mantener retrocompatibilidad con bibliotecas y algunas cosas más. Aunque si lo llevamos al terreno de las maldades, podríamos sustituir todas las llamadas a printf() por lo que nosotros queramos, como abrir un intérprete de comandos, por lo que nada más ejecutar el primer printf() el programa abrirá un bash/sh/dash/etc. Eso sí, si el programa tenía activado el SUID o SGID, la shell la abrirá con el usuario dueño del archivo, lo cual puede ser muy malo. Afortunadamente, en la mayoría de sistemas esto ya no es un problema.

Otro posible ataque es debido a bugs de los programas instalados. Por ejemplo, hace poco tiempo, la aplicación nmap, muy útil para auditoría de red tenía el bit SUID definido en algunas distribuciones Linux, con lo que podíamos acceder a un modo interactivo y ejecutar un intérprete de comandos, con lo que teníamos root en muy poco tiempo. ¿Necesita nmap ese SUID? Si estamos en un servidor, ¿necesitamos nmap?
De todas formas, es una buena práctica de seguridad tener un listado de todos los archivos con SUID o SGID. De la siguiente forma:

find / -user root -perm -u=s -type f
/usr/sbin/pppd
/usr/bin/pkexec
/usr/bin/nvidia-modprobe
/usr/bin/passwd
/usr/bin/sudo
/usr/bin/gpasswd
/usr/bin/chsh
/usr/bin/chfn
/usr/bin/newgrp

Y de la misma forma que ponemos -u=s para SUID, probaremos -g=s para SGID. Lo primero es preguntarnos, ¿necesitamos todo esto?. Si es nuestro trabajo estar al tanto de la seguridad del sistema, deberíamos revisar uno a uno todos los archivos que se pueden ejecutar, y no estaría de más crear un informe sobre cada uno de ellos, para revisarlo en el futuro.
Además, es importante hacer esto de forma periódica para ver que no hay cambios, o asegurarnos de que los cambios están controlados.

OverlayFS exploit. Podemos probarlo, afectaba desde Linux 3.13 hasta Linux 3.19. Podemos encontrarlo aquí. Sólo hay que compilarlo y veremos si el programa nos permite escalar privilegios

SUID/SGID en nuestro día a día

Seguramente hayas utilizado esta característica en el pasado casi sin darte cuenta. Ya que necesitaríamos privilegios especiales para escribir cualquier archivo sobre el que no tengamos permiso, por ejemplo como hace la orden passwd. Este comando, que sirva para cambiar nuestra contraseña de usuario deberá escribir sobre un archivo que ni tan solo podemos leer por cuestiones de seguridad, /etc/shadow y para hacerlo, necesitamos obligatoriamente permisos de superusuario. Si hacemos stat podremos ver:

stat /usr/bin/passwd
Fichero: ‘/usr/bin/passwd’
Tamaño: 54256      Bloques: 112        Bloque E/S: 4096   fichero regular
Dispositivo: 813h/2067d Nodo-i: 203318      Enlaces: 1
Acceso: (4755/-rwsr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Acceso: 2017-06-27 22:23:51.194148876 +0200
Modificación: 2017-05-17 01:37:35.000000000 +0200
Cambio: 2017-05-22 02:50:43.470092977 +0200
Creación: --

Por supuesto, sudo. Cómo si no se las apaña para cambiar el usuario antes de hacer la ejecución de un programa. Aunque tenemos que cumplir con la propia seguridad de sudo (archivo sudoers).

Ping… ¡ehh! ¿Por qué ping requiere privilegios? ping lo utilizamos muchas veces para probar la red, saber si tenemos conexión y saber el tiempo de respuesta de un servidor. Pero ping necesita acceso directo a los protocolos de red y eso sólo lo puede hacer root.

Otros comandos podrían ser mount / umount, mlocate y algunos más. Nosotros incluso podríamos crear algunos programas para la administración de nuestros servidores, toma de decisiones, y mucho más. Eso sí, con mucho cuidado, y estudiando las posibilidades de un usuario o malware a afectar nuestra máquina. A veces, ésta no siempre es la mejor solución.

Foto principal: Alex Knight

The post Permitir que nuestros usuarios ejecuten tareas controladas en nombre de otro. #SUID #SGID – Con ejemplos y ataques appeared first on Poesía Binaria.

by Gaspar Fernández at July 12, 2017 08:12 AM

July 11, 2017

enavas.blogspot.com.es

Crear paquete deb para instalar más fácilmente VirtualBox Extension Pack

No entiendo por qué Oracle crea un paquete para instalar VirtualBox en distribuciones basadas en Debian y, sin embargo, no lo hace con el VirtualBox Extension Pack. 

Para facilitar la tarea de instalarlo en los equipos de mi centro, yo sí creo un paquete que realiza la instalación desatendida, según el procedimiento que vimos en el post anterior. De este modo, se instala y actualiza automáticamente desde mi repositorio local.

No publico el paquete porque los términos de licencia de VirtualBox no lo permiten:
9. Can I redistribute the VirtualBox Extension Pack?
No. Neither the Personal Use and Evaluation License nor the Oracle VM VirtualBox Enterprise license allows you to distribute the VirtualBox Extension Pack binaries. So you may not make them available on your own websites or other mirrors or distribute them in any other way.
Pero es muy fácil empaquetarlo uno mismo.
Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at July 11, 2017 10:01 AM

Instalar VirtualBox Extension Pack de forma desatendida

En el post anterior vimos cómo instalar VirtualBox Extension Pack de forma interactiva:

Descargamos el VirtualBox Extension Pack correspondiente a la versión que estamos instalando desde https://www.virtualbox.org/wiki/Downloads:
# wget http://download.virtualbox.org/virtualbox/5.1.22/Oracle_VM_VirtualBox_Extension_Pack-5.1.22-115126.vbox-extpack
Este paquete nos proporciona soporte para dispositivos USB 2.0 y USB 3.0, VirtualBox RDP, encriptación de discos, NVMe y arranque PXE para tarjetas Intel. Cuando lo hayamos descargado, no tenemos más que instalarlo:
# vboxmanage extpack install Oracle_VM_VirtualBox_Extension_Pack-5.1.22-115126.vbox-extpack --replace
Nos pedirá que aceptemos la licencia. Aceptamos y si todo ha ido bien, veréis el progreso de la instalación:
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Successfully installed "Oracle VM VirtualBox Extension Pack".
Y listo.

Ahora bien, en muchas ocasiones nos va a interesar realizar la instalación de forma desatendida, sin que nos pida aceptar la licencia. En este caso, si realizamos la instalación manual desde un terminal, veremos un mensaje como el siguiente:
For batch installaltion add
--accept-license=715c7246dc0f779ceab39446812362b2f9bf64a55ed5d3a905f053cfab36da9e
to the VBoxManage command line.
Lo que quiere decir que podemos realizar la instalación desatendida simplemente añadiendo el parámetro de aceptación con el código de licencia:
# vboxmanage extpack install Oracle_VM_VirtualBox_Extension_Pack-5.1.22-115126.vbox-extpack --replace --accept-license=715c7246dc0f779ceab39446812362b2f9bf64a55ed5d3a905f053cfab36da9e
Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at July 11, 2017 09:47 AM

Instalar VirtualBox + VirtualBox Extension Pack en Ubuntu desde la línea de comandos

Vamos a ver cómo instalar VirtualBox y VirtualBox Extension Pack en Ubuntu desde un terminal porque hay alguna cosilla que ha cambiado respecto al post que escribí en junio de 2016.

Para empezar, decir que podéis descargar los paquetes de VirtualBox y VirtualBox Extension Pack directamente desde la web de Oracle e instalarlos manualmente:
http://www.oracle.com/technetwork/es/server-storage/virtualbox/downloads/index.html

El paquete VirtualBox se encuentra disponible con licencia GPLv2 para las plataformas Windows, Mac OS X, Linux y Solaris.

En cuanto al paquete VirtualBox Extension Pack, es gratuito para uso personal, educativo o de evaluación bajo los términos de la Licencia de uso y evaluación personal de VirtualBox en plataformas Windows, Mac OS X, Linux y Solaris x-86.

Otra posiblidad es utilizar los repositorios oficiales. Así que, lo primero será añadir los repositorios a nuestra lista:
# echo "deb http://download.virtualbox.org/virtualbox/debian $(lsb_release -cs) contrib" > /etc/apt/sources.list.d/virtualbox.list
Una vez añadido el repositorio, descargamos la clave pública y la añadimos al anillo de claves.

Podemos descargar la clave del repositorio:
  • Desde aquí para Debian 8 ("Jessie") / Ubuntu 16.04 ("Xenial")
  • Y desde aquí para distribuciones más antiguas.
Y añadirla al anillo de claves manualmente:

Para Debian 8 ("Jessie") / Ubuntu 16.04 ("Xenial"):
# apt-key add oracle_vbox_2016.asc
Para distribuciones más antiguas:
# apt-key add oracle_vbox.asc

O descargarla y añadirla directamente:

Para Debian 8 ("Jessie") / Ubuntu 16.04 ("Xenial"):
# wget -q https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | sudo apt-key add -
Para distribuciones más antiguas:
# wget -q https://www.virtualbox.org/download/oracle_vbox.asc -O- | sudo apt-key add -
A continuación, actualizamos los índices de los repositorios:
# apt-get update
E instalamos el paquete VirtualBox. La última versión disponible a día de hoy es la 5.1:
# apt-get install virtualbox-5.1
Instalamos también el paquete dkms, si no lo hemos instalado aún, para asegurar que los módulos del kernel de VirtualBox (vboxdrv, vboxnetflt y vboxnetadp) se actualicen cada vez que cambie el kernel:
# apt-get install dkms
Por último, descargamos el VirtualBox Extension Pack correspondiente a la versión que estamos instalando desde https://www.virtualbox.org/wiki/Downloads:
# wget http://download.virtualbox.org/virtualbox/5.1.22/Oracle_VM_VirtualBox_Extension_Pack-5.1.22-115126.vbox-extpack
Este paquete nos proporciona soporte para dispositivos USB 2.0 y USB 3.0, VirtualBox RDP, encriptación de discos, NVMe y arranque PXE para tarjetas Intel. Cuando lo hayamos descargado, no tenemos más que instalarlo:
# vboxmanage extpack install Oracle_VM_VirtualBox_Extension_Pack-5.1.22-115126.vbox-extpack --replace
Nos pedirá que aceptemos la licencia. Aceptamos y si todo ha ido bien, veréis el progreso de la instalación:
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Successfully installed "Oracle VM VirtualBox Extension Pack".
Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at July 11, 2017 09:21 AM

July 09, 2017

Ruben J Garcia

Programacion funcional en Java – Libro con 50% descuento

Consigue el libro programacion funcional en Java con un 50% de descuento hasta que se complete. Se el primero en comprarlo y llevatelo a mitad de precio

Consiguelo aqui

El estado del libro es de un 45% completo y los capitulos escritos hasta el momento son:

  • Capitulo 1: La belleza de la pureza
  • Capitulo 2: Composicion de funciones
  • Capitulo 3: Funciones de orden superior
  • Capitulo 4: Currificacion
  • Capitulo 5: Las colecciones como nunca las habias visto
  • Capitulo 6: El poder de la evaluacion perezosa
  • Capitulo 7: Recursion

Otros temas a tratar que seran escritos proximamente son:

  • Tipos de datos algebraicos
  • Higher Kinded Types
  • Programacion monadica: Funtores, Monoides, Monadas
  • Diseño de DSLs
  • Librerias funcionales en Java

The post Programacion funcional en Java – Libro con 50% descuento appeared first on Ruben J Garcia.

by Ruben Garcia at July 09, 2017 11:22 AM

Blog Bitix

Iniciar rápido un proyecto de Java con Gradle o de Spring con Spring Initializr

Gradle
Spring
Java

Cuando se empieza un proyecto nuevo desde cero se debe disponer de una herramienta de construcción, una estructura de directorios que siga las convenciones de la herramienta de construcción, añadir las dependencias que vayamos a utilizar y alguna clase que muestre algo al ejecutarlo para comprobar que disponemos de la infraestructura básica de compilación, teses, generación de artefactos e inicio de proyecto.

Dado que las clases Java hay que compilarlas para facilitar la tarea están las herramientas de construcción y estas siguen una serie de convenciones en la estructura de directorios además de requerir algunos archivos. En un proyecto de duración de varios meses o años el tiempo dedicado a crear esta infraestructura básica es despreciable y no complicado si nos basamos en un proyecto similar del que copiar, sin embargo, para hacer alguna prueba rápida es costoso.

En Maven existen los arquetipos que construyen el esqueleto básico del proyecto en base a unas plantillas. En Gradle el equivalente es el plugin init pudiendo elegir crear la estructura de una librería o aplicación Java, Groovy o Scala ejecutable. También se puede elegir el framework para hacer las pruebas automatizadas unitarias, de integración o funcionales.

Al usar el plugin init de Gradle se especifica el tipo de artefacto, aplicación o librería, y el framework para las pruebas unitarias en este caso Spock.

Para proyectos que usen Spring Boot está disponible la herramienta Spring Initializr que en pocos minutos permite disponer de una aplicación funcional con las propiedades que se seleccionen. Se puede elegir la herramienta de construcción, Maven o Gradle, la versión de Spring Boot, los metadatos de la aplicación para el paquete de las clases y artefacto, las dependencias de otros módulos de Spring y otras librerías populares.

Cambiando a la versión completa del generador es posible cambiar el tipo de empaquetado (jar o war), la versión de Java o el lenguaje de programación, además seleccionar aquellas dependencias que inicialmente sean necesarias, muchas son de otros proyectos de Spring. Las dependencias están agrupadas por categorías y van desde seguridad, framework web, motores de plantillas, SQL, NoSQL, numerosas herramientas para la nube, integración con redes sociales, entrada/salida o utilidades para operaciones.

Una vez seleccionadas las opciones se genera el proyecto y descarga un archivo comprimido zip. Con el comando gradlew bootRun si inicia la aplicación, pero dependiendo de las dependencias incluidas quizá sea necesaria hacer alguna configuración adicional antes de poder iniciar la aplicación, por ejemplo si seleccionamos la dependencia de jOOQ hay que definir las propiedades para el DataSource en el archivo application.properties con las que el contenedor inversión de control de Spring pueda crear las conexiones a la base de datos.

Como con todos los generadores de código es recomendable saber suficientemente que es código que generan para en caso de modificaciones posteriores saber como aplicarlas. También es posible que no se adapte exactamente a lo que necesitamos, por ejemplo, si queremos hacer un multiproyecto con Gradle o si una dependencia necesaria no está incluida en la lista de categorías hay añadirla después. A partir de aquí se empieza a programar el proyecto.

En el libro Spring Boot in Action se comenta detalladamente Spring Boot que ofrece múltiples nuevas posibilidades que hace más fácil el desarrollo de un proyecto con Spring. Por otro lado para conocer más detalladamente y ampliamente el ecosistema de Spring está el libro Mastering Spring 5.0 que también inlcuye secciones sobre Spring Boot.

En definitiva el plugin init de Gradle y la utilidad Spring Initializr son unas buenas herramientas para empezar un proyecto Java rápidamente y en pocos minutos disponer de un proyecto básico funcional y listo para implementar la funcionalidad de la aplicación.

by pico.dev at July 09, 2017 11:00 AM

July 08, 2017

Blog Bitix

Introducción a los portales y ejemplo de portlet con Liferay

Muchas organizaciones usan portales para mantener su presencia en internet. Los portales son herramientas muy versátiles que incluyen la gestión de contenidos y flujo de trabajo para publicarlo, foros, blog, … Liferay es uno de los más conocidos que usa la plataforma Java. La unidad básica funcional de un portal es un portlet que en ciertos aspectos son similares en otros diferentes a lo que son los servlets en las aplicaciones web Java.

Java
Liferay

Los portales son una especialización de un sitio web que presenta información diversa de una forma integrada y uniforme. Suelen aplicarse cuando una entidad tiene necesidades de presentar información según el usuarios autenticado, su rol, los usuarios necesitan colaborar o se necesita integrar información de múltiples fuentes. Son usados por entidades públicas como gobiernos, ayuntamientos y también por corporaciones de tamaño mediano y grande.

Algunos de sus casos de uso son:

Uno de los servidores de portales más destacados y usados es Liferay aunque no es el único siendo Apache Pluto el servidor de referencia. En lo poco que los he probado Liferay comparado con Apache Pluto el primero tarda bastante más en iniciarse, se nota más lento y me ha dado problemas al usar el framework Apache Tapestry para desarrollar un portlet, sin embargo, Liferay incorpora más portlets con multitud de funcionalidades, es más usado y solicitado en ofertas de trabajo. Tanto Liferay como Apache Pluto implementan la especificación de los portlets de Java que son la pieza básica funcional de un portal.

Liferay es el contenedor de portlets y proporciona un entorno de ejecución similar a lo que los contenedores de servlets como Tomcat proporcionan para los servlets. Las similitudes y diferencias entre un servlet y un portlet son las siguientes:

  • Los portlets son gestionados por un contenedor.
  • Su ciclo de vida está gestionado por el contenedor.
  • Generan contenido dinámico.
  • Interactúan con el cliente mediante peticiones y respuestas.

Y se diferencia en que:

  • Los portlets generan únicamente un fragmento de la página web.
  • No están asociados directamente a una URL.
  • No pueden generar contenido arbitrario, si se solicita text/html los portlets deben generar text/html.

El contenedor de portlets proporciona funcionalidades como:

  • Almacenamiento persistente para las preferencias.
  • Procesamiento de solicitudes.
  • Modos de los portlets.
  • Estado de la ventana o fragmento.
  • Información de usuario,

Liferay incluye más de 60 portlets listos para usar que cumplen las funciones de CMS, foros, blogs, agregador de blogs, wiki, calendario, encuestas, anuncios, herramientas sociales, de comercio electrónico, integración de contenido de sistemas externos, geolocalización, tiempo, administración, gestión de flujo de trabajo y otros muchos más ofrecidos en el marketplace.

Desde la página de descargas se puede obtener la edición para la comunidad de Liferay además de otros productos eligiendo la versión deseada y en la red para desarrolladores obtener documentación y material de referencia. Una vez descargado el archivo de la distribución de Liferay y descomprimido se inicia con el comando ubicado en tomcat-8.0.32/bin/startup.sh. En el archivo tomcat-8.0.32logs/catalina.out se emiten las trazas y mensajes del servidor. Iniciado Liferay se presenta una página de configuración, se han de aceptar los términos y condiciones e iniciar sesión con el usuario creado en la primera página de configuración.

Para añadir un portlet propio a Liferay hay que acceder al Panel de control > Aplicaciones > Gestor de aplicaciones y pulsar la opción cargar ubicada en la parte superior derecha de la página. En la salida del servidor aparecerán varias trazas relativas al despliegue del portlet.

Los portlets se distribuyen por lo general como archivos de aplicaciones web .war con varios descriptores adicionales con información que usa Liferay para el despliegue del portlet.

En el siguiente ejemplo comentaré cómo crear un portlet Hola Mundo sin ayuda de ningún framework como Spring o Apache Tapestry aunque Liferay proporciona ayuda y documentación para desarrollarlos con Liferay MVC Portlet o Spring MVC.

El archivo descriptor principal es portlet.xml donde se describen los portlets de la aplicación indicando por ejemplo su nombre, la clase que lo implementa o los modos que soporta, otros archivos descriptores son web.xml, liferay-portlet.xml y liferay-display.xml con unas propiedades exclusivas de Liferay indicando el icono y la categoría en la que ubicar el portlet en la paleta de portlets.

Un portlet es una clase Java que extiende de GenericPortlet. En el caso del ejemplo es muy sencillo ya que solo emite un mensaje usando una preferencia de configuración que Liferay se encarga de persistir, tiene un modo de edición y procesa una acción para cambiar el valor de una preferencia que se utiliza al emitir el mensaje.

Los portlets con sus diferencias funcionales con los servlets tienen muchas similitudes y una API con clases equivalentes a los servlets. Así la clase principal de la que hay que heredar para crear un portlet es GenericPortlet o implementar la interfaz Portlet. Las peticiones en los portlets siguen una serie de fases que se van ejecutando en el siguiente orden ActionPhase, EventPhase, HeaderPhase y RenderPhase. Para los recursos como imágenes o documentos hay una fase específica ResourcePhase.

Fases y métodos del ciclo de vida de un portlet

Para cada una de estas fases en la API de los portlets hay un método específico que son processAction, procesEvent, renderHeaders y render. Los portlets poseen modos que se visualizan con los métodos doEdit, doHelp y doView o el correspondiente anotado con @RenderMode. Cada uno de esos métodos para cada una de las fases reciben dos parámetros uno que representa a la petición que heredan de PortletRequest y son ActionRequest, ClientDataRequest, EventRequest, HeaderRequest, RenderRequest y ResourceRequest. Los objetos que representan a las respuestas heredan de PortletResponse y son ActionResponse, EventResponse, HeaderResponse, MimeResponse, RenderResponse, ResourceResponse y StateAwareResponse.

La interfaz PorletPreferences obtenida con el método getPreferences() de una clase que herede de PortletRequest también es importante ya que con ella el portlet es capaz de persistir incluso entre reinicios del servidor los datos relativos a su funcionamiento que desee aunque esto no sustituye a la utilización de una base de datos como PostgreSQL o MongoDB. Los portlets también tienen el equivalente de filtros de los servlets con la clase PortletFilter y el equivalente de sesión con la clase PortletSession.

Usando como herramienta de construcción del proyecto Gradle el archivo .war a desplegar el Liferay se genera con la tarea build en el directorio build/libs/HolaMundoPortlet-0.1.war. Esta archivo hay que desplegarlo en Liferay para posteriormente incluirlo en alguna página, se visualice el contenido que genera y se pueda interactuar con él.

Desarrollar un portlet con su API directamente es una tarea costosa si la funcionalidad o complejidad del portlet es mucha. Al igual que en Java no se suele utilizar la API de los servlets directamente, aunque es la API subyacente, y se suele utilizar alguno de los muchos frameworks disponibles para los portlets también hay varios frameworks entre los que elegir. En el artículo Portlets con el framework Apache Tapestry y Apache Pluto muestro un ejemplo usando un framework de alto nivel, orientado a componentes y altamente productivo.

Aunque el libro Liferay in Action o Portlets in Action no están actualizados a la última versión sirven para conocer los conceptos básicos de su funcionamiento, explican la teoría e incluyen ejemplos de código de como crear un portlet.

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando ./gradlew build.

by pico.dev at July 08, 2017 09:00 PM

Portlets con el framework Apache Tapestry y Apache Pluto

Los portales ofrecen una solución para los casos de uso de integración de aplicaciones, edición de contenido a modo de CMS, agregación de blogs, foros, colaboración entre personas, red social entre otros. La pieza fundamental de un portal en Java es un portlet. Desarrollar un portlet usando la API directamente no es simple, algunos frameworks que usaríamos para desarrollar aplicaciones y páginas web son usables para desarrollar portlets, Apache Tapestry es uno de ellos como muestro con un ejemplo en este artículo.

Apache Tapestry
Apache Pluto
Java

La API ofrecida de los portlets se puede considerar de bajo nivel y para facilitar la tarea de su programación es posible emplear un framework al igual que ocurre al programar una aplicación web con los servlets utilizando el lenguaje Java. Aún así es importante conocer los conceptos subyacentes de los portlets que están explicados de forma didáctica en el libro Portlets in Action.

Explicado como crear un portlet directamente con su API usaré el mismo ejemplo pero usando el framework Apache Tapestry que también es usable para realizar aplicaciones web pero para el que existe un módulo para desarrollar portlets y una pequeña documentación.

Liferay 7 debe usar algún mecanismo especial para cargar las clases no compatible con Tapestry por ello en este ejemplo usaré el contenedor de portlets Apache Pluto. Apache Pluto es la implementación de referencia para la API de los portlets, inicia el servidor significativamente más rápido que Liferay aunque no incorpora tantos portlets listos para usar.

El libro Portlets in Action define portal de la siguiente manera traducida al español:

Un portal es una colección de miniaplicaciones web llamadas portlets. Un portal soporta características como personalización, agregación de contenido o autenticación. Los portlets actúan como aplicaciones web dentro del portal mostradas en ventanas donde cada ventana en una página del portal representa un portlet. El portal agrega la información y proporciona una vista consolidada al usuario.

El ejemplo consiste en un mensaje de saludo que incluye un nombre el cual se introduce con un formulario desde el mismo portlet. Los portlets usando Apache Tapestry son muy similares a una aplicación web, con lo que gran parte del conocimiento es el mismo, pero en los que están a disposición varios servicios adicionales de la API de los portlets como PortletRequestGlobals donde están agregados varios objetos relativos las peticiones y respuestas como PortletRequest para la petición con ActionRequest, EventRequest, RenderRequest y ResourceRequest, y PortletResponse para la respuesta con ActionResponse, EventResponse, RenderResponse, ResourceResponse, … y la amplia colección de componentes reusables de toda aplicación con uno específico para enlazar páginas en un portlet, PortletPageLink. Apache Tapestry permite abstraerse en gran medida de la API subyacente de los portlets y las diferencias con una aplicación web no serán muy significativas. Todos los conceptos conocidos para desarrollar aplicaciones y páginas web sirven prácticamente en su totalidad para desarrollar portlets.

Los componentes usables en las plantillas de las páginas, salvo alguno adicional son los mismos que en una aplicación web. Unos 57 componentes listos para usar además de los propios y específicos de la aplicación.

Al igual que en el framework están incluidos múltiples componentes el contenedor de dependencias que tiene integrado Tapestry ofrece muchos servicios que es posible inyectar en las páginas y en componentes nuevos y propios, también desarrollar nuevos servicios que necesiten los portlets.

Para hacer el ejemplo Hola Mundo hay que definir dos páginas, una para mostrar el mensaje y otra para obtener un nombre, cada página se compone de una clase Java y una plantilla asociada que genera el HTML, ambos elementos son muy simples. El portlet hará uso del mecanismo de preferencias proporcionado por el portal con la clase PorletPreferences y que se encarga de persistir en su propia base de datos para obtener y guardar valores en este caso el nombre usado en el mensaje. El portlet usa un formulario que envía el nombre donde se utilizan los componentes Form, Label y TextField.

El resto son varios archivos descriptores necesarios entre los que está el típico web.xml de las aplicaciones web Java y el descriptor específico de los portlets portlet.xml.

Con Apache Tapestry están a nuestra disposición todas las facilidades de un framework de más alto nivel que la API de los portlets, con la API de los portlets accesible si es necesaria, altamente productivo y con el que reutilizaremos en otros portlets o proyectos los componentes desarrollados con una librería de componentes.

Construido el portlet con una tarea de Gradle el portlet se despliega copiando el archivo war al directorio de despliegue de los portlets de Apache Pluto, en webapps. Una vez desplegado accediendo a la página de administración se configuran los portlets que incluye cada página. El usuario y contraseña para iniciar sesión en Apache Pluto es pluto para el usuario y pluto para la contraseña.

Páginas de administración y sesión de Apache Pluto

Insertado el portlet en una página y accediendo a ella el portlet muestra el mensaje que emite y seleccionando la opción edit acceder a la página de preferencias acceder a la página que muestra el formulario y permite cambiar el mensaje. Este es el resultado del portlet desplegado en Apache Pluto.

Porlet con Apache Tapestry en Apache Pluto

Para conocer más sobre los portlets el libro Portlets in Action es una buena fuente de documentación.

Descargado y descomprimido el binario de Apache Pluto para inicia con el comando startup.sh. Apache Pluto es en realidad un servidor Apache Tomcat con las adiciones para proporcionarle la funcionalidad de portal en la dirección http://localhost:8080/pluto.

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando ./pluto-3.0.0/bin && ./gradlew build.

Portada libro: PlugIn Tapestry

Libro PlugIn Tapestry

Si te interesa Apache Tapestry descarga gratis el libro de más de 300 páginas que he escrito sobre este framework en el formato que prefieras, PlugIn Tapestry: Desarrollo de aplicaciones y páginas web con Apache Tapestry, y el código de ejemplo asociado. En el libro comento detalladamente muchos aspectos que son necesarios en una aplicación web como persistencia, pruebas unitarias y de integración, inicio rápido, seguridad, formularios, internacionalización (i18n) y localización (l10n), AJAX, ... y como abordarlos usando Apache Tapestry.


by pico.dev at July 08, 2017 11:30 AM

July 07, 2017

enavas.blogspot.com.es

Paquete pkgsync 1.40

He actualizado el paquete pkgsync a la versión 1.40, en la que he introducido los siguientes cambios:
  • Se resuelve una errata en el man.
  • Modifico purge-old-kernels para que elimine dependencias instaladas al realizar una actualización del kernel que ya no son necesarias.
  • Modifico pkgsync para ejecutar el procedimiento wait_for_apt_or_dpkg antes de apagar el equipo o reiniciarlo para evitar que se apague antes de terminar las actualizaciones.
Aquí podéis ver el código completo de pkgsync:


Y si queréis descargar el paquete que instala esta versión de pkgsync, aquí lo tenéis:
https://drive.google.com/open?id=0B3XAklnKX7ZjOEZwSVJUQkloQzA
Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at July 07, 2017 11:02 AM

Paquete linex-ubuntu-puppet 2.18

En la nueva versión del paquete linex-ubuntu-puppet_2.18 he realizado las siguientes modificaciones:
  • Corregido bug que no permitía forzar la ejecución de sinc_puppet al encontrarse desactivado.
  • Añadidos ficheros readpkgsyncconfig.rb y readsincpuppetconfig.rb para convertir en variables facter los valores de configuración de /etc/default/pkgsync y /usr/share/linex-ubuntu-puppet/sincpuppet.default
    • Los facter de pkgsync comienzan por el prefijo pkgsync_
    • Los facter de sincpuppet comienzan por el prefijo puppet_
  • Eliminado el parámetro de configuración obsoleto WAITFORCERT 
Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at July 07, 2017 08:12 AM

July 06, 2017

enavas.blogspot.com.es

Implantar un controlador de dominio adicional utilizando Zentyal

En un post de febrero de 2017, os mostré que es posible gestionar los Windows del centro utilizando un controlador de dominio implementado mediante Zentyal

Zentyal es una distribución basada en Ubuntu que nos permite, mediante diferentes módulos, ofrecer una serie de servicios en nuestra red. En particular, el paquete zentyal-samba nos proporciona un controlador de dominio y un sistema de compartición de ficheros.

Implanté un controlador de dominio primario (PDC) utilizando este sistema a finales del curso pasado y la verdad es que me ha venido realmente bien para hacer que los usuarios se logueen con su login y password particular, y, además, para administrar fácilmente el conjunto de máquinas Windows mediante directivas de grupo (GPO).

Aprovechando que estos días puedo concentrarme un poco más en lo que hago, he aprovechado para montar un controlador de dominio adicional (BDC):


¿Qué me aporta ésto?
  • En primer lugar, un BDC me proporciona tolerancia a fallos. Cuando los servidores miembro o las estaciones de trabajo necesitan confirmar nombres de usuario y contraseñas, buscan un controlador de dominio (DC) disponible, ya sea el PDC o un BDC. De este modo, si el PDC se cae, pero un BDC está disponible, es posible seguir realizando operaciones de sólo lectura de DC, es decir, que se podrán seguir realizando inicios de sesión.
  • Por otra parte, los BDC ayudan a mantener el tiempo de respuesta cuando muchos usuarios inician sesión simultáneamente. Microsoft recomienda un BDC para cada 2000 usuarios. 

Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at July 06, 2017 11:42 AM

Añadir el módulo zentyal-radius con mschap a zentyal 5.0

Si queréis añadir el soporte para radius en versiones 4.0, 4.2 o 5.0, podéis recurrir al foro de Zentyal, donde el usuario julio tiene publicadas las instrucciones para descargar el código del módulo zentyal-radius_3.5.1, aplicarle un parche que lo adapta a las siguientes versiones y volver a construir el paquete.

Siguiendo sus instrucciones, he generado el paquete que instala el módulo en la versión 5.0 y funciona perfectamente:
sudo apt-get install zbuildtools build-essential fakeroot dpkg-dev -y
mkdir ~/tmp
cd ~/tmp
wget 'http://archive.zentyal.org/zentyal/pool/main/z/zentyal-radius/zentyal-radius_3.5.1.tar.gz' -O zentyal-radius_3.5.1.tar.gz
tar -xf zentyal-radius_3.5.1.tar.gz
mv zentyal-radius-3.5.1 zentyal-radius-5.0
wget 'https://drive.google.com/uc?export=download&id=0B4_d-7xL0AS_bGRPYW92VXdtN00' -O zentyal-radius-5.0.patch
patch -t -p1 -i zentyal-radius-5.0.patch
cd zentyal-radius-5.0
dpkg-buildpackage -rfakeroot -b -tc
cd ..
sudo dpkg -i zentyal-radius_5.0_all.deb
sudo apt-get install -f -y
De este modo, podreḿos controlar qué grupo de usuarios del servidor Zentyal pueden acceder a la red vía freeradius, algo muy interesante porque vamos a poder configurar nuestro portal cautivo en pfSense para que utilice el servicio radius de Zentyal.
Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at July 06, 2017 07:03 AM

July 05, 2017

Poesía Binaria

Píldora #Bash: Conocer el tiempo que lleva un proceso abierto en Linux

Bash tiempo proceso
¡Una nueva sección! Después de tanto tiempo y tantas secciones inacabadas. Algo que tenía ganas de hacer, es crear posts con esa serie de recetas, scripts, oneliners, o píldoras que se me van ocurriendo mientras trabajo en consola. Suelen ser cosas pequeñas y deberían caber en un tweet junto con una pequeña descripción. De todas formas a mí me gusta explicar un poco más las cosas para que quede bien claro.

En este caso, vamos a empezar conociendo el tiempo que lleva abierto un proceso, o un programa. Puede ser una información útil si, por ejemplo, tenemos corriendo servicios que ante un problema se reinician solos. O porque simplemente queremos saber ese dato, al igual que: ¿cuánto tiempo llevo con el ordenador encendido? que podemos responder con uptime. En este caso queremos saber cuánto tiempo llevo con un programa arrancado, como puede ser firefox, spotify, chrome, o apache.

Al grano

Vamos a poner dos métodos que iré explicando más adelante:

pid=$(pidof firefox); s=$(($(date +%s)-$(stat -c %Y /proc/”$pid”))); echo $(date -ud “@$s” +”$(($s/86400)) dias %Hh:%Mm:%Ss”)
1 dias 23h:39m:24s

O de una forma más corta, podemos utilizar

ps -eo pid,etime,comm | grep firefox
24441  1-23:53:14 firefox

Donde veremos primero el PID, luego el tiempo y luego el nombre del proceso.

Explicando el primero

En el primer ejemplo, lo primero que hacemos es coger el ID del proceso (PID).

pid=$(pidof firefox)

Tras ello, sacaremos la fecha y hora en formato UNIX del momento actual (como siempre, esto será el número de segundos desde el 1 de Enero de 1970 a las 00:00).
date +%s

Luego consultaremos la fecha del directorio /proc/PID y la pondremos en formato UNIX también. Recordemos que todos los procesos tendrán un directorio virtual en /proc/ con información sobre los mismos.
stat -c %Y /proc/”$pid

El objetivo es restar las dos fechas, así obtenemos el número de segundos transcurridos desde que se inició el proceso. .
s=$(($(date +%s)-$(stat -c %Y /proc/”$pid”))); echo $s

Ahora sólo queda ponerlo en un formato más humano, es decir, en días, horas, minutos y segundos. Para ello, el número de días lo podemos sacar a mano, ya que sería $s (el número de segundos) dividido entre 86400 (los segundos que tiene un día). Pero el resto se lo podemos pedir al comando date. Lo hacemos así porque date presenta fechas y horas (1 de Enero de 2017 a las 12:34:45) no tiempos transcurridos (120 días 3 horas, 4 minutos, 5 segundos), aunque la hora actual es lo mismo que pedir el tiempo transcurrido desde las 00:00.
Podríamos también calcular todos los elementos a mano (días, horas, minutos y segundos), el problema es que el script ya no entraba en un tweet:

pid=$(pidof firefox); secs=$(($(date +%s)-$(stat -c %Y /proc/”$pid”))); printf ‘%d days %dh:%dm:%ds\n’ $(($secs/86400)) $(($secs%86400/3600)) $(($secs%3600/60)) $(($secs%60))
1 dias 23h:39m:24s

El segundo ejemplo, con ps

Este segundo ejemplo, será mucho más portable entre sistemas UNIX, y mucho más corto, es verdad, pero no nos da mucho juego a la hora de escoger el formato de salida. El formato del tiempo será fijo (días-horas:minutos:segundos) y será importante visualizar el PID o el nombre del proceso.
Además, es mucho más lento, ya que con ps estamos analizando el tiempo de todos los procesos del sistema, aunque luego en pantalla sólo mostremos el que nos interesa porque la salida de ps la hemos pasado por grep.

The post Píldora #Bash: Conocer el tiempo que lleva un proceso abierto en Linux appeared first on Poesía Binaria.

by Gaspar Fernández at July 05, 2017 08:20 AM

July 04, 2017

Poesía Binaria

¿Cómo cerrar un puerto TCP ocupado por una aplicación en GNU/Linux?

Cuando vamos a establecer una comunicación entre dos máquinas a través de una red TCP/IP, vamos lo que estamos haciendo a diario miles de veces con nuestro ordenador mientras navegamos por Internet, lo hacemos a través de un puerto. Imaginemos que tenemos un sistema de comunicación rudimentario entre 10 amigos, con 5 cables y, cada cable, nos permite hablar con uno de nuestros amigos, pero claro, como sólo tenemos 5 cables, sólo podemos hablar con 5 amigos al mismo tiempo, así que en algún punto del recorrido deberá haber alguien con la capacidad de enchufar y desenchufar esos cables. El caso es que esos cables serían los canales, o puertos de nuestro sistema, alguien deberá enchufar y desenchufar cables para asegurarse de que nos conectemos con quien queremos.
Por lo tanto, yo tengo 5 cables que corresponden con las 5 conexiones que puedo tener simultáneas, ahora, por seguir un orden, si quiero conectarme con Alberto, éste se conectará con mi canal 1, aunque nadie me dice a mí que yo también esté en su canal 1. Ahora bien, conecto con Bruno por el canal 2 y cierro a Alberto, para conectar con Carla, que podemos enchufarla en el 1, ya que está libre… ahora Bruno y Alberto contactarán entre ellos, cada uno por alguno de los canales que tenga libre. Bueno, ¿se capta la idea?

Hablando de TCP/IP tenemos algunos más de 5 puertos (podríamos tener 65535 puertos) y serían las conexiones que podemos tener abiertas al mismo tiempo desde una máquina, o al menos desde una misma dirección IP. Y, hablando de nuestro ordenador, cada programa que tenemos en ejecución y que hace conexiones de red puede estar utilizando determinados puertos para establecer las comunicaciones. Por ejemplo, nuestro navegador, programas de chat, correo, música online, sincronización de información y demás tendrán ciertos puertos abiertos para utilizar dichos servicios. Algunos puertos estarán abiertos en modo escucha (para que otros se conecten con nosotros) y otros puertos serán las conexiones establecidas (nos hemos conectado a un puerto en modo escucha, en nuestro equipo, o en un equipo de la red).

Entonces, las aplicaciones que corren en nuestro sistema pueden tener determinados puertos abiertos para realizar su trabajo.

Nos gusta el cacharreo

Ahora bien, puede que si estamos desarrollando un programa que haga uso de la red, nuestro programa deje un puerto abierto y se haya quedado bloqueado. O también puede ser que estemos intentando poner a prueba la gestión de errores de un software, o estemos haciendo algo de ingeniería inversa. En cualquier modo, lo que queremos es cerrar sin piedad un puerto en nuestro ordenador.
Tenemos que tener cuidado porque, si lo hacemos sin control, puede que algún programa haga cosas muy raras. Además, necesitaremos permisos de root para algunas cosas, por lo que serán acciones privilegiadas.
En mi caso, casi siempre que hago esto es para experimentar. Por ejemplo, ¿cómo se comportaría mi programa si cierro la conexión de repente? Sin que ninguna de las dos partes se lo espere. Como también está bien utilizar iptables para restringir las futuras comunicaciones de mi aplicación (sería algo así como tirar del cable). El objetivo es que nuestro software sea más rubusto y sepa qué hacer en este tipo de casos.

Ver qué programa utiliza qué puerto

Lo primero que debemos hacer es averiguar qué proceso está utilizando el puerto que queremos. Con netstat.

netstat -tanp
(No todos los procesos pueden ser identificados, no hay información de propiedad del proceso
no se mostrarán, necesita ser superusuario para verlos todos.)
Conexiones activas de Internet (servidores y establecidos)
Proto  Recib Enviad Dirección local         Dirección remota       Estado       PID/Program name
tcp        0      0 127.0.0.1:631           0.0.0.0:*               ESCUCHAR    --
tcp        0      0 0.0.0.0:45847           0.0.0.0:*               ESCUCHAR    18904/nc
tcp        0      0 0.0.0.0:17500           0.0.0.0:*               ESCUCHAR    19556/dropbox
tcp        0      0 127.0.0.1:4381          0.0.0.0:*               ESCUCHAR    30420/spotify
tcp        0      0 192.168.0.7:60892       64.233.167.188:5228     ESTABLECIDO 22144/libpepflashpl
tcp        0      0 192.168.0.7:42090       157.55.235.157:40008    ESTABLECIDO 1992/skype
tcp        0      0 192.168.0.7:39342       xx.xxx.xxx.xx:28         ESTABLECIDO 7428/ssh
tcp     3775      0 127.0.0.1:35381         127.0.0.1:37516         ESTABLECIDO --
tcp        0      0 192.168.0.7:48130       192.30.253.124:443      ESTABLECIDO 24441/firefox
tcp        0      1 192.168.0.7:33380       92.189.149.89:35148     FIN_WAIT1   --
tcp        0      1 192.168.0.7:33988       92.189.149.89:35148     FIN_WAIT1   --
tcp        0      1 192.168.0.7:39694       37.35.181.204:63905     FIN_WAIT1   --
tcp        0      0 192.168.0.7:60244       xx.xxx.xxx.xx:143        ESTABLECIDO 3708/thunderbird
tcp        0      0 192.168.0.7:60544       138.68.115.83:443       TIME_WAIT   --
tcp        0      0 127.0.0.1:50542         127.0.0.1:35381         ESTABLECIDO 7345/emacs
tcp        0      0 192.168.0.7:53492       72.21.206.121:443       ESTABLECIDO 24441/firefox
tcp        0      0 127.0.0.1:37516         127.0.0.1:35381         ESTABLECIDO 7345/emacs

Sólo he puesto una pequeña muestra. Con los argumentos tanp conseguimos:
  • -t: Sólo muestra conexiones TCP.
  • -a: Muestra también los puertos que estamos escuchando
  • -n: No resuelve las direcciones. (Es mucho más rápido, pero veremos sólo IPs y no nombres)
  • -p: Muestra los procesos que originan dichas conexiones. (pid y nombre, si es posible)

Vemos que muchos programas no aparecen y eso puede ser debido a los privilegios con los que hemos ejecutado el programa, por lo que si utilizamos sudo deberíamos ver todos o casi todos. Por supuesto, la salida de netstat la podemos pasar por grep, para realizar un filtrado de lo que nos interesa:

netstat -tanp | grep  40008
tcp        0      0 192.168.0.7:42090       157.55.235.157:40008    ESTABLECIDO 1992/skype

Si queremos más información sobre las conexiones abiertas y su asociación con procesos, en lugar de netstat podremos utilizar lsof. Aunque con lsof veremos muchísima información, ya que no sólo se centra en conexiones de red, sino que veremos cada descriptor de archivo abierto en el sistema. Y como las conexiones de red suelen tener un descriptor de archivo asociado, las veremos también . Por lo que, con lsof, podremos visualizar todos los descriptores abiertos por todos los procesos. Por ejemplo:

sudo lsof -n | grep emacs | grep TCP
emacs      7345                     gaspy   17u     IPv4           40529162       0t0        TCP 127.0.0.1:49778->127.0.0.1:35381 (ESTABLISHED)
emacs      7345                     gaspy   18u     IPv4           40538567       0t0        TCP 127.0.0.1:50542->127.0.0.1:35381 (ESTABLISHED)
emacs      7345                     gaspy   19u     IPv4           40585112       0t0        TCP 127.0.0.1:53658->127.0.0.1:35381 (ESTABLISHED)
emacs      7345                     gaspy   20u     IPv4           40595540       0t0        TCP 127.0.0.1:53728->127.0.0.1:35381 (ESTABLISHED)
emacs      7345                     gaspy   21u     IPv4           41279086       0t0        TCP 127.0.0.1:37436->127.0.0.1:35381 (ESTABLISHED)
emacs      7345                     gaspy   22u     IPv4           41283195       0t0        TCP 127.0.0.1:37516->127.0.0.1:35381 (ESTABLISHED)
emacs      7345                     gaspy   23u     IPv4           41284210       0t0        TCP 127.0.0.1:37578->127.0.0.1:35381 (ESTABLISHED)

Con lo que veremos las conexiones TCP que ha establecido mi aplicación Emacs.

También podemos conocer con fuser, el proceso que origina la conexión. Conociendo el puerto (por ejemplo 35381):

fuser -n tcp 35381
35381/tcp:            7359

Matando procesos

Si queremos ser rápidos, lo más fácil para cerrar la conexión de manera abrupta, y una buena forma para probar nuestros programas es matarlos. Como muchos sabréis podemos hacerlo con kill.

kill 7345

O con killall, pero tenemos que tener cuidado si hay varios procesos con el mismo nombre.
killall emacs

Aunque tanto kill como killall, por defecto intentan cerrar la aplicación educadamente, y la aplicación puede elegir cerrarse o no. Incluso puede estar bloqueada, por lo que si queremos podemos utilizar el argumento -9 o -SIGKILL , con lo que el programa no tendrá más remedio que terminar, es más, no tiene elección, ya que es el sistema operativo el que lo mata.

De todas formas, una forma algo más segura es matar al proceso que tiene un determinado puerto. Igual que antes veíamos la información con fuser. Este comando también mata aplicaciones, directamente enviando SIGKILL, es decir, matando, sin pedir permiso, las aplicaciones (a no ser que lo especifiquemos en los argumentos):

fuser -k -n tcp 8080
8080/tcp:            23003

Método artesano que sólo cierra conexiones

Me encanta este método. Con él hacemos que el proceso entre en depuración y lo matamos. Una cosa importante a tener en cuenta, como dije antes, son los descriptores. Cada conexión, o fichero abierto tiene un descriptor único para la aplicación en la que se encuentra. Y suelen ser números pequeños y secuenciales. Así como la salida estándar por pantalla suele ser el 1, la salida de error el 2, y la entrada por teclado el 0, cuando abrimos el primer fichero, se le asignará el 3 y cuando creamos una conexión después el 4, y así sucesivamente. Entonces, veamos cómo al ejecutar lsof, vemos en mi cuarta columna, generalmente unos números. Para hacer el ejemplo más legible, he ejecutado netcat para abrir un puerto, así:

nc -l 54321

Luego, para averiguar el ID de proceso, lo podemos hacer con fuser, por ejemplo, aunque podemos utilizar cualquier comando de los explicados anteriormente:
fuser -n tcp 54321
54321/tcp:           23101

Ya que tenemos nuestro PID, 23101, vemos los descriptores abiertos por ese proceso:
lsof -np 23101
COMMAND   PID  USER   FD   TYPE    DEVICE SIZE/OFF    NODE NAME
nc      23101 gaspy  cwd    DIR      8,22    12288 7602177 /home/gaspy
nc      23101 gaspy  rtd    DIR      8,18     4096       2 /
nc      23101 gaspy  txt    REG      8,18    31248  129397 /bin/nc.openbsd
nc      23101 gaspy  mem    REG      8,18  1868984  426046 /lib/x86_64-linux-gnu/libc-2.23.so
nc      23101 gaspy  mem    REG      8,18   101200  400728 /lib/x86_64-linux-gnu/libresolv-2.23.so
nc      23101 gaspy  mem    REG      8,18    81040  393967 /lib/x86_64-linux-gnu/libbsd.so.0.8.2
nc      23101 gaspy  mem    REG      8,18   162632  396890 /lib/x86_64-linux-gnu/ld-2.23.so
nc      23101 gaspy    0u   CHR    136,14      0t0      17 /dev/pts/14
nc      23101 gaspy    1u   CHR    136,14      0t0      17 /dev/pts/14
nc      23101 gaspy    2u   CHR    136,14      0t0      17 /dev/pts/14
nc      23101 gaspy    3u  IPv4 139144920      0t0     TCP *:54321 (LISTEN)

Al final, veremos 0u, 1u, 2u, 3u (la u indica que es de lectura/escritura; r, sería lectura y w, escritura. Aunque algunas veces tenemos descriptores de lectura/escritura que no son necesariamente así… pero eso es otra historia). Lo que nos interesa es que el descriptor 3 es el que corresponde con la conexión que queremos cerrar. Ahora, podemos utilizar gdb para depurar el programa e introducir un comando close() a dicho descriptor, para cerrarlo (salen muchas letras, pero es sencillo):

sudo gdb -p 23101
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type “show copying”
and “show warranty” for details.
This GDB was configured as “x86_64-linux-gnu”.
Type “show configuration” for configuration details.
Para las instrucciones de informe de errores, vea:
.
Find the GDB manual and other documentation resources online at:
.
For help, type “help”.
Type “apropos word” to search for commands related to “word”.
Adjuntando a process 23101
Leyendo símbolos desde /bin/nc.openbsd…(no se encontraron símbolos de depuración)hecho.
Leyendo símbolos desde /lib/x86_64-linux-gnu/libbsd.so.0…(no se encontraron símbolos de depuración)hecho.
Leyendo símbolos desde /lib/x86_64-linux-gnu/libresolv.so.2…Leyendo símbolos desde /usr/lib/debug//lib/x86_64-linux-gnu/libresolv-2.23.so…hecho.
hecho.
Leyendo símbolos desde /lib/x86_64-linux-gnu/libc.so.6…Leyendo símbolos desde /usr/lib/debug//lib/x86_64-linux-gnu/libc-2.23.so…hecho.
hecho.
Leyendo símbolos desde /lib64/ld-linux-x86-64.so.2…Leyendo símbolos desde /usr/lib/debug//lib/x86_64-linux-gnu/ld-2.23.so…hecho.
hecho.
0x00007ff39bffa060 in __accept_nocancel () at ../sysdeps/unix/syscall-template.S:84
84 ../sysdeps/unix/syscall-template.S: No existe el archivo o el directorio.
call close(3)
1 = 0
quit
Una sesión de depuración está activa.
Inferior 1 [process 23355] will be detached.
¿Salir de cualquier modo? (y or n)
y
Separando desde el programa: /bin/nc.openbsd, process 23355

Eso sí, puede que el programa que estamos corriendo dependa de la conexión, o ese sea su único propósito, por ejemplo netcat o telnet, por lo que una vez cerrada la conexión se cierran. Aunque otros programas utilizan las conexiones de red realizan otras tareas como por ejemplo mantener un entorno gráfico, monitorizar el sistema, actualizar un fichero, etc; deberían poder gestionar correctamente ese cierre de conexión sin sufrir ningún desastre.

killcx, o cerrar conexiones educadamente

Ésta es una de esas herramientas (escrita en Perl) que deben estar en nuestra caja de herramientas de sysadmin. Y sirve para matar conexiones, aunque lo hace de un modo seguro. Es más, es capaz de cerrar una conexión que se ha quedado bloqueada en el sistema. Para utilizarla debemos hacer:

sudo ./killcx 127.0.0.1:54321 lo
killcx v1.0.3 -- (c)2009-2011 Jerome Bruandet -- http://killcx.sourceforge.net/
[PARENT] checking connection with [127.0.0.1:54321]
[PARENT] found connection with [127.0.0.1:44904] (ESTABLISHED)
[PARENT] forking child
[CHILD]  setting up filter to sniff ACK on [lo] for 5 seconds
[PARENT] sending spoofed SYN to [127.0.0.1:44904] with bogus SeqNum
[CHILD]  hooked ACK from [127.0.0.1:44904]
[CHILD]  found AckNum [3556219343] and SeqNum [477005426]
[CHILD]  sending spoofed RST to [127.0.0.1:44904] with SeqNum [3556219343]
[CHILD]  sending RST to remote host as well with SeqNum [477005426]
[CHILD]  all done, sending USR1 signal to parent [23768] and exiting
[PARENT] received child signal, checking results…
=> success : connection has been closed !

La IP y puerto variarán según nuestras necesidades, y lo es el dispositivo, que podrá ser eth0, wlan0, etc.
La herramienta podemos descargarla desde aquí.

Foto principal: Alex Lehner

The post ¿Cómo cerrar un puerto TCP ocupado por una aplicación en GNU/Linux? appeared first on Poesía Binaria.

by Gaspar Fernández at July 04, 2017 08:41 AM

July 01, 2017

# rm-rf.es

Instalar la versión específica de un paquete con YUM

Cuando ejecutamos yum install , por defecto (como es lógico), se va a instalar la última versión disponible del paquete en el repositorio. En el caso de que ya tengamos ese paquete instalado y no sea la última versión, se actualizará.

Se puede dar el caso de que queramos instalar un paquete o actualizarlo, pero no necesariamente a la última versión, sino a una intermedia. En ese caso, es tan sencillo como especificar la versión a instalar indicando el paquete completo en la ejecución de yum:

# yum install mypackage-1.0.2-23.el6

El único “problema” aquí es que quizás, no sabemos el nombre exacto del paquete (paquete-version-arquitectura). Para saber las versiones disponibles del paquete en el repositorio utilizamos el parámetro --showduplicates:

# yum --showduplicates list foo
Installed Packages
foo.noarch 0.6.1-1 installed 
Available Packages
foo.noarch 0.6.0-9 installed 
foo.noarch 0.6.0-8 installed 
foo.noarch 0.6.0-7 installed 
[...]

Si quisieramos instalar una versión inferior a la que tenemos del paquete, haríamos uso de la funcionalidad “downgrade” de yum:

# yum downgrade foo

by Alex at July 01, 2017 09:38 AM

June 30, 2017

enavas.blogspot.com.es

Error "invalid byte sequence in US-ASCII" en Puppet

En nuestros centros utilizamos puppetmaster con passenger y apache.

Probablemente alguno de vosotros haya visto el siguiente error en alguna ocasión: "invalid byte sequence in US-ASCII". Pues bien, una manera de evitarlo, es forzar que el puppetmaster utilice UTF-8.

Para ello, editamos el archivo /usr/share/puppet/rack/puppetmasterd/config.ru y le añadimos la siguiente línea:

Encoding.default_external = Encoding::UTF_8

A continuación podéis ver el fichero /usr/share/puppet/rack/puppetmasterd/config.ru de mi puppetmaster:
# a config.ru, for use with every rack-compatible webserver.
# SSL needs to be handled outside this, though.

# if puppet is not in your RUBYLIB:
# $LOAD_PATH.unshift('/opt/puppet/lib')

$0 = "master"

# if you want debugging:
# ARGV << "--debug"

ARGV << "--rack"

# Rack applications typically don't start as root. Set --confdir and --vardir
# to prevent reading configuration from ~puppet/.puppet/puppet.conf and writing
# to ~puppet/.puppet
ARGV << "--confdir" << "/etc/puppet"
ARGV << "--vardir" << "/var/lib/puppet"

# NOTE: it's unfortunate that we have to use the "CommandLine" class
# here to launch the app, but it contains some initialization logic
# (such as triggering the parsing of the config file) that is very
# important. We should do something less nasty here when we've
# gotten our API and settings initialization logic cleaned up.
#
# Also note that the "$0 = master" line up near the top here is
# the magic that allows the CommandLine class to know that it's
# supposed to be running master.
#
# --cprice 2012-05-22

require 'puppet/util/command_line'
# we're usually running inside a Rack::Builder.new {} block,
# therefore we need to call run *here*.
run Puppet::Util::CommandLine.new.execute

Encoding.default_external = Encoding::UTF_8
Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at June 30, 2017 11:34 AM

# rm-rf.es

Usar variables de entorno en unidades systemd

Systemd permite configurar variables de entorno para ser cargadas en sus “unidades“, es decir, en los procesos/demonios que se ejecutan a través de este sistema. La configuración se establece en el archivo de configuración del servicio/unidad, y permite establecer un listado de variables de entorno o la llamada a un archivo que contendrá todas las variables.

Si se decide establecer las variables directamente en el archivo de la unidad, la directiva a utilizar es Environment=:

[Service]
Environment=ENV1=foo
Environment=ENV2=bar
[...]

Recordad que los archivos de definición/configuración de las unidades se encuentran en /etc/systemd/

Si se decide establecer las variables de entorno en un fichero independiente, la directiva a utilizar es EnvironmentFile=/ruta/al/archivo:

[Service]
EnvironmentFile=/ruta/al/archivo
[...]

Una vez establecidos los cambios, es necesario recargar la configuración del demonio de systemctl:

# systemctl daemon-reload

Y por supuesto reiniciar el servicio correspondiente sobre el que hayamos realizado los cambios.

by Alex at June 30, 2017 11:20 AM

enavas.blogspot.com.es

Eliminar perfiles de usuario en el sistema operativo Windows de los equipos de Infolab

Como los equipos de Infolab disponen de arranque dual, además de eliminar los directorios HOME locales de usuario, para completar el proceso de limpieza, es conveniente eliminar los perfiles de usuario en Windows. Para hacerlo de una forma sencilla, suministro la herramienta Delprof2 a todos los clientes Windows usando una directiva de grupo.

Delprof2 elimina perfiles de usuario inactivos. No obstante, si queremos hacer limpieza para recuperar el espacio en disco ocupado por perfiles de usuario que ya no se van a utilizar, no tenemos más que ejecutarlo como administrador sin parámetros y eliminará todos los perfiles excepto el que estemos usando y algunos perfiles especiales necesarios para el sistema operativo (como el perfil "Predeterminado").

Delprof2 dispone de opciones de filtrado adicionales de manera que:
  • Es posible eliminar copias localmente en caché de perfiles móviles.
  • O eliminar sólo aquellos perfiles que no se hayan utilizado en un número de días especificado.
Además, es posible utilizarlo tanto de forma local como remota.

En la página de la herramienta encontraréis toda la información, incluida la sintaxis del comando y una serie de ejemplos de uso.
Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at June 30, 2017 09:10 AM

Eliminar directorios HOME locales en Ubuntu de equipos Infolab y portátiles

Mis equipos de Infolab y portátiles se autentican contra el servidor ldap y se crea un directorio HOME local para cada usuario que inicia sesión en la máquina. Como ya comenté en el post anterior, ahora que hemos llegado a final de curso, es conveniente realizar limpieza borrando los directorios HOME locales de estas máquinas.

Para borrar dichos directorios suministro a los equipos mediante puppet el siguiente script que en su día escribí para portátiles:
#!/bin/bash
#
# /usr/local/sbin/borrahomes
# Esteban M. Navas Martin
# algodelinux@gmail.com
# Fecha creacion: 17/06/2015

# Requiere tener instalado el paquete facter para identificar el tipo de máquina
tipo=$(facter tipo)

if [ $tipo = "infolab" ] || [[ $tipo =~ notebook.* ]]; then

# Borramos los directorios HOME
rm -fr /home/profesor/* 2>/dev/null
rm -fr /home/alumnos/* 2>/dev/null

# Borramos las credenciales de usuario cacheadas
for usuario in `cc_dump |awk '{print $3}' | sed '1,2d'`; do
cc_test -update any $usuario -
done

# Creamos un fichero testigo para borrar homes solamente cuando no exista el fichero
touch /etc/homecleaned
fi
Como podéis comprobar, hace uso del facter tipo definido en el fichero /etc/escuela2.0 para asegurar que solamente se ejecute en equipos de infolab y portátiles.
Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at June 30, 2017 08:53 AM

June 29, 2017

systemadmin.es

Hacer un rescan de discos iSCSI

En el caso que hayamos añadido discos o bien cambiado el tamaño de un uno de los discos iSCSI, vamos a necesitar hacer un rescan de las sesiones iSCSI

Vamos a suponer que hemos ampliado el siguiente disco:

# fdisk -l /dev/sdb

Disk /dev/sdb: 32.2 GB, 32212254720 bytes
64 heads, 32 sectors/track, 30720 cylinders
Units = cylinders of 2048 * 512 = 1048576 bytes

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1               1       30720    31457264   83  Linux

Mediante iscsiadm podemos hacer el rescan de las sessiones iSCSI:

# iscsiadm -m node -R
Rescanning session [sid: 1, target: iqn.1992-08.com.netapp:sn.193472889, portal: 10.12.16.222,3260]

A continuación veremos el nuevo tamaño del disco:

# fdisk -l /dev/sdb

Disk /dev/sdb: 85.8 GB, 85899345920 bytes
64 heads, 32 sectors/track, 81920 cylinders
Units = cylinders of 2048 * 512 = 1048576 bytes

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1               1       30720    31457264   83  Linux
Tags:

by Jordi Prats at June 29, 2017 02:56 PM

June 28, 2017

enavas.blogspot.com.es

Eliminar directorios HOME de usuario en equipos de Infolab

Como ya he comentado en más de una ocasión, mis equipos de Infolab tienen habilitado el arranque dual (Ubuntu+Windows) de manera que:
  • En Ubuntu se inicia sesión contra el servidor LDAP y se crea un home local para cada usuario.
  • En Windows se inicia sesión con el  servidor Active Directory implementado mediante samba con Zentyal y se crea un perfil local parar cada usuario.
Con el tiempo, lo más práctico será iniciar sesión tanto en Windows como en Ubuntu contra el mismo servidor y lo más probable es que lo haga utilizando el servidor Zentyal.

Ahora que hemos llegado a fin de curso, es conveniente realizar limpieza tanto en Ubuntu como en Windows eliminando los perfiles locales de los usuarios. Para ello:
  • En Ubuntu utilizo un script al que llamé borrahomes.
  • En Windows utilizo la herramienta delprof2.
Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at June 28, 2017 05:09 PM

June 27, 2017

Blog Bitix

Hemeroteca #11

Desde hace ya tiempo escribir y publicar en el blog es una de las cosas que realmente me gustan y me motivan a pesar de que el blog me requiere mucho tiempo de mi tiempo personal, cada artículo me exige entre 5 y 10 horas de dedicación durante el fin de semana y en mi tiempo libre. Es satisfactorio ver que cada semana y cada mes el número de visitas aumentan a un ritmo rozando los dos dígitos y que también se nota en los ingresos por publicidad de AdSense que en parte dono a alguno de los proyectos de software libre que usó o me parecen interesantes de apoyarles económicamente aunque sea pequeña.

Aún no he llegado al punto de plantearme seriamente abandonar el blog y recuperar mi tiempo para leer, ver películas que ahora me descargo pero pocas veo, andar en bicicleta, pasear u otras cosas, a veces pienso que le dedico mucho tiempo al blog, antes escribía un artículo a la semana, ahora estoy publicando muchas dos artículos faltándome más tiempo para editar y publicar los artículos que para redactarlos. La fe de poder de usar en un trabajo muchas de las herramientas de escribo, que es uno de mis motivaciones de tener el blog, me mantiene escribiendo aunque la realidad es que llevo ya 3 lustros trabajando y en prácticamente la totalidad de proyectos la tecnología estaba ya decidida e impuesta.

El número de visitas ha aumentado notablemente de unas 9K páginas vistas en enero de 2016 a unas 30K en enero de 2017 y ahora a finales de junio unas 60K. Solamente en estos seis primeros meses ya he duplicado el tráfico mayoritariamente proveniente del buscador Google. Los ingresos por AdSense también han aumentado notablemente de 15€ pasando a 50€ mensuales con los que ahora cada dos meses recibo una transferencia de Google en mi cuenta corriente lo que empieza a ser una cantidad respetable aunque no compense por ello solamente la dedicación que requiere.

Más del 90% del tráfico que recibo proviene del buscador Google y el resto de tráfico directo o de referencia. Solo unos 5 artículos son los que reciben la mayor parte de las visitas y que intento aprovechar para que los usuarios accedan a otros artículos relacionados. El aumento de visitas se debe a que con el paso del tiempo habré posicionado mejor algunos artículos en Google y en menor medida a los nuevos que he publicado. A Google creo que le gustan los sitios que publican nuevo contenido con asiduidad y regularmente en primera instancia y en medida similar si es de calidad. De enero de 2014 a enero de 2016 el crecimiento parece plano pero también fue constante aunque simplemente se ve enmascarado por el de los últimos meses.

Evolución visitas e ingresos

Analizando los ingresos y visitas de mi blog y divagando cual sería el tráfico que debería generar para vivir únicamente blog si con 60K páginas vistas obtengo 50€ en ingresos al mes, debería multiplicar por ¿30, 40? el tráfico de este momento para vivir del blog, pero siendo más modesto multiplicar por 5 o 10 ya serían unos ingresos muy notables y algo que parece alcanzable aunque no sea fácilmente, ¿cuantas visitas mensuales son esas para una web? ¿3,6M de páginas vistas al mes? ¿300K o 600K siendo más modesto?. Quizá si publicase en inglés la audiencia sería mayor, aún no se cual es el tráfico que poseen otras páginas hispanas personales de temática tecnológica, software libre o programación más conocidos para saber cual es el límite de visitas alcanzable en este nicho de temática ya que los blogs que sigo en pocos he visto esta misma exhivición impúdica de datos que incluyo aquí (si como blogger te sientes aludido ya tienes tema para un artículo ;). Medios como Xataka o Genbeta por citar algunos tecnológicos muy conocidos profesionales, empresariales o de grupos editoriales con las vistas que tienen deben generar suficiente tráfico para que sus ingresos solo en publicidad costeen los gastos de los redactores, servidores, viajes, paguen algunos sueldos, etc.

Cambiando de tema y yendo a la hemeroteca en la lista de artículos que he publicado en estos seis meses están los siguientes, en total 40 (incluido este) nuevos artículos únicos y fabricados artesanalmente a mano. Este semestre he hecho dos donaciones de 60€ y publicados otros tantos artículos comentando a que proyectos.

Este semestre he publicado una nueva serie sobre electrónica aprovechando que compre un kit con varios elementos electrónicos con los que jugar para la Raspberry Pi 3 que he usado en la 1, se ha compuesto de un total de 10 artículos y aún podría escribir alguno más pero lo dejaré para otro momento si recupero las ganas de cacharrear con el hardware otra vez.

La otra serie de varios artículos publicados durante otras tantas semanas ha sido sobre Docker Swarm continuando y completando un poco más la serie sobre Docker para crear clusters de nodos con la tecnología de la se se está hablando mucho y está transformando el estado del arte para el despliegue, ejecución y distribución de servicios.

Entre otros artículos que he publicado está un script para instalar Arch Linux de forma desatendida, automatizada y personalizable. Dado que Arch Linux no posee un instalador y hay que introducir los comandos directamente en la terminal para realizar la instalación después de leer una buena cantidad de documentación de la estupenda wiki de Arch Linux, este script sirve para instalar Arch Linux de forma sencilla o como consulta de los comandos a ejecutar paso a paso para instalar esta distribución.

También he publicado algún que otro artículo de opinión de dos noticias relevantes que se han producido en este periodo de tiempo, como son el ataque del ransomware WannaCry y que afectó a algunas empresas y organizaciones y relacionado con este tema me preguntaba si las distribuciones GNU/Linux son más seguras que Windows. También daba mi opinión sobre el el anuncio de Shuttleworth de abandonar la convergencia con el servidor gráfico Mir y el entorno de escritorio Unity. Y un último sobre la diferencia de trato para bien de Pepephone con lo que es habitual en otras empresas de telecomunicaciones para mal.

Dos artículos para usuarios sin muchos conocimientos de como instalar Windows o la distribución Ubuntu de GNU/Linux. Explicando paso a paso y detalladamente con capturas de pantalla cuales son los pasos para realizar la instalación desde cero.

Un par de artículos patrocinados de los cuales uno ha sido otra forma de ingreso.

También he publicado un par de artículos en inglés traducción de otros que publique en español como experimento para comprobar que tal se indexan en Google y si alguno de ellos atrae visitas a mi blog.

Habiendo publicado dos series con una buena cantidad de artículos este semestre he publicado pocos artículos de programación. A destacar de estos últimos ha sido el resumen como en años anteriores de la conferencia BilboStack celebrada en febrero de las presentaciones a las que asistí. Varios artículos sobre diferentes tipos de bases de datos relacionales, de documentos y de clave valor representadas por PostgreSQL, MongoDB y Redis. También como realizar autenticación mutua entre cliente y servidor con certificados ya sea con el programa curl, una aplicación en la plataforma Java o con un navegador web.

Para acabar publique un artículo de un cargador de pilas recargables, un paquete de pilas de la marca blanca de Amazon y un reloj con un pequeño análisis y múltiples fotos.

Que disfrutéis leyendo algunos de los artículos que publiqué y aprovechar para suscribiros con vuestro lector de feeds preferido a Blog Bitix para no perderos ninguno de los que publique en el siguiente semestre que posiblemente verse bastante sobre Java.

by pico.dev at June 27, 2017 07:00 PM

June 26, 2017

enavas.blogspot.com.es

Utilizar autofs para automontar directorios compartidos vía NFS en Infolab

Antes de nada, tengo que decir que mis equipos de Infolab no montan el home remoto del servidor. En lugar de ésto, inician sesión contra el servidor LDAP y se crea un home local para cada usuario.

Tomé esta decisión teniendo en cuenta que los equipos tienen una gran capacidad de almacenamiento en los discos duros locales y el espacio en el servidor siempre va a ser más limitado (Un equipo de Infolab tiene dos discos duros de 2Tb y el servidor tiene un sólo disco duro de 2Tb).

No obstante, también me interesa montar directorios compartidos del servidor y del nas vía nfs , algo que podemos hacer fácilmente utilizando autofs y añadirlos a los bookmarks de los usuarios. 

Autofs nos permite montar sistemas de archivos locales y remotos bajo demanda y desmontarlos automáticamente cuando no se usen. Esto quiere decir que los sistemas de archivos se van a montar cuando el usuario acceda a ellos y se desmontarán después de un tiempo de inactividad.

Mi NAS comparte el almacenamiento con los equipos de Infolab en una de sus interfaces de red a la que he asignado el nombre de nasinfolab y exporta varios directorios mediante nfs, entre ellos: "instituto" y "multimedia"  y queremos que ambos directorios se encuentren disponibles para las máquinas de la VLAN de Infolab, junto con el directorio "aulas" que se encuentra almacenado en servidor. Lo que tendríamos que hacer sería configurar autofs en cada máquina para que acceda a dicho directorio.

Ésto es algo que podemos configurar de una manera muy sencilla mediante puppet, pero veamos cómo hacerlo manualmente:

Primero, instalamos autofs en el cliente, si no lo tenemos instalado ya:
# apt-get install autofs

Una vez instalado, editamos el archivo /etc/auto.master y le añadimos las siguientes líneas:
/servidor /etc/auto.instituto --ghost
/nas /etc/auto.nas --ghost
Si no hemos configurado nada aún en autofs, el fichero os quedará más o menos así:
#
# Sample auto.master file
# This is an automounter map and it has the following format
# key [ -mount-options-separated-by-comma ] location
# For details of the format look at autofs(5).
#
#/misc /etc/auto.misc
#
# NOTE: mounts done from a hosts map will be mounted with the
# "nosuid" and "nodev" options unless the "suid" and "dev"
# options are explicitly given.
#
#/net -hosts
#
# Include /etc/auto.master.d/*.autofs
#
+dir:/etc/auto.master.d
#
# Include central master map if it can be found using
# nsswitch sources.
#
# Note that if there are entries for /net or /misc (as
# above) in the included master map any keys that are the
# same will not be seen as the first read key seen takes
# precedence.
#
+auto.master
/servidor /etc/auto.instituto --ghost
/nas /etc/auto.nas --ghost
Con ésto, estamos especificando:
  • Un punto de montaje en /servidor, que configuraremos en el archivo /etc/auto.instituto. Por cierto, el directorio de montaje no es necesario crearlo. Lo crea autofs de forma automática.
  • Un punto de montaje en /nas, que configuraremos en el archivo /etc/auto.nas. Al igual que en el caso anterior, el directorio de montaje no es necesario crearlo. Lo crea autofs de forma automática.
A continuación creamos el archivo /etc/auto.instituto con el siguiente contenido:

aulas -fstype=nfs,vers=3,rw,hard,intr,nodev,nosuid,nolock,rsize=8192 servidor:/home/aulas
Donde:
  • aulas son los punto de montaje dentro de /instituto.
  • -fstype=nfs,vers=3,rw,hard,intr,nodev,nosuid,nolock,rsize=8192 son las opciones de montaje.
  • servidor:/home/aulas es el directorio nfs de la máquina remota que queremos montar.
De este modo, cuando el usuario acceda a /servidor/aulas, se realizará automáticamente el montaje.

A continuación creamos el archivo /etc/auto.nas con el siguiente contenido:

instituto -fstype=nfs,vers=4,rw,hard,intr,nodev,nosuid,nolock,rsize=8192 nasinfolab:/instituto


multimedia -fstype=nfs,vers=4,rw,hard,intr,nodev,nosuid,nolock,rsize=8192 nasinfolab:/multimedia
Donde:
  • instituto y multimedia son los punto de montaje dentro de /nas.
  • -fstype=nfs,vers=4,rw,hard,intr,nodev,nosuid,nolock,rsize=8192 son las opciones de montaje.
  • nasinfolab:/instituto y nasinfolab:/multimedia son los directorios nfs de la máquina remota que queremos montar.
De este modo, cuando el usuario acceda a /nas/instituto o a /nas/multimedia, se realizará automáticamente el montaje.

Para facilitar la tarea de montaje, he creado marcadores en /etc/skel/.config/gtk-3.0/bookmarks, para que cada home de usuario que se cree localmente tenga dicha configuración y que el usuario pueda acceder directamente a los recursos compartidos simplemente haciendo clic directamente sobre ellos.

El contenido del fichero /etc/skel/.config/gtk-3.0/bookmarks es el siguiente:
file:///servidor/aulas
file:///nas/multimedia
file:///nas/instituto
De este modo, cada usuario tendrá dicha configuración en $HOME/.config/gtk-3.0/bookmarks
Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at June 26, 2017 10:22 AM

June 25, 2017

UnLugarEnElMundo

Script desatendido para eliminar ficheros antiguos de un servidor ftp

Hace ya un tiempo que dejamos por aquí el “esqueleto” de un script para realizar una conexión y transferencia desatendida a un servidor ftp. La finalidad del mismo era automatizar los backups en nuestro hosting cuando lo que nos proporcionan para ello es este medio. Auxiliar a este tenía uno que eliminaba los backups antiguos, pero nunca llegué a estar demasiado satisfecho de él. Hace poco buscando mejorarlo vi una solución maravillosamente elegante en stackoverflow. El script original es este:

#!/bin/bash
# get a list of files and dates from ftp and remove files older than ndays
ftpsite="ftp.yourserver.com"
ftpuser="loginusername"
ftppass="password"
putdir="/public_ftp/admin/logs"

ndays=7

# work out our cutoff date
MM=`date --date="$ndays days ago" +%b`
DD=`date --date="$ndays days ago" +%d`

echo removing files older than $MM $DD

# get directory listing from remote source
listing=`ftp -i -n $ftpsite <<EOMYF 
user $ftpuser $ftppass
binary
cd $putdir
ls
quit
EOMYF
`
lista=( $listing )

# loop over our files
for ((FNO=0; FNO<${#lista[@]}; FNO+=9));do
  # month (element 5), day (element 6) and filename (element 8)
  #echo Date ${lista[`expr $FNO+5`]} ${lista[`expr $FNO+6`]}          File: ${lista[`expr $FNO+8`]}

  # check the date stamp
  if [ ${lista[`expr $FNO+5`]}=$MM ];
  then
    if [[ ${lista[`expr $FNO+6`]} -lt $DD ]];
    then
      # Remove this file
      echo "Removing ${lista[`expr $FNO+8`]}"
      ftp -i -n $ftpsite <<EOMYF2 
      user $ftpuser $ftppass
      binary
      cd $putdir
      delete ${lista[`expr $FNO+8`]}
      quit
EOMYF2

    fi
  fi
done

Por comentarlo un poco y “ganarnos el pan”, el script tiene tres bloques: el primero de definición de variables que tendrás que personalizar con tus datos (hasta la línea 8 incluida), el segundo en el que se realiza una conexión con el servidor y se obtiene un listado de todos los ficheros que están en el directorio que indicamos (hasta la línea 25) y por último un tercer bloque en el que se realiza el borrado propiamente dicho.

En el primer bloque la variable ndays en la línea 8 define la máxima antigüedad de los ficheros que no se eliminaran (7 días en este caso) y la variable putdir en la 6 el directorio del servidor ftp donde dejamos los archivos. Si, como yo, dejas los backups directamente en el raiz del servidor ftp puedes eliminar (o comentar) las líneas 6, 20 y 42

En el segundo bloque, la línea 14 indica la fecha límite de los ficheros que se conservaran. Todos los anteriores a esta se eliminarán. Si no quieres que aparezca en la salida puedes eliminarla o comentarla.

En el tercer bloque, si quieres hacer pruebas de que el script funciona antes de lanzarlo en modo real, puedes comentar la línea 43. Esto te mostrará en la consola los ficheros que se eliminarían pero no te los borrará realmente con lo cual podrás comprobar que el script hace lo que realmente necesitas. La línea 38 es la que te muestra el fichero que va a borrarse. Puedes eliminarla o comentarla también cuando ya no te interese. Por último, la línea 30 que aparece comentada muestra un listado de todos los ficheros del servidor ftp antes de realizar el borrado. Puedes descomentarla también para evaluar si está trabajando de forma correcta.

Artículo Original: .

Este artículo pertenece a Un lugar en el mundo... Si quieres ver actualizaciones y comentarios interesantes visita el texto original en: Script desatendido para eliminar ficheros antiguos de un servidor ftp || Hospedado en un Cloud VPS de Gigas.

by Josemaría at June 25, 2017 04:03 PM

# rm-rf.es

Lentitud en login – Solaris y OpenSolaris

En sistemas operativos Solaris y OpenSolaris, por defecto, cuando un usuario inicia sesión en el sistema, se realizan determinadas operaciones que pueden provocar lentitud en el acceso por ssh o al hace su, por ejemplo.

El origen de esta situación es, que en el archivo /etc/profile, que se ejecuta cada vez que el usuario hace login, se realiza una comprobación de la quota del usuario, si tiene mensajes nuevos y presenta el banner motd:

[...]
        if [ ! -f .hushlogin ]
        then
                /usr/sbin/quota
                #       Allow the user to break the Message-Of-The-Day only.
                trap "trap '' 2"  2
                /bin/cat -s /etc/motd
                trap "" 2

                /bin/mail -E
[...]

Si nuestra $HOME tiene mucha ocupación, o se sirve a través de un filesystem remoto, ahí está el problema. La solución la dice el propio script de profile, crear un archivo llamado .hushlogin para omitir esta comprobación:

$ touch ~/.hushlogin

Una vez creado, el acceso debería ser, al menos, más rápido.

by Alex at June 25, 2017 08:23 AM

June 24, 2017

enavas.blogspot.com.es

Administrar extensiones de Gnome Shell en portablet Vexia con gnome-tweak-tool

En un post de mayo, vimos cómo administrar extensiones de Gnome Shell desde Firefox o Google Chrome. Para los que no lo sepan, también podemos administrarlas mediante gnome-tweak-tool:


Por cierto, las extensiones que instalemos como usuario, se guardarán en el directorio:
$HOME/.local/share/gnome-shell/extensions/

Ya comentaré en otro post qué extensiones de gnome-shell utilizo en mi portablet Vexia.
Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at June 24, 2017 06:25 PM

Controlar el aspecto y la configuración de gnome-shell con gnome-tweak-tool

Nuestros portablets Vexia llevan montado Ubuntu Xenial con entorno de escritorio GNOME SHELL, motivado porque estos últimos dispositivos tienen pantalla táctil.

Los usuarios a los que se ha asignado un portablet son responsables de su configuración y mantenimiento principalmente porque se les dió permisos de administración, algo que puede parecer muy interesante a algunos, pero que a otros les complica un poco más la vida sin necesidad.

Para configurar el aspecto del entorno gráfico como usuario, mi recomendación en estos dispositivos es utilizar gnome-tweak-tool, que es sencillo de instalar desde un terminal porque se encuentra en los repositorios:
# apt-get install gnome-tweak-tool
Una vez instalado el paquete, si desplazáis el puntero del ratón a la esquina superior izquierda de la pantalla, os aparecerá el buscador de aplicaciones. Si escribís "gnome-tweak-tool":


Y pulsáis Enter, podréis abrir rápidamente la herramienta para configurar diferentes aspectos del entorno gráfico:

Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at June 24, 2017 06:13 PM

June 23, 2017

systemadmin.es

NRPE en Ubuntu 16.04: Ignora dont_blame_nrpe

En el Debian Bug report logs – #756479 podremos ver como se han deshabilitado los comandos desde el servidor (compilando el nrpe sin –enable-command-args con argumentos tan sólidos como “hay gente que los usa mal“. Vamos a ver cómo usar un PPA alternativo para saltarnos la restricción de Debian


Podemos usar el PPA dontblamenrpe:

add-apt-repository ppa:dontblamenrpe/ppa

Configuramos preferencia del PPA sobre el paquete de la distribución:

cat <<EOF > /etc/apt/preferences.d/nrpe_dontblamenrpe 
Package: *
Pin: release o=LP-PPA-dontblamenrpe
Pin-Priority: 700
EOF

Podemos ver las prioridades mediante apt-cache policy:

root@ubuntu16:~# apt-cache policy nagios-nrpe-server
nagios-nrpe-server:
  Installed: (none)
  Candidate: 2.15-1ubuntu10
  Version table:
     2.15-1ubuntu10 700
        700 http://ppa.launchpad.net/dontblamenrpe/ppa/ubuntu xenial/main amd64 Packages
        100 /var/lib/dpkg/status
     2.15-1ubuntu1 500
        500 http://ad.archive.ubuntu.com/ubuntu xenial/main amd64 Packages

Actualizamos e instalamos:

apt-get update
apt-get install nagios-nrpe-server

Una vez instalados ya dispondremos del binarion de nrpe con la opción enable-command-args habilitada

Tags: ,

by Jordi Prats at June 23, 2017 11:26 AM

June 22, 2017

systemadmin.es

sar: Invalid system activity file

Al intentar ver el contenido de un fichero de sar podemos ver el siguiente mensaje:

# sar -f /var/log/sa/sar09
Invalid system activity file: /var/log/sa/sar09 (0x3130)

Dicho error puede parecer critico, pero en realidad nos esta diciendo que no entiende el contenido del fichero. La razón es simplemente que debemos usar los ficheros sa en lugar de los sar:

# sar -f /var/log/sa/sa09
Tags:

by Jordi Prats at June 22, 2017 12:22 PM

June 21, 2017

enavas.blogspot.com.es

Utilizar la herramienta PsPasswd para cambiar la password de un usuario local en máquinas remotas

PsPasswd es una herramienta de la suite PsTools que nos va a permitir cambiar la password de un usuario local en una máquina remota, algo que nos viene como anillo al dedo para cambiar la contraseña del administrador local.

Veamos un ejemplo:
C:\PSTools> pspasswd.exe \\infolab-prueba -u AdminEdu -p password_actual AdminEdu nueva_password
En el ejemplo anterior estamos usando el propio administrador local para cambiar su clave de forma remota.
C:\PSTools> pspasswd.exe \\infolab-prueba -u instituto\gestor -p password_usuario_gestor AdminEdu nueva_password
Por otra parte, en lugar de indicar el nombre del equipo, podemos especificar un nombre de fichero que contenga un listado de las máquinas a las que hay que cambiar la password:
C:\PSTools> pspasswd.exe @fichero -u instituto\gestor -p password_usuario_gestor AdminEdu nueva_password
Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at June 21, 2017 12:16 PM

GPO: Agregar un grupo del dominio al grupo local de Administradores

Para que un usuario pueda instalar aplicaciones en el sistema, debe tener permisos de Administrador. 

Si queremos que un grupo de usuarios del dominio no administradores puedan instalar aplicaciones, podemos añadir su grupo del dominio al grupo local de Administradores. O incluso podemos crear un grupo específico (por ejemplo Setup) que agreguemos al grupo local de Administradores y añadir y quitar usuarios cuando queramos concederles/denegarles permisos de administrador.

Para agregar un grupo del dominio como administrador local, crearemos una directiva de grupo en:
"Configuración del equipo" -> "Configuración de Windows" -> "Configuración de seguridad" -> "Grupos restringidos":

Hacemos clic con el botón derecho sobre "Grupos restringidos" y se nos mostrará un menú de contexto. De las diferentes opciones que nos aparecen, hacemos clic en "Agregar grupo" y se abrirá un cuadro de diálogo que nos permitirá agregar el grupo:


Hacemos clic en el botón "Examinar" y se nos abrirá un nuevo cuadro de diálogo en el que escribiremos el nombre del grupo de usuarios del dominio. A continuación hacemos clic en el botón "Comprobar nombres" para que busque el nombre de grupo en el dominio. Veremos que el nombre del grupo se subraya.


Pulsamos el botón "Aceptar" y nos mostrará el grupo del dominio añadido:


Pulsamos el botón "Aceptar" y se nos abrirá el cuadro de Propiedades. En el cuadro que dice "Este grupo es un miembro de:" pulsamos el botón "Agregar". Se abrirá un cuadro donde introducimos el nombre del grupo de administradores locales: Administradores. Y, a continuación, pulsamos el botón "Aceptar".


Es importante destacar que en la ventana anterior, no pulsamos el botón "Examinar" porque queremos agregar el grupo del dominio al grupo de administradores local y esta opción nos serviría para buscar un grupo del dominio.

Una vez hecho lo anterior, así nos quedaría configurada la pertenencia:


Pulsamos el botón "Aceptar" y volveremos de nuevo al editor de directivas de grupo, donde podremos añadir más grupos restringidos:

Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at June 21, 2017 10:53 AM

Instalación silenciosa de NetBeans en Windows

Al igual que en Linux, podemos realizar una instalación desatendida de NetBeans en Windows iniciando el instalador con el parámetro --silent:

Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at June 21, 2017 08:17 AM

June 20, 2017

enavas.blogspot.com.es

Eliminar el mensaje "No Valid Subscription" en versiones Proxmox 4.4+

Parece que en versiones más recientes de Proxmox, ya no funciona el viejo método de eliminar el popup con el mensaje "No Valid Subscription" que aparece al hacer login. No obstante, tal y como apuntaba el usuario Marcel G en el siguiente post, podemos seguir eliminándolo de la siguiente manera:
# sed -i.bak 's/NotFound/Active/g' /usr/share/perl5/PVE/API2/Subscription.pm && systemctl restart pveproxy.service
Si os dáis cuenta, estamos reemplazando "NotFound" por "Active" en el fichero "/usr/share/perl5/PVE/API2/Subscription.pm" y haciendo una copia de seguridad del mismo antes de reemplazar.
Publicado por primera vez en http://enavas.blogspot.com.es

by noreply@blogger.com (Esteban M. Navas Martín) at June 20, 2017 12:21 PM