17 de June de 2020

Jose Manuel

proxmox

Proxmox lleva siendo desde hace años un posible sustituto de vmware con la ventaja adicional de permitir la creación de contenedores.
Lleva acompañándome muchos años y no entiendo que en muchas empresas se siga usando vmware existiendo proxmox.
Vamos a ver como instalarlo en un solo servidor consiguiendo este esquema:

Instalar Proxmox

Primero instala Debian con una partición para el sistema de 50G dejando el resto del disco libre y luego sigue estos pasos que en resumen viene a ser:

  • configurar ip fija en tu servidor: ya estará hecho si usas cualquier proveedor pero si estás probando en un virtualbox pon esto sustituyendo tu ip fija en /etc/network/interfaces y reinicia:
  auto ethquesea
  iface ethquesea inet static
    address ip.qu.se.a/mascaraquesea
    gateway gate.way.que.sea
  
  • asociar esa ip fija al nombre de tu servidor: hay que agregar en el /etc/hosts esto:
  ip.qu.se.a   tuhostname.tu.dominio tuhostname
  
  • instalar proxmox:
  echo "deb http://download.proxmox.com/debian/pve buster pve-no-subscription" > /etc/apt/sources.list.d/pve-install-repo.list
  wget http://download.proxmox.com/debian/proxmox-ve-release-6.x.gpg -O /etc/apt/trusted.gpg.d/proxmox-ve-release-6.x.gpg
  apt update && apt full-upgrade
  apt install proxmox-ve postfix open-iscsi
  apt remove os-prober
  

Configurar la red

Ahora solo tenemos una IP de entrada pero queremos tener muchos contenedores así que, siguiendo el esquema de arriba vamos a crear una red a la que enganchar los contenedores y les vamos a dar salida a internet.

En la interfaz web ubicada en https://tuhostname.tu.dominio:8006 nos vamos a Datacenter|tuhostname , Network y creamos un Linux Bridge:

asociandole una dirección ip:

Y tras un reinicio nos debería aparecer el bridge levantado:

Probar la red

Vamos a crear un par de contenedores para probar que todo funciona así que nos vamos a agregar una plantilla bajándonos la de debian 10 por ejemplo:

pinchamos en "Create CT", rellenamos lo que queramos y en la pestaña "Network" ponemos la ip del bridge como gateway y elegimos una ip del rango. Yo, para no liarme suelo poner la ip igual al número del contenedor:

Ahora crea otro contenedor con otra ip y arranca los dos.

Si abres una shell en uno de ellos deberías poder hacer ping al otro y al gateway:

Hasta aquí es más o menos lo de siempre pero todavía no tenemos acceso a internet ni pueden acceder a nuestro servidor desde fuera.

Configurar la salida a internet

Esta configuración es parecida a la que tienes en tu casa donde tu sales a internet con la ip de tu router así que tienes que decirle al servidor que haga nat.

Primero habilita el forwarding en /etc/sysctl.conf:

net.ipv4.ip_forward=1

Ahora instala iptables-persistent:

apt install iptables-persistent

Configúralo para que arranque al inicio creando este archivo en /etc/network/if-pre-up.d/iptables:

#!/bin/bash
/sbin/iptables-restore  /etc/iptables/rules.v4

Y configura en /etc/iptables/rules.v4 el nateo:

*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A POSTROUTING -s red.del.brid.ge/mascarabridge ! -d red.del.brid.ge/mascarabridge -j MASQUERADE
COMMIT

Ahora reinicia, arranca los dos contenedores y comprueba que tienen salida a internet.

Redireccionar puertos

Imagina que quieres dar acceso por ssh al servidor, por ejemplo, que se llegue al puerto 22 del contenedor 100 usando el puerto 22100 del servidor.

Pues en el fichero /etc/iptables/rules.v4, en la zona de nat, agregas una regla tal que así:

-A PREROUTING -d tu.ip.publi.ca -i ethquesea -p tcp -m tcp --dport 22100 -j DNAT --to-destination 10.20.30.100:22

Redireccionar tráfico http y https

Para eso podemos usar nginx, apache, haproxy, ... pero en este ejemplo usaremos nginx.

Instalamos nginx en el servidor:

apt install nginx

Y creamos un proxy inverso de esta forma en /etc/nginx/sites-available/test1.conf:

server {
    server_name test1.tu-ip-publi-ca.nip.io;
    listen 80;
    location / {
        proxy_pass http://ip.de.tu.contenedor:80;
    }
}

Y lo activamos:

ln -s /etc/nginx/sites-available/test1.conf /etc/nginx/sites-enabled/test1.conf

Al reiniciar nginx ya estará accesible.

Para el tráfico https te recomiendo usar letsencrypt que te configura todo solo. Puedes seguir esta guía.

El día a día de proxmox

El día a día consiste en crear contenedor/máquina virtual y agregar un proxy inverso en el nginx.

Gestión muy sencilla.

Conclusión

Llevaba años queriendo escribir esto y he ido a escribirlo cuando ya estoy sustituyendo Proxmox por Kubernetes. ¡Así es la vida!

Cuidado, Proxmox es una solución de virtualización que está al nivel de vmware. De hecho no entiendo como en muchas empresas se usa vmware existiendo proxmox.

Pero hoy día, si puedes, plantéate usar Kubernetes que ya te hace la configuración del nginx, nateo y certificados sola. Además, facilita enormemente el despliegue de las aplicaciones y se está convirtiendo en el standard de facto en el mundo de la gestión de contenedores.

17 de June de 2020 a las 06:16

26 de April de 2020

Jose Manuel

Sword Art Online (II): Hollow Fragment

En la primera temporada de Anime, capítulo 14 "El fin del mundo", tras enfrentarse al jefe del piso 75 la historia da un giro importante.

El juego es un spin-off en el que hay un fallo en el sistema y los jugadores siguen en Aincrad hasta el piso 100. Tu eres Kirito.

Todos los jugadores de la serie de anime están también en el juego y puedes hacer pareja con ellos en los combates así que la idea se parece bastante a la de la serie de Anime.

SPOILERS!!! : Voy a hacer referencia a los capítulos 1 al 14 así que no sigas leyendo si no los has visto.

Versiones

Pese a lo que pueda parecer ¡¡este es un remake de un juego para PSP del año 2013!!

Lo que ocurre es que por un lado ha tenido un cierto éxito y por otro marca el arranque de toda la saga de videojuegos, que tenemos para rato, así que tenemos ediciones para PC, PS4 y PSVita:

Se ajusta perfectamente a la pantalla de la PSVita así que no echarás de menos una pantalla más grande.

Al final de este artículo contaré cosas específicas sobre la versión para PSP.

¿Jugarlo o no jugarlo?

Este era mi segundo RPG después de picotear el Pokemon Red así que cuando empecé este juego no sabía a lo que me iba a enfrentar.

De hecho, después de haber visto la serie en tan poco tiempo, me esperaba un juego igualmente corto e intenso, pero me equivoqué.

Es un juego que está entre las 50 y 300 horas según lo hábil que seas y lo que quieras perderte en él. No es para tomárselo a la ligera y debe ser jugado después de haber visto al menos los primeros 14 capítulos de la serie de anime o no te enterarás de donde salen los personajes ni empatizarás con ellos.

El juego está en inglés y hay que tener un nivel de comprensión bastante alto para enterarte de los tutoriales si quieres ahorrarte unas cuantas horas de frustraciones.

Decir que un juego es un RPG dice tanto de un juego como tener ruedas de un coche. Por lo que he podido ver cualquier juego en el que ganes puntos de experiencia es un RPG y tenemos los JRPG, ARPG, ... Para que nos aclaremos: este juego no es como los Pokemon y si te gustan los Pokemon probablemente no te gustará este juego.

¿Quieres vivir SAO con sus normas e historias? ¿Entender porqué murió tanta gente y porqué no era necesario que murieran? Entonces este juego te interesa.

Es japonés

Algo que llama la atención es el número de horas invertidas en diálogos que cuentan una historia.

En este juego el tiempo invertido en secuencias de este tipo debe rondar entre el 20%, y el 20% de 50 horas son muchas horas.

Recuerda que la intención de este juego no solo es matar bichos, sino contar una historia.

Por ejemplo, este diálogo está al principio y dura 2 minutos.

Respuestas

Cada juego de la saga plantea una o varias hipótesis.

Cuando se hace un juego, antes de salir al mercado es probado para ajustar cosas como el nivel de dificultad, su duración, gráficos, ... y luego se saca al gran público.

Pero ¿y si nuestra limitación estuviera solo en nuestra imaginación?

Por ejemplo: tu, jugador, juegas la primera versión, das feedback, te borran la memoria y vuelves a jugar al juego perfectamente ajustado para ti. ¡Seguro que te a la segunda te gusta! Esto solo se puede hacer teóricamente en un juego de una sola persona pero no en un VRMMORPG.

En un VRMMORPG no se puede parar el tiempo porque hay más personas a tu alrededor. No se pueden borrar cosas que se han hecho porque permanecen en otras personas. Entonces ¿que hacemos? Pues ya que te hemos engañado para ponerte un casco que puede acceder a tu cerebro directamente, clonamos tu mente y la metemos en una IA que resida en un mundo paralelo al que estás tú. De esa forma podremos ajustar el juego que tu vives mientras está ocurriendo en ese mundo paralelo.

¡¡Bienvenido a la Hollow Area!!

La Hollow Area

En realidad, aunque la historia se acaba cuando derrotas al jefe del piso 100, el objetivo de los desarrolladores del juego para PSVita era la Hollow Area, no continuar la historia original. Eso ya lo hicieron para el de PSP.

En mi caso, yo no me hice la Hollow Area por falta de tiempo y me perdí parte de la historia nueva. Aún así tardé 60 horas en acabarme el juego repartidas en 9 meses unos 15 minutos al día.

Esta es la mejor guía que he encontrado para la Hollow Area.

Hasta el rabo todo es toro

Eres Kirito y tu objetivo es avanzar sin que nadie muera.

Kirito vio morir a Diabel buscando el Last Attack Bonus.

Kirito sabe que los monstruos mantienen su poder de ataque y son igual de mortales desde el comienzo de la batalla hasta que pierden su ultimo punto de vida y nunca se confía pensando en que ya está casi vencido.

Kirito es cauto y valora sus posibilidades antes de entrar en batalla ... a no ser que un grupo de incautos y una Asuna mas incauta todavía le necesiten:

Kirito dice al ejército que no ataquen todos a la vez porque sabe que los ataques se hacen por turnos. Un equipo ataca y el otro pasa a retaguardia a curarse.

Comportate como Kirito, arriésgate hasta donde lo haría Kirito, piensa como Kirito y el juego irá bien.

Empieza el master

Con toda esta información ya deberías saber si te quieres meter en el juego. Si es así te voy a ahorrar unas cuantas horas de frustración con los siguientes consejos que he aprendido.

No te voy a engañar: casi hay que hacerse un puto master para aprender a jugar.

Vamos a seguir esta convención para los botones:

Los japoneses usan los botones A y B justo al revés que nosotros así que en los menús tendrás que usar el A para elegir la opción y el B para salir.

El joystick derecho solo se usa para la cámara así que no es necesario mencionarlo más.

Presta atención en los tutoriales

Lee con atención los tutoriales y practica en ellos. Si te dedicas a pasártelos lo antes posible más adelante lo vas a pagar en horas de juego bastante frustrantes.

No te recorras la Hollow Area al principio

Es un área a la que solo tienes acceso tu y te puedes llevar a un compi. El juego puede dar lugar a entender que deberías recorrerla al principio. ¡No lo hagas!

En este área te vas a encontrar desde mindundis de nivel 80 hasta monstruos de nivel cientomucho que te matarán solo con mirarte.

Eso si, si consigues sobrevivir aquí subirás "rápidamente" 10 niveles y cuando vuelvas para pasarte pisos, los monstruos, incluidos los primeros jefes de piso, te parecerán una broma.

No se trata de darle a un botón muchas veces

Al principio yo me hinchaba a darle al botón A hasta que el oponente se moría, pero creo que lo hacía de aburrimiento o pena. ;-) Normalmente el que estaba cerca de morir era yo y me acababa doliendo el dedo. Tranquilo que no hay que empezar desde el principio cuando te matan. ;-)

Abajo tienes 3 barras y un indicador que pone "Risk".

La barra verde de HP

Es la vida que te queda y baja cuando te golpean o te envenenan. El daño que te hacen es directamente exponencial al nivel del atacante y el número consecutivo de ataques con éxito sobre ti. Si el enemigo consigue darte 3 veces seguidas y la cuarta es un combo probablemente te mate sin que te hayas dado cuenta.

Si no te dan y esperas la barra de HP acabará subiendo pero en combate eso no sirve.

Botón R1 + A recupera como un 50% de la barra de HP. Úsalo siempre que Kirito diga que "esto no pinta bien" durante la batalla. Tarda un tiempo en recargarse así que solo sirve para un apuro.

Botón X (el triangulito) sirve para defenderse y tiene el añadido de aumentar tu barra de SP si consigues defenderte por lo que es muy importante. Saber usar esta habilidad correctamente en el momento adecuado será la diferencia entre vivir y morir.

Botón L1 + R1 y usar poción para recuperar todos los HP:

También tienes pociones que minimizan el daño recibido y hacen que la barra baje menos rápido.

Te recomiendo que te desenganches de la batalla y te retires un poco para usarla.

J1 + Y sirve para esquivar y si se usa justo cuando te van a dar evitarás daños. Gasta la barra de Burst y sube la de SP si lo haces en el momento correcto.

¡Correr como un cobarde! Con DPad-Right te "desenganchas" de la batalla y puedes salir corriendo. El malo te perseguirá e intentará atacarte pero te hará mucho menos daño y dejará de perseguirte cuando cambies de zona. Salir corriendo puede ser la mejor opción en la Hollow Area donde te enfrentas a bichos de todos los niveles.

La barra amarilla de Burst y nivel de Risk

La barra amarilla baja cuando pulsas el botón A o cuando usas una habilidad, es decir, siempre que atacas, te defiendes o estornudas.

Sube rápidamente si tu nivel de Risk es bajo. Sube desesperadamente lento si tu nivel de Risk es de 5. Tu objetivo debe ser siempre tener un nivel de Risk que no supere el 3 para poder seguir repartiendo mandobles a diestro y siniestro.

Con DPad-Down haces switch con tu compañero. Eso hará que tu nivel de Risk baje a 0 y tu barra de Burst suba rápidamente.

Cuando tu partner diga algo como Please switch, ¡hazlo! salvo que le veas muy mal de HP en cuyo caso debes aguantar como puedas y decirle que se cure con

La barra morada de SP

Cada vez que usas un skill baja entre un tercio y un medio de la barra. Activar un skill sirve para asestar un montón de golpes seguidos a tu adversario que le harán bastante daño.

Las habilidades se activan con L1 + A/B/X/Y .

Se recarga de varias formas, la primera de ella esperando, pero si haces eso los combates se harán absurdamente largos y probablemente te acaben matando.

Cuando pulsas DPad-Up refuerzas un determinado comportamiento en tu compañero para que lo repita más veces y eso además subirá un poco la barra. No deberías usarlo para subir la barra sino para reforzar comportamientos pero en un apuro te ayudará.

¡Parrying! Con la B te puedes defender de los ataques y si lo haces en el momento correcto, cuando te están atacando, bloquearás su ataque y además tu barra de SP subirá una burrada, lo que te permitirá contraatacar en ese mismo momento.

Pociones de SP: hay pociones para todo y por supuesto para esto también. En combate te puede interesar tomarte una que restaura todo tu SP u otra que hará subir la barra más rápidamente.

Técnicas de combate

Aquí no hay turnos pero si hay franjas de tiempo en las que debes hacer las cosas. No hablo de llegar al nivel de precisión necesario en el Patapón pero si te acercas a él todo será más fácil. Cuando Asuna dice algo como "Now, launch a well timed attack" piensa que a lo mejor es por algo.

Cuando estás en combate en modo automático verás que aparecen las estelas de las espadas y de forma periódica aparece una circunferencia azul o amarilla rodeando a Kirito. Si le das a Burst (botón A) justo en el momento en que sale el círculo azul, lo vuelves a hacer en los siguientes ciclos y en una de ellas lanzas una habilidad verás como hace mucho más daño que si la lanzas al principio. Entre circunferencias azules tendrás que esquivar o bloquear los ataques de tu contrincante. Piensa en la típica película de lucha de espadas. El prota primero tantea a su oponente para acabar derrotándolo con un ataque final en el momento adecuado. Tu eres el prota.

Cuando tu compi te dice "Please switch", resérvate una de las barras de SP y hazle caso. Tu nivel de Risk bajará rápidamente y podrás atacar en el momento preciso para usar el SP ejecutando una habilidad junto a ella.

En un combate tan importante como saber defenderse es saber cuando y como atacar.

Si tienes el nivel suficiente, puedes evitar que el enemigo lance una habilidad usando el botón Y y aprovechar para contraatacar:

Habilidades

Para mi hay de tres tipos: largas, cortas y para todo el que este cerca.

Largas

Viene bien cuando el enemigo tarda mucho entre ataque y ataque.

La mejor combinacion es ataque largo, parrying a su contraataque y otro ataque largo.

Cortas

Hacen daño a los enemigos que dejan poco tiempo entre ataque y ataque y constan de 1 o 2 golpes.

Para todo el que esté cerca

Son habilidades cortas que afectan a cualquier enemigo que esté cerca de ti. Hacen menos daño que las otras pero se lo hacen a todos a la vez.

Ten en cuenta que en el fondo el juego es una cuestión de números. Si tienes 10 enemigos cutres atacándote todos a la vez, te harán el mismo daño que uno 10 veces más fuerte ... pero peor porque mientras te cargas a uno no estarás atendiendo a otro y no puedes bloquear los ataques de todos a la vez, así que la efectividad de los que vayan quedando subirá de forma exponencial y te acabará matando un mindundi cualquiera de ellos.

Una habilidad circular que gaste media barra de SP te dará para 2 golpes circulares seguidos, recarga de SP y otros 2 golpes circulares. Con eso tendrás a todos más cerca de su final y derrotar a un grupo será bastante sencillo.

Técnicas ¿de ligue?

Cuando llegué al piso 98 me pasó algo extraño: me mataron tres veces.

Me puse a buscar como subir de nivel rápidamente y me topé con esto: Fast Dating and Bedroom Strategy | Hollow Fragment.

A veces me equivocaba, le daba a la B en la ciudad y Kirito hincaba rodilla o se podía hablar con sus amigas pero no me imaginaba que formara parte de un minijuego que consistía en llevártelas a la cama.

La verdad, no tengo tiempo para esas tontadas, pero que sepas que esa posibilidad existe.

Están locos estos japos. ;-D

Infinity Moment

Es la versión para PSP. Si quieres jugarlo en una consola portátil y no tienes la PSVita ... poder se puede pero está en su mayor parte en japonés.

He probado a arrancarlo en mi PSP y es jugable pero se nota la falta del joystick derecho para las vistas así como la diferencia en la interfaz, adaptada a una pantalla más pequeña que la de la PSVita.

Te puedes apoyar en estas traducciones si vas a usar la versión japonesa que es la que está en el store o ponerte un parche en el ojo y buscar en google algo como "sao infinity moment english patched" para acabar bajándote la versión parcheada a inglés.

Además para el tutorial puedes seguir este gameplay en español de Infinity Moment.

Sobre los personajes

Como ya dije al principio a partir de aquí las historias divergen y los juegos siguen una historia diferente así que nos podemos encontrar personajes tanto de Aincrad como de ALO u otros arcos.

Nos podemos encontrar a Suguha Kirigaya (Leafa) con un avatar muy parecido al de ALfheim Online:

O a Asada Shino (Sinon), que en en vez de ser la francotiradora que puede conozcas de Gun Gale Online esta ocasión adquirirá la habilidad de arquera:

Te dejo que descubras más.

Otros enlaces útiles

26 de April de 2020 a las 14:33

10 de April de 2020

Jose Manuel

"Trine 3: The Artifacts of Power" en Ubuntu Bionic 18.04

Me he hecho fan de los Trine I y II así que ya que estaba me he acabado el Trine III: The Artifacts of Power.
En este juego se rompen las reglas de los anteriores así que nos encontramos ante otro juego distinto, pero de eso ya hablaré al final. ¿Empezamos por instalarlo?

Instalación

Instalamos normalmente y cuando va a arrancar, adivina ... no funciona. :-/

Da este fallo:

error while loading shared libraries: libpng12.so.0: cannot open shared object file: No such file or directory

Instalamos el paquete que tiene la librería que necesitamos ( visto en askubuntu ):

wget -q -O /tmp/libpng12.deb http://mirrors.kernel.org/ubuntu/pool/main/libp/libpng/libpng12-0_1.2.54-1ubuntu1_amd64.deb \
  && dpkg -i /tmp/libpng12.deb \
  && rm /tmp/libpng12.deb

¡¡ A jugar !!

Trines I, II vs Trine III

Sencillamente, son juegos distintos.

Los Trines I, II (y creo que también el IV) están hechos con un falso 3D que da sensación de profundidad, pero en cuanto a jugabilidad, los juegos son 2D.

Trine III es un juego 3D de verdad y eso les supuso un reto nuevo a los desarrolladores de Frozenbyte que tuvieron que repensar muchas cosas:

  • las habilidades de los personajes no cambian a lo largo del juego
  • Amadeus elige lo que quiere mover "a ojo" sin apuntar
  • el gancho de Zoya solo se ata a argollas de metal
  • Pontius solo tiene un arma
  • No se trata de acabarse el nivel sino de conseguir Trineángulos
  • ...

Olvida lo que sabes de los dos anteriores y vuelve a pensar todo desde 0.

Acaba el juego, pero no la historia

Parece que todas estas innovaciones hicieron que se dispararan las críticas por un lado y que se inflara el presupuesto por otro así que cuando se acaba el juego, la historia del juego se queda a medias ... igual que el juego.

Si, estaban pensados muchos más niveles pero se quedó a la mitad.

Si quieres saber porqué, hay un hilo en Steam donde lo explica el vicepresidente de Frozenbyte.

3D: cosas buenas y cosas malas

Manejar a los personajes en un espacio 3D real usando una superficie 2D como es la pantalla a veces se vuelve jodidamente difícil:

  • me he caído por muchos precipicios mientras comprobaba los límites del escenario
  • las cosas que "flotan", no sabes si están más cerca o más lejos y tienes que ir probando
  • las luchas se pueden volver bastante confusas hasta el punto de perder a tu personaje detrás de los enemigos

Pero para mi la atmósfera y la libertad de movimiento que se consigue a cambio vale mucho la pena:

caché

Se solucionarían muchos problemas haciendo una versión VR del juego que permitiera percibir bien la profundidad.

¿Bueno o malo?

Es un juegazo. Muy entretenido y con buenos puzles.

Una obra de arte en movimiento. Con imágenes de los tres primeros juegos tendríamos arte para cambiar todos los cuadros del Museo del Prado.

Pero si vienes de jugar al I o al II, que también son buenísimos, y te esperas lo mismo evolucionado, te llevarás un chasco.

10 de April de 2020 a las 22:00

05 de April de 2020

Jose Manuel

Kubernetes para impostores

En este artículo vamos a ver como instalar Kubernetes en Ubuntu para luego desplegar una aplicación en él accesible desde tu pc.

En el siguiente veremos como hacer lo mismo pero en un servidor con Ubuntu, certificados https válidos, de que hacer backup, ...

microk8s

Usaremos microk8s que tiene versión para Linux, Windows y MAC.

Versión corta

Copia y pega esto en un terminal:

sudo snap install kubectl --classic

Te habrá pedido la contraseña. Para el resto ya la tiene:

