code

Programación funcional: Enfrenta a la concurrencia

Submitted by gwolf on Wed, 03/14/2012 - 19:06
Wolf G.  2012.  Programación funcional: Enfrenta a la concurrencia. Software Gurú. :48-49.

El tema eje de el presente número de Software Gurú es el manejo de datos a muy gran escala (y disculparán que no use la frase más de moda en la industria, Big Data, habiendo otras igual de descriptivas en nuestro idioma). Al hablar de muy gran escala tenemos que entender que pueden ser juegos de datos mucho mayores de lo que acostumbramos — Estamos hablando de un aumento de por lo tres a seis órdenes de magnitud en la escala de los datos a analizar: Según las definiciones más comunes hoy en día, en el rango entre decenas de terabytes y petabytes.

Dar un salto tan grande nos presenta retos en muy diversas esferas. Para muchas de las necesidades que enfrentamos, tenemos que adecuar nuestros procesos de desarrollo, las herramientas que empleamos, el modelo con el cual almacenamos, solicitamos y procesamos la información, e incluso el hardware mismo. Enfocaré este texto a un paradigma de programación que permite enfrentar a la concurrencia de una forma más natural y menos traumática de lo que acostumbramos.

Una de las razones por las que este tema ha armado tanto alboroto en el campo del desarrollo de software es que, si bien la capacidad de cómputo a nuestro alcance ha crecido de forma francamente bestial desde casi cualquier métrica en el tiempo que nos ha tocado vivir como profesionales, nuestra formación sigue estando basada en un modelo de desarrollo muy difícil de escalar. Vamos, el problema no lo tienen las computadoras, sino nosotros los programadores: No sólo tenemos que explicar a la computadora lo que requerimos que haga, sino que además de ello tenemos que cuidar que no se tropiece –cual si fuera un ciempiés– con su propia marcha. Siempre que hablemos de muy gran escala debemos hablar, sí o sí, de un alto grado de paralelismo en nuestras aplicaciones. Y por muchos años, el paralelismo fue precisamente algo de lo que buena parte de los programadores buscaban escapar, por las complicaciones que conlleva ante una programación imperativa, necesariamente secuencial.

Las alarmas comenzaron a sonar fuertemente hacia el año 2005, en que los fabricantes de hardware tuvieron que cambiar su estrategia (y lograron, sorprendentemente, inyectarle algunos años más de vida a la ley de Moore, la cual indica que el número de transistores que componen a un chip se duplica aproximadamente cada dos años, ritmo que se ha mantenido por 40 años ya): Al migrar el desarrollo de procesadores una estrategia de multiprocesamiento (CPUs múltiples empaquetados como una sóla unidad), dejando de lado la carrera de los megahertz, aventaron la papa caliente hacia el lado de los desarrolladores: Tendríamos que adecuarnos a una realidad de concurrencia verdadera y ya no simulada.

Los sistemas multiprocesador no son, claro está, tan recientes. El gran cambio es que ahora prácticamente todas las computadoras de rango medio (incluso ya algunos teléfonos celulares) tienen esta tecnología disponible. Claro está, todo el software de infraestructura, desde los sistemas operativos, compiladores y bibliotecas tuvieron que irse adecuando gradualmente para poder administrar y ofrecer al usuario estos recursos.

Por muchos años, vivimos sabiéndolo en un mundo de falsa concurrencia: Una computadora sólo podía hacer una cosa a la vez, dado que contaba con un sólo procesador. Por la velocidad de su operación, y por el empeño que se puso en que los cambios de contexto fueran tan ágiles como fuese posible, nos daba la impresión de que varias cosas ocurrían al mismo tiempo. Esto, claro, no debe sorprender a ninguno de ustedes — El gran reto introducido por el paralelismo real es manejar correctamente escenarios mucho más complejos de condiciones de carrera que antes no se presentaban tan fácilmente. Antes del paralelismo, podíamos indicar al sistema operativo que nuestro programa estaba por entrar a una sección crítica, con lo cual éste podía decidir retirar el control a nuestro programa para entregarlo a otro si estaba cercano a finalizar su tiempo, o darle una prórroga hasta que saliera de dicha sección.

Cuando hay más de un procesador (un CPU multicore o multinúcleo alberga a varios procesadores, en ocasiones compartiendo elementos como uno de los niveles de memoria cache), la situación se complica: El sistema operativo puede, sí, mantener en ejecución a uno de los programas para reducir la probabilidad de conflictos, pero se hizo indispensable hacer la colaboración entre procesos algo explícito.

Claro, esto no fue un desarrollo repentino ni algo fundamentalmente novedoso. Los mutexes nos han acompañado por muy largos años, y la programación multihilos nos ha regalado dolores de cabeza desde hace muchos años. Sin embargo, en sistemas uniprocesador, la incidencia de condiciones de carrera era suficientemente baja como para que muchos las ignoraran.

Una de las razones por las que la concurrencia nos provoca esos dolores de cabeza es porque nos hemos acostumbrada a enfrentarnos a ella con las herramientas equivocadas. Un tornillo puede clavarse a martillazos, y no dudo que haya quien use destornilladores para meter clavos, pero tendremos mucho mayor éxito (y un tiempo de entrega mucho más aceptable) si usamos la herramienta correcta.

Los lenguajes basados en programación funcional resuelven en buena medida los problemas relacionados con la concurrencia, y pueden de manera natural desplegarse en un entorno masivamente paralelo. Sin embargo, requieren un cambio más profundo en la manera de pensar que, por ejemplo, cuando adoptamos la adopción de la programación orientada a objetos.

¿Cuál es la diferencia? Aprendimos a programar de forma imperativa, con el símil de la lista de instrucciones para una receta de cocina — Los lenguajes puramente funcionales son mucho más parecidos a una definición matemática, en que no hay una secuencia clara de resolución, sino que una definición de cómo se ve el problema una vez resuelto, y los datos se encargan de ir marcando el camino de ejecución. Los lenguajes puramente funcionales tienen una larga historia (Lisp fue creado en 1958), pero en la industria nunca han tenido la adopción de los lenguajes imperativos. Hay una tendencia en los últimos 20 años, sin embargo, de incorporar muchas de sus características en lenguajes mayormente imperativos.

La principal característica que diferencía a los lenguajes funcionales que nos hacen pensar en definiciones matemáticas es que la llamada a una función no tiene efectos secundarios — ¿Han depurado alguna vez código multihilos para darse cuenta que el problema venía de una variable que no había sido declarada como exclusiva? Con la programación funcional, este problema simplemente no se presentaría. Esto lleva a que podamos definir (en AliceML) el cálculo de la serie de Fibonacci como:

      fun fib 0 = 0
        | fib 1 = 1
        | fib n  if (n > 1) = spawn fib(n-1) + fib(n-2);
        | fib _ = raise Domain
    

A diferencia de una definición imperativa, la función es definida dependiendo de la entrada recibida, y la última línea nos muestra el comportamiento en caso de no estar contemplado por ninguna de las condiciones. Y el puro hecho de indicar la palabra «spawn» indica al intérprete que realice este cálculo en un hilo independiente (que podría ser enviado a otro procesador, o incluso a otro nodo, para su cálculo).

Otra de las propiedades de estos lenguajes, las funciones de órden superior (funciones que toman como argumentos a otras funciones). Por ejemplo, en Haskell:

      squareList = map (^2) list
    

Al darle una lista de números a la función squareList, nos entrega otra lista, con el cuadrado de cada uno de los elementos de la lista original. Y, obviamente, esto se puede generalizar a cualquier transformación que se aplicar iterativamente a cada uno de los elementos de la lista.

Hay varios tipos de funciones de órden superior, pero en líneas generales, pueden generalizarse al mapeo (repetir la misma función sobre los elementos de una lista, entregando otra lista como resultado) y la reducción (obtener un resultado único por aplicar la función en cuestión a todos los elementos de la lista). Y es, de hecho, basándose en juegos de mapeo/reducción que se ejecutan la mayor parte de las tareas intensivas en datos en Google.