sudo snap install helm --classic
sudo snap install microk8s --classic
microk8s.enable
microk8s.start
mkdir $HOME/.kube
microk8s.config > $HOME/.kube/config
microk8s enable dns
microk8s enable dashboard
microk8s enable ingress
microk8s enable storage

Hasta aquí son unos 3 minutos con una conexión que baja a 10MB/s .

Cuando todos los pods estén en estado Running habremos terminado:

~$  kubectl get po --all-namespaces
NAMESPACE     NAME                                              READY   STATUS    RESTARTS   AGE
ingress       nginx-ingress-microk8s-controller-l5ccz           1/1     Running   0          2m41s
kube-system   coredns-588fd544bf-ftfz7                          1/1     Running   0          2m51s
kube-system   dashboard-metrics-scraper-db65b9c6f-mbh96         1/1     Running   0          2m43s
kube-system   heapster-v1.5.2-58fdbb6f4d-hln5h                  4/4     Running   0          2m43s
kube-system   hostpath-provisioner-75fdc8fccd-v4bth             1/1     Running   0          2m34s
kube-system   kubernetes-dashboard-67765b55f5-hpnnn             1/1     Running   0          2m43s
kube-system   monitoring-influxdb-grafana-v4-6dc675bf8c-mmwr7   2/2     Running   0          2m43s
~$

Hasta aquí otros 3 minutos.

El proceso completo de instalación de Kubernetes no deberían ser más de 10 minutos.

Cuando termines, si te conectas a localhost en tu navegador, debería saludarte con un 404 Not Found un tal openresty.

Ahora vamos a ver si funciona instalando un wordpress con el chart de bitnami

helm repo add bitnami https://charts.bitnami.com/bitnami
helm upgrade --install wordpress \
  --set wordpressUsername=admin \
  --set wordpressPassword=admin \
  --set service.type=ClusterIP \
  --set ingress.enabled=true \
  --set ingress.hostname=localhost \
  bitnami/wordpress

Comprobamos que los pods se levanten:

~$ kubectl get po
NAME                         READY   STATUS    RESTARTS   AGE
wordpress-7d5756c684-pjgfq   1/1     Running   0          2m37s
wordpress-mariadb-0          1/1     Running   0          2m37s

Y en 3 minutos más:

El proceso completo desde 0 hasta un wordpress levantado en kubernetes no deberían ser más de 15 minutos.

Lo de arriba pero con la salida de los comandos.

Instalamos los clientes kubectl y helm:

~$ sudo snap install kubectl --classic
kubectl 1.17.3 from Canonical✓ installed
~$ sudo snap install helm --classic
helm 3.1.2 from Snapcrafters installed

Instalamos Kubernetes con microk8s:

~$ sudo snap install microk8s --classic
microk8s v1.18.0 from Canonical✓ installed
~$ microk8s.enable
~$ microk8s.start
Iniciado.
Enabling pod scheduling
node/yinyan already uncordoned

Configuramos el .kube/config para que los clientes sepan llegar a Kubernetes:

~$ mkdir $HOME/.kube
~$ microk8s.config > $HOME/.kube/config

Activamos algunos addons:

  • dns:
  ~$ microk8s enable dns
  Enabling DNS
  Applying manifest
  serviceaccount/coredns created
  configmap/coredns created
  deployment.apps/coredns created
  service/kube-dns created
  clusterrole.rbac.authorization.k8s.io/coredns created
  clusterrolebinding.rbac.authorization.k8s.io/coredns created
  Restarting kubelet
  DNS is enabled
  
  • dashboard:
  ~$ microk8s enable dashboard
  Applying manifest
  serviceaccount/kubernetes-dashboard created
  service/kubernetes-dashboard created
  secret/kubernetes-dashboard-certs created
  secret/kubernetes-dashboard-csrf created
  secret/kubernetes-dashboard-key-holder created
  configmap/kubernetes-dashboard-settings created
  role.rbac.authorization.k8s.io/kubernetes-dashboard created
  clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard created
  rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
  clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
  deployment.apps/kubernetes-dashboard created
  service/dashboard-metrics-scraper created
  deployment.apps/dashboard-metrics-scraper created
  service/monitoring-grafana created
  service/monitoring-influxdb created
  service/heapster created
  deployment.apps/monitoring-influxdb-grafana-v4 created
  serviceaccount/heapster created
  clusterrolebinding.rbac.authorization.k8s.io/heapster created
  configmap/heapster-config created
  configmap/eventer-config created
  deployment.apps/heapster-v1.5.2 created

  If RBAC is not enabled access the dashboard using the default token retrieved with:

  token=$(microk8s kubectl -n kube-system get secret | grep default-token | cut -d " " -f1)
  microk8s kubectl -n kube-system describe secret $token

  In an RBAC enabled setup (microk8s enable RBAC) you need to create a user with restricted
  permissions as shown in:
  https://github.com/kubernetes/dashboard/blob/master/docs/user/access-control/creating-sample-user.md
  
  • ingress:
  ~$ microk8s enable ingress
  Enabling Ingress
  namespace/ingress created
  serviceaccount/nginx-ingress-microk8s-serviceaccount created
  clusterrole.rbac.authorization.k8s.io/nginx-ingress-microk8s-clusterrole created
  role.rbac.authorization.k8s.io/nginx-ingress-microk8s-role created
  clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-microk8s created
  rolebinding.rbac.authorization.k8s.io/nginx-ingress-microk8s created
  configmap/nginx-load-balancer-microk8s-conf created
  daemonset.apps/nginx-ingress-microk8s-controller created
  Ingress is enabled
  
  • storage:
  ~$ microk8s enable storage
  Enabling default storage class
  deployment.apps/hostpath-provisioner created
  storageclass.storage.k8s.io/microk8s-hostpath created
  serviceaccount/microk8s-hostpath created
  clusterrole.rbac.authorization.k8s.io/microk8s-hostpath created
  clusterrolebinding.rbac.authorization.k8s.io/microk8s-hostpath created
  Storage will be available soon
  

Instalamos un wordpress:

~$ helm upgrade --install wordpress --set wordpressUsername=admin --set wordpressPassword=admin --set service.type=ClusterIP --set ingress.enabled=true --set ingress.hostname=localhost bitnami/wordpress
Release "wordpress" does not exist. Installing it now.
NAME: wordpress
LAST DEPLOYED: Sun Apr  5 22:41:25 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
** Please be patient while the chart is being deployed **

To access your WordPress site from outside the cluster follow the steps below:

1. Get the WordPress URL and associate WordPress hostname to your cluster external IP:

   export CLUSTER_IP=$(minikube ip) # On Minikube. Use: `kubectl cluster-info` on others K8s clusters
   echo "WordPress URL: http://localhost/"
   echo "$CLUSTER_IP  localhost" | sudo tee -a /etc/hosts

2. Open a browser and access WordPress using the obtained URL.

3. Login with the following credentials below to see your blog:

  echo Username: admin
  echo Password: $(kubectl get secret --namespace default wordpress -o jsonpath="{.data.wordpress-password}" | base64 --decode)
~$

Y esperamos a que se levante:

~$ kubectl get po
NAME                         READY   STATUS    RESTARTS   AGE
wordpress-7d5756c684-pjgfq   1/1     Running   0          2m37s
wordpress-mariadb-0          1/1     Running   0          2m37s

El proceso completo desde 0 hasta un wordpress levantado en kubernetes no deberían ser más de 15 minutos.

05 de April de 2020 a las 21:03

"Trine 2: The Complete History" en Ubuntu Bionic 18.04

Trine Enchanted Edition me encantó así que vamos a por Trine 2: Complete Story.
¿Empezamos por instalarlo?

Instalación

Usa el script de play.it para Trine 2.

Si quieres en los ports de Ubuntu también tienes un paquete de play.it que no he probado pero debería hacer lo mismo.

Si lo instalas con el script oficial, se instalará pero al arrancar verás un fallo del tipo "me falta una librería" que implica bajarse unos fuentes y compilarlos. La librería se usa para la pantalla inicial que salta antes de empezar el juego. play.it ya se lo baja todo, lo compila por ti y te crea dos paquetes.

¡¡A jugar!!

¡Sorpresaaa!

Llegará un momento en que te saldrá esta pantalla:

Pero no, no se ha acabado:

Me sentí un poco troleado. A mi me gustaba como acababa el juego, pero hay que reconocer que la continuación también me ha gustado.

La continuación son 6 niveles que se agregaron después con la expansión "Goblin Menace" así que no te asustes si se acaba pero no se acaba.

Cambian las reglas

A partir de aquí verás que todo es más difícil pero eso es porque presuponen que tus personajes tienen habilidades que a lo mejor no tienen:

  • Pontius "El Bravo": habilidad de planear con su escudo.
  • Amadeus "El Magnífico": habilidad de magnetizar objetos metálicos.
  • Zoya "La Silenciosa": habilidad de ralentizar el tiempo.

Si no tienes estas habilidades no se si se puede hacer así que mejor consíguelas.

¿Y si me atasco?

El mejor walkthrough que he visto es este:

¿Y comparado con el I?

Trine II es como el I pero más en todo.

El artwork está mejor conseguido, los personajes tienen más habilidades, la historia es mejor, ... pero la esencia del juego es la misma que la del I.

Esto no es malo. ¿eh? Es un juegazo se mire por donde se mire.

A un jugador que haya jugado al I sin acabárselo hace más de un mes, le pones el II diciéndole que es el I más adelantado y tardará un rato en darse cuenta de que no es así.

Si has jugado al I y te apetece volver a jugarlo, mejor cómprate el II y así cambias la historia. Si no has jugado al I, puedes empezar directamente con el II ya que también tiene su tutorial y la historia es independiente de la del I. Si eres un friki como yo y te gusta ver la evolución de las sagas, cómprate los dos. ;-)

05 de April de 2020 a las 15:59

27 de March de 2020

Jose Manuel

Trine en Ubuntu Bionic 18.04

Tenía pendiente el trine desde hace años y ahora que estoy con fiebre, tos, dolor muscular ... y encerrado en una habitación, lo he buscado en GoG y ¡hay versión para Linux! pero cuando voy a instalarlo en Ubuntu ... no funciona.
Os cuento lo que he tenido que hacer para instalarlo.

Instalando ando

Empieza como siempre: te lo bajas, das permisos al .sh y lo instalas.

Cuando lo vas a ejecutar peta con este fallo:

$ ./start.sh 
Running Trine Enchanted Edition
ERROR: ld.so: object 'libgtk3-nocsd.so.0' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
./bin/trine1_linux_launcher_32bit: error while loading shared libraries: libgtk-x11-2.0.so.0: cannot open shared object file: No such file or directory

Y te fijas bien en la página de requisitos donde pone que el juego es de 32 bits y necesitas instalar esto:

Requires libc6:i386 libasound2:i386 libasound2-data:i386 libasound2-plugins:i386 libwrap0:i386 libopenal1:i386 libvorbisfile3:i386 libGLU1:i386 libfreetype6:i386 libportaudio0:i386 libgtk2.0-0:i386 and dependencies

Y aquí empiezan los problemas ... algunos paquetes no existen:

$ sudo apt-get -y install libc6:i386 libasound2:i386 libasound2-data:i386 libasound2-plugins:i386 libwrap0:i386 libopenal1:i386 libvorbisfile3:i386 libGLU1:i386 libfreetype6:i386 libportaudio0:i386 libgtk2.0-0:i386
[sudo] contraseña para jmferrerm: 
Leyendo lista de paquetes... Hecho
Creando árbol de dependencias       
Leyendo la información de estado... Hecho
Nota, seleccionando «libasound2-data» en lugar de «libasound2-data:i386»
E: No se ha podido localizar el paquete libGLU1:i386
E: No se ha podido localizar el paquete libportaudio0:i386

solución

Instala esto:

$ sudo apt-get -y install libc6:i386 libasound2:i386 libasound2-data:i386 libasound2-plugins:i386 libwrap0:i386 libopenal1:i386 libvorbisfile3:i386  libfreetype6:i386  libgtk2.0-0:i386

Lo vuelves a ejecutar y el pete cambia:

Trine Enchanted Edition$ ./start.sh 
Running Trine Enchanted Edition
ERROR: ld.so: object 'libgtk3-nocsd.so.0' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
./bin/trine1_linux_launcher_32bit: /home/elmanytas/bin/GOG Games/Trine Enchanted Edition/lib/libz.so.1: version `ZLIB_1.2.9' not found (required by /usr/lib/i386-linux-gnu/libpng16.so.16)

La librería que proveen no vale así que la mueves y haces un link a la del sistema:

~/bin/GOG Games/Trine Enchanted Edition/lib$ mv libz.so.1 libz.so.1.old
~/bin/GOG Games/Trine Enchanted Edition/lib$ ln -s ln -s /lib/i386-linux-gnu/libz.so.1

¡A jugar!

ACTUALIZACIÓN 20200405

Parece que hay un script que te crea paquetes debian de trine con todas sus dependencias. Antes de hacer lo que he dicho arriba prueba con esto:

Trine Enchanted Edition [/.play.it]

No lo he probado con el 1, pero si con el 2 y funciona.

27 de March de 2020 a las 22:13

20 de October de 2019

Jose Manuel

Salvando al Principe de Persia

Originalmente era el príncipe el que tenía que salvar a la princesa, pero con los juegos modernos, este se ha quedado apartado y ahora somos nosotros los que tenemos que salvarle a él.

La buena noticia es que es fácil salvarle y en este post explico como.

También ayuda que sea uno de los mejores videojuegos de todos los tiempos. :-D

Demasiado difícil

En los tiempos que corren, con videojuegos fáciles que cuando no juegan solos tienen vidas infinitas, es difícil pedir a alguien que se esfuerce mínimamente.

Además, se asume que un juego se puede continuar al día siguiente, no empezar desde el principio una y otra vez.

Necesitamos bajar el nivel para que se vea atractivo para los chavales. Triste pero cierto.

Bajando el nivel

Vamos a pasar de 3 vidas a 5 y de 60 minutos a 300. Ademas podremos guardar/restaurar la partida con R1/L1.

Emulador

Usando Retroarch tenemos disponibles estos cheats para la SNES que permiten vidas infinitas y tiempo infinito peeeeeero con la PSVita podemos usar el SDL Prince of Persia Vita que usa la resolución del de MSDOS y da gusto jugarlo.

Eso si, la partida se queda en RAM así que si cierras el juego perderás el progreso.

La versión de Nintendo 3DS da pena así que ni la mires.

Trusquis

Pulsamos botón de start y luego SETTINGS | MODS ajustando los parámetros a nuestro gusto.

Relación con Aladdin

Según Fandom el prota es un huérfano que vive en las calles hasta que un día escala los muros del palacio donde conoce a la princesa y se enamora de ella. Sus sentimientos son recíprocos con la princesa a pesar de sus diferentes clases sociales.

El Juego empieza cuando el Sultán de Persia ha sido llamado a una guerra en un lugar lejano. El malvado Vizier Jaffar ve la oportunidad de quedarse el trono casándose con la princesa y encierra al protagonista en las mazmorras.

Vamos, no se a ti pero a mi el argumento me recuerda bastante a la última versión de Aladdin.

Por si te gusta la serie ...

... aquí tienes el wiki de Fandom donde encontrarás TODO.

20 de October de 2019 a las 20:48

10 de July de 2019

Jose Manuel

Sword Art Online (I)

Yo no lo sabía pero en Japón Sword Art Online es tan famosa como aquí Star Wars (y un buen sustituto ahora que Disney la ha terminado de destrozar).

Han hecho y siguen haciendo novelas ligeras, mangas, videojuegos, animes y películas.

Te cuento lo que he visto interesante.

¿De que va?

Sword Art Online es un VRMMORPG ( Virtual Reality Massively Multiplayer Online Role-Playing Game ), es decir, como el World of Warcraft pero con un casco de realidad virtual.

Lo guay que tiene ese casco es que una vez puesto intercepta todas las señales que entran y salen de tu cerebro de forma que dejas de sentir y poder mover tu cuerpo para solo sentir y mover tu avatar. Lo que se llama inmersión total (Full Dive).

nervegear

Para conseguir penetrar en el cerebro usa microondas, como las de calentar la leche, pero de baja intensidad.

El día en que se lanza el juego 10000 personas se conectan y empiezan a jugar. En este tipo de juegos los recursos son limitados así que el que antes entra tiene más facilidades para hacerse con objetos únicos, subir de nivel y acabarse el juego en primer lugar.

Pasadas unas horas los jugadores quieren desconectarse para hacer cosas como tomarse una pizza, estudiar para un examen, ... pero el botón de desconectar ha desaparecido del menú.

logout

Tras el desconcierto inicial todos los jugadores son forzosamente teletransportados a la plaza central del primer piso y el creador del juego, que es un bromista de la leche, les comunica que puede matarles cuando le venga en gana friéndoles el cerebro con las microondas que usa el casco.

logout

Las reglas son las siguientes:

  • si alguien te intenta quitar el casco mueres
  • si mueres en el juego mueres de verdad
  • si quieres volver al mundo real acábate el juego llegando hasta el piso 100 y cargándote a todos los jefes de todas las plantas
  • no existe comunicación con el mundo real para hacer la experiencia más "inmersiva"
  • en el mundo real conocen estas mismas reglas

Se quedaría solo en una broma pesada si fuera un juego corto, pero es que en la prueba beta solo consiguieron llegar hasta el décimo piso después de unos meses.

youaredeath

El protagonista es Kirito, un beta tester del juego, que se ve atrapado junto a otros miles de personas en ese metaverso. En ese juego mortal conoce a un montón de gente con quienes vive muchos meses.

people

No pretende ser una historia alegre para niños así que prepárate para ver morir a niños y preadolescentes, romances, dramas, historias de superación, ... e incluso sexo censurado en el capítulo 16.5 de las novelas ligeras.

Y esta es la intro de la serie, canción cortesía de LiSa:

¿Y porqué es especial?

Todos los jugadores se ven obligados a vivir en ese metaverso durante muuuuucho tiempo y para muchos acaba convirtiéndose en su mundo real. Es muy interesante ver los sentimientos y la forma de afrontar la situación de todas las personas, desde la heroicidad de los protagonistas a la cobardía de los suicidas pasando por la maldad de los asesinos. De alguna forma todos nos veremos reflejados en algún personaje de la serie y entenderemos realmente que significa el concepto de metaverso.

people

Velocidad

La serie va a la esencia de lo que quiere contar. No es un Dragon Ball ni nada por el estilo.

En los primeros 14 capítulos se cuenta la historia de lo que pasa en los primeros 75 pisos.

Fíjate lo que acabo de escribir: 75 pisos en 14 capítulos. Pasan muchíiiiiiiisimas cosas en cada capítulo de 20 minutos así que es imposible aburrirse.

Cultura general

Solo es necesario que te veas los primeros 14 capitulos para comprender el fenomeno y solo necesitas ver los dos primeros, de 20 minutos cada uno, para saber si te va a gustar o no.

Además, a partir de ese capítulo 14 salen todos los videojuegos de la saga así que si o si necesitas llegar hasta ahí si vas a jugar los juegos.

No te dejes liar por lo que te cuento a continuación y haz lo que pone en los dos párrafos de arriba. ;-)

A saltos

La sensación que se te queda cuando ves el anime, manga o novelas ligeras es que se pegan unos saltos muy grandes quedándote con la sensación de no saber de donde salen los personajes o como se ha llegado hasta ahí.

sao_light_novels

Esto ocurre porque el autor, Reki Kawahara, presentó la novela a un concurso que limitaba el tamaño de la misma y tu estás viendo esa versión.

Pero entre los capítulos pasan muchas cosas que están en las novelas ligeras de Sword Art Online Progressive donde se cuentan las cosas más en detalle:

sao_progressive

No en la reunión para enfrentarse al primer jefe

Kirito es un luchador solitario. Cuando se cruza con alguien en alguna mazmorra y le ve mal intenta ayudarle pero no interviene salvo que vea las cosas mal.

Un día en una mazmorra ve a un jugador encapuchado que tiene algo especial. Se nota que es novato porque hace tonterías de novato, pero cuando lucha lo hace con un nivel de definición PERFECTO nunca visto antes para él así que le pica la curiosidad y cuando el jugador acaba con los monstruos a su alrededor y se sienta apoyado en una pared a descansar, Kirito se le acerca para hablar con él.

asuna_encapuchada

Cuando el otro le contesta se lleva una sorpresa al ver que es un jugador de un tipo muy extraño en Aincrad porque no es un jugador sino ¡una jugadora!

Kirito ve en ella a una persona que si formara parte de un raid podría ser muy relevante, ayudar a muchas personas y ser clave para liberarlos a todos de ese juego mortal.

Esa jugadora es lo que se suele llamar la empollona de la clase: metódica, perfeccionista, tenaz, ...

A ella no le gustan los videojuegos y tenía un examen la semana pasada al que no ha podido asistir. El casco de realidad virtual es de su hermano pero el día del estreno del juego él estaba de viaje así que ella se decidió a probarlo y se vio encerrada ahí. Fue el mayor error de su vida.

Ella estaba decidida a suicidarse luchando hasta morir en esa mazmorra pero Kirito la salvó. Su visión del mundo cambió mientras se daba una ducha de polígonos azules en la habitación de Kirito y los sentía como si fueran agua en su cuerpo virtual.

Kirito no conoce a Asuna en la reunión para acabar con el jefe del primer piso tal como parece en el Anime. ¿Y como se yo todo esto?

Complemento casi necesario

Para enterarte bien de la historia y entender de donde salen personajes como Asuna, Argo la rata, Agil, ... tienes que leerte los hechos que ocurren entre el primer y el segundo capítulo.

En las 112 primeras páginas del primer volumen de Sword Art Online Progressive está todo lo que necesitas saber.

sao_volumen_1

Lo tienes traducido solo por molestar aquí.

En las siguientes 200 páginas hay cosas que no necesitas saber pero querrás saber.

El resto de volúmenes están muy bien pero no son necesarios para comprender la historia principal aunque encierran cosas como el origen de Aincrad contado por la elfa oscura Kizmel.

kizmel

Te puedes bajar todo traducido de un grupo que lo hace solo por molestar y al que le debo un montón de horas de entretenimiento. ;-)

En concierto

Si ya has visto la serie, cuando escuches este concierto no podrás evitar que se te erize la piel. Toda la banda sonora cantada por profesionales y muy bien ambientada:

Tiene una de las mejores bandas sonoras que he escuchado. Y cada vez que lo hago encuentro un matiz nuevo.

Ahora mismo se me esta erizando el bello.

Gracias Yuki

Entregas

Como he dicho, en aquel alejado rincón del planeta, Sword Art Online ha tenido y sigue teniendo un gran impacto desde que empezó en el 2009:

También se está planificando crear una especie de NerveGear, pero sin sorpresa, y otro juego llamado "Sword Art Online - The Beginning -":

Me he visto todas las temporadas de anime, jugado a los dos primeros juegos y estoy con el tercero.

Mundos

Pero esta serie es muy ambiciosa y entre sus animes, novelas y juegos, cubre desde los mundos de espadas:

sao+alo

hasta los mundos de armas en Phantom Bullet y Alternative:

phantom_bullet

Y nos da una visión sobre como sería vivir en ellos de verdad usando muy bien el concepto de metarverso.

También cubren la realidad aumentada en Ordinal Scale:

ordinal_scale

Y cultivar Inteligencia Artificial dentro de un metaverso en Alicization.

sao+alo

Todo dentro de Metaversos accesibles solo por Realidad Virtual. Si te gustan todos estos temas, no debes perderte esta serie.

Bye bye Star Wars

Desde que Star Wars pasó a ser de Disney y pusieron a anidar a un Porg en el Halcón milenario estoy buscando otra saga que esté a la altura y esta lo está para mi.

He cambiado un mundo de fantasía en el que existe una fuerza midicloriana que lo une todo y pretende ser realista pero nunca podrá serlo, por otro fantástico, que pretende ser fantástico y cuyos únicos poderes se basan en tu trabajo, insistencia y a veces en predecir las líneas de predicción.

Como es un universo VR con trabajo y esfuerzo si podremos hacerlo, aunque yo no lo veré.

Coste

Aunque nadie dijo que fuera a ser barato. :-D

Enlaces interesantes

Un poco de música para amenizar el trabajo

Una hora de música épica que encontrarás en Sword Art Online:

10 de July de 2019 a las 14:33

05 de April de 2019

Jose Manuel

AWS S3 ¿on-premise?

minio ha sido, junto a un bug de la máquina de vending que me permite sacar dos bollitos por el precio de uno, mi descubrimiento más grande de esta semana.
Permite tener un servicio compatible con AWS S3 en tu cluster de Kubernetes. Esto podrá parecer innecesario si trabajas en cloud pública, donde ese servicio ya existe, pero en entornos on-premise es una necesidad muy real.

¿Porqué AWS S3 on-premise?

Cuando hablamos de servicios cloud no solo hablamos de disponibilidad, replicación, gigas, y con casinos, y ....... .

Para el desarrollador de un equipo agile lo importante es tener un api para poder trabajar. Y si además es un api "estandarizada" pues mucho mejor porque nos permite desarrollar nuestras aplicaciones de forma que son independientes del entorno sobre el que corren.

Por desgracia en los clientes que suelo frecuentar hay una cierta alergia a todo lo que sea externalizar servicios por lo que AWS S3 les provoca urticaria pero minio encaja como un guante.

Despliegue en OpenShift

Usamos los objetos de karrier.io un poco modificados e incrustados en una plantilla que puedes encontrar en este repositorio.

Ejecuta:

oc new-app -f minio-template.yaml

Y ya está. ¿A que pensabas que iba a ser más difícil? ;-)

openshift

Recuerda apuntar la "Access Key" y la "Secret Key".

Venga, te pongo la salida del comando para que parezca más difícil:

jmferrerm@serenity:~/blog/AWSS3on-premise$ oc new-app -f minio-template.yaml -p MINIO_ACCESS_KEY=holaaaaaaa -p MINIO_SECRET_KEY=adiooooooos
--> Deploying template "jmferrer-minio-template/minio" for "minio-template.yaml" to project jmferrer-minio-template

     min.io
     ---------
     A min.io service.  For more information about using this template, including OpenShift considerations, see https://github.com/elmanytas/minio-openshift/blob/master/README.md.

     WARNING: This template needs a default storage class with space enough.

     The following service(s) have been created in your project: minio.

     For more information about using this template, including OpenShift considerations, see https://github.com/elmanytas/minio-openshift/blob/master/README.md.

     * With parameters:
        * Name=minio
        * Memory Limit=512Mi
        * Application Hostname=
        * Access Key=holaaaaaaa
        * Secret Key=adiooooooos

--> Creating resources ...
    secret "minio-keys" created
    service "minio" created
    route "minio" created
    statefulset "minio" created
--> Success
    Access your application via route 'minio-jmferrer-minio-template.osapps.elmanytas.es'
    Run 'oc status' to view your app.
jmferrerm@serenity:~/ownCloud/blog/AWSS3on-premise$

Uso con la cli de aws

Hacemos un uso normal cambiando el endpoint url tal como pone aquí:

jmferrerm@serenity:~$ aws --endpoint-url=http://minio-jmferrer-minio-template.osapps.elmanytas.es s3 ls
jmferrerm@serenity:~$ aws --endpoint-url=http://minio-jmferrer-minio-template.osapps.elmanytas.es s3 mb s3://swordartonline
make_bucket: swordartonline
jmferrerm@serenity:~$ aws --endpoint-url=http://minio-jmferrer-minio-template.osapps.elmanytas.es s3 cp /tmp/YukiKajiuraSAOLive.mp4  s3://swordartonline
upload: ../../tmp/YukiKajiuraSAOLive.mp4 to s3://swordartonline/YukiKajiuraSAOLive.mp4
jmferrerm@serenity:~$ aws --endpoint-url=http://minio-jmferrer-minio-template.osapps.elmanytas.es s3 ls s3://swordartonline
2019-04-04 20:04:27  237535530 YukiKajiuraSAOLive.mp4
jmferrerm@serenity:~$

GUI

El GUIaburros es simple y escueto.

login

Tanto que no necesita mayor explicación:

interfaz

Happy object storing!!

Un poco de música épica para amenizar tu fin de semana

Conciertazo en vivo de Yuki Kajiura 梶浦由記 at 「Sword Art Online event “Sing all Overtures”」:

05 de April de 2019 a las 20:51

26 de March de 2019

Jose Manuel

Crea tu portal con Antora

A la hora de crear un portal siempre nos encontramos con los mismos problemas: la gestión de permisos, la "caducidad" de la plataforma, el formato de la documentación, la gestión manual de la documentación, uniformidad de los estilos en todos los portales, transformación entre diferentes formatos, ...

Antora es un generador de portales a partir de AsciiDoc, lo cual se suma a la facilidad que tiene para transformarse en varios formatos como epub, pdf o html.

Tendencias

Desde hace unos años podemos ver como diferentes empresas desarrollan su documentación usando un lenguaje de marcado organizado en repositorios:

Soporte

Existen plugins de AsciiDoc para los CMS más populares como pueden ser Wordpress o Drupal. Y lo mismo con Markdown.

También tenemos plugins para los principales IDEs que permiten ver en tiempo real el resultado de tu trabajo:

Github Atom Microsoft Visual Studio Code
Atom Code

Y por supuesto, tal como has podido ver pinchando en los enlaces de tendencias, están soportados de caja en cualquier servicio de git que ofrezca una mínima funcionalidad como Github o Gitlab.

Sintaxis de lenguajes de marcado

Hay unos que se caracterizan por ser más fáciles y otros más difíciles pero con más funcionalidad.

Por ejemplo, para poner énfasis en algo tenemos lo siguiente:

Markdown AsciiDoc DocBook
texto en **negrita** texto en *negrita*

texto en <emphasis>negrita</emphasis>

Resumir toda una sintaxis en tres líneas es muy difícil pero esto nos da una idea de que Markdown y AsciiDoc pueden llegar a parecerse en cuanto a simplicidad mientras DocBook, al usar xml, puede ser más tedioso.

La tendencia ha sido simplificar todo lo posible la edición manteniendo toda la funcionalidad necesaria y por eso lo más usado suele ser Markdown o AsciiDoc. Por supuesto que existen otros formatos como Doxygen, que son perfectamente válidos, pero parece que el mercado tiende a Markdown o AsciiDoc dependiendo del uso.

¿Markdown o AsciiDoc?

Si queremos un documento que al mostrarse por la web tenga enlaces a otros documentos pero al generarse el PDF se incrusten, deberemos poner en AsciiDoc:

ifdef::env-gitlab,env-github,env-browser[]
Secciones:

* link:./arquitectura/arquitectura.adoc[Arquitectura]
* link:./infraestructura/infraestructura.adoc[Infraestructura]

endif::[]

ifdef::ebook-format-kf8,backend-pdf[]

include::./arquitectura/arquitectura.adoc[]
include::./infraestructura/infraestructura.adoc[]

endif::[]

Si quieres hacerlo en Markdown, no podrás.

AsciiDoc tiene bastantes funcionalidades que Markdown no tiene y su uso es casi igual de fácil.

En Markdown ha habido intentos de incluir funcionalidad que en AsciiDoc viene de caja pero han desembocado en distintas implementaciones que pueden funcionar o no dependiendo del servicio que utilices.
Por ejemplo, la implementación de Gitlab es distinta a la de Github, lo que supone un problema en cuanto a portabilidad.

Renderizando, ando

Vamos a renderizar este documento a diferentes formatos a partir de este archivo, como son:

Para renderizar un documento hemos usamos la imagen docker-asciidoctor que la organización mantiene en dockerhub.

Creando un portal

Podría subir los html estáticos a un servidor y ya tendría mi portal, pero existen frameworks que permiten generar portales fácilmente tomando como fuentes uno o varios repositorios.

En la wikipedia nos encontramos con tres frameworks cuyas pruebas me han hecho llegar a las siguientes conclusiones:

Antora

Antora permite la creación de un portal a partir de un playbook en formato yaml donde se definen todos los repositorios que lo forman.

De esta forma podemos tener diferentes repositorios para sistemas, seguridad, desarrollo, …​ y Antora se encargará de juntarlos todos en un solo portal al que aplicará los mismos estilos. Cada uno de esos repositorios es un "componente" del portal para Antora.

En cada repositorio (componente) necesitamos crear un archivo llamado antora.yml donde definiremos las secciones que formarán este componente. Cada una de esas secciones es un "módulo" para Antora.

Si el repositorio tiene varias ramas nos puede crear una versión del componente por cada una de ellas.

Un ejemplo de Antora

Por suerte la documentación oficial es realmente clara en este aspecto pero voy a intentar simplificarla más.

Clona el siguiente repositorio:

git clone https://gitlab.com/antora/demo/demo-site

Dentro del repositorio verás el playbook site.yml con este contenido:

site:
  title: Antora Demo Site
  # the 404 page and sitemap files only get generated when the url property is set
  url: https://example.org/docs
  start_page: component-b::index.adoc
content:
  sources:
  - url: https://gitlab.com/antora/demo/demo-component-a.git
    branches: master
  - url: https://gitlab.com/antora/demo/demo-component-b.git
    branches: [v2.0, v1.0]
    start_path: docs
ui:
  bundle:
    url: https://gitlab.com/antora/antora-ui-default/-/jobs/artifacts/master/raw/build/ui-bundle.zip?job=bundle-stable
    snapshot: true

Este archivo indica a antora que la raíz del portal (site.start_page) será el archivo index.adoc del componente b.

Además irá a los dos content.sources y generará sus html con la versión master para el primero mientras para el segundo generará las versiones v2.0 y v1.0 partiendo del directorio docs.

Ejecuta esto para generar los estáticos:

docker run -u $UID --privileged -v `pwd`:/antora --rm -t antora/antora site.yml

Tu portal ahora se encuentran en build/site/index.html

Cambios para construir un portal

Imagina que tienes un archivo en AsciiDoc llamado antora.adoc en un repositorio y quieres cambiar su estructura para tener un portal. Todo el contenido está en la rama master de un único repositorio ubicado en https://github.com/elmanytas/antora-examples:

A partir de este momento puedes trabajar tal como lo hacías antes escribiendo en modules/ROOT/pages/ y dejando las imágenes en modules/ROOT/assets/images/. Todo lo que escribas aparecerá en tu portal ejecutando:

docker run -u $UID --privileged -v `pwd`:/antora --rm -t antora/antora site.yml

26 de March de 2019 a las 23:33

23 de March de 2019

Jose Manuel

Kubernetes a través de Terraform

En esta ocasión vamos a probar como de bueno o malo es el provider de Terraform para Kubernetes.

Por si no lo conoces, Terraform es el "anillo único" que permite gestionar como código todas las infraestructuras que se te pongan por delante (y para las que haya un provider). Una ventaja de Terraform es que si eliminas un objeto de tu código, también se elimina en tu infraestructura, lo que no pasa con Cloudformation de AWS o Heat de OpenStack.

Buscando el Ingress

Con un rápido vistazo a la página del provider de Terraform para Kubernetes echamos en falta algo tan normal como el objeto Ingress y tampoco podemos crear objetos custom. Si además conoces OpenShift verás que faltan DeploymentConfig y Route.

Pero vamos a ver porqué no están los Ingress. Lo primero que pensé es que a lo mejor era un custom que no formaba parte del core de Kubernetes y por eso no estaba agregado así que me fui al código del provider de Kubernetes.
Vi que importaba un tal k8s.io/api/apps/v1 y me fui a buscarlo a github donde vi que el Ingress está implementado en el core directamente ¡desde hace 2 años!

Conclusión: en Terraform faltan cosas que no te esperas que falten, como Ingress aunque parece que algo se está moviendo, y OpenShift viene con muchos objetos que ni se pueden gestionar desde Terraform ni creo que se vayan a poder gestionar a corto plazo aunque algo se está moviendo también.

Caso OpenShift

Si estamos dispuestos a usar Deployments en OpenShift y gestionar las rutas a mano, entonces este provider si nos puede valer.

Con OpenShift he probado esto:

provider "kubernetes" {
  host = "https://openshift.serenity.es:9443"
}

resource "kubernetes_config_map" "example" {
  metadata {
    name = "my-config"
    namespace = "terraform"
  }

  data {
    api_host = "myhost:443"
    db_host  = "dbhost:5432"
  }
}

Y me ha creado el configmap:

jmferrerm@serenity:~/gitops/openshift$ oc get cm
NAME        DATA      AGE
my-config   2         6s

Luego he probado a borrarlo del fichero y lo ha borrado de OpenShift así que en principio hace lo que dice que hace:

jmferrerm@serenity:~/gitops/openshift$ terraform apply
kubernetes_config_map.example: Refreshing state... (ID: terraform/my-config)

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  - kubernetes_config_map.example


Plan: 0 to add, 0 to change, 1 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

kubernetes_config_map.example: Destroying... (ID: terraform/my-config)
kubernetes_config_map.example: Destruction complete after 0s

Apply complete! Resources: 0 added, 0 changed, 1 destroyed.
jmferrerm@serenity:~/gitops/openshift$ oc get cm
No resources found.

¿Lo uso o no lo uso?

Esto es algo que te toca a ti valorar ... pero si quieres mi opinión, para Kubernetes es un SI rotundo gestionando con un "kubectl apply" los ingress, que raramente van a cambiar, y esperando a que finalmente se cree esa función.

En OpenShift tenemos que estar dispuestos a usar Deployments en vez de DeploymentConfigs y eso en la mayoría de ocasiones suele ser un problema ya que al crear una aplicación, OpenShift utiliza DeploymentConfigs.
En OpenShift el criterio es ... ¿Quiero usar GitOps o los procedimientos que me ofrece RedHat para la gestión de Kubernetes?

Yo llevo apostando por GitOps desde antes que alguien le diera nombre.

23 de March de 2019 a las 07:20

10 de March de 2019

Jose Manuel

Currículum

Jose Manuel Ferrer Mosteiro

Skills

  • Administrador Unix con experiencia en múltiples distribuciones de GNU/Linux (RHEL, Ubuntu, CentOS, Debian) y Windows.
  • Conocimientos de IaaS / PaaS públicos con AWS y GCE .
  • Conocimientos muy profundos de IaaS / PaaS privados con OpenStack, Kubernetes y OpenShift así como de Docker y KVM.
  • Gestión de la configuración y automatización (Puppet, Ansible, OpenStack Heat).
  • Programación con Python, Ruby, Bash y Perl.
  • Sistemas de control de versiones git y svn.
  • Experiencia con despliegue y gestión de sistemas distribuidos (ElasticSearch, MongoDB, Logstash, ActiveMQ, RabbitMQ)
  • Habilidades en entornos de realidad virtual (OpenSim, High Fidelity).

Charlas

Experiencia

Septiembre 2014 - ahora: Paradigma Digital

  • Despliegue, gestión y uso de Kubernetes, OpenShift y OpenStack.
  • Automatización y gestión de la configuración con Ansible y Puppet.
  • Despliegue, gestión y uso de jobs y pipelines en Jenkins.
  • Docker
  • Codificación en Python y bash
  • Git
  • Gestión de RHEL, Debian, CentOS y Ubuntu.
  • Despliegue y gestión de ElasticSearch, Logstash y Kibana dentro y fuera de OpenShift.
  • Despliegue y gestión de MongoDB y Redis.
  • Despliegue y gestión de RabbitMQ y ActiveMQ.

10 de March de 2019 a las 06:45

25 de January de 2019

Jose Manuel

MySQL no es perfecto

Primer problema de MySQL en los 12 años de vida de este blog:
MariaDB [drupal7]> select * from semaphore;
ERROR 144 (HY000): Table './drupal7/semaphore' is marked as crashed and last (automatic?) repair failed
MariaDB [drupal7]> repair table semaphore;
+-------------------+--------+----------+----------------------------------------+
| Table             | Op     | Msg_type | Msg_text                               |
+-------------------+--------+----------+----------------------------------------+
| drupal7.semaphore | repair | warning  | Number of rows changed from -2032 to 0 |
| drupal7.semaphore | repair | status   | OK                                     |
+-------------------+--------+----------+----------------------------------------+
2 rows in set (0.00 sec)

MariaDB [drupal7]>
Hasta hoy yo estaba convencido de que era irrompible.

25 de January de 2019 a las 10:57

31 de December de 2018

Jose Manuel

Retrogaming IV: Las maquinitas

Las maquinitas

Toda una reliquia de nuestra niñez. Nos pasamos horas frente a una pantalla de cristal líquido escuchando un pitido tras otro con nuestra Game & Watch preferida.

Pues puedes volver a hacerlo y a tus hijos les encantarán estos juegos.

El problema

No todas las maquinitas se ven igual en todos los emuladores y el catálogo de juegos disponibles es muy limitado así que para muchos juegos no nos quedará otra que comprar las máquinas originales.

Y no estoy hablando de juegos extraños. El Donkey Kong II, uno de los grandes referentes de este género, solo se puede jugar bien con la maquinita original.

Y aquí llega el auténtico problema: salvo que tengas 6000€ sueltos en el bolsillo y unos meses libres para buscar, ir y venir, no podrás comprarlas todas. El precio de cada maquinita en el mercado de segunda mano oscila entre los 50€ y los 500€ dependiendo de distintos factores en los que no voy a entrar.

Si, la maquinita que tienes tirada en el trastero vale más que los pendientes de oro que le regalaste a tu chica. :-D

Formatos de pantalla

Las maquinitas se hicieron en un momento en que primero se pensaba el juego y luego el hardware. Eso hizo que hubiera maquinitas de una sola pantalla en horizontal, una pantalla en vertical, dos pantallas en horizontal dispuestas en vertical o dos pantallas en horizontal dispuestas en horizontal. Lo único que falta es en diagonal. ;-)

Como te podrás imaginar, en un mundo que ha evolucionado hacia el formato panorámico con una sola pantalla, emular estas consolas puede resultar un problema así que veremos cada caso por separado tomando como referencia los siguientes juegos que todos conocemos:

  • Donkey Kong Junior
  • Donkey Kong
  • Mario Bros

Donkey Kong Jr.

Este parece de los fáciles: pantalla panorámica, cruceta y un botón. Pero si buscamos su ROM no la encontraremos así que ya no es tan fácil.

Pero estamos buscando mal: en el año 2007 Nintendo sacó la Game & Watch Gallery 3 y uno de los juegos que tenia era precisamente el Donkey Kong Jr. Asi que el problema ahora es emular una GameBoy Advance y ¡eso es muy fácil!
Aqui lo tenemos:

Con otros juegos, como el Donkey Kong Circus, emularemos la consola usando el core Handhelds Electronic de RetroArch con este resultado:

Mas adelante entraremos más en detalle, pero ahora quédate con que de una forma mas o menos retorcida si se puede jugar bien a casi todos los que tengan formato panorámico, siempre que la rom este disponible.

Donkey Kong

Dos pantallas en horizontal dispuestas en vertical.

En una sola pantalla panorámica ... poderse se puede pero el resultado es un churro con el core Handhelds Electronic de retroarch por culpa del hardware:

En este caso la pantalla cuanto más alta mejor así que si hay que elegir yo me quedaria con la PSVita.

Si has leído mi artículo anterior pensarás: "pues pon la psvita en vertical usando el joystick derecho para las flechas y el botón para saltar". ¡Eres un blasfemo! ¡A un niño no se le enseña a jugar a una maquinita con un joystick! ;-)

La buena noticia es que en el 2006 Nintendo hizo la Game & Watch Collection 1 para Nintendo DS donde incluyó entre otros el Donkey Kong y asi es como se ve en una Nintendo 3ds y una dsi:

Doy fe de que la sensación es casi exactamente igual a la de la máquina original.

Mario Bros.

Dos pantallas en horizontal dispuestas en horizontal.

Si el panorama del formato vertical estaba mal este no está mucho mejor. En este formato la PSVita gana por la proporción y tamaño de la pantalla. Incluso haciendo zoom el resultado sigue sin ser óptimo, aunque si mejor que el que viene en la Game & Watch Gallery 3 tal como se puede ver aquí:

He probado a jugar con la PSVita al Mario Bros habiendo obtenido los 800 y pico puntos que obtengo con la maquinita original y tengo que decir que me quedo con Retroarch antes que con el de la Game & Watch Gallery 3. La emulación tiene algunos fallos que ocurren cuando tardas demasiado en recoger un paquete pero por lo demás está perfecta.

Para el Mario Bros existe un Homebrew de Nintendo DS muy bien logrado en el que se usa la cruceta para los dos personajes del que hablaré en la sección de Homebrews.

Listado de todos los juegos

Si te interesa de verdad este tema en este artículo de la wikipedia tienes TODO.

Nintendo ¡no mató los Game & Watch al evolucionar las consolas! Con una pequeña búsqueda podemos encontrar varios títulos disponibles para DS y 3DS.

Además, mediante emulación utilizando retroarch y bajándonos las roms de varias maquinitas desde MADrigal podemos conseguir unos cuantos títulos.

En el wiki de emulation.miraheze.org tenemos información más extendida.

Tienes enlaces para bajarte varios juegos y homebrews en este blog.

Virtual Console para Nintendo 3ds

Nintendo publicó varios juegos de Game & Watch para GameBoy, GameBoy Color y GameBoy Advance que se ven bastante bien en la 3ds y su UX nos acerca bastante a la real. Además, podemos comprar todos los juegos de GameBoy que están en el catálogo. Un punto para Nintendo.
Por supuesto también funcionan con los cores que vienen en Retroarch. En el post de GameBoy explicaré como.

Pegas:

  • Con los juegos de dos pantallas para GameBoy Nintendo optó por poner la pantalla superior más pequeña y la inferior más grande. Tampoco es que se pueda hacer mucho mejor pero el resultado es bastante cutre. Los juegos de dos pantallas hay que jugarlos con dos pantallas.
  • Al ser juegos de GameBoy emulados, heredan la resolución de pantalla de esta máquina que resulta claramente insuficiente para los juegos de Game & Watch.

  • Una pega más es que no se ven las sombras tan características de este tipo de pantallas LCD. No les hubiera costado nada emularlas.
  • Empezamos con los que ahora Nintendo ofrece como Virtual Console:

    Game & Watch Collection para Nintendo DS

    Allá por el 2006 Nintendo sacó dos juegos que emulaban Game & Watch para Nintendo DS aprovechándose bien de las dos pantallas.

    Sin duda, si lo que quieres es revivir estos clásicos de dos pantallas y no tienes la maquinita original, necesitas el Game & Watch Collection 1. Se hace una emulación casi perfecta utilizando las dos pantallas y la disposición de los controles recuerda mucho más a los originales.

    Si me dan a elegir mejor en la DS que en la 3DS porque la DS tiene las dos pantallas iguales y la resolución encaja mucho mejor.

    Homebrews

    La mala noticia es que Nintendo solo saco esos tres juegos de dos pantallas dejando de lado otros grandes como el Donkey Kong II.

    Donkey Kong II

    Existe un Homebrew del Donkey Kong II para Nintendo DS hecho por Martin Kool pero no tiene bien resuelto el tema de las colisiones así que no es muy jugable. En el apartado estético roza la perfeccion. Con la Y y con la X se activan las sombras y las colisiones.

    Mario Bros

    Para el Mario Bros existe un Homebrew para Nintendo DS muy bien logrado en el que se usa la cruceta para Mario y Luigi.

    Poniendo otra cruceta en la parte izquierda de la pantalla superior creo que se podria conseguir casi la misma sensacion que en la consola original.
    Habría que usar una DS Lite y mover la antena al lado derecho de la pantalla o en el caso de la DSi quitar la antena tal como se ve en esta foto de la pantalla desmontada:

    Donkey Kong Jr.

    Existe un homebrew interesante para el Donkey Kong Jr. en github cortesía de PaulGoes: https://github.com/PaulGoes/DS-Donkey-Kong-Jr/

    Pokemon Mini

    Un comercial pensó ... ¿Y si aprovechando el poder de la marca Pokemon hacemos una videoconsola que no tenga nada que ver con Pokemon para conseguir ventas millonarias? Y así nació ¡Pokemon Mini! pero les salió mal y cerraron el chiringuito poco después de abrirlo.

    Me recuerda a lo de, "visto el éxito de Java, ¡llamémoslo JavaScript!". :-D
    Vamos, que no tienen nada que ver pero aprovechando el nombre de Pokemon sacaron esta consola donde podemos encontrar juegos de todo tipo con la temática de Pokemon. Por ejemplo, cada vez que haces 4 líneas del tirón con el Tetris, aparece una pokeball en la pantalla y capturas un Pokémon.
    Esta es extremadamente difícil de conseguir pudiendo llegar fácilmente en el mercado de segunda mano a los $500.

    También existe un emulador para el Pokemon Mini así que si a tu hijo le gustan los Pokemon y quieres que aprenda a jugar al tetris esta puede ser una buena opción.

    Existen emuladores para Nintendo DS y PSP así que funciona sobre 3ds y PSVita sin problemas. Me vuelvo a quedar con la 3ds por tema de tamaño de pantalla.

    Hay un port nativo para 3ds.

    La mejor

    La Nintendo DS es la mejor máquina para jugar a los juegos Game&Watch que existen disponibles para ella. La segunda opción es la 3DS y la peor es la PSVita/PSP tal como le pasaría a cualquier consola con una sola pantalla.

    Nintendo, por favor

    Señores de Nintendo, fabriquen estas maquinas por 2 euros en China y las compraremos por 15. ¡Solo tenéis que poner las manos para recoger el dinero!

    31 de December de 2018 a las 08:38

    25 de July de 2018

    Jose Manuel

    Retrogaming III: Los emuladores

    Seguro que ya lo cononoces el agregador de emuladores con más tirón del momento: Libretro o Retroarch. Pero lo que no conoces son algunos trusquis mal documentados que te permiten jugar bien y que te voy a contar aquí.

    En este post haré una pequeña introducción a retroarch, instalación y lanzamiento de alguna rom que se vea mal.

    Por si no lo conoces ...

    ... libretro es un lanzador de emuladores, que él denomina cores. Existen cores para Arcade, maquinitas, Gameboy, PlayStation, ... y todos ellos vienen instalados o son fácilmente descargables con Retroarch, que es otro proyecto que utiliza el api de libretro para hacer el frontend.

    Su diseño modular en interfaz y cores nos permite poder instalar solo lo que necesitamos permitiéndonos utilizar hardware a medida. Actualmente el 90% de las soluciones de emulación funcionan con Retroarch.

    Hace no mucho tiempo ...

    ... en nuestro planeta, si querías usar un juego primero tenías que elegir un emulador que pudiera emularla de entre todos los existentes, luego conocer los parámetros con los que lanzar el emulador y muchas veces el juego fallaba sin saber porqué.

    Con retroarch tenemos un solo instalador para todos los emuladores existentes, una sola interfaz para lanzar los juegos y un procedimiento de instalación fácil y rápido.

    Instalación

    Primero ve a la y mira si tu consola está entre ellas. Si no aparece ahí puedes probar suerte directamente en la página de descargas.

    Te recuerdo que en esta serie de posts no hablamos de PCs sino de PSP, PSVita, NDS y 3DS.

    En esta parte doy por supuesto que tu consola ya está desbloqueada y conoces de forma básica su manejo. Si no lo está y no sabes como hacerlo te tendrás que esperar a que lo cuente en algún post de esta serie para que lo explique un poco así que ten paciencia y mientras tanto ¡no actualices el sistema de la consola!

    Instalación en PSVita

    Tenemos dos opciones de instalación: vía homebrew browser y vía descarga de la aplicación.

    La instalación usando el Homebrew Browser dejó de funcionar en algún momento porque ahora es necesaria una copia manual de archivos después de instalar el paquete vpk y el Homebrew Browser solo instala paquetes.

    En la página de descargas vemos dos archivos y nos tenemos que bajar los dos. Instalamos el vpk utilizando VitaShell.

    Copiamos el contenido de Retroarch_data.7z en ux0:data/ para lo cual no recomiendo utilizar el servidor de ftp que viene con VitaShell porque aunque solo son 28mb, son miles de archivos que transmitidos por ftp pueden tardar horas en copiarse.

    Y ya lo tenemos:

    Instalación en PSP

    Nos vamos a la página de descargas y nos bajamos el archivo para nuestra consola ... pero vemos que ocupa muy poco espacio, solo 4 megas y pico.

    Esto se debe a que tiene muy poquitos cores y algunos de los que faltan son muy importantes, como el de MAME, pero eso ya lo hablaremos más adelante.

    Para instalarlo copiamos el contenido del 7z al directorio PSP/GAME/RetroArch de la tarjeta y ya está instalado.

    Instalación en Nintendo New 3ds

    Como ya sabrás podemos utilizar homebrews en formato cia o 3dsx. Los .cia son instalables de 3ds que aparecerán en el menú con el resto de los juegos mientras los .3dsx son archivos que copiamos en el directorio sdmc:/3ds/ y que se podrán abrir usando "The homebrew launcher".

    Si elegimos el formato 3dsx solo tenemos que copiar el contenido del archivo en la raíz de nuestra MicroSD o en sdmc:/3ds/ en caso de usar el servicio de FTP, cosa que no recomiendo porque nos podemos tirar horas para copiar todo.

    Si elegiste la distribución 3dsx ¡ya está instalado! peeeeero me ha dado problemas que lo han hecho inusable asi que no lo recomiendo.

    Si elegiste la distribución cia debes instalar todos los cia usando el FBI de la forma habitual.

    En el caso de Nintendo, el resultado es un poco más sucio porque una vez instalado todo tendrás un icono por cada uno de los cores en el menú:

    Se suponía que Retroarch te ocultaba la existencia de los cores pero este te los muestra todos en el menú principal. Yo los he puesto muy a la derecha para diferenciarlos del resto de programas.

    Instalación en Nintendo DSi

    La Nintendo DSi no está soportada por retroarch pero tiene emuladores por separado que ya veremos más adelante. No la subestimes por no poder usar Retroarch, aunque ya te adelanto que no es la mejor opcion.

    Primeros pasos

    La guía oficial es bastante explicativa.

    Configuración de retroarch

    Probablemente nunca tengas necesidad de tocar la configuración pero por si acaso en el repo de retroarch puedes encontrar lo necesario para saber donde tocar.

    El fichero de configuración se encuentra en ux0:/data/retroarch/retroarch.cfg en el caso de la psvita o en sdmx:retroarch/retroarch.cfg en el caso de la 3ds.

    En este archivo se guarda la configuración de retroarch y de los cores de retroarch a nivel general. Si ves que TODOS los juegos de GameBoy funcionan mejor con una configuración aquí es donde debes tocar.

    Convenciones

    Es muy importante conocer el nombre de los botones para poder entender cualquier guía así que memoriza estos nombres:

    En las máquinas que solo tienen dos botones, como la GameBoy, los botones son el A y el B.

    Funciones que debes habilitar

    Antes de empezar a jugar debes tener activada la función que te permite congelar la partida y guardar el estado del emulador o realizar configuraciones específicas para ese juego.

    Se configura en "Configuración | Input | Menu Toggle Gamepad Combo" con las teclas del pad derecha e izquierda.

    En la PSVita se activa con L + R + Select + Start. Si tienes la 1000 te costará cogerle el trusqui a pulsar Select y Start a la vez pero yo ya lo hago sin problemas.

    En la New 3ds yo he elegido L + R + Y + Down pero pulsando sobre la parte inferior de la pantalla táctil también sale.

    Configuración avanzada

    Esto no te va a hacer falta, pero por si te hace falta te pongo un par de casos de juegos cuya configuración he tenido que cambiar para que se vean bien.

    Rotación de la pantalla y remapeo de teclas

    Vamos con el pacman de Arcade donde al arrancar vemos que ¡está del revés!

    Con el juego arrancado pulsamos el Menu Toggle Gamepad Combo y en la configuración elegimos la opción "Overrides":

    Y guardamos las opciones para ese juego:

    Esto nos creará un archivo de configuración para ese juego en la ruta_de_datos_retroarch/config/nombre_del_emulador/nombre_de_la_rom.cfg .

    Configuramos las opciones:

    video_rotation = 2
    video_allow_rotate = true
    


    y este será el resultado en el que rotamos 180 grados la pantalla:

    Pero este juego esta pensado para una pantalla mas vertical asi que necesitamos cambiar la rotacion y el mapeo de teclas.
    Rotamos la pantalla con esta configuracion:

    video_rotation = 3
    video_allow_rotate = true
    

    Y para el mapeo de teclas, mientras estamos en el juego salimos al menu con el Menu Toggle Gamepad Combo, vamos a "Controls" y cambiamos el mapeo de teclado para que:
    • arriba -> izquierda
    • abajo -> derecha
    • izquierda -> abajo
    • derecha -> arriba

    Luego guardamos los cambios, salimos, entramos y aqui esta:

    Proporción de la pantalla

    Pongamos por caso que arrancamos el Mario Bros y nos sale este churro:

    Pero esperamos esta proporción:

    Le damos a la combinación de teclas de arriba (Menu Toggle Gamepad Combo), elegimos la opción de sobreescribir las opciones para este juego y eso nos creará un archivo donde podemos personalizarlas, en el caso de la psvita, en ux0:data/retroarch/config/Game & Watch/Mario Bros. (Nintendo, Multi Screen).cfg.

    Sabiendo que la pantalla de la psvita es de 960x544 configuramos estas opciones:

    custom_viewport_width = 960
    custom_viewport_height = 544
    


    y el resultado es el siguiente:

    Si queremos hacer zoom sobre una zona del juego no tenemos más que decirle que nuestra pantalla es más grande de lo que realmente es y que empiece a pintar en el vacío:

    custom_viewport_width = 1200
    custom_viewport_heigh = 680
    custom_viewport_x = -115
    custom_viewport_y = -100
    


    Este es el resultado:

    Conclusiones

    Con Retroarch podrás tener todos los emuladores que quieras y aunque nunca vayas a tocar la configuración, puedes hacerlo para adaptarla a cualquier máquina existente en el mercado y poder enseñarle a tus hijos lo que eran juegos de verdad en una consola portátil:

    25 de July de 2018 a las 15:11

    Retrogaming (II)

    Cuando buscamos recordar juegos antiguos y no tenemos restricciones nos vale cualquier portátil viejo pero si queremos una máquina que nos quepa en el bolsillo empiezan los problemas.

    En esta y sucesivas entradas veremos una comparativa entre distintas consolas portátiles y como les pegan los distintos emuladores que existen entre los que nos encontramos:

    To retro or not to retro?

    La definición de retro es bastante subjetiva. Para alguien mayor puede que solo los juegos de Arcade sean retro pero para mis hijos lo es todo lo que tiene más de 10 años.

    Para mi algo retro es algo que no puedes comprar nuevo en una tienda aunque tengas dinero infinito. Por ejemplo, una Nintendo GameBoy. En el caso del software el panorama se complica bastante porque hay juegos que tienen 20 años y se siguen vendiendo para consolas modernas, como por ejemplo SEGA Genesis Classics para PS4 o SEGA 3d Classics Collection para Nintendo 3DS.

    También tenemos en la tienda The Legend of Zelda: Ocarina of Time 3D que es exactamente el mismo juego que se hizo para Nintendo 64.

    Es bastante habitual que los fabricantes de consolas modernas sigan haciendo reediciones de juegos viejos por lo que a lo mejor ya tienes el trozo de retroconsola que necesitas y no lo sabías.

    ¡Podemos jugar legalmente al Sonic si nos compramos una Nintendo 3DS! Si es así ¿Es moralmente correcto bajárselo de emuparadise, portalroms, romsmania, loveroms, ... y jugarlo? ¿No es más cómodo y seguro pagar los 20$ que valen los 9 juegos?

    ¿Y en el coche?

    ¡Podemos comprar el Golden Axe para PS4! Pero ¿como hago para enseñárselo a mis hijos en el coche de viaje o en la sala de espera del médico?

    ¿Como hago para que mis hijos sepan para que sirve un pollo de goma con una polea en el medio en una consola portátil?

    ¿Que es ser portátil?

    Para mi una consola portátil es aquella que te cabe en el bolsillo tal y como lo hace un móvil:

    • Por ejemplo la Nintendo DSi es una consola portátil.
    • La PSVita cabe en el bolsillo por un pelo pero también se pueden considerar portátil.
    • La Nintendo Switch NO es una consola portátil a pesar de no necesitar estar enchufada para funcionar. Es una consola estupenda y para algunos casos la mejor que existe pero no cabe en el bolsillo así que no esperes verla mencionar en esta serie.

    ¿Que nos sirve para jugar?

    Para mi es esencial la parte ergonómica de la consola y eso hace que un móvil con pantalla táctil me parezca una opción horrible. Si quieres destrozar un juego úsalo en tu móvil.

    Es necesario que al menos disponga de cruceta y 4 botones ya que son los que usan los juegos antiguos y es deseable que permita jugar a juegos más modernos.

    ¿Porqué con emuladores?

    En mi caso es crucial que todos los juegos funcionen sobre un emulador ya que nos permite guardar una instantánea de la partida para seguir a partir de ahí si nos matan.

    En los juegos de mi época cuando te mataban tenías que empezar desde el principio y eso es algo que cuando vas justo de tiempo no te puedes permitir.

    Consolas a comparar con los emuladores

    Voy a comparar las siguientes consolas:

    Se quedan fuera de la comparativa la GPD XD, Retromini, raspiboy, ... que tienen muy buena pinta pero hasta la fecha no he tenido contacto con ellas así que no puedo opinar para bien ni para mal.

    Puede que los resultados te sorprendan ya que no hay ninguna perfecta para todo aunque ya te adelanto que yo me decanto por la PSVita ya que cubre más casos de uso que el resto.

    Temas legales

    No queda del todo claro si utilizar emuladores bajándonos las roms es legal o no y tampoco queda claro si desbloquear una consola es legal o no.

    Desbloquear una consola consiste en ejecutar programas con los que en un principio el fabricante no contaba como por ejemplo una calculadora. Si bien es cierto que eso te permite utilizar backup de juegos y por lo tanto ser un pirata, tener una consola desbloqueada, siempre que sea para uso personal y no haya ánimo de lucro, no está perseguido.

    En caso de serlo habría que empezar por declarar ilegal el sistema operativo que más se utiliza para jugar a juegos piratas, piratearlos o se usó para entrenar a los pilotos que estrellaron los aviones contra las torres gemelas: Microsoft Windows.

    25 de July de 2018 a las 05:08

    08 de July de 2018

    Jose Manuel

    Retrogaming (I)

    En esta serie de post os voy a mostrar mis experiencias con casi toda la historia de los videojuegos desde las Game&Watch hasta la PSVita pasando por la PlayStation sin dejar de lado a Nintendo.

    Al final explicaré como conseguir las consolas necesarias, hackeo de las mismas y todo lo que necesitas saber para sacarles todo el partido. Y por supuesto cual me parece la mejor para usarla de retroconsola.

    Limitaciones

    Solo una limitacion: debe poder jugarse en una consola portátil bien a traves de emulación o bien con algún tipo de hack porque mi cantidad de tiempo para sentarse a jugar es extremadamente limitada pero si puedo hacerlo esperando al autobús.

    Muchos padres sabréis de lo que estoy hablando. Es lo que ocurre cuando pasas de tener poco dinero pero si tienes tiempo a tener poco tiempo pero si dinero.

    ¿Porqué?

    Tras leer Ready Player One quise:

    • entender que es lo que hace realmente bueno un juego: ¿Porqué antes nos pasabamos horas delante de una pantalla con gráficos pixelados mientras ahora tenemos en el store de nuestro móvil miles de juegos que desinstalamos al minuto? ¿Que es lo que hace realmente bueno a un juego?
    • vivir parte de la historia de los videojuegos que me había perdido: cuando mis compañeros hablan de ciertos juegos antiguos y no los conozco me siento como si hablaran de Optimus Prime y no supiera quien es.
    • enseñarle a mis hijos como se jugaba antes: los niños van a tener sobredosis de gráficos y efectos especiales pero a lo mejor esa no es la esencia que hace un juego bueno. Ahora nos tragamos cualquier cosa que pongan en el cine con buenos efectos especiales. ¿Es realmente lo mejor para ellos o tienen que aprender a valorar algo más?

    Un buen juego

    Para valorar la sensación que ofrece un juego yo tomo en cuenta los siguientes factores por orden de importancia:

    • jugabilidad
    • ergonomía
    • historia
    • estética
    • juega con amigos

    Jugabilidad

    Nos podemos pasar horas jugando al Candy Crush o al Tetris. Son juegos sencillos y que cualquier estudiante de informática puede programar despues del primer año de carrera.

    Son pura jugabilidad.

    Ergonomía

    Volviendo al Candy Crush y al Tetris, fíjate que antes triunfaba era el Tetris y ahora el Candy Crush. ¿Porqué?

    El Candy Crush parece estar diseñado para jugar en móviles y todos tenemos un móvil. Se puede jugar solo con un solo dedo.

    Para jugar al Tetris sin frustrarte necesitas botones para desplazamiento y giros. Si le das el Tetris a tu hijo en el móvil te va a durar un par de minutos. Dale el mismo juego en una GameBoy y le tendras enganchado horas.
    Yo y mi hijo podemos dar fe de ello.

    Los que dicen que con un teléfono móvil las videoconsolas no tienen sentido sencillamente no tienen ni idea de lo que están hablando. Intenta jugar sin dos Joysticks al Geometry Wars.

    Estética

    En el store de tu móvil tienes un monton de candy crushes pero en el apartado estético (explosiones, sonidos, desplazamientos, ...) el equipo de desarrollo ha hecho un gran trabajo. Ese factor es el diferencial en muchos juegos que pasan de ser "uno más" a ser auténticos éxitos.

    Historia

    Ya existían juegos parecidos a los Angry Birds. Una de las claves de su éxito ha sido la historia de los cerdos malos que se quieren comer los huevos. ¿Quien no va a querer ayudarles?

    Muchas veces he oído decir que es un juego sencillo que podía haber hecho cualquiera. Tu mismo podrías haber hecho el Apple Flinger.

    Si todavía no entiendes la diferencia juega un rato al Angry Birds y otro al Apple Flinger. Luego sigue leyendo.

    Juega con amigos

    Por ultimo, la posibilidad de jugar online compitiendo con tus amigos o con otros clanes es otro factor que hay que tomar en cuenta.

    Para mi es totalmente prescindible pero hay que reconocer que muchos juegos no tendrian el éxito que tienen si no fueran online, por ejemplo el World of Warcraft.

    AdjuntoTamaño
    Image icon Imagen de portada.3.81 MB
    Image icon Portada reducida175.44 KB

    08 de July de 2018 a las 07:02

    10 de March de 2018

    Jose Manuel

    Juego, Metaverso y Realidad Virtual (y III)

    VRMMOM

    Virtual Reality Masive Multiplayer Online Metaverse .

    Características deseables en un VRMMOM

    Un software para construir un VRMMOM debería:
    • permitir compartir y crear contenido
    • ser Sofware Libre para poder:
      • modificar y redistribuir las modificaciones
      • desplegar tantas copias de la plataforma como queramos
      • poder elegir si desplegar en infraestructura pública o privada
    • tener carácter distribuido:
      • legislación distribuida
      • tolerancia a fallos
    • ser infinitamente escalable
    • usar protocolos abiertos para ser interoperable
    • ...

    ¡Como internet!

    Un poco de historia

    El software sobre el que voy a hablar en los siguientes posts lleva gestándose unos 20 años y hay una persona que nos va a servir de hilo conductor. No es una idea peregrina que se le acaba de ocurrir a alguien.

    Todo empieza así: un adolescente sueña con una realidad virtual que no tenga las mismas limitaciones que tiene nuestro mundo material … pero es solo un adolescente. Su nombre es Philip Rosedale.

    Su trayectoria resumida en unas pocas líneas:

    • Con 17 años crea su propia compañía para vender sistemas de bases de datos y comienza a estudiar física, acabando la carrera años más tarde.
    • Con 26 años (1994) Rosedale empieza a aterrizar el sueño de crear mundos virtuales usando Internet.
    • Con 27 años (1995) crea FreeVue destinado a la reproducción de vídeos en streaming.
    • Con 28 años (1996) FreeVue se integra en RealNetworks y pasa a llamarse RealPlayer. Es nombrado CTO y Vicepresidente de la empresa.
    • Con 29 años (1997) Rosedale, ya con dinero en el bolsillo, deja RealNetworks.
    • Con 31 años (1999) se lanza a por su sueño:
      • funda Linden Lab dedicado a la creación de hardware háptico para su uso dentro de entornos de Realidad Virtual
      • pero lo abandona por un problema de patentes de hardware
    • Con 33 años (2001) de Philip renombran su metaverso de pruebas "Linden World" y lo llaman "Second Life".
    • Con 34 años (2002) de Philip Rosedale se saca la primera beta de SecondLife con 16 regiones.
    • Con 35 años (2003) de Philip se introduce la moneda, teletransportes, ... y se evoluciona el producto.
    • Con 38 años (2006) de Philip Linden Labs recibe un premio a la innovación y uno de sus primeros usuarios pasa a ser millonario gracias a SecondLife.
    • Con 39 años (2007) de Philip Linden Labs hace Open Source el cliente. La comunidad deduce a partir de él las especificaciones del protocolo y crea OpenSimulator.
      A partir de OpenSimulator nacen otras compañías y organizaciones donde el protocolo que usa Second Life pasará a ser el más extendido en internet para la creación de mundos virtuales interconectados ... pero centrémonos en Philip.
    • Con 40 años (2008) Philip anuncia su dimisión como CEO y pasa a ser Director de la empresa.
    • Con 41 años (2009) Philip ve que las cosas no van bien y deja la empresa que el mismo fundó.

    Una trayectoria bastante movida. Lo que pasó a continuación fue la gran caída de interés sobre este mercado al aparecer alternativas que encajaban mejor con las necesidades de los usuarios y el tema dejó de salir en los telediarios.

    El interés sigue ahí

    Sin embargo en el 2011 se publica "Ready Player One" claramente inspirado en Second Life resultando un éxito rotundo en ventas que ha llegado hasta nuestros días y del que Steven Spielberg ha sacado una película que ¡se estrena en solo 20 días!

    En realidad el interés siempre ha estado ahí pero la tecnología hardware nunca ha estado a la altura.

    La historia continúa

    Desde el 2009 hasta ahora han seguido pasando cosas y para mi la más relevante desde el punto de vista de software es que:

    • con 45 años (2013) y 4 hijos Rosedale comienza un nuevo proyecto:

    caché

    ¡High Fidelity cumple!

    High Fidelity cumple todas las características que debería cumplir un VRMMOM:

    • es software Libre
    • personalizable hasta el extremo
    • infinitamente escalable
    • distribuido

    En High Fidelity se solucionan los problemas de los que adolecen anteriores tecnologías, se incorporan los últimos avances en hardware háptico y de realidad virtual así como los últimos avances en tecnologías distribuidas como blockchain.

    En los próximos posts veremos donde encaja cada pieza en High Fidelity.

    ¡El futuro está llegando!

    ¿Te imaginas hacer teletrabajo de verdad? ¿o quedar con tus amigos sin moverte del sofá viéndoles sonreir y hacer bromas?
    ¡No queda mucho para eso!

    ¡Emociónate!

    caché

    10 de March de 2018 a las 07:50

    31 de January de 2018

    Jose Manuel

    Juego, Metaverso y Realidad Virtual (II)

    En la década de los 2000 hubo una explosión en el interés por estos campos que llevó a empresas como Linden Lab a tener gran relevancia a nivel mundial pero rondando el año 2008 el mercado se desplomó sobreviviendo los mejor posicionados.

    Han pasado 10 años y mientras tanto para muchos ha pasado desapercibido que ese desplome del mercado en realidad nunca ha existido sino que el mercado se ha diversificado.

    Esto es lo que hay

    En el caso de los metaversos Linden Labs se ha traducido en una caída de usuarios a unos 40000 diarios en Second Life, que ya los quisieran muchas empresas, a los que da servicio una empresa con más de 200 empleados. A esos usuarios hay que sumar el resto de usuarios de los más de 100 de grids basados en Opensim y otros grids basados en otras tecnologías que actualmente está creciendo de forma moderada.

    También ha habido un desplazamiento de los usuarios que buscaban jugar hacia juegos masivos en línea como World of Warcraft.

    Los usuarios que querían experiencias de realidad virtual han encontrado un hueco en visitas virtuales a otros lugares utilizando tecnologías como Google VR.

    Los usuarios para los que la comunicación simple con texto e imágenes desde cualquier dispositivo era suficiente (la mayoría) se han desplazado a las grandes redes sociales.

    Algo está pasando

    Pero ahora se están dando varios factores de forma simultánea:

    ¿Puede estar preparándose otro boom?

    31 de January de 2018 a las 06:24

    20 de January de 2018

    Jose Manuel

    Juego, Metaverso y Realidad Virtual (I)

    A cualquier persona que tenga ojos en la cara le ha tenido que llamar la atención la relevancia que poco a poco está ganando el mercado de la muchas veces mal llamada Realidad Virtual.

    Las cosas claras

    Como cada vez que comienza una nueva moda el sector comercial va a empezar a usar el término Realidad Virtual para vender su producto, aunque no tenga nada que ver con eso. Ha pasado con términos como cloud, dron, linux o robot y seguirá pasando en el futuro.

    Muchas veces confundimos o vemos en la misma frase los términos juego, realidad virtual y metaverso que, aunque puedan relacionarse, se refieren a cosas distintas.

    Un juego ...

    ... se define como la actividad que realiza uno o más jugadores, empleando su imaginación o herramientas para crear una situación con un *número determinado de reglas*, con el fin de proporcionar entretenimiento o diversión (en wikipedia).


    La realidad virtual ...

    ... es un *entorno de escenas u objetos de apariencia real* (en wikipedia).

    Los metaversos ...

    ... son *entornos donde los humanos interactúan* social y económicamente como iconos, a través de un soporte lógico en un ciberespacio, el que actúa como una metáfora del mundo real, pero sin las limitaciones físicas o económicas allí impuestas (en wikipedia).

    41 ejemplos metaversos en el 2008 (caché):

    Algunas diferencias

    Utilidad y objetivos

    En un juego existen unos objetivos marcados por el propio juego. Tu personaje dentro del juego sirve para algo porque tiene unos objetivos.

    Sin embargo en un metaverso abierto la pregunta no es ¿para qué sirve el entorno? sino ¿para qué sirves tú? Los creadores del metaverso no ponen los objetivos sino que los ponen sus usuarios.

    En el término Realidad Virtual la existencia de objetivos es irrelevante.

    Interacción con el entorno

    En un juego el usuario interacciona modificándolo a medida que avanza.

    En un metaverso el usuario también interacciona pudiendo crear o eliminar objetos.

    En un entorno de Realidad Virtual no es necesaria la interacción del usuario pudiendo limitarse a mirar a su alrededor haciendo una "visita virtual".

    Interacción con otros usuarios

    En un juego no es necesaria la interacción con otros jugadores. Eres solo tú, la máquina y la empresa que explotará tus datos si te has bajado el juego gratis dándole permiso para usar tu GPS, ver tus contactos, fotos, hacer llamadas y enviar SMS. ;-)

    En un metaverso el usuario necesariamente ha de estar conectado a una red a la que también están conectados otros usuarios.

    En un entorno de Realidad Virtual no es necesaria la interacción con otras personas.

    Inmersión sensorial en el entorno

    En un juego no es necesaria la inmersión sensorial. Se puede jugar mientras se mantiene una conversación con otra persona en el mundo real.

    En un metaverso tampoco es necesaria la inmersión sensorial. Se puede interaccionar sin desconectarse del mundo real.

    En un entorno de Realidad Virtual SI es necesaria la inmersión ya que se bloquean tus sentidos a las sensaciones del mundo real.

    Tiempo real

    En un juego no es necesaria una respuesta inmediata. Un juego se puede poner en pausa.

    En un metaverso el tiempo corre para todos por igual ya que es un entorno interconectado. Las cosas ocurren aunque nadie las vea.

    En un entorno de Realidad Virtual podemos descansar y volver en otro momento sin que nada haya cambiado.

    Problemas de rendimiento imprevisible

    Un juego es un entorno controlado en el que se puede tener una cierta certeza de su fluidez dado que podemos conseguir que los objetos y texturas entren en la memoria de la tarjeta de vídeo.

    En un metaverso tanto el número de avatares como el número de objetos y texturas diferentes que pueden existir en un mismo lugar son desconocidos por lo que nos enfrentamos a graves problemas de rendimiento.

    El entorno de Realidad Virtual es un entorno controlado.

    Persistencia

    Un juego puede volver a ser jugado tantas veces como se quiera sin tener en cuenta como fue el resultado anterior.

    En un metaverso el estado debe ser actualizado y persistido de forma indefinida para que tenga sentido.

    En un entorno de realidad virtual puede no ser necesario almacenar el estado.

    En resumen

    Juego Metaverso Realidad Virtual
    Utilidad y objetivos *
    Interacción con el entorno * *
    Interacción con otros usuarios *
    Inmersión sensorial *
    Tiempo real * *
    Problemas de rendimiento imprevisibles *

    Juego + Metaverso + Realidad Virtual = High Fidelity

    (caché)

    Is not a game!

    En otros posts explicaré detalles sobre esta plataforma.

    20 de January de 2018 a las 07:49

    31 de December de 2017

    david::

    As the world shows you their teeth and people hate you in slow motion, you look at her sleeping...

    As the world shows you their teeth and people hate you in slow motion, you look at her sleeping happily in your arms. Who knows what she is dreaming of right now. Supermassive red giants collapsing for millions of years so she can be here with you.

    How lucky is that.

    31 de December de 2017 a las 19:22

    24 de October de 2017

    Jose Manuel

    Sincronizar dos repositorios de git

    Sincronizar dos repositorios con todas sus ramas es fácil pero encontrarlo en Google es realmente difícil.

    Nosotros lo usamos en jobs de Jenkins para sincronizar los repositorios de nuestro gitlab con los del servidor de turno de git del cliente.

    Pasos:

    1. Crear un repositorio
    2. Agregar remote 1
    3. Agregar remote 2
    4. Bajar remote 1
    5. Bajar remote 2
    6. Subir remote 1
    7. Subir remote 2
    8. Subir remote 1

    Y en código

    git init repositorio
    git remote add origin https://git.server1.com/usuario/repositorio.git
    git remote add upstream https://git.server2.com/usuario/repositorio.git
    git fetch -a origin
    git fetch -a upstream
    git push upstream "refs/remotes/origin/*:refs/heads/*"
    git push origin "refs/remotes/origin/*:refs/heads/*"
    

    solución de conflictos

    Si da algún conflicto del tipo:

     ! [rejected]        origin/develop -> develop (non-fast-forward)
    error: failed to push some refs to 'https://git.server1.com/usuario/repositorio.git'
    consejo: Updates were rejected because a pushed branch tip is behind its remote
    consejo: counterpart. Check out this branch and integrate the remote changes
    consejo: (e.g. 'git pull ...') before pushing again.
    consejo: See the 'Note about fast-forwards' in 'git push --help' for details.
    

    Vas al repositorio que tu sepas más desactualizado, eliminas la rama que tenga el contenido más viejo y le das a actualizar o haces un merge manual y o bien reduces el tiempo de sincronización entre repositorios o bien usas solo uno de los dos.

    En mi caso el job de Jenkins se ejecuta cada minuto y no estamos teniendo conflictos.

    AdjuntoTamaño
    Image icon git_logo.png4.2 KB

    24 de October de 2017 a las 11:08

    10 de February de 2017

    david::

    T3chfest 2017

    https://drive.google.com/file/d/0B7W0kQVbSVoAbkdvaXVXNXdFUlU/view

    10 de February de 2017 a las 07:47

    14 de November de 2016

    david::

    Slides of my next talk at GUL UC3M

    14 de November de 2016 a las 17:15

    27 de June de 2016

    Jose Manuel

    Conectando dos puntos a 8 km de distancia

    Normalmente escribo para explicar cosas difíciles pero esta vez escribo para explicar algo extremadamente sencillo: tirar un "cable de red" entre dos puntos a 8 km de distancia a un coste irrisorio.

    Nunca había confiado en la tecnología wireless y como además necesitas hacer una inversión en un equipamiento que no sabes si va a funcionar, nunca me había atrevido antes. Pero como este verano tenía un poco de tiempo he pensado que si otros se lo gastan en copas yo me lo puedo gastar en formación jugando a la antena rusa.

    El resultado ha sido conseguir unir dos casas con visión directa en unas pocas horas con un "cable wireless".

    Lo que queremos

    Vamos a hacer que las dos casitas se vean como si estuvieran en la misma red. La casita de la derecha tendrá acceso a internet a través de la casita de la izquierda:

    Fundamentos de andar por casa

    Salvo que hayas estado viviendo en otro planeta los últimos 5 años, estarás familiarizado con la típica red wifi casera con un portátil (Station) conectado a un punto de acceso (Access Point) utilizando cifrado WPA2 Personal. Pues pon el punto de acceso (AP) en el foco de una antena parabólica, haz lo mismo con el portátil (Station) y aléjalos 1 kilómetro. Verás con sorpresa que sigue habiendo comunicación entre los dos.

    Además necesitaríamos un protocolo que retransmitiera entre antenas paquetes como los que se usan para el DHCP. Como si las antenas fueran dos switches conectados por un cable "wireless". Pues el protocolo existe y se llama WDS.

    Material que he usado

    Dos antenas parabólicas que incluyan la electrónica de red necesaria para hacer de Access Point y Station. Deben poder configurarse en modo bridge y soportar WDS. Mejor si funcionan a 5GHz por la sobreutilización de los 2.4GHz . Las Ubiquiti PowerBeam M5 cumplen esas características.

    También necesitaremos dos cables de red para unir el transformador con la antena ya que utiliza PoE (Power Over Ethernet) donde que se usan 2 pares para la red y otros dos pares para la alimentación.

    Montaje

    Lo primero, monta las antenas tal como pone en las instrucciones. La primera la monté yo y la segunda la montó mi hijo de 6 años así que no debe ser muy difícil.

    Ahora, por cada antena, conecta un cable de red a la antena y el otro extremo donde pone PoE. Si enchufas el transformador se deberían encender las lucecitas de la antena.

    Pon las antenas una frente a la otra a una cierta distancia. Puedes usar dos sillas, una en cada rincón de la habitación.

    Configuración

    Para la configuración he utilizado este enlace de ubiquity que describo a continuación.

    Para las dos antenas

    Entre el conector del transformador donde pone LAN y tu portátil conectas otro cable. Cuidado porque si te equivocas y conectas el portátil a donde pone PoE pasarán 24 voltios por la tarjeta de red, lo que hará que te empiece a oler a quemado y te quedes sin él.

    Ahora accede a la antena como diga el manual (probablemente poniendo una dirección IP en un navegador) y configura una IP libre del rango que vayas a usar. En el caso del ejemplo será la 192.168.1.2 para una antena y la 192.168.1.3 para la otra.

    Access Point

    Elige una de las antenas como Access Point y configúrala de esta forma:

    La configuración del "cable wireless" se hace en "Basic Wireless Settings" donde tendremos que poner:

    • Wireless Mode: Access Point
    • WDS: Activado
    • SSID: El SSID de la red wifi entre las dos antenas.

    Seguramente querremos cifrar la información que pasa por el "cable wireless" así que podemos configurar WPA2 Personal en "Wireless Security" tal como se ve en la imagen.

    Station

    La otra antena se configura en modo Station (como si fuera el portátil que se conecta al punto de acceso) de esta forma:

    Pruebas de conectividad

    Si lo has hecho todo bien, estando conectado a una antena deberías poder hacer ping a la otra. Si esto funciona ya está tirado el cable entre las dos antenas y solo queda "estirarlo".

    Orientar las antenas

    La orientación de las antenas es un tema bastante delicado porque con una pequeña desviación el invento no funcionará, pero gracias a los móviles que tenemos ahora se puede hacer de una forma bastante sencilla y precisa.

    Es extremadamente recomendable que haya dos personas, una en cada antena por si hay que reorientar. Yo lo hice solo y me funcionó a la primera pero reconozco que tuve mucha suerte.

    Pon la antena en el poste de forma que no se caiga pero permita ser movida para orientarla correctamente.

    Orientación horizontal.

    Necesitas un programa tipo OsmAnd donde marcarás como destino el lugar donde vaya a ubicarse la otra antena. Vuelve a la ubicación actual y te saldrá una flechita que te indicará hacia donde orientar la antena.

    Bloquea la rotación de la pantalla para que se quede siempre en vertical.

    Pon el móvil dentro de la parabólica, justo en el centro y tocándola como si fuera el pincho de la antena (Antenna Feed). Orienta la antena hacia donde indica la flecha.

    Orientación vertical.

    A ojo la hice yo y me funcionó bien. ;-)

    Pero si quieres hacerlo bien activa las curvas de nivel en el móvil, mira a que altura están los dos puntos que quieres unir y la distancia en línea recta. Restando las dos alturas vemos la diferencia de alturas, que es lo que nos interesa. Haz un eje de coordenadas y pon un puntito donde X será la distancia que separa los dos puntos e Y será la diferencia entre las dos alturas.

    Para averiguar el ángulo solo tienes que pasar esas coordenadas rectangulares a coordenadas polares (θ = atan( y / x )).

    Lo más importante es que si inclinas una antena 1 grado hacia arriba, inclines la otra 1 grado hacia abajo. Lo que subas en un extremo lo tienes que bajar en el otro si quieres que el invento funcione.

    Comprobación de la fuerza de la señal

    A la hora de orienar la antena podemos usar el programa que viene en la consola de gestión de la antena que nos dará una idea de la fuerza de la señal.

    La hora de la verdad

    Desde un extremo haz ping al otro y si funciona. ¡ya tienes el cable tirado!

    27 de June de 2016 a las 07:00

    08 de June de 2016

    david::

    Photo



    08 de June de 2016 a las 15:12

    25 de March de 2016

    david::

    On telegram and dependencies

    I’ve just committed two small, but quite interesting, changes to zoe-startup-kit.

    First, I’ve deprecated the tg bot in favour of rmed’s tgbot. It’s built on pyTelegramBotAPI, and works out of the box. Create your tg bot, paste the API key in etc/tgbot.conf and you’re done.

    Regarding python dependencies, zam made me think. Not only it install the desired agent, it also installs its dependencies in agents/xx/lib. It can, and should, be added to the launch script. Paste your code, paste your dependencies in a file, you’re done.

    Here you can find the tgbot agent. Notice the “pip-requirements.txt” file. Now, when it is first launched, its dependencies will be downloaded and added to sys.path automatically. Lovely.

    25 de March de 2016 a las 09:37

    10 de February de 2016

    david::

    Slides of my next #t3chfest 2016 talk

    10 de February de 2016 a las 23:58

    28 de September de 2015

    Jose Manuel

    Flash: ese virus de Linux

    En esta noche de insomnio he encendido el ordenador para aprovechar el tiempo y al arrancar el navegador el monitor de red registraba un tráfico de red de unos pocos kb/s cuando yo todavía no había abierto una página así que he hecho un "iftop -B -i wlan0" y me he encontrado una sorpresa.

    La sorpresa

    ¡Tráfico desde y hacia la IP 66.117.29.11!

    Investigando

    Me conecto al puerto 80 y me devuelve un bonito "The requested URL "/test" was not found on this server. That's all we know.". Hago un escaneo de puertos y tiene abierto también el 443. Misma respuesta.

    Apago el navegador, desactivo el plugin de flash y deja de haber tráfico. Ups, olvidé hacer un tcpdump para ver a que endpoint llegaba el tráfico.

    Buscando en internet

    He buscado la IP y parece que es de Adobe pero en virustotal pone que se resuelven dominios tan exóticos como nationalbankofcanada.tt.omtrdc.net y doy fe de que es así.

    Mirando en abine veo que el dominio es de una empresa que se dedica a vender datos de usuario.

    Conclusión

    Supongo que el plugin estaría actualizando mis datos en su base de datos de usuarios.

    No se en que momento el plugin de flash paso de ser algo serio a un virus pero no me extraña que haya bastantes empresas que lo rechacen frontalmente y que no funcione en algunos navegadores.

    Y así es como mi relación con el plugin de flash terminó un 28 de Septiembre de 2015 a las 6 de la mañana.

    28 de September de 2015 a las 05:00

    12 de February de 2015

    david::

    Slides of my next #t3chfest talk

    12 de February de 2015 a las 20:14

    Jose Manuel

    Redis Sentinel (parte 1)

    Redis es un gestor de bases de datos nosql clave-valor que por si mismo no funciona en alta disponibilidad. Para conseguir la alta disponibilidad se utiliza sentinel que ya viene con redis desde la versión 2.8.

    En este artículo indico como conseguir un redis en HA y como usarlo desde python ahorrándote unas horas de aprendizaje.

    Si no tienes conocimientos básicos de clustering tendrás que hacer un acto de fe cuando diga ciertas cosas como que necesitamos al menos tres servidores. No voy a explicarlo en este artículo.

    Como funciona

    Sistemas

    Redis se puede configurar en un conjunto de réplica con un primario y múltiples secundarios. El problema es que no tenemos failover, es decir, si se cae el redis primario todo el sistema deja de funcionar.

    Para solucionar el problema, en vez de dotar de failover al propio redis, se ha creado otro componente llamado sentinel que monitoriza a los redis y es capaz de reconfigurar el replicaset para volver a otro estado estable y avisar a los clientes en caso de caída de un nodo de la réplica.p>

    Salvando las distancias, es como si en mongodb tuviéramos 3 nodos árbitros y tres nodos de datos sin capacidad de votación. 6 procesos en total.

    Desarrollo

    Cuando te ofrecen un redis con un primario para hacer las escrituras y un secundario para lecturas asíncronas que seguramente pasarás de usar por si tiene datos desfasados, si se cae el primario tu programa dejará de funcionar.

    Para solucionar ese problema, en vez de acceder directamente al redis, accederemos a sentinel que nos dirá cual es el nodo primario de redis y una vez tengamos esa información ya podremos acceder al redis primario.

    Es solo agregar una línea más de código.

    Despliegue

    Necesitas tres servidores que llamaremos redis-01, redis-02 y redis-03.

    Por si no quieres montarlos te los puedes bajar de los tres enlaces anteriores. Son contenedores lxc comprimidos así que para usarlos instala lxc con un

    sudo apt-get install lxc
    los descomprimes en /var/lib/lxc/ y los arrancas con
    sudo lxc-start -n redis-01 -d
    sudo lxc-start -n redis-02 -d
    sudo lxc-start -n redis-03 -d
    
    Puedes conectarte con root/root a las direcciones 10.0.3.201, 10.0.3.202 y 10.0.3.203.

    Replica set

    Tras instalar redis, nos aseguramos de que en /etc/redis.conf escuche en todas las interfaces comentando la línea:

    bind_ip=127.0.0.1

    Elegimos uno de los tres como primario y configuramos el resto como esclavos con un:

    redis-cli
    slaveof 10.0.3.201 6379

    Tras hacerlo en los dos esclavos ejecutamos info en el maestro para comprobar que están replicando adecuadamente:

    redis-cli
    info

    Sentinel

    Viene junto con redis a partir de la versión 2.8 así que ya lo tendrás instalado sin saberlo.

    Lo único que hay decirle a los sentinel es la ip y puerto del primario en la replica set. Con eso sacará cuales son los demás nodos del replica set y los demás sentinel que se hayan conectado a ese maestro.

    En /etc/redis/redis-sentinel.conf de todos cambia esta línea

    sentinel monitor mymaster 127.0.0.1 6379 2
    Por esta otra
    sentinel monitor mymaster 10.0.3.201 6379 2
    Y ejecutar
    redis-sentinel /etc/redis/redis-sentinel.conf
    en los tres servidores.

    12 de February de 2015 a las 18:24

    09 de November de 2014

    david::

    Slides of my next tech FP talk at GUL UC3M

    09 de November de 2014 a las 13:31

    02 de November de 2014

    david::

    Introducing zoe.state

    Suppose that you arrive home and Zoe asks you if you want to hear some music. You answer “yes” and she triggers a playlist. This is really easy to do:

    1. Create an agent that detects your presence at home (pinging your phone is enough) and asks you if you want to hear some music
    2. Create a command “yes” that, when invoked, plays your favourite spotify playlist.

    Ok that was easy, let’s try something a little bit more difficult. Suppose you hate your neighbour and you are pretty sure that, eventually, you will want him killed. In fact it is not much harder:

    1. Create an agent that detects your anger (pretty easy) and asks you if you are angry because of your neighbour.
    2. Create a command “yes” that, when invoked, kills your neighbour. 

    Now, you see the problem, you arrive at home, you are so happy because you got a raise, and Zoe asks you if you want to hear some music. You answer yes. 

    Your favourite music starts playing and your neighbour dies. 

    This happens because fuzzy commands are not exclusive. This means that you can have two different scripts that are activated with the command “yes”. Zoe can’t tell wether you are answering the music question or wether you are deciding on your neighbour fatal destiny. 

    Correlating the “yes” command with your presence or anger would not be an optimal solution, because they are not exclusive: you can arrive at home angry and answer “yes” to the music question, and the killing bot would decide it’s a green light for him.

    The solution here is simple: do not create a command that kills people with a single “yes”. Make it triggered with something like “yes, kill my neighbour”.

    In any case, this example shows the underlying problem of managing state. Zoe is mostly a stateless machine (well, it depends on your agents). So, it would be great to have her some sense on your state. 

    The following picture shows some code I’m working on:

    image

    1. When zoe detects my presence, sends a “hello” message to this agent
    2. This agent offers me to hear some music and stores two commands, “yes /please” and “no /thanks”. Those commands are nothing but messages, in this case to the same agent.
    3. When I send her a “yes” or “no”, zoe sends the correct message to this agent.

    Pretty easy, isn’t it? There are two main advantages of this:

    1. Inherent to this design, you can implement full workflows with this. 
    2. Now, what would happen if two different agents are triggered at the same time, one of them asking about music and the other asking about killing your neighbour, you answer will be sent only to the agent that asked last.

    Now you can write at last your killer app.

    02 de November de 2014 a las 18:34

    25 de October de 2014

    david::

    Exact match in Zoe commands

    We have just added exact match commands in Zoe. This lets you match the input command against a regexp.

    When your command script is queried with –get, just return the regexp quoted in “/” and no \n at the end. That is, 

    echo -n “/your regexp here/”

    When the user asks for something that matches the regexp, your script will be invoked with the following options:

    If you are a sysadmin or a more-than-a-newby UNIX user, you will feel so comfortable with this. Have a taste of this exact match support in https://github.com/voiser/zoe-startup-kit/blob/master/cmdproc/regexp.sh

    25 de October de 2014 a las 10:10

    07 de September de 2014

    Jose Manuel

    Ubuntu 14.04 con el escritorio clásico

    Aburrido estarás ya de sitios en los que dicen que Ubuntu es la solución al hambre en el mundo. No lo es pero en este momento me parece la mejor distribución que hay para cualquier uso muy por encima del resto.

    Una de las cosas que me enerva hasta el punto de haberme pasado a KDE durante una temporada es Unity o el nuevo Gnome que viene en Ubuntu Gnome así que vamos a ver cómo cargárnoslos para poner un Gnome normal al que le funcione todo incluidos los efectos de escritorio.

    ¡32 bits por favor!

    Como cada dos años he vuelto a cometer el mismo error: instalar Ubuntu de 64 bits. Este año el escarmiento ha venido por haber intentado asistir a un webinar con webex y no poder hacerlo porque el javaleches que utilizaba sólo funcionaba bien con 32 bits.

    Con esto no digo que la de 64 bits vaya mal pero siempre hay alguna aplicación privativa que no te va a funcionar y necesitas que funcione.

    Es increíble que a estas alturas sigamos así pero "esto es lo que hay y nosotros no hemos sido". Advertido quedas.

    Ubuntu != Ubuntu Gnome

    Después de hacer todo lo que pongo abajo no quedará el mismo escritorio con uno que con otro empezando por el gestor de archivos que es distinto en uno o en otro, o la posibilidad de usar una segunda fila de escritorios que con Ubuntu Gnome se vuelve más engorrosa.

    Si todavía no has elegido mejor instala Ubuntu con Unity que tras los cambios te resultará más familiar.

    Instalando gnome sin efectos

    Instalamos los paquetes necesarios:

    sudo apt-get install gnome-session-flashback

    Cerramos y abrimos la sesión con Gnome Flashback (Metacity).

    Activando los efectos: empiezan los problemas

    Como te podrás imaginar para lo de arriba no me molesto en escribir una entrada. Los problemas vienen a partir de ahora cuando activamos los efectos porque deja de funcionar el Alt-Tab y no podemos elegir el número de escritorios.

    Activar drivers privativos

    Necesitamos que la tarjeta de vídeo funcione bien así que vamos a controladores adicionales:

    E instalamos los que nos toquen. En mi caso los de nvidia.

    Cuando acabes reinicia y arranca con Gnome Flashback (Compiz).

    Instalando gnome con efectos

    Primero instala los paquetes necesarios:

    sudo apt-get install compiz-plugins compiz-plugins-default compizconfig-settings-manager

    Arrancando CompizConfig Settings Manager

    Nos interesa el el Compiz Config Settings Manager así que ve a "Herramientas del sistema|Preferencias|CompizConfig Settings Manager"

    Configurando varios escritorios

    Pincha en "Opciones Generales":

    Ve a la pestaña de la derecha que pone "Tamaño de Escritorio". No se ve así que tienes que darle a la flecha de la derecha hasta que aparezca:

    En este punto puedes elegir el número de escritorios y su disposición en altura y longitud. Si has instalado Ubuntu Gnome sólo podrás moverte con Ctrl-Alt-Cursor de forma horizontal. Supongo que para moverte de forma vertical tendrás que configurar algo en algún sitio que no me he molestado en mirar.

    Configurando Alt-Tab para cambiar entre ventanas

    Vamos a "Gestión de ventanas|Cambiador de Aplicaciones" y lo activamos:

    En este punto ya funcionará el Alt-Tab pero se verá un poco feo así que vamos a ir a su configuración pinchando en su icono y desactivamos el check de "Icono".

    cerrar,minimizar,maximizar:menu

    Desde mi punto de vista los botones del marco de la ventana deberían estar a la izquierda en ese orden pero hay gente que los quiere más a lo Windows.

    Si has instalado Ubuntu Gnome los tienes a lo Windows y si es Ubuntu los tendrás a la izquierda.

    Para cambiarlos ejecuta dconf en cualquier terminal y ve a la clave "org|gnome|desktop|wm|preferences|button-layout" o dale a buscar button-layout y te saldrá directamente la clave que buscamos.

    Resultado de :close,minimize,maximize:menu":

    Resultado de minimize,maximize,close:":

    El álbum de hoy

    Nomoredolls - Nomoredolls (caché), un poco de rock para empezar la mañana:

    07 de September de 2014 a las 15:37

    28 de July de 2014

    Jose Manuel

    Introducción a ELK (Elasticsearch, Logstash y Kibana) (parte 3)

    En todas las aplicaciones que he conocido el cuello de botella siempre ha estado en el mismo sitio: el almacenamiento.

    Puedes poner 20 frontales web y 20 servidores de aplicación pero en la capa de persistencia tiene que haber un almacenamiento compartido que puede provocar verdaderos quebraderos de cabeza y muchas noches de insomnio al sysadmin de turno.

    Para entender la problemática vamos a ver que tiempos manejamos en un entorno típico con mysql y cómo escalamos con Elasticsearch. En los siguientes artículos de SQL vs NoSQL entraré más en el detalle. En este artículo sólo quiero que se entienda la problemática y cómo se podría "resolver" con Elasticsearch.

    Más rápido por favor

    Imaginémonos que usamos mysql en mi portátil manejando unos tiempos de 0.01 segundos por inserción:

    mysql> create table `tabla` (`id` varchar(5) NOT NULL, `data` varchar(5), primary key(`id`));
    Query OK, 0 rows affected (0.02 sec)
    
    mysql> insert into `tabla` values ("1","2");
    Query OK, 1 row affected (0.01 sec)
    
    mysql> insert into `tabla` values ("2","2");
    Query OK, 1 row affected (0.00 sec)
    
    mysql> insert into `tabla` values ("3","2");
    Query OK, 1 row affected (0.00 sec)
    
    mysql> insert into `tabla` values ("4","2");
    Query OK, 1 row affected (0.02 sec)
    
    mysql> 
    

    Eso nos da una capacidad máxima de 100 inserciones por segundo que podrá parecer mucho pero ahora imagínate 10 servidores enviando líneas de log a razón de 10 por segundo de forma simultánea y verás como no te parece tanto.

    Con elasticsearch dentro de una máquina virtual con discos de portátil estoy sacando unas 300 inserciones por segundo. Está mejor pero también tenemos un techo.

    Soluciones SQL

    Usar el típico entorno de replicación de mysql no soluciona el problema porque tenemos más escrituras que lecturas. En todo caso lo empeoraría porque la base de datos estaría más tiempo ocupada enviando datos a sus réplicas.

    También podríamos tener varios servidores de mysql e ir enviando las líneas de log en roundrobin pero eso obligaría al software que va a explotar esos datos a hacer una gestión extra.

    Además, al utilizar SQL, el software que va a insertar y explotar esos datos está obligado a cambiar el esquema de la base de datos cada vez que haya un cambio de un campo en un archivo de log.

    Solución Elasticsearch

    Elasticsearch es un gestor de bases de datos NoSQL que para el caso que nos ocupa tiene tres ventajas:

    • Todos son maestros: En un grupo de replica (replica set) puedes insertar datos en cualquier servidor que ellos se las apañarán para replicarlos en los demás.
    • Inserción asíncrona: Se envían los datos a la base de datos y el servidor te da el OK antes de hacer la inserción real en la base de datos y replicarlo al resto. Esto reduce muuuuucho los tiempos de inserción aunque crea otros problemas de latencia que en este dominio nos dan exactamente igual.
    • Sin esquema: en una misma "tabla" puedes insertar "filas" con diferentes esquemas lo que posibilita poder insertar líneas de log desde diferentes orígenes. Pongo tabla y filas entre comillas porque ni las tablas se llaman tablas ni las filas se llaman filas, pero ya lo veremos en un artículo posterior.

    Solución escalable

    "Solucionando" cuellos de botella

    En esta solución utilizaremos un servidor de redis que es otro gestor NoSQL (¡sorpresa!) utilizado como catalizador para que el logstash que almacena los datos en elasticsearch no explote. Se usará como un gestor de colas donde los agentes irán metiendo líneas de log desde los servidores y logstash las irá recogiendo para insertarlas en la base de datos.

    De esta forma conseguimos:

    • Paliar el problema con el cuello de botella en la base de datos.
    • Monitorizar cuando nos vamos quedando sin capacidad mirando la longitud de la cola en redis. Por ejemplo haciendo un plugin de Zabbix que mire el tamaño de la cola de redis y nos devuelva un número que luego se podrá representar en una gráfica. Si el número supera un umbral. ¡alerta, necesitamos más capacidad!

    Visto en código suponiendo que tomamos los datos de un apache en el agente fíjate en el output:

    input {
      file {
        type => "auth"
        path => "/var/log/auth.log"
      }
    }
    filter {
      # This is a standard syslog line like this:
      # Mar  9 17:17:02 path-precise CRON[25638]: pam_unix(cron:session): session closed for user root
      if [type]=="auth" {
        # Look for patterns in /opt/logstash/patterns/grok-patterns
        grok {
          match => [ "message", "%{SYSLOGLINE}" ]
        }
        # Set timestamp: http://logstash.net/docs/1.4.1/filters/date#match
        date {
          match => [ "timestamp", "MMM dd HH:mm:ss",
                                  "MMM  d HH:mm:ss",
                                  "ISO8601" ]
        }
      }
    }
    output {
      redis {
        host => "localhost"
      }
    }
    
    Y en el servidor de logstash fíjate en input:
    input {
      redis {
        host => "localhost"
      }
    }
    output {
      elasticsearch_http {
        host => "127.0.0.1"
      }
    }
    

    Podríamos tener múltiples agentes disparando al mismo redis y de ahí viene la solución oficial:

    Hay que tener cuidado con redis porque para ganar velocidad almacena en memoria los datos así que en caso de dejar de funcionar el logstash o el elasticsearch durante un período de tiempo prolongado te puedes encontrar con un redis que ocupa en memoria 4GB. Si, también me ha pasado, ... hace una semana (nota mental: volver a poner 4GB de memoria al servidor de logstash ;-) ).

    Escalando horizontalmente

    La alarma que tenemos para la longitud de la cola de redis se dispara y en el kibana vemos datos de lo que pasó hace una hora. El problema puede estar en Logstash o en Elasticsearch así que vamos a crear otra máquina virtual con la pila completa de Redis, Logstash, Elasticsearch en cluster con el otro y un Kibana.

    ¡Cuidado! Para escalar realmente necesitaríamos tocar conceptos como el sharding que se tocarán en un artículo posterior. Aquí vamos a crear un conjunto de réplica entre dos servidores de Elasticsearch.

    ¿Has replicado ya el entorno anterior? ¿Y a qué estás esperando? Cuando tengas los dos servidores de Elasticsearch levantados en la misma red verás con sorpresa que ¡Ya están en el conjunto de réplica! Abre los kibanas de ambas instancias y verás como ves los mismos datos.

    Este fue el detonante que me impulsó a meterme en el mundo NoSQL. Yo que vengo de un mundo de almacenamientos compartidos, clusters RedHat, IPs flotantes, réplicas que no se recuperan automáticamente en caso de caída de un maestro ... y va este y se configura sólo con un doble click sin pedirle permiso al sistema operativo.

    Configuración de Elasticsearch

    Su configuración por defecto está escuchando a que alguien dentro del cluster "elasticsearch" se anuncie por multicast. Cuando eso ocurre los dos servidores se sincronizan y a partir de ahí los datos que insertas en un servidor están disponibles en el otro un segundo más tarde.

    La configuración más relevante que puedes encontrar en /etc/elasticsearch/elasticsearch.yml y que permite este comportamiento es la siguiente:

    cluster.name: elasticsearch
    discovery.zen.ping.multicast.enabled: true
    

    Con un rápido vistazo en el archivo de configuración podrás ver entre otras cosas que también puedes utilizar unicast para la configuración entre los nodos en caso de que estés usando una red que no permita usar multicast o servidores en la nube como por ejemplo dos instancias de Amazon EC2.

    Plugin para ver el estado del cluster en un navegador

    Con el plugin elasticsearch-head podemos ver el estado del cluster y gestionarlo desde un navegador.

    Solución a problemas que te acabarán ocurriendo

    Antes de nada ten presente que logstash crea una "base de datos", que en elasticsearch se llama indice, cada día. Supongo que hace esto para que el indice de logs no crezca hasta el infinito haciéndose inmanejable. Puedes ver los que ha ido creando en /var/lib/elasticsearch/elasticsearch/nodes/0/indices/.

    Too many open files

    Te pasará más o menos en el momento en que todo el mundo se haya acostumbrado a usar el kibana y se haya convertido en una aplicación crítica para la empresa pero no tengas sufiente experiencia para solucionar el problema rápidamente. Como será algo con lo que no contabas probablemente tampoco tengas tiempo para solucionarlo. Eso fue lo que me pasó a mi.

    La causa del problema es que cada vez que logstash crea un índice en elasticsearch éste crea y mantiene abiertos un porrón de archivos. En mi caso para el índice logstash-2014.07.08 tiene abiertos 62 archivos:

    root@path-precise:/etc/elasticsearch# lsof | grep /var/lib/elasticsearch/elasticsearch/nodes/0/indices/logstash-2014.06.26 | wc
         62     558   10582
    root@path-precise:/etc/elasticsearch# 
    

    Como además la configuración por defecto de elasticsearch crea tres shards el número de archivos abiertos se triplica. No voy a explicar esta afirmación. Veremos que es un shard en un artículo posterior.

    Llegar al límite de 1024 archivos, se llega bastante rápido así que deberás realizar estas tres cosas en el servidor:

    • Reducir el número de shards a 1: Si tu elasticsearch va sobrado de capacidad en el archivo de configuración de elasticsearch /etc/elasticsearch/elasticsearch.yml, sección Index, deja la siguiente configuración:
      index.number_of_shards: 1
      index.number_of_replicas: 0
      
    • Desactivar o eliminar los indices que no utilices: esto hará que la información de los mismos no esté accesible pero tampoco se abran los archivos que componen el indice:
      • Desactivar un indice:
        curl -XPOST 'localhost:9200/logstash-2014.06.26/_close'
      • Eliminar un indice:
        curl -XDELETE 'http://localhost:9200/logstash-2014.06.26/
    • Aumentar el límite de archivos abiertos en el /etc/security/limits.conf: se puede aumentar agregando las líneas:
      logstash  hard  nofile 32000
      logstash  soft  nofile 32000

    Se me ha llenado el disco y ahora elasticsearch no arranca

    No digo que me haya pasado, porque si me hubiera pasado significaría que no tenía bien monitorizada la máquina y que no me habría dado cuenta cuando ocurrió, pero en el hipotético caso de que me hubiera pasado, que no digo que me haya pasado, lo que hay que hacer es arreglar o borrar unos archivos de datos que se han corrompido.

    Elasticsearch, antes de insertar datos de verdad, los guarda en unos archivos de texto que usa como si fuera un buffer. El problema es que al estar el disco lleno esos archivos de texto se corrompen así que cuando Elasticsearch va a leerlos para indexar esos datos no puede hacerlo y se pega un tortazo.

    Una vez liberado el disco, el archivo que tienes que arreglar o borrar con la consecuente pérdida de datos está en el directorio translog del indice que de problemas. El log del elasticsearch te dirá cual está fallando. Por ejemplo, si te dice que el shard 0 del indice test está fallando vas a /var/lib/elasticsearch/elasticsearch/nodes/0/indices/test/0/translog y dentro verás que hay dos archivos, un translog-1405060275771 y otro translog-1405060275771.recovering. El que tienes que arreglar o borrar es el que se apellida .recovering .

    El álbum de hoy

    Shedneryan debe ser la obra que más he escuchado de Jamendo (caché). Ideal para trabajar:

    Espero que este artículo te haya servido de ayuda.

    28 de July de 2014 a las 05:53

    06 de July de 2014

    Jose Manuel

    ManiaDrive

    Maniadrive es un juego de coches de los que jugábamos cuando éramos pequeños. Me vino a la cabeza porque ahora tengo un hijo pequeño así que lo he sacado del cajón y empaquetado para vosotros.

    Se trata de un clon del conocido trackmania pero con licencia libre.

    Descripción

    Incluye un montón de pistas así que se puede jugar en modo historia.

    También puedes usar el modo multijugador por internet o crear tus propias pistas con el editor que viene integrado. Hice esta pista para que el niño aprendiera a usar su primer juego de coches:


    Si quieres usarla descarga el archivo en ~/.mania_drive/data y cárgala desde el editor.

    Paquete para Ubuntu

    He hecho un paquete a partir de los binarios que se pueden bajar desde sourceforge que configura el sonido a través de alsa-oss y añade las entradas "ManiaDrive" y "ManiaDrive track editor" en el apartado de juegos:

    Algunas imágenes del juego

    Espero que os guste:

    06 de July de 2014 a las 15:35

    26 de June de 2014

    Jose Manuel

    Introducción a ELK (Elasticsearch, Logstash y Kibana) (parte 2)

    Vamos a hacer algo útil con los datos que tenemos sin modificar mucho el ejemplo anterior. La salida, en vez de ir a un correo vamos a meterla en Elasticsearch para luego poder hacer consultas con Kibana.

    Hay multitud de tutoriales en internet así que no me voy a extender mucho en el cómo hacerlo sino en qué cosas puede hacer que funcione mejor en base a mi experiencia en los casi dos años que llevo usándolo.

    ¿Cómo funciona?

    El esquema será el que ilustra la imagen de la portada donde se ve el flujo de los datos.
    Esta imagen no refleja el cómo los datos viajan de un lado al otro y eso es lo que realmente hace falta entender así que ahí va la misma imagen ligeramente retocada:

    Como ves hay dos almacenes (log y elasticsearch) en los que están los datos que nos interesan y dos piezas de software (logstash y kibana) que hacen transformaciones con ellos y los mueven o los muestran como nosotros queremos.

    Logstash

    Si has seguido las instrucciones del artículo anterior ya lo tienes instalado.

    Para acceder a los logs que necesitamos es necesario que se ejecute como root así que ve a /etc/default/logstash y pon LS_USER=root.

    Dado que va a leer de los logs en este caso (aunque podría leer desde otro sitio) y escribir en elasticsearch necesitamos saber cómo son los logs de los que vamos a leer y cómo meter los datos en elasticsearch.

    read

    La primera parte es la más peliaguda porque cada aplicación tiene un log distinto pero hay un par de cosas que tendremos que tener en cuenta siempre:

    • Formato de la hora que usa la aplicación para escribir en el log
    • Datos que podemos querer consultar del log
    timestamp

    Me viene a la cabeza el log de squid donde la hora viene en el primer campo en segundos desde 01/Ene/1970 (fecha epoch) hasta la del apache donde viene en formato legible en el cuarto campo pasando por las de diversas aplicaciones que guardan el día y la hora en dos campos distintos separados por un pipe "|".

    Si queremos hacer una consulta del estilo "¿qué paso esta noche a las 3 de la madrugada?" necesitamos que logstash sea capaz de entender todos esos formatos de hora para poder insertarlos en la base de datos con el mismo timestamp.

    fields

    Pongamos por caso que tenemos el log de apache siguiente:

    127.0.0.1 - - [20/Jul/2013:08:16:58 +0200] "POST /my/machines HTTP/1.1" 404 443 "-" "-"

    Si utilizamos como separador de campo los espacios veremos que nos meterá la fecha en dos campos y eso no es lo que queremos. Tampoco podemos separar campos utilizando comillas porque no todos los campos tienen comillas así que hay que gestionar esto de una forma más inteligente.

    write

    En este caso concreto es bien fácil, ya que existe el output elasticsearch al que le indicamos donde está la base de datos y el resto lo gestiona él.

    Hay dos cosas a tener en cuenta:

    • Utilizar el plugin de elasticsearch con protocol => "http" para utilizar el API Rest de la base de datos. De esta forma ante una actualización de logstash o la base de datos, es menos probable que se rompa la aplicación.
    • logstash crea una base de datos diaria y realiza muchos accesos a disco lo cual, tras meses de uso, puede desembocar en problemas para el sistema operativo que se tratarán en la sección de elasticsearch.

    Ejemplo completo: SpyYourFriend

    Queremos poder responder a la siguiente pregunta: ¿cuando se eliminó el directorio /var/www/kibana del servidor y quien lo hizo?

    Vamos a utilizar como fuente de datos el .bash_history y el /var/log/auth.log.

    Pasos:

    • Configurar la bash para que agregue líneas en el history cada vez que se pulsa el enter y que ponga la fecha de cada comando en el log.
    • Configurar logstash para extraer los campos de cada log e insertar la información en la base de datos.
    Configurar la bash

    No me extiendo mucho. Simplemente agrega esto al .bashrc de root:

    export HISTTIMEFORMAT="%F %T "
    export PROMPT_COMMAND='history -a'
    

    Con esto dejaremos el timestamp de cada comando en /root/.bash_history y forzaremos a escribir en el history cada vez que tecleamos un comando en vez de al hacer logout.

    Configurar logstash para extraer datos de /var/log/auth.log

    Vamos a introducir la variable type que utilizaremos para "etiquetar" un flujo y poderle dar un trato diferencial a lo largo del archivo de configuración de logstash. A tener en cuenta:

    • Entrada: líneas del archivo en "/var/log/auth.log"
    • Proceso: extraer campos y configurar timestamp.
    • Salida: enviar todo a elasticsearch.
    input {
      file {
        type => "auth"
        path => "/var/log/auth.log"
      }
    }
    filter {
      # This is a standard syslog line like this:
      # Mar  9 17:17:02 path-precise CRON[25638]: pam_unix(cron:session): session closed for user root
      if [type]=="auth" {
        # Look for patterns in /opt/logstash/patterns/grok-patterns
        grok {
          match => [ "message", "%{SYSLOGLINE}" ]
        }
        # Set timestamp: http://logstash.net/docs/1.4.1/filters/date#match
        date {
          match => [ "timestamp", "MMM dd HH:mm:ss",
                                  "MMM  d HH:mm:ss",
                                  "ISO8601" ]
        }
      }
    }
    output {
      elasticsearch {
        protocol => "http"
        host => "localhost"
      }
    }
    

    Este es el ejemplo más sencillo que puede haber pero se puede complicar bastante. Pasemos al ejemplo siguiente.

    Configurar logstash para extraer datos del history

    El archivo de history tiene una pinta como esta:

    root@yinyan-precise:~# tail .bash_history 
    #1403070049
    history
    #1403070054
    ls
    #1403070056
    history
    #1403070062
    cd
    #1403070066
    more .bash_history 
    root@yinyan-precise:~#

    donde como se puede observar el timestamp está escrito en formato epoch precedido por un "#" y además el comando está en la siguiente línea. Esto último seguro que te recuerda al catalina.out del tomcat donde cada "línea" de log está compuesta de múltiples líneas.

    • Entrada: /root/.bash_history
    • Proceso:
      1. Juntamos las dos líneas en una sola eliminando '\n' y '#'
      2. Extraemos el campo de la fecha y el de la línea de comandos
      3. Utilizamos la fecha en formato epoch para poner valor al timestamp
      4. Agregamos un campo con la línea en formato más legible
    • Salida: Elasticsearch

    Agárrate que vienen curvas:

    input {
      file {
        type => "bash_history"
        path => "/root/.bash_history"
      }
    }
    filter {
      if [type]=="bash_history" {
        # Poner las dos líneas como una sola en el campo message
        multiline {
          pattern => "^#"
          what => "next"
        }
        # Cambiar fecha del principio
        # Vamos a separar los campos eliminando el retorno de carro y el comentario
        mutate {
          add_field => ["temp_message", "%{message}"]
        }
        mutate {
          gsub => [
            "temp_message", "\n", " ",
            "temp_message", "^#", ""
          ]
        }
        grok {
          match => [ "temp_message", "%{WORD:unix_date} %{GREEDYDATA:command_line}"]
        }
        mutate {
          remove_field => ["temp_message"]
        }
        # Copio el contenido del timestamp a otra variable para conservar el momento
        # en que el mensaje llegó al servidor de logstash
        mutate {
          add_field => [ "input_timestamp", "%{@timestamp}" ]
        }
        # Sobreescribo el timestamp con la fecha que pone en el archivo de log
        date {
          match => [ "unix_date", "UNIX"]
        }
        mutate {
          remove_field => ["unix_date"]
        }
        # Agrego un campo con la línea en formato legible
        mutate {
          add_field => [ "human_readable_message", "%{@timestamp} %{command_line}" ]
        }
      }
    }
    output {
      elasticsearch {
        protocol => "http"
        host => "localhost"
      }
    }
    
    Toda la configuración junta
    input {
      file {
        type => "auth"
        path => "/var/log/auth.log"
      }
      file {
        type => "bash_history"
        path => "/root/.bash_history"
      }
    }
    filter {
      # This is a standard syslog line like this:
      # Mar  9 17:17:02 path-precise CRON[25638]: pam_unix(cron:session): session closed for user root
      if [type]=="auth" {
        # Look for patterns in /opt/logstash/patterns/grok-patterns
        grok {
          match => [ "message", "%{SYSLOGLINE}" ]
        }
        # Set timestamp: http://logstash.net/docs/1.4.1/filters/date#match
        date {
          match => [ "timestamp", "MMM dd HH:mm:ss",
                                  "MMM  d HH:mm:ss",
                                  "ISO8601" ]
        }
      }
      if [type]=="bash_history" {
        # Example: "#1403708872\n tar -zxvf kibana-3.1.0.tar.gz "
        # This is a multiline log. Set message var with both lines.
        multiline {
          pattern => "^#"
          what => "next"
        }
        # Split fields. First field unix_date until first space. Second field command line after first space.
        # Use aux var temp_message.
        mutate {
          add_field => ["temp_message", "%{message}"]
        }
        # temp_message=="#1403708872\n tar -zxvf kibana-3.1.0.tar.gz "
        # Remove \n and #
        mutate {
          gsub => [
            "temp_message", "\n", " ",
            "temp_message", "^#", ""
          ]
        }
        # temp_message=="1403708872 tar -zxvf kibana-3.1.0.tar.gz "
        # Set unix_date and command_line
        grok {
          match => [ "temp_message", "%{WORD:unix_date} %{GREEDYDATA:command_line}"]
        }
        mutate {
          remove_field => ["temp_message"]
        }
        # unix_date=="1403708872"
        # command_line=="tar -zxvf kibana-3.1.0.tar.gz "
        # Set input_timestamp to the timestamp when the log line is processed by logstash
        mutate {
          add_field => [ "input_timestamp", "%{@timestamp}" ]
        }
        # Set timestamp and remove temporal var unix_date
        date {
          match => [ "unix_date", "UNIX"]
        }
        mutate {
          remove_field => ["unix_date"]
        }
        # Add a field with the log line in human readable format
        mutate {
          add_field => [ "human_readable_message", "%{@timestamp} %{command_line}" ]
        }
      }
    }
    output {
      elasticsearch {
        protocol => "http"
        host => "localhost"
      }
    }
    

    Elasticsearch

    Su instalación consiste en bajarse el paquete de aquí e instalarlo.

    En el siguiente post haré un monográfico de elasticsearch. De momento sólo diré que para enviar la información a la base de datos hay que poner esto en el output:

    output {
      elasticsearch {
        protocol => "http"
        host => "localhost"
      }
    }
    

    Kibana

    Yo lo defino como un visualizador gráfico de consultas lucene que sirve para hacer búsquedas que no sabes que vas a hacer hasta que las haces.

    Esto te da una enorme flexibilidad pero no te permitirá hacer unos buenos informes. El tema de los informes se tratará más adelante en el siguiente post.

    Instalación y ejecución

    En versiones anteriores Kibana era una aplicación Ruby que funcionaba sobre Sinatra en el servidor. Ahora es una aplicación que se ejecuta enteramente en el navegador, lo que significa que desde tu navegador hará falta acceso a la base de datos (se puede restringir).

    Bájate el kibana de aquí, lo descomprimes en /var/www/ y en config.js escribe la url que vas a poner en el navegador para acceder a tu servidor de elastisearch.

    SpyMyFriend en funcionamiento

    Si abrimos en el navegador la url donde hemos descomprimido el kibana y pinchamos en "here" veremos como tanto las líneas del auth que nos indican el momento y el origen de la conexión por ssh al servidor como los comandos que se han ido ejecutando han sido correctamente indexados.

    Hacer búsquedas es bastante sencillo ya que se usa la sintaxis de lucene así que no hay que saber acerca de cómo funciona la base de datos que hay detrás. Si queremos buscar cuando se ejecutó un rm basta con poner "rm" y lo buscará.

    Si pulsamos en el evento nos saldrá una descripción de los campos con sus valores, lo que nos dará una idea para hacer más búsquedas:


    Ahí vemos que la búsqueda "correcta" hubiera sido command_line:"*rm*"

    Ahora vamos a poner en verde las líneas del auth.log, en amarillo las del bash_history y en rojo la línea donde se ha borrado el kibana.

    Sigue habiendo mucho ruido. De las líneas del auth.log nos interesan las que nos indican una conexión por ssh:


    Al parecer tras hacer el estropicio quien sea se dejó la sesión abierta porque tras hacerlo no hay actividad en el auth.log de cierre de sesión ssh.

    Encontramos actividad de ssh en el auth a las 17:06 y que luego se han tecleado una serie de comandos. Ampliamos la parte que nos interesa:

    Ahora vamos a los eventos y vemos que alguien se conectó desde 127.0.0.1 y seguidamente estuvo trasteando con la instalación de kibana pero que luego la dejó bien. ¡Oh sorpresa! ¡He sido yo mismo!

    Anotaciones

    Este ejemplo, sobre todo la parte del bash_history, es bastante complicado pero si lo has entendido y lo has repetido en tu computadora te puedes considerar un usuario con experiencia de logstash y kibana.

    Existen otras alternativas a logstash como por ejemplo fluentd que también es bastante popular. Entiendo que una vez entiendas cómo funciona logstash podrás hacer extensible ese conocimiento al resto de alternativas tanto libres como privativas.

    Elasticsearch es un mundo en si mismo así que lo dejo para el siguiente post en el que intentaré hacer un "mapeo" entre SQL y NoSQL (mongodb y elasticsearch) ya que si nunca has usado una base de datos NoSQL pero eres un experto en SQL siento decirte que de NoSQL no tienes ni idea. Cambia tanto la filosofía a nivel de sistemas como a nivel de desarrollo.

    Espero que este post os ayude.

    26 de June de 2014 a las 07:23

    08 de June de 2014

    Jose Manuel

    Introducción a ELK (Elasticsearch, Logstash y Kibana) (parte 1)

    Se trata de un gestor de logs, o eso es al menos lo que nos venden.

    En realidad yo lo veo como algo mucho más genérico: una navaja suiza para gestión de datos que permite su transporte entre máquinas, procesamiento y consulta en tiempo real.

    En este artículo escribiré sobre logstash para en artículos posteriores hablar de su integración con Elasticsearch y Kibana.

    Cuando conozcas la potencia de ELK no sabrás como has sido capaz de vivir sin él hasta ahora.

    Ventajas aplicadas a archivos de log

    Con logstash no necesitas hacer una recolección de logs porque ya te la hace él, y tampoco necesitas hacer un tratamiento de los datos porque se le puede decir que te lo haga él o programarle una rutina que te actualice lo que sea en tiempo real. De esta forma en cualquier momento puedes saber lo que está pasando en tus sistemas y aplicaciones.

    Se puede usar tanto para procesar logs de apache como para procesar logs de aplicaciones internas o bases de datos por lo que puedes generar informes útiles tanto para la dirección como para ti o el equipo de desarrolladores. Por ejemplo, tal como viene "de fábrica" se le puede pedir un diagrama de barras con el número de peticiones que ha hecho un cliente a tu API agrupadas cada 5 minutos.

    Ahora imagínate que tienes un montón de instancias en Amazon que están constantemente creándose y destruyéndose en función de la carga pero quieres saber qué está pasando con ellas: cuando las creas configuras un logstash en ellas para que envíe los datos que te interesan a tu servidor de logs y problema solucionado. El accesorio perfecto para la descentralización de sistemas.

    Cómo funciona: el sistema de plugins/

    Pues como todos los programas: recibe unas entradas, las procesa y crea unas salidas. Sólo que es en sentido literal. Para ilustrarlo mira este dibujo:

    En él puedes ver lo que es logstash y en los plugins en los que que tienes que pensar cuando vas a diseñar un sistema con él: entradas, codecs/filtros y salidas.

    Una entrada es un plugin que utiliza logstash para extraer datos de algún sitio y pasársela al plugin de codec/filtro que devuelve otros datos y por último pasársela al plugin de salida.

    Intencionalmente he juntado los codecs y los filtros en el mismo saco porque aunque esto es incorrecto, me parece más didáctico. Más adelante lo aclararé.

    A estas alturas te habrás dado cuenta, y sino te lo digo yo, que lo realmente importante no es logstash sino sus plugins. En logstash todo gira alrededor de los plugins. Te puedes encontrar un listado abajo en la página de documentación.

    Instalación básica

    En este post me centraré más en mostrar cómo funciona logstash, no cómo se instala en producción así que ve a la página de http://logstash.net/docs/1.4.1/repositories, agrega el repositorio y ejecuta apt-get install logstash logstash-contrib. También hay paquetes para CentOS.

    Si no usas Debian ni CentOS puedes ir a http://logstash.net, pinchar en el botón gordo que pone "Download" y deja el archivo en algún sitio. Necesitarás java así que instálalo con un apt-get install default-jdk.

    Ejemplo de uso

    Vamos a suponer que en tu site hay una nueva página llamada /my/machines.html y quieres saber si la visita alguien así que haremos que cuando aparezca una entrada con ese texto en tu archivo de log, te llegue un mensaje al correo avisándote.

    Instala un apache en tu PC con un apt-get install apache2.

    Vamos a la página de documentación donde están los plugins disponibles y elegimos los que nos interesan:

    • plugin de entrada: file
    • plugin para filtro: grep
    • plugin de salida: email

    Pinchando en el plugin de entrada file podemos ver que para procesar los archivos de log que están en /var/log/apache2/*log debemos decirle algo como:

    input {
      file {
        path = ["/var/log/apache2/*log"]
      }
    }
    

    Pinchando en el plugin para filtro grep y teniendo en cuenta que una línea de log sería algo así:

    127.0.0.1 - - [20/Jul/2013:08:16:58 +0200] "POST /my/machines.html HTTP/1.1" 404 443 "-" "-"
    

    Tendríamos que configurarlo de esta forma:

    filter {
      grep {
        match = {"message", "/my/machines.html"}
      }
    }
    

    Y por último, pinchando en el plugin de salida email y suponiendo que utilizaremos una cuenta de correo de un proveedor externo para enviar los correos tenemos que poner como plugin de salida:

    output {
      email {
        subject => "Nueva visita"
        to => "direccion@gmail.com"
        from => "direccion@gmail.com"
        body => "%{message}"
        via => "smtp"
        options => [
          "smtpIporHost", "smtp.gmail.com",
          "port", "587",
          "enable_ssl", "true",
          "authenticationType", "plain",
          "userName", "cuentaDeEnvio",
          "password", "contrasenyaDeCuentaDeEnvio",
          "starttls", "true"
        ]
      }
    }
    

    Cada vez que ejecutemos esto:
    wget http://localhost/my/machines.html
    nos aparecerá en nuestro archivo de log el acceso a esa página, logstash lo verá y nos enviará un e-mail advirtiéndolo.

    Este ejemplo no es muy útil porque nadie quiere que le inunden el correo con líneas de log pero nos da una idea de lo que se puede hacer con los filtros y plugins.

    En marcha

    Si has seguido los pasos de arriba ya tienes instalado todo lo que necesitas así que vamos a ponerlo todo junto.

    Crea un archivo llamado /etc/logstash/conf.d/logstash.conf con el contenido:

    input {
      file {
        path => ["/var/log/apache2/*log"]
      }
    }
    filter {
      grep {
        match => {"message" => "/my/machines.html"}
      }
    }
    output {
      stdout {}
      email {
        subject => "Nueva visita"
        to => "direccion@gmail.com"
        from => "direccion@gmail.com"
        body => "%{message}"
        via => "smtp"
        options => [
          "smtpIporHost", "smtp.gmail.com",
          "port", "587",
          "enable_ssl", "true",
          "authenticationType", "plain",
          "userName", "cuentaDeEnvio",
          "password", "contrasenyaDeCuentaDeEnvio",
          "starttls", "true"
        ]
      }
    }
    

    Advertencias en producción

    Esto es sólo un ejemplo muy didáctico para ver cómo funciona el sistema de plugins en Logstash: entrada, procesado y salida. Así que me he permitido introducir un par de incorrecciones.

    El filtro grep no se usa

    La forma correcta sería con el input que he descrito, sin filter y metiendo dentro del output una condición para que se envíe el e-mail cuando la línea la cumpla. Más adelante lo aclararé.

    Cuando encuentra un error muchas veces Logstash se para

    En el ejemplo utilizamos como salida el smtp de gmail y esto es una mala idea porque en caso de estar inaccesible mientras Logstash intenta enviar un e-mail, nos devolverá un error y se parará. Si mientras nos damos cuenta de que está parado se rotan los logs habremos "perdido" todo el procesamiento de esa información que está entre la parada y el momento de rotar los logs.

    Con esto quiero decir que es siempre mejor tener un relay de correo en local configurado para reenviar los correos al relay de tu red o a tu proveedor externo.

    08 de June de 2014 a las 07:53

    06 de May de 2014

    david::

    Zoe controlling my TV (thanks to this)



    Zoe controlling my TV (thanks to this)

    06 de May de 2014 a las 10:59

    03 de May de 2014

    Jose Manuel

    Google Code Jam 2014 ... con obstáculos - Round 1A, 1B y fin

    El comentario de anonimo en mi post anterior me ha descubierto una cosa que no conocía: la Programación Competitiva. Yo pensaba que esto era un invento de Google pero resulta que ya estaba inventado. Un gran aporte. Muchas gracias.

    Le he estado dando bastantes vueltas y he decidido mantener mi mente "virgen" porque lo que me interesa es saber hasta donde puedo llegar con mis limitaciones actuales, no preparame para ganar un concurso. El año que viene ya veremos si opino lo mismo.

    Round 1A

    Gracias a un "papá miedo" tuve la "suerte" de despertarme a las 3 de la mañana así que aproveché para ver los tres problemas y hacerme una idea de la dificultad. Vi asequibles tanto el "Problem A. Charging Chaos" como el "Problem B. Full Binary Tree" pero el "Problem C. Proper Shuffle" era más difícil.

    Al día siguiente vi que el corte estaba en hacer los dos primeros problemas sin cometer equivocaciones así que tomé nota para la siguiente.

    Round 1B

    Tras haber solicitado el correspondiente permiso marital para poder pasar la tarde frente al ordenador empiezo por el primer problema.

    Problem A. The Repeater

    Lo que nos piden

    En el primer problema nos piden cual es el número mínimo de pasos necesarios para igualar varias cadenas de texto cadenas de texto siguiendo dos reglas:

    • Si hay dos caracteres consecutivos iguales se puede eliminar uno de los dos.
    • Si hay un caracter se puede duplicar.

    Por ejemplo, si tenemos la cadena "aaabcc" y queremos llegar a "abbbcc" tenemos que pasar por "aabcc", "abcc" y "abbcc". ¿Fácil no?

    Aquí tenemos unos ejemplos del concurso:

    • Caso 1: Cadenas:
      • mmaw
      • maw
      Solución: Case #1: 1
    • Caso 2: Cadenas:
      • gcj
      • cj
      Solución: Case #2: Fegla Won
    • Caso 3: Cadenas:
      • aaabbb
      • ab
      • aabb
      Solución: Case #3: 4
    • Caso 4: Cadenas:
      • abc
      • abc
      Solución: Case #4: 0
    • Caso 5: Cadenas:
      • aabc
      • abbc
      • abcc
      Solución: Case #5: 3

    La solución

    La solución consiste en primero comprobar si el problema tiene solución y en caso de tenerla averiguar cuantos pasos son necesarios para llegar desde una cadena a la otra. Si has hecho este problema probablemente esto te sonará un poco raro pero me explicaré más adelante.

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    import sys
    import time
     
    def getValue(inputFile,dataType="string"):
      line=""
      value=0
      while len(line) 1:
        line=inputFile.readline()
     
      if dataType=="string":
        value=line.split()[0]
      elif dataType=="integer":
        value=int(line.split()[0])
      elif dataType=="float":
        value=float(line.split()[0])
     
      return value
     
    def reducedCase(case):
      char=""
      reduced=""
    
      i=0
      while i len(case):
        if not(char==case[i]):
          char=case[i]
          reduced=reduced+char
        i=i+1
    
      return reduced
    
    def testPossible(cases):
      # For each case test if removing duplicates make them the same
      reduced=reducedCase(cases[0][0])
      possible=1
      i=1
      while i len(cases) and possible==1:
        if not(reduced==reducedCase(cases[i][0])):
          possible=0
        i=i+1
      return possible
    
    def convert(case1, case2):
      # Try to find the number of steps to translate case1 to case2
      steps=0
    
      diff=0
      i=0
      j=0
      char=case1[0]
      while i len(case1) and j len(case2):
        found=0
        while i len(case1) and found==0:
          if char==case1[i]:
            i=i+1
          else: 
            found=1
        found=0
        while j len(case2) and found==0:
          if char==case2[j]:
            j=j+1
          else:
            found=1
        steps=steps+abs(i-j-diff)
        diff=abs(i-j)
    
        if i len(case1):
          char=case1[i]
      return steps
       
    ### solve it! ###
    def solveIt(cases):
      res=1
    
      # Reducir duplicados en todos y comprobar que sale la misma cadena para ver si
      # es posible resolverlo
      possible=testPossible(cases)
      if possible==1:
        i=1
        while i len(cases):
          #Elegir uno como plantilla e igualar el resto.
          steps=convert(cases[0][0],cases[i][0])
          cases[i][1]=steps
          i=i+1
    
        res=0
        for case in cases:
          if case[1]>res:
            res=case[1]
      else:
        res=-1
     
      return res
     
    if __name__=='__main__':
      # Open input and output files
      inputFile=open(sys.argv[1],'r')
      outputFile=open(sys.argv[2],'w')
     
      # Get number of cases
      NoC=int(getValue(inputFile))
      # for each case
      for i in range(NoC):
        # get case data
        inputs=getValue(inputFile,"integer")
        cases=[]
        while inputs>0:
          case=getValue(inputFile,"string")
          cases.append([case,-1])
          inputs=inputs-1
        # solve problem
        res=solveIt(cases)
     
        # write data
        if res==-1:
          outputFile.write("Case #"+str(i+1)+": Fegla Won\n")
          print "Case #"+str(i+1)+": Fegla Won"
        else:
          outputFile.write("Case #"+str(i+1)+": "+str(res)+"\n")
          print "Case #"+str(i+1)+": "+str(res)
     
      # Close input and output files
      inputFile.close()
      outputFile.close()
    

    Resultados

    En el ejemplo que viene la entrada es:

    5
    2
    mmaw
    maw
    2
    gcj
    cj
    3
    aaabbb
    ab
    aabb
    2
    abc
    abc
    3
    aabc
    abbc
    abcc
    

    Y la salida correcta es:

    Case #1: 1
    Case #2: Fegla Won
    Case #3: 4
    Case #4: 0
    Case #5: 3

    Sin embargo a mi me sale mal el último resultado y me empiezo a poner nervioso:

    Case #1: 1
    Case #2: Fegla Won
    Case #3: 4
    Case #4: 0
    Case #5: 2
    

    19:45

    "La cagamos Luis"

    ... dijo Carlos Sainz cuando se enteró de que su motor llevaba estando defectuoso desde la salida.

    Resuelvo el problema que he descrito pero no el que me piden y a estas horas ya no me da tiempo a rectificar.

    Para resolver el problema hay que tener en cuenta todas las cadenas simultáneamente y yo las he tenido en cuenta de una en una

    En el último caso yo obtengo como resultado 2 porque aabc->abc->abbc y aabc->abc->abcc . Así que como mucho necesito dos pasos pero lo que en realidad hay que hacer entiendo es pasar a la vez todas las cadenas a una sóla de esta forma:

    ["aabc","abbc"]->["abc","abbc"]->["abc","abc"]->["abcc","abcc"]
    Y de ahí salen los tres pasos.

    No tengo tiempo para volver a rediseñar el programa así que se acabó esta ronda para mí.

    ¿Round 1C?

    "En habiendo agotado" todos los permisos maritales que tenía para el Google Code Jam, me tengo que retirar de esta convocatoria así que ya veremos el año que viene si aprendo a leer.

    Creo que me tendré que conformar con presentarme al Tuenti Challenge 4 y acabar mi curso de mongodb para desarrolladores y mi curso de mongodb para administradores avanzados.

    03 de May de 2014 a las 18:41

    23 de April de 2014

    david::

    I'll make my own Zoe. With blackjack. And hookers.

    I’m working in a reduced distribution of Zoe with the basic components, so you can build your own assistant with the basic services running out of the box. So you don’t have to clone our installation and trim all the services you don’t care about.

    It includes the basic agents (natural, broadcast, users, log, relay), some natural language commands, the communication agents (mail, jabber, twitter) and some example agents.

    In order to make it easier to add new agents, the server has been updated to feature dynamic agent registration, which means that instead of registering your agent in a configuration file, you can send a message to the server with the agent parameters (name, host, port and optionally a list of topics it listens to). This message is automatically generated by the Python library zoe.deco, which I think is the best option to start writing agents.

    By the way, the server’s source code has been updated to make use of Akka instead of scala.actor, and to have a cleaner and more functional style. I’m still a complete newbie at FP so I beg you to forgive me if the code does not reach the pure functional meta-existentialist beauty standards :P

    As soon as it is tested in Linux and OS X I’ll drop the code to a new Github repo.

    23 de April de 2014 a las 19:50

    13 de April de 2014

    Jose Manuel

    Google Code Jam 2014 ... con obstáculos - Qualification Round

    Preparando el concurso

    Dado que la entrada y salida de datos es siempre exactamente igual he hecho una plantilla que usaré en todos los retos:

    #!/usr/bin/python
    # -*- coding: utf-8 -*- 
    import sys
    import time
    
    def getValue(inputFile,dataType="string"):
      line=""
      value=0
      while len(line) 1:
        line=inputFile.readline()
    
      if dataType=="string":
        value=line.split()[0]
      elif dataType=="integer":
        value=int(line.split()[0])
      elif dataType=="float":
        value=float(line.split()[0])
    
      return value
    
    def getList(inputFile,dataType="string",separator="space"):
      # dataType could be string, integer and float
      # separator can be space or none
      list=[]
      
      line=""
      while len(line) 1:
        line=inputFile.readline()
    
        if  separator=="space":
          list=line.split()
        elif separator=="none":
          line=line.rstrip('\n')
          for i in range(len(line)):
            list.append(line[i])
    
    
      #if dataType=="string": ... already a string
      if dataType=="integer":
        i=0
        while (i len(list)):
          list[i]=int(list[i])
          i=i+1
      elif dataType=="float":
        i=0
        while (i len(list)):
          list[i]=float(list[i])
          i=i+1
      return list
    
    def getBoard(inputFile,dimX,dimY,dataType="string",separator="none"):
      line=""
      board=[]
     
      for y in range(dimY):
          board.append(getList(inputFile,dataType,separator))
     
      return board
    
    def printBoard(board,array="0"):
      #print board
      for i in range(len(board)):
        for j in range(len(board[i])):
          if array=="1":
            sys.stdout.write("[\""+str(board[i][j])+"\"]")
          else:
            sys.stdout.write(str(board[i][j]))
            
        print ""
      
    ### solve it! ###
    def solveIt(inputs, values,board):
    #  time.sleep(1)
    #  print ""
    #  print inputs
    #  print values
    #  print board
    
      res=[]
      i=0
      j=1
    
      res.append(i)
      res.append(j)
    
      return res
    
    if __name__=='__main__':
      # Open input and output files
      inputFile=open(sys.argv[1],'r')
      outputFile=open(sys.argv[2],'w')
    
      # Get number of cases
      NoC=int(getValue(inputFile))
    
      # for each case
      for i in range(NoC):
        # get case data
        inputs=getValue(inputFile,"integer")
        values=getList(inputFile,"integer")
        board=getBoard(inputFile,"integer")
        # solve problem
        res=solveIt(inputs, values, board)
    
        # write data    
        outputFile.write("Case #"+str(i+1)+": "+str(res[0]+1)+" "+str(res[1]+1)+"\n")
    #    print "Case #"+str(i+1)+": "+str(res[0]+1)+" "+str(res[1]+1)
    
      # Close input and output files
      inputFile.close()
      outputFile.close()
    

    Y pensarás ¿no puedes hacer eso el día del concurso? Pues no porque tengo los minutos contados. 10 minutos pueden suponer la diferencia entre que de tiempo a resolver un problema o no.

    Insomnio provocado

    4:00

    Aprovecho una subida de fiebre del niño para despertarme del todo y valorar la dificultad de los problemas.

    Esta vez me voy directo al "Contest scoreboard" donde veo que los mejores tardan 15 minutos en resolver el primero, otros 15 el segundo y alrededor de una hora el tercero y el cuarto así que supongo que los fáciles son el primero y el segundo.

    Tras leer el primero, parece más una broma que un problema. El segundo también parece fácil pero necesita de una lectura más profunda del problema y con menos sueño.

    Mañana será otro día. Bueno, hoy dentro de un rato será otro día.

    Problem A. Magic Trick

    7:30

    Este problema es facilísimo. Nos dan dos arrays distintos en los que los números cambian de posición y nos piden que busquemos los números de una fila del primer array en otra fila del segundo array.

    • Si se encuentran 2 -> Case #x: Bad magician!
    • Si no se encuentran -> Volunteer cheated!
    • Si se encuentra 1 -> Case #x: x
    8:40

    Tras un "tengo pis" y un "dale el antibiótico al niño" la solución, utilizando la plantilla como librería es la siguiente contenida en la función solveIt:

    #!/usr/bin/python
    # -*- coding: utf-8 -*- 
    import time
    import sys 
    import gcjtemplate
    
    ### solve it! ###
    def solveIt(row1,board1,row2,board2):
      res=[]
      for i in board2[row2-1]:
        if i in board1[row1-1]:
          res.append(i)
    
      return res
    
    if __name__=='__main__':
      # Open input and output files
      inputFile=open(sys.argv[1],'r')
      outputFile=open(sys.argv[2],'w')
    
      # Get number of cases
      NoC=int(gcjtemplate.getValue(inputFile))
    
      # for each case
      for i in range(NoC):
        # get case data
        row1=gcjtemplate.getValue(inputFile,"integer")
        board1=gcjtemplate.getBoard(inputFile,4,4,"integer","space")
        row2=gcjtemplate.getValue(inputFile,"integer")
        board2=gcjtemplate.getBoard(inputFile,4,4,"integer","space")
        # solve problem
        res=solveIt(row1, board1, row2, board2)
    
        # write data    
        if len(res)==0:
          outputFile.write("Case #"+str(i+1)+": Volunteer cheated!\n")
          print ("Case #"+str(i+1)+": Volunteer cheated!")
        elif len(res)==1:
          outputFile.write("Case #"+str(i+1)+": "+str(res[0])+"\n")
          print ("Case #"+str(i+1)+": "+str(res[0]))
        elif len(res)>1:
          outputFile.write("Case #"+str(i+1)+": Bad magician!\n")
          print ("Case #"+str(i+1)+": Bad magician!")
        else:
          time.sleep(5)
          print "HELP, HELP!"
    
      # Close input and output files
      inputFile.close()
      outputFile.close()
    

    Problem B. Cookie Clicker Alpha

    8:45

    En este problema la dificultad está más en comprenderlo que en resolverlo.

    Tu objetivo es llegar a tener un número de galletas en el menor tiempo posible. Empiezas con una fábrica de galletas y que te ha costado x galletas. Cuando llegas a esas x galletas puedes elegir entre comprar una fábrica para doblar la capacidad de producción o seguir produciendo como hasta ahora.

    Se trata de elegir la mejor estrategia para decir cual es el menor número de segundos que se tarda en llegar a conseguir el número de galletas que queremos.

    Hay que tener en cuenta que nos dan unos límites que, aunque en python nos dan igual, en otros lenguajes nos vienen bien para elegir el tipo de datos.

    9:09

    Se levanta la tropa, les llevo al parque, reunión familiar, comilona, ...

    23:43

    Estoy a 1:15 de decidir si paso a la siguiente fase o no. En teoría es factible pero no me gusta ir tan corto de tiempo.

    00:35

    El que nos den 8 minutos para entregar el resultado de nuestro programa en vez de los 4 habituales es un indicador de que puede ser bastante costoso en términos computacionales.

    Este problema es de naturaleza recursiva ya que para decidir entre comprar o no comprar otra fábrica de galletas hay que saber qué es lo que pasaría si no se comprara otra o qué pasaría si se comprara otra, en cuyo caso habría que volver a saber qué es lo que pasaría si no se comprara otra o qué pasaría si se comprara otra, ... hasta que viéramos que deja de salir a cuenta comprar otra fábrica.

    Sin embargo el problema se puede enfocar desde un punto de vista más lineal si pensamos en qué vamos a basar la decisión final: si con la capacidad de producción que tengo ahora tardo menos en producir las galletas que aumentando la producción en una fábrica más es que no debo comprar más fábricas.

    Ignorando el resto de la plantilla que he puesto arriba del todo, la solución es la siguiente:

    ### solve it! ###
    def solveIt(c,f,x):
      res=0.0
    
      speed=2
      cookies=0.0
      spentSeconds=0
    
      finish=0
      while finish==0:
        withoutMoreFarms=x/speed
    
        secondsToBuyFarm=c/speed
        newSpeed=speed+f
        withOneMoreFarm=secondsToBuyFarm+x/newSpeed
    
        if withOneMoreFarm withoutMoreFarms:
          spentSeconds=spentSeconds+secondsToBuyFarm
          speed=newSpeed
        else:
          spentSeconds=spentSeconds+withoutMoreFarms
          finish=1
        
    #    print "spentSeconds: "+str(spentSeconds)
    
      res=spentSeconds
      return res
    
    if __name__=='__main__':
      # Open input and output files
      inputFile=open(sys.argv[1],'r')
      outputFile=open(sys.argv[2],'w')
    
      # Get number of cases
      NoC=int(getValue(inputFile))
    
      # for each case
      for i in range(NoC):
        # get case data
        c,f,x=getList(inputFile,"float")
        # solve problem
        res=solveIt(c,f,x)
    
        # write data    
        outputFile.write("Case #"+str(i+1)+": "+str(round(res,7))+"\n")
        #print "Case #"+str(i+1)+": "+str(round(res,7))
    
      # Close input and output files
      inputFile.close()
      outputFile.close()
    

    Una vez enviada la respuesta al Large Set te indican que:
    You have already tried this input set. (Judged at the end of the contest.)
    Así que no hay forma de saber si ya tengo los 25 puntos que necesito o no.

    ¿Mas?

    1:00

    Pues va a ser que a estas horas lo que me apetece es dormir. Mañana publicaré este post y el resultado del concurso.

    9:20

    ¡He pasado!

    Lo que no entiendo muy bien es cómo puede haber gente que lo haya hecho peor todavía que yo y haber pasado también, pero ahí están los resultados.

    Para la próxima a mirar la librería multiprocessing que me hará falta para utilizar todos los cores de mi máquina.

    13 de April de 2014 a las 07:35

    17 de December de 2013

    Ana

    Voy a comprar pasta de dientes sin flúor

    Me he quedado flipando, pero resulta que el flúor es tóxico y provoca caries O_o

    Lo usaban los alemanes en la II Guerra Mundial para controlar a la población O_O
    Y España fluorando el agua.

    Dos extractillos y enlace a la noticia, por si queréis echarle un vistazo (y si alguien sabe algo sobre si es verdad o mentira, que lo diga, porfa).

    http://r-evolucion.es/2013/09/03/espana-fomenta-la-fluoracion-del-agua-y-el-mundo-la-prohibe/

    "se comprobó que la fluoración causó ligeros daños a una parte específica del cerebro, haciendo más difícil para la persona afectada defendiera su libertad y causando que la persona llegue a ser más dócil a la autoridad. El flúor sigue siendo una de las más fuertes substancias anti-psicóticas conocidas, y está contenida en un 25% de los mayores tranquilizantes"

    "Durante la década de los años ´90, la investigación realizada por la toxicóloga Dra. Phillis Mullenix de Harvard demostró que el flúor en el agua puede llevar a un menor coeficiente intelectual, y los síntomas producidos en ratas se parecían fuertemente al déficit de atención e hiperactividad (SDAH)"

    17 de December de 2013 a las 14:25

    15 de August de 2013

    Ana

    ¡Software libre en la uni! II

    No sé qué os parecerá a vosotros, pero a mí me ha sorprendido:

    http://www.uc3m.es/portal/page/portal/cultura_y_deporte/espacio_abierto/cursos/sw_libre

    Taller de Diseño Gráfico con Software Libre

    Desde luego es una buena opción para aprender, para enseñar y para manejarse después, aunque algunas personas crean que el software privativo tiene que ser mejor "porque si no no habría gente que paga por él".

    Me parece una buena iniciativa. Aunque a lo mejor hace competencia a los cursos del GUL :p

    15 de August de 2013 a las 21:38

    11 de October de 2012

    Fernando Cerezal

    Elecciones a delegados en la universidad

    Llegan este año las elecciones a delegados. Parece que nos han escuchado de años anteriores y ahora aparece un anuncio en aula global y se mandan correos sobre el tema.

    Este año vuelvo a presentarme, al igual que los dos anteriores. Este año hemos conseguido que se cambien algunos profesores, y se han dado toques de atención a algunos departamentos. Poco a poco, vamos consiguiendo que las cosas cambien. Aún hay muchas cosas en las que trabajar, y es necesario poder expresar de una forma responsable y sin miedo los problemas que existen, tanto directamente a los profesores como a las instancias superiores que sean necesarias. Si bien parece que los alumnos estamos en desventaja, saber con quien hablar puede dejar en clara desventaja a quien no sigue las normas de la universidad. Y algunos ya sabéis de mis más y mis menos con algunos profesores, y que en la mayoría de las ocasiones han tenido que ceder: De las entregas de boletines de ejercicios por sorpresa en clase a cambiar la forma de evaluación durante el curso. Al final han tenido que acogerse a lar normas.

    Aunque tuve una etapa anterior en la delegación, sobre el 2007, muchas cosas han cambiado en esta nueva etapa. Hemos tenido que pegarnos con los problemas en la implantación de las últimas fases de los grados, y con la implantación del plan 2011 de las ingenierías TIC (a.k.a. plan ABET). Conocer los problemas que aparecen en cada momento es vital para solucionarlos cuanto antes.

    Ser estos dos últimos años subdelegado de curso y de titulación, y el último año miembro del Claustro, me han permitido conocer trabajar con mucha gente. Para empezar habría que agradecer a Paco Valera su dedicación como subdirector de la titulación en los últimos años con los problemas de los nuevos planes de estudio, y cuya puerta siempre estaba abierta para hablar de cualquier problema, o dar a un toque a los profesores que fuese necesario.  Si bien apenas acaba de empezar el curso, la misma sensación tengo con el nuevo subdirector, Mario Muñoz, con quien ya he tratado algunos problemas.

    Aunque vuelvo a presentarme, salga quien salga sabe que puede contar con mi ayuda para lo que necesite.

    11 de October de 2012 a las 13:43

    30 de September de 2012

    Fernando Cerezal

    REAMDE, como soltarle una pullita a Google

    Hace poco que he empezado a leer "REAMDE", el último libro de Neal Stephenson. En él habla de un personaje que ha creado un videojuego cuyas primeras imágenes al cargar son como las de Google Earth, pero que el personaje no tienen ningún remordimiento porque los que los que hicieron Google Earth copiaron esa idea de un libro.


    30 de September de 2012 a las 16:37

    27 de May de 2010

    Fernando J. Pereda

    iostreams are VERY thread-unsafe on Mac OS X

    This was both surprising and disgusting. Our in-house data acquisition software needs to convert lots of floats to ascii so that they can ve viewed in real time. This is very easy to do with a stringify-like function like the one found in paludis/paludis/util/stringify.hh.

    stringify looks trivial, there’s no shared state nor there is any static data, so I thought that I could call stringify from several threads at the same time. I don’t think there’s any guarantee about thread safety of ostringstream’s operator<< but it looked like a safe assumption. Well, incorrect.

    operator<< calls vsnprintf, which should be thread-safe by itself. However, OSX's vsnprintf ultimately calls localeconv_l, which is not thread-safe. And, you end up with something like this:

    #0 0x96f734a9 in malloc_error_break ()
    #1 0x96f6e497 in szone_error ()
    #2 0x96e98503 in szone_free ()
    #3 0x96e9836d in free ()
    #4 0x96e97f24 in localeconv_l ()
    #5 0x96e93335 in __vfprintf ()
    #6 0x96ecb9b5 in vsnprintf ()
    #7 0x0144615e in std::__convert_from_v ()
    #8 0x01437d2a in std::num_put<char, std::ostreambuf_iterator<char, std::char_traits > >::_M_insert_float ()
    #9 0x0143803d in std::num_put<char, std::ostreambuf_iterator<char, std::char_traits > >::do_put ()
    #10 0x0144ab6a in std::ostream::_M_insert ()
    #11 0x0000fb25 in std::basic_ostringstream<char, std::char_traits, std::allocator >::str () at sstream:217
    ...

    Which means there’s no way of converting stuff to human readable in a thread-safe manner. I’m not sure whether I’m missing something or not… but this looks very fishy. I ended up adding a stupid big mutex around my stringify calls, but that looks more like a workaround that a final solution to the problem. Plus, this doesn’t protect ANY other uses of iostream’s operator<< such as loggers.

    Ok… looks like that wasn’t a very accurate diagnostic. This is going to be more annoying than I thought.

    — ferdy


    Tagged: C, osx, programming, threads

    27 de May de 2010 a las 08:33

    01 de May de 2010

    Fernando J. Pereda

    Finally, a real AMSV (Autonomous Marine Surface Vehicle)

    After lots of work from different people, it finally is a real AMSV. Nothing too fancy yet (just a mere PD controller for speed and heading). It is, nonetheless, a very interesting platform for future research.

    With semi-strong current and some wind it managed to follow a very nice path across some waypoints:

    The trajectory between p2 and the shore was done manually using a joystick. Interestingly enough, that path is less nice than those done by the autonomous control.

    I hope to be able to post more niceties soon.

    — ferdy

    01 de May de 2010 a las 15:15

    17 de December de 2009

    Roberto Muñoz

    Poliamor

    «Como digo, soy un hombre. Me gustan las mujeres. A veces esa atracción está incluso fuera de mi control. Puedo controlar mis actos, aunque no lo que siento. Miro a las chicas por la calle, y a algunas las encuentro realmente atractivas. No sentiré especial devoción por Sorolla o Velázquez, pero es que no todas las obras de arte se encuentran en los museos. A veces me salto a los intermediarios y voy directamente a la exposición de Dios.»
    -- Javier Malonda (aunque bien se puede atribuir a cualquier hombre heterosexual)

    Al final de la entrada de donde he extraído lo anterior se da el enlace de la Wikipedia del Poliamor. Después de leerlo veo que un poliamoroso famoso es Eric S. Raymond. Que la wikipedia lo define como:
    «Raymond es un neopagano, un confeso anarcocapitalista, y un defensor del derecho a poseer y utilizar armas de fuego. Tiene un gran interés en la ciencia ficción. Es músico amateur y cinturón negro de taekwondo. Además sufre una leve parálisis cerebral congénita.»
    A eso añádele poliamoroso. El amigo «dospistolas» no se aburre, y es más listo que el hambre, como se suele decir.

    17 de December de 2009 a las 18:58

    02 de November de 2009

    Roberto Muñoz

    TTS 2.0

    He publicado la versión 2.0 de TTS (TalkToSerial) que tiene las siguientes mejoras:


    Para más info visitad el Wiki. Y si se quiere descargar, aquí está el código fuente.

    02 de November de 2009 a las 19:59

    29 de May de 2009

    Fernando J. Pereda

    MSDNAA, clever?

    So MSDNAA lets university students get some Microsoft products for free for educational purposes. That’s all fine and dandy except that you can’t directly download stuff, you have to do it using a shitty download manager.

    It is hilarious that you have to run a Windows executable to download a copy of Windows XP.

    Chicken and egg?… Yeah, that’s clever.

    One point for you Suckrosoft.


    Tagged: enterprisey, idiots, rant, suckrosoft

    29 de May de 2009 a las 09:02

    10 de May de 2009

    Fernando J. Pereda

    OpenSceneGraph

    For SpaceFish I wanted a quick way to load a 3D model and be able to rotate it easily. This, along with an artificial horizon is a nice way to see the attitude of the plane while it is far to see it. It is also quite good to replay recorded data during experiments to study it further in the lab.

    Since I haven’t really done anything in OpenGL beyond stupid examples and helloworld-like programs and given that I don’t have much time to devote to this task I decided to use an existing framework. Among Irrlicht, OpenSceneGraph and Ogre. I decided to give OpenSceneGraph a try, for no particular reason.

    Unfortunately, it took a while to get it working under OSX… it needs something like this. I use MacPorts for this kind of stuff under OSX:

    fixOpenSceneGraph()
    {
    	local lib_dir=/opt/local/lib
    	pushd ${lib_dir} > /dev/null
    	echo pushd ${lib_dir}
    	for i in libosg*.dylib* libOpenThreads*.dylib* ; do
    		echo install_name_tool -id ${lib_dir}/${i} ${i}
    		otool -L ${i} | sed -e 1d | while read f ; do
    			if [[ ${f} =~ ^libosg ]] || [[ ${f} =~ ^libOpenThreads ]] ; then
    				l=${f%% *}
    				echo install_name_tool -change ${l} ${lib_dir}/${l} ${i}
    			fi
    		done
    	done
    	popd > /dev/null
    	echo popd
    	port contents OpenSceneGraph |
    		sed -n -e '/^[[:space:]]*\/opt\/local\/bin\//p' -e '/\.so/p' |
    		while read f ; do
    		otool -L ${f} | sed -e 1d | while read d ; do
    			if [[ ${d} =~ ^libosg ]] || [[ ${d} =~ ^libOpenThreads ]] ; then
    				l=${d%% *}
    				echo install_name_tool -change ${l} ${lib_dir}/${l} ${f}
    			fi
    		done
    	done
    }

    It wasn’t fun to figure that out (thank you CMake)…

    Anyway, I think I’ll stick to OpenSceneGraph until it annoys me enough. For now, I managed to do what I wanted in less than 2 hours, which is pretty good when you have a stupidly tight schedule.

    — ferdy


    Tagged: cmake-sucks-goat-balls, cpp, openscenegraph, osx, spacefish

    10 de May de 2009 a las 22:18

    27 de April de 2009

    Fernando J. Pereda

    Small C trivia

    This is somehow surprising the first time you see it and it is interesting to remind it to people from time to time. The question is easy, does this program always return 0? That is, are those summations the same?

    If there’s a case when it doesn’t, provide a sample input and explain why it happens.

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[])
    {
    	float f[argc - 1];
    	for (int i = 1; i < argc; i++)
    		f[i - 1] = atof(argv[i]);
    	float r1 = 0;
    	for (int i = 0; i < argc - 1; i++)
    		r1 += f[i];
    	float r2 = 0;
    	for (int i = argc - 2; i >= 0; i--)
    		r2 += f[i];
    	return r1 != r2;
    }

    As usual, I’ll post the solution in a couple of days or when someone gets it right (which is always the case :))

    — fpereda

    Update: correct typo spotted by Snaury.


    Tagged: C, CS, programming, trivia

    27 de April de 2009 a las 09:21

    21 de March de 2009

    Fernando J. Pereda

    The Burning Ship fractal

    I finally sat down and wrote support for drawing the Burning Ship Fractal into gmandel. It only took a couple of minutes, but I haven’t really had spare time lately.

    Some parts of the fractal are quite interesting and different from other fractals derived from the Mandelbrot set. Here are some pictures using gmandel:

    burningship1 burningship2 burningship3

    — fpereda


    Tagged: burningship, chaos, fractal, gmandel

    21 de March de 2009 a las 19:11

    15 de March de 2009

    Fernando J. Pereda

    Bye-Bye Gentoo

    My retirement from Gentoo is complete now.

    Good luck to everybody. I hope some people understand the real needs of Gentoo and where it should go. Even if I’m not planning to come back to Gentoo (either as a user or as a developer), I certainly hope the best for it.

    Cheers.

    — ferdy


    Tagged: gentoo

    15 de March de 2009 a las 17:23

    16 de February de 2009

    Fede Mon

    esta tarde a la expo de Star Wars en Madrid, quien se viene?

    16 de February de 2009 a las 12:03

    13 de February de 2009

    Fede Mon

    me encanta: la camiseta con el piechart de la procastinación: http://ping.fm/caI56

    13 de February de 2009 a las 00:54

    10 de February de 2009

    Fernando J. Pereda

    Selected!

    So this led to this

    ’nuff said!

    Mood: Extremelly happy.

    — ferdy


    Tagged: esa, estec, happy, research, spacefish

    10 de February de 2009 a las 18:11

    02 de February de 2009

    Fernando J. Pereda

    More reading

    I finished reading Anathem a while ago, and I really do recommend it. It was weird at first, but really nice in the end. It finished a bit fast, I’d say it needs another hundred pages to tie some of the stuff.

    Also, Ricardo Cervera (you don’t have an url these days, you do?) sent me Introduction to Algorithms which I’ve been skimming through. Really nice book, of course. — Thanks.

    As part of one of the research projects I’m involved, I just started reading/studying Aircraft control and simulation. Fortunately, it is not hurting as much as I expected. Though it is not for the faint of heart.

    — ferdy


    Tagged: book, reading, thanks

    02 de February de 2009 a las 12:05