Podemos encontrar frecuentemente otros dos patrones en estos lenguajes, aunque por simplicidad no los incluyo en estos ejemplos: Por un lado, al no tener efectos secundarios, tenemos la garantía de que toda llamada a una función con los mismos argumentos tendrá los mismos resultados, por lo que un cálculo ya realizado no tiene que recalcularse, y podemos guardar los resultados de las funciones (especialmente en casos altamente recursivos, como éste). En segundo, la evaluación postergada: Podemos indicar al intérprete que guarde un apuntador a un resultado, pero que no lo calcule hasta que éste sea requerido para una operación inmediata (por ejemplo, para desplegar un resultado, o para asignarlo a un cálculo no postergable).

Una de las grandes desventajas que enfrentó la programación funcional es que los lenguajes funcionales puros crecieron dentro de la burbuja académica, resultando imprácticos para su aplicación en la industria del desarrollo. Esto ha cambiado fuertemente. Hoy en día podemos ver lenguajes que gozan de gran popularidad y han adoptado muchas construcciones derivadas de la programación funcional, como Python, Ruby o Perl. Hay lenguajes funcionales que operan sobre las máquinas virtuales de Java (Clojure) y .NET (F#). Por otro lado, lenguajes como Erlang, OCaml y Scheme se mantienen más claramente adheridos a los principios funcionales, pero con bibliotecas estándar y construcciones más completas para el desarrollo de aplicaciones.

El manejo de cantidades masivas de datos están llevando a un pico de interés en la programación funcional. No dejen pasar a esta interesante manera de ver al mundo - Puede costar algo de trabajo ajustar nuestra mente para pensar en términos de este paradigma, pero los resultados seguramente valdrán la pena.

acts_as_catalog, real_fk y acts_as_magic_model — Tres plugins simples para toda ocasión

Submitted by gwolf on Fri, 06/05/2009 - 08:29
Written in...: 
2009
I prepared this for a short presentation at RubyCamp UNAM. I present the three Rails plugins I wrote in 2008, acts_as_catalog, real_fk and acts_as_magic_model
Resumen: 
Preparé esto para una presentación corta en el RubyCamp UNAM. Presento los tres plugins de Rails que escribí en 2008: acts_as_catalog, real_fk y acts_as_magic_model

Bringing closer Debian and Rails: Bridging apparently incompatible cultures

Submitted by gwolf on Mon, 08/25/2008 - 13:32
Written in...: 
2008

Ruby on Rails has become a very popular framework for Web-based applications. And, even though Rails itself is neatly packaged and integrated in Debian, supporting Rails applications (specially in a large-scale provider) can prove rather difficult. Besides the core application, we face problems such as handling plugins, concurrent versions, and the like. In this BoF session we discussed the different problems we face, looking towards adequate solutions.
This talk was presented at DebConf 8, Mar del Plata, Argentina.

Resumen: 

Ruby on Rails se ha convertido en un framework muy popular para el desarrollo de aplicaciones Web. Si bien Rails mismo está empaquetado e integrado correctamente en Debian, el manejar aplicaciones Rails (especialmente si se trata de un proveedor de servicios a gran escala) puede ser más bien complicado. Además de la aplicación misma, nos encontramos con problemas como el manejo de plugins, tener disponibles versiones concurrentes de diferentes bibliotecas, y cosas por el estilo. En esta sesión discutimos acerca de los diferentes retos que esto nos trae, buscando llegar a soluciones adecuadas.
Esta ponencia fue presentada en DebConf 8, Mar del Plata, Argentina.

Security in Perl scripts / Seguridad en scripts de Perl

Submitted by gwolf on Sun, 02/10/2008 - 00:16
Written in...: 
2002

I presented this tutorial at Congreso de Seguridad en Cómputo 2000, and later rewrote it (and moved it to a free, portable format) for Días de Software Libre at Guadalajara, May 2002. In this tutorial, I review some important key points not to fall in security errors while programming with Perl. I later adapted it together with a coworker, Alex Juárez, and we presented it in English at YAPC::Europe 2002. Here you will find this text both in Spanish and in English.

Resumen: 

Un tutorial que presenté para el Congreso de Seguridad en Cómputo en noviembre del 2000, y tras reescribirlo en un formato libre y portable, lo presenté de nuevo en los Días de Software Libre en Guadalajara, mayo del 2002. Lo adapté y traduje junto con mi compañero de trabajo Alex Juárez, y lo presentamos en el YAPC::Europe::2002. Reviso aquí una serie de puntos importantes para no caer en importantes errores de seguridad al programar con Perl. Está tanto en inglés como en español.

Scripts de seguridad en Perl

Submitted by gwolf on Tue, 02/05/2008 - 21:59
Written in...: 
2000

Tutorial I presented at Computer Security conference 2000, giving many examples of small Perl scripts that can help improve security at a site.

Resumen: 

Tutorial que presenté en el congreso Seguridad en Cómputo 2000, dando varios ejemplos de pequeños scripts en Perl que pueden ayudar a la seguridad de un sitio.

SmbGate

Submitted by gwolf on Mon, 02/04/2008 - 00:14
Written in...: 
2006

SmbGate is a little program written in Perl (using the Embperl framework) that allows users to connect to their home directories in a SMB server (be it Samba running on an Unix-like environment or Windows). It implements read-only access, using a Web-based interface.

Resumen: 

SmbGate es un pequeño programita escrito en Perl (usando el framework Embperl) que permite a los usuarios conectasre a sus directorios raiz de un servidor SMB (sea Samba sobre algún Unixoide o Windows), implementando acceso de sólo lectura, sobre una interfaz Web

EOT - Expire Old Threads

Submitted by gwolf on Sun, 02/03/2008 - 15:39
Written in...: 
2003

Copyright (c) 2003, 2005 Gunnar Wolf - gwolf@gwolf.org

RATIONALE

I started using mutt as my mail reader a couple of months ago. One of the features I most liked about mutt is that the messages are by default sorted by thread - this really helps following a long conversation in a very active mailing list!

In order to have the threading as complete as possible, I started archiving all my old messages - of course, as mutt users do, I now save each mailing list to a different folder. Life was great.

Resumen: 

Copyright (c) 2003,2005 Gunnar Wolf - gwolf@gwolf.org

RAZONES

Comencé a usar mutt como mi lector de correo hace un par de meses. Una de las características que más me gustaron de mutt es que los mensajes normalmente aparecen ordenados por hilo - esto ayuda realmente a seguir una conversación larga en una lista muy activa!

Para preservar el hilado de los mensajes, decidí archivar todos mis mensajes viejos - claro, tal como acostumbran hacer los usuarios de mutt. Cada lista va para un folder diferente, y la vida es bella.

Sin embargo, la vida no era perfecta. Después de un par de semanas, algunas de mis listas tenían tanto tráfico -con más de 2000 mensajes archivados- que a mutt le tomaba demasiado tiempo ya abrirlos. Y si bien parte de la culpa puedo echársela a que uso buzones en formato mbox, el cambiar a maildir no haría más que posponer este mismo problema por un par de semanas. Y no quería cortar artificialmente el buzón cada cierto tiempo, pues perdería los beneficios de mis queridos hilos.

Me encontré con el maravilloso y tremendamente completo módulo de Perl Mail::Box, y me dí cuenta que mover hilos completos era muy simple, así que escribí este programita que expirara hilos en vez de mensajes individuales.

USO

El uso es muy simple. Antes que nada, como siempre:
eot -h
te dará una lista de las opciones de EOT, todas ellas opcionales (aunque usualmente querrás especificar al menos -f y -F).

Las opciones válidas son:

  1. eot -f <from_mailbox> -t <from_type> -F <to_mailbox> -T <to_type> -p <period>
  2. All arguments are optional.
  3. opt description default
  4. ======================================================================
  5. -f Which source mailbox to use mailbox
  6. -t What format is this mailbox in (mbox, maildir, mh) mbox
  7. -F Which destination mailbox to use mailbox.arch
  8. -T What format is this mailbox in (mbox, maildir, mh) mbox
  9. -p Period of time to declare a thread as old, in days 7
  10. -v Whether to report work statistics to STDOUT 0

-f and -F se refieren a un buzón -un archvio si es tipo mbox o un directorio si es tipo maildir o MH- en el directorio local, o un path completo o relativo al buzón en cuestión.

-t y -T indican el tipo de buzón a abrir - mbox, maildir or mh.

-p indicates how old (in days) should the last message in a thread be
for the whole thread to be considered inactive.

Si no especificas -v, EOT correrá en silencio. Si especificas -v un
corto resumen de actividad aparecerá después de correr.

LICENCIA

EOT is está cubierto por la GNU GPL versión 2 o superior, a tu discreción.
El texto completo de la GNU GPL puede ser encontrado aquí.

REQUISITOS

EOT fue escrito en Perl, y por tanto requiere Perl (versión 5 o
superior). Además de esto, EOT requiere de los siguientes módulos de
Perl:
Mail::Box (probado con 2.038)
Date::Parse - parte de TimeDate (probado con 1.1400)

Puedes encontrarlos en el CPAN. Si usas un sistema Debian, están respectivamente en los paquetes libmail-box-perl y libtimedate-perl.

AUTOR

EOT fue creado por Gunnar Wolf (gwolf@gwolf.org) en mayo del 2003. Puedes usarlo libremente para el propósito que sea, siempre que te
atengas a la licencia GNU GPL.

BAJARLO

Ok, veo que te interesó ;-)

Puedes bajar la versión 1.1 de EOT aquí.

IPManage

Submitted by gwolf on Sun, 02/03/2008 - 15:24
Written in...: 
2003

A system I wrote while working for FES Iztacala. It helps a network administrator on his tough job relating MAC and IP addresses, generating configurations for the DHCP server and for ARP.
Several years later, already working at IIIEc UNAM, I practically re-wrote it from scratch, cleaner, with an object-oriented layer, using the Template Toolkit for the presentation, and as an Apache module (with mod_perl). Both versions are useful and usable - here you have both. Both are, however, in a "snapshot" state, lacking smaller bits of functionality and documentation.
IPManage (2003, CGI-oriented edition)
IPManage (2007, OOP, mod_perl-driven edition)

Resumen: 

Un sistema que hice cuando trabajé para la FES Iztacala. Ayuda a los administradores de redes en su ardua labor relacionando direcciones IP y MAC, generando configuraciones para el servidor de DHCP y ARP.
Varios años más tarde, ya trabajando en el IIEc UNAM, prácticamente lo re-escribí completo, más limpio, con una capa orientada a objetos, utilizando Template Toolkit para la presentación, y como módulo de Apache (con mod_perl). Ambas versiones son funcionales y usables - Aquí están ambas. Ambas están, sin embargo, en un estado de "snapshot", con pequeñas omisiones en lo que concierne a funcionalidad y documentación.
IPManage (versión de 2003, orientada a CGI)
IPManage (versión de 2007, OOP, basada en mod_perl)

TEPATCHE - OpenBSD automatic system patcher / Parchador Automático de sistema OpenBSD

Submitted by gwolf on Sun, 02/03/2008 - 12:57
Written in...: 
2003

RATIONALE

OpenBSD is a stable, robust and secure operating system. Systems administrators running OpenBSD tend to be also more security conscious than administrators running other operating systems. Nevertheless, patching an OpenBSD system can be a tedious process for many people. If a person manages multiple OpenBSD servers, patching each of them can be a long and repetitive task, ideal for automatization.

Resumen: 

RAZONES

OpenBSD es un sistema operativo estable, robusto y seguro. Los administradores de sistemas que corren OpenBSD tienden a ser mas conscientes de la seguridad que los administradores corriendo otros sistemas operativos. En ocasiones, parchar un sistema OpenBSD puede volverse un proceso tedioso para muchas personas. Si una persona se encarga de muchos servidores OpenBSD, el parchar cada uno de ellos puede ser una tarea larga y repetitiva, ideal para automatizarla.
Tepatche revisará periódicamente el sitio FTP que se le indique, y si hay un nuevo parche que pueda ser aplicado, lo descarga, aplica, compila e instala. Tepatche mantiene una pequeña base de datos de estado para saber en que estado se encuentra cada uno de los parches del sistema.

REQUISITOS

  • Una instalación completa de OpenBSD (incluyendo el código fuente en /usr/src y los fuentes del kernel en /usr/src/sys). Tepatche fue probado con OpenBSD versión 3.1, pero mientras se diseñaba, los parches para el 2.9 y 3.0 también fueron estudiados y, como el formato es el mismo, deben de funcionar. Es importante mencionar que la versión 2.9 y versiones mas viejas ya NO SON MANTENIDAS, no hay nuevos parches que sean liberados para ellos. Es importante que se haga una actualización en caso de que estes corriendo una versión vieja.
  • Tepatche usa el módulo de Perl Net::FTP. Puedes instalarlo desde los ports (p5-libnet) ó desde CPAN. Tepatche fue diseñado y probado con p5-libnet-1.0901, la versión de los puertos 3.1.

NOTAS

  • Tepatche esta liberado bajo la licencia BSD - Leer el archivo COPYING
  • Este es código EXPERIMENTAL. A mi me funciona. Sin embargo, es código hecho para ser corrido como root y para modificar binarios vitales del sistema, y un error de programación puede llevar a consecuencias desastrosas.
  • Tepatche asume que los parches publicados en el ftphost especificado son confiables. Si el ftphost (normalmente ftp.openbsd.org o uno de sus espejos) fueran comprometidos, cualquier cosa pudiera pasar. Si Tepatche instala un parche comprometido, puees revertirlo con la opción de parche -R (ver man patch(1)). Hay que notar que Tepatche no correrá cualquier comando que encuentre en un parche, solo los que reconozca... pero hay mucho espacio ahí.
  • Si el aplicar un parche requiere una compilación del kernel, el administrador del sistema DEBE HACERLO MANUALMENTE. Tepatche parchará los fuentes, pero compilar el kernel involucra muchos pasos que requieren que se opere manualmente.
  • Tepatche SOLAMENTE parchará el sistema base - Si usas ports extra, estos NO serán parchados. Por favor véase las notas referentes a los ports y a la auditoría de seguridad en: http://www.openbsd.org/ports.html

USO

Tepatche consiste en un archivo de programa (/usr/local/sbin/tepatche), un archivo de configuración (/etc/tepatche.conf) y un directorio de datos (/var/db/tepatche). El archivo de configuración contiene los siguientes campos:

  • ftphost: Servidor FTP a conectarse (ej: ftp.openbsd.org)
  • ftpdir: La base del directorio FTP para los parches (ej: /pub/OpenBSD/patches/3.1)
  • ftppasv: Donde el modo pasivo FTP es requerido (1) o no (0)
  • ftplogin: usuario y password para ingresar (separado por una coma, ej: anonymous, gwolf@gwolf.cx)
  • archs: Lista separada por comas de arquitecturas a descargar (ej: i386, common) Por favor, recuerda incluir common!
  • patchdir: Donde los parches serán almacenados en nuestra computadora (ej: /var/db/tepatche)
  • statusfile: Localización del archivo de estado (ej: /var/db/tepatche/statusfile)

Con este archivo en su lugar, Tepatche corre simplemente sin argumentos, solo /usr/local/sbin/tepatche. Sugiero que lo corras desde tu crontab (ver man crontab(5)). Sugiero correrlo una vez al día, cuando mucho una vez por cada hora - por favor no inundes ftp.openbsd.org con peticiones cada minuto ;-)

ARCHIVO DE ESTADO

Tepatche mantiene la información que necesita acerca del estado del sistema en el 'statusfile' (por default, en /var/db/tepatche/statusfile). Este es un archivo de texto plano con el siguiente formato:
<descriptor>::<status>
Donde 'descriptor' es una cadena alfanumérica, y 'status' es un número de estado válido. Los números válidos son:

  • 1: nuevo - El parche acaba de ser bajado.
  • 2: aplicado - El parche ya fue aplicado al árbol de fuentes
  • 3: construído - Los binarios relevantes ya fueron generados en el árbol fuente
  • 4: instalado - Los binarios fueron ya instalados en su lugar. El parche ya fue completamente instalado.
  • 5: kernel - El parche requiere recompilar el kernel. Cuando tepatche llega a este estado, el parche fue aplicado, pero aún no ha sido construído..
  • 10: error - Ocurrió un error en algún punto del proceso de parche

El descriptor usualmente llevará el formato <arch>/<num>_<description>.patch - Indica la arquitectura para la cual fue creado, el número consecutivo de parche, una muy corta descripción acerca de su función, y el sufijo '.patch'. Esta es la nomenclatura estándar que sigue el equipo de Open:BSD. Un nombre ejemplo podría ser:
common/001_sshafs.patch
Esto indica que el parche será aplicado a todas las arquitecturas (common), que es el primer parche producido para esta versión del sistema (001), y que corrige problemas relacionados con 'sshafs'.
Si quieres modificar este archivo (claro está, BAJO TU PROPIO RIESGO), puedes seguir estas convenciones para indicar a Tepatche el nuevo estado del parche. Por ejemplo, en la versión 3.1 de OpenBSD apareció un bug muy peligroso en OpenSSH. El equipo de OpenBSD sugirió actualizar de inmediato a OpenSSH 3.4. Posteriormente, para la gente que no actualizó, publicaron un parche (common/006_sshpreauth.patch). Mucha gente ya instaló el árbol de 3.4, con lo que modificaron manualmente el directorio /usr/src/usr.bin/ssh lo cual hace necesario editar /var/db/tepatche/statusfile y reemplazar
common/006_sshpreauth.patch::10
por
common/006_sshpreauth.patch::4

POR HACER

Al menos:

  • Hacer la salida mas amigable (a medio-hacer)
  • Manejo mas confiable de errores (a medio-hacer)
  • (tal vez) incluir un mecanismo de compilación del kernel
  • Probar, probar, probar

DESCARGAS

Puedes obtener Tepatche (actualmente version 0.85) Justo aqui.
Si te interesa leer el artículo publicado en la edición de diciembre del 2003 de SysAdmin, aquí lo tienes.

¿POR QUE TEPATCHE?

Tepatche es una bebida ligeramente alcohólica en México, en donde yo vivo y donde el programa fué concebido. Tepache es el resultado de
fermentar piña en agua. Tomado de http://www.fao.org/docrep/x0560e/x0560e09.htm :
Tepache es una bebida ligera, refrescante preparada y consumida en todo México. En el pasado, el tepache era preparado con maíz, pero en la actualidad varias frutas como la piña, manzana y naranja son usados. La pulpa y el jugo de la fruta son puestos a fermentar por uno o dos días en agua con algo de azucar morena. La mezcla es puesta en barriles de madera sin tapa llamados "tepacheras", que se cubren con trapos queseros. Después de uno o dos días, el tepache es una dulce y refrescante bebida. Si se deja fermentar por mas tiempo, se convierte en una bebida alcohólica y después en vinagre. Los microorganismos asociados con el producto incluyen al Bacilo Sutbtilis, Torulopsis insconspicna, Saccharomyces cerevisiae y Candida queretana (Aidoo, 1986).
Si eres curioso, puedes encontrar recetas de como preparar tepache (en español) en http://www.chi.itesm.mx/chihuahua/arte_cultura/cocina/bebidas/tepache.html o http://mexico.udg.mx/cocina/bebidas/tepache.html

AGRADECIMIENTOS

Primero y sobre todo, quiero agradecer al equipo de OpenBSD por la increíble cantidad de trabajo que hay puesto en este proyecto.
En menor escala, Tepatche no hubiera sido posible sin la ayuda de OpenBSD México. En este proyecto específico, recibí una gran ayuda de Alex Juárez, César Yáñez y Karl Heinz Holtschmit.
Por supuesto, quiero agradecer a mi lugar de trabajo, UNAM FES Iztacala, por permitirme en trabajar en seguridad y software libre por casi 3 años - Y espero sean muchos mas.

Syndicate content