pornoHARDWARE.comhttps://pornohardware.com/2021-02-27T03:54:02+01:00El blog de un administrador de sistemas, friki, programador, padre y alienígena a partes iguales.Unifica el estilo del código de un proyecto con Editorconfig2021-02-27T03:54:02+01:002021-02-27T03:54:02+01:00BhEaNtag:pornohardware.com,2021-02-27:/2021/02/27/unifica-el-estilo-del-codigo-de-un-proyecto-con-editorconfig/<p>Dicen que en la variedad está el gusto. Y efectivamente, siempre es mejor tener muchas opciones para poder elegir entre
ellas la que más nos guste. Pero cuando por <em>variedad</em> no nos referimos a los sabores de un helado sino a que en un
mismo proyecto tenemos gente que usa un editor de código que finaliza los archivos con una nueva linea mientras que
otros usan otro editor que no, unos indentan los archivos con espacios y otros con tabuladores, unos tienen el tamaño máximo
de cada línea de 80 carácteres y otros de 120... al final acabamos con un popurrí de estilos que en el mejor de los
casos hará que las revisiones de código sean un infierno y que haya cambios en el código cuya aprobación dependerá
subjetivamente de la persona que esté revisándolos en ese momento. La variedad ahora ya no está tan bien, ¿verdad?</p>
<p>Dicen que en la variedad está el gusto. Y efectivamente, siempre es mejor tener muchas opciones para poder elegir entre
ellas la que más nos guste. Pero cuando por <em>variedad</em> no nos referimos a los sabores de un helado sino a que en un
mismo proyecto tenemos gente que usa un editor de código que finaliza los archivos con una nueva linea mientras que
otros usan otro editor que no, unos indentan los archivos con espacios y otros con tabuladores, unos tienen el tamaño máximo
de cada línea de 80 carácteres y otros de 120... al final acabamos con un popurrí de estilos que en el mejor de los
casos hará que las revisiones de código sean un infierno y que haya cambios en el código cuya aprobación dependerá
subjetivamente de la persona que esté revisándolos en ese momento. La variedad ahora ya no está tan bien, ¿verdad?</p>
<p>Por suerte, para intentar solucionar estos problemas de <em>convivencia</em> entre los integrantes de un equipo existen
herramientas (o mejor dicho, <em>convenciones</em> o <em>acuerdos</em>) como <a href="https://editorconfig.org/">Editorconfig</a>, los cuales
permiten definir una serie de configuraciones para que independientemente de la persona (o del editor de código que
ésta utilice) el <em>estilo</em> del proyecto sea siempre el mismo.</p>
<p>Vamos a ver en qué consiste:</p>
<ol>
<li><a href="#whatis">¿Qué es Editorconfig?</a></li>
<li><a href="#config">Configuración</a></li>
<li><a href="#refs">Referencias</a></li>
</ol>
<h2>¿Qué es Editorconfig?<a name="whatis"></a></h2>
<p><a href="https://editorconfig.org/">Editorconfig</a> es una especificación que intenta definir una serie de configuraciones acerca
del estilo de un proyecto de forma que cualquier persona que participe en él pueda hacerlo siguiendo las reglas
definidas.</p>
<p>Por ejemplo, hay personas que utilizan espacios en blanco para <em>indentar</em> el código, sin embargo otras prefieren
utilizar tabuladores. Si en un proyecto cuyos archivos están <em>indentados</em> con espacios llega una persona y modifica uno
de esos archivos para implementar una nueva funcionalidad o corregir algún bug, debería respetar el estilo del proyecto
y continuar utilizando espacios en blanco para indentar el código. Pero a veces esto no es así debido a las preferencias
personales de cada uno, o incluso aunque esa persona no lo haga a propósito, si el IDE que utiliza está configurado para
usar tabuladores, estará añadiendo <em>su parte</em> de código utilizando estos tabuladores en lugar de espacios en blanco como
en el resto del proyecto.</p>
<p>Si definimos todas estas reglas de estilo utilizando la especificación de <a href="https://editorconfig.org/">Editorconfig</a>
dará igual que cada uno tenga unas preferencias personales distintas o que cada IDE tenga una configuración por defecto
diferente, ya que al abrir el proyecto todos los IDEs sabrán que deben usar espacios en blanco para indentar el código.</p>
<p>Existen multitud de editores de código e IDEs compatibles con <a href="https://editorconfig.org/">Editorconfig</a>, ya sea de forma
nativa (como por ejemplo el maravilloso <a href="https://www.jetbrains.com/idea/">IntelliJ IDEA</a> o esa guarrería de
<a href="https://visualstudio.microsoft.com/">Visual Studio</a> que utilizáis algunos) o por medio de plugins (como el
maravilloso <a href="https://www.vim.org/">VIM</a>, <a href="https://www.sublimetext.com/">Sublime</a> o esa guarrería
de <a href="https://www.gnu.org/software/emacs/">Emacs</a> que solo gente con 6 dedos en cada mano puede utilizar).</p>
<p>Basta con definir estas reglas en un archivo llamado <code>.editorconfig</code> en la raíz de nuestro proyecto para que cualquier
editor de código o IDE compatible entienda qué reglas de estilo debe utilizar.</p>
<h2>Configuración<a name="config"></a></h2>
<p>La configuración no podría ser más sencilla. Como he comentado antes, basta con añadir a la raíz de nuestro proyecto un
archivo de texto plano llamado <code>.editorconfig</code> con la configuración de reglas que queramos definir.</p>
<p>Realmente el archivo <code>.editorconfig</code> podría estar en cualquier directorio de nuestro proyecto, ya que al abrir un
archivo, los IDEs compatibles buscarán este archivo en el mismo directorio en el que se encuentre el archivo que
acabamos de abrir y en caso de no encontrarlo ahí, buscaría en el directorio padre, y así sucesivamente hasta que o
bien encuentre un archivo <code>.editorconfig</code> con una directiva especial que le haga dejar de buscar o bien llegue al
directorio raíz del disco.</p>
<p>Supongo que en alguna extraña circunstancia (aunque realmente no se me ocurre cual) podría darse el caso en el que
queramos tener una configuración de reglas de estilo definidas para nuestro proyecto, pero que en uno de los
subdirectorios del proyecto quisiéramos tener una configuración diferente. En ese caso sí que podría tener sentido tener
diferentes archivos <code>.editorconfig</code>, pero para el 99% de los casos es suficiente (y recomendable) tener únicamente un
archivo <code>.editorconfig</code> en la raíz del proyecto.</p>
<p>Un ejemplo de uno de estos archivos sería algo así:</p>
<div class="highlight"><pre><span></span><code><span class="c1"># EditorConfig is awesome: https://EditorConfig.org</span>
<span class="na">root</span> <span class="o">=</span> <span class="s">true</span>
<span class="k">[*]</span>
<span class="na">charset</span> <span class="o">=</span> <span class="s">utf-8</span>
<span class="na">end_of_line</span> <span class="o">=</span> <span class="s">LF</span>
<span class="na">insert_final_newline</span> <span class="o">=</span> <span class="s">true</span>
<span class="na">trim_trailing_whitespace</span> <span class="o">=</span> <span class="s">true</span>
<span class="na">indent_style</span> <span class="o">=</span> <span class="s">space</span>
<span class="na">indent_size</span> <span class="o">=</span> <span class="s">4</span>
<span class="na">max_line_length</span> <span class="o">=</span> <span class="s">120</span>
<span class="k">[*.{yml,yaml,yml.j2,yaml.j2}]</span>
<span class="na">indent_size</span> <span class="o">=</span> <span class="s">2</span>
<span class="k">[*.md]</span>
<span class="na">max_line_length</span> <span class="o">=</span> <span class="s">140</span>
<span class="na">trim_trailing_whitespace</span> <span class="o">=</span> <span class="s">false</span>
<span class="k">[Makefile]</span>
<span class="na">indent_style</span> <span class="o">=</span> <span class="s">tab</span>
</code></pre></div>
<p>Como podéis ver, se trata de un <a href="https://es.wikipedia.org/wiki/INI_(extensi%C3%B3n_de_archivo)">archivo INI </a> en el que
se definen configuraciones generales y configuraciones específicas según el nombre o extensión de determinados archivos.</p>
<p>Según este archivo de ejemplo, el proyecto tendría definidas unas configuraciones generales (las que están bajo el
bloque <code>[*]</code>) y otras específicas para algunos archivos determinados que redefinirían algunas de esas configuraciones
generales (las que están bajo los bloques <code>[*.{yml,yaml,yml.j2,yaml.j2}]</code>, <code>[*.md]</code> y <code>[Makefile]</code>).</p>
<p>Por ejemplo, de forma general para todo el proyecto (bloque <code>[*]</code>) tenemos definido entre otras cosas que la indentación se debe hacer con
espacios en blanco (<code>indent_style = space</code>) y que el tamaño máximo de linea debe ser de 120
carácteres (<code>max_line_length = 120</code>). Sin embargo, los archivos <a href="https://es.wikipedia.org/wiki/Markdown">Markdown</a>
(aquellos con extensión <code>.md</code>) tendrán un tamaño máximo de linea de 140 carácteres (<code>max_line_length = 140</code>) y en los
archivos <code>Makefile</code> se deberá utilizar tabuladores para indentar el código (<code>indent_style = tab</code>).</p>
<p>Para definir los archivos sobre los que aplicarán las configuraciones se puede simplemente poner el nombre del archivo
(como en el ejemplo anterior, en el bloque <code>Makefile</code>) o utilizar algunos de los <em>comodines</em> compatibles. Estos
comodines son los siguientes:</p>
<table>
<thead>
<tr>
<th align="left">Comodín</th>
<th align="left">Descripción</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">*</td>
<td align="left">Equivale a cualquier carácter (o conjunto de carácteres) excepto a <code>/</code>, por lo que no se puede utilizar para indicar un path.</td>
</tr>
<tr>
<td align="left">**</td>
<td align="left">Equivale a cualquier carácter (o conjunto de carácteres).</td>
</tr>
<tr>
<td align="left">?</td>
<td align="left">Equivale a cualquier carácter (solo a uno).</td>
</tr>
<tr>
<td align="left">[nombre]</td>
<td align="left">Equivale al nombre especificado.</td>
</tr>
<tr>
<td align="left">[!nombre]</td>
<td align="left">Equivale a cualquier nombre excepto al especificado.</td>
</tr>
<tr>
<td align="left">{s1, s2, s3}</td>
<td align="left">Equivale a cualquiera de los carácteres especificados.</td>
</tr>
<tr>
<td align="left">{num1..num2}</td>
<td align="left">Equivale a cualquier número entero entre <em>num1</em> y <em>num2</em> (pueden ser positivos o negativos).</td>
</tr>
</tbody>
</table>
<blockquote>
<p>Se puede usar la barra invertida (<code>\</code>) para escapar cualquiera de éstos carácteres y evitar así que sean interpretados como comodines.</p>
</blockquote>
<p>Si te has fijado bien en el archivo que he puesto de ejemplo quizás te hayas dado cuenta de 2 cosas:</p>
<p>La primera es que se pueden escribir comentarios utilizando el símbolo <code>#</code>. Cualquier línea que empiece por ese carácter
será ignorada al <em>parsear</em> el archivo.</p>
<p>Y la segunda es que hay una directiva que no está dentro de ningún bloque: <code>root = true</code>.</p>
<p>Al principio del artículo comenté que en un mismo proyecto se podían tener tantos archivos <code>.editorconfig</code> como
quisiéramos y que al abrir uno de los archivos de nuestro proyecto, el IDE primero intentaría leer el <code>.editorconfig</code>
que hubiera en el mismo directorio donde estuviera el archivo que estamos abriendo, y después intentaría leer el
archivo <code>.editorconfig</code> que hubiera en el directorio padre, y así iría subiendo en el árbol de directorios sucesivamente
hasta llegar o bien al directorio raíz de nuestro disco o bien hasta que se encuentre con un archivo <code>.editorconfig</code> que
tenga ésta directiva configurada a <code>true</code>.</p>
<p>Por lo tanto, dado que mi recomendación es que únicamente tengáis un archivo <code>.editorconfig</code> en el directorio raíz de
vuestro proyecto, este archivo debería tener siempre la directiva <code>root = true</code> para evitar que el IDE continue buscando
archivos <code>.editorconfig</code> fuera de vuestro proyecto.</p>
<p>Con respecto a las diferentes directivas de configuración que podemos utilizar en dichos archivos, éstas son todas las
que existen actualmente (los valores alfanuméricos NO son sensibles a mayúsculas/minúsculas, aunque la recomendación es
utilizar siempre minúsculas):</p>
<ul>
<li>
<p><strong>indent_style</strong>: Se utiliza para especificar si queremos indentar el código usando espacios o tabuladores. Sus
posibles valores son <code>space</code> o <code>tab</code> respectivamente.</p>
</li>
<li>
<p><strong>indent_size</strong>: Aquí podemos indicar el número de carácteres que se usarán en cada indentación. Por ejemplo, si en <strong>indent_style</strong> hemos
especificado indentar el código con espacios, cada vez que indentemos el código un nivel se
usarán tantos espacios como hayamos configurado aquí. Lo normal suelen ser <code>2</code> o <code>4</code>, pero por supuesto puedes usar
tantos como quieras. </p>
<p>Si en lugar de poner un valor numérico como <code>2</code> o <code>4</code>, pones el valor <code>tab</code>, el valor de <strong>indent_size</strong> será el que
hayamos definido en <strong>tab_width</strong> (y en caso de no tener definido ningún valor en <strong>tab_width</strong> se usará el valor que
tenga configurado el editor que estemos utilizando).</p>
</li>
<li>
<p><strong>tab_width</strong>: Especifica el tamaño de un tabulador.</p>
</li>
<li>
<p><strong>end_of_line</strong>: Indica el formato que hay que utilizar para indicar el final de linea (también llamado <em>retorno de
carro</em>, en referencia a su origen en las antiguas máquinas de escribir). Sus posibles valores son:</p>
<ul>
<li><code>lf</code>: Normalmente utilizado por Linux.</li>
<li><code>crlf</code>: Normalmente utilizado por Windows.</li>
<li><code>cr</code>: Normalmente utilizado por MacOS.</li>
</ul>
<p>Según la propia documentación de
<a href="https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties#end_of_line">Editorconfig</a>, tienen pensado
añadir un nuevo valor aparte de los 3 anteriores llamado <code>native</code> para dejar que sea el propio programa de gestión de
versiones que usemos (<a href="https://git-scm.com/">git</a> o similar) quien se encargue de utilizar un final de línea u otro
dependiendo del sistema operativo que estemos utilizando. Pero mientras implementan este nuevo valor, si quieres que
sea el control de versiones quien se encargue, <strong>no</strong> definas este valor en tu <code>.editorconfig</code>.</p>
</li>
<li>
<p><strong>charset</strong>: Especifica el juego de carácteres (encoding) que queremos utilizar en nuestros archivos. Sus posibles
valores pueden ser <code>utf-8</code>, <code>latin1</code>, etc.</p>
</li>
<li>
<p><strong>trim_trailing_whitespace</strong>: Este valor nos permite indicar si queremos eliminar aquellos espacios en blanco que haya
al final de una linea. Si lo establecemos a <code>true</code> los espacios en blanco que pudiera haber al final de cualquier
línea serán eliminados, y con <code>false</code> obviamente NO se eliminarán.</p>
</li>
<li>
<p><strong>insert_final_newline</strong>: Si establecemos este valor a <code>true</code> el editor de código que estemos utilizando intentará
dejar una linea en blanco al final de cada archivo. En caso contrario (<code>false</code>) los archivos terminarán inmediatamente
después del último carácter de la última linea que haya en el archivo.</p>
</li>
<li>
<p><strong>max_line_length</strong>: Especifica el tamaño máximo que podrán tener las líneas en los archivos que abramos con nuestro
editor de código. La idea es no tener líneas muy largas que obliguen a hacer <em>scroll horizontal</em> y que permitan leer
el código de forma mucho más cómoda. Esta directiva NO es compatible con todos los editores compatibles con
Editorconfig, por lo que si utilizas un editor de código <em>un poco raro</em> quizás no haga caso a esta propiedad aunque la
tengas definida en tu <code>.editorconfig</code>.</p>
</li>
</ul>
<p>Este es el ejemplo completo del archivo <code>.editorconfig</code> que suelo utilizar en todos mis proyectos, por si te sirve de
ayuda a la hora de hacerte una idea antes de escribir el tuyo (o si simplemente quieres cogerlo y usarlo tal cual en
tus proyectos):</p>
<div class="highlight"><pre><span></span><code><span class="c1"># EditorConfig is awesome: https://EditorConfig.org</span>
<span class="c1"># top-most EditorConfig file</span>
<span class="na">root</span> <span class="o">=</span> <span class="s">true</span>
<span class="c1"># Unix-style newlines with a newline ending every file</span>
<span class="k">[*]</span>
<span class="na">charset</span> <span class="o">=</span> <span class="s">utf-8</span>
<span class="na">end_of_line</span> <span class="o">=</span> <span class="s">LF</span>
<span class="na">insert_final_newline</span> <span class="o">=</span> <span class="s">true</span>
<span class="na">trim_trailing_whitespace</span> <span class="o">=</span> <span class="s">true</span>
<span class="na">indent_style</span> <span class="o">=</span> <span class="s">space</span>
<span class="na">indent_size</span> <span class="o">=</span> <span class="s">4</span>
<span class="na">max_line_length</span> <span class="o">=</span> <span class="s">120</span>
<span class="k">[*.{yml,yaml,yml.j2,yaml.j2}]</span>
<span class="na">indent_size</span> <span class="o">=</span> <span class="s">2</span>
<span class="k">[*.{json,json.j2}]</span>
<span class="na">indent_size</span> <span class="o">=</span> <span class="s">2</span>
<span class="k">[*.{tf,tfvars}]</span>
<span class="na">indent_size</span> <span class="o">=</span> <span class="s">2</span>
<span class="k">[*.md]</span>
<span class="na">max_line_length</span> <span class="o">=</span> <span class="s">140</span>
<span class="na">trim_trailing_whitespace</span> <span class="o">=</span> <span class="s">false</span>
<span class="k">[Makefile]</span>
<span class="na">indent_style</span> <span class="o">=</span> <span class="s">tab</span>
<span class="k">[*.go]</span>
<span class="na">indent_style</span> <span class="o">=</span> <span class="s">tab</span>
<span class="k">[COMMIT_EDITMSG]</span>
<span class="na">max_line_length</span> <span class="o">=</span> <span class="s">0</span>
</code></pre></div>
<p>Como habrás comprobado, <a href="https://editorconfig.org/">Editorconfig</a> es algo muy sencillo de implementar, no require la instalación de ningún software
para poder utilizarlo (a no ser que tu IDE no lo soporte de forma nativa y tengas que instalar algún plugin) y te
permitirá mantener un mismo estilo en aquellos proyectos en los que participen diferentes personas con diferentes
sistemas operativos, IDEs o preferencias personales.</p>
<p>Como siempre, espero que el artículo te haya resultado de utilidad. Y por supuesto, no dudes en distribuirlo y
compartirlo con todo el mundo (pero por favor, cita siempre la fuente original de este artículo).</p>
<p>Alaaaaaaaaaaaaaaaaaaaaaaa!</p>
<h2>Referencias<a name="refs"></a></h2>
<ul>
<li>Página oficial de Editorconfig: <a href="https://editorconfig.org">https://editorconfig.org</a></li>
<li>Repositorios de código de Editorconfig en Github: <a href="https://github.com/editorconfig">https://github.com/editorconfig</a></li>
</ul>Alta disponibilidad en etcd: Desplegando un cluster paso a paso2018-05-06T00:14:02+01:002018-05-06T00:14:02+01:00BhEaNtag:pornohardware.com,2018-05-06:/2018/05/06/alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/<p>Si estas intentando montar un <a href="https://es.wikipedia.org/wiki/Cl%C3%BAster_de_alta_disponibilidad">cluster</a> de <a href="https://kubernetes.io/">Kubernetes</a> en alta disponibilidad, o bien tienes alguna experiencia en esto porque lo has visto anteriormente o porque ya has trabajado con ello antes, o bien has llegado a este artículo buscando ayuda en Internet después de haber pasado un buen rato intentando seguir sin éxito los pasos de la incorrecta documentación oficial de <em>multi-master</em> en Kubernetes <a href="https://kubernetes.io/docs/setup/independent/high-availability/">que hay publicada al respecto</a>.</p>
<p>Bien por este motivo o bien porque quieres tener un servicio de <a href="https://coreos.com/etcd/docs/latest/">etcd</a> tolerante a fallos para tu proyecto, espero que con este artículo no te quede ninguna duda sobre cómo montar un cluster para conseguir alta disponibilidad y comunicaciones totalmente cifradas con SSL en el servicio de <em>etcd</em>.</p>
<p>Así que basta ya de hablar y vamos <em>al turrón</em>...</p>
<p>Si estas intentando montar un <a href="https://es.wikipedia.org/wiki/Cl%C3%BAster_de_alta_disponibilidad">cluster</a> de <a href="https://kubernetes.io/">Kubernetes</a> en alta disponibilidad, o bien tienes alguna experiencia en esto porque lo has visto anteriormente o porque ya has trabajado con ello antes, o bien has llegado a este artículo buscando ayuda en Internet después de haber pasado un buen rato intentando seguir sin éxito los pasos de la incorrecta documentación oficial de <em>multi-master</em> en Kubernetes <a href="https://kubernetes.io/docs/setup/independent/high-availability/">que hay publicada al respecto</a>.</p>
<p>Bien por este motivo o bien porque quieres tener un servicio de <a href="https://coreos.com/etcd/docs/latest/">etcd</a> tolerante a fallos para tu proyecto, espero que con este artículo no te quede ninguna duda sobre cómo montar un cluster para conseguir alta disponibilidad y comunicaciones totalmente cifradas con SSL en el servicio de <em>etcd</em>.</p>
<p>Así que basta ya de hablar y vamos <em>al turrón</em>...</p>
<p>Para intentar organizarlo un poco, voy a dividir el artículo en varias partes:</p>
<ol>
<li><a href="#whatis">¿Qué es etcd?</a></li>
<li><a href="#init">Consideraciones iniciales de nuestro cluster</a></li>
<li><a href="#ssl">Creación de los certificados SSL</a></li>
<li><a href="#install">Instalación y configuración del cluster</a></li>
<li><a href="#admin">Administración básica</a></li>
<li><a href="#refs">Referencias</a></li>
</ol>
<h2>¿Qué es etcd?<a name="whatis"></a></h2>
<p><a href="https://github.com/coreos/etcd">Etcd</a> es un servidor de almacenamiento de datos de tipo clave-valor (similar a <a href="https://redis.io/">Redis</a>, aunque con bastantes diferencias) diseñado para funcionar de forma distribuida, rápida y estable.</p>
<p>Forma parte del sistema <a href="https://coreos.com/">CoreOS</a>, y es un proyecto de <a href="https://es.wikipedia.org/wiki/C%C3%B3digo_abierto">código abierto</a> escrito en <a href="https://golang.org/">Go</a> y liberado bajo licencia <a href="https://github.com/coreos/etcd/blob/master/LICENSE">Apache 2.0</a>.</p>
<p>Etcd es un proyecto maduro y que lleva muchos años en desarrollo constante por lo que muchos grandes proyectos lo utilizan para almacenar sus configuraciones debido a su gran estabilidad y rapidez, pero últimamente su desarrollo se ha visto potenciado aún más sobre todo por el auge que está teniendo <a href="https://kubernetes.io/">Kubernetes</a>, que es uno de estos grandes proyectos que utilizan <em>etcd</em>.</p>
<p>Toda la comunicación con <em>etcd</em> se realiza a través de una <a href="https://es.wikipedia.org/wiki/Interfaz_de_programaci%C3%B3n_de_aplicaciones">API</a> que puede ser explotada mediante <a href="http://json.org/">JSON</a> a través de <a href="https://es.wikipedia.org/wiki/Protocolo_de_transferencia_de_hipertexto">HTTP/HTTPS</a> o a través del cliente <a href="https://github.com/coreos/etcd/tree/master/etcdctl">etcdctl</a> para linea de comandos.</p>
<p>A principios de año (enero de 2018), CoreOS (y por lo tanto <em>etcd</em>) fué comprado por <a href="https://www.redhat.com">Redhat</a>.</p>
<h2>Consideraciones iniciales de nuestro cluster<a name="init"></a></h2>
<p>Como recomendación general, para montar un cluster en alta disponibilidad debemos utilizar el mayor número posible de nodos.</p>
<p>En cualquier caso, debemos utilizar <strong>al menos 3 nodos</strong> para el cluster ya que aunque teóricamente bastaría con 2 nodos para tener tolerancia a fallos, en un cluster de <em>etcd</em> siempre debe haber un nodo <em>principal</em> (llamado <em>leader</em>) que es el que tendrá el control de determinadas funciones del cluster, y si ese nodo <em>leader</em> quedara fuera de servicio por algún motivo, los demás nodos del cluster utilizarían un <em>quórum</em> para designar quién sería el nuevo <em>leader</em>. El algoritmo que se utiliza para obtener dicho quórum es <a href="https://raft.github.io/">Raft</a>, usado no solo para este proyecto sino para muchísimos otros, por lo tanto debe haber al menos 3 nodos para que si se pierde el nodo <em>leader</em> los otros 2 puedan designar un <em>sustituto</em>.</p>
<p>Así que en este artículo vamos a crear un cluster con 3 nodos que tendrán estas características:</p>
<table>
<thead>
<tr>
<th align="left">#</th>
<th align="left">Nombre</th>
<th align="left">IP</th>
<th align="left">RAM</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">1</td>
<td align="left">etcd01</td>
<td align="left">192.168.1.83</td>
<td align="left">2 Gb</td>
</tr>
<tr>
<td align="left">2</td>
<td align="left">etcd02</td>
<td align="left">192.168.1.84</td>
<td align="left">2 Gb</td>
</tr>
<tr>
<td align="left">3</td>
<td align="left">etcd03</td>
<td align="left">192.168.1.85</td>
<td align="left">2 Gb</td>
</tr>
</tbody>
</table>
<p>Todas estas máquinas parten de una instalación limpia de mi sistema operativo favorito (<a href="https://www.debian.org">Debian</a>, concretamente la versión <em>stable</em> 9.4) pero debería funcionar prácticamente igual (con ligeros cambios en algunos <em>paths</em> o en el nombre de algún paquete) en cualquier otra distribución de Linux.</p>
<p>Antes de empezar, asegúrate de que todos estos servidores tienen conectividad entre ellos, y que resuelven los nombres de los demás. Lo mejor sería que tuvieras tu propio servidor <a href="https://es.wikipedia.org/wiki/Sistema_de_nombres_de_dominio">DNS</a> (<a href="https://www.isc.org/downloads/bind/1">bind</a> o similar) configurado en tu red para resolver todos los nombres de tus servidores, pero sino, puedes añadir las 3 direcciones IP con sus respectivos nombres al archivo <code>/etc/hosts</code> de cada uno de ellos:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">/etc/hosts</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/hosts'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="mi">127</span><span class="p">.</span><span class="mi">0</span><span class="p">.</span><span class="mi">0</span><span class="p">.</span><span class="mi">1</span> <span class="n">localhost</span>
<span class="mi">192</span><span class="p">.</span><span class="mi">168</span><span class="p">.</span><span class="mi">1</span><span class="p">.</span><span class="mi">83</span> <span class="n">etcd01</span>
<span class="mi">192</span><span class="p">.</span><span class="mi">168</span><span class="p">.</span><span class="mi">1</span><span class="p">.</span><span class="mi">84</span> <span class="n">etcd02</span>
<span class="mi">192</span><span class="p">.</span><span class="mi">168</span><span class="p">.</span><span class="mi">1</span><span class="p">.</span><span class="mi">85</span> <span class="n">etcd03</span>
<span class="o">#</span> <span class="n">The</span> <span class="n">following</span> <span class="n">lines</span> <span class="k">are</span> <span class="n">desirable</span> <span class="k">for</span> <span class="n">IPv6</span> <span class="n">capable</span> <span class="n">hosts</span>
<span class="p">::</span><span class="mi">1</span> <span class="n">localhost</span> <span class="n">ip6</span><span class="o">-</span><span class="n">localhost</span> <span class="n">ip6</span><span class="o">-</span><span class="n">loopback</span>
<span class="n">ff02</span><span class="p">::</span><span class="mi">1</span> <span class="n">ip6</span><span class="o">-</span><span class="n">allnodes</span>
<span class="n">ff02</span><span class="p">::</span><span class="mi">2</span> <span class="n">ip6</span><span class="o">-</span><span class="n">allrouters</span>
</code></pre></div>
</figure>
<p>Ni qué decir tiene que es recomendable asegurarse siempre de que partimos de un sistema actualizado:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get update
$ sudo apt-get dist-upgrade
</code></pre></div>
<p>En mi caso, las últimas versiones disponibles en el momento de escribir este artículo son (no te preocupes si alguno no te suena, los iremos viendo a medida que los vayamos necesitando):</p>
<ul>
<li>Etcd: 3.3.4</li>
<li>cfssl: 1.2</li>
<li>cfssljson: 1.2</li>
</ul>
<h2>Creación de los certificados SSL<a name="ssl"></a></h2>
<p>Como acabo de comentar, toda la comunicación tanto entre el cliente y el servidor de <em>etcd</em> como entre los propios servidores de <em>etcd</em> de un cluster puede realizarse por SSL, cifrando de esa forma todas las comunicaciones y aportando otra capa de seguridad al sistema.</p>
<p>Aunque podríamos montar el cluster utilizando únicamente HTTP, es muy sencillo generar unos certificados y configurar <em>etcd</em> para que los use, por lo que vamos a hacerlo de esta forma.</p>
<p>Lo primero que debemos hacer será generar los certificados que vamos a necesitar, que son:</p>
<ul>
<li><strong>Cliente</strong>: Este certificado es el que usaremos nosotros (o la aplicación que se vaya a conectar a <em>etcd</em>, como por ejemplo <em>Kubernetes</em>) para conectarnos al cluster.</li>
<li><strong>Servidor</strong>: Este certificado es el que usará cada uno de los nodos de nuestro cluster para cifrar las comunicaciones.</li>
<li><strong>Peer</strong> (<em>no se muy bien como traducirlo</em>): Este certificado es el que usará cada nodo para conectarse a los demás nodos del cluster (muy similar al certificado de cliente, pero generaremos ambos para diferenciar unas conexiones de otras).</li>
</ul>
<p>La explicación sobre el intercambio de certificados en una comunicación SSL, los tipos de certificados, su firma, etc. es algo que queda fuera del ámbito de este artículo por lo que no voy a explicarlo con demasiado detalle. Si alguno de estos conceptos no te queda claro, te recomiendo que investigues un poco acerca del funcionamiento de estos certificados (intentaré escribir otro artículo sobre SSL algún dia).</p>
<p>Para generar los certificados vamos a utilizar <a href="https://cfssl.org/"><code>cfssl</code></a>, que es una herramienta de código-abierto desarrollada por <a href="https://www.cloudflare.com/es/">CloudFlare</a> muy fácil de utilizar y que nos permite generar y firmar certificados desde la linea de comandos.</p>
<p>En lugar de ir nodo por nodo, vamos a instalar la herramienta en nuestra máquina local para generar los certificados, y una vez generados los copiaremos a los 3 nodos.</p>
<p>Como dije antes, en el momento de escribir este artículo la última versión de <code>cfssl</code> era la 1.2, por lo que os recomiendo que antes de instalarla comprobéis en su página (<a href="https://pkg.cfssl.org/">https://pkg.cfssl.org/</a>) que no haya ninguna versión más reciente, y en caso de haberla, cambiad las siguientes URLs según corresponda para poder instalar la aplicación actualizada:</p>
<div class="highlight"><pre><span></span><code>$ sudo curl -o /usr/local/bin/cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
$ sudo curl -o /usr/local/bin/cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
$ sudo chmod +x /usr/local/bin/cfssl*
</code></pre></div>
<p>Creamos un directorio en cualquier parte de nuestro disco duro (y nos situamos en él) para ir guardando los certificados de forma temporal hasta que los hayamos copiado a los nodos de nuestro cluster:</p>
<div class="highlight"><pre><span></span><code>$ mkdir <span class="nv">$HOME</span>/etcd-certs
$ <span class="nb">cd</span> <span class="nv">$HOME</span>/etcd-certs
</code></pre></div>
<p>Y ahora vamos creando los certificados necesarios:</p>
<h3>Certificado de la Autoridad de Certificación (CA)</h3>
<p>Primero, crearemos un archivo <code>JSON</code> llamado <code>ca-config.json</code> con la configuración de la <a href="https://es.wikipedia.org/wiki/Autoridad_de_certificaci%C3%B3n"><em>Autoridad de Certificación (CA)</em></a> que va a firmar los certificados que vamos a generar.</p>
<p>En él definiremos la expiración de los certificados, el uso que les vamos a dar (autenticación, firma, ...), etc:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">ca-config.json</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/ca-config.json'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">"signing"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"default"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"expiry"</span><span class="p">:</span><span class="s2">"43800h"</span>
<span class="p">},</span>
<span class="nt">"profiles"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"server"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"expiry"</span><span class="p">:</span><span class="s2">"43800h"</span><span class="p">,</span>
<span class="nt">"usages"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"signing"</span><span class="p">,</span>
<span class="s2">"key encipherment"</span><span class="p">,</span>
<span class="s2">"server auth"</span><span class="p">,</span>
<span class="s2">"client auth"</span>
<span class="p">]</span>
<span class="p">},</span>
<span class="nt">"client"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"expiry"</span><span class="p">:</span><span class="s2">"43800h"</span><span class="p">,</span>
<span class="nt">"usages"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"signing"</span><span class="p">,</span>
<span class="s2">"key encipherment"</span><span class="p">,</span>
<span class="s2">"client auth"</span>
<span class="p">]</span>
<span class="p">},</span>
<span class="nt">"peer"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"expiry"</span><span class="p">:</span><span class="s2">"43800h"</span><span class="p">,</span>
<span class="nt">"usages"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"signing"</span><span class="p">,</span>
<span class="s2">"key encipherment"</span><span class="p">,</span>
<span class="s2">"server auth"</span><span class="p">,</span>
<span class="s2">"client auth"</span>
<span class="p">]</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Después crearemos otro archivo llamado <code>ca-csr.json</code> donde irá la configuración de la <a href="https://es.wikipedia.org/wiki/Autoridad_de_certificaci%C3%B3n#Solicitud_de_un_certificado"><em>solicitud de certificación (CSR)</em></a>, donde indicaremos el algoritmo de cifrado que queremos utilizar, la longitud de la clave, los datos del certificado, etc:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">ca-csr.json</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/ca-csr.json'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">"CN"</span><span class="p">:</span><span class="s2">"etcd"</span><span class="p">,</span>
<span class="nt">"key"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"algo"</span><span class="p">:</span><span class="s2">"rsa"</span><span class="p">,</span>
<span class="nt">"size"</span><span class="p">:</span><span class="mi">2048</span>
<span class="p">},</span>
<span class="nt">"names"</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span>
<span class="nt">"C"</span><span class="p">:</span><span class="s2">"ES"</span><span class="p">,</span>
<span class="nt">"L"</span><span class="p">:</span><span class="s2">"Madrid"</span><span class="p">,</span>
<span class="nt">"O"</span><span class="p">:</span><span class="s2">"PornoHardware S.L.U."</span><span class="p">,</span>
<span class="nt">"OU"</span><span class="p">:</span><span class="s2">"Tech department"</span><span class="p">,</span>
<span class="nt">"ST"</span><span class="p">:</span><span class="s2">"Spain"</span>
<span class="p">}</span>
<span class="p">]</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Generamos los certificados de nuestra <em>Autoridad de Certificación</em>:</p>
<div class="highlight"><pre><span></span><code>$ cfssl gencert -initca ca-csr.json <span class="p">|</span> cfssljson -bare ca -
</code></pre></div>
<p>Una vez ejecutado el comando habremos obtenido 3 nuevos archivos:</p>
<ul>
<li><code>ca.csr</code>: La <em>petición</em> de generación de certificado.</li>
<li><code>ca.pem</code>: El certificado <em>raíz</em>.</li>
<li><code>ca-key.pem</code>: La <em>clave</em> del certificado <em>raíz</em>.</li>
</ul>
<p>Ya tenemos nuestro certificado <em>raíz</em>, vamos a seguir con los demas...</p>
<h3>Certificado de cliente</h3>
<p>Este certificado es el que usaremos nosotros mismos para conectarnos al cluster y lanzar los comandos que queramos ejecutar de forma segura.</p>
<p>Creamos el archivo <code>client.json</code>:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">client.json</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/client.json'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">"CN"</span><span class="p">:</span> <span class="s2">"client"</span><span class="p">,</span>
<span class="nt">"key"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"algo"</span><span class="p">:</span> <span class="s2">"ecdsa"</span><span class="p">,</span>
<span class="nt">"size"</span><span class="p">:</span> <span class="mi">256</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Y utilizando el recién creado certificado <em>raíz</em> y la configuración que habíamos definido al principio, generamos el certificado de cliente:</p>
<div class="highlight"><pre><span></span><code>$ cfssl gencert -ca<span class="o">=</span>ca.pem -ca-key<span class="o">=</span>ca-key.pem -config<span class="o">=</span>ca-config.json -profile<span class="o">=</span>client client.json <span class="p">|</span> cfssljson -bare client
</code></pre></div>
<p>Una vez ejecutado el comando habremos obtenido 3 nuevos archivos:</p>
<ul>
<li><code>client.csr</code>: La <em>petición</em> de generación de certificado.</li>
<li><code>client.pem</code>: El certificado de cliente.</li>
<li><code>client-key.pem</code>: La <em>clave</em> del certificado de cliente.</li>
</ul>
<h3>Certificados <em>peer</em> y de servidor</h3>
<p>Cada uno de los nodos necesita también un certificado para cifrar las conexiones que los demás nodos se hagan entre si (peer). Este certificado necesita generarse para un nombre de host y una IP en concreto (la de cada servidor), por lo tanto necesitamos generar 3 certificados diferentes (uno para cada nodo de nuestro cluster).</p>
<p>Creamos <strong>un archivo de configuración por cada nodo</strong>, donde indicaremos el nombre del servidor y su IP, entre otras cosas:</p>
<p>Para el nodo 1:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">config-etcd01.json</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/config-etcd01.json'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">"CN"</span><span class="p">:</span> <span class="s2">"etcd01"</span><span class="p">,</span>
<span class="nt">"hosts"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"etcd01"</span><span class="p">,</span>
<span class="s2">"etcd01.local"</span><span class="p">,</span>
<span class="s2">"192.168.1.83"</span>
<span class="p">],</span>
<span class="nt">"key"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"algo"</span><span class="p">:</span> <span class="s2">"ecdsa"</span><span class="p">,</span>
<span class="nt">"size"</span><span class="p">:</span> <span class="mi">256</span>
<span class="p">},</span>
<span class="nt">"names"</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span>
<span class="nt">"C"</span><span class="p">:</span> <span class="s2">"ES"</span><span class="p">,</span>
<span class="nt">"L"</span><span class="p">:</span> <span class="s2">"Madrid"</span><span class="p">,</span>
<span class="nt">"ST"</span><span class="p">:</span> <span class="s2">"Spain"</span>
<span class="p">}</span>
<span class="p">]</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Para el nodo 2:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">config-etcd02.json</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/config-etcd02.json'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">"CN"</span><span class="p">:</span> <span class="s2">"etcd02"</span><span class="p">,</span>
<span class="nt">"hosts"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"etcd02"</span><span class="p">,</span>
<span class="s2">"etcd02.local"</span><span class="p">,</span>
<span class="s2">"192.168.1.84"</span>
<span class="p">],</span>
<span class="nt">"key"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"algo"</span><span class="p">:</span> <span class="s2">"ecdsa"</span><span class="p">,</span>
<span class="nt">"size"</span><span class="p">:</span> <span class="mi">256</span>
<span class="p">},</span>
<span class="nt">"names"</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span>
<span class="nt">"C"</span><span class="p">:</span> <span class="s2">"ES"</span><span class="p">,</span>
<span class="nt">"L"</span><span class="p">:</span> <span class="s2">"Madrid"</span><span class="p">,</span>
<span class="nt">"ST"</span><span class="p">:</span> <span class="s2">"Spain"</span>
<span class="p">}</span>
<span class="p">]</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Para el nodo 3:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">config-etcd03.json</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/config-etcd03.json'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">"CN"</span><span class="p">:</span> <span class="s2">"etcd03"</span><span class="p">,</span>
<span class="nt">"hosts"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"etcd03"</span><span class="p">,</span>
<span class="s2">"etcd03.local"</span><span class="p">,</span>
<span class="s2">"192.168.1.85"</span>
<span class="p">],</span>
<span class="nt">"key"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"algo"</span><span class="p">:</span> <span class="s2">"ecdsa"</span><span class="p">,</span>
<span class="nt">"size"</span><span class="p">:</span> <span class="mi">256</span>
<span class="p">},</span>
<span class="nt">"names"</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span>
<span class="nt">"C"</span><span class="p">:</span> <span class="s2">"ES"</span><span class="p">,</span>
<span class="nt">"L"</span><span class="p">:</span> <span class="s2">"Madrid"</span><span class="p">,</span>
<span class="nt">"ST"</span><span class="p">:</span> <span class="s2">"Spain"</span>
<span class="p">}</span>
<span class="p">]</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Como todos los certificados que vamos a generar tendrán el mismo nombre (<code>server.pem</code>, <code>server-key.pem</code>, ...) independientemente del nodo al que correspondan, vamos a crear un subdirectorio por cada nodo y a generar los certificados de cada uno de ellos en su respectivo directorio.</p>
<p>Creamos el subdirectorio, entramos en él, generamos los certificados (tanto los de servidor como los <em>peer</em>) y continuamos con el siguiente sucesivamente hasta que hayamos generado los certificados de los 3 servidores:</p>
<div class="highlight"><pre><span></span><code>$ mkdir <span class="nv">$HOME</span>/etcd-certs/etcd01
$ <span class="nb">cd</span> <span class="nv">$HOME</span>/etcd-certs/etcd01
$ cfssl gencert -ca<span class="o">=</span>../ca.pem -ca-key<span class="o">=</span>../ca-key.pem -config<span class="o">=</span>../ca-config.json -profile<span class="o">=</span>server ../config-etcd01.json <span class="p">|</span> cfssljson -bare server
$ cfssl gencert -ca<span class="o">=</span>../ca.pem -ca-key<span class="o">=</span>../ca-key.pem -config<span class="o">=</span>../ca-config.json -profile<span class="o">=</span>peer ../config-etcd01.json <span class="p">|</span> cfssljson -bare peer
$ mkdir <span class="nv">$HOME</span>/etcd-certs/etcd02
$ <span class="nb">cd</span> <span class="nv">$HOME</span>/etcd-certs/etcd02
$ cfssl gencert -ca<span class="o">=</span>../ca.pem -ca-key<span class="o">=</span>../ca-key.pem -config<span class="o">=</span>../ca-config.json -profile<span class="o">=</span>server ../config-etcd02.json <span class="p">|</span> cfssljson -bare server
$ cfssl gencert -ca<span class="o">=</span>../ca.pem -ca-key<span class="o">=</span>../ca-key.pem -config<span class="o">=</span>../ca-config.json -profile<span class="o">=</span>peer ../config-etcd02.json <span class="p">|</span> cfssljson -bare peer
$ mkdir <span class="nv">$HOME</span>/etcd-certs/etcd03
$ <span class="nb">cd</span> <span class="nv">$HOME</span>/etcd-certs/etcd03
$ cfssl gencert -ca<span class="o">=</span>../ca.pem -ca-key<span class="o">=</span>../ca-key.pem -config<span class="o">=</span>../ca-config.json -profile<span class="o">=</span>server ../config-etcd03.json <span class="p">|</span> cfssljson -bare server
$ cfssl gencert -ca<span class="o">=</span>../ca.pem -ca-key<span class="o">=</span>../ca-key.pem -config<span class="o">=</span>../ca-config.json -profile<span class="o">=</span>peer ../config-etcd03.json <span class="p">|</span> cfssljson -bare peer
</code></pre></div>
<p>Una vez ejecutados todos los comandos habremos obtenido 6 nuevos archivos en cada subdirectorio:</p>
<ul>
<li><code>peer.csr</code>: La <em>petición</em> de generación de certificado.</li>
<li><code>peer.pem</code>: El certificado <em>peer</em>.</li>
<li><code>peer-key.pem</code>: La <em>clave</em> del certificado <em>peer</em>.</li>
<li><code>server.csr</code>: La <em>petición</em> de generación de certificado.</li>
<li><code>server.pem</code>: El certificado de servidor.</li>
<li><code>server-key.pem</code>: La <em>clave</em> del certificado de servidor.</li>
</ul>
<p>Si todo ha ido bien, ahora deberíamos tener todos los certificados necesarios para nuestro cluster generados en <code>$HOME/etcd-certs/</code>, por lo que deberíamos tener algo parecido a ésto:</p>
<div class="highlight"><pre><span></span><code><span class="err">├─ $HOME/etcd-certs/</span>
<span class="err">│ ├─ ca.csr</span>
<span class="err">│ ├─ ca.pem</span>
<span class="err">│ ├─ ca-config.json</span>
<span class="err">│ ├─ ca-csr.json</span>
<span class="err">│ ├─ ca-key.pem</span>
<span class="err">│ ├─ client.csr</span>
<span class="err">│ ├─ client.json</span>
<span class="err">│ ├─ client.pem</span>
<span class="err">│ ├─ client-key.pem</span>
<span class="err">│ ├─ config-etcd01.json</span>
<span class="err">│ ├─ config-etcd02.json</span>
<span class="err">│ ├─ config-etcd02.json</span>
<span class="err">│ ├─ etcd01/</span>
<span class="err">│ │ ├─ peer.csr</span>
<span class="err">│ │ ├─ peer.pem</span>
<span class="err">│ │ ├─ peer-key.pem</span>
<span class="err">│ │ ├─ server.csr</span>
<span class="err">│ │ ├─ server.pem</span>
<span class="err">│ │ └─ server-key.pem</span>
<span class="err">│ ├─ etcd02/</span>
<span class="err">│ │ ├─ peer.csr</span>
<span class="err">│ │ ├─ peer.pem</span>
<span class="err">│ │ ├─ peer-key.pem</span>
<span class="err">│ │ ├─ server.csr</span>
<span class="err">│ │ ├─ server.pem</span>
<span class="err">│ │ └─ server-key.pem</span>
<span class="err">│ └─ etcd03/</span>
<span class="err">│ ├─ peer.csr</span>
<span class="err">│ ├─ peer.pem</span>
<span class="err">│ ├─ peer-key.pem</span>
<span class="err">│ ├─ server.csr</span>
<span class="err">│ ├─ server.pem</span>
<span class="err">│ └─ server-key.pem</span>
</code></pre></div>
<p>Ya tenemos todos los archivos que necesitamos para poder configurar nuestro cluster de <em>etcd</em> utilizando SSL, por lo que ya solo nos queda copiarlos a cada uno de los nodos.</p>
<p>No hace falta que copiemos todos los archivos a cada nodo, únicamente vamos a necesitar estos:</p>
<ul>
<li><code>ca.pem</code></li>
<li><code>client.pem</code></li>
<li><code>client-key.pem</code></li>
</ul>
<p>Y para cada uno de los nodos únicamente los de su respectivo subdirectorio:</p>
<ul>
<li><code>etcdXX/server.pem</code></li>
<li><code>etcdXX/server-key.pem</code></li>
<li><code>etcdXX/peer.pem</code></li>
<li><code>etcdXX/peer-key.pem</code></li>
</ul>
<p>Como ya comenté antes, en mi caso estoy montando este cluster de <em>etcd</em> para su uso con Kubernetes por lo que voy a copiar los certificados al directorio <code>/etc/kubernetes/pki/etcd</code> de cada nodo, pero vosotros podéis copiarlos al directorio que queráis (<code>/etc/etcd/certs</code>, por ejemplo).</p>
<p>Una vez copiados estos 7 archivos a cada nodo ya podemos empezar con la configuración del cluster.</p>
<p><em>Importante: Aunque no todos los archivos generados hacen falta os recomiendo que los guardéis igualmente (sobre todo los archivos de configuración) por si en un futuro necesitáis volver a generar los certificados de alguno de los servidores o generar nuevos certificados para un nuevo nodo con el que ampliar el cluster.</em></p>
<h2>Instalación y configuración del cluster<a name="install"></a></h2>
<p>Antes de nada, si los nodos que vas a utilizar para el cluster tienen algún <em>firewall</em> configurado, debemos abrir los puertos necesarios para poder conectarnos.</p>
<p><em>Etcd</em> utiliza estos puertos por defecto:</p>
<ul>
<li><strong>2379</strong>: Para las conexiones de los clientes</li>
<li><strong>2380</strong>: Para las conexiones entre los demás nodos del cluster</li>
</ul>
<p>Por lo tanto debemos asegurarnoss de que podemos conectarnos al puerto 2380 de cualquier nodo desde cualquier nodo y al puerto 2379 de cualquier nodo desde donde vayamos a hacer peticiones al cluster.</p>
<p>Es importante comprobar que no tengamos en nuestros nodos ninguna versión de <em>etcd</em> ya instalada. Si es así, hay que desinstalarla primero.</p>
<p>Antes de instalar una nueva versión de <em>etcd</em> tenemos que saber cuál es esa última versión, por lo que vamos a la zona de <em>releases</em> de su página de Github (<a href="https://github.com/coreos/etcd/releases">https://github.com/coreos/etcd/releases</a>) y lo comprobamos.</p>
<p>En este momento la última versión es la 3.3.4, por lo que descargamos e instalamos dicha versión <strong>en cada uno de los nodos</strong> de nuestro cluster:</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">export</span> <span class="nv">VERSION</span><span class="o">=</span>v3.3.4
$ curl -sSL https://github.com/coreos/etcd/releases/download/<span class="nv">$VERSION</span>/etcd-<span class="nv">$VERSION</span>-linux-amd64.tar.gz <span class="p">|</span> sudo tar -xzv --strip-components<span class="o">=</span><span class="m">1</span> -C /usr/local/bin/
</code></pre></div>
<p>Ahora que ya tenemos <em>etcd</em> instalado en los 3 nodos, vamos a configurarlo.</p>
<p>Creamos un archivo <code>/etc/etdc.env</code> en <strong>cada uno de los nodos</strong> con el nombre e IP de cada servidor:</p>
<p>Para el nodo 1:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">/etc/etcd.env</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/etcd01/etcd.env'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="na">PEER_NAME</span><span class="o">=</span><span class="s">etcd01</span>
<span class="na">PRIVATE_IP</span><span class="o">=</span><span class="s">192.168.1.83</span>
</code></pre></div>
</figure>
<p>Para el nodo 2:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">/etc/etcd.env</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/etcd02/etcd.env'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="na">PEER_NAME</span><span class="o">=</span><span class="s">etcd02</span>
<span class="na">PRIVATE_IP</span><span class="o">=</span><span class="s">192.168.1.84</span>
</code></pre></div>
</figure>
<p>Para el nodo 3:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">/etc/etcd.env</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/etcd03/etcd.env'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="na">PEER_NAME</span><span class="o">=</span><span class="s">etcd03</span>
<span class="na">PRIVATE_IP</span><span class="o">=</span><span class="s">192.168.1.85</span>
</code></pre></div>
</figure>
<p>Ahora vamos a crear los archivos de configuración de <a href="https://freedesktop.org/wiki/Software/systemd/">systemd</a> para que podamos arrancar, reiniciar y parar el servicio de <em>etcd</em> como haríamos con cualquier otro servicio.</p>
<p>Para eso, creamos un archivo <code>/etc/systemd/system/etcd.service</code> en <strong>cada uno de los nodos</strong>, indicando los argumentos que se le pasarán al programa <em>etcd</em> cuando arranque, y que son básicamente el nombre e IP del servidor, el nombre e IP de los demás nodos del cluster, la ruta a los certificados que generamos en el paso anterior, etc.</p>
<p>El archivo quedaría más o menos así para el nodo 1:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">/etc/systemd/system/etcd.service</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/etcd01/etcd.service'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="k">[Unit]</span>
<span class="na">Description</span><span class="o">=</span><span class="s">etcd</span>
<span class="na">Documentation</span><span class="o">=</span><span class="s">https://github.com/coreos/etcd</span>
<span class="na">Conflicts</span><span class="o">=</span><span class="s">etcd.service</span>
<span class="na">Conflicts</span><span class="o">=</span><span class="s">etcd2.service</span>
<span class="k">[Service]</span>
<span class="na">EnvironmentFile</span><span class="o">=</span><span class="s">/etc/etcd.env</span>
<span class="na">Type</span><span class="o">=</span><span class="s">notify</span>
<span class="na">Restart</span><span class="o">=</span><span class="s">always</span>
<span class="na">RestartSec</span><span class="o">=</span><span class="s">5s</span>
<span class="na">LimitNOFILE</span><span class="o">=</span><span class="s">40000</span>
<span class="na">TimeoutStartSec</span><span class="o">=</span><span class="s">0</span>
<span class="na">ExecStart</span><span class="o">=</span><span class="s">/usr/local/bin/etcd \</span>
<span class="s"> --name etcd01 \</span>
<span class="s"> --data-dir /var/lib/etcd \</span>
<span class="s"> --initial-advertise-peer-urls https://192.168.1.83:2380 \</span>
<span class="s"> --listen-peer-urls https://192.168.1.83:2380 \</span>
<span class="s"> --listen-client-urls https://192.168.1.83:2379,https://127.0.0.1:2379 \</span>
<span class="s"> --advertise-client-urls https://192.168.1.83:2379 \</span>
<span class="s"> --initial-cluster-token etcd-cluster-1 \</span>
<span class="s"> --initial-cluster etcd01=https://192.168.1.83:2380,etcd02=https://192.168.1.84:2380,etcd03=https://192.168.1.85:2380 \</span>
<span class="s"> --initial-cluster-state new \</span>
<span class="s"> --cert-file=/etc/kubernetes/pki/etcd/server.pem \</span>
<span class="s"> --key-file=/etc/kubernetes/pki/etcd/server-key.pem \</span>
<span class="s"> --client-cert-auth \</span>
<span class="s"> --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem \</span>
<span class="s"> --peer-cert-file=/etc/kubernetes/pki/etcd/peer.pem \</span>
<span class="s"> --peer-key-file=/etc/kubernetes/pki/etcd/peer-key.pem \</span>
<span class="s"> --peer-client-cert-auth \</span>
<span class="s"> --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem</span>
<span class="k">[Install]</span>
<span class="na">WantedBy</span><span class="o">=</span><span class="s">multi-user.target</span>
</code></pre></div>
</figure>
<p>Para el nodo 2:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">/etc/systemd/system/etcd.service</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/etcd02/etcd.service'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="k">[Unit]</span>
<span class="na">Description</span><span class="o">=</span><span class="s">etcd</span>
<span class="na">Documentation</span><span class="o">=</span><span class="s">https://github.com/coreos/etcd</span>
<span class="na">Conflicts</span><span class="o">=</span><span class="s">etcd.service</span>
<span class="na">Conflicts</span><span class="o">=</span><span class="s">etcd2.service</span>
<span class="k">[Service]</span>
<span class="na">EnvironmentFile</span><span class="o">=</span><span class="s">/etc/etcd.env</span>
<span class="na">Type</span><span class="o">=</span><span class="s">notify</span>
<span class="na">Restart</span><span class="o">=</span><span class="s">always</span>
<span class="na">RestartSec</span><span class="o">=</span><span class="s">5s</span>
<span class="na">LimitNOFILE</span><span class="o">=</span><span class="s">40000</span>
<span class="na">TimeoutStartSec</span><span class="o">=</span><span class="s">0</span>
<span class="na">ExecStart</span><span class="o">=</span><span class="s">/usr/local/bin/etcd \</span>
<span class="s"> --name etcd02 \</span>
<span class="s"> --data-dir /var/lib/etcd \</span>
<span class="s"> --initial-advertise-peer-urls https://192.168.1.84:2380 \</span>
<span class="s"> --listen-peer-urls https://192.168.1.84:2380 \</span>
<span class="s"> --listen-client-urls https://192.168.1.84:2379,https://127.0.0.1:2379 \</span>
<span class="s"> --advertise-client-urls https://192.168.1.84:2379 \</span>
<span class="s"> --initial-cluster-token etcd-cluster-1 \</span>
<span class="s"> --initial-cluster etcd01=https://192.168.1.83:2380,etcd02=https://192.168.1.84:2380,etcd03=https://192.168.1.85:2380 \</span>
<span class="s"> --initial-cluster-state new \</span>
<span class="s"> --cert-file=/etc/kubernetes/pki/etcd/server.pem \</span>
<span class="s"> --key-file=/etc/kubernetes/pki/etcd/server-key.pem \</span>
<span class="s"> --client-cert-auth \</span>
<span class="s"> --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem \</span>
<span class="s"> --peer-cert-file=/etc/kubernetes/pki/etcd/peer.pem \</span>
<span class="s"> --peer-key-file=/etc/kubernetes/pki/etcd/peer-key.pem \</span>
<span class="s"> --peer-client-cert-auth \</span>
<span class="s"> --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem</span>
<span class="k">[Install]</span>
<span class="na">WantedBy</span><span class="o">=</span><span class="s">multi-user.target</span>
</code></pre></div>
</figure>
<p>Para el nodo 3:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">/etc/systemd/system/etcd.service</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/etcd03/etcd.service'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="k">[Unit]</span>
<span class="na">Description</span><span class="o">=</span><span class="s">etcd</span>
<span class="na">Documentation</span><span class="o">=</span><span class="s">https://github.com/coreos/etcd</span>
<span class="na">Conflicts</span><span class="o">=</span><span class="s">etcd.service</span>
<span class="na">Conflicts</span><span class="o">=</span><span class="s">etcd2.service</span>
<span class="k">[Service]</span>
<span class="na">EnvironmentFile</span><span class="o">=</span><span class="s">/etc/etcd.env</span>
<span class="na">Type</span><span class="o">=</span><span class="s">notify</span>
<span class="na">Restart</span><span class="o">=</span><span class="s">always</span>
<span class="na">RestartSec</span><span class="o">=</span><span class="s">5s</span>
<span class="na">LimitNOFILE</span><span class="o">=</span><span class="s">40000</span>
<span class="na">TimeoutStartSec</span><span class="o">=</span><span class="s">0</span>
<span class="na">ExecStart</span><span class="o">=</span><span class="s">/usr/local/bin/etcd \</span>
<span class="s"> --name etcd03 \</span>
<span class="s"> --data-dir /var/lib/etcd \</span>
<span class="s"> --initial-advertise-peer-urls https://192.168.1.85:2380 \</span>
<span class="s"> --listen-peer-urls https://192.168.1.85:2380 \</span>
<span class="s"> --listen-client-urls https://192.168.1.85:2379,https://127.0.0.1:2379 \</span>
<span class="s"> --advertise-client-urls https://192.168.1.85:2379 \</span>
<span class="s"> --initial-cluster-token etcd-cluster-1 \</span>
<span class="s"> --initial-cluster etcd01=https://192.168.1.83:2380,etcd02=https://192.168.1.84:2380,etcd03=https://192.168.1.85:2380 \</span>
<span class="s"> --initial-cluster-state new \</span>
<span class="s"> --cert-file=/etc/kubernetes/pki/etcd/server.pem \</span>
<span class="s"> --key-file=/etc/kubernetes/pki/etcd/server-key.pem \</span>
<span class="s"> --client-cert-auth \</span>
<span class="s"> --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem \</span>
<span class="s"> --peer-cert-file=/etc/kubernetes/pki/etcd/peer.pem \</span>
<span class="s"> --peer-key-file=/etc/kubernetes/pki/etcd/peer-key.pem \</span>
<span class="s"> --peer-client-cert-auth \</span>
<span class="s"> --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem</span>
<span class="k">[Install]</span>
<span class="na">WantedBy</span><span class="o">=</span><span class="s">multi-user.target</span>
</code></pre></div>
</figure>
<p>Ya solo nos queda reiniciar el demonio de <em>systemd</em> de cada nodo para que lea el archivo que acabamos de crear:</p>
<div class="highlight"><pre><span></span><code>$ sudo systemctl daemon-reload
</code></pre></div>
<p>Y ahora ya podemos gestionar el demonio de <em>etcd</em> con el comando <em>systemctl</em> o con <em>service</em>, por lo que vamos a levantar el proceso y a configurarlo para que se inicie automáticamente al arrancar el servidor:</p>
<div class="highlight"><pre><span></span><code>$ sudo systemctl <span class="nb">enable</span> etcd
$ sudo systemctl start etcd
</code></pre></div>
<p>Si todo ha ido bien, ahora mismo ya tendremos el servicio de <em>etcd</em> levantado, por lo que hacemos lo mismo en los otros 2 nodos.</p>
<blockquote>
<p>Si es la primera vez que estas levantando el servicio, hay veces en las que al invocar a <em>systemctl</em> se queda el proceso <em>esperando eternamente</em> (hasta que salta el <em>más-que-generoso-timeout(TM)</em>, me refiero). La mayoría de las veces se debe a que el proceso se demonio de <em>etcd</em> se inicia correctamente, pero se queda intentando conectarse con los otros 2 nodos del cluster, por lo que si aún no los hemos levantado, el proceso lo reintenta indefinidamente y parece que se queda <em>congelado</em>...
<br /><br />
En estos casos, puesto que el proceso se levanta correctamente, o bien sales con <code>CTRL</code> + <code>C</code>, o bien levantas los demonios en los otros 2 nodos.</p>
</blockquote>
<p>Puedes comprobar si el servicio se ha levantado correctamente con:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> sudo systemctl status etcd
<span class="go">- etcd.service - etcd</span>
<span class="go"> Loaded: loaded (/etc/systemd/system/etcd.service; enabled; vendor preset: enabled)</span>
<span class="go"> Active: active (running) since Tue 2018-05-06 00:21:53 CEST; 11s ago</span>
<span class="go"> Docs: https://github.com/coreos/etcd</span>
<span class="go"> Main PID: 9426 (etcd)</span>
<span class="go"> Tasks: 18 (limit: 4915)</span>
<span class="go"> Memory: 10.1M</span>
<span class="go"> CPU: 145ms</span>
<span class="go"> CGroup: /system.slice/etcd.service</span>
<span class="go"> └─9426 /usr/local/bin/etcd --name etcd01 --data-dir /var/lib/etcd --initial-advertise-peer-urls https://192.168.1.83:2380 --listen-peer-urls https://192.168.1.83:2380 --listen-client-urls https://192.168.1.83:2379,https://127.0.0.1:2379 --advertise-client-urls</span>
<span class="go">May 06 00:21:53 etcd01 etcd[20483]: established a TCP streaming connection with peer c37956d0928a73d9 (stream Message reader)</span>
<span class="go">May 06 00:21:53 etcd01 etcd[20483]: established a TCP streaming connection with peer c37956d0928a73d9 (stream MsgApp v2 reader)</span>
<span class="go">May 06 00:21:53 etcd01 etcd[20483]: raft.node: 1e9f81657a2688f9 elected leader b5a3b7906f500074 at term 1291</span>
<span class="go">May 06 00:21:53 etcd01 etcd[20483]: 1e9f81657a2688f9 initialzed peer connection; fast-forwarding 8 ticks (election ticks 10) with 2 active peer(s)</span>
<span class="go">May 06 00:21:53 etcd01 etcd[20483]: published {Name:etcd01 ClientURLs:["https://192.168.1.83:2379"]} to cluster e47a206dc7abb150</span>
<span class="go">May 06 00:21:53 etcd01 etcd[20483]: ready to serve client requests</span>
<span class="go">May 06 00:21:53 etcd01 etcd[20483]: ready to serve client requests</span>
<span class="go">May 06 00:21:53 etcd01 systemd[1]: Started etcd.</span>
<span class="go">May 06 00:21:53 etcd01 etcd[20483]: serving client requests on 127.0.0.1:2379</span>
<span class="go">May 06 00:21:53 etcd01 etcd[20483]: serving client requests on 192.168.1.83:2379</span>
</code></pre></div>
<p>Esto significa que ya tenemos nuestro cluster funcionando y aceptando conexiones por el puerto 2379!</p>
<h2>Administración básica<a name="admin"></a></h2>
<p>Ahora que ya tenemos el cluster funcionando, vamos a ver algunos comandos que nos serán de utilidad a la hora de administrar el cluster, comprobar su estado, añadir un nuevo nodo, etc.</p>
<p>Recuerda que hemos configurado nuestro cluster para usar SSL en cualquier conexión, por lo que necesitaremos el certificado de cliente en cualquier sitio desde el que nos queramos conectar al cluster.</p>
<p>Al servidor <em>etcd</em> se accede utilizando la API, como ya expliqué al principio del artículo, pero existe una utilidad llamada <code>etcdctl</code> que nos permite acceder a dicha API desde la linea de comandos. Vamos a ver sus opciones, pero antes tenemos que establecer la variable de sesión <code>ETCDCTL_API=3</code> ya que de lo contrario la utilidad nos mostrará opciones <em>obsoletas</em> (luego explicaré el tema de las variables de sesión):</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> <span class="nb">export</span> <span class="nv">ETCDCTL_API</span><span class="o">=</span><span class="m">3</span>
<span class="gp">$</span> etcdctl --help
<span class="go">NAME:</span>
<span class="go"> etcdctl - A simple command line client for etcd3.</span>
<span class="go">USAGE:</span>
<span class="go"> etcdctl</span>
<span class="go">VERSION:</span>
<span class="go"> 3.3.4</span>
<span class="go">API VERSION:</span>
<span class="go"> 3.3</span>
<span class="go">COMMANDS:</span>
<span class="go"> get Gets the key or a range of keys</span>
<span class="go"> put Puts the given key into the store</span>
<span class="go"> del Removes the specified key or range of keys [key, range_end)</span>
<span class="go"> txn Txn processes all the requests in one transaction</span>
<span class="go"> compaction Compacts the event history in etcd</span>
<span class="go"> alarm disarm Disarms all alarms</span>
<span class="go"> alarm list Lists all alarms</span>
<span class="go"> defrag Defragments the storage of the etcd members with given endpoints</span>
<span class="go"> endpoint health Checks the healthiness of endpoints specified in `--endpoints` flag</span>
<span class="go"> endpoint status Prints out the status of endpoints specified in `--endpoints` flag</span>
<span class="go"> endpoint hashkv Prints the KV history hash for each endpoint in --endpoints</span>
<span class="go"> move-leader Transfers leadership to another etcd cluster member.</span>
<span class="go"> watch Watches events stream on keys or prefixes</span>
<span class="go"> version Prints the version of etcdctl</span>
<span class="go"> lease grant Creates leases</span>
<span class="go"> lease revoke Revokes leases</span>
<span class="go"> lease timetolive Get lease information</span>
<span class="go"> lease list List all active leases</span>
<span class="go"> lease keep-alive Keeps leases alive (renew)</span>
<span class="go"> member add Adds a member into the cluster</span>
<span class="go"> member remove Removes a member from the cluster</span>
<span class="go"> member update Updates a member in the cluster</span>
<span class="go"> member list Lists all members in the cluster</span>
<span class="go"> snapshot save Stores an etcd node backend snapshot to a given file</span>
<span class="go"> snapshot restore Restores an etcd member snapshot to an etcd directory</span>
<span class="go"> snapshot status Gets backend snapshot status of a given file</span>
<span class="go"> make-mirror Makes a mirror at the destination etcd cluster</span>
<span class="go"> migrate Migrates keys in a v2 store to a mvcc store</span>
<span class="go"> lock Acquires a named lock</span>
<span class="go"> elect Observes and participates in leader election</span>
<span class="go"> auth enable Enables authentication</span>
<span class="go"> auth disable Disables authentication</span>
<span class="go"> user add Adds a new user</span>
<span class="go"> user delete Deletes a user</span>
<span class="go"> user get Gets detailed information of a user</span>
<span class="go"> user list Lists all users</span>
<span class="go"> user passwd Changes password of user</span>
<span class="go"> user grant-role Grants a role to a user</span>
<span class="go"> user revoke-role Revokes a role from a user</span>
<span class="go"> role add Adds a new role</span>
<span class="go"> role delete Deletes a role</span>
<span class="go"> role get Gets detailed information of a role</span>
<span class="go"> role list Lists all roles</span>
<span class="go"> role grant-permission Grants a key to a role</span>
<span class="go"> role revoke-permission Revokes a key from a role</span>
<span class="go"> check perf Check the performance of the etcd cluster</span>
<span class="go"> help Help about any command</span>
<span class="go">OPTIONS:</span>
<span class="go"> --cacert="" verify certificates of TLS-enabled secure servers using this CA bundle</span>
<span class="go"> --cert="" identify secure client using this TLS certificate file</span>
<span class="go"> --command-timeout=5s timeout for short running command (excluding dial timeout)</span>
<span class="go"> --debug[=false] enable client-side debug logging</span>
<span class="go"> --dial-timeout=2s dial timeout for client connections</span>
<span class="go"> -d, --discovery-srv="" domain name to query for SRV records describing cluster endpoints</span>
<span class="go"> --endpoints=[127.0.0.1:2379] gRPC endpoints</span>
<span class="go"> --hex[=false] print byte strings as hex encoded strings</span>
<span class="go"> --insecure-discovery[=true] accept insecure SRV records describing cluster endpoints</span>
<span class="go"> --insecure-skip-tls-verify[=false] skip server certificate verification</span>
<span class="go"> --insecure-transport[=true] disable transport security for client connections</span>
<span class="go"> --keepalive-time=2s keepalive time for client connections</span>
<span class="go"> --keepalive-timeout=6s keepalive timeout for client connections</span>
<span class="go"> --key="" identify secure client using this TLS key file</span>
<span class="go"> --user="" username[:password] for authentication (prompt if password is not supplied)</span>
<span class="go"> -w, --write-out="simple" set the output format (fields, json, protobuf, simple, table)</span>
</code></pre></div>
<p>Como puedes ver este comando tiene bastantes parámetros, por lo que vamos a echar un ojo a los más importantes:</p>
<ul>
<li><code>--endpoints</code>: Aqui debemos especificar todos los nodos de nuestro cluster (host y puerto) separados por comas, de forma que si uno de ellos estuviera caído nuestra consulta sería enviada de forma automática a otro de los nodos. Por ejemplo, en nuestro caso sería: <code>https://etcd01:2379,https://etcd02:2379,https://etcd03:2379</code>.</li>
<li><code>--cert</code>: La ruta del certificado de cliente que vamos a utilizar para conectarnos. En nuestro caso sería: <code>/etc/kubernetes/pki/etcd/client.pem</code>.</li>
<li><code>--key</code>: La ruta de la clave del certificado de cliente. En nuestro caso sería: <code>/etc/kubernetes/pki/etcd/client-key.pem</code>.</li>
<li><code>--cacert</code>: La ruta hacia la <em>entidad certificadora</em> con la que hemos generado los certificados. En nuestro caso sería: <code>/etc/kubernetes/pki/etcd/ca.pem</code>.</li>
<li><code>--write-out</code>: Aqui indicamos cómo queremos que nos devuelva al respuesta del comando que vamos a lanzar al cluster. Puede ser <code>simple</code>, <code>json</code>, <code>table</code>, etc.</li>
<li><code>--debug</code>: Con esta opción podemos ver las llamadas HTTP/HTTPS que se estan lanzando a la API del cluster para ejecutar el comando que vayamos a ejecutar. Muy util para depurar el proceso si tenemos algún problema con los datos que estamos obteniendo.</li>
</ul>
<p>Por comodidad, tener que estar introduciendo las rutas de todos los certificados y la lista de <em>endpoints</em> cada vez que lancemos un comando puede resultar una auténtica tortura. Por suerte, podemos definir una serie de variables de entorno que una vez definidas permitirán a <code>etcdctl</code> conocer el valor de todos estos parámetros sin que tengamos que estar tecleándolos constantemente. Estas variables son:</p>
<ul>
<li><code>ETCDCTL_CERT</code>: La ruta que pondríamos en el parámetro <code>--cert-file</code>.</li>
<li><code>ETCDCTL_KEY</code>: La ruta que pondríamos en el parámetro <code>--key-file</code>.</li>
<li><code>ETCDCTL_CACERT</code>: La ruta que pondríamos en el parámetro <code>--ca-file</code>.</li>
<li><code>ETCDCTL_ENDPOINTS</code>: La lista (separada por comas) de endpoints (host y puerto) de nuestro cluster.</li>
<li><code>ETCDCTL_API</code>: Versión de la API que queramos utilizar. Puede ser <code>2</code> o <code>3</code>.</li>
</ul>
<p>Una vez que hemos visto los parámetros, vamos con algunos de los comandos disponibles:</p>
<ul>
<li><code>get</code>: Devuelve el valor de una clave.</li>
<li><code>put</code>: Establece el valor de una clave.</li>
<li><code>endpoint health</code>: Muestra el estado de los nodos del cluster.</li>
<li><code>check perf</code>: Realiza un informe de rendimiento del cluster.</li>
<li>Etc... (esta vez me refiero a <em>etcétera</em>, no al nombre del programa del que estamos hablando xDDD)</li>
</ul>
<p>Vamos a probar alguno de ellos...</p>
<p>Nos conectamos a cualquiera de los nodos (por ejemplo al primero: <code>etcd01</code>) y definimos las variables de sesión con los valores necesarios para no tener que preocuparnos de ellos en cada ejecución del comando <code>etcdctl</code>:</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">export</span> <span class="nv">ETCDCTL_CERT</span><span class="o">=</span>/etc/kubernetes/pki/etcd/client.pem
$ <span class="nb">export</span> <span class="nv">ETCDCTL_KEY</span><span class="o">=</span>/etc/kubernetes/pki/etcd/client-key.pem
$ <span class="nb">export</span> <span class="nv">ETCDCTL_CACERT</span><span class="o">=</span>/etc/kubernetes/pki/etcd/ca.pem
$ <span class="nb">export</span> <span class="nv">ETCDCTL_ENDPOINTS</span><span class="o">=</span>https://etcd01:2379,https://etcd02:2379,https://etcd03:2379
$ <span class="nb">export</span> <span class="nv">ETCDCTL_API</span><span class="o">=</span><span class="m">3</span>
</code></pre></div>
<p>Ahora vamos a lanzar el comando <code>endpoint health</code> para ver <em>la salud</em> de nuestro recién creado cluster:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl endpoint health
<span class="go">https://etcd02:2379 is healthy: successfully committed proposal: took = 2.397419ms</span>
<span class="go">https://etcd01:2379 is healthy: successfully committed proposal: took = 1.535434ms</span>
<span class="go">https://etcd03:2379 is healthy: successfully committed proposal: took = 2.331939ms</span>
</code></pre></div>
<p>Que indica que los 3 nodos estan funcionando correctamente (<em>...is healthy</em>).</p>
<blockquote>
<p>Si en lugar del resultado os muestra algún error relacionado con los certificados significa que no habeis puesto bien las rutas de las variables de sesión, o que vuestro usuario no tiene permiso para leer dichos archivos.</p>
</blockquote>
<p>Ahora vamos a introducir una clave de prueba y su valor. Por ejemplo:</p>
<div class="highlight"><pre><span></span><code>$ etcdctl put clavePrueba <span class="s2">"Esto es una prueba"</span>
</code></pre></div>
<p>Leemos el valor de la clave <code>clavePrueba</code>:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl get clavePrueba
<span class="go">Esto es una prueba</span>
</code></pre></div>
<p>Vamos ahora con algo más <em>delicado</em>: gestionar nuevos nodos.
Supongamos que queremos añadir un nuevo nodo a nuestro cluster. Por comodidad y para <em>matar dos pájaros de un tiro</em> vamos primero a quitar uno de los nodos del cluster y luego lo volveremos a meter.</p>
<p>Con el comando <code>member list</code> vemos la lista de nodos que componen nuestro cluster, y el <a href="https://es.wikipedia.org/wiki/Identificador">ID</a> de cada uno de ellos:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl member list
<span class="go">b5a3b7906f500074, started, etcd01, https://192.168.1.83:2380, https://192.168.1.83:2379</span>
<span class="go">c37956d0928a73d9, started, etcd02, https://192.168.1.84:2380, https://192.168.1.84:2379</span>
<span class="go">1e9f81657a2688f9, started, etcd03, https://192.168.1.85:2380, https://192.168.1.85:2379</span>
</code></pre></div>
<p>Para eliminar uno de ellos, por ejemplo el nodo 3 (<code>etcd03</code>), ejecutamos el comando <code>member remove</code> indicando el ID del nodo que queremos eliminar de nuestro cluster:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl member remove 1e9f81657a2688f9
<span class="go">Member 1e9f81657a2688f9 removed from cluster e47a206dc7abb150</span>
</code></pre></div>
<p>Si volvemos a obtener la lista de nodos del cluster veremos que ya solo tenemos 2:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl member list
<span class="go">b5a3b7906f500074, started, etcd01, https://192.168.1.83:2380, https://192.168.1.83:2379</span>
<span class="go">c37956d0928a73d9, started, etcd02, https://192.168.1.84:2380, https://192.168.1.84:2379</span>
</code></pre></div>
<p>El procedimiento para añadir un nodo es tambien muy sencillo, pero si el nodo que queremos añadir ya ha formado parte de un cluster <em>etcd</em> anteriormente (como es nuestro caso ya que lo acabamos de eliminar ahora mismo) hay que hacer un par de cosas antes:</p>
<ul>
<li>Detener el servicio de <em>etcd</em> en el nuevo nodo que queremos añadir: <code>$ sudo systemctl stop etcd</code>.</li>
<li>Eliminar el directorio donde se guardan los datos de <em>etcd</em> para que al añadirlo al cluster se sincronice de nuevo con el resto de nodos: <code>$ sudo rm -rf /var/lib/etcd/member</code>.</li>
</ul>
<p>Una vez hecho esto, ya podemos continuar con el proceso para añadirlo a nuestro cluster.</p>
<p>Ejecutamos el comando <code>member add</code> junto con el nombre y el endpoint de <em>peer</em> del nuevo nodo que queremos añadir:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl member add etcd03 --peer-urls<span class="o">=</span><span class="s2">"https://192.168.1.85:2380"</span>
<span class="go">Member c398e05912695024 added to cluster e47a206dc7abb150</span>
<span class="go">ETCD_NAME="etcd03"</span>
<span class="go">ETCD_INITIAL_CLUSTER="etcd01=https://192.168.1.83:2380,etcd02=https://192.168.1.84:2380,etcd03=https://192.168.1.85:2380"</span>
<span class="go">ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.1.85:2380"</span>
<span class="go">ETCD_INITIAL_CLUSTER_STATE="existing"</span>
</code></pre></div>
<p>El comando muestra los datos del nuevo nodo que hemos añadido (nombre, endpoints, etc) así como su estado actual, que es <code>existing</code>. Esto significa que aunque el nodo se ha añadido al cluster, aún no está <em>operativo</em>. Podemos verlo si de nuevo volvemos a pedir el listado de nodos:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl member list
<span class="go">b5a3b7906f500074, started, etcd01, https://192.168.1.83:2380, https://192.168.1.83:2379</span>
<span class="go">c37956d0928a73d9, started, etcd02, https://192.168.1.84:2380, https://192.168.1.84:2379</span>
<span class="go">c398e05912695024, unstarted, , https://192.168.1.85:2380,</span>
</code></pre></div>
<p>Como ves, el nuevo nodo está <code>unstarted</code>, por lo que aún no está funcionando (como es lógico).</p>
<p>Para <em>iniciarlo</em>, nos conectamos a dicho nodo y editamos el archivo de configuración de <code>systemctl</code> del <em>etcd</em> (el archivo <code>/etc/systemd/system/etcd.service</code> que creamos cuando estábamos configurando el cluster). Tenemos que sustituir la linea <code>--initial-cluster-state new</code> por <code>--initial-cluster-state existing</code>, por lo que el archivo quedaría así:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">/etc/systemd/system/etcd.service</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/etcd03-new/etcd.service'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="k">[Unit]</span>
<span class="na">Description</span><span class="o">=</span><span class="s">etcd</span>
<span class="na">Documentation</span><span class="o">=</span><span class="s">https://github.com/coreos/etcd</span>
<span class="na">Conflicts</span><span class="o">=</span><span class="s">etcd.service</span>
<span class="na">Conflicts</span><span class="o">=</span><span class="s">etcd2.service</span>
<span class="k">[Service]</span>
<span class="na">EnvironmentFile</span><span class="o">=</span><span class="s">/etc/etcd.env</span>
<span class="na">Type</span><span class="o">=</span><span class="s">notify</span>
<span class="na">Restart</span><span class="o">=</span><span class="s">always</span>
<span class="na">RestartSec</span><span class="o">=</span><span class="s">5s</span>
<span class="na">LimitNOFILE</span><span class="o">=</span><span class="s">40000</span>
<span class="na">TimeoutStartSec</span><span class="o">=</span><span class="s">0</span>
<span class="na">ExecStart</span><span class="o">=</span><span class="s">/usr/local/bin/etcd \</span>
<span class="s"> --name etcd03 \</span>
<span class="s"> --data-dir /var/lib/etcd \</span>
<span class="s"> --initial-advertise-peer-urls https://192.168.1.85:2380 \</span>
<span class="s"> --listen-peer-urls https://192.168.1.85:2380 \</span>
<span class="s"> --listen-client-urls https://192.168.1.85:2379,https://127.0.0.1:2379 \</span>
<span class="s"> --advertise-client-urls https://192.168.1.85:2379 \</span>
<span class="s"> --initial-cluster-token etcd-cluster-1 \</span>
<span class="s"> --initial-cluster etcd01=https://192.168.1.83:2380,etcd02=https://192.168.1.84:2380,etcd03=https://192.168.1.85:2380 \</span>
<span class="s"> --initial-cluster-state existing \</span>
<span class="s"> --cert-file=/etc/kubernetes/pki/etcd/server.pem \</span>
<span class="s"> --key-file=/etc/kubernetes/pki/etcd/server-key.pem \</span>
<span class="s"> --client-cert-auth \</span>
<span class="s"> --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem \</span>
<span class="s"> --peer-cert-file=/etc/kubernetes/pki/etcd/peer.pem \</span>
<span class="s"> --peer-key-file=/etc/kubernetes/pki/etcd/peer-key.pem \</span>
<span class="s"> --peer-client-cert-auth \</span>
<span class="s"> --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem</span>
<span class="k">[Install]</span>
<span class="na">WantedBy</span><span class="o">=</span><span class="s">multi-user.target</span>
</code></pre></div>
</figure>
<p>Recargamos la configuración de <code>systemctl</code> e iniciamos el servicio de <em>etcd</em>:</p>
<div class="highlight"><pre><span></span><code>$ sudo systemctl daemon-reload
$ sudo systemctl start etcd
</code></pre></div>
<p>Al cabo de unos pocos segundos (dependiendo del tamaño de la base de datos de <em>etcd</em> que tengamos en nuestro cluster), el nuevo nodo se habrá sincronizado y si pedimos de nuevo la lista de nodos tendríamos que ver que el nuevo nodo ya está funcionando como los demás:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl member list
<span class="go">b5a3b7906f500074, started, etcd01, https://192.168.1.83:2380, https://192.168.1.83:2379</span>
<span class="go">c37956d0928a73d9, started, etcd02, https://192.168.1.84:2380, https://192.168.1.84:2379</span>
<span class="go">736e5742db963896, started, etcd03, https://192.168.1.85:2380, https://192.168.1.85:2379</span>
</code></pre></div>
<blockquote>
<p>Por coherencia con el resto de nodos, yo recomiendo que una vez se ha añadido el nuevo nodo al cluster y todo está funcionando, editemos de nuevo el archivo <code>/etc/systemd/system/etcd.service</code> y volvamos a cambiar el <code>--initial-cluster-state existing</code> por <code>--initial-cluster-state new</code> para dejarlo como estaba (igual que en el resto de nodos) pero realmente daría igual ya que una vez iniciado el servicio por primera vez, ese parámetro ya no se vuelve a tener en cuenta.</p>
</blockquote>
<p>Bueno, pues ya tenemos el cluster otra vez <em>completo</em>, ¿pero cómo sabemos que realmente esta funcionando en alta disponibilidad, y va a seguir haciéndolo aunque alguno de sus nodos se quede fuera de servicio? Vamos a comprobarlo:</p>
<p>Detenemos el servicio de <em>etcd</em> en el nodo 1 (<code>etcd01</code>):</p>
<div class="highlight"><pre><span></span><code>$ sudo systemctl stop etcd
</code></pre></div>
<p>Y volvemos a preguntar por el valor de la clave que guardamos antes:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl get clavePrueba
<span class="go">Esto es una prueba</span>
</code></pre></div>
<p>Como ves, obtenemos el valor de la clave sin problemas aún con el nodo 1 fuera de servicio.</p>
<p>Ahora, levantamos de nuevo el servicio <em>etcd</em> en el nodo 1, lo detenemos el nodo 2 y volvemos a preguntar por la clave (es importante que ANTES de detener el nodo 2 vuelvas a iniciar el nodo 1, ya que un cluster de 3 nodos puede <em>sobrevivir</em> si falla 1 nodo, pero no si fallan 2):</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl get clavePrueba
<span class="go">Esto es una prueba</span>
</code></pre></div>
<p>De nuevo sigue funcionando... así que vamos con la última prueba: levantamos de nuevo el servicio <em>etcd</em> en el nodo 2, lo detenemos en el nodo 3 y volvemos a preguntar por la clave:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl get clavePrueba
<span class="go">Esto es una prueba</span>
</code></pre></div>
<p>Como ves, el cluster sigue funcionando aunque cualquiera de sus nodos deje de hacerlo.</p>
<p>Ya tienes tu cluster montado y funcionado, así que ya puedes empezar a utilizarlo sin problemas!</p>
<p>Como siempre, espero que el artículo os haya resultado de utilidad! Y por supuesto, no dudéis en distribuirlo y compartirlo con todo el mundo (pero por favor, citad siempre la fuente original de éste artículo).</p>
<p>Alaaaaaaaaaaaaaaaaaaaaaaa!</p>
<h2>Referencias<a name="refs"></a></h2>
<ul>
<li><a href="https://coreos.com/etcd">https://coreos.com/etcd</a></li>
<li><a href="https://github.com/coreos/etcd/tree/master/etcdctl">https://github.com/coreos/etcd/tree/master/etcdctl</a></li>
<li><a href="https://github.com/coreos/etcd/blob/master/Documentation/faq.md">https://github.com/coreos/etcd/blob/master/Documentation/faq.md</a></li>
<li><a href="https://github.com/coreos/etcd/blob/master/Documentation/op-guide/configuration.md">https://github.com/coreos/etcd/blob/master/Documentation/op-guide/configuration.md</a></li>
<li><a href="https://blog.cloudflare.com/introducing-cfssl">https://blog.cloudflare.com/introducing-cfssl</a></li>
</ul>High availability in etcd: Deploying a cluster step by step2018-05-06T00:14:02+01:002018-05-06T00:14:02+01:00BhEaNtag:pornohardware.com,2018-05-06:/en/2018/05/06/alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/<p>Si estas intentando montar un <a href="https://es.wikipedia.org/wiki/Cl%C3%BAster_de_alta_disponibilidad">cluster</a> de <a href="https://kubernetes.io/">Kubernetes</a> en alta disponibilidad, o bien tienes alguna experiencia en esto porque lo has visto anteriormente o porque ya has trabajado con ello antes, o bien has llegado a este artículo buscando ayuda en Internet después de haber pasado un buen rato intentando seguir sin éxito los pasos de la incorrecta documentación oficial de <em>multi-master</em> en Kubernetes <a href="https://kubernetes.io/docs/setup/independent/high-availability/">que hay publicada al respecto</a>.</p>
<p>Bien por este motivo o bien porque quieres tener un servicio de <a href="https://coreos.com/etcd/docs/latest/">etcd</a> tolerante a fallos para tu proyecto, espero que con este artículo no te quede ninguna duda sobre cómo montar un cluster para conseguir alta disponibilidad y comunicaciones totalmente cifradas con SSL en el servicio de <em>etcd</em>.</p>
<p>Así que basta ya de hablar y vamos <em>al turrón</em>...</p>
<!-- more -->
<p>Para intentar organizarlo un poco, voy a dividir el artículo en varias partes:</p>
<ol>
<li><a href="#whatis">¿Qué es etcd?</a></li>
<li><a href="#init">Consideraciones iniciales de nuestro cluster</a></li>
<li><a href="#ssl">Creación de los certificados SSL</a></li>
<li><a href="#install">Instalación y configuración del cluster</a></li>
<li><a href="#admin">Administración básica</a></li>
<li><a href="#refs">Referencias</a></li>
</ol>
<h2>¿Qué es etcd?<a name="whatis"></a></h2>
<p><a href="https://github.com/coreos/etcd">Etcd</a> es un servidor de almacenamiento de datos de tipo clave-valor (similar a <a href="https://redis.io/">Redis</a>, aunque con bastantes diferencias) diseñado para funcionar de forma distribuida, rápida y estable.</p>
<p>Forma parte del sistema <a href="https://coreos.com/">CoreOS</a>, y es un proyecto de <a href="https://es.wikipedia.org/wiki/C%C3%B3digo_abierto">código abierto</a> escrito en <a href="https://golang.org/">Go</a> y liberado bajo licencia <a href="https://github.com/coreos/etcd/blob/master/LICENSE">Apache 2.0</a>.</p>
<p>Etcd es un proyecto maduro y que lleva muchos años en desarrollo constante por lo que muchos grandes proyectos lo utilizan para almacenar sus configuraciones debido a su gran estabilidad y rapidez, pero últimamente su desarrollo se ha visto potenciado aún más sobre todo por el auge que está teniendo <a href="https://kubernetes.io/">Kubernetes</a>, que es uno de estos grandes proyectos que utilizan <em>etcd</em>.</p>
<p>Toda la comunicación con <em>etcd</em> se realiza a través de una <a href="https://es.wikipedia.org/wiki/Interfaz_de_programaci%C3%B3n_de_aplicaciones">API</a> que puede ser explotada mediante <a href="http://json.org/">JSON</a> a través de <a href="https://es.wikipedia.org/wiki/Protocolo_de_transferencia_de_hipertexto">HTTP/HTTPS</a> o a través del cliente <a href="https://github.com/coreos/etcd/tree/master/etcdctl">etcdctl</a> para linea de comandos.</p>
<p>A principios de año (enero de 2018), CoreOS (y por lo tanto <em>etcd</em>) fué comprado por <a href="https://www.redhat.com">Redhat</a>.</p>
<h2>Consideraciones iniciales de nuestro cluster<a name="init"></a></h2>
<p>Como recomendación general, para montar un cluster en alta disponibilidad debemos utilizar el mayor número posible de nodos.</p>
<p>En cualquier caso, debemos utilizar <strong>al menos 3 nodos</strong> para el cluster ya que aunque teóricamente bastaría con 2 nodos para tener tolerancia a fallos, en un cluster de <em>etcd</em> siempre debe haber un nodo <em>principal</em> (llamado <em>leader</em>) que es el que tendrá el control de determinadas funciones del cluster, y si ese nodo <em>leader</em> quedara fuera de servicio por algún motivo, los demás nodos del cluster utilizarían un <em>quórum</em> para designar quién sería el nuevo <em>leader</em>. El algoritmo que se utiliza para obtener dicho quórum es <a href="https://raft.github.io/">Raft</a>, usado no solo para este proyecto sino para muchísimos otros, por lo tanto debe haber al menos 3 nodos para que si se pierde el nodo <em>leader</em> los otros 2 puedan designar un <em>sustituto</em>.</p>
<p>Así que en este artículo vamos a crear un cluster con 3 nodos que tendrán estas características:</p>
<table>
<thead>
<tr>
<th align="left">#</th>
<th align="left">Nombre</th>
<th align="left">IP</th>
<th align="left">RAM</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">1</td>
<td align="left">etcd01</td>
<td align="left">192.168.1.83</td>
<td align="left">2 Gb</td>
</tr>
<tr>
<td align="left">2</td>
<td align="left">etcd02</td>
<td align="left">192.168.1.84</td>
<td align="left">2 Gb</td>
</tr>
<tr>
<td align="left">3</td>
<td align="left">etcd03</td>
<td align="left">192.168.1.85</td>
<td align="left">2 Gb</td>
</tr>
</tbody>
</table>
<p>Todas estas máquinas parten de una instalación limpia de mi sistema operativo favorito (<a href="https://www.debian.org">Debian</a>, concretamente la versión <em>stable</em> 9.4) pero debería funcionar prácticamente igual (con ligeros cambios en algunos <em>paths</em> o en el nombre de algún paquete) en cualquier otra distribución de Linux.</p>
<p>Antes de empezar, asegúrate de que todos estos servidores tienen conectividad entre ellos, y que resuelven los nombres de los demás. Lo mejor sería que tuvieras tu propio servidor <a href="https://es.wikipedia.org/wiki/Sistema_de_nombres_de_dominio">DNS</a> (<a href="https://www.isc.org/downloads/bind/1">bind</a> o similar) configurado en tu red para resolver todos los nombres de tus servidores, pero sino, puedes añadir las 3 direcciones IP con sus respectivos nombres al archivo <code>/etc/hosts</code> de cada uno de ellos:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">/etc/hosts</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/hosts'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="mi">127</span><span class="p">.</span><span class="mi">0</span><span class="p">.</span><span class="mi">0</span><span class="p">.</span><span class="mi">1</span> <span class="n">localhost</span>
<span class="mi">192</span><span class="p">.</span><span class="mi">168</span><span class="p">.</span><span class="mi">1</span><span class="p">.</span><span class="mi">83</span> <span class="n">etcd01</span>
<span class="mi">192</span><span class="p">.</span><span class="mi">168</span><span class="p">.</span><span class="mi">1</span><span class="p">.</span><span class="mi">84</span> <span class="n">etcd02</span>
<span class="mi">192</span><span class="p">.</span><span class="mi">168</span><span class="p">.</span><span class="mi">1</span><span class="p">.</span><span class="mi">85</span> <span class="n">etcd03</span>
<span class="o">#</span> <span class="n">The</span> <span class="n">following</span> <span class="n">lines</span> <span class="k">are</span> <span class="n">desirable</span> <span class="k">for</span> <span class="n">IPv6</span> <span class="n">capable</span> <span class="n">hosts</span>
<span class="p">::</span><span class="mi">1</span> <span class="n">localhost</span> <span class="n">ip6</span><span class="o">-</span><span class="n">localhost</span> <span class="n">ip6</span><span class="o">-</span><span class="n">loopback</span>
<span class="n">ff02</span><span class="p">::</span><span class="mi">1</span> <span class="n">ip6</span><span class="o">-</span><span class="n">allnodes</span>
<span class="n">ff02</span><span class="p">::</span><span class="mi">2</span> <span class="n">ip6</span><span class="o">-</span><span class="n">allrouters</span>
</code></pre></div>
</figure>
<p>Ni qué decir tiene que es recomendable asegurarse siempre de que partimos de un sistema actualizado:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get update
$ sudo apt-get dist-upgrade
</code></pre></div>
<p>En mi caso, las últimas versiones disponibles en el momento de escribir este artículo son (no te preocupes si alguno no te suena, los iremos viendo a medida que los vayamos necesitando):</p>
<ul>
<li>Etcd: 3.3.4</li>
<li>cfssl: 1.2</li>
<li>cfssljson: 1.2</li>
</ul>
<h2>Creación de los certificados SSL<a name="ssl"></a></h2>
<p>Como acabo de comentar, toda la comunicación tanto entre el cliente y el servidor de <em>etcd</em> como entre los propios servidores de <em>etcd</em> de un cluster puede realizarse por SSL, cifrando de esa forma todas las comunicaciones y aportando otra capa de seguridad al sistema.</p>
<p>Aunque podríamos montar el cluster utilizando únicamente HTTP, es muy sencillo generar unos certificados y configurar <em>etcd</em> para que los use, por lo que vamos a hacerlo de esta forma.</p>
<p>Lo primero que debemos hacer será generar los certificados que vamos a necesitar, que son:</p>
<ul>
<li><strong>Cliente</strong>: Este certificado es el que usaremos nosotros (o la aplicación que se vaya a conectar a <em>etcd</em>, como por ejemplo <em>Kubernetes</em>) para conectarnos al cluster.</li>
<li><strong>Servidor</strong>: Este certificado es el que usará cada uno de los nodos de nuestro cluster para cifrar las comunicaciones.</li>
<li><strong>Peer</strong> (<em>no se muy bien como traducirlo</em>): Este certificado es el que usará cada nodo para conectarse a los demás nodos del cluster (muy similar al certificado de cliente, pero generaremos ambos para diferenciar unas conexiones de otras).</li>
</ul>
<p>La explicación sobre el intercambio de certificados en una comunicación SSL, los tipos de certificados, su firma, etc. es algo que queda fuera del ámbito de este artículo por lo que no voy a explicarlo con demasiado detalle. Si alguno de estos conceptos no te queda claro, te recomiendo que investigues un poco acerca del funcionamiento de estos certificados (intentaré escribir otro artículo sobre SSL algún dia).</p>
<p>Para generar los certificados vamos a utilizar <a href="https://cfssl.org/"><code>cfssl</code></a>, que es una herramienta de código-abierto desarrollada por <a href="https://www.cloudflare.com/es/">CloudFlare</a> muy fácil de utilizar y que nos permite generar y firmar certificados desde la linea de comandos.</p>
<p>En lugar de ir nodo por nodo, vamos a instalar la herramienta en nuestra máquina local para generar los certificados, y una vez generados los copiaremos a los 3 nodos.</p>
<p>Como dije antes, en el momento de escribir este artículo la última versión de <code>cfssl</code> era la 1.2, por lo que os recomiendo que antes de instalarla comprobéis en su página (<a href="https://pkg.cfssl.org/">https://pkg.cfssl.org/</a>) que no haya ninguna versión más reciente, y en caso de haberla, cambiad las siguientes URLs según corresponda para poder instalar la aplicación actualizada:</p>
<div class="highlight"><pre><span></span><code>$ sudo curl -o /usr/local/bin/cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
$ sudo curl -o /usr/local/bin/cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
$ sudo chmod +x /usr/local/bin/cfssl*
</code></pre></div>
<p>Creamos un directorio en cualquier parte de nuestro disco duro (y nos situamos en él) para ir guardando los certificados de forma temporal hasta que los hayamos copiado a los nodos de nuestro cluster:</p>
<div class="highlight"><pre><span></span><code>$ mkdir <span class="nv">$HOME</span>/etcd-certs
$ <span class="nb">cd</span> <span class="nv">$HOME</span>/etcd-certs
</code></pre></div>
<p>Y ahora vamos creando los certificados necesarios:</p>
<h3>Certificado de la Autoridad de Certificación (CA)</h3>
<p>Primero, crearemos un archivo <code>JSON</code> llamado <code>ca-config.json</code> con la configuración de la <a href="https://es.wikipedia.org/wiki/Autoridad_de_certificaci%C3%B3n"><em>Autoridad de Certificación (CA)</em></a> que va a firmar los certificados que vamos a generar.</p>
<p>En él definiremos la expiración de los certificados, el uso que les vamos a dar (autenticación, firma, ...), etc:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">ca-config.json</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/ca-config.json'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">"signing"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"default"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"expiry"</span><span class="p">:</span><span class="s2">"43800h"</span>
<span class="p">},</span>
<span class="nt">"profiles"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"server"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"expiry"</span><span class="p">:</span><span class="s2">"43800h"</span><span class="p">,</span>
<span class="nt">"usages"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"signing"</span><span class="p">,</span>
<span class="s2">"key encipherment"</span><span class="p">,</span>
<span class="s2">"server auth"</span><span class="p">,</span>
<span class="s2">"client auth"</span>
<span class="p">]</span>
<span class="p">},</span>
<span class="nt">"client"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"expiry"</span><span class="p">:</span><span class="s2">"43800h"</span><span class="p">,</span>
<span class="nt">"usages"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"signing"</span><span class="p">,</span>
<span class="s2">"key encipherment"</span><span class="p">,</span>
<span class="s2">"client auth"</span>
<span class="p">]</span>
<span class="p">},</span>
<span class="nt">"peer"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"expiry"</span><span class="p">:</span><span class="s2">"43800h"</span><span class="p">,</span>
<span class="nt">"usages"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"signing"</span><span class="p">,</span>
<span class="s2">"key encipherment"</span><span class="p">,</span>
<span class="s2">"server auth"</span><span class="p">,</span>
<span class="s2">"client auth"</span>
<span class="p">]</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Después crearemos otro archivo llamado <code>ca-csr.json</code> donde irá la configuración de la <a href="https://es.wikipedia.org/wiki/Autoridad_de_certificaci%C3%B3n#Solicitud_de_un_certificado"><em>solicitud de certificación (CSR)</em></a>, donde indicaremos el algoritmo de cifrado que queremos utilizar, la longitud de la clave, los datos del certificado, etc:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">ca-csr.json</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/ca-csr.json'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">"CN"</span><span class="p">:</span><span class="s2">"etcd"</span><span class="p">,</span>
<span class="nt">"key"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"algo"</span><span class="p">:</span><span class="s2">"rsa"</span><span class="p">,</span>
<span class="nt">"size"</span><span class="p">:</span><span class="mi">2048</span>
<span class="p">},</span>
<span class="nt">"names"</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span>
<span class="nt">"C"</span><span class="p">:</span><span class="s2">"ES"</span><span class="p">,</span>
<span class="nt">"L"</span><span class="p">:</span><span class="s2">"Madrid"</span><span class="p">,</span>
<span class="nt">"O"</span><span class="p">:</span><span class="s2">"PornoHardware S.L.U."</span><span class="p">,</span>
<span class="nt">"OU"</span><span class="p">:</span><span class="s2">"Tech department"</span><span class="p">,</span>
<span class="nt">"ST"</span><span class="p">:</span><span class="s2">"Spain"</span>
<span class="p">}</span>
<span class="p">]</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Generamos los certificados de nuestra <em>Autoridad de Certificación</em>:</p>
<div class="highlight"><pre><span></span><code>$ cfssl gencert -initca ca-csr.json <span class="p">|</span> cfssljson -bare ca -
</code></pre></div>
<p>Una vez ejecutado el comando habremos obtenido 3 nuevos archivos:</p>
<ul>
<li><code>ca.csr</code>: La <em>petición</em> de generación de certificado.</li>
<li><code>ca.pem</code>: El certificado <em>raíz</em>.</li>
<li><code>ca-key.pem</code>: La <em>clave</em> del certificado <em>raíz</em>.</li>
</ul>
<p>Ya tenemos nuestro certificado <em>raíz</em>, vamos a seguir con los demas...</p>
<h3>Certificado de cliente</h3>
<p>Este certificado es el que usaremos nosotros mismos para conectarnos al cluster y lanzar los comandos que queramos ejecutar de forma segura.</p>
<p>Creamos el archivo <code>client.json</code>:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">client.json</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/client.json'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">"CN"</span><span class="p">:</span> <span class="s2">"client"</span><span class="p">,</span>
<span class="nt">"key"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"algo"</span><span class="p">:</span> <span class="s2">"ecdsa"</span><span class="p">,</span>
<span class="nt">"size"</span><span class="p">:</span> <span class="mi">256</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Y utilizando el recién creado certificado <em>raíz</em> y la configuración que habíamos definido al principio, generamos el certificado de cliente:</p>
<div class="highlight"><pre><span></span><code>$ cfssl gencert -ca<span class="o">=</span>ca.pem -ca-key<span class="o">=</span>ca-key.pem -config<span class="o">=</span>ca-config.json -profile<span class="o">=</span>client client.json <span class="p">|</span> cfssljson -bare client
</code></pre></div>
<p>Una vez ejecutado el comando habremos obtenido 3 nuevos archivos:</p>
<ul>
<li><code>client.csr</code>: La <em>petición</em> de generación de certificado.</li>
<li><code>client.pem</code>: El certificado de cliente.</li>
<li><code>client-key.pem</code>: La <em>clave</em> del certificado de cliente.</li>
</ul>
<h3>Certificados <em>peer</em> y de servidor</h3>
<p>Cada uno de los nodos necesita también un certificado para cifrar las conexiones que los demás nodos se hagan entre si (peer). Este certificado necesita generarse para un nombre de host y una IP en concreto (la de cada servidor), por lo tanto necesitamos generar 3 certificados diferentes (uno para cada nodo de nuestro cluster).</p>
<p>Creamos <strong>un archivo de configuración por cada nodo</strong>, donde indicaremos el nombre del servidor y su IP, entre otras cosas:</p>
<p>Para el nodo 1:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">config-etcd01.json</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/config-etcd01.json'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">"CN"</span><span class="p">:</span> <span class="s2">"etcd01"</span><span class="p">,</span>
<span class="nt">"hosts"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"etcd01"</span><span class="p">,</span>
<span class="s2">"etcd01.local"</span><span class="p">,</span>
<span class="s2">"192.168.1.83"</span>
<span class="p">],</span>
<span class="nt">"key"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"algo"</span><span class="p">:</span> <span class="s2">"ecdsa"</span><span class="p">,</span>
<span class="nt">"size"</span><span class="p">:</span> <span class="mi">256</span>
<span class="p">},</span>
<span class="nt">"names"</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span>
<span class="nt">"C"</span><span class="p">:</span> <span class="s2">"ES"</span><span class="p">,</span>
<span class="nt">"L"</span><span class="p">:</span> <span class="s2">"Madrid"</span><span class="p">,</span>
<span class="nt">"ST"</span><span class="p">:</span> <span class="s2">"Spain"</span>
<span class="p">}</span>
<span class="p">]</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Para el nodo 2:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">config-etcd02.json</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/config-etcd02.json'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">"CN"</span><span class="p">:</span> <span class="s2">"etcd02"</span><span class="p">,</span>
<span class="nt">"hosts"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"etcd02"</span><span class="p">,</span>
<span class="s2">"etcd02.local"</span><span class="p">,</span>
<span class="s2">"192.168.1.84"</span>
<span class="p">],</span>
<span class="nt">"key"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"algo"</span><span class="p">:</span> <span class="s2">"ecdsa"</span><span class="p">,</span>
<span class="nt">"size"</span><span class="p">:</span> <span class="mi">256</span>
<span class="p">},</span>
<span class="nt">"names"</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span>
<span class="nt">"C"</span><span class="p">:</span> <span class="s2">"ES"</span><span class="p">,</span>
<span class="nt">"L"</span><span class="p">:</span> <span class="s2">"Madrid"</span><span class="p">,</span>
<span class="nt">"ST"</span><span class="p">:</span> <span class="s2">"Spain"</span>
<span class="p">}</span>
<span class="p">]</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Para el nodo 3:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">config-etcd03.json</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/config-etcd03.json'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">"CN"</span><span class="p">:</span> <span class="s2">"etcd03"</span><span class="p">,</span>
<span class="nt">"hosts"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"etcd03"</span><span class="p">,</span>
<span class="s2">"etcd03.local"</span><span class="p">,</span>
<span class="s2">"192.168.1.85"</span>
<span class="p">],</span>
<span class="nt">"key"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"algo"</span><span class="p">:</span> <span class="s2">"ecdsa"</span><span class="p">,</span>
<span class="nt">"size"</span><span class="p">:</span> <span class="mi">256</span>
<span class="p">},</span>
<span class="nt">"names"</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span>
<span class="nt">"C"</span><span class="p">:</span> <span class="s2">"ES"</span><span class="p">,</span>
<span class="nt">"L"</span><span class="p">:</span> <span class="s2">"Madrid"</span><span class="p">,</span>
<span class="nt">"ST"</span><span class="p">:</span> <span class="s2">"Spain"</span>
<span class="p">}</span>
<span class="p">]</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Como todos los certificados que vamos a generar tendrán el mismo nombre (<code>server.pem</code>, <code>server-key.pem</code>, ...) independientemente del nodo al que correspondan, vamos a crear un subdirectorio por cada nodo y a generar los certificados de cada uno de ellos en su respectivo directorio.</p>
<p>Creamos el subdirectorio, entramos en él, generamos los certificados (tanto los de servidor como los <em>peer</em>) y continuamos con el siguiente sucesivamente hasta que hayamos generado los certificados de los 3 servidores:</p>
<div class="highlight"><pre><span></span><code>$ mkdir <span class="nv">$HOME</span>/etcd-certs/etcd01
$ <span class="nb">cd</span> <span class="nv">$HOME</span>/etcd-certs/etcd01
$ cfssl gencert -ca<span class="o">=</span>../ca.pem -ca-key<span class="o">=</span>../ca-key.pem -config<span class="o">=</span>../ca-config.json -profile<span class="o">=</span>server ../config-etcd01.json <span class="p">|</span> cfssljson -bare server
$ cfssl gencert -ca<span class="o">=</span>../ca.pem -ca-key<span class="o">=</span>../ca-key.pem -config<span class="o">=</span>../ca-config.json -profile<span class="o">=</span>peer ../config-etcd01.json <span class="p">|</span> cfssljson -bare peer
$ mkdir <span class="nv">$HOME</span>/etcd-certs/etcd02
$ <span class="nb">cd</span> <span class="nv">$HOME</span>/etcd-certs/etcd02
$ cfssl gencert -ca<span class="o">=</span>../ca.pem -ca-key<span class="o">=</span>../ca-key.pem -config<span class="o">=</span>../ca-config.json -profile<span class="o">=</span>server ../config-etcd02.json <span class="p">|</span> cfssljson -bare server
$ cfssl gencert -ca<span class="o">=</span>../ca.pem -ca-key<span class="o">=</span>../ca-key.pem -config<span class="o">=</span>../ca-config.json -profile<span class="o">=</span>peer ../config-etcd02.json <span class="p">|</span> cfssljson -bare peer
$ mkdir <span class="nv">$HOME</span>/etcd-certs/etcd03
$ <span class="nb">cd</span> <span class="nv">$HOME</span>/etcd-certs/etcd03
$ cfssl gencert -ca<span class="o">=</span>../ca.pem -ca-key<span class="o">=</span>../ca-key.pem -config<span class="o">=</span>../ca-config.json -profile<span class="o">=</span>server ../config-etcd03.json <span class="p">|</span> cfssljson -bare server
$ cfssl gencert -ca<span class="o">=</span>../ca.pem -ca-key<span class="o">=</span>../ca-key.pem -config<span class="o">=</span>../ca-config.json -profile<span class="o">=</span>peer ../config-etcd03.json <span class="p">|</span> cfssljson -bare peer
</code></pre></div>
<p>Una vez ejecutados todos los comandos habremos obtenido 6 nuevos archivos en cada subdirectorio:</p>
<ul>
<li><code>peer.csr</code>: La <em>petición</em> de generación de certificado.</li>
<li><code>peer.pem</code>: El certificado <em>peer</em>.</li>
<li><code>peer-key.pem</code>: La <em>clave</em> del certificado <em>peer</em>.</li>
<li><code>server.csr</code>: La <em>petición</em> de generación de certificado.</li>
<li><code>server.pem</code>: El certificado de servidor.</li>
<li><code>server-key.pem</code>: La <em>clave</em> del certificado de servidor.</li>
</ul>
<p>Si todo ha ido bien, ahora deberíamos tener todos los certificados necesarios para nuestro cluster generados en <code>$HOME/etcd-certs/</code>, por lo que deberíamos tener algo parecido a ésto:</p>
<div class="highlight"><pre><span></span><code><span class="err">├─ $HOME/etcd-certs/</span>
<span class="err">│ ├─ ca.csr</span>
<span class="err">│ ├─ ca.pem</span>
<span class="err">│ ├─ ca-config.json</span>
<span class="err">│ ├─ ca-csr.json</span>
<span class="err">│ ├─ ca-key.pem</span>
<span class="err">│ ├─ client.csr</span>
<span class="err">│ ├─ client.json</span>
<span class="err">│ ├─ client.pem</span>
<span class="err">│ ├─ client-key.pem</span>
<span class="err">│ ├─ config-etcd01.json</span>
<span class="err">│ ├─ config-etcd02.json</span>
<span class="err">│ ├─ config-etcd02.json</span>
<span class="err">│ ├─ etcd01/</span>
<span class="err">│ │ ├─ peer.csr</span>
<span class="err">│ │ ├─ peer.pem</span>
<span class="err">│ │ ├─ peer-key.pem</span>
<span class="err">│ │ ├─ server.csr</span>
<span class="err">│ │ ├─ server.pem</span>
<span class="err">│ │ └─ server-key.pem</span>
<span class="err">│ ├─ etcd02/</span>
<span class="err">│ │ ├─ peer.csr</span>
<span class="err">│ │ ├─ peer.pem</span>
<span class="err">│ │ ├─ peer-key.pem</span>
<span class="err">│ │ ├─ server.csr</span>
<span class="err">│ │ ├─ server.pem</span>
<span class="err">│ │ └─ server-key.pem</span>
<span class="err">│ └─ etcd03/</span>
<span class="err">│ ├─ peer.csr</span>
<span class="err">│ ├─ peer.pem</span>
<span class="err">│ ├─ peer-key.pem</span>
<span class="err">│ ├─ server.csr</span>
<span class="err">│ ├─ server.pem</span>
<span class="err">│ └─ server-key.pem</span>
</code></pre></div>
<p>Ya tenemos todos los archivos que necesitamos para poder configurar nuestro cluster de <em>etcd</em> utilizando SSL, por lo que ya solo nos queda copiarlos a cada uno de los nodos.</p>
<p>No hace falta que copiemos todos los archivos a cada nodo, únicamente vamos a necesitar estos:</p>
<ul>
<li><code>ca.pem</code></li>
<li><code>client.pem</code></li>
<li><code>client-key.pem</code></li>
</ul>
<p>Y para cada uno de los nodos únicamente los de su respectivo subdirectorio:</p>
<ul>
<li><code>etcdXX/server.pem</code></li>
<li><code>etcdXX/server-key.pem</code></li>
<li><code>etcdXX/peer.pem</code></li>
<li><code>etcdXX/peer-key.pem</code></li>
</ul>
<p>Como ya comenté antes, en mi caso estoy montando este cluster de <em>etcd</em> para su uso con Kubernetes por lo que voy a copiar los certificados al directorio <code>/etc/kubernetes/pki/etcd</code> de cada nodo, pero vosotros podéis copiarlos al directorio que queráis (<code>/etc/etcd/certs</code>, por ejemplo).</p>
<p>Una vez copiados estos 7 archivos a cada nodo ya podemos empezar con la configuración del cluster.</p>
<p><em>Importante: Aunque no todos los archivos generados hacen falta os recomiendo que los guardéis igualmente (sobre todo los archivos de configuración) por si en un futuro necesitáis volver a generar los certificados de alguno de los servidores o generar nuevos certificados para un nuevo nodo con el que ampliar el cluster.</em></p>
<h2>Instalación y configuración del cluster<a name="install"></a></h2>
<p>Antes de nada, si los nodos que vas a utilizar para el cluster tienen algún <em>firewall</em> configurado, debemos abrir los puertos necesarios para poder conectarnos.</p>
<p><em>Etcd</em> utiliza estos puertos por defecto:</p>
<ul>
<li><strong>2379</strong>: Para las conexiones de los clientes</li>
<li><strong>2380</strong>: Para las conexiones entre los demás nodos del cluster</li>
</ul>
<p>Por lo tanto debemos asegurarnoss de que podemos conectarnos al puerto 2380 de cualquier nodo desde cualquier nodo y al puerto 2379 de cualquier nodo desde donde vayamos a hacer peticiones al cluster.</p>
<p>Es importante comprobar que no tengamos en nuestros nodos ninguna versión de <em>etcd</em> ya instalada. Si es así, hay que desinstalarla primero.</p>
<p>Antes de instalar una nueva versión de <em>etcd</em> tenemos que saber cuál es esa última versión, por lo que vamos a la zona de <em>releases</em> de su página de Github (<a href="https://github.com/coreos/etcd/releases">https://github.com/coreos/etcd/releases</a>) y lo comprobamos.</p>
<p>En este momento la última versión es la 3.3.4, por lo que descargamos e instalamos dicha versión <strong>en cada uno de los nodos</strong> de nuestro cluster:</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">export</span> <span class="nv">VERSION</span><span class="o">=</span>v3.3.4
$ curl -sSL https://github.com/coreos/etcd/releases/download/<span class="nv">$VERSION</span>/etcd-<span class="nv">$VERSION</span>-linux-amd64.tar.gz <span class="p">|</span> sudo tar -xzv --strip-components<span class="o">=</span><span class="m">1</span> -C /usr/local/bin/
</code></pre></div>
<p>Ahora que ya tenemos <em>etcd</em> instalado en los 3 nodos, vamos a configurarlo.</p>
<p>Creamos un archivo <code>/etc/etdc.env</code> en <strong>cada uno de los nodos</strong> con el nombre e IP de cada servidor:</p>
<p>Para el nodo 1:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">/etc/etcd.env</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/etcd01/etcd.env'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="na">PEER_NAME</span><span class="o">=</span><span class="s">etcd01</span>
<span class="na">PRIVATE_IP</span><span class="o">=</span><span class="s">192.168.1.83</span>
</code></pre></div>
</figure>
<p>Para el nodo 2:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">/etc/etcd.env</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/etcd02/etcd.env'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="na">PEER_NAME</span><span class="o">=</span><span class="s">etcd02</span>
<span class="na">PRIVATE_IP</span><span class="o">=</span><span class="s">192.168.1.84</span>
</code></pre></div>
</figure>
<p>Para el nodo 3:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">/etc/etcd.env</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/etcd03/etcd.env'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="na">PEER_NAME</span><span class="o">=</span><span class="s">etcd03</span>
<span class="na">PRIVATE_IP</span><span class="o">=</span><span class="s">192.168.1.85</span>
</code></pre></div>
</figure>
<p>Ahora vamos a crear los archivos de configuración de <a href="https://freedesktop.org/wiki/Software/systemd/">systemd</a> para que podamos arrancar, reiniciar y parar el servicio de <em>etcd</em> como haríamos con cualquier otro servicio.</p>
<p>Para eso, creamos un archivo <code>/etc/systemd/system/etcd.service</code> en <strong>cada uno de los nodos</strong>, indicando los argumentos que se le pasarán al programa <em>etcd</em> cuando arranque, y que son básicamente el nombre e IP del servidor, el nombre e IP de los demás nodos del cluster, la ruta a los certificados que generamos en el paso anterior, etc.</p>
<p>El archivo quedaría más o menos así para el nodo 1:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">/etc/systemd/system/etcd.service</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/etcd01/etcd.service'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="k">[Unit]</span>
<span class="na">Description</span><span class="o">=</span><span class="s">etcd</span>
<span class="na">Documentation</span><span class="o">=</span><span class="s">https://github.com/coreos/etcd</span>
<span class="na">Conflicts</span><span class="o">=</span><span class="s">etcd.service</span>
<span class="na">Conflicts</span><span class="o">=</span><span class="s">etcd2.service</span>
<span class="k">[Service]</span>
<span class="na">EnvironmentFile</span><span class="o">=</span><span class="s">/etc/etcd.env</span>
<span class="na">Type</span><span class="o">=</span><span class="s">notify</span>
<span class="na">Restart</span><span class="o">=</span><span class="s">always</span>
<span class="na">RestartSec</span><span class="o">=</span><span class="s">5s</span>
<span class="na">LimitNOFILE</span><span class="o">=</span><span class="s">40000</span>
<span class="na">TimeoutStartSec</span><span class="o">=</span><span class="s">0</span>
<span class="na">ExecStart</span><span class="o">=</span><span class="s">/usr/local/bin/etcd \</span>
<span class="s"> --name etcd01 \</span>
<span class="s"> --data-dir /var/lib/etcd \</span>
<span class="s"> --initial-advertise-peer-urls https://192.168.1.83:2380 \</span>
<span class="s"> --listen-peer-urls https://192.168.1.83:2380 \</span>
<span class="s"> --listen-client-urls https://192.168.1.83:2379,https://127.0.0.1:2379 \</span>
<span class="s"> --advertise-client-urls https://192.168.1.83:2379 \</span>
<span class="s"> --initial-cluster-token etcd-cluster-1 \</span>
<span class="s"> --initial-cluster etcd01=https://192.168.1.83:2380,etcd02=https://192.168.1.84:2380,etcd03=https://192.168.1.85:2380 \</span>
<span class="s"> --initial-cluster-state new \</span>
<span class="s"> --cert-file=/etc/kubernetes/pki/etcd/server.pem \</span>
<span class="s"> --key-file=/etc/kubernetes/pki/etcd/server-key.pem \</span>
<span class="s"> --client-cert-auth \</span>
<span class="s"> --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem \</span>
<span class="s"> --peer-cert-file=/etc/kubernetes/pki/etcd/peer.pem \</span>
<span class="s"> --peer-key-file=/etc/kubernetes/pki/etcd/peer-key.pem \</span>
<span class="s"> --peer-client-cert-auth \</span>
<span class="s"> --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem</span>
<span class="k">[Install]</span>
<span class="na">WantedBy</span><span class="o">=</span><span class="s">multi-user.target</span>
</code></pre></div>
</figure>
<p>Para el nodo 2:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">/etc/systemd/system/etcd.service</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/etcd02/etcd.service'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="k">[Unit]</span>
<span class="na">Description</span><span class="o">=</span><span class="s">etcd</span>
<span class="na">Documentation</span><span class="o">=</span><span class="s">https://github.com/coreos/etcd</span>
<span class="na">Conflicts</span><span class="o">=</span><span class="s">etcd.service</span>
<span class="na">Conflicts</span><span class="o">=</span><span class="s">etcd2.service</span>
<span class="k">[Service]</span>
<span class="na">EnvironmentFile</span><span class="o">=</span><span class="s">/etc/etcd.env</span>
<span class="na">Type</span><span class="o">=</span><span class="s">notify</span>
<span class="na">Restart</span><span class="o">=</span><span class="s">always</span>
<span class="na">RestartSec</span><span class="o">=</span><span class="s">5s</span>
<span class="na">LimitNOFILE</span><span class="o">=</span><span class="s">40000</span>
<span class="na">TimeoutStartSec</span><span class="o">=</span><span class="s">0</span>
<span class="na">ExecStart</span><span class="o">=</span><span class="s">/usr/local/bin/etcd \</span>
<span class="s"> --name etcd02 \</span>
<span class="s"> --data-dir /var/lib/etcd \</span>
<span class="s"> --initial-advertise-peer-urls https://192.168.1.84:2380 \</span>
<span class="s"> --listen-peer-urls https://192.168.1.84:2380 \</span>
<span class="s"> --listen-client-urls https://192.168.1.84:2379,https://127.0.0.1:2379 \</span>
<span class="s"> --advertise-client-urls https://192.168.1.84:2379 \</span>
<span class="s"> --initial-cluster-token etcd-cluster-1 \</span>
<span class="s"> --initial-cluster etcd01=https://192.168.1.83:2380,etcd02=https://192.168.1.84:2380,etcd03=https://192.168.1.85:2380 \</span>
<span class="s"> --initial-cluster-state new \</span>
<span class="s"> --cert-file=/etc/kubernetes/pki/etcd/server.pem \</span>
<span class="s"> --key-file=/etc/kubernetes/pki/etcd/server-key.pem \</span>
<span class="s"> --client-cert-auth \</span>
<span class="s"> --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem \</span>
<span class="s"> --peer-cert-file=/etc/kubernetes/pki/etcd/peer.pem \</span>
<span class="s"> --peer-key-file=/etc/kubernetes/pki/etcd/peer-key.pem \</span>
<span class="s"> --peer-client-cert-auth \</span>
<span class="s"> --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem</span>
<span class="k">[Install]</span>
<span class="na">WantedBy</span><span class="o">=</span><span class="s">multi-user.target</span>
</code></pre></div>
</figure>
<p>Para el nodo 3:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">/etc/systemd/system/etcd.service</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/etcd03/etcd.service'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="k">[Unit]</span>
<span class="na">Description</span><span class="o">=</span><span class="s">etcd</span>
<span class="na">Documentation</span><span class="o">=</span><span class="s">https://github.com/coreos/etcd</span>
<span class="na">Conflicts</span><span class="o">=</span><span class="s">etcd.service</span>
<span class="na">Conflicts</span><span class="o">=</span><span class="s">etcd2.service</span>
<span class="k">[Service]</span>
<span class="na">EnvironmentFile</span><span class="o">=</span><span class="s">/etc/etcd.env</span>
<span class="na">Type</span><span class="o">=</span><span class="s">notify</span>
<span class="na">Restart</span><span class="o">=</span><span class="s">always</span>
<span class="na">RestartSec</span><span class="o">=</span><span class="s">5s</span>
<span class="na">LimitNOFILE</span><span class="o">=</span><span class="s">40000</span>
<span class="na">TimeoutStartSec</span><span class="o">=</span><span class="s">0</span>
<span class="na">ExecStart</span><span class="o">=</span><span class="s">/usr/local/bin/etcd \</span>
<span class="s"> --name etcd03 \</span>
<span class="s"> --data-dir /var/lib/etcd \</span>
<span class="s"> --initial-advertise-peer-urls https://192.168.1.85:2380 \</span>
<span class="s"> --listen-peer-urls https://192.168.1.85:2380 \</span>
<span class="s"> --listen-client-urls https://192.168.1.85:2379,https://127.0.0.1:2379 \</span>
<span class="s"> --advertise-client-urls https://192.168.1.85:2379 \</span>
<span class="s"> --initial-cluster-token etcd-cluster-1 \</span>
<span class="s"> --initial-cluster etcd01=https://192.168.1.83:2380,etcd02=https://192.168.1.84:2380,etcd03=https://192.168.1.85:2380 \</span>
<span class="s"> --initial-cluster-state new \</span>
<span class="s"> --cert-file=/etc/kubernetes/pki/etcd/server.pem \</span>
<span class="s"> --key-file=/etc/kubernetes/pki/etcd/server-key.pem \</span>
<span class="s"> --client-cert-auth \</span>
<span class="s"> --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem \</span>
<span class="s"> --peer-cert-file=/etc/kubernetes/pki/etcd/peer.pem \</span>
<span class="s"> --peer-key-file=/etc/kubernetes/pki/etcd/peer-key.pem \</span>
<span class="s"> --peer-client-cert-auth \</span>
<span class="s"> --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem</span>
<span class="k">[Install]</span>
<span class="na">WantedBy</span><span class="o">=</span><span class="s">multi-user.target</span>
</code></pre></div>
</figure>
<p>Ya solo nos queda reiniciar el demonio de <em>systemd</em> de cada nodo para que lea el archivo que acabamos de crear:</p>
<div class="highlight"><pre><span></span><code>$ sudo systemctl daemon-reload
</code></pre></div>
<p>Y ahora ya podemos gestionar el demonio de <em>etcd</em> con el comando <em>systemctl</em> o con <em>service</em>, por lo que vamos a levantar el proceso y a configurarlo para que se inicie automáticamente al arrancar el servidor:</p>
<div class="highlight"><pre><span></span><code>$ sudo systemctl <span class="nb">enable</span> etcd
$ sudo systemctl start etcd
</code></pre></div>
<p>Si todo ha ido bien, ahora mismo ya tendremos el servicio de <em>etcd</em> levantado, por lo que hacemos lo mismo en los otros 2 nodos.</p>
<blockquote>
<p>Si es la primera vez que estas levantando el servicio, hay veces en las que al invocar a <em>systemctl</em> se queda el proceso <em>esperando eternamente</em> (hasta que salta el <em>más-que-generoso-timeout(TM)</em>, me refiero). La mayoría de las veces se debe a que el proceso se demonio de <em>etcd</em> se inicia correctamente, pero se queda intentando conectarse con los otros 2 nodos del cluster, por lo que si aún no los hemos levantado, el proceso lo reintenta indefinidamente y parece que se queda <em>congelado</em>...
<br /><br />
En estos casos, puesto que el proceso se levanta correctamente, o bien sales con <code>CTRL</code> + <code>C</code>, o bien levantas los demonios en los otros 2 nodos.</p>
</blockquote>
<p>Puedes comprobar si el servicio se ha levantado correctamente con:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> sudo systemctl status etcd
<span class="go">- etcd.service - etcd</span>
<span class="go"> Loaded: loaded (/etc/systemd/system/etcd.service; enabled; vendor preset: enabled)</span>
<span class="go"> Active: active (running) since Tue 2018-05-06 00:21:53 CEST; 11s ago</span>
<span class="go"> Docs: https://github.com/coreos/etcd</span>
<span class="go"> Main PID: 9426 (etcd)</span>
<span class="go"> Tasks: 18 (limit: 4915)</span>
<span class="go"> Memory: 10.1M</span>
<span class="go"> CPU: 145ms</span>
<span class="go"> CGroup: /system.slice/etcd.service</span>
<span class="go"> └─9426 /usr/local/bin/etcd --name etcd01 --data-dir /var/lib/etcd --initial-advertise-peer-urls https://192.168.1.83:2380 --listen-peer-urls https://192.168.1.83:2380 --listen-client-urls https://192.168.1.83:2379,https://127.0.0.1:2379 --advertise-client-urls</span>
<span class="go">May 06 00:21:53 etcd01 etcd[20483]: established a TCP streaming connection with peer c37956d0928a73d9 (stream Message reader)</span>
<span class="go">May 06 00:21:53 etcd01 etcd[20483]: established a TCP streaming connection with peer c37956d0928a73d9 (stream MsgApp v2 reader)</span>
<span class="go">May 06 00:21:53 etcd01 etcd[20483]: raft.node: 1e9f81657a2688f9 elected leader b5a3b7906f500074 at term 1291</span>
<span class="go">May 06 00:21:53 etcd01 etcd[20483]: 1e9f81657a2688f9 initialzed peer connection; fast-forwarding 8 ticks (election ticks 10) with 2 active peer(s)</span>
<span class="go">May 06 00:21:53 etcd01 etcd[20483]: published {Name:etcd01 ClientURLs:["https://192.168.1.83:2379"]} to cluster e47a206dc7abb150</span>
<span class="go">May 06 00:21:53 etcd01 etcd[20483]: ready to serve client requests</span>
<span class="go">May 06 00:21:53 etcd01 etcd[20483]: ready to serve client requests</span>
<span class="go">May 06 00:21:53 etcd01 systemd[1]: Started etcd.</span>
<span class="go">May 06 00:21:53 etcd01 etcd[20483]: serving client requests on 127.0.0.1:2379</span>
<span class="go">May 06 00:21:53 etcd01 etcd[20483]: serving client requests on 192.168.1.83:2379</span>
</code></pre></div>
<p>Esto significa que ya tenemos nuestro cluster funcionando y aceptando conexiones por el puerto 2379!</p>
<h2>Administración básica<a name="admin"></a></h2>
<p>Ahora que ya tenemos el cluster funcionando, vamos a ver algunos comandos que nos serán de utilidad a la hora de administrar el cluster, comprobar su estado, añadir un nuevo nodo, etc.</p>
<p>Recuerda que hemos configurado nuestro cluster para usar SSL en cualquier conexión, por lo que necesitaremos el certificado de cliente en cualquier sitio desde el que nos queramos conectar al cluster.</p>
<p>Al servidor <em>etcd</em> se accede utilizando la API, como ya expliqué al principio del artículo, pero existe una utilidad llamada <code>etcdctl</code> que nos permite acceder a dicha API desde la linea de comandos. Vamos a ver sus opciones, pero antes tenemos que establecer la variable de sesión <code>ETCDCTL_API=3</code> ya que de lo contrario la utilidad nos mostrará opciones <em>obsoletas</em> (luego explicaré el tema de las variables de sesión):</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> <span class="nb">export</span> <span class="nv">ETCDCTL_API</span><span class="o">=</span><span class="m">3</span>
<span class="gp">$</span> etcdctl --help
<span class="go">NAME:</span>
<span class="go"> etcdctl - A simple command line client for etcd3.</span>
<span class="go">USAGE:</span>
<span class="go"> etcdctl</span>
<span class="go">VERSION:</span>
<span class="go"> 3.3.4</span>
<span class="go">API VERSION:</span>
<span class="go"> 3.3</span>
<span class="go">COMMANDS:</span>
<span class="go"> get Gets the key or a range of keys</span>
<span class="go"> put Puts the given key into the store</span>
<span class="go"> del Removes the specified key or range of keys [key, range_end)</span>
<span class="go"> txn Txn processes all the requests in one transaction</span>
<span class="go"> compaction Compacts the event history in etcd</span>
<span class="go"> alarm disarm Disarms all alarms</span>
<span class="go"> alarm list Lists all alarms</span>
<span class="go"> defrag Defragments the storage of the etcd members with given endpoints</span>
<span class="go"> endpoint health Checks the healthiness of endpoints specified in `--endpoints` flag</span>
<span class="go"> endpoint status Prints out the status of endpoints specified in `--endpoints` flag</span>
<span class="go"> endpoint hashkv Prints the KV history hash for each endpoint in --endpoints</span>
<span class="go"> move-leader Transfers leadership to another etcd cluster member.</span>
<span class="go"> watch Watches events stream on keys or prefixes</span>
<span class="go"> version Prints the version of etcdctl</span>
<span class="go"> lease grant Creates leases</span>
<span class="go"> lease revoke Revokes leases</span>
<span class="go"> lease timetolive Get lease information</span>
<span class="go"> lease list List all active leases</span>
<span class="go"> lease keep-alive Keeps leases alive (renew)</span>
<span class="go"> member add Adds a member into the cluster</span>
<span class="go"> member remove Removes a member from the cluster</span>
<span class="go"> member update Updates a member in the cluster</span>
<span class="go"> member list Lists all members in the cluster</span>
<span class="go"> snapshot save Stores an etcd node backend snapshot to a given file</span>
<span class="go"> snapshot restore Restores an etcd member snapshot to an etcd directory</span>
<span class="go"> snapshot status Gets backend snapshot status of a given file</span>
<span class="go"> make-mirror Makes a mirror at the destination etcd cluster</span>
<span class="go"> migrate Migrates keys in a v2 store to a mvcc store</span>
<span class="go"> lock Acquires a named lock</span>
<span class="go"> elect Observes and participates in leader election</span>
<span class="go"> auth enable Enables authentication</span>
<span class="go"> auth disable Disables authentication</span>
<span class="go"> user add Adds a new user</span>
<span class="go"> user delete Deletes a user</span>
<span class="go"> user get Gets detailed information of a user</span>
<span class="go"> user list Lists all users</span>
<span class="go"> user passwd Changes password of user</span>
<span class="go"> user grant-role Grants a role to a user</span>
<span class="go"> user revoke-role Revokes a role from a user</span>
<span class="go"> role add Adds a new role</span>
<span class="go"> role delete Deletes a role</span>
<span class="go"> role get Gets detailed information of a role</span>
<span class="go"> role list Lists all roles</span>
<span class="go"> role grant-permission Grants a key to a role</span>
<span class="go"> role revoke-permission Revokes a key from a role</span>
<span class="go"> check perf Check the performance of the etcd cluster</span>
<span class="go"> help Help about any command</span>
<span class="go">OPTIONS:</span>
<span class="go"> --cacert="" verify certificates of TLS-enabled secure servers using this CA bundle</span>
<span class="go"> --cert="" identify secure client using this TLS certificate file</span>
<span class="go"> --command-timeout=5s timeout for short running command (excluding dial timeout)</span>
<span class="go"> --debug[=false] enable client-side debug logging</span>
<span class="go"> --dial-timeout=2s dial timeout for client connections</span>
<span class="go"> -d, --discovery-srv="" domain name to query for SRV records describing cluster endpoints</span>
<span class="go"> --endpoints=[127.0.0.1:2379] gRPC endpoints</span>
<span class="go"> --hex[=false] print byte strings as hex encoded strings</span>
<span class="go"> --insecure-discovery[=true] accept insecure SRV records describing cluster endpoints</span>
<span class="go"> --insecure-skip-tls-verify[=false] skip server certificate verification</span>
<span class="go"> --insecure-transport[=true] disable transport security for client connections</span>
<span class="go"> --keepalive-time=2s keepalive time for client connections</span>
<span class="go"> --keepalive-timeout=6s keepalive timeout for client connections</span>
<span class="go"> --key="" identify secure client using this TLS key file</span>
<span class="go"> --user="" username[:password] for authentication (prompt if password is not supplied)</span>
<span class="go"> -w, --write-out="simple" set the output format (fields, json, protobuf, simple, table)</span>
</code></pre></div>
<p>Como puedes ver este comando tiene bastantes parámetros, por lo que vamos a echar un ojo a los más importantes:</p>
<ul>
<li><code>--endpoints</code>: Aqui debemos especificar todos los nodos de nuestro cluster (host y puerto) separados por comas, de forma que si uno de ellos estuviera caído nuestra consulta sería enviada de forma automática a otro de los nodos. Por ejemplo, en nuestro caso sería: <code>https://etcd01:2379,https://etcd02:2379,https://etcd03:2379</code>.</li>
<li><code>--cert</code>: La ruta del certificado de cliente que vamos a utilizar para conectarnos. En nuestro caso sería: <code>/etc/kubernetes/pki/etcd/client.pem</code>.</li>
<li><code>--key</code>: La ruta de la clave del certificado de cliente. En nuestro caso sería: <code>/etc/kubernetes/pki/etcd/client-key.pem</code>.</li>
<li><code>--cacert</code>: La ruta hacia la <em>entidad certificadora</em> con la que hemos generado los certificados. En nuestro caso sería: <code>/etc/kubernetes/pki/etcd/ca.pem</code>.</li>
<li><code>--write-out</code>: Aqui indicamos cómo queremos que nos devuelva al respuesta del comando que vamos a lanzar al cluster. Puede ser <code>simple</code>, <code>json</code>, <code>table</code>, etc.</li>
<li><code>--debug</code>: Con esta opción podemos ver las llamadas HTTP/HTTPS que se estan lanzando a la API del cluster para ejecutar el comando que vayamos a ejecutar. Muy util para depurar el proceso si tenemos algún problema con los datos que estamos obteniendo.</li>
</ul>
<p>Por comodidad, tener que estar introduciendo las rutas de todos los certificados y la lista de <em>endpoints</em> cada vez que lancemos un comando puede resultar una auténtica tortura. Por suerte, podemos definir una serie de variables de entorno que una vez definidas permitirán a <code>etcdctl</code> conocer el valor de todos estos parámetros sin que tengamos que estar tecleándolos constantemente. Estas variables son:</p>
<ul>
<li><code>ETCDCTL_CERT</code>: La ruta que pondríamos en el parámetro <code>--cert-file</code>.</li>
<li><code>ETCDCTL_KEY</code>: La ruta que pondríamos en el parámetro <code>--key-file</code>.</li>
<li><code>ETCDCTL_CACERT</code>: La ruta que pondríamos en el parámetro <code>--ca-file</code>.</li>
<li><code>ETCDCTL_ENDPOINTS</code>: La lista (separada por comas) de endpoints (host y puerto) de nuestro cluster.</li>
<li><code>ETCDCTL_API</code>: Versión de la API que queramos utilizar. Puede ser <code>2</code> o <code>3</code>.</li>
</ul>
<p>Una vez que hemos visto los parámetros, vamos con algunos de los comandos disponibles:</p>
<ul>
<li><code>get</code>: Devuelve el valor de una clave.</li>
<li><code>put</code>: Establece el valor de una clave.</li>
<li><code>endpoint health</code>: Muestra el estado de los nodos del cluster.</li>
<li><code>check perf</code>: Realiza un informe de rendimiento del cluster.</li>
<li>Etc... (esta vez me refiero a <em>etcétera</em>, no al nombre del programa del que estamos hablando xDDD)</li>
</ul>
<p>Vamos a probar alguno de ellos...</p>
<p>Nos conectamos a cualquiera de los nodos (por ejemplo al primero: <code>etcd01</code>) y definimos las variables de sesión con los valores necesarios para no tener que preocuparnos de ellos en cada ejecución del comando <code>etcdctl</code>:</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">export</span> <span class="nv">ETCDCTL_CERT</span><span class="o">=</span>/etc/kubernetes/pki/etcd/client.pem
$ <span class="nb">export</span> <span class="nv">ETCDCTL_KEY</span><span class="o">=</span>/etc/kubernetes/pki/etcd/client-key.pem
$ <span class="nb">export</span> <span class="nv">ETCDCTL_CACERT</span><span class="o">=</span>/etc/kubernetes/pki/etcd/ca.pem
$ <span class="nb">export</span> <span class="nv">ETCDCTL_ENDPOINTS</span><span class="o">=</span>https://etcd01:2379,https://etcd02:2379,https://etcd03:2379
$ <span class="nb">export</span> <span class="nv">ETCDCTL_API</span><span class="o">=</span><span class="m">3</span>
</code></pre></div>
<p>Ahora vamos a lanzar el comando <code>endpoint health</code> para ver <em>la salud</em> de nuestro recién creado cluster:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl endpoint health
<span class="go">https://etcd02:2379 is healthy: successfully committed proposal: took = 2.397419ms</span>
<span class="go">https://etcd01:2379 is healthy: successfully committed proposal: took = 1.535434ms</span>
<span class="go">https://etcd03:2379 is healthy: successfully committed proposal: took = 2.331939ms</span>
</code></pre></div>
<p>Que indica que los 3 nodos estan funcionando correctamente (<em>...is healthy</em>).</p>
<blockquote>
<p>Si en lugar del resultado os muestra algún error relacionado con los certificados significa que no habeis puesto bien las rutas de las variables de sesión, o que vuestro usuario no tiene permiso para leer dichos archivos.</p>
</blockquote>
<p>Ahora vamos a introducir una clave de prueba y su valor. Por ejemplo:</p>
<div class="highlight"><pre><span></span><code>$ etcdctl put clavePrueba <span class="s2">"Esto es una prueba"</span>
</code></pre></div>
<p>Leemos el valor de la clave <code>clavePrueba</code>:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl get clavePrueba
<span class="go">Esto es una prueba</span>
</code></pre></div>
<p>Vamos ahora con algo más <em>delicado</em>: gestionar nuevos nodos.
Supongamos que queremos añadir un nuevo nodo a nuestro cluster. Por comodidad y para <em>matar dos pájaros de un tiro</em> vamos primero a quitar uno de los nodos del cluster y luego lo volveremos a meter.</p>
<p>Con el comando <code>member list</code> vemos la lista de nodos que componen nuestro cluster, y el <a href="https://es.wikipedia.org/wiki/Identificador">ID</a> de cada uno de ellos:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl member list
<span class="go">b5a3b7906f500074, started, etcd01, https://192.168.1.83:2380, https://192.168.1.83:2379</span>
<span class="go">c37956d0928a73d9, started, etcd02, https://192.168.1.84:2380, https://192.168.1.84:2379</span>
<span class="go">1e9f81657a2688f9, started, etcd03, https://192.168.1.85:2380, https://192.168.1.85:2379</span>
</code></pre></div>
<p>Para eliminar uno de ellos, por ejemplo el nodo 3 (<code>etcd03</code>), ejecutamos el comando <code>member remove</code> indicando el ID del nodo que queremos eliminar de nuestro cluster:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl member remove 1e9f81657a2688f9
<span class="go">Member 1e9f81657a2688f9 removed from cluster e47a206dc7abb150</span>
</code></pre></div>
<p>Si volvemos a obtener la lista de nodos del cluster veremos que ya solo tenemos 2:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl member list
<span class="go">b5a3b7906f500074, started, etcd01, https://192.168.1.83:2380, https://192.168.1.83:2379</span>
<span class="go">c37956d0928a73d9, started, etcd02, https://192.168.1.84:2380, https://192.168.1.84:2379</span>
</code></pre></div>
<p>El procedimiento para añadir un nodo es tambien muy sencillo, pero si el nodo que queremos añadir ya ha formado parte de un cluster <em>etcd</em> anteriormente (como es nuestro caso ya que lo acabamos de eliminar ahora mismo) hay que hacer un par de cosas antes:</p>
<ul>
<li>Detener el servicio de <em>etcd</em> en el nuevo nodo que queremos añadir: <code>$ sudo systemctl stop etcd</code>.</li>
<li>Eliminar el directorio donde se guardan los datos de <em>etcd</em> para que al añadirlo al cluster se sincronice de nuevo con el resto de nodos: <code>$ sudo rm -rf /var/lib/etcd/member</code>.</li>
</ul>
<p>Una vez hecho esto, ya podemos continuar con el proceso para añadirlo a nuestro cluster.</p>
<p>Ejecutamos el comando <code>member add</code> junto con el nombre y el endpoint de <em>peer</em> del nuevo nodo que queremos añadir:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl member add etcd03 --peer-urls<span class="o">=</span><span class="s2">"https://192.168.1.85:2380"</span>
<span class="go">Member c398e05912695024 added to cluster e47a206dc7abb150</span>
<span class="go">ETCD_NAME="etcd03"</span>
<span class="go">ETCD_INITIAL_CLUSTER="etcd01=https://192.168.1.83:2380,etcd02=https://192.168.1.84:2380,etcd03=https://192.168.1.85:2380"</span>
<span class="go">ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.1.85:2380"</span>
<span class="go">ETCD_INITIAL_CLUSTER_STATE="existing"</span>
</code></pre></div>
<p>El comando muestra los datos del nuevo nodo que hemos añadido (nombre, endpoints, etc) así como su estado actual, que es <code>existing</code>. Esto significa que aunque el nodo se ha añadido al cluster, aún no está <em>operativo</em>. Podemos verlo si de nuevo volvemos a pedir el listado de nodos:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl member list
<span class="go">b5a3b7906f500074, started, etcd01, https://192.168.1.83:2380, https://192.168.1.83:2379</span>
<span class="go">c37956d0928a73d9, started, etcd02, https://192.168.1.84:2380, https://192.168.1.84:2379</span>
<span class="go">c398e05912695024, unstarted, , https://192.168.1.85:2380,</span>
</code></pre></div>
<p>Como ves, el nuevo nodo está <code>unstarted</code>, por lo que aún no está funcionando (como es lógico).</p>
<p>Para <em>iniciarlo</em>, nos conectamos a dicho nodo y editamos el archivo de configuración de <code>systemctl</code> del <em>etcd</em> (el archivo <code>/etc/systemd/system/etcd.service</code> que creamos cuando estábamos configurando el cluster). Tenemos que sustituir la linea <code>--initial-cluster-state new</code> por <code>--initial-cluster-state existing</code>, por lo que el archivo quedaría así:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">/etc/systemd/system/etcd.service</span><a href='/files/2018-05-06-alta-disponibilidad-en-etcd-desplegando-un-cluster-paso-a-paso/etcd03-new/etcd.service'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="k">[Unit]</span>
<span class="na">Description</span><span class="o">=</span><span class="s">etcd</span>
<span class="na">Documentation</span><span class="o">=</span><span class="s">https://github.com/coreos/etcd</span>
<span class="na">Conflicts</span><span class="o">=</span><span class="s">etcd.service</span>
<span class="na">Conflicts</span><span class="o">=</span><span class="s">etcd2.service</span>
<span class="k">[Service]</span>
<span class="na">EnvironmentFile</span><span class="o">=</span><span class="s">/etc/etcd.env</span>
<span class="na">Type</span><span class="o">=</span><span class="s">notify</span>
<span class="na">Restart</span><span class="o">=</span><span class="s">always</span>
<span class="na">RestartSec</span><span class="o">=</span><span class="s">5s</span>
<span class="na">LimitNOFILE</span><span class="o">=</span><span class="s">40000</span>
<span class="na">TimeoutStartSec</span><span class="o">=</span><span class="s">0</span>
<span class="na">ExecStart</span><span class="o">=</span><span class="s">/usr/local/bin/etcd \</span>
<span class="s"> --name etcd03 \</span>
<span class="s"> --data-dir /var/lib/etcd \</span>
<span class="s"> --initial-advertise-peer-urls https://192.168.1.85:2380 \</span>
<span class="s"> --listen-peer-urls https://192.168.1.85:2380 \</span>
<span class="s"> --listen-client-urls https://192.168.1.85:2379,https://127.0.0.1:2379 \</span>
<span class="s"> --advertise-client-urls https://192.168.1.85:2379 \</span>
<span class="s"> --initial-cluster-token etcd-cluster-1 \</span>
<span class="s"> --initial-cluster etcd01=https://192.168.1.83:2380,etcd02=https://192.168.1.84:2380,etcd03=https://192.168.1.85:2380 \</span>
<span class="s"> --initial-cluster-state existing \</span>
<span class="s"> --cert-file=/etc/kubernetes/pki/etcd/server.pem \</span>
<span class="s"> --key-file=/etc/kubernetes/pki/etcd/server-key.pem \</span>
<span class="s"> --client-cert-auth \</span>
<span class="s"> --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem \</span>
<span class="s"> --peer-cert-file=/etc/kubernetes/pki/etcd/peer.pem \</span>
<span class="s"> --peer-key-file=/etc/kubernetes/pki/etcd/peer-key.pem \</span>
<span class="s"> --peer-client-cert-auth \</span>
<span class="s"> --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem</span>
<span class="k">[Install]</span>
<span class="na">WantedBy</span><span class="o">=</span><span class="s">multi-user.target</span>
</code></pre></div>
</figure>
<p>Recargamos la configuración de <code>systemctl</code> e iniciamos el servicio de <em>etcd</em>:</p>
<div class="highlight"><pre><span></span><code>$ sudo systemctl daemon-reload
$ sudo systemctl start etcd
</code></pre></div>
<p>Al cabo de unos pocos segundos (dependiendo del tamaño de la base de datos de <em>etcd</em> que tengamos en nuestro cluster), el nuevo nodo se habrá sincronizado y si pedimos de nuevo la lista de nodos tendríamos que ver que el nuevo nodo ya está funcionando como los demás:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl member list
<span class="go">b5a3b7906f500074, started, etcd01, https://192.168.1.83:2380, https://192.168.1.83:2379</span>
<span class="go">c37956d0928a73d9, started, etcd02, https://192.168.1.84:2380, https://192.168.1.84:2379</span>
<span class="go">736e5742db963896, started, etcd03, https://192.168.1.85:2380, https://192.168.1.85:2379</span>
</code></pre></div>
<blockquote>
<p>Por coherencia con el resto de nodos, yo recomiendo que una vez se ha añadido el nuevo nodo al cluster y todo está funcionando, editemos de nuevo el archivo <code>/etc/systemd/system/etcd.service</code> y volvamos a cambiar el <code>--initial-cluster-state existing</code> por <code>--initial-cluster-state new</code> para dejarlo como estaba (igual que en el resto de nodos) pero realmente daría igual ya que una vez iniciado el servicio por primera vez, ese parámetro ya no se vuelve a tener en cuenta.</p>
</blockquote>
<p>Bueno, pues ya tenemos el cluster otra vez <em>completo</em>, ¿pero cómo sabemos que realmente esta funcionando en alta disponibilidad, y va a seguir haciéndolo aunque alguno de sus nodos se quede fuera de servicio? Vamos a comprobarlo:</p>
<p>Detenemos el servicio de <em>etcd</em> en el nodo 1 (<code>etcd01</code>):</p>
<div class="highlight"><pre><span></span><code>$ sudo systemctl stop etcd
</code></pre></div>
<p>Y volvemos a preguntar por el valor de la clave que guardamos antes:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl get clavePrueba
<span class="go">Esto es una prueba</span>
</code></pre></div>
<p>Como ves, obtenemos el valor de la clave sin problemas aún con el nodo 1 fuera de servicio.</p>
<p>Ahora, levantamos de nuevo el servicio <em>etcd</em> en el nodo 1, lo detenemos el nodo 2 y volvemos a preguntar por la clave (es importante que ANTES de detener el nodo 2 vuelvas a iniciar el nodo 1, ya que un cluster de 3 nodos puede <em>sobrevivir</em> si falla 1 nodo, pero no si fallan 2):</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl get clavePrueba
<span class="go">Esto es una prueba</span>
</code></pre></div>
<p>De nuevo sigue funcionando... así que vamos con la última prueba: levantamos de nuevo el servicio <em>etcd</em> en el nodo 2, lo detenemos en el nodo 3 y volvemos a preguntar por la clave:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> etcdctl get clavePrueba
<span class="go">Esto es una prueba</span>
</code></pre></div>
<p>Como ves, el cluster sigue funcionando aunque cualquiera de sus nodos deje de hacerlo.</p>
<p>Ya tienes tu cluster montado y funcionado, así que ya puedes empezar a utilizarlo sin problemas!</p>
<p>Como siempre, espero que el artículo os haya resultado de utilidad! Y por supuesto, no dudéis en distribuirlo y compartirlo con todo el mundo (pero por favor, citad siempre la fuente original de éste artículo).</p>
<p>Alaaaaaaaaaaaaaaaaaaaaaaa!</p>
<h2>Referencias<a name="refs"></a></h2>
<ul>
<li><a href="https://coreos.com/etcd">https://coreos.com/etcd</a></li>
<li><a href="https://github.com/coreos/etcd/tree/master/etcdctl">https://github.com/coreos/etcd/tree/master/etcdctl</a></li>
<li><a href="https://github.com/coreos/etcd/blob/master/Documentation/faq.md">https://github.com/coreos/etcd/blob/master/Documentation/faq.md</a></li>
<li><a href="https://github.com/coreos/etcd/blob/master/Documentation/op-guide/configuration.md">https://github.com/coreos/etcd/blob/master/Documentation/op-guide/configuration.md</a></li>
<li><a href="https://blog.cloudflare.com/introducing-cfssl">https://blog.cloudflare.com/introducing-cfssl</a></li>
</ul>Implementa tests en tus roles de Ansible con Molecule2018-03-12T16:12:40+01:002018-03-12T16:12:40+01:00BhEaNtag:pornohardware.com,2018-03-12:/2018/03/12/implementa-tests-en-tus-roles-de-ansible-con-molecule/<p>Hoy en dia nadie concibe (o nadie debería concebir, mejor dicho) empezar un proyecto de programación sin sus correspondientes tests. Tranquilidad en el desarrollo, código más robusto, anticiparnos a los errores, etc. son algunas de las <em>maravillas</em> que nos ofrece el mundo del <em>testing</em>, así que si tiene tantas ventajas... ¿porqué no íbamos a aplicarlo también a otros ámbitos que no sean exclusivamente los de la programación?</p>
<p><a href="https://www.ansible.com/">Ansible</a> es una de esas herramientas indispensables para cualquiera que administre servidores, automatizando la instalación de nuevos servicios, el despliegue de aplicaciones, configuraciones, etc. permitiendo que llevemos a cabo todas esas tareas de forma sencilla, rápida y automatizada ya sea en un servidor, en diez o en miles de ellos mediante la creación de <a href="https://docs.ansible.com/ansible/latest/playbooks_reuse_roles.html"><em>roles</em></a>.</p>
<p>En este artículo voy a explicar cómo implementar el <em>framework</em> <a href="https://molecule.readthedocs.io">Molecule</a> en dichos roles para poder testear su sintaxis, su <a href="https://es.wikipedia.org/wiki/Idempotencia">idempotencia</a> (me encanta esta palabra) y su ejecución en diferentes instancias con diferentes sistemas operativos y configuraciones.</p>
<p>Hoy en dia nadie concibe (o nadie debería concebir, mejor dicho) empezar un proyecto de programación sin sus correspondientes tests. Tranquilidad en el desarrollo, código más robusto, anticiparnos a los errores, etc. son algunas de las <em>maravillas</em> que nos ofrece el mundo del <em>testing</em>, así que si tiene tantas ventajas... ¿porqué no íbamos a aplicarlo también a otros ámbitos que no sean exclusivamente los de la programación?</p>
<p><a href="https://www.ansible.com/">Ansible</a> es una de esas herramientas indispensables para cualquiera que administre servidores, automatizando la instalación de nuevos servicios, el despliegue de aplicaciones, configuraciones, etc. permitiendo que llevemos a cabo todas esas tareas de forma sencilla, rápida y automatizada ya sea en un servidor, en diez o en miles de ellos mediante la creación de <a href="https://docs.ansible.com/ansible/latest/playbooks_reuse_roles.html"><em>roles</em></a>.</p>
<p>En este artículo voy a explicar cómo implementar el <em>framework</em> <a href="https://molecule.readthedocs.io">Molecule</a> en dichos roles para poder testear su sintaxis, su <a href="https://es.wikipedia.org/wiki/Idempotencia">idempotencia</a> (me encanta esta palabra) y su ejecución en diferentes instancias con diferentes sistemas operativos y configuraciones.</p>
<p>Me voy a extender bastante en este artículo ya que una vez que conozcas y entiendas Molecule verás que realmente es muy sencillo y su utilización no tiene demasiada complicación, pero si es la primera vez que te encuentras con este framework hay pequeñas (pero muchas) cosas que hay que entender para poder aprovecharlo al 100%.</p>
<p>Quiero dejar claro que éste artículo es sobre Molecule, no sobre Ansible... por lo que doy por hecho que ya conoces Ansible, sabes en qué consisten sus roles, cómo utilizarlos, etc.</p>
<p>Si este no es tu caso, seguramente este artículo no te será de mucha ayuda así que quizás deberías ponerte a <em>enredar</em> con Ansible primero (intentaré escribir un artículo sobre Ansible algún dia).</p>
<p>Aclarado este punto, comencemos:</p>
<ol>
<li><a href="#whatis">¿Qué es Molecule?</a></li>
<li><a href="#install">Instalación inicial del framework</a></li>
<li><a href="#configure">Configuración y ejecución de tests</a></li>
<li><a href="#refs">Referencias</a></li>
</ol>
<h2>¿Qué es Molecule?<a name="whatis"></a></h2>
<p>Según lo definen en su <a href="https://molecule.readthedocs.io">propia página web</a>, Molecule es un <a href="https://es.wikipedia.org/wiki/Framework">framework</a> que facilita el desarrollo y los tests de los roles de Ansible. Permite la realización de tests con múltiples instancias, sistemas operativos, proveedores de virtualización, escenarios, etc.</p>
<p><img class="left" src="/images/logos/logo_molecule.png">
Molecule se encarga de que los roles que hagamos estén bien escritos, sean mantenibles, fácilmente entendibles y de que el resultado de su ejecución sea el esperado.</p>
<p>Es decir, Molecule nos provee de la infraestructura necesaria para poder <em>lanzar</em> nuestros roles en diferentes escenarios, comprobar su funcionamiento, asegurarnos de que cumplen las reglas de estilo que queremos, etc.</p>
<p>Disponemos de varios <em>drivers</em> con los que ejecutar los tests. Uno de los más interesantes es el de <a href="https://www.docker.com/">Docker</a> ya que a través de este driver Molecule puede levantar contenedores con cualquier sistema operativo o configuración y ejecutar en ellos nuestros roles de Ansible para asegurarnos de que funcionan correctamente en cualquier sistema operativo o versión.</p>
<p>Aparte de esto, Molecule cuenta también con otras funcionalidades que nos ayudan con el correcto desarrollo de nuestros roles de Ansible, como por ejemplo:</p>
<ul>
<li><strong>Analizador <em>Linter</em></strong>: Molecule dispone de varios <a href="https://es.wikipedia.org/wiki/Lint">lints</a> que se encargarán de comprobar que la sintaxis de nuestros roles sea correcta, que su código cumpla con los estándares de estilo que hayamos definido, etc.</li>
<li><strong>Comprobación de idempotencia</strong>: Uno de los fundamentos básicos de Ansible es la idempotencia, es decir, que podamos ejecutar un role o tarea tantas veces como queramos y que el resultado de todas esas ejecuciones sea el mismo que si únicamente lo hubiéramos ejecutado una vez.</li>
<li><strong>Ejecución de roles en diferentes entornos</strong>: Como os comentaba antes, según el driver que utilicemos Molecule puede ejecutar los roles en diferentes contenedores de Docker, en entornos Cloud, máquinas virtuales, etc.</li>
<li><strong>Verificación de resultados</strong>: Molecule puede ejecutar diferentes scripts una vez terminada la ejecución de nuestros roles para comprobar que efectivamente han hecho lo que se supone que debían hacer. La forma más común de hacerlo es mediante <a href="https://testinfra.readthedocs.io/">Testinfra</a>, una serie de scripts que podemos realizar para comprobar en qué estado está nuestro servidor después de la ejecución de un role de Ansible.</li>
</ul>
<p>Ahora que ya sabemos más o menos de qué va la cosa, vamos a ver cómo se utiliza.</p>
<h2>Instalación inicial del framework<a name="install"></a></h2>
<p>Podemos instalar Molecule utilizando el gestor de paquetes de nuestra distribución (<a href="https://manpages.debian.org/stretch/apt/apt.8.en.html">apt</a>, <a href="https://www.centos.org/docs/5/html/yum/">yum</a>, etc) pero (al igual que Ansible) Molecule está escrito en <a href="https://www.python.org/">Python</a>, por lo que personalmente recomiendo su instalación utilizando <code>pip</code> dentro de un <code>virtualenv</code>.</p>
<p>Tanto <a href="https://pypi.python.org/pypi/pip/">pip</a> como <a href="https://pypi.python.org/pypi/virtualenv/">virtualenv</a> son dos aplicaciones completamente indispensables en el mundo de Python por lo que supongo que las conocerás bien, pero por si acaso:</p>
<ul>
<li><strong>pip</strong>: Se trata de un gestor de paquetes de Python. Podríamos decir que <code>pip</code> es a Python lo que <code>apt</code> es a <a href="https://www.debian.org/index.es.html">Debian</a> o lo que <code>yum</code> es a <a href="https://www.centos.org/">CentOS</a>. Tienes toda la información sobre esta aplicación aquí: <a href="https://pip.pypa.io/en/stable/">https://pip.pypa.io/en/stable/</a>.</li>
<li><strong>virtualenv</strong>: Python es un lenguaje genial, muy potente y versátil... pero debido a sus múltiples versiones, a sus incompatibilidades entre ellas, a su ingente cantidad de librerías, etc, etc. a veces es una locura disponer de todos los paquetes y librerías que necesitamos en nuestro proyecto. Para solucionar estos problemas nació <code>virtualenv</code>, una herramienta que permite gestionar entornos virtuales de Python. Dentro de estos entornos podemos instalar las librerías de Python que queramos, módulos, etc. y estarán disponibles y accesibles únicamente desde dicho entorno, por lo que cuando salgamos de él, todo lo que hubiéramos instalado dejará de estar disponible para el resto del sistema. De esta forma podemos crear un <em>entorno virtual</em> para nuestro proyecto e instalar en él las librerías necesarias sin que éstas afecten a las del resto del sistema (ni las del resto del sistema a nuestro entorno, por supuesto). Tienes toda la información sobre <code>virtualenv</code> aquí: <a href="https://virtualenv.pypa.io/en/stable/">https://virtualenv.pypa.io/en/stable/</a>, pero no te preocupes si es la primera vez que lo ves y todavía no lo tienes claro, lo veremos más en detalle un poco más adelante.</li>
</ul>
<p>Por lo tanto, aunque podrías simplemente ejecutar <code>apt-get install molecule</code> desde tu flamante Debian, es mejor mantener el sistema <em>limpio</em> e instalar Molecule y el resto de paquetes necesarios únicamente dentro del entorno virtual de nuestro role.</p>
<p>Empecemos por el principio: supongamos que queremos escribir un role de Ansible que se encargue (por ejemplo) de instalar el editor <a href="https://www.vim.org/">Vim</a>.</p>
<p>Llamaremos a nuestro role <code>vim-installer</code>.</p>
<p>Lo primero que necesitamos es crear la estructura de archivos y directorios típica de un role de Ansible, por lo que ejecutamos el comando <code>ansible-galaxy</code> de esta forma:</p>
<div class="highlight"><pre><span></span><code>$ ansible-galaxy init --verbose vim-installer
</code></pre></div>
<p>Este comando creará un directorio llamado <code>vim-installer</code> que contendrá la siguiente estructura:</p>
<div class="highlight"><pre><span></span><code><span class="err">└─ vim-installer/</span>
<span class="err"> ├─ defaults/</span>
<span class="err"> │ └─ main.yml</span>
<span class="err"> ├─ files/</span>
<span class="err"> ├─ handlers/</span>
<span class="err"> │ └─ main.yml</span>
<span class="err"> ├─ meta/</span>
<span class="err"> │ └─ main.yml</span>
<span class="err"> ├─ tasks/</span>
<span class="err"> │ └─ main.yml</span>
<span class="err"> ├─ templates/</span>
<span class="err"> ├─ tests/</span>
<span class="err"> │ ├─ inventory</span>
<span class="err"> │ └─ test.yml</span>
<span class="err"> ├─ vars/</span>
<span class="err"> │ └─ main.yml</span>
<span class="err"> └─ README.md</span>
</code></pre></div>
<p>Esta es la estructura típica que tienen todos los roles de Ansible.</p>
<p>Por simplificar el ejemplo, hemos acordado que nuestro role únicamente iba a encargarse de instalar Vim, por lo que editamos el archivo <code>tasks/main.yml</code> y creamos una tarea que instale dicho paquete:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">tasks/main.yml</span><a href='/files/2018-03-12-implementa-tests-en-tus-roles-de-ansible-con-molecule/tasks-main.yml'>download</a></figcaption>
<div class="highlight"><pre><span></span><code>---
<span class="c1"># tasks file for vim-installer</span>
- name: Instalando Vim
apt:
name: vim
state: present
</code></pre></div>
</figure>
<p>Como veis es un role muy sencillo en el que he usado a propósito el módulo <code>apt</code> para instalar el paquete para que cuando probemos el role en diferentes sistemas operativos podamos ver cómo funciona correctamente cuando lo hacemos en distribuciones basadas en Debian (en las que si se usa el comando <code>apt</code>) y cómo falla cuando lo probamos en otras distribuciones que no tienen dicho comando (como CentOS, Fedora, SuSE, etc).</p>
<p>Ya tenemos entonces nuestro role para instalar Vim usando Ansible, pero antes de continuar vamos a crear un <em>virtualenv</em> para poder instalar Molecule y sus dependencias.</p>
<p>Lo primero será instalar Virtualenv y Pip (si no los tenemos instalados ya). Para instalarlos, ahora si, podemos utilizar el gestor de paquetes de nuestra distribución:</p>
<p>Para los que uséis distribuciones de machotes, como por ejemplo Debian:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install virtualenv python-pip
</code></pre></div>
<p>Para los que prefieran distribuciones de niñitas, como por ejemplo CentOS:</p>
<div class="highlight"><pre><span></span><code>$ sudo yum install python-virtualenv python2-pip
</code></pre></div>
<p>Ahora que ya los tenemos instalados, creamos un nuevo entorno virtual con el comando <code>virtualenv</code> (dentro del directorio de nuestro proyecto) y lo <em>activamos</em>:</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">cd</span> vim-installer
$ virtualenv venv
$ <span class="nb">source</span> venv/bin/activate
</code></pre></div>
<p>Esto creará un nuevo directorio llamado <code>venv</code> (el nombre que le hemos dado a nuestro entorno virtual) en el cual se guardarán las librerías y módulos de Python que instalemos de ahora en adelante y hasta que salgamos del <em>virtualenv</em>.</p>
<p>Os habréis dado cuenta de cuando hemos activado el <em>virtualenv</em> con el comando <code>source venv/bin/activate</code> nos aparece en el <em>prompt</em> el nombre de nuestro entorno virtual entre paréntesis, verdad? Eso nos indica que estamos <em>dentro</em> de dicho <em>virtualenv</em>, y aparecerá siempre hasta que salgamos del mismo (con el comando <code>deactivate</code> o al cerrar el terminal).</p>
<p>Ahora que estamos dentro de un <em>virtualenv</em> aislado del resto del sistema vamos a instalar los paquetes necesarios utilizando el comando <code>pip</code>.</p>
<p>Podríamos instalar los paquetes de uno en uno con <code>pip install <nombre-paquete></code>, pero cuando tenemos varios proyectos diferentes al final se nos olvida qué paquetes son necesarios para cada uno de ellos, por lo que una <em>buena práctica</em> recomendada es la de tener un archivo llamado <code>requirements.txt</code> con la lista de paquetes necesarios para poder ejecutar nuestro proyecto.</p>
<p>Por lo tanto, vamos a crear dicho archivo de texto en la raíz de nuestro proyecto conteniendo el nombre y versión de los paquetes que necesitamos:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">requirements.txt</span><a href='/files/2018-03-12-implementa-tests-en-tus-roles-de-ansible-con-molecule/requirements.txt'>download</a></figcaption>
<div class="highlight"><pre><span></span><code>molecule><span class="o">=</span><span class="m">2</span>
docker-py><span class="o">=</span><span class="m">1</span>
testinfra><span class="o">=</span><span class="m">1</span>.7
</code></pre></div>
</figure>
<p>Y ahora los instalamos todos a la vez (incluidas sus muchas dependencias) con el comando:</p>
<div class="highlight"><pre><span></span><code><span class="o">(</span>venv<span class="o">)</span> $ pip install -r requirements.txt
</code></pre></div>
<p>Ya tenemos Molecule instalado, pero para poder utilizarlo hacen falta varios archivos de configuración, directorios, etc. Sería una pérdida de tiempo tener que crear esas cosas de forma manual (aunque podríamos hacerlo si quisiéramos), por lo que vamos a decirle a Molecule que los genere automáticamente:</p>
<div class="highlight"><pre><span></span><code><span class="o">(</span>venv<span class="o">)</span> $ molecule init scenario --role-name vim-installer
</code></pre></div>
<p>Podríamos especificar el parámetro <code>--driver <nombre_del_driver></code> para decirle a Molecule que utilice un driver u otro (<code>Vagrant</code>, <code>Docker</code>, <code>Azure</code>, <code>EC2</code>, <code>OpenStack</code>, etc), pero el que vamos a ver aquí es Docker (que es el driver por defecto en Molecule) por lo que no hace falta especificarlo.</p>
<p>Este comando añadirá 2 cosas a nuestro actual role:</p>
<ul>
<li><code>.yamllint</code>: Este archivo contiene la configuración y las reglas del analizador <em>linter</em> de archivos <a href="https://es.wikipedia.org/wiki/YAML">yaml</a> (si no sabes qué es esto no te preocupes, lo explicaré un poco más adelante).</li>
<li><code>molecule/</code>: En este directorio se guarda la configuración de Molecule para nuestro role, así como todos los demás archivos necesarios para la ejecución de los tests.</li>
</ul>
<p>Nuestra estructura de archivos y directorios estará ahora de esta forma:</p>
<div class="highlight"><pre><span></span><code><span class="err">└─ vim-installer/</span>
<span class="err"> ├─ defaults/</span>
<span class="err"> │ └─ main.yml</span>
<span class="err"> ├─ files/</span>
<span class="err"> ├─ handlers/</span>
<span class="err"> │ └─ main.yml</span>
<span class="err"> ├─ meta/</span>
<span class="err"> │ └─ main.yml</span>
<span class="err"> ├─ molecule/ <--- nuevo subdirectorio (con el contenido de Molecule)</span>
<span class="err"> │ └─ default/</span>
<span class="err"> │ ├─ tests/</span>
<span class="err"> │ │ ├─ test_default.py</span>
<span class="err"> │ │ └─ test_default.pyc</span>
<span class="err"> │ ├─ create.yml</span>
<span class="err"> │ ├─ destroy.yml</span>
<span class="err"> │ ├─ Dockerfile.j2</span>
<span class="err"> │ ├─ INSTALL.rst</span>
<span class="err"> │ ├─ molecule.yml</span>
<span class="err"> │ ├─ playbook.yml</span>
<span class="err"> │ └─ prepare.yml</span>
<span class="err"> ├─ tasks/</span>
<span class="err"> │ └─ main.yml</span>
<span class="err"> ├─ templates/</span>
<span class="err"> ├─ tests/</span>
<span class="err"> │ ├─ inventory</span>
<span class="err"> │ └─ test.yml</span>
<span class="err"> ├─ vars/</span>
<span class="err"> │ └─ main.yml</span>
<span class="err"> ├─ README.md</span>
<span class="err"> └─ .yamllint <--- nuevo archivo (con las reglas del lint de YAML)</span>
</code></pre></div>
<p>Antes de seguir y para evitar malentendidos no debemos confundir el directorio <code>tests/</code> (que es el que crea Ansible al inicializar el role) con el directorio <code>molecule/default/tests/</code> (que es el que crea Molecule con sus tests de <em>Testinfra</em> y que ya veremos más adelante). Por lo que ya que vamos a realizar los tests con Molecule podemos prescindir del directorio <code>tests/</code> de Ansible, así que lo eliminamos y así evitamos posibles confusiones:</p>
<div class="highlight"><pre><span></span><code><span class="o">(</span>venv<span class="o">)</span> $ rm -rf tests
</code></pre></div>
<p>Con esto ya tendríamos un role de Ansible con el entorno de Molecule instalado. Vamos ahora a configurarlo...</p>
<h2>Configuración y ejecución de tests<a name="configure"></a></h2>
<p>La configuración general de Molecule está en el archivo <code>molecule/default/molecule.yml</code>. Ahí es donde se configuran tanto los parámetros globales de los tests de Molecule como los parámetros específicos de cada uno de los tests individuales.</p>
<p>Más adelante veremos detenidamente qué son y para qué sirven cada uno de los archivos que se han generado en el paso anterior, pero antes hay algunas cosas que debemos saber sobre cómo funciona Molecule.</p>
<p>En primer lugar hay que saber que Molecule incluye varios tipos de comprobaciones. No se limita a lanzar los tests que hayamos programado, sino que hace varias comprobaciones diferentes, y ejecutar esos tests son solo una de ellas.</p>
<p>Aunque Molecule tiene varios <em>drivers</em> (como mencioné al principio) y en este artículo vamos a utilizar el driver Docker, cabe recordar igualmente que hay muchos otros como por ejemplo <code>EC2</code> (para utilizar instancias de <a href="https://aws.amazon.com/es/">Amazon Web Services</a> en lugar de contenedores Docker), o <a href="https://azure.microsoft.com/es-es/">Azure</a>, <a href="https://www.openstack.org/">OpenStack</a>, <a href="https://www.vagrantup.com/">Vagrant</a>, etc.</p>
<p>Estas son las <em>acciones</em> que podemos ejecutar en Molecule:</p>
<ul>
<li><code>lint</code>: Comprueba que los archivos <code>.yml</code> de nuestro role cumplen las reglas de estilo especificadas.</li>
<li><code>destroy</code>: Destruye los contenedores Docker de una ejecución anterior (si los hubiera).</li>
<li><code>dependency</code>: Instala las dependencias necesarias (en caso de haberlas) de los contenedores Docker donde vamos a probar nuestro role.</li>
<li><code>syntax</code>: Comprueba que la sintaxis de los archivos <code>.yml</code> de nuestro role es correcta.</li>
<li><code>create</code>: Construye e inicia todos los contenedores donde vayamos a probar nuestros roles.</li>
<li><code>prepare</code>: Prepara (si es necesario) los contenedores antes de ejecutar los roles (por si hubiera que instalar algún paquete en ellos o hacer cualquier otra cosa).</li>
<li><code>converge</code>: Ejecuta el role en todos los contenedores que previamente se han creado.</li>
<li><code>idempotence</code>: Ejecuta de nuevo los roles (como en el paso anterior) para comprobar que el resultado es el mismo que la primera vez y asegurar de esta forma el <a href="https://es.wikipedia.org/wiki/Idempotencia">principio de idempotencia</a> necesario en cualquier role de Ansible.</li>
<li><code>side-effect</code>: Esta comprobación viene desactivada por defecto, y se encarga de comprobar efectos colaterales de la ejecución del role en los contenedores (no la he usado nunca, así que poco puedo hablar de ella).</li>
<li><code>verify</code>: Ejecuta tests (de <em>Testinfra</em> o <em>Goss</em>) para comprobar que el role ha hecho lo que se suponía que debía hacer en cada uno de los contenedores.</li>
<li><code>destroy</code>: Una vez terminados los tests, destruye todos los contenedores y finaliza la ejecución.</li>
</ul>
<p>Solo después de haber ejecutado una a una todas estas acciones y de no haber registrado ningún error en ellas se daría por buena la ejecución de Molecule y podríamos decir que nuestro role <em>pasa los tests</em> (OK). Si se detecta un error en cualquiera de ellas, se interrumpe la ejecución y se asume que nuestro role <em>no pasa los tests</em> (KO).</p>
<p>Un test <em>completo</em> incluiría todas esas estas acciones, pero también podemos ejecutar Molecule para que lleve a cabo solo una de ellas (o varias).</p>
<p>La mayoría de estos tests de Molecule se corresponden con una de estas acciones, pero hay algunos tests que conllevan varias de ellas. Por ejemplo, antes de ejecutar la acción de <code>converge</code> (que es la que ejecuta el role en los diferentes contenedores de Docker) tendremos que haber creado los contenedores mediante la acción <code>create</code>. Por lo tanto, estos serían los tests de los que disponemos en Molecule (y las acciones que conlleva cada uno de ellos):</p>
<ul>
<li><a href="#test-lint">Lint</a>: Este test únicamente se corresponde con la acción <code>lint</code>.</li>
<li><a href="#test-syntax">Syntax</a>: Este test únicamente se corresponde con la acción <code>syntax</code>.</li>
<li><a href="#test-converge">Converge</a>: Este test se corresponde con las acciones: <code>create</code>, <code>prepare</code>, <code>converge</code> y <code>destroy</code>.</li>
<li><a href="#test-idempotence">Idempotence</a>: Este test únicamente se corresponde con la acción <code>idempotence</code>.</li>
<li><a href="#test-side-effect">Side-effect</a>: Este test únicamente se corresponde con la acción <code>side-effect</code>.</li>
<li><a href="#test-verify">Verify</a>: Este test únicamente se corresponde con la acción <code>verify</code>.</li>
</ul>
<p>En el archivo de configuración de Molecule (<code>molecule/default/molecule.yml</code>) podemos configurar la secuencia de acciones que tendrá asociado cada test. Esto se hace definiendo las secuencias dentro del bloque de configuración de <code>scenario</code>. En mi caso, suelo dejar ese bloque de esta forma:</p>
<div class="highlight"><pre><span></span><code><span class="nt">scenario</span><span class="p">:</span>
<span class="nt">name</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">default</span>
<span class="nt">create_sequence</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">create</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">prepare</span>
<span class="nt">check_sequence</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">destroy</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">create</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">prepare</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">converge</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">check</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">destroy</span>
<span class="nt">converge_sequence</span><span class="p">:</span>
<span class="c1"># - dependency</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">create</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">prepare</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">converge</span>
<span class="nt">destroy_sequence</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">destroy</span>
<span class="nt">test_sequence</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">lint</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">destroy</span>
<span class="c1"># - dependency</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">syntax</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">create</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">prepare</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">converge</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">idempotence</span>
<span class="c1"># - side_effect</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">verify</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">destroy</span>
</code></pre></div>
<p>Es decir, cuando se invoque a <code>create</code> en realidad se estará ejecutando la acción <code>create</code> y luego la acción <code>prepare</code>. Cuando se invoque a <code>check</code> se estará ejecutando las acciones <code>destroy</code>, <code>create</code>, <code>prepare</code>, <code>converge</code>, <code>check</code> y <code>destroy</code>. En el caso de invocar un test completo, suelo deshabilitar (según el caso) las acciones <code>dependency</code> y <code>side_effect</code>.</p>
<p>Vamos a ver cada uno de los tests con un poco más de detenimiento...</p>
<h3>Test <code>lint</code><a name="test-lint"></a></h3>
<p>Se conoce como <em>linter</em> (o <em>lint</em> a secas) al programa que se encarga de examinar nuestro código en busca de partes incorrectas, sospechosas, incompatibles, etc.</p>
<p>En este caso, el test <code>lint</code> de Molecule se encarga de examinar los archivos <code>.yml</code> que forman nuestro role de Ansible para comprobar que cumple con una serie de reglas predefinidas. Estas reglas suelen ser reglas de formato, como por ejemplo que todos los archivos comiencen con tres guiones (los archivos <code>.yml</code> suelen empezar por <code>---</code>), que no haya líneas cuya longitud supere un determinado número de caracteres (para que el código sea legible), etc.</p>
<p>Vamos a ejecutar este test, a ver qué nos dice Molecule:</p>
<div class="highlight"><pre><span></span><code><span class="o">(</span>venv<span class="o">)</span> $ molecule lint
</code></pre></div>
<p>El resultado de ese comando en nuestro role será algo parecido a esto:</p>
<div class="highlight"><pre><span></span><code>--> Test matrix
└── default
└── lint
--> Scenario: <span class="s1">'default'</span>
--> Action: <span class="s1">'lint'</span>
--> Executing Yamllint on files found in /tmp/vim-installer/...
/tmp/vim-installer/tasks/main.yml
<span class="m">2</span>:31 error no new line character at the end of file <span class="o">(</span>new-line-at-end-of-file<span class="o">)</span>
/tmp/vim-installer/meta/main.yml
<span class="m">1</span>:1 warning missing document start <span class="s2">"---"</span> <span class="o">(</span>document-start<span class="o">)</span>
<span class="m">30</span>:4 warning missing starting space in comment <span class="o">(</span>comments<span class="o">)</span>
<span class="m">48</span>:5 warning comment not indented like content <span class="o">(</span>comments-indentation<span class="o">)</span>
<span class="m">56</span>:3 warning comment not indented like content <span class="o">(</span>comments-indentation<span class="o">)</span>
<span class="m">57</span>:42 error no new line character at the end of file <span class="o">(</span>new-line-at-end-of-file<span class="o">)</span>
/tmp//vim-installer/vars/main.yml
<span class="m">2</span>:30 error no new line character at the end of file <span class="o">(</span>new-line-at-end-of-file<span class="o">)</span>
/tmp/vim-installer/handlers/main.yml
<span class="m">2</span>:34 error no new line character at the end of file <span class="o">(</span>new-line-at-end-of-file<span class="o">)</span>
/tmp/vim-installer/defaults/main.yml
<span class="m">2</span>:34 error no new line character at the end of file <span class="o">(</span>new-line-at-end-of-file<span class="o">)</span>
</code></pre></div>
<p>Que viene a decir que hay 5 archivos (de los generados por <em>Ansible</em> al inicializar el nuevo role) que no cumplen con las reglas de estilo predefinidas para los archivos <code>.yml</code>.</p>
<p>Es más que probable que aparezcan otro <em>cientos</em> de errores aparte de estos debido a que al estar dentro de un <code>virtualenv</code> tendremos un montón de archivos <code>.yml</code> en dicho directorio (los cuales no tiene porqué cumplir ninguna de nuestras reglas de estilo ya que son archivos de terceros sobre los que no tenemos ningún control) por lo que antes de nada, edita el archivo <code>.yamllint</code> y añade <code>ignore: venv/</code> justo debajo de <code>extends: default</code> para que no se tenga en cuenta lo que hay en ese directorio. Después, ejecuta de nuevo el test <code>lint</code> para ver si ya no aparecen esos archivos en el informe de Molecule.</p>
<p>Dicho esto, si en lugar de inicializar un nuevo role (como he hecho yo para escribir este artículo) estuvieras implementando Molecule en un role que ya tuvieras hecho de antemano, obviamente la salida de este test podría ser diferente (podría haber otros errores diferentes o incluso no haber ninguno).</p>
<p>La mayoría de los errores que nos está mostrando Molecule ahora son debidos a que los archivos no terminan con un <a href="https://es.wikipedia.org/wiki/Retorno_de_carro"><em>retorno de carro</em></a> (que es una de las reglas de estilo que tiene el <em>linter</em> por defecto), por lo que si editamos los archivos <code>tasks/main.yml</code>, <code>meta/main.yml</code>, <code>vars/main.yml</code>, <code>handlers/main.yml</code> y <code>defaults/main.yml</code>, añadimos un retorno de carro al final y volvemos a ejecutar el test <code>lint</code> obtendríamos algo parecido a esto:</p>
<div class="highlight"><pre><span></span><code>--> Test matrix
└── default
└── lint
--> Scenario: <span class="s1">'default'</span>
--> Action: <span class="s1">'lint'</span>
--> Executing Yamllint on files found in /tmp/vim-installer/...
/tmp/vim-installer/meta/main.yml
<span class="m">1</span>:1 warning missing document start <span class="s2">"---"</span> <span class="o">(</span>document-start<span class="o">)</span>
<span class="m">30</span>:4 warning missing starting space in comment <span class="o">(</span>comments<span class="o">)</span>
<span class="m">48</span>:5 warning comment not indented like content <span class="o">(</span>comments-indentation<span class="o">)</span>
<span class="m">56</span>:3 warning comment not indented like content <span class="o">(</span>comments-indentation<span class="o">)</span>
Lint completed successfully.
--> Executing Flake8 on files found in /tmp/vim-installer/molecule/default/tests/...
Lint completed successfully.
--> Executing Ansible Lint on /tmp/vim-installer/molecule/default/playbook.yml...
Lint completed successfully.
</code></pre></div>
<p>La mayoría de los errores que teníamos antes han desaparecido. Y para solucionar el resto podemos o bien ir corrigiéndolos o bien configurar el <em>linter</em> para desactivar esa regla en concreto (en caso de que no queramos que se aplique en nuestro role por algún motivo).</p>
<p>Esta configuración se guarda en el archivo <code>.yamllint</code>, el cual fué creado de forma automática por Molecule cuando inicializamos el role y cuyo contenido es:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">.yamllint</span><a href='/files/2018-03-12-implementa-tests-en-tus-roles-de-ansible-con-molecule/yamllint'>download</a></figcaption>
<div class="highlight"><pre><span></span><code>extends: default
ignore: .venv/
rules:
braces:
max-spaces-inside: <span class="m">1</span>
level: error
brackets:
max-spaces-inside: <span class="m">1</span>
level: error
line-length: disable
</code></pre></div>
</figure>
<p>Por ejemplo, es una regla recomendable que en todos los archivos <code>.yml</code> los comentarios estén indentados igual que el resto de líneas que no son comentarios, por lo que el <em>linter</em> se quejará si detecta algún archivo que no cumpla esta regla (como acabamos de ver en nuestro ejemplo).</p>
<p>Pero si por cualquier motivo nosotros queremos permitir que estos comentarios no tengan que cumplir las reglas de indentación, podemos editar la configuración del <code>lint</code> y añadir <code>comments-indentation: false</code>. El archivo de configuración quedaría entonces de esta forma:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">.yamllint</span><a href='/files/2018-03-12-implementa-tests-en-tus-roles-de-ansible-con-molecule/yamllint-comments-indentation'>download</a></figcaption>
<div class="highlight"><pre><span></span><code>extends: default
ignore: venv/
rules:
comments-indentation: <span class="nb">false</span>
braces:
max-spaces-inside: <span class="m">1</span>
level: error
brackets:
max-spaces-inside: <span class="m">1</span>
level: error
line-length: disable
</code></pre></div>
</figure>
<p>Si volvemos a ejecutar ahora el test <code>lint</code> el resultado será:</p>
<div class="highlight"><pre><span></span><code>--> Test matrix
└── default
└── lint
--> Scenario: <span class="s1">'default'</span>
--> Action: <span class="s1">'lint'</span>
--> Executing Yamllint on files found in /tmp/vim-installer/...
/tmp/vim-installer/meta/main.yml
<span class="m">1</span>:1 warning missing document start <span class="s2">"---"</span> <span class="o">(</span>document-start<span class="o">)</span>
<span class="m">30</span>:4 warning missing starting space in comment <span class="o">(</span>comments<span class="o">)</span>
Lint completed successfully.
--> Executing Flake8 on files found in /tmp/vim-installer/molecule/default/tests/...
Lint completed successfully.
--> Executing Ansible Lint on /tmp/vim-installer/molecule/default/playbook.yml...
Lint completed successfully.
</code></pre></div>
<p>Como puedes ver, ya no aparecen los errores relativos a los comentarios que aparecían antes.</p>
<p>Aparte de la configuración de las reglas, hay algunas otras cosas que podemos configurar relativas al propio <em>linter</em>. Si examinas el contenido del archivo de configuración de Molecule (<code>molecule/default/molecule.yml</code>) verás algo parecido a esto:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">molecule/default/molecule.yml</span><a href='/files/2018-03-12-implementa-tests-en-tus-roles-de-ansible-con-molecule/molecule.yml'>download</a></figcaption>
<div class="highlight"><pre><span></span><code>---
dependency:
name: galaxy
driver:
name: docker
lint:
name: yamllint
platforms:
- name: instance
image: centos:7
provisioner:
name: ansible
lint:
name: ansible-lint
scenario:
name: default
verifier:
name: testinfra
lint:
name: flake8
</code></pre></div>
</figure>
<p>Si modificamos el bloque del <code>lint</code> podemos configurar algunas cosas, como activar/desactivar este test, elegir qué <em>linter</em> queremos usar, etc.</p>
<p>Una cosa que a mi me gusta cambiar aquí es la ubicación del archivo de definición de reglas de estilo (<code>.yamllint</code>) ya que me gusta que esté dentro del directorio de Molecule, por lo que el bloque <code>lint</code> de mi configuración suele ser así:</p>
<div class="highlight"><pre><span></span><code><span class="nt">lint</span><span class="p">:</span>
<span class="nt">name</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">yamllint</span>
<span class="nt">enabled</span><span class="p">:</span> <span class="s">"True"</span>
<span class="nt">options</span><span class="p">:</span>
<span class="nt">config-file</span><span class="p">:</span> <span class="s">"molecule/.yamllint"</span>
<span class="nt">format</span><span class="p">:</span> <span class="s">"standard"</span>
</code></pre></div>
<p>Supongo que más o menos ha quedado claro como funciona el test <code>lint</code>, verdad? Toda la información sobre las posibles configuraciones de este test están en su <a href="https://molecule.readthedocs.io/en/latest/configuration.html#lint">documentación oficial</a>.</p>
<p>Y si quieres profundizar más en relación a las reglas que puedes aplicar, instrucciones para integrar un <em>linter</em> en tu <a href="https://es.wikipedia.org/wiki/Entorno_de_desarrollo_integrado">IDE</a>, etc. puedes consultar esta documentación en la página web del proyecto <a href="https://yamllint.readthedocs.io/en/latest/index.html">yamllint</a>.</p>
<h3>Test <code>syntax</code><a name="test-syntax"></a></h3>
<p>Vamos con el siguiente test, que como habrás podido adivinar por el nombre, únicamente se encarga de comprobar la sintaxis de nuestro role.</p>
<p>Si ejecutamos este test, Molecule recorrerá de nuevo todos los archivos <code>.yml</code> de nuestro role en busca de errores sintácticos.</p>
<p>Vamos a probar el test:</p>
<div class="highlight"><pre><span></span><code><span class="o">(</span>venv<span class="o">)</span> $ molecule syntax
</code></pre></div>
<p>El resultado debería ser:</p>
<div class="highlight"><pre><span></span><code>--> Test matrix
└── default
└── syntax
--> Scenario: <span class="s1">'default'</span>
--> Action: <span class="s1">'syntax'</span>
playbook: /tmp/vim-installer/molecule/default/playbook.yml
</code></pre></div>
<p>Lo que significa que el test ha pasado correctamente y que no hay ningún error de sintaxis.</p>
<p>Para probar que efectivamente el test funciona vamos editar uno de los archivos para introducir un error a propósito. Editamos, por ejemplo, el archivo <code>tasks/main.yml</code> y escribimos cualquier cosa incorrecta:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">vars/main.yml</span><a href='/files/2018-03-12-implementa-tests-en-tus-roles-de-ansible-con-molecule/vars-main-error.yml'>download</a></figcaption>
<div class="highlight"><pre><span></span><code>---
<span class="c1"># vars file for vim-installer</span>
esto-falla-seguro
</code></pre></div>
</figure>
<p>Aunque el archivo tiene un formato <code>.yml</code> válido y cumple todas las reglas de estilo por defecto (es decir, pasaría el test <code>lint</code>) eso de <code>esto-falla-seguro</code> no es ningún comando válido de Ansible, por lo que si volvemos a ejecutar el analizador sintáctico veremos algo así:</p>
<div class="highlight"><pre><span></span><code>--> Test matrix
└── default
└── syntax
--> Scenario: <span class="s1">'default'</span>
--> Action: <span class="s1">'syntax'</span>
ERROR! The vars/main.yml file <span class="k">for</span> role <span class="s1">'vim-installer'</span> must contain a dictionary of variables
ERROR:
</code></pre></div>
<p>Perfecto! Molecule se ha dado cuenta del error y nos avisa, por lo que volvemos a dejar el archivo como estaba y pasamos al siguiente test.</p>
<h3>Test <code>converge</code><a name="test-converge"></a></h3>
<p>En este test es donde vamos a aprovechar todo el potencial de Docker, ya que es el que nos permite ejecutar nuestro role en diferentes contenedores, cada uno de ellos con un sistema operativo diferente, versiones diferentes del mismo sistema operativo, distintas configuraciones o cualquier otra cosa que se nos ocurra.</p>
<p>Por defecto, cuando lanzamos este test, Molecule ejecuta las acciones <code>dependency</code>, <code>create</code>, <code>prepare</code> y <code>converge</code>. En mi caso, como ya puse un poco más arriba, suelo modificar esta secuencia para que no ejecute la acción <code>dependency</code> (porque no hay ninguna dependencia en el role que estamos probando).</p>
<p>Vamos a configurar Molecule para probar nuestro role en Linux Debian 8 (por poner un ejemplo) y luego ya probaremos en otros sistemas operativos diferentes.</p>
<p>Editamos el archivo de configuración (<code>molecule/default/molecule.yml</code>) y añadimos estas líneas en el bloque <code>platforms</code>:</p>
<div class="highlight"><pre><span></span><code><span class="nt">platforms</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="nt">name</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">molecule_debian8</span>
<span class="nt">image</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">debian:8-slim</span>
<span class="nt">privileged</span><span class="p">:</span> <span class="s">"True"</span>
</code></pre></div>
<p>Con esta configuración estamos definiendo una instancia llamada <code>molecule_debian8</code> (que se creará utilizando la imagen <code>debian:8-slim</code>). Yo he elegido esta imagen para probar el role, pero obviamente podéis usar cualquier imagen que haya en <a href="https://hub.docker.com/">Docker Hub</a>) o incluso crear vuestras propias imágenes.</p>
<p>Vamos a lanzar el test:</p>
<div class="highlight"><pre><span></span><code><span class="o">(</span>venv<span class="o">)</span> $ molecule converge
</code></pre></div>
<p>Tardará un poco (sobre todo la primera vez, porque tiene que descargar la imagen desde Docker Hub) pero una vez terminado deberíamos ver algo parecido a esto:</p>
<div class="highlight"><pre><span></span><code>--> Test matrix
└── default
├── create
├── prepare
└── converge
--> Scenario: <span class="s1">'default'</span>
--> Action: <span class="s1">'create'</span>
PLAY <span class="o">[</span>Create<span class="o">]</span> ******************************************************************
TASK <span class="o">[</span>Create Dockerfiles from image names<span class="o">]</span> *************************************
changed: <span class="o">[</span>localhost<span class="o">]</span> <span class="o">=</span>> <span class="o">(</span><span class="nv">item</span><span class="o">=</span>None<span class="o">)</span>
TASK <span class="o">[</span>Discover <span class="nb">local</span> Docker images<span class="o">]</span> ********************************************
ok: <span class="o">[</span>localhost<span class="o">]</span> <span class="o">=</span>> <span class="o">(</span><span class="nv">item</span><span class="o">=</span>None<span class="o">)</span>
TASK <span class="o">[</span>Build an Ansible compatible image<span class="o">]</span> ***************************************
changed: <span class="o">[</span>localhost<span class="o">]</span> <span class="o">=</span>> <span class="o">(</span><span class="nv">item</span><span class="o">=</span>None<span class="o">)</span>
TASK <span class="o">[</span>Create docker network<span class="o">(</span>s<span class="o">)]</span> ************************************************
TASK <span class="o">[</span>Create molecule instance<span class="o">(</span>s<span class="o">)]</span> *********************************************
changed: <span class="o">[</span>localhost<span class="o">]</span> <span class="o">=</span>> <span class="o">(</span><span class="nv">item</span><span class="o">=</span>None<span class="o">)</span>
TASK <span class="o">[</span>Wait <span class="k">for</span> instance<span class="o">(</span>s<span class="o">)</span> creation to complete<span class="o">]</span> *******************************
changed: <span class="o">[</span>localhost<span class="o">]</span> <span class="o">=</span>> <span class="o">(</span><span class="nv">item</span><span class="o">=</span>None<span class="o">)</span>
PLAY RECAP *********************************************************************
localhost : <span class="nv">ok</span><span class="o">=</span><span class="m">5</span> <span class="nv">changed</span><span class="o">=</span><span class="m">3</span> <span class="nv">unreachable</span><span class="o">=</span><span class="m">0</span> <span class="nv">failed</span><span class="o">=</span><span class="m">0</span>
--> Scenario: <span class="s1">'default'</span>
--> Action: <span class="s1">'prepare'</span>
PLAY <span class="o">[</span>Prepare<span class="o">]</span> *****************************************************************
PLAY RECAP *********************************************************************
--> Scenario: <span class="s1">'default'</span>
--> Action: <span class="s1">'converge'</span>
PLAY <span class="o">[</span>Converge<span class="o">]</span> ****************************************************************
TASK <span class="o">[</span>Gathering Facts<span class="o">]</span> *********************************************************
ok: <span class="o">[</span>molecule_debian8<span class="o">]</span>
PLAY RECAP *********************************************************************
molecule_debian8 : <span class="nv">ok</span><span class="o">=</span><span class="m">1</span> <span class="nv">changed</span><span class="o">=</span><span class="m">0</span> <span class="nv">unreachable</span><span class="o">=</span><span class="m">0</span> <span class="nv">failed</span><span class="o">=</span><span class="m">0</span>
</code></pre></div>
<p>Podemos ver como se han ido ejecutando las 3 acciones: crear los contenedores (acción <code>create</code>), prepararlos (acción <code>prepare</code>) y después lanzar nuestro role en ellos (acción <code>converge</code>).</p>
<p>El role se ha ejecutado correctamente (como era de esperar) porque estamos probando en una distribución Debian, pero qué pasaría si probáramos también en un sistema operativo que no tenga el comando <code>apt</code> que estamos usando en el role? Vamos a editar de nuevo el archivo de configuración de Molecule (<code>molecule/default/molecule.yml</code>) y vamos a añadir una instancia CentOS 7 (por ejemplo):</p>
<div class="highlight"><pre><span></span><code><span class="nt">platforms</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="nt">name</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">molecule_debian8</span>
<span class="nt">image</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">debian:8-slim</span>
<span class="nt">privileged</span><span class="p">:</span> <span class="s">"True"</span>
<span class="p p-Indicator">-</span> <span class="nt">name</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">molecule_centos7</span>
<span class="nt">image</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">centos:7</span>
<span class="nt">privileged</span><span class="p">:</span> <span class="s">"True"</span>
</code></pre></div>
<p>Volvemos a lanzar el test <code>converge</code>, y el resultado esta vez es diferente:</p>
<div class="highlight"><pre><span></span><code>--> Test matrix
└── default
├── create
├── prepare
└── converge
--> Scenario: <span class="s1">'default'</span>
--> Action: <span class="s1">'create'</span>
PLAY <span class="o">[</span>Create<span class="o">]</span> ******************************************************************
TASK <span class="o">[</span>Create Dockerfiles from image names<span class="o">]</span> *************************************
changed: <span class="o">[</span>localhost<span class="o">]</span> <span class="o">=</span>> <span class="o">(</span><span class="nv">item</span><span class="o">=</span>None<span class="o">)</span>
ok: <span class="o">[</span>localhost<span class="o">]</span> <span class="o">=</span>> <span class="o">(</span><span class="nv">item</span><span class="o">=</span>None<span class="o">)</span>
TASK <span class="o">[</span>Discover <span class="nb">local</span> Docker images<span class="o">]</span> ********************************************
changed: <span class="o">[</span>localhost<span class="o">]</span> <span class="o">=</span>> <span class="o">(</span><span class="nv">item</span><span class="o">=</span>None<span class="o">)</span>
ok: <span class="o">[</span>localhost<span class="o">]</span> <span class="o">=</span>> <span class="o">(</span><span class="nv">item</span><span class="o">=</span>None<span class="o">)</span>
TASK <span class="o">[</span>Build an Ansible compatible image<span class="o">]</span> ***************************************
changed: <span class="o">[</span>localhost<span class="o">]</span> <span class="o">=</span>> <span class="o">(</span><span class="nv">item</span><span class="o">=</span>None<span class="o">)</span>
changed: <span class="o">[</span>localhost<span class="o">]</span> <span class="o">=</span>> <span class="o">(</span><span class="nv">item</span><span class="o">=</span>None<span class="o">)</span>
TASK <span class="o">[</span>Create docker network<span class="o">(</span>s<span class="o">)]</span> ************************************************
TASK <span class="o">[</span>Create molecule instance<span class="o">(</span>s<span class="o">)]</span> *********************************************
changed: <span class="o">[</span>localhost<span class="o">]</span> <span class="o">=</span>> <span class="o">(</span><span class="nv">item</span><span class="o">=</span>None<span class="o">)</span>
changed: <span class="o">[</span>localhost<span class="o">]</span> <span class="o">=</span>> <span class="o">(</span><span class="nv">item</span><span class="o">=</span>None<span class="o">)</span>
TASK <span class="o">[</span>Wait <span class="k">for</span> instance<span class="o">(</span>s<span class="o">)</span> creation to complete<span class="o">]</span> *******************************
changed: <span class="o">[</span>localhost<span class="o">]</span> <span class="o">=</span>> <span class="o">(</span><span class="nv">item</span><span class="o">=</span>None<span class="o">)</span>
changed: <span class="o">[</span>localhost<span class="o">]</span> <span class="o">=</span>> <span class="o">(</span><span class="nv">item</span><span class="o">=</span>None<span class="o">)</span>
PLAY RECAP *********************************************************************
localhost : <span class="nv">ok</span><span class="o">=</span><span class="m">5</span> <span class="nv">changed</span><span class="o">=</span><span class="m">3</span> <span class="nv">unreachable</span><span class="o">=</span><span class="m">0</span> <span class="nv">failed</span><span class="o">=</span><span class="m">0</span>
--> Scenario: <span class="s1">'default'</span>
--> Action: <span class="s1">'prepare'</span>
PLAY <span class="o">[</span>Prepare<span class="o">]</span> *****************************************************************
PLAY RECAP *********************************************************************
--> Scenario: <span class="s1">'default'</span>
--> Action: <span class="s1">'converge'</span>
PLAY <span class="o">[</span>Converge<span class="o">]</span> ****************************************************************
TASK <span class="o">[</span>Gathering Facts<span class="o">]</span> *********************************************************
ok: <span class="o">[</span>molecule_centos7<span class="o">]</span>
ok: <span class="o">[</span>molecule_debian8<span class="o">]</span>
TASK <span class="o">[</span>vim-installer : Instalando Vim<span class="o">]</span> ******************************************
fatal: <span class="o">[</span>molecule_centos7<span class="o">]</span>: FAILED! <span class="o">=</span>> <span class="o">{</span><span class="s2">"changed"</span>: false, <span class="s2">"cmd"</span>: <span class="s2">"apt-get update"</span>, <span class="s2">"msg"</span>: <span class="s2">"[Errno 2] No such file or directory"</span>, <span class="s2">"rc"</span>: <span class="m">2</span><span class="o">}</span>
changed: <span class="o">[</span>molecule_debian8<span class="o">]</span>
PLAY RECAP *********************************************************************
molecule_centos7 : <span class="nv">ok</span><span class="o">=</span><span class="m">1</span> <span class="nv">changed</span><span class="o">=</span><span class="m">0</span> <span class="nv">unreachable</span><span class="o">=</span><span class="m">0</span> <span class="nv">failed</span><span class="o">=</span><span class="m">1</span>
molecule_debian8 : <span class="nv">ok</span><span class="o">=</span><span class="m">2</span> <span class="nv">changed</span><span class="o">=</span><span class="m">1</span> <span class="nv">unreachable</span><span class="o">=</span><span class="m">0</span> <span class="nv">failed</span><span class="o">=</span><span class="m">0</span>
ERROR:
</code></pre></div>
<p>Lógicamente la ejecución del role en la instancia CentOS ha fallado. Vamos a modificar un poco el role para asegurarnos de que se funciona correctamente tanto en Debian como en CentOS. Editamos el archivo <code>tasks/main.yml</code> y añadimos otra tarea específica para CentOS utilizando la cláusula <code>when</code> para ejecutar un modulo u otro dependiendo de la distribución en la que estemos ejecutando el role:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">tasks/main.yml</span><a href='/files/2018-03-12-implementa-tests-en-tus-roles-de-ansible-con-molecule/tasks-main-when.yml'>download</a></figcaption>
<div class="highlight"><pre><span></span><code>---
<span class="c1"># tasks file for vim-installer</span>
- name: Instalando Vim en Debian
apt:
name: vim
state: present
when: <span class="nv">ansible_distribution</span> <span class="o">==</span> <span class="s1">'Debian'</span>
- name: Instalando Vim en CentOS
yum:
name: vim
state: present
when: <span class="nv">ansible_distribution</span> <span class="o">==</span> <span class="s1">'CentOS'</span>
</code></pre></div>
</figure>
<p>Lanzamos de nuevo el test <code>converge</code>:</p>
<div class="highlight"><pre><span></span><code>--> Test matrix
└── default
├── create
├── prepare
└── converge
--> Scenario: <span class="s1">'default'</span>
--> Action: <span class="s1">'create'</span>
Skipping, instances already created.
--> Scenario: <span class="s1">'default'</span>
--> Action: <span class="s1">'prepare'</span>
Skipping, instances already prepared.
--> Scenario: <span class="s1">'default'</span>
--> Action: <span class="s1">'converge'</span>
PLAY <span class="o">[</span>Converge<span class="o">]</span> ****************************************************************
TASK <span class="o">[</span>Gathering Facts<span class="o">]</span> *********************************************************
ok: <span class="o">[</span>molecule_centos7<span class="o">]</span>
ok: <span class="o">[</span>molecule_debian8<span class="o">]</span>
TASK <span class="o">[</span>vim-installer : Instalando Vim en Debian<span class="o">]</span> ********************************
skipping: <span class="o">[</span>molecule_centos7<span class="o">]</span>
ok: <span class="o">[</span>molecule_debian8<span class="o">]</span>
TASK <span class="o">[</span>vim-installer : Instalando Vim en CentOS<span class="o">]</span> ********************************
skipping: <span class="o">[</span>molecule_debian8<span class="o">]</span>
changed: <span class="o">[</span>molecule_centos7<span class="o">]</span>
PLAY RECAP *********************************************************************
molecule_centos7 : <span class="nv">ok</span><span class="o">=</span><span class="m">2</span> <span class="nv">changed</span><span class="o">=</span><span class="m">1</span> <span class="nv">unreachable</span><span class="o">=</span><span class="m">0</span> <span class="nv">failed</span><span class="o">=</span><span class="m">0</span>
molecule_debian8 : <span class="nv">ok</span><span class="o">=</span><span class="m">2</span> <span class="nv">changed</span><span class="o">=</span><span class="m">0</span> <span class="nv">unreachable</span><span class="o">=</span><span class="m">0</span> <span class="nv">failed</span><span class="o">=</span><span class="m">0</span>
</code></pre></div>
<p>Como verás, aparte de que las acciones <code>create</code> y <code>prepare</code> no se han ejecutado porque no ha habido cambios en ellas desde la última ejecución (para acelerar el proceso) el role ha funcionado tanto en la instancia Debian como en la CentOS.</p>
<p>Ya tenemos otro de los tests de Molecule funcionando! Vamos con el siguiente:</p>
<h3>Test <code>Idempotence</code><a name="test-idempotence"></a></h3>
<p>Uno de los requisitos fundamentales de todo role de Ansible es que cumpla el principio de idempotencia. Como ya expliqué antes, esto significa que da igual el número de veces que ejecutemos el role: siempre tiene que dar el mismo resultado.</p>
<p>Esto se hace para evitar que haya tareas que solo funcionan la primera vez que se ejecutan o por el contrario que únicamente funcionan <em>a la segunda</em>. En Ansible podemos ejecutar el mismo role 100 veces contra el mismo servidor, y este debería funcionar correctamente sin provocar ningún error las 100 veces.</p>
<p>Para comprobar esto, Molecule ejecuta el mismo role varias veces en las instancias que hayamos configurado en el test anterior (el test <code>converge</code>) y si en alguna de estas veces el role falla, el test nos lo hará saber.</p>
<p>Vamos a ver qué sucede al ejecutar este test con nuestro role actual:</p>
<div class="highlight"><pre><span></span><code><span class="o">(</span>venv<span class="o">)</span> $ molecule idempotence
</code></pre></div>
<p>Si el resultado es este:</p>
<div class="highlight"><pre><span></span><code>--> Test matrix
└── default
└── idempotence
--> Scenario: <span class="s1">'default'</span>
--> Action: <span class="s1">'idempotence'</span>
ERROR: Instances not converged. Please converge instances first.
</code></pre></div>
<p>Significa que las instancias no están en ejecución y preparadas para este test, por lo que las levantamos con el comando <code>molecule converge</code> y ejecutamos el test de nuevo. El resultado debería ser parecido a esto:</p>
<div class="highlight"><pre><span></span><code>--> Test matrix
└── default
└── idempotence
--> Scenario: <span class="s1">'default'</span>
--> Action: <span class="s1">'idempotence'</span>
Idempotence completed successfully.
</code></pre></div>
<p>El test ha funcionado, por lo que nuestro role cumple con el principio de idempotencia.</p>
<p>Vamos con el siguiente test:</p>
<h3>Test <code>Side-effect</code><a name="test-side-effect"></a></h3>
<p>Este test se utiliza para ver si la ejecución de un role ha tenido <em>efectos colaterales</em> que pudieran provocar errores, a pesar de que la ejecución del propio role haya sido correcta.</p>
<p>No se suele utilizar, por lo que incluso viene desactivado por defecto. Para habilitar este test hay que editar el archivo de configuración de Molecule y añadir la acción <code>side_effect</code> al bloque <code>test_sequence</code> dentro de <code>scenario</code>, o bien lanzar manualmente el test con el comando:</p>
<div class="highlight"><pre><span></span><code><span class="o">(</span>venv<span class="o">)</span> $ molecule side-effect
</code></pre></div>
<p>Pero antes tendríais que definir un <em>playbook</em> que se encargue de comprobar dichos <em>efectos colaterales</em>. Como ya os comenté, yo no he usado este test nunca por lo que poco puedo deciros mucho más sobre él.</p>
<h3>Test <code>Verify</code><a name="test-verify"></a></h3>
<p>Este test es uno de los más importantes, ya que es el que realmente se encarga de comprobar si lo que se supone que hace nuestro role se ha hecho realmente.</p>
<p>Molecule soporta 2 formas de ejecutar estas comprobaciones:</p>
<ul>
<li><a href="https://testinfra.readthedocs.io">Testinfra</a>: Esta herramienta es a su vez un plugin del framework <a href="https://docs.pytest.org/en/latest/">Pytest</a>, y permite ejecutar <a href="https://es.wikipedia.org/wiki/Script">scripts</a> escritos en <a href="https://www.python.org/">Python</a> para realizar las comprobaciones.</li>
<li><a href="https://goss.rocks/">Goss</a>: Es otra herramienta similar para definir comprobaciones pero que a diferencia de Testinfra utiliza archivos YAML en lugar de scripts en Python.</li>
</ul>
<p>Por defecto, Molecule utiliza <em>Testinfra</em> para ejecutar los tests <code>verify</code>, pero ambos son perfectamente válidos. Personalmente utilizo <em>Testinfra</em>.</p>
<p>Editamos el archivo de configuración de Molecule (<code>molecule/default/molecule.yml</code>) e indicamos en el bloque <code>verifier</code> cual de los 2 queremos utilizar. En nuestro caso:</p>
<div class="highlight"><pre><span></span><code><span class="nt">verifier</span><span class="p">:</span>
<span class="nt">name</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">testinfra</span>
<span class="nt">enabled</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">True</span>
<span class="nt">directory</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">tests/</span>
<span class="nt">lint</span><span class="p">:</span>
<span class="nt">name</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">flake8</span>
</code></pre></div>
<p>Como ves, aquí también podemos indicar el directorio donde estarán los scripts con las comprobaciones que queramos hacer (relativo a <code>molecules/default/</code>), si queremos deshabilitar el test o incluso un <em>linter</em> (no tiene nada que ver con el que usábamos antes en el test <code>lint</code>) para analizar el código de estos scripts (se usa <a href="http://flake8.pycqa.org/en/latest/">flake8</a> porque como ya dije, los scripts de Testinfra se escriben en Python).</p>
<blockquote>
<p>Todos los tests que vayamos a ejecutar deben estar en archivos cuyo nombre <strong>comience por <code>test_</code></strong>, sino no se ejecutarán (puede parecer una tontería, pero lo recalco para evitar que os volváis locos por este motivo, como me pasó a mi xDD).</p>
</blockquote>
<p>Vamos a echarle un vistazo al test que Molecule trae por defecto (<code>molecule/default/tests/test_default.py</code>):</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">molecule/default/tests/test_default.py</span><a href='/files/2018-03-12-implementa-tests-en-tus-roles-de-ansible-con-molecule/test_default.py'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">testinfra.utils.ansible_runner</span>
<span class="n">testinfra_hosts</span> <span class="o">=</span> <span class="n">testinfra</span><span class="o">.</span><span class="n">utils</span><span class="o">.</span><span class="n">ansible_runner</span><span class="o">.</span><span class="n">AnsibleRunner</span><span class="p">(</span>
<span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s1">'MOLECULE_INVENTORY_FILE'</span><span class="p">])</span><span class="o">.</span><span class="n">get_hosts</span><span class="p">(</span><span class="s1">'all'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">test_hosts_file</span><span class="p">(</span><span class="n">host</span><span class="p">):</span>
<span class="n">f</span> <span class="o">=</span> <span class="n">host</span><span class="o">.</span><span class="n">file</span><span class="p">(</span><span class="s1">'/etc/hosts'</span><span class="p">)</span>
<span class="k">assert</span> <span class="n">f</span><span class="o">.</span><span class="n">exists</span>
<span class="k">assert</span> <span class="n">f</span><span class="o">.</span><span class="n">user</span> <span class="o">==</span> <span class="s1">'root'</span>
<span class="k">assert</span> <span class="n">f</span><span class="o">.</span><span class="n">group</span> <span class="o">==</span> <span class="s1">'root'</span>
</code></pre></div>
</figure>
<p>Aunque no seas un experto en Python seguro que puedes deducir sin problemas lo que hace este sencillo código:</p>
<ul>
<li>Comprueba que exista el archivo <code>/etc/hosts</code>.</li>
<li>Comprueba que pertenezca al usuario <code>root</code>.</li>
<li>Comprueba que pertenezca también al grupo <code>root</code>.</li>
</ul>
<p>Las 3 <em>aserciones</em> son ciertas en cualquier distribución Linux, por lo que si lanzamos este test debería ejecutarse correctamente:</p>
<div class="highlight"><pre><span></span><code><span class="o">(</span>venv<span class="o">)</span> $ molecule verify
</code></pre></div>
<p>Y el resultado:</p>
<div class="highlight"><pre><span></span><code>--> Test matrix
└── default
└── verify
--> Scenario: <span class="s1">'default'</span>
--> Action: <span class="s1">'verify'</span>
--> Executing Testinfra tests found in /tmp/vim-installer/molecule/default/tests/...
<span class="o">=============================</span> <span class="nb">test</span> session <span class="nv">starts</span> <span class="o">==============================</span>
platform linux2 -- Python <span class="m">2</span>.7.14+, pytest-3.4.2, py-1.5.2, pluggy-0.6.0
rootdir: /tmp/vim-installer/molecule/default, inifile:
plugins: testinfra-1.11.1
collected <span class="m">2</span> items
tests/test_default.py .. <span class="o">[</span><span class="m">100</span>%<span class="o">]</span>
<span class="o">==========================</span> <span class="m">2</span> passed in <span class="m">10</span>.71 <span class="nv">seconds</span> <span class="o">===========================</span>
Verifier completed successfully.
</code></pre></div>
<p>Vale, el test se ejecuta correctamente... pero lo que se está comprobando en él no tiene nada que ver con nuestro role, por lo que vamos a modificarlo un poco para que compruebe algo que de verdad nos asegure que nuestro role funciona.</p>
<p>Como nuestro role únicamente instala Vim, vamos a modificar el test para comprobar que el paquete Vim esté instalado. Aprovechando la potencia que nos da el framework de Testinfra, modificamos el test para que compruebe si el paquete <code>vim</code> está instalado (y aprovechamos para quitar los <code>import</code> y demás cosas que no usamos):</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">molecule/default/tests/test_default.py</span><a href='/files/2018-03-12-implementa-tests-en-tus-roles-de-ansible-con-molecule/test_default_vim.py'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">test_vim_is_installed</span><span class="p">(</span><span class="n">host</span><span class="p">):</span>
<span class="n">vim</span> <span class="o">=</span> <span class="n">host</span><span class="o">.</span><span class="n">package</span><span class="p">(</span><span class="s2">"vim"</span><span class="p">)</span>
<span class="k">assert</span> <span class="n">vim</span><span class="o">.</span><span class="n">is_installed</span>
</code></pre></div>
</figure>
<p>Lanzamos de nuevo el test y comprobamos el resultado:</p>
<div class="highlight"><pre><span></span><code>--> Test matrix
└── default
└── verify
--> Scenario: <span class="s1">'default'</span>
--> Action: <span class="s1">'verify'</span>
--> Executing Testinfra tests found in /tmp/vim-installer/molecule/default/tests/...
<span class="o">=============================</span> <span class="nb">test</span> session <span class="nv">starts</span> <span class="o">==============================</span>
platform linux2 -- Python <span class="m">2</span>.7.14+, pytest-3.4.2, py-1.5.2, pluggy-0.6.0
rootdir: /tmp/vim-installer/molecule/default, inifile:
plugins: testinfra-1.11.1
collected <span class="m">2</span> items
tests/test_default.py F. <span class="o">[</span><span class="m">100</span>%<span class="o">]</span>
<span class="o">===================================</span> <span class="nv">FAILURES</span> <span class="o">===================================</span>
______________ test_vim_is_installed<span class="o">[</span>ansible://molecule_centos7<span class="o">]</span> _______________
<span class="nv">host</span> <span class="o">=</span> <testinfra.host.Host object at 0x7f6c912ed1d0>
def test_vim_is_installed<span class="o">(</span>host<span class="o">)</span>:
<span class="nv">vim</span> <span class="o">=</span> host.package<span class="o">(</span><span class="s2">"vim"</span><span class="o">)</span>
> assert vim.is_installed
E assert False
E + where <span class="nv">False</span> <span class="o">=</span> <package vim>.is_installed
tests/test_default.py:12: <span class="nv">AssertionError</span>
<span class="o">======================</span> <span class="m">1</span> failed, <span class="m">1</span> passed in <span class="m">9</span>.15 <span class="nv">seconds</span> <span class="o">======================</span>
</code></pre></div>
<p>El test falla! ¿Qué es lo que está pasando? El role ha fallado y no se ha instalado Vim? No, no es eso... el role funciona perfectamente, el problema es que en Debian cuando instalas el editor Vim se instalan los paquetes <code>vim</code> y <code>vim-common</code>, pero CentOS únicamente se instala <code>vim-common</code>, por lo que el test falla al buscar el paquete <code>vim</code> en esta distribución.</p>
<p>Editamos de nuevo el test y cambiamos el nombre del paquete de <code>vim</code> a <code>vim-common</code>:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">molecule/default/tests/test_default.py</span><a href='/files/2018-03-12-implementa-tests-en-tus-roles-de-ansible-con-molecule/test_default_vim_common.py'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">test_vim_is_installed</span><span class="p">(</span><span class="n">host</span><span class="p">):</span>
<span class="n">vim</span> <span class="o">=</span> <span class="n">host</span><span class="o">.</span><span class="n">package</span><span class="p">(</span><span class="s2">"vim-common"</span><span class="p">)</span>
<span class="k">assert</span> <span class="n">vim</span><span class="o">.</span><span class="n">is_installed</span>
</code></pre></div>
</figure>
<p>Y ahora si, al ejecutar el test vemos que el role ha funcionado perfectamente:</p>
<div class="highlight"><pre><span></span><code>--> Test matrix
└── default
└── verify
--> Scenario: <span class="s1">'default'</span>
--> Action: <span class="s1">'verify'</span>
--> Executing Testinfra tests found in /tmp/vim-installer/molecule/default/tests/...
<span class="o">=============================</span> <span class="nb">test</span> session <span class="nv">starts</span> <span class="o">==============================</span>
platform linux2 -- Python <span class="m">2</span>.7.14+, pytest-3.4.2, py-1.5.2, pluggy-0.6.0
rootdir: /tmp/vim-installer/molecule/default, inifile:
plugins: testinfra-1.11.1
collected <span class="m">2</span> items
tests/test_default.py .. <span class="o">[</span><span class="m">100</span>%<span class="o">]</span>
<span class="o">===========================</span> <span class="m">2</span> passed in <span class="m">9</span>.98 <span class="nv">seconds</span> <span class="o">===========================</span>
Verifier completed successfully.
</code></pre></div>
<p>Perfecto! Ya tenemos todos los tests de Molecule configurados.</p>
<p>Si recuerdas cuando estuvimos definiendo las secuencias en el archivo de configuración de Molecule seguramente te fijarías en que había una secuencia llamada <code>test</code> que se encargaba de llamar uno a uno a todos los tests, verdad? Me refiero a este código dentro del bloque <code>scenario</code> del archivo <code>molecule/default/molecule.yml</code>:</p>
<div class="highlight"><pre><span></span><code><span class="nt">test_sequence</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">lint</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">destroy</span>
<span class="c1"># - dependency</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">syntax</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">create</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">prepare</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">converge</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">idempotence</span>
<span class="c1"># - side_effect</span>
<span class="c1"># - verify</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">destroy</span>
</code></pre></div>
<p>Si ejecutamos ese test se lanzarán una a una todas acciones que hayamos configurado en esa secuencia, por lo que cuando queramos pasar todos los tests del role o estemos configurando el proyecto para utilizar un sistema de Integración Contínua (como el de <a href="https://docs.gitlab.com/ce/ci/">Gitlab-CI</a> que ya comenté <a href="/2017/04/24/integracion-continua-en-pelican-usando-gitlab-ci/">en este otro artículo</a>) no hace falta que los ejecutes uno a uno, puede ejecutarlos todos de forma automática con el comando:</p>
<div class="highlight"><pre><span></span><code><span class="o">(</span>venv<span class="o">)</span> $ molecule <span class="nb">test</span>
</code></pre></div>
<p>Y ahora si, creo que con esto tienes más que suficiente para implementar este genial framework de tests que es Molecule. Me temo que ya no hay excusa cuando al cambiar algo en un role se te rompa otra cosa accidentalmente.</p>
<p>Cubre todas las tareas que hagas con tests y dormirás más tranquilo!</p>
<p>Ah, se me olvidaba! Si tienes problemas con la configuración de alguno de los tests, puedes añadir el parámetro <code>--debug</code> a Molecule para que muestre mucha más información de lo que va haciendo en cada una de las acciones:</p>
<div class="highlight"><pre><span></span><code><span class="o">(</span>venv<span class="o">)</span> $ molecule --debug <span class="nb">test</span>
</code></pre></div>
<p>Como siempre, espero que el artículo te haya resultado de utilidad! Y por supuesto no dudes en distribuirlo y compartirlo con todo el mundo, pero por favor: <em>cita siempre la fuente original de éste artículo</em>.</p>
<p>Alaaaaaaaaaaaaaaaaaaaaaaa!</p>
<h2>Referencias<a name="refs"></a></h2>
<ul>
<li><a href="https://molecule.readthedocs.io/">https://molecule.readthedocs.io/</a></li>
<li><a href="https://github.com/metacloud/molecule">https://github.com/metacloud/molecule</a></li>
<li><a href="https://yamllint.readthedocs.io">https://yamllint.readthedocs.io</a></li>
<li><a href="https://testinfra.readthedocs.io">https://testinfra.readthedocs.io</a></li>
</ul>Correcta instalación de Java en Debian mediante paquetes DEB2017-11-12T15:58:52+01:002017-11-12T15:58:52+01:00BhEaNtag:pornohardware.com,2017-11-12:/2017/11/12/correcta-instalacion-de-java-en-debian-mediante-paquetes-deb/<p>Hay muchas formas de instalar diferentes versiones de Java en nuestros sistemas: en la propia web de <a href="www.oracle.com/technetwork/java/javase/downloads/">Oracle</a> (que como todos sabéis, es el <a href="https://elpais.com/tecnologia/2009/04/20/actualidad/1240216080_850215.html">propietario de Java</a> desde hace varios años) podemos descargar diferentes versiones (9, 8, 7, ...), en diferentes formatos (comprimido con <em>tar.gz</em>, paquetes para <a href="https://www.centos.org/">CentOS</a>/<a href="https://www.redhat.com/">RedHat</a>, ejecutables binarios, ...) y para diferentes sistemas operativos (Linux, MacOS, Windows y SPARC).</p>
<p>Incluso hay repositorios no-oficiales que ponen a disposición de todo el mundo los paquetes de instalación de Java en otros formatos, por lo que a simple vista cualquiera diría que existiendo tanta variedad incluso nosotros (fieles y exigentes defensores de <a href="https://www.debian.org/index.es.html">Debian</a> y de la <a href="https://es.wikipedia.org/wiki/Mantenibilidad">mantenibilidad</a> de los sistemas) estaríamos contentos, verdad?</p>
<p>Pues va a ser que no...</p>
<p>Hay muchas formas de instalar diferentes versiones de Java en nuestros sistemas: en la propia web de <a href="www.oracle.com/technetwork/java/javase/downloads/">Oracle</a> (que como todos sabéis, es el <a href="https://elpais.com/tecnologia/2009/04/20/actualidad/1240216080_850215.html">propietario de Java</a> desde hace varios años) podemos descargar diferentes versiones (9, 8, 7, ...), en diferentes formatos (comprimido con <em>tar.gz</em>, paquetes para <a href="https://www.centos.org/">CentOS</a>/<a href="https://www.redhat.com/">RedHat</a>, ejecutables binarios, ...) y para diferentes sistemas operativos (Linux, MacOS, Windows y SPARC).</p>
<p>Incluso hay repositorios no-oficiales que ponen a disposición de todo el mundo los paquetes de instalación de Java en otros formatos, por lo que a simple vista cualquiera diría que existiendo tanta variedad incluso nosotros (fieles y exigentes defensores de <a href="https://www.debian.org/index.es.html">Debian</a> y de la <a href="https://es.wikipedia.org/wiki/Mantenibilidad">mantenibilidad</a> de los sistemas) estaríamos contentos, verdad?</p>
<p>Pues va a ser que no...</p>
<p>¿Y porqué no? Pues porque ninguna de estas opciones está pensada para instalarse correctamente en Debian, y te voy a explicar porqué:</p>
<p>Podríamos descomprimir los archivos <code>.tar.gz</code> y copiar manualmente su contenido a <em>alguna parte</em> de nuestro disco duro, crear los <a href="https://es.wikipedia.org/wiki/Enlace_simb%C3%B3lico">enlaces simbólicos</a> que apunten a dichos archivos, añadir los <em>paths</em> a nuestras variables de entorno, etc.</p>
<p>Esto no es nada complicado, pero no es mantenible ya que si el dia de mañana queremos desinstalarlo (o actualizar a una nueva versión), volver sobre nuestros pasos y eliminar todo eso nos llevaría un tiempo que no siempre tendremos (aparte de que sería <em>un coñazo</em>, vaya). Por no mencionar que seguro que se nos olvidaría algo, y acabaríamos dejando archivos innecesarios en el disco, <em>ensuciando</em> cada vez más nuestro servidor.</p>
<p>Por lo tanto necesitamos aprovechar las ventajas de nos ofrecen los paquetes propios de cada distribución y de sus gestores, ya que ellos se encargan de instalar, actualizar y desinstalar correctamente las aplicaciones sin dejar el sistema en un estado inconsistente, manejar las dependencias que necesite la aplicación que estamos instalando, etc.</p>
<p>El problema es que Oracle solo proporciona paquetes para Linux en formato <a href="https://es.wikipedia.org/wiki/RPM_Package_Manager">RPM</a> (CentOS y RedHat) por lo que tendríamos que instalar el gestor de paquetes de RPM en nuestra distribución Debian.</p>
<p>Y aunque hacerlo es muy sencillo, no lo recomiendo en absoluto ya que aunque para cosas <em>sencillas</em> este método funciona bien, cada distribución suele tener una forma ligeramente distinta de hacer algunas cosas, rutas diferentes donde almacenar los archivos, etc. y normalmente no coinciden unas con otras. Si instalamos un paquete en una distribución para la que no ha sido pensado lo más normal es que la aplicación no se instale correctamente, y si por casualidad se instala, su funcionamiento podría no ser el adecuado.</p>
<p>Si hacer <a href="https://es.wikipedia.org/wiki/Depuraci%C3%B3n_de_programas"><em>debug</em></a> en el código que estamos escribiendo para solucionar un <a href="https://es.wikipedia.org/wiki/Error_de_software">bug</a> ya es complicado en algunas ocasiones, no parece buena idea añadir aún más posibles causas de error al asunto, no crees?</p>
<p>Queda descartado entonces el uso de paquetes RPM en sistemas Debian...</p>
<p>En este punto, puede que alguno de vosotros esté pensando en la herramienta <a href="https://wiki.debian.org/Alien">alien</a>, verdad? Para quienes no la conozcan, esta herramienta permite convertir paquetes de otras distribuciones a paquetes Debian.</p>
<p>Genial, ¿no? ¿ya tenemos la solución entonces? Pues me temo que no...</p>
<p>Convertir los paquetes mediante esta herramienta no siempre funciona. Para cosas muy sencillas quizás si, pero no siempre es capaz de interpretar todas las diferencias entre unas distribuciones y otras, por lo que la mayoría de las veces habrá una parte de la instalación que no se haga (no se establecerá un enlace simbólico, no se reiniciará un servicio o cualquier otra cosa) y de nuevo estaremos ante una instalación incompleta (o peor aún, inestable) de la aplicación.</p>
<p>Por lo tanto debemos instalar únicamente paquetes DEB que hayan sido generados y empaquetados pensando en que iban a ser instalados en un sistema Debian. Y Oracle no, pero como dije al principio hay muchos otros repositorios de código no-oficiales que ofrecen Java en otros formatos, incluyendo el que nosotros queremos.</p>
<p>El hecho de utilizar repositorios no-oficiales no tiene ningún problema <em>per se</em>, pero si al igual que yo sois un poco <em>precavidos</em> (por no decir paranoicos) seguro que no estáis cómodos instalando paquetes que no podéis comprobar si han sido manipulados con algún tipo de <a href="https://es.wikipedia.org/wiki/Malware"><em>malware</em></a>, especialmente si hablamos de entornos de producción.</p>
<p>Cada uno es libre de hacer lo que quiera (hasta el dia en el que yo mande, por supuesto) por lo que si decidís utilizar un repositorio no-oficial de Java para descargar e instalar los paquetes en vuestros sistemas no hay ningún problema. Yo sin embargo no me fio de nadie (por algo soy sysadmin!), por lo que no estoy a gusto usando estos repositorios.</p>
<p>Así que, ¿cómo lo hacemos entonces? ¿programamos en otro lenguaje que no sea Java? ¿nos olvidamos de Debian y reinstalamos CentOS en nuestros ordenadores? ¿dejamos la informática y nos dedicamos a criar ganado en la montaña? No tengo inconveniente en programar en cualquier lenguaje, y me encanta la montaña... pero jamas usaré CentOS en mis servidores, así que seguiré buscando una solución... xDDD</p>
<p>Por suerte, nuestra querida Debian ya pensó en esto y dió con la solución: <em>java-package</em>.</p>
<p>Tal y como se explica en la propia página de Debian, la aplicación <em>java-package</em> nos permite generar paquetes DEB partiendo de los archivos Java descargados de la web oficial de Oracle. Es decir, bajando el archivo <code>.tar.gz</code> de la versión de Java que queramos desde la web de Oracle, podemos generar un paquete DEB para instalar sin problemas en nuestra distribución Debian.</p>
<p>Ahora si, esto tiene mucha mejor pinta!</p>
<p>Lo primero que tenemos que hacer es instalar el paquete <em>java-package</em>:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install java-package
</code></pre></div>
<p>Este paquete nos provee del comando <code>make-jpkg</code>, que es quien se encarga de generar el paquete DEB.</p>
<p>Ahora vamos a descargar de la web de Java el archivo con la versión que queramos instalar.</p>
<p>Accedemos a <a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">la página de descargas de Java</a> y descargamos el archivo para Linux en formato <code>.tar.gz</code>:</p>
<p><img class="center" src="/images/posts/2017-11-12-correcta-instalacion-de-java-en-debian-mediante-paquetes-deb/screenshot-oracle-website.png"></p>
<p>A dia de hoy la última versión disponible es la 9.0.1. No obstante vamos a descargar también la version 8 (concretamente la <em>8u151</em>) para que veáis cómo pueden convivir varias versiones de Java al mismo tiempo sin problemas.</p>
<p>Guardaremos ambos archivos en <code>/tmp</code>:</p>
<div class="highlight"><pre><span></span><code><span class="err">└─ tmp/</span>
<span class="err"> ├─ jdk-8u152-linux-x64.tar.gz</span>
<span class="err"> ├─ jdk-9.0.1_linux-x64_bin.tar.gz</span>
</code></pre></div>
<p>Si os fijáis bien, los nombres de ambos archivos son ligeramente diferentes, no solo en la versión sino también en otras partes.</p>
<p>Es muy importante que os fijéis en esto ya que parece ser que Oracle ha cambiado la forma de nombrar dichos archivos a partir de la versión 9, y esto provoca que el comando <code>make-jpkg</code> no reconozca el archivo correctamente.</p>
<p>Quizás cuando leáis este artículo ya lo hayan corregido (realmente es un fallo muy absurdo), pero a dia de hoy es necesario renombrar el archivo al formato que tenían antes para que la generación del paquete funcione. El nombre debe ser <em>jdk-version-linux-arquitectura.tar.gz</em>:</p>
<div class="highlight"><pre><span></span><code>$ mv /tmp/jdk-9.0.1_linux-x64_bin.tar.gz /tmp/jdk-9-linux-x64.tar.gz
</code></pre></div>
<p>Ahora ya tenemos los 2 archivos con los nombres que <code>make-jpkg</code> espera encontrar:</p>
<div class="highlight"><pre><span></span><code><span class="err">└─ tmp/</span>
<span class="err"> ├─ jdk-8u152-linux-x64.tar.gz</span>
<span class="err"> ├─ jdk-9-linux-x64.tar.gz</span>
</code></pre></div>
<p>Ahora ejecutamos el comando <code>make-jpkg</code> dos veces, una con cada archivo:</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">cd</span> /tmp
$ make-jpkg jdk-8u152-linux-x64.tar.gz
$ make-jpkg jdk-9-linux-x64.tar.gz
</code></pre></div>
<p>Si todo ha ido bien, una vez que hayan finalizado tendremos 2 nuevos paquetes DEB en <code>/tmp</code>:</p>
<div class="highlight"><pre><span></span><code><span class="err">└─ tmp/</span>
<span class="err"> ├─ oracle-java8-jdk_8u151_amd64.deb</span>
<span class="err"> ├─ oracle-java9-jdk_9_amd64.deb</span>
</code></pre></div>
<p>Y ya podremos instalarlos sin ningún problema con nuestro maravilloso <a href="https://es.wikipedia.org/wiki/Dpkg">dpkg</a>:</p>
<div class="highlight"><pre><span></span><code>$ sudo dpkg -i /tmp/oracle-java8-jdk_8u151_amd64.deb
$ sudo dpkg -i /tmp/oracle-java9-jdk_9_amd64.deb
</code></pre></div>
<p>Hecho! Ya tenemos instaladas las 2 versiones de Java en nuestro sistema. Puedes comprobarlo con:</p>
<div class="highlight"><pre><span></span><code>$ dpkg -l <span class="s2">"oracle-java*"</span>
<span class="nv">Desired</span><span class="o">=</span>Unknown/Install/Remove/Purge/Hold
<span class="p">|</span> <span class="nv">Status</span><span class="o">=</span>Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
<span class="p">|</span>/ Err?<span class="o">=(</span>none<span class="o">)</span>/Reinst-required <span class="o">(</span>Status,Err: <span class="nv">uppercase</span><span class="o">=</span>bad<span class="o">)</span>
<span class="o">||</span>/ Name Version Architecture Description
+++-<span class="o">====================</span>-<span class="o">============</span>-<span class="o">===============</span>-<span class="o">=====================================================</span>
ii oracle-java8-jdk 8u152 amd64 Java Platform, Standard Edition <span class="m">8</span> Development Kit
ii oracle-java9-jdk <span class="m">9</span> amd64 Java Platform, Standard Edition <span class="m">9</span> Development Kit
</code></pre></div>
<p>De ahora en adelante, podemos utilizar nuestro gestor de paquetes para gestionarlas como haríamos con cualquier otro paquete instalado por medio de <code>dpkg</code> o incluso de <code>apt-get</code>. Por ejemplo, si quisiéramos desinstalar una de ellas (la versión 8, por ejemplo) bastaría con ejecutar:</p>
<div class="highlight"><pre><span></span><code>$ sudo dpkg -r oracle-java8-jdk
</code></pre></div>
<p>Para seleccionar una o otra como la versión <em>por defecto</em> solo tenéis que apuntar los <a href="https://es.wikipedia.org/wiki/Enlace_simb%C3%B3lico">enlaces simbólicos</a> que hay en <code>/etc/alternatives/</code> al directorio correspondiente.</p>
<p>Con este comando podéis ver a donde apunta cada comando de java (<code>java</code>, <code>javac</code>, <code>javadoc</code>, etc) actualmente:</p>
<div class="highlight"><pre><span></span><code>$ ls -l /etc/alternatives/java*
lrwxrwxrwx <span class="m">1</span> root root <span class="m">48</span> Nov <span class="m">12</span> <span class="m">15</span>:31 /etc/alternatives/java -> /usr/lib/jvm/oracle-java9-jdk-amd64/bin/java
lrwxrwxrwx <span class="m">1</span> root root <span class="m">45</span> Nov <span class="m">12</span> <span class="m">15</span>:45 /etc/alternatives/javac -> /usr/lib/jvm/oracle-java9-jdk-amd64/bin/javac
lrwxrwxrwx <span class="m">1</span> root root <span class="m">47</span> Nov <span class="m">12</span> <span class="m">15</span>:45 /etc/alternatives/javadoc -> /usr/lib/jvm/oracle-java9-jdk-amd64/bin/javadoc
lrwxrwxrwx <span class="m">1</span> root root <span class="m">45</span> Nov <span class="m">12</span> <span class="m">15</span>:45 /etc/alternatives/javah -> /usr/lib/jvm/oracle-java9-jdk-amd64/bin/javah
lrwxrwxrwx <span class="m">1</span> root root <span class="m">45</span> Nov <span class="m">12</span> <span class="m">15</span>:45 /etc/alternatives/javap -> /usr/lib/jvm/oracle-java9-jdk-amd64/bin/javap
lrwxrwxrwx <span class="m">1</span> root root <span class="m">50</span> Nov <span class="m">12</span> <span class="m">15</span>:31 /etc/alternatives/javaws -> /usr/lib/jvm/oracle-java9-jdk-amd64/bin/javaws
</code></pre></div>
<p>En mi caso todos los comandos apuntan a la versión 9 porque están enlazados con los comandos que hay en <code>/usr/lib/jvm/oracle-java9-jdk-amd64/bin</code>. Podéis verlo aquí:</p>
<div class="highlight"><pre><span></span><code>$ java -version
java version <span class="s2">"9.0.1"</span>
Java<span class="o">(</span>TM<span class="o">)</span> SE Runtime Environment <span class="o">(</span>build <span class="m">9</span>.0.1+11<span class="o">)</span>
Java HotSpot<span class="o">(</span>TM<span class="o">)</span> <span class="m">64</span>-Bit Server VM <span class="o">(</span>build <span class="m">9</span>.0.1+11, mixed mode<span class="o">)</span>
</code></pre></div>
<p>Si quisiera que la versión de Java por defecto fuera la 8, solo tendría que cambiar el destino de los enlaces simbólicos. Por ejemplo:</p>
<div class="highlight"><pre><span></span><code>$ sudo ln -sf /usr/lib/jvm/oracle-java8-jdk-amd64/jre/bin/java /etc/alternatives/java
</code></pre></div>
<p>Ahora la versión de Java por defecto es la 8:</p>
<div class="highlight"><pre><span></span><code>$ java version <span class="s2">"1.8.0_152"</span>
Java<span class="o">(</span>TM<span class="o">)</span> SE Runtime Environment <span class="o">(</span>build <span class="m">1</span>.8.0_152-b16<span class="o">)</span>
Java HotSpot<span class="o">(</span>TM<span class="o">)</span> <span class="m">64</span>-Bit Server VM <span class="o">(</span>build <span class="m">25</span>.152-b16, mixed mode<span class="o">)</span>
</code></pre></div>
<p>Y eso es todo!</p>
<p>Como siempre, espero que el artículo os haya resultado de utilidad! Y por supuesto, no dudéis en distribuirlo y compartirlo con todo el mundo (pero por favor, cita siempre la fuente original de éste artículo).</p>
<p>Alaaaaaaaaaaaaaaaaaaaaaaa!</p>Firmando emails con OpenDKIM2017-11-10T23:50:06+01:002017-11-10T23:50:06+01:00BhEaNtag:pornohardware.com,2017-11-10:/2017/11/10/firmando-emails-con-opendkim/<p>El <a href="http://es.wikipedia.org/wiki/Spam">SPAM</a> es una de las mayores <em>lacras</em> que inundan Internet desde el principio de su creación. Genera <a href="https://www.aeaweb.org/articles?id=10.1257/jep.26.3.87">cien veces más pérdidas a la sociedad que beneficio a sus creadores</a> y supone el <a href="https://mybroadband.co.za/news/internet/14250-spam-a-whopping-84-of-email-traffic.html">84% de los emails que recibimos</a>. Y este mal existe, entre otras cosas, porque el sistema de correo electrónico de Internet se diseñó dando por hecho que toda la gente que lo iba a utilizar lo haría <em>de buena fe</em>: craso error.</p>
<p>Pensar que nadie iba a utilizar el correo electrónico para <em>hacer cosas malas</em> hizo que se diseñara, entre otras muchas cosas, sin ningún sistema que garantice a quien los recibe que dichos mensajes no han sido <em>manipulados por el camino</em> o escritos por remitentes falsos.</p>
<p>Por estos motivos, <em>Internet</em> lleva años desarrollando herramientas y sistemas que ayuden a <em>paliar</em> los problemas de diseño que el correo electrónico tiene de base.</p>
<p><a href="http://www.dkim.org/">DKIM</a> es uno de estos mecanismos, y permite a los destinatarios de un mensaje de correo electrónico saber si un email ha sido realmente enviado por el remitente y no por alguien haciéndose pasar por él (esta práctica se denomina <a href="https://es.wikipedia.org/wiki/Email_spoofing">mail spoofing</a>).</p>
<p>El <a href="http://es.wikipedia.org/wiki/Spam">SPAM</a> es una de las mayores <em>lacras</em> que inundan Internet desde el principio de su creación. Genera <a href="https://www.aeaweb.org/articles?id=10.1257/jep.26.3.87">cien veces más pérdidas a la sociedad que beneficio a sus creadores</a> y supone el <a href="https://mybroadband.co.za/news/internet/14250-spam-a-whopping-84-of-email-traffic.html">84% de los emails que recibimos</a>. Y este mal existe, entre otras cosas, porque el sistema de correo electrónico de Internet se diseñó dando por hecho que toda la gente que lo iba a utilizar lo haría <em>de buena fe</em>: craso error.</p>
<p>Pensar que nadie iba a utilizar el correo electrónico para <em>hacer cosas malas</em> hizo que se diseñara, entre otras muchas cosas, sin ningún sistema que garantice a quien los recibe que dichos mensajes no han sido <em>manipulados por el camino</em> o escritos por remitentes falsos.</p>
<p>Por estos motivos, <em>Internet</em> lleva años desarrollando herramientas y sistemas que ayuden a <em>paliar</em> los problemas de diseño que el correo electrónico tiene de base.</p>
<p><a href="http://www.dkim.org/">DKIM</a> es uno de estos mecanismos, y permite a los destinatarios de un mensaje de correo electrónico saber si un email ha sido realmente enviado por el remitente y no por alguien haciéndose pasar por él (esta práctica se denomina <a href="https://es.wikipedia.org/wiki/Email_spoofing">mail spoofing</a>).</p>
<p>Hay distintos sistemas para otorgar un poco más de seguridad al envío de correo electrónico, pero en este artículo me voy a centrar únicamente en explicar qué es DKIM y cómo configurar la implementación <a href="https://es.wikipedia.org/wiki/C%C3%B3digo_abierto">open-source</a> de dicho protocolo: <a href="http://www.opendkim.org/">OpenDKIM</a>.</p>
<p>Comencemos:</p>
<ol>
<li><a href="#whatis">¿Qué es DKIM y OpenDKIM?</a></li>
<li><a href="#install">Instalación y configuración de OpenDKIM</a></li>
<li><a href="#test">Comprobación del sistema</a></li>
<li><a href="#refs">Referencias</a></li>
</ol>
<h2>¿Qué es DKIM y OpenDKIM?<a name="whatis"></a></h2>
<p>Como comentaba al principio, DKIM es un mecanismo a través del cual se intenta evitar la suplantación de identidades a la hora de enviar mensajes de correo electrónico.</p>
<p>DKIM otorga a un servidor de correo la capacidad de <em>firmar</em> los emails que envía, de forma que cuando éstos llegan a su destinatario, este puede comprobar que realmente fueron enviados por dicho servidor y no por otro servidor que estuviera haciéndose pasar por él.</p>
<p>Un correo electrónico (de ahora en adelante: <em>un email</em>) no es más que un <em>paquete de datos</em> que contiene cabeceras (<em>headers</em>) con la fecha de envío, el nombre del remitente, el asunto del mensaje, etc. y un cuerpo (<em>body</em>) que contiene el texto del mensaje. Un ejemplo muy básico de un email sería algo así:</p>
<div class="highlight"><pre><span></span><code><span class="n">Date</span><span class="o">:</span> <span class="n">Thu</span><span class="o">,</span> <span class="mi">12</span> <span class="n">Oct</span> <span class="mi">2017</span> <span class="mi">04</span><span class="o">:</span><span class="mi">15</span><span class="o">:</span><span class="mi">51</span>
<span class="n">Content</span><span class="o">-</span><span class="n">type</span><span class="o">:</span> <span class="n">text</span><span class="o">/</span><span class="n">plain</span>
<span class="n">To</span><span class="o">:</span> <span class="n">destinatario</span><span class="err">@</span><span class="n">dominio1</span><span class="o">.</span><span class="na">com</span>
<span class="n">From</span><span class="o">:</span> <span class="s2">"Remitente"</span> <span class="o"><</span><span class="n">remitente</span><span class="err">@</span><span class="n">dominio2</span><span class="o">.</span><span class="na">com</span><span class="o">></span>
<span class="n">Subject</span><span class="o">:</span> <span class="n">Mensaje</span> <span class="n">urgente</span>
<span class="n">Visita</span> <span class="n">pornohardware</span><span class="o">.</span><span class="na">com</span><span class="o">!</span>
</code></pre></div>
<p>El texto <code>Visita pornohardware.com!</code> sería el contenido del email (<em>body</em>), y <code>Date</code>, <code>Content-type</code>, <code>To</code>, <code>From</code>, etc. serían las cabeceras (<em>headers</em>) con la información sobre este.</p>
<p>Cuando este email llega a nuestro correo, la aplicación que usemos para leerlo nos dirá que tenemos un mensaje enviado el dia <code>12 de octubre de 2017</code> de parte de un tal <code>"Remitente" <remitente@dominio2.com></code> y cuyo <em>asunto</em> es <code>Mensaje urgente</code>.</p>
<p>¿Pero qué sucedería si alguien nos envía ese mismo mensaje, pero cambiando la cabecera <code>From</code>?</p>
<div class="highlight"><pre><span></span><code><span class="n">Date</span><span class="o">:</span> <span class="n">Thu</span><span class="o">,</span> <span class="mi">12</span> <span class="n">Oct</span> <span class="mi">2017</span> <span class="mi">04</span><span class="o">:</span><span class="mi">15</span><span class="o">:</span><span class="mi">51</span>
<span class="n">Content</span><span class="o">-</span><span class="n">type</span><span class="o">:</span> <span class="n">text</span><span class="o">/</span><span class="n">plain</span>
<span class="n">To</span><span class="o">:</span> <span class="n">destinatario</span><span class="err">@</span><span class="n">dominio1</span><span class="o">.</span><span class="na">com</span>
<span class="n">From</span><span class="o">:</span> <span class="s2">"Elon Musk"</span> <span class="o"><</span><span class="n">elonmusk</span><span class="err">@</span><span class="n">spacex</span><span class="o">.</span><span class="na">com</span><span class="o">></span>
<span class="n">Subject</span><span class="o">:</span> <span class="n">Mensaje</span> <span class="n">urgente</span>
<span class="n">Visita</span> <span class="n">pornohardware</span><span class="o">.</span><span class="na">com</span><span class="o">!</span>
</code></pre></div>
<p>Lo que sucedería en este caso es que al abrir nuestro cliente de correo creeríamos que el sr. <code>Elon Musk <elonmusk@spacex.com></code> nos habría escrito un email.</p>
<p>Esto es porque no se hace ninguna validación sobre si una cabecera ha sido manipulada o sobre si el remitente es realmente quien dice ser. Y cambiar las cabeceras de un email es absolutamente trivial, no tiene ninguna dificultad para cualquiera que tenga unos mínimos conocimientos básicos de informática (y realmente tampoco son necesarios, ya que si no los tienes, existen multitud de programas que te permiten hacerlo <em>a golpe de click</em>).</p>
<p>Es extremadamente fácil manipular el remitente de un email, hasta un niño pequeño, un patán analfabeto o incluso un amante del <em>reggeton</em> podría hacerlo, así que: ¿cómo podemos evitar que nos engañen cuando nos escriben un email?: firmando los emails que enviamos, y asegurándonos de que el destinatario verifica dicha firma cuando los recibe. Y eso es exactamente lo que nos permite hacer DKIM.</p>
<p>Cómo ya expliqué en el artículo <a href="/2015/01/01/instalacion-y-configuracion-de-un-servidor-de-correo-completo-en-linux/">Instalación y configuración de un servidor de correo completo en Linux</a>, el flujo común del envío de un email es:</p>
<p><span class="graphviz" style="text-align: center;"><img src="data:image/png;base64,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qK6uxu3bt5GcnIwePXqI2q6mxIpdKHO36fZQ5969e/Hqq68a/b2vry+CgoKgVqvxzTff2DRWU+exJearpWMwRkhsgDjzTbNPSklJwalTp1BVVYXi4mLEx8fj3r17UCqV2styhbBVnzVn6nZoTtxi9NudO3cgl8sRFBSEH374weR2ElH74dBgieu6iMhkt27dEnw5r8bQoUPx6NEjnWUODg5wd3fHU089hZCQEERFRcHf31/vsxUVFdi4cSPy8vJQVlaGbt26ISIiAt7e3vj8888BAAEBAdi1a5fO59LT07F161ZkZWVh4MCBOr9r/u5CAJg4caL2CcPFxcVIT0/H6dOn8eTJEwwYMAALFizA9u3bUVhYCKDxLFZiYmKL7a6srMSWLVu071H09PSEv78/5syZg2HDhmnLXbt2Dbt27cK5c+dw584dSKVS9OvXD5MnT8bkyZN17pt98OCBdp2a9+w+//zzWLRokfZBKJcuXTJ4NlulUrXaB35+fli7di2AxoerbNiwAevWrcPly5dRV1eHoKAgLF26VO89u0Lb2hK1Wo2PPvoIubm5+PXXXxEYGIgVK1bggw8+wNWrVwEAc+fOxZgxY/Ta9/rrr2PJkiV6l8+OHDkS//jHP1qsV0jshvr09ddfx+jRoxETE6OzPC4uDsHBwZg1a5bO8gULFmDhwoWCt+nY2NhWx6h5+40xdx4BQElJCV588UXtz0OGDMHOnTt1yty5c0fvaedeXl74+OOPTR6rtsTalKnz2BLz1VIxGGNKbELn21//+tcW62y+T3JxcdG+LzYsLAyAsH2SJfvM2PwVczs0NW4x+u3OnTsYP348GhoakJWVhQEDBrQ4Vs35+PigW7duJn2GiCxiD5NdonbCnGSXiIiI2hcmu0Ttxh5exkxERERERER2h8kuERERERER2R0mu0RERERERGR3mOwSERERERGR3WGyS0RERERERHaHyS4RERERERHZHSa7REREREREZHeY7BIREREREZHdYbJLREREREREdofJLhEREREREdkdJrtERERERERkd5jsEhERERERkd1hsktERERERER2h8kuERERERER2R0mu0RERERERGR3mOwSERERERGR3WGyS0RERERERHaHyS4RERERERHZHSa7REREViBVV6Lnjcu2DoOIiKjTcLJ1AETU6A9/+IOtQyAiS/p3EXDyLHr/OcbWkRAREXUKPLNLREREREREdofJLhEREREREdkdJrtERERERERkd5jsEhERERERkd1hsktERERERER2h8kuERERERER2R0mu0RERERERGR3mOwSERERERGR3WGyS0RERERERHaHyS4RERERERHZHSa7REREREREZHeY7BIREREREZHdYbJLREREREREdofJLhEREREREdkdJrtERERERERkd5jsEhERERERkd1hsktERERERER2h8kuERERERER2R0mu0RERERERGR3mOwSERERERGR3WGyS0RERERERHaHyS4RERERERHZHSa7REREREREZHeY7BIREREREZHdYbJLREREREREdofJLhEREREREdkdJrtERERERERkd5jsEhERERERkd1hsktERERERER2h8kuERERERER2R0mu0RERERERGR3nGwdABERkd2peQyU39Nd9uB+439/+T/d5RJHoNdT1omLiIioE3FoaGhosHUQREREduXxb8DHq4C62tbLDhwMTJ5t6YiIiIg6mz28jJmIiEhsUhfANwBwaO0w6wAEBFslJCIios6GyS4REZElBIYADfUtl3FyakyKiYiISHRMdomIiCzhGT/AWWr89xIJMGgI4NTFejERERF1Ikx2iYiILMHRCfAbAjg6Gv59fQMQyEuYiYiILIXJLhERkaUEBAN1dYZ/5+IC/HGgdeMhIiLqRJjsEhERWUq/AYCru/5yR0cgIKTxUmYiIiKyCB5liYiILMXBofFS5eaXMtfV8SnMREREFsZkl4iIyJIMXcrs4Qn8Vz/bxENERNRJMNklIiKypKf7AV1lv//s6AgMDgXgYLOQiIiIOgMmu0RERJYWGPL7pcy8hJmIiMgqmOwSERFZWtNLmWXeQK+nbBsPERFRJ8Bkl4iIyNJ69gG8ejX+f9Dzto2FiIiok3CydQBE1LrKykpbh0BEbSQdMBgu90/goY8v6jmniTq0Ll26wM3NzdZhEFErmOwSdQC3b9+2dQhE1EZd3L3gI/NGcaUaqFTbOhwiaoOuXbviD3/4g63DIKJW8DJmIiIiK3ji6o5fAobaOgwiIqJOg8kuERGRlVTLeto6BCIiok6DyS4RERERERHZHSa7REREREREZHeY7BIREREREZHdYbJLREREREREdofJLhEREREREdkdJrtERERERERkd5js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3L4FgGXLlqFbt25ISUnBd999h+rqaty4cQMrV640eHlmXFwc+vbti5SUFJw6dQpVVVUoLi5GfHw87t27B6VSqb1Mti3MiUuMedC3b1+kpqYiNzcXVVVVKCkpwerVq3Hv3j2de3at1Q/mtlGM+GwxBobU19ejvLwcJ06cwPz585GRkYFXX30VKSkp2oTW3Dluzblz584dyC6BedcAACAASURBVOVyBAUF4YcffjC5H4io43BosMQ1f0QkqsuXL5tUfujQoXj06JGgsqmpqRg/fjwyMzOxdu1and+9/vrrWLJkSYufr6ysxJYtW7Tvj/T09IS/vz/mzJmDYcOGAQAuXbqk91f6119/HaNHj0ZMTIzO8ri4OAQHB2PWrFk6yxcsWICFCxeioqICGzduRF5eHsrKytCtWzdERETA29sbn3/+OQAgICAAsbGxeu9YnDhxIvz8/Exu57Vr17Br1y6cO3cOd+7cgVQqRb9+/TB58mRMnjxZ+yVPaH+0pi19umTJEgQFBeksHzlyJP7xj3/oLEtPT8fWrVuRlZWFgQMH6vyu+ftIgca+S05OFtz/u3btMto+oesYP368zcfKUD8DgEqlMhqDuX0LNN5HmZ6ejtOnT+PJkycYMGAAFixYgO3bt6OwsBBA49PMExMTATS+v1XThpKSEri4uGjf3xoWFmZ2G5ozNS4x5kHztslkMjz//PNYtGiR3kOHxOoHU/rKlDYKia811h4DQ8cRBwcHuLu746mnnkJISAiioqLg7++v91lz9xPWmjt37tzB+PHj0dDQgKysLAwYMKDV/miua9eu+MMf/mDy54jIqvYw2SXqAExNdomIiMhymOwSdQh7eBkzERERERER2R0mu0RERERERGR3mOwSERERERGR3WGyS0RERERERHaHyS4RERERERHZHSa7REREREREZHeY7BIREREREZHdYbJLREREREREdofJLhEREREREdkdJrtERERERERkd5jsEhERERERkd1hsktERERERER2h8kuERERERER2R0mu0RERERERGR3mOwSERERERGR3WGyS0RERERERHaHyS4RERERERHZHSa7REREREREZHeY7BIREVmBa+V9PH3pW1uHQURE1Gk42ToAImrd4MGDbR0CEbXVv4uAvOvoMfV1W0dCRETUKfDMLhEREREREdkdJrtERERERERkd5jsEhERERERkd1hsktERERERER2h8kuERERERER2R0mu0RERERERGR3mOwSERERERGR3WGyS0RERERERHaHyS4RERERERHZHSa7REREREREZHeY7BIREREREZHdYbJLREREREREdofJLhEREREREdkdJrtERERERERkd5jsEhERERERkd1hsktERERERER2h8kuERERERER2R0mu0RERERERGR3mOwSERERERGR3WGyS0RERERERHaHyS4RERERERHZHSa7REREREREZHeY7BIREREREZHdYbJLREREREREdofJLhEREREREdkdJrtERERERERkd5jsEhERERERkd1hsktERERERER2h8kuERERERER2R0mu0RERERERGR3mOwSERERERGR3WGyS0RERERERHbHoaGhocHWQRAREdkV9a/Ans+B+rrfl9U+AR49Ajy76pbt/V/ApBjrxkdERGT/9jjZOgIiIiK749G1MdG994v+736rbvKDAxAQbLWwiIiIOhNexkxERGQJg58HJAIOs/5MdomIiCyByS4REZEl+D8LtHSnkIMD0Oe/gO49rBcTERFRJ8Jkl4iIyBK6dgee/kNjUmuIgwQIet66MREREXUiTHaJiIgsZfBzgJFcF/X1gN8Qq4ZDRETUmTDZJSIishT/Z2Ew25U4AP18AXdPq4dERETUWTDZJSIishQXN+CPAxovWW6qAY1nfYmIiMhimOwSERFZUmCI/oOqJBJg4GDbxENERNRJMNklIiKypIFBgKPj7z9LJIBvACB1sV1MREREnQCTXSIiIkvq4gwMCPz9nbv1DUBAiG1jIiIi6gSY7BIREVlaYEjj05cBoEsX4Bk/28ZDRETUCTDZJSIisrT/HgQ4Sxv/f1AQ4NTFtvEQERF1Ak7NFzx58gTV1dW2iIWIiMhuuT7jD+cfLqLqj4NQW1lp63CIiIjsSrdu3fSW6SW71dXVuH37tlUCIiIi6iw8uvXGf0ld8Z+GLmjgcZaIiEhUhpJdXsZMRERkBWqvPrj/34FocHCwdShERESdApNdIiIia3BwQNl/B9o6CiIiok6DyS4REZGV8KwuERGR9TDZJSIiIiIiIrvDZJeIiIiIiIjsDpNdIiIiIiIy2ZYtW/D888+joKDA1qEQGaT36iFzDB06FI8ePRJU9quvvkJgYCAyMzOxdu1aAECvXr1w7Ngx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Unx8vDIzM5Wdnd3sjQhOnjypSZMm6ejRo8rOztauXbu0cOFCvfHGGzp16pTN/qWlpUpOTtaWLVuUlpam3bt3a926dQoLC9P06dOVm5vrdB2a42q5nG3b5pjrtnXrVkvdNmzYoMGDB2vhwoXasGGDT9rB2bZypY7Olq+19YHZ1q1bFR8frx49ekiS7rnnHrVv3175+fk6d+6c1b5N2y8jI0MPP/ywduzYoVdeeUUFBQWaP3++1Xv27NmjefPmaejQofrggw/08ccfa8KECZa7fLbEl33W0vhz5sYiVVVVWrRokX73u99p+/btevvtt1VeXq5p06bps88+s+znjT7zZr+7m3bTNlmyZIkeffRR7dy5UwsWLNDmzZu1YMECZWRkaNasWfr000/1xBNPKDc3V3/+85+t8nR2bHjjBi+RkZEymUy65ZZbnFrL3eGLtSA/P18vvfSS3n33XR0/flwhISEymUxKT09XSkqKTCaTOnbsaJXGiBEjZDKZ1L9/f5v03W1zR/PO1bXL0/VAcn+sOrNeeZqnJ5xZS9zpc0kqKCiwulnorFmzJElz5syxBLruHms9addAHPtcybO5tceV85jGGrfXq6++qs8//9ymvTxdS9wZJ86cXwd6zXGmPzxZf2GNYLcZ9u7G3PQbDnf9+9//Vu/evZWYmKjQ0FB169ZNf/jDH9SrVy+r/ZYtW6aioiLNnz9ft956q8LDw9W7d28tWbJE9fX1Wrx4sd30p02bpsGDByssLEwDBw7UF198oejoaP32t79VXV2d5VMss0OHDqmkpER33nlni2VftmyZLly4oLS0NCUmJio8PFyxsbF66aWXVFpaarP/0qVL9f3332vBggVKSkpSRESEevXqpczMTF1xxRV6+eWXdfbsWafr4K1yudu29uqWlpampKQkderUSd26dVNKSopGjBjht3ZwtI8rdXS3fIHuA7NNmzbpvvvus/wdHR2tpKQk1dbW6sMPP2z2vQ888IDi4+PVsWNHDRs2TElJSfryyy9VVlZmtd/gwYM1ffp0de7cWdHR0XrooYc0duxYvfvuuw6/cXDEm33mzPhrSUVFhebOnauEhASFh4drwIABysjI0KVLl5SRkWHZzxt95s1+91ba48ePV//+/dWxY0eNGzdOvXv31p49ezRlyhT17dtX4eHhmjBhgnr06GH30nhvjg1nPPLI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qFGqra21e8OrVatWafTo0V59pmFdXZ0OHz6smJgYTZo0SdHR0ZaT1IsXL3otn0Dn6a2ymD9Vt3eHywkTJigrK8vyt6/60tUymy+53rNnj9X2srIynThxwmZ/cx2b/ra5urpaBQUFCg0Ntbnk0tk8S0tLbb5JNYuJiVFJSYnN/qdPn7bZ15W2daX+3hibvhzf3krblfZLTEy0tFP79u2VmJio119/XUFBQXZ//37x4kV9+eWXVtu++eYblZSUqE+fPpZvhrw5P7zVLq7OFW/UoTXNFUd27typLl262A10pYZ7JkgNN7Byd4wHcu5VVVXp2LFjVtvsjVl/1EFybc65MhZa4ko7uJJvXV2d5s2bZ7nreOOfBDz55JPasWOHJO8ce9wREhKi5ORknTt3Tm+//ba2bNmiyZMne5yuL+vj7LxuTedbuHwQ7MKnUlNT1bNnTz333HPas2ePKioqVF5ero0bN2rlypV66qmnvPotYXBwsAYPHqzS0lKtXr1aZWVlunjxovbv3291Z2FvCkSe3ipLamqqevTooaysLOXn56uyslLFxcVatGiRzpw5Y/WbXV/1patlnjt3rqKiopSZmal9+/apqqpK3333nZ5++mm7l06a65iZmaldu3apsrJShYWFWrBggc6cOaO0tDTLJViO2Mvz22+/1XPPPefwk+zhw4erpKRE69atU1VVlU6dOqWMjAy736q40rau1N8bY9OX49tbabs6Nl988UUdP35c1dXVOnfunFatWqX6+nq7j86IiIjQsmXL9MUXX+inn37S0aNHlZaWpg4dOigtLc3tMvijXdyZK57WoTXNFUfy8vJ0//33O3y9d+/eiouLU0VFhT755JNm03IkkHOvY8eOWrx4sY4cOdLsmPVHHcycnXOujIWWuNIOruSbmZmp3bt364UXXmj2N8feOPa4a+LEiQoNDdXy5cs1bNgwXXPNNR6n6cv6ODuvXR2TRUVFio+PV1xcnL7++mtPmwCXqaB6vu+/7J08edLu5YvNGTJkiNN3xszKytKYMWOsnj1p9thjj2n27NnNvr+8vFxvvvmm5blskZGR6tevn6ZOnaphw4ZJarjJw6RJk2zSHjlypJKTk622p6amKiEhQVOmTLHaPmPGDD3xxBMqKyvT8uXLtXv3bpWWlioqKkojRoxQTEyM/va3v0mS+vfvr5SUFJvnTd59993q27evy/V0Ns8xY8bYTTspKcnv9V+/fr2khufmmfvH/Jzdm2++WTNnzrS5iY0nfTl79mybSwJvu+02rVixwuUyFxYWKjs7W/v377c8x3PGjBl65513rJ7jmZ6ebreOYWFhlmcDDh061GG/NtY4z5qaGvXt21epqalauXKlDh06ZHmEhllFRYVeeeUV5efn6/z58xowYIDmz5+vF198UV999ZUk6dFHH9Xvf/97p9vWXllaqr+rbWuPp2k0t3Z4o3yutN+xY8e0fv16HTx4UEVFRQoNDVWvXr00fvx4jR8/3upy5QcffFBlZWV66623lJWVpcOHD6umpkZxcXGaM2eOzV3r3Z0fkmQymbza5mauzhVXxqEzeQZ6rjRWXFysUaNGWf4eOHCg1q5da7VPUVGR7rzzTqtt3bp10+uvv+7zdc0ed44t5mdDv/baa/ryyy9VW1trM2b9OQ5dmXOujoWm7D0ju7l2cDXfO++8UxMnTnRYV6nhzsIjR46U5Nyxx51jpjPS09P13nvvKScnR4MGDXLqPS2d53lyLG0pbWfntStjsqioSGPGjFF9fb1yc3MVGxvrVDuY9ezZ0+YSdVx2NhLsGoA7wS4A75g+fbrdE3hc/szBrvkupPAMcwXwn7y8PK1bt67FD8TgGMGuIWzkMmYAAADAQDZs2GBzBRjQFhHsAgAAAJex3NxczZ07V1VVVdqwYYPOnz9vc0k+0BYR7AKAGz766CPFxcWpoKBA1dXViouL0/PPPx/oYsELcnJyFBcXp2PHjqmkpERxcXFavnx5oIt12WKuAP6xY8cODR8+XOvXr9eSJUv89shHoDXjN7sGwG92AQAAAO/hN7uGwG92AQAAAADGQ7ALAAAAADAcgl0AAAAAgOEQ7AIAAAAADIdgFwAAAABgOAS7AAAAAADDIdgFAAAAABgOwS4AAAAAwHAIdgEAAAAAhkOwCwAAAAAwHIJdAAAAAIDhEOwCAAAAAAyHYBcAAAAAYDgEuwAAAAAAw2kf6ALAc+Hh4YEuAgAAAGAYHTp0CHQR4AUEuwYQExMT6CIAAAAAQKvCZcwAAAAAAMMh2AUAAAAAGA7BLgAAAADAcP4/LyeaPo4rwp4AAAAASUVORK5CYII="></span></p>
<p>Por defecto, todas las partes implicadas en este proceso (el servidor de correo que envía el email y servidor de correo que lo recibe) asumen que los datos del email son <em>verdaderos</em>, por lo que ninguna de ellas detectaría un email <em>manipulado</em> cuya dirección del remitente se hubiera cambiado para suplantar la identidad del mismo.</p>
<p>Ahí es donde entra DKIM, que permite al servidor de correo que envía el email <em>firmar</em> dicho mensaje con una clave privada, de forma que el servidor de correo que lo recibe puede verificar que la firma es correcta utilizando la correspondiente clave pública (que está disponible en el <a href="https://es.wikipedia.org/wiki/Sistema_de_nombres_de_dominio">DNS</a> del dominio que envía el mensaje).</p>
<p>El flujo común del envío de un email con DKIM sería entonces algo así:</p>
<p><span class="graphviz" style="text-align: center;"><img src="data:image/png;base64,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4XJ6sh3AsfPy119/ze9//3s+//xzwsLCeOqppyzq1BXnFpPJxCuvvMKhQ4e4ceMGPXr0YMGCBbz88st89tlnAMycOZPw8PBa67amWGs6BqZMmeKyfgP2n1eysrJ4+OGHKS8vJzU1lU6dOtlVT/XVrFkzl3zZKVKVEnBxOW8n4CIiDdnNmzcZPnw4jz76KC+99JJDn922bRvvvvtunUmFiIjUnxJwcQfdgi4iIuIh5eXlLFu2jJCQEObOnevw57ds2WL1a5KIiIg0HkrARUREPOTq1at8++23/O1vf7Nrdt/U1FTmz59PYWEhW7Zs4caNG1a3zYuIiEjjodeQiYiIeEhERAQbN2506DP79u1j0KBB3H///axYscJjr5YSERER19Mz4OJyegZcRERERBo7PQMu7qBb0EVEREREREQ8QAm4iIiIiIiIiAcoARcRERERERHxACXgIiIiIiIiIh6gBFxERERERETEA/QaMnG5oKAgb4cgInJHC/nqHACmjg94ORIRkTuXrmnFHZSAi8tFRER4OwQRkTvbyYMAtNDrcURERBoV3YIuIiIiIiIi4gFKwEVEREREREQ8QAm4iIiIiIiIiAcoARcRERERERHxACXgIiIiIiIiIh6gBFxERERERETEA5SAi4iIiIiIiHiAEnARERERERERD1ACLiIiIiIiIuIBSsBFREREREREPEAJuIiIiIiIiIgHKAEXERERERER8QAl4CIiIiIiIiIeoARcRERERERExAOUgIuIiIiIiIh4gBJwEREREREREQ9QAi4iIiIiIiLiAUrARURERERERDxACbiIiIiIiIiIBygBFxEREREREfEAJeAiIiIiIiIiHqAEXERERERERMQDlICLiIiIiIiIeIAScBEREREREREPUAIuIiIiIiIi4gFKwEVEREREREQ8QAm4iIiIiIiIiAcoARcRERERERHxACXgIiIiIiIiIh6gBFxERERERETEA5SAi4iIiIiIiHhAE28HICIiIrW4VQBFP1ouu11k/v/1q5bL/QMgMNgzcYmIiIjDfMrLy8u9HYSIiIjU4HQ67Npq37oPTYIHo90bj4iIiDhNt6CLiIg0ZF17gsGO07XBYF5XREREGiwl4CIiIg1ZQCDc1wV8ajllGwzmdQICPReXiIiIOEwJuIiISEP3QB+glifGysv/dx0RERFpyJSAi4iINHQde4BvLfOm+vpCx+6ei0dEREScogRcRESkoWvaFDo/AAZf678ZDNC5JzT183xcIiIi4hAl4CIiIo1Bj95QVma9vKwcevTyfDwiIiLiMCXgIiIijcF9ncHf33q5nz/c29nz8YiIiIjDlICLiIg0BgZf6N7L8llwX1/zr9++Nm5NFxERkQZHCbiIiEhj0b0XlJb8v3+XlpqXiYiISKOgBFxERKSxaH8fhDT7f/8ODoWf3ue9eERERMQhSsBFREQaDR/zZGwGX/N/D/QBHx9vByUiIiJ2UgIuIiLSmHTrBWWl5v90+7mIiEij0qT6gsLCQnJzc70Ri4iIiNjhJyFhAGQVlcLly16ORkRERGyJiIggKCjIYplVAn779m1u3LjhsaBERETEMQHt/g+AztciIiINWFhYmNUyqwRcREREGrbrP9HEayIiIo2REnAREZFGpji4Wd0riYiISIOjSdhEREREREREPEAJuIiIiIiIiIgHKAEXERERERER8QCXJOD9+/cnMjLSrv/Onz8PQEpKSuWykSNHuiKMRmfnzp2VddCnTx9vh1OpocZ1N/F0G2RmZhIZGUlsbKzb99XYNfSxq6HH5yp3Szld4V//+hfPPfcc//Zv/0ZUVFRlvQ0cONDboXnU3XZuc2d577a6dJQ36udu2WdDiqUhlV8aV3u4JAHPyMhg69atAAwfPhyj0Wjzv5CQkMrPPPnkkxiNRrp06eKKEBqMwsJCHnnkEebMmVPnug8//DBGo5Ho6GgPRGa/hhrX3cTTbbBt2zYAzp49y8WLFz2yz8bA1vHc0Meuhh6fMxpjO3hSbeedrKwsYmNj+de//sWqVatIT0/n008/5dVXX8VgaDw3wTlybq3J3XZuc2d577a6dJQ36udu2WdDiqW2fbpizBLHNKT+WJfGc/ZtJMrLyykrK6OsrMzboYjYpaysjA8++IBu3boB/y8ZFx3PDYXaoXa11c/WrVsxmUwsWrSIBx98kICAAIKDgxkzZgxHjhzxQrTOUR8QkcZEY5bUxqOvITt69Kgnd+cVwcHB7Ny509thiNjtk08+oUmTJvz+979n8uTJfPjhh8THx+Pr6+vt0LxOx3PDoHaoXW31c/nyZQA6d+7syZBcTn1ARBoTjVlSG4/8Av7EE0/wj3/8wxO7EhEHvf/++/ziF7+gR48edO7cmatXr3Lo0CFvhyUiLnD79m0AmjZt6uVIREREBDz8C3h9FRcX8/rrr7N7926+//57/P396dWrFxMmTCAmJsbieba8vDz+8pe/cODAAXJycggNDaV3794888wzdO3aFYB9+/Yxf/78ys98+OGHrFmzhvT0dPLz823GMHfuXOLi4igtLeXBBx+sXD569GgeffRRi+0dP34cf3//yn9funSJlStXcuzYMUpKSujevbvF+tVdv36dN954g3379vHDDz8QGBhIVFQUM2bMoH///naX4dChQ4SHh9e4H0fjsqdu61K1bNnZ2YSHh3Pfffcxbtw4HnroIYt6c1U9vPTSS7z00kt21ZUjZbQnvrp4ow0A8vPzOXjwIP/5n/8JwC9/+UuWL1/O+++/z/Dhwy3WrV7Hu3fvJjk5mSNHjuDr60tUVBQJCQm0b9++cp3S0lL27NlDamoqX375JSaTifbt2zNhwgSmTJlS5zOojvRvZ9uspv5Xfd/Vj+cKly5dYsWKFZw6dYrbt2/Ts2dP5s2bR69evSzWc0Wbuardnd12TX3g8OHDNG3alKFDh/LCCy9gMplYunQpx44dIygoiJiYGJ5//nmCg4MrP2tv37C3HZxx8+ZNBg0aZLGstjE+OTnZZdtw1Tmq+rhWUT/VP9u3b1+bdfCLX/yCJUuWWCyzd3yu7/EN9p3Xne0DnhpXvd0HKsZAR8rraNs5WpfVpaSk8OqrrwLQunVrVq9ezapVqzAajZSWllqNm46U25FzsCPXHo70B2+cwxvDPp25frPn2qKhl7+uMctd/bA6HXeWXD3m1ofLfwHfv3+/1cznp06dcsm2ly5dyttvv83//b//lyNHjvDBBx9w33338Zvf/IYTJ05UrnflyhUmT57M7t27WbRoEUeOHGHdunXk5+czdepUzpw5A8CIESMwGo2VicbixYuZPHkyH3/8MW+//TYGg4FDhw4xZMgQDAYDO3bsIC4uDgBfX1+MRiNRUVEkJSWRnJxstb2qLl++TGxsLOfPnyc5OZmDBw+yaNEi/vrXv/LNN99YrZ+bm8vkyZPZvn07CQkJHD58mHfffZeAgABmzZpFamqq3WWojaNx2Vu3tako244dOyrLtmXLFvr168eiRYvYsmWLW+rB3rpypIz2xtfQ2qDCjh07iIqKol27dgA8+uijNGnShEOHDnHt2jWLdavXX2JiItOmTWPfvn288sorpKens2DBAovPpKWl8fzzzxMdHc0HH3zAnj17mDRpEitWrGDlypV1xufONqur/9V2PFcoLCxkyZIl/Pu//zt79+5lw4YN5Ofn89RTT3H8+PHK9VzRZq5sd2e3Xb1OVqxYwcyZMzlw4AALFy7ko48+YuHChSQmJjJ37lz279/Ps88+S2pqKn/+858t9mlv37CnHZwVGhqK0Whk8ODBdo3xtW3D3vMEuPYcVVP9VF9+/Phxi0lRa7rLxZHxub7HN9h3XnemD3hyXPV2H3CmvI60naPbtqXqpIk3b94kMTGRefPmceDAAZvjpr3lduQc7EjfdqQ/eOMc3hj26ez1mz3XFg29/LWNWe7qh7bouMPhbdc3r7KXyxNwW7OgV/8lyFmffvopHTt2ZODAgfj7+9OyZUv+67/+iw4dOlist3r1arKysliwYAFDhw4lKCiIjh07smLFCsrLy1m6dKnN7T/11FP069ePgIAAevbsyZkzZwgPD+fJJ5+krKyMjRs3Wqx/6tQpcnJy+PnPf15n7KtXr+bmzZskJCQwcOBAgoKC6NSpE3/4wx/Izc21Wn/VqlV89913LFy4kJiYGEJCQujQoQNJSUm0atWKZcuWcfXqVbvL4Kq4nK1bW2VLSEggJiaG4OBgWrZsSVxcHEOGDPFYPdS0jiNldDY+b7dBhffff59f/vKXlf8ODw8nJiaG0tJSPvzww1o/O2HCBKKioggMDGTAgAHExMRw7tw58vLyLNbr168fs2bNolmzZoSHhzNlyhTGjh3LW2+9hclksjtWcG2b2dP/6mIymZg/fz69evUiKCiIHj16kJiYyO3bt0lMTKxczxVt5sp2d9W2x48fT/fu3QkMDGTcuHF07NiRtLQ0pk+fTteuXQkKCmLSpEm0a9fOZsLnyr5RH0888USNY/z333/PmDFj6tyGI+cJV5+jXMnR46O+bWjved1R3hhXvdkHHC0v2N92zmy7Nrdu3WLRokWV54+axk17yu3IOdiRvu1I+3ijrzWGfTp7fWTPtUVjKH9N3NUP66LjrmGddxvVLOhDhgzh9OnTLF68mLNnz1bOLPjRRx/Rr1+/yvX27t2LwWBg2LBhFp+PiIjg/vvv57PPPiM7O9tq+w888IDN/UZHR9OtWze2bdvG9evXK5evX7+eqVOn2jVZVcVss4MHD7ZY3rp1a5sXGnv37gWwKoOfnx/R0dEUFRXZnMG2pjK4Mi5n6rb6NgCbF3Nr165l2rRpVuu6ox5qWseRMjobX1XeaAOAL774gsuXLzN69GiL5RUJeV2zoVevv7Zt2wLmbxkrxMTEsG7dOqvPdunShZKSEodfeebKNrOn/9XF39+fyMhIi2WdOnWidevWXLhwobIuXHXcuKLdXbntHj16WPy7VatWNpe3adPGol+A6/tGfQwaNIhOnTrZHONjY2Np0qTup7UcOU+4+hzlSo4cH65oQ3vP647yxrjqzT7gaHkdaTtHt12XwMBAq1tJbY2bVdU29oN952BHrz3sbR9v9LXGsk+o//WbrWuLxlD+mrirH9ZFx13DOu965Bnw6t8GO+u3v/0tUVFR/OMf/+Cpp54CoE+fPkyaNImRI0cC5ufJKr65HThwYI3byszMpE2bNhbLAgMDa1x/+vTpJCQksHnzZuLi4sjMzOTEiRMsW7aszriLi4spKCjA39+foKAgq7+3aNGCzMxMi/VNJhP+/v4Wz0xWaNmyJYDNb3hqK4Or4gLH67b6NmoqmyPr1rcebK3jSBnDw8Odjq/q/jzdBhXef/99CgoKarzI/eqrrzAajVYJZoWQkBCLf1ckKVVfuWEymUhJSWHv3r1kZ2dz8+ZNi8/8+OOPtcZYnbvbzFFhYWH4+PhYLW/RogU5OTlcu3aNsLAwlx039dlGTeqz7ep1aDAYMBgMBAQEWC2v/ioWV/eN+po2bRq/+93vLMb4jIwMq+eja2PPecJd5yhXcGR8Bte0oT3ndWfK4a1x1Rt9wNHygv1t58y26xIaGmpzedVxs+LLvAq1jf32nIOdufYA+84p3riOaiz7dOb6qK5ri8ZQ/pq4qx/ac97XcdewzruNahI2Hx8fxo0bx7hx4ygpKeHYsWOkpKQQHx/P888/zxNPPIGfnx+hoaEUFhZy4sQJl71K6aGHHmLVqlW88847zJgxg5SUFCZOnGjXRYqfnx/BwcEUFBRQWFho1Vlu3LhhtX5ISAgmk4mCggKrfVTc1hEREVGvMjkTV33rtq6yObKuq+qh+j4dKWN94/NGGwCUlJSwfft2Nm3aZDFBUIXly5ezadMmtm3bVmMCbo85c+Zw8uRJEhISGDt2LM2bN8fHx4dNmzaxfPlyysvLnd52BVe2maNqusW24vn5Fi1auOy4cce45u5t18YTfcMRjzzyCKtXr7YY4x977DGaNWtm9zbsOU94q77t4cj4DK5pQ3vO686UwxvjKninDzhaXrC/7ZzZdl3y8/MpLy+3+vKy6rhpD0euERy99nCkfbxxHdUY9umu67fGUP7atuOuflgXHXcN67zr0VvQH3/88Xq9E2/gwIFcunQJMH8jNnDgQF577TV8fHwsni8cNWoUpaWlNid/W7duHaNHj6a0tNShffv6+jJ16lSuXbvGhg0b2LVrF7GxsXZ/vuLWi7S0NIvleXl5lWWqquKb/+rPTRYXF5Oeno6/v7/VbRfOcDQuV9RtRdkOHz5s9bdJkyaxfPlyq3XdXQ9VOVJGV8TnjTY4cOAAzZs3t5l8g/nZXjBP0lZUVFTrtmpSVlbG6dOniYiIIDY2lvDw8MqB39lt1sSZNrOn/9WlsLCQCxcuWCz78ssvycnJoUuXLpXfJruizdwxrnli27Z4sm/Yy8/Pj8mTJ1eO8du3b2fq1KlY5aQkAAAgAElEQVQObcPe84Sn69sR9h4frmpDe8/rjvLGuAre6wOOlNfRtnO0LutSVFTEuXPnLJbZGjft4cg52JGx35H28UZfawz7dOf1W2Mof03c1Q/rouOuYZ13G9Uz4AAvv/wyX3zxBcXFxVy7do1169ZRXl5uMeV9fHw87du358UXXyQtLQ2TyUR+fj5bt25l7dq1PPfcc059+zFx4kRCQkJYs2YNI0aMoHXr1nZ/dv78+YSFhZGUlMTRo0cpLCzk4sWLvPDCCzZvn4iPj6ddu3YkJSVx8OBBCgoKyMzMZOHChVy5coWEhITK2zzqw5m46lu3FWVbvnw5hw4doqCggOzsbJYsWcKVK1csngfxVD04W0ZXxOeNNti2bRu/+tWvavx7x44diYyMxGQy8fHHH9tRa9YMBgP9+vUjNzeX9evXk5eXR1FRERkZGRazXrqCM21mT/+rS2BgIEuXLuXs2bPcunWL8+fPk5CQQNOmTUlISHAqPleU0Z315wqe6BsJCQlERkby3Xff2f2Zxx9/HH9/f9asWcOAAQP42c9+5vB+7TlPeLq+HWHv8eHKNrTnvO4ob4yrFbzRBxwpr6Nt52hd1iUkJITVq1dz5syZWsdNezhyDnb02sPe9vFGX2ss+3TX9VtjKH9N3NUP66LjrmGdd33Kq90jlp+fb/drJSr079+fW7du2bXu8uXLefjhhy3eTVfh6aefZt68eTV+9sKFC2zevJkTJ06QlZWFv78/HTp0YPz48YwfP97itor8/Hxef/31yvfThYaG0q1bN2bMmMGAAQMAOHv2rM1vpo1GY40xJCcns379elJTU+ncubPF36q/Ow7MtzVWzC6YmZlJcnIyGRkZ3L59m06dOjF79mw2btxIeno6YP7lcfHixYD5vXkVZcjOziYgIKDyHXvR0dFOl6E6R+Oyp27rUr1s4eHh9O3blzlz5lhNnuCqenCkrhwpoz3x1cVTbZCdnc2oUaMq/92zZ0/efvtti3WysrKsZvZv2bIlr732mlX9VRyz1W9THzZsGH/605/Iy8tjzZo1HD58mNzcXMLCwhgyZAgRERG8+eabAHTv3p3NmzfbjNdTbWar/9V0PHft2tXqvZorV67k3LlzlJaWEhkZyW9+8xurtz+44rixZxvOjK32bttWezz99NOMGDGCyZMnWyyPj4+nV69eTJ8+3WL57NmzefbZZ+3uG3FxcXW2g61yzpo1C6PRyNGjRx16bcjixYt57733SElJoU+fPnZ/rqrazhMVXHWOqqmfjhkzpsbz0TPPPGM1+dGGDRvo3bs3YP/4XN/jG+w7r9d1bq2JN85tFTzZB5wpr6Nt52hd1mTixInk5eXxxhtvsHz5ck6fPk1JSYnVuOlIuR05Bzty7eFIf/BGX2sM+3T2+q2ua4uGXv6YmJhaxyx39cOa6Lizvw+4Iq+qrn379oSFhVksc0kCLiIi0lDcvHmT4cOH8+ijj/LSSy859Nlt27bx7rvv1po0iohzKhKBipmRRcT9dNx5l60EvNHdgi4iIlKT8vJyli1bRkhICHPnznX481u2bLH61V5ERETEVZSAi4jIHePq1at8++23/O1vf7Nrht3U1FTmz59PYWEhW7Zs4caNG1aPYIiIiIi4ihJwERG5Y0RERLBx40Y6duxo92f27dvHoEGD2Lx5MytWrGgQrygRuZOkpKQQGRnJhQsXyMnJITIykjVr1ng7LJE7mo67hkvPgIuIiIiIiIi4mJ4BFxEREfGg8vJy/uM//oPRo0eTmZnp7XBERMTLmng7ABGxVPU1Uq1bt26Qs1bu3LmTBQsWAODn58eJEydctm1Plf9f//oXf/7znzl+/Dh5eXmUlZUB5ndlHj161C379CZXtFlj6JuucKeVs6GUp6HE4Wmvv/46Fy5cYMOGDfzkJz+x+JujdXK31qErVX+t3fHjx/H39/diRI2LM33Q1uuKfXx8CAkJ4Z577qFXr16MHz+e7t27W6yTl5fHsGHDKv/dtWtX3nrrLav2qr4eWL8CsaysjPfee48PPviAixcvcuvWLVq0aEGXLl0YNmwYMTExVseniLvoF3CRBubJJ5/EaDTSpUsXb4dSo4cffhij0Wj3e84d4YnyZ2VlERsby7/+9S9WrVpFeno6n376Ka+++qpD74xuTFzRZo2hbzqqsLCQRx55hDlz5lQuu9PK2VDK01Di8KRDhw6xa9cum8k3OF4nta1vqy+LtREjRmA0Ghk+fLi3Q2mUnDmOMzIy2Lp1KwDDhw/HaDRy+vRpPvzwQ+bOnculS5d4/PHHWbRoET/++GPl58LDwzEajfz9738H4J///CdJSUlW269Y7+2336Z58+YYjUarV0m+8MIL/PGPf2TEiBFs27aN9PR0NmzYQLdu3Vi2bBmPP/64M9Uh4hT9Ai4id52tW7diMplYtGgRDz74YOXyMWPGMGbMGC9GJp5WXl5OWVlZ5R0QIq40bNgwq1/m3EV9WRoTg8FAy5YtGT58OMOHD2flypWsW7eOGzdusHr1anx8fCzW9/PzIygoiK1bt9K3b1/Gjh1r977OnTvHjh07mDhxIjNnzqxc3r59e37zm99w8+ZNdu3a5bKyidTlzvypR0SkFpcvXwagc+fOXo5EvC04OJidO3eydu1ab4ciUi/qy9KYxcfH07NnT/bv38/OnTut/u7n50diYiIGg4GXX37ZofkULl68CMC9995r8+969aR4mhJwEbnr3L59G4CmTZt6ORIRERHx8fHh17/+NYDV7eMVBg8ezNNPP01BQQH/+Z//SVFRkV3bbtmyJUCN87v07duXw4cPOxG1iHN0C7p4zfXr13njjTfYt28f2dnZhIeHc9999zFu3Dgeeughi0k2qq77ww8/EBgYSFRUFDNmzKB///6A9cQqu3fvJjk5mcOHD9O0aVOGDh3KCy+8gMlkYunSpRw7doygoCBiYmJ4/vnnCQ4OBqwnGFm9ejWrVq3CaDRSWlpKz549mTdvHr169bK53w8//JA1a9aQnp5Ofn4+YH4OMDw83K5yVHfp0iVWrFjBqVOnuH37ttX+AUpLS9mzZw+pqal8+eWXmEwm2rdvz4QJE5gyZUrlc8011dGRI0fw9fUlKiqKhIQE2rdvbxXDypUrOXbsGCUlJXTv3t1iO7W1rb3ltIe95axJ9fL37dvX5nq/+MUvWLJkic3P2Grfl156iZdeeqlyHWf7nivKWMHRNsvLy+Mvf/kLBw4cICcnh9DQUHr37s0zzzxD165d7dpnfbbtquMXnD8e6jsZk6fGtLqOV0e4qr85UnZn47h58yaDBg2y+NzcuXOJi4ujtLTU4nGS0aNHk5ycDNSvbzt6PvjrX//Kf//3fwPQq1cvNm7cCEBaWhqzZ88GoHnz5jVe7Nsz3ttSV1+2t33cMf7cvn2bTp068cwzz7Bp0ybS09MBGD9+PD/5yU+cqi9XjldXr16t87hyZ/+sSX3GTWfHCHeeB+zRu3dvAM6cOUNJSQlNmlinKbNnz+bs2bN88sknLFu2zOLcW9t2IyIiOHLkCLNnz2bmzJn06dPnjp3zRRo+9TzxitzcXCZPnsyOHTtISEjg8OHDbNmyhX79+rFo0SK2bNlite727dsr13333XcJCAhg1qxZpKamAtYTq6xYsYKZM2dy4MABFi5cyEcffcTChQtJTExk7ty57N+/n2effZbU1FT+/Oc/V+6v6gQjN2/eJDExkXnz5nHgwAE2bNhAfn4+Tz31FMePH7e538WLFzN58mQ+/vhj3n777coB3t5yVFVYWMiSJUv493//d/bu3Wtz/2C+WHn++eeJjo7mgw8+YM+ePUyaNIkVK1awcuXKyvWqx5qYmMi0adPYt28fr7zyCunp6ZUzZVe4fPkysbGxnD9/nuTkZA4ePMiiRYv461//yjfffFNj2zpSTnvZW86aVC//8ePHMRqNlf8dOnSozs/Yal9X9T1XlBEcb7MrV64wefJkdu/ezaJFizhy5Ajr1q0jPz+fqVOncubMGbv2a4u92/ZGHbpyMiZPjGn2HK+OckV/c6Ts9YkjNDQUo9HIkCFDMBgM7Nixg7i4OAB8fX0xGo1ERUWRlJRUmdzUt287ej6Ii4vDaDQSGBhosZ0hQ4ZgNBqtZnmuyt7x3pba+rIj7eOO8efQoUP84Q9/4K233uKLL77Az88Po9HI4sWLnaovV49XVY+rV199lZMnT1odV470z8GDB9vdP2vi7LhZnzHCnecBe1X8Ul1aWkpeXp7NdQwGA4mJibRt25bU1FS2b99e53aDgoJ49dVXadu2LWlpacycOZPhw4eTkJDAjh07LCZ+E/EEJeDiFatWreK7774jISGBmJgYgoODadmyJXFxcQwZMsTmugsXLiQmJoaQkBA6dOhAUlISrVq1YtmyZVy9etVqHxWvtAgMDGTcuHF07NiRtLQ0pk+fTteuXQkKCmLSpEm0a9fOZuIFcOvWLRYtWkRUVBSBgYH06NGDxMREbt++TWJios3PPPXUU/Tr14+AgAB69uzJmTNnCA8Pd6ocJpOJ+fPn06tXL4KCgmrdf79+/Zg1axbNmjUjPDycKVOmMHbsWN566y1MJpPNWCdMmFBZtgEDBhATE8O5c+csTnyrV6/m5s2bJCQkMHDgQIKCgujUqRN/+MMfyM3NrbFtHW0vezlTTleqqX2rqm/fq28ZHW2z1atXk5WVxYIFCxg6dChBQUF07NiRFStWUF5eztKlS52uL2e37e06dJQnxjR7jldn1LeuHCm7K+J48sknKSsrq/y1tMKpU6fIycmxeJ7TlX3bmfOBIxwZ7x3haPu4Y/zp2LEjy5cvt3oVlTNcPV5VPa6io6MZNmyYzePK3np54oknauyf33//vV0TfTpbxvqMEe48D7haeHg4r776Kk2aNGHx4sVcunSpzs/07t2b7du388c//pHhw4dTVFTE9u3bWbhwIaNHj7b53LmIuygBF6+oeG+krZP/2rVrmTZtmtW61WeS9fPzIzo6mqKiIo4cOWK1nR49elj8u1WrVjaXt2nThitXrtiMMzAw0Oq2q06dOtG6dWsuXLhg83MPPPCAzW05Uw5/f38iIyPr3H9MTAzr1q2z2meXLl0oKSmpnICkrljbtm0LYFGuipgGDx5ssW7r1q3p0KGDS8ppL2fL6Uo1tW9V9el7riijM21mMBis2iwiIoL777+fzz77jOzs7Dr3a4uz2/Z2HTrKE2OaPcero1xRV46U3RVxREdH061bN7Zt28b169crl69fv56pU6fi6+trEZur+rYz5wNH2DveO8qR9nHn+FNx23t9uXq8qn5ctWnTBrA8rhypl0GDBtGpUyeb/TM2NtbmbdXVOVvG+owR7jwP2KsiziZNmlh9sV1dz549ee6557h165bdz4P7+fnx2GOP8dprr3HkyBH+9re/8fDDD3P9+nUSEhL4/PPPXVIOkbroGXDxuOLiYkwmE/7+/hbPbTqzbsXtSrZ+1au+vsFgwGAwEBAQYLW8pte2hIaG2lzeokULcnJyuHbtWmViUKH6rXT1KUdYWJjVqzhs7d9kMpGSksLevXvJzs7m5s2bFuvXdHtVSEiIxb8rLgwq6qO4uJiCggL8/f0JCgqyGUfVmUjr0172cLacrmSrfaurT9+rbxmdbTOAgQMH1rjdzMzMygtTe9Vn296sQ0d5akyr63h1hiv6m71ld2Uc06dPJyEhgc2bNxMXF0dmZiYnTpxg2bJlVrGBa/q2M+cDR9g73jvC0fZx9/jTrFkzh+K3tX1Xj1fVj6uKNqh6XDlaL9OmTeN3v/udRf/MyMionFukNvUpo7NjhDvPA444efIkAFFRUXZ9UREbG8vp06fZtWsXf/zjH5k4caLd+/L19SU6Opro6Gjuuece1q1bx549e+jWrZvT8YvYSwm4eJyfnx8hISGYTCYKCgpqvSioa92K2zQjIiLcEmt+fj7l5eVWF0XXrl0DzBdG9nC2HDXd7ld9/3PmzOHkyZMkJCQwduxYmjdvjo+PD5s2bWL58uWUl5fbFaetuIODgykoKKCwsNDqgurGjRsuKae93FXOhqS+ZXSmzUJDQyksLOTEiRMWvx7Wlzu3XRtP95PGNKZV54r+Zm/ZXRnHQw89xKpVq3jnnXeYMWMGKSkpTJw40WL/ru5/jpwPDAZD5dsWqqqeuFVl73jvCEfbx93jT0VZqrO3vhrLmPLII4+wevVqi/752GOP2fUFhDfK6K16raqsrIy///3vAJWzodtj8eLF/POf/+T999+vcbLHU6dOER8fz8GDB23+vX///pXvIBfxBN2CLl4xcuRIAJszwU6aNInly5dbrVv9Oc/i4mLS09Px9/e3utXNVYqKijh37pzFsi+//JKcnBy6dOni0K8RzpSjsLCQCxcu1Lr/srIyTp8+TUREBLGxsYSHh1deINr7io7aVNy2mJaWZrE8Ly/P5nNX7movd5ezIXBVGR1ts1GjRlFaWsqpU6es/rZu3TpGjx5NaWmpI0XxyLZt8VY/aSxjWlWuqitHyu6qOHx9fZk6dSrXrl1jw4YN7Nq1i9jYWKv1XNn/HDkfREREkJOTY7Fubm4u33//fY3bt2e8d4a97ePu8Sc3N7fGdzc7Ul+NYUzx8/Nj8uTJlf1z+/btTJ061e59erqM3tpnVatXr8ZoNDJy5Ei7npOvEBQUxMqVKwkMDKxM4KsrLy/n2rVrnD171ubfz58/D+CRmd5FQAm4eEl8fDzt2rVj+fLlHDp0iIKCArKzs1myZAlXrlyxeCatYt2kpCQOHjxIQUEBmZmZLFy4kCtXrpCQkFB526arhYSEsHr1as6cOcOtW7c4f/48CQkJNG3alISEBIe25Uw5AgMDWbp0KWfPnq1x/waDgX79+pGbm8v69evJy8ujqKiIjIwMu2Yfrsv8+fMJCwsjKSmJo0ePUlhYyMWLF3nhhRds3mLorvZydzkbAleV0Zk2a9++PS+++CJpaWmYTCby8/PZunUra9eu5bnnnnP6FxF3btsWb/WTxjKmVeWqunKk7K6MY+LEiYSEhLBmzRpGjBhB69atbcbmqv7nyPlg0KBB5OTk8O6771JYWMg333xDYmJirb9i2zPeO8Pe9nHn+PPVV1/x4osv1nhnhyP11VjGlMcffxx/f3/WrFnDgAED+NnPfmb3Pj1dRm/ss6ysjGvXrrF//35mzZrFunXr+NWvfkVSUpLNRzFq07FjR37/+9/Xud5//dd/sWPHDnJyciguLiYrK4uUlBT+8pe/0L17dx577DFniyPiEJ/yavfN5Ofn23xNjYirXb9+nddff93ivaR9+/Zlzpw5VhNFVV83ICCg8p250dHRAJw9e9bqF5Cnn36aESNGMHnyZIvl8fHx9OrVi+nTp1ssnz17Ns8++yxgvrjLy8vjjTfeYPny5Zw+fZqSkhIiIyP5zW9+U/leVlv7BTAajXWW2VY5bL13duXKlZw7d47S0lKr/YP5l801a9Zw+PBhcnNzCQsLY8iQIURERPDmm28C0L17d37729/arKN58+ZZTf4zbNgw/vSnPwHm576Sk5PJyMiofKfr7Nmz2bhxo8U7XRcvXmx3OWtStfzVY7S3nJs3b7a57ervTAXzrYKJiYk888wzVhNfbdiwgSZNmtTZvq7se/UtYwVH2yw/P7+yzX744QdCQ0Pp1q0bM2bMYMCAAUDtbVMbe7btjTqMi4uz2R+6du3qVDk9NabVdbxW585jypGyuyOO5ORk1q9fT2pqKp07d7YZmz39ry72ng8qmEwmXnnlFQ4dOsSNGzfo0aMHCxYs4OWXX+azzz4DYObMmZWzOYN9431NddijR48axzZ72wfsP5c4Mv6UlJTQtWtX4uPjWbt2LadOneLEiRNO1dd//Md/APVrU2eOK2frZfHixbz33nukpKTQp0+fWuOqrj7jpqNjhCP7dOY80L9/f6sZ8H18fAgODuaee+6hd+/eTJgwwer567y8PKtJ4Wrrf0uWLGH37t1Wd3uUlZVx5swZ9u3bx8mTJ/nhhx+4evUqAQEB3HvvvYwaNYqpU6dazTEi4grt27cnLCzMYpkScJEaVFxwVcwgKyIidyedD1xj1qxZNhPwO9W2bdt499136/zCQkTuXLYScN2CLiIiIiLiYlu2bLG6U0dERAm4iIiIiEg9paamMn/+fAoLC9myZQs3btzg5z//ubfDEpEGRgm4SDUpKSlERkZy4cIFcnJyiIyMZM2aNd4OS0REPEznA9fYuXMnkZGRpKenU1xcTGRkpF2TZjVG+/btY9CgQWzevJkVK1Z45ZVeItKw6RlwERERERERERfTM+AiIiIiIiIiXtLE2wGIiEjjtXPnThYsWACAn5+fU7MbV3/1nrMzTbsiFnF/Pdb0SqKQkBDuueceevXqxfjx4+nevbtL9+sq6mciIlIf+gVcRESc9vDDD2M0Gut8v3ttnnzySYxGI126dPF6LK5UWFjII488wpw5cxrEduzl7nrMyMhg69atAAwfPhyj0cjp06f58MMPmTt3LpcuXeLxxx9n0aJF/Pjjj26JoTpH6rih9TMREWlclICLiIi4QXl5OWVlZZSVlTWI7TRkBoOBli1bMnz4cN58801mzpzJP/7xDxYsWEC1qWrc4m6oYxERaRh0C7qIiIgbBAcHs3PnzgazncYkPj6e48ePs3//fnbu3MnYsWPdur+7sY5FRMQ79Au4iIiINCg+Pj78+te/BmDz5s1ejkZERMR19Au4iIjY7dKlS6xcuZJjx45RUlJC9+7dmT9/fo3r5+Xl8Ze//IUDBw6Qk5NDaGgovXv35plnnqFr164ejeX69eu88cYb7Nu3jx9++IHAwECioqKYMWMG/fv3B8zv8K26jd27d5OcnMzhw4dp2rQpQ4cO5YUXXsBkMrF06VKOHTtGUFAQMTExPP/88wQHB9vczvHjx/H3969x+0eOHMHX15eoqCgSEhJo3759rdtxpEyurkd3tmlVvXv3BuDMmTOUlJTQpEkTSktL2bNnD6mpqXz55ZeYTCbat2/PhAkTmDJlCgaDgZs3bzJo0CCLbc2dO5e4uDhKS0t58MEHK5ePHj2aRx99tNY6drR+REREaqNfwEVExC6XL18mNjaW8+fPk5yczMGDB1m0aBF//etf+eabb6zWv3LlCpMnT2b37t0sWrSII0eOsG7dOvLz85k6dSpnzpzxWCy5ublMnjyZ7du3k5CQwOHDh3n33XcJCAhg1qxZpKamAjBixAiMRiPDhw8HYMWKFcycOZMDBw6wcOFCPvroIxYuXEhiYiJz585l//79PPvss6SmpvLnP/+5cn/Vt1PT8sTERKZNm8a+fft45ZVXSE9Pr5xhu7btOFImV9ajO9u0upYtWwJQWlpKXl4eAGlpaTz//PNER0fzwQcfsGfPHiZNmsSKFStYuXIlAKGhoRiNRoYMGYLBYGDHjh3ExcUB4Ovri9FoJCoqiqSkJJKTk2utY0frR0REpC5KwEVExC6rV6/m5s2bJCQkMHDgQIKCgujUqRN/+MMfyM3Ntbl+VlYWCxYsYOjQoQQFBdGxY0dWrFhBeXk5S5cu9Vgsq1at4rvvvmPhwoXExMQQEhJChw4dSEpKolWrVixbtoyrV69afa7idViBgYGMGzeOjh07kpaWxvTp0+natStBQUFMmjSJdu3acejQIYfLMWHCBKKioggMDGTAgAHExMRw7ty5yoSzNs6WqaqG1Kb26tevH7NmzaJZs2aEh4czZcoUxo4dy1tvvYXJZKpc78knn6SsrIyNGzdafP7UqVPk5OTw85//vM59OVo/IiIidVECLiIidjly5AgAgwcPtljeunVrOnToYLX+3r17MRgMDBs2zGJ5REQE999/P5999hnZ2dkeiwWwisXPz4/o6GiKiooqt1lVjx49LP7dqlUrm8vbtGnDlStXHCwFPPDAAxb/btu2LYBd23K2TFU1pDatrqIOmjRpQnh4OAAxMTGsW7fOat0uXbpQUlLCxYsXK5dFR0fTrVs3tm3bxvXr1yuXr1+/nqlTp+Lr61tnDI7Wj4iISF30DLiIiNSpuLiYgoIC/P39CQoKsvp7ixYtyMzMtFi/4tfIgQMH1rjdzMxM2rRp45FY/P39K5/RrqriVmdbv2hWX99gMGAwGAgICLBa7swrrEJCQiz+3aSJ+bRc17bqU6aq22gobWrLyZMnAYiKiqqsF5PJREpKCnv37iU7O5ubN29afKb6e8OnT59OQkICmzdvJi4ujszMTE6cOMGyZcvq3L+j9SMiImIPJeAiIlInPz8/goODKSgooLCw0CohuXHjhtX6oaGhFBYWcuLECbt+bXRnLCEhIZhMJgoKCqwS1orbtCMiIlwWo7u5okwNqU2rKysr4+9//ztA5WzoAHPmzOHkyZMkJCQwduxYmjdvjo+PD5s2bWL58uVW7wx/6KGHWLVqFe+88w4zZswgJSWFiRMn2vzSojpH60dERMQeugVdRETsMmTIEMA8EVZVeXl5XLp0yWr9UaNGUVpayqlTp6z+tm7dOkaPHk1paalHYhk5ciSA1XPaxcXFpKen4+/vb3WbcUPnijI1pDatavXq1RiNRkaOHMmYMWMAc1J++vRpIiIiiI2NJTw8HB8fHwCKiopsbsfX15epU6dy7do1NmzYwK5du4iNjbU7DkfrR0REpC5KwEVExC7z588nLCyMpKQkjh49SmFhIRcvXuSFF16weYtufHw87du358UXXyQtLQ2TyUR+fj5bt25l7dq1PPfcc07/iupMLO3atSMpKYmDBw9SUFBAZmYmCxcu5MqVKyQkJFTett1YuKJMDaVNy8rKuHbtGvv372fWrFmsW7eOX/3qVyQlJVUm2QaDgX79+pGbm8v69evJy8ujqKiIjIwMtmzZUuO2J06cSEhICGvWrGHEiBG0bt3a7rgcrZ+srCyioqKIjHlYrs8AACAASURBVIzk888/d7geRETkzudTXu1+rfz8fL1aQ0REbMrMzCQ5OZmMjAxu375Np06dmD17Nhs3biQ9PR0wzxy+ePFiwHxOef311yvfUx0aGkq3bt2YMWMGAwYMACAlJYVXX33VYj9PP/008+bNc2ks169fr4wlOzubgICAyndmR0dHA3D27FmrX0iffvppRowYweTJky2Wx8fH06tXL6ZPn26xfPbs2XTt2tXqXdGPPPIIU6ZMsbn9efPmERkZabF82LBhTJgwweZ2EhMT7S5TXdzRprXp378/t27dsljm4+NDcHAw99xzD71792bChAl069bN6rN5eXmsWbOGw4cPk5ubS1hYGEOGDCEiIoI333wTgO7du7N582aLzyUnJ7N+/XpSU1Pp3Lmzxd+qv2sdLOvYkfrJysri4Ycfpry8nNTUVDp16lRnfYiIyJ2rffv2hIWFWSxTAi4iIiIiIiLiYrYScN2CLiIiIiIiIuIBSsBFREREREREPEAJuIiIiIiIiIgHKAEXERERERER8QAl4CIiIiIiIiIeoARcRERERERExAOUgIuIiIiIiIh4gBJwEREREREREQ9QAi4iIiIiIiLiAUrARUSkwWhS/COtvjyDT3mZt0ORO0CzrK8Jyc3ydhgiIiKVmlRfEBQURPv27b0Ri4iI3KUMBTfxO/UJfp+fBL8AgntFUxreytthSSMX9OVJmp48S2mbdvzYewgl93YCfLwdloiI3CWCgoKslvmUl5eXeyEWERERuHEdMg7A6XTwD4B+w6DPEGja1NuRyZ0iOwuO7oV/noVWbSE6Bnr0Bh/dBCgiIp6nBFxERDwv/xocOwSnP4XgUHPi/eBAaGJ1Y5aIa1z5HtIPwPlTEBYOA4ZDz/5gUCIuIiKeowRcREQ85/pV+HQ/nM2AZs2h71DoNRB8lXiLh1Ttg6HNod9QffkjIiIeowRcRETcL/cHc9KjXx+loah6F0ZQCPSPgQcHQBM9/iAiIu6jBFxERNwn53vzM97nT0FEa4j+Nz1/Kw1L1XkI/Pyh9yDzIxH+Ad6OTERE7kBKwEVExPWqTnzV+h7oPwx69AEfzUAtDVShCU5+Yv5V3OALfQabH5EICPR2ZCIicgdRAi4iIq7z7dfw6T746jNo1wEGjoSO3dCrn6TRuFUAJ47A8cNQVmb+RXzAcAiwfpWMiIiIo5SAi4hI/X17yfyM91efwU/vhQEjoGN3b0cl4rziIvMv4un7obQUevYz9+uQZt6OTEREGjEl4CIi4ryvv4TDu+C7THPiPeTncG8nb0cl4jrFReYZ0z/dD7cKIbIvDB4NoWHejkxERBohJeAiIuKgcvjqczjyMXx/2ZxwD3sIftLB24GJuE9pCRiPw5E95ufFuz1oTsTDI7wdmYiINCJKwEVExD7l5XDxc0j7H/jhO/Oz3YNHwz3tvR2ZiOeUlsLnp8xfQF2/Cl16wtCfQ8vW3o5MREQaASXgIiJSu/JyuHAWDv8PXMuB+7uZbzVv287bkYl4T+VxsRuuXfnf42IMtP2ptyMTEZEGTAm4iIjYVlYKn52CT/ZCXq5+6ROxxeadIaPgnp95OzIREWmAlICLiIilqrfY5udB9wdh0Cho0crbkYk0YNXmRvjpvTD0IejQ0duBiYhIA6IEXEREzGxNMjVkDDRv6e3IRBqXby+Zb03P/Eqv5RMREQtKwEVE7na3i+FMul6zJOJq314yH1dffQbtOsDAkeZb1PHxdmQiIuIlSsBFRO5WFe83PrrPnIT37Gf+pS6kmbcjE7mzZH9nPs7+eRZat4X+MdCjN/gYvB2ZiIh4mBJwEZG7TdGPcOoofLoPysrMiffAkRAc6u3IRO5sOd9DxgE4f8o8meGAf4PuvcGgRFxE5G6hBFxE5G5xqwBOHIHjh8HHB/oMgb5DISDQ25GJ3F1yfzDfmv7ZKWjW3Hwc9hoIvk28HZmIiLiZEnARkTtdoQlOfgLHDoHBF/oMhn7DwD/A25GJ3N2uX4Pjh+DUpxASaj4uHxwATZp6OzIREXETJeAiIneqgpvmpPt4Gvj5m5877TMEmuriXqRByc+DYwfhdLqOVRGRO5wScBGRO03lxfynEBRivpjXr2oiDV+hCTIOwok0aOJnvltFj4mIiNxRlICLiNwprl8zT6x29pj5FWL9hsKDA6GJnisVaVSqztdQXm5+PnzAcAgI8nZkIiJST0rARUQau9xsc+L92SloFm6+UO/ZXzMrizR2lW8s2A9lpXpVoIjIHUAJuIhIY3Xle0g/oFcaidzpiovgbIY5Eb9VCJF9YfBo850uIiLSqCgBFxFpbHKy4JO98M+z0KotRMdAj97go8Rb5I5WWgLG43Bkj/l58W4PmhPx8AhvRyYiInZSAi4i0lh89zUc3QdffQ5t7oGBI6FrT8DH25GJiCeVlsLnp+DIx+ZJF7s/CINGQYtW3o5MRETqoARcRKSh+/aS+dbTrz6Dn95rfga0Y3dvRyUi3lZWap774ZO9kJcL93eDIT+Htu28HZmIiNRACbiISEP17SU4vBsyv1LiLSI1Ky+Hi59D2m74IQs6djPfmn5Pe29HJiIi1SgBFxFpaL7+Eg7thKzL5sR76EPQoaO3oxKRBq/c/IjKkT3w/Tdwbyfz+NGug7cDExGR/6UEXESkQfjfC+e0PfDD/144xzwM9/zM24GJSGP09ZdweBd8l6k7aEREGhAl4CIi3lRx6+jh3ebZze/vBkPGQNufejsyEbkT2JxDohuavFFExDuUgIuIeEN5OVw4a068r12BLj1h6Bho2cbbkYnInajqWxRa3wP9h0GPPuCjRFxExJOUgIuIeFLFrMV6fZCIeENOFmQchPMnIaINRP8b9OgNPgZvRyYicldQAi4i4gkV7+1N2wM3r0O3B82zFIdHeDsyEbkbXfkB0vfD+VMQFg4DhkPP/mBQIi4i4k5KwEVEnPH5aXMSXZfbxXAmHdIPQGEBRPY1J96hYW4PUUSkTtevmp8RP5thHpf6DYMHB0KTJnV/9otz0PkB98coInIHUQIuIuKo9AOw/yP4/2bB/+lqe53iIvMF7af7oehHiOpvnvwopJlHQxURsUt+Hhw7CKc/Bf9AcyLeZwg0bWp7/UsXYPPfYNQvoO8Qz8YqItKIKQEXEXFExkHY95F5AuG2P4Xp8y3/XlwEJz8xJ95lpdCzHwwcCcGhXglXRMQhBTfh2CE4kQZN/aH3IHMy7h9gud7GNfD9ZSgHRv/CnKyLiEidlICLiNjr+GH4+B+Wy379DHToCLcKzResxw9DWZn5onXAcAgI8k6sIiL1UWgyf5l47JD5ufA+Q6DvUAgIhMsX4Z21VVb2URIuImInJeAiIvY4/SnsSsX8c8//MhjMv4K3/z9w6ig0aWr+paj3IOtfi0REGqPqXy727Ac/fAtZ35jv8qnkA6N/CX0Gey1UEZHGQAm4iEhdTqfDrvewSL6rCgqp+TZNEZE7QdGP5kQ8/SAU3aphJR8Y80vorSRcRKQmeteEiEhtzmTA7lqSb4MBWrWFIWOUfIvIncs/AAaNgnt+Wsurysrhf7bBySMeDU1EpDFRAi4iUpOzGbBrK9R2o1BZGWR+Bd997bGwRES8IjsLvv7KPO7VqCIJ/8RjYYmINCZKwEVEbPn/27v3uKjq/PHjL0AZboooXjaXr7ZhKobkBRFvPDStVcN29csjvqK5ol8veWO3lLFskzIVTE1d06wl1FxXzK+uKa5LknJZw2syWA8tc7ENRVBEBhTk8vuD38wyMMCcYZgZ9f18PHwUZz7zuZ3z+XzOZ845n5N1Go40MfnWcXSEjC9bPk9CCGFLGcng5GBCwGr4x36ZhAshhBEyARdCiLo0p+FIommTb4CqavjxEuT93LL5EkIIWym4Ad9nQ6WpSwdVQ/L+msd4hBBC6LWydQaEEMKuZJ+BpETDR74dnWre+11V9Z9JuYMDuLpDWy/o0BHatoMHD2yRYyGEaHn3SmteM1Z8B+7chruFNdt0HBxq+kqAykqguqa//HtiTf/Zd5Atci2EEHZHVkFvAdeuXePu3bu2zoYQQqF2P1/hl+fTgWqqnFpR4eJGuVsbyt3a8MDNnQcu7pS7uvPA1YMKFzeqHUy5FVM8Snx8fPD09GyRuLOzs1skXiFaikNVJa3vldT8u1+C8///b+tSLc6lxbS6fw/HygpwcODnvkMp9PG1dZaFEI+hZ555xtZZMCBXwIUQAnCoqqLS2YUfQibwwNWDylatbZ0lIYSwa9WOTpS7t6XcvW2DYZwelNdMyu+V4FBVSbXuKrkQQjymZAIuhBBAtaMjxR272jobQgjxSKls7Uxla2fut/GydVaEEMIuyCJsQgghhBBCCCGEFcgEXAghhBBCCCGEsAKZgAshhBBCCCGEEFYgE3AhhBBCCCGEEMIKZBE2YXeqqqr4/PPPOXjwIFeuXOHevXu0b9+enj17MmLECEJCQnjiiSfMijshIYG1a9cC0KlTJ44dO2bJrOv9+OOPfPjhh5w5c4bCwkKqqqoA8PDw4OTJky2SphBCiIeTjHtC1Dhy5AhLliwBwNnZmbNnz9o4R0JYnlwBF3Zn6dKlvPfee4waNYoDBw6QmZnJ9u3b6d27N6tWreLll182CF9aWsr48eOZN29ek3H/7ne/Q6PR0LNnz5bKPrm5uURERPDjjz/ywQcfkJmZyddff83atWtxdJQmJ4QQwpCMe8JalBw7tkhz7NixaDQagoKCrJAzIWxDroALu5KdnU1SUhL//d//TWRkpH67j48PCxcupLi4mL///e8G36murqaqqkr/a7ut7d27F61Wy7Jly3j22Wf1259//nmef/55G+ZMPEwGDRpEr1692LFjh62zIoRoQTLuCWuyxbFjb8erELYmE3BhV65cuQJA9+7djX7+wgsv1DsRcXd358iRIy2dNZNdu3YNgKefftrGORFCCGHvZNwT1mSLY8fejlchbE3uCxJ2pUOHDgANPi82cOBA0tLSrJklxR48eABA69atbZwTIYQQ9k7GPSGEeLzIFXBhV/r374+3tzcZGRnMnTuXyMhIBgwY0OAzZCkpKSxatEj/95kzZ1CpVGalXVlZSXJyMvv27eP7779Hq9Xi4+PDpEmTmDx5cpPPsdXNy8CBA42Ge+mll1ixYoXR73zxxRds2rSJzMxMioqKAFi+fDnLly/Xhzl69Cjr1q0jLS2N1q1bM3z4cJYuXYpWq2XlypWcPn0aNzc3QkJCWLx4Me7u7hYro05hYSFbt27l+PHj3Lx5kzZt2tC/f3/mzJlDr1699OHKy8vZtm0bR48e5fr166hUKvr168ekSZMICQkxKb07d+7w8ccfk5KSQl5eHl5eXjz55JOEhoby61//2mB/1w5748YNXF1dCQgIYPr06QwaNMjsOjcWJjU1FS8vL5PrwtSy1F4w6fz58/j7+wPg6OjIhQsXLLofhRC2J+OefY97dfOry0tGRgZOTk4EBASgVqvx8fEx+J4p41FTWnr80x07lihjQ/lr6ni9evUq69ev5/Tp01RUVODn52cQvi4lY64Q9krO0oRdcXNzY+3atXTp0oX09HQiIyMZOXIkarWapKQk7t+/bxB+1KhRaDQaRo4c2ey009PTWbx4MUFBQRw8eJDk5GTCwsJYs2YN69evb/L7dfNy5swZNBqN/l9qamqT34mJiSE8PJwvv/ySXbt24ejoWC/MmjVriIyM5Pjx40RHR3Po0CGio6NZvXo18+fP56uvvuLVV19l3759fPjhhxYtI0B+fj7h4eEcPXqUZcuWkZGRQXx8PEVFRUyZMkU/SQRYuXIlu3bt4o033iAjI4ODBw/y5JNPsnDhQpNWNi0oKCA8PJykpCTUajVpaWkkJiYSGBjIsmXLSExMrBf28OHD+rC7d+/GxcWFmTNnsm/fPrPr3FgYpXVhall0Cya5urrSr18//fFTOy5L7EchhH2Qcc++x726eVm9ejVTp04lJSWF999/n8zMTP2q3TqmjkeNscb4Z4kyNpW/xo7Xa9euERERwcWLF1m3bh0nTpxg2bJlfPTRR/z000/1wisZc4WwZzIBF3anf//+HD58mPfee4+RI0dSVlbG4cOHiY6OZsyYMS36HFFgYCAzZ86kbdu2eHl5MXnyZMaNG8dnn32GVqttsXR1ZsyYQWBgIC4uLvTt25cLFy7g5eVlEGbixIn4+fnh6upKaGgovr6+pKenM23aNHr16oWbmxthYWF07drV6MlPc8u4YcMGcnNzWbJkCcOHD8fNzQ1fX1/WrFlDdXU1K1eu1If9+uuv8fX1JTg4GJVKRYcOHXjttdfo1q2bSfXxwQcf8PPPP6NWqwkJCcHd3Z0OHTowe/Zshg0bZjRsdHQ0ISEheHh40K1bN2JjY+nYsSOrVq3i1q1bZtV5Q2GU1IWSspjC1seqEMJyZNyz73GvtkmTJhEQEICrqyuDBw8mJCSE7OxsCgsL9WHMHY9qs8b4Z4kyNmdM27BhA8XFxajVaoKDg3Fzc6NHjx68++67FBQUGA1v6pgrhD2TCbiwS87OzkyYMIGNGzeSkZHBJ598wtixY7lz5w5qtZrvvvvO4mmGhIQQHx9fb3vPnj2pqKjQL5TTkp555pkmw/Tp08fg744dOxrd3rlzZ/Lz8w22WaKMx44dw9HRkREjRhhs9/b25qmnnuLbb78lLy8PgGHDhvHNN98QExNDVlaWfgXUQ4cOERgYaFJaunjq2rJlC1OnTq0Xtm6+nJ2dCQoKoqysjIyMjHrxmFLnDYVRUhdKytIUezhWhRCWJeNew2w97jWW3y5dugAYpGvueFSbNca/higpY3PGNF2ehg4darC9U6dORn+oVzLmCmHP5BlwYfecnJwICgoiKCiIX/ziF8THx5OcnEzv3r0tmo5WqyUhIYFjx46Rl5dHcXGxwed1bwNsCa6urk2Gqf1sG9Q8G+zo6IiLi0u97XVf+dHcMpaXl+uvFgQHBzcYLicnh86dO/Pmm28SEBDA3/72N2bMmAHAgAEDCAsL47nnnjMpLZVKVa/MSsPqFjky9ou6KXVuLIySuvDy8jK5LKawh2NVCNFyZNwzZMtxry4PDw+Dv1u1qjmV1qXbnPFIx1rjX0OaW0ZTlJeXU1JSgkqlws3Nrd7n7du3JycnxyC8kvMPIeyZTMCFXTl//jxRUVGcOHHC6OeDBg0iPj6eu3fvWjztefPmce7cOdRqNePGjaNdu3Y4ODiwc+dO4uLiqK6utnia1tbcMjo7O9OmTRtKS0s5e/YsTk5OjYZ3cHAgNDSU0NBQKioqOH36NAkJCURFRbF48WJeeeWVRtPy8PBAq9VSUlLS6CDfVFjdrXfe3t6N5lcJpXVhall0HBwcGvzscThWhXhcyLjXsqxdRkuMRw/D+Kd0TDMWh7u7OyUlJZSWltabhNc93pWOuULYM7kFXdiV6upqbt++TVZWltHPL168CGDxlS6rqqr45ptv8Pb2JiIiAi8vL/0EqKyszKJp2Yqlyjh69GgqKys5f/58vc/i4+MZM2YMlZWVQM2v1FevXgVqfkEPDg5m48aNODg4GH1Ory7dVXJjr+AJCwsjLi6uXti68ZaXl5OZmYlKpap3m1tzKakLJWUBcHFx0b/aB+DFF1/k888/fyyOVSEeJzLutRxbldES45G9j39KxzRjdLevp6enG2wvLCzUnzvUpmTMFcKeyQRc2KXXXnuNpKQkbt68SXl5Obm5uSQkJLB161b8/PyYMGGCRdNzdHQkMDCQgoICPv30UwoLCykrK+PUqVMGK40+zCxVxqioKHx8fHjrrbdIT09Hq9VSVFTE3r172bJlC6+//rrBL9PvvPMOly9fpry8nNu3bxMfH091dbVJr2GJioqia9euxMXFkZqaSklJCXl5eaxYsYL8/HyDZ8x0YWNjYzlx4gQlJSXk5OQQHR1Nfn4+arVafyuepSipCyVlAfDz8+Nf//oXN27c4MKFC/z73/+mf//+Zu1HtVqNv78/P//8s0XLL4SwHBn3LM9WZbTEePQwjH9KxjRjFi1ahKenJ7GxsZw8eZLS0lKuXLnC0qVLjd6WrvT8Q8Y+Ya8cqh+F+4vszLVr11rkVrHHQVVVFRcuXCAlJYVz585x48YNbt26hYuLC927d2f06NFMmTJF/9xX3fdLAowfP57Vq1cbjb/2O5Z1Zs2axYIFCygsLGTTpk2kpaVRUFCAp6cnw4YNw9vbmz//+c9AzaRoz549RuNuLC9z5syptwDK9u3badWqFREREfXi0mg0+v/PysqqF2bWrFmMGjWK8PBwg+1RUVH069ePadOmGWyfO3cur776arPLqFNUVMS2bdv07xtt06YNvXv3Zvr06QwePFgf7tKlS+zZs4ezZ8+Sm5uLSqWiW7duTJw4kYkTJzZ6m7XOnTt39Gnp3jM6cOBA5s2bV2+RlrphXVxc9O9BDQoKarA+oek6rxtGaV0oLcu//vUv3n77bb777js8PT2ZMWOGfn8r3Y8zZ85Eo9Fw8uRJeUd4M/n4+ODp6dkicWdnZ7dIvMK+ybhXw17HvYbysmDBAvz9/Q22jxgxgs2bNwOmjUdNsfT419D+mjx5skXKaCx/TR2vOTk5rFu3jlOnTvHgwQN69OjB3Llz2bFjB5mZmUDNKvgxMTGAsjFXxj6hY8pij9YkE/AWIBNwIYS9KC4uZuTIkbz44ossX77c1tl56MkEXAgh7J+MfaI2e5uAy89BQgjxiKqurmbVqlV4eHgwf/58W2dHCCGEaHEy9gl7JxNwIYR4RN26dYt///vffPLJJxZdAVcIIYSwVzL2CXsnt6C3ALkFXQghHk1yC7oQQgjxcJFb0IUQQgghhBBCiMeQTMCFEMKK/u///o9nn32WpKQkW2dFCCGEEEJYmUzARYs7cuQI/v7++Pv7M2DAAJvlIyEhQZ+P5557zmb5aGmPWjmVlseey5+VlcWaNWtYv34948aNs3V2rN42c3Jy8Pf3N/oKImF99txWLOlxKefDzF7OEx52VVVVJCYmMmXKFIKDg3n22WcZNWoUc+fOZffu3eTm5hqEHzRokL7ea//r27cvI0aMYOHChQ0+GmNKf15aWlov7gsXLjRZjrVr1xp856OPPlJWEcKolJQUg3otKyuzdZYeWzIBFy1u7NixaDQak9972VJ+97vfodFo6Nmzp03zYUmlpaWMHz+eefPm6bc9auVUWh57LX9BQQFvvPEG69atY+TIkbbODmD9tnngwAGg5oeIK1euWCVN0TB7bSvN8Tj0iY8iezlPeNgtXbqU9957j1GjRnHgwAEyMzPZvn07vXv3ZtWqVbz88ssG4U+dOsXevXsBGDlyJBqNBo1Gwz//+U/efvttLly4wNSpU/n666/rpWVKf+7m5oZGo9GnAbB169ZGy3Dnzh0SExOBmveFazQaZs+ebXoliAaNGjUKjUZjN+cgjzOZgAvxEKuurqaqqoqqqipbZ0U0wdvbm0OHDhEcHGzrrNhEVVUVBw8epHfv3sB/Tt6EsCTpE8XjKjs7m6SkJCZOnEhkZCSdO3dGpVLh4+PDwoUL602+G+Ph4cFzzz3HkiVLqKioIDY21uBzc/pzlUrFE088QXp6OhcvXmww3M6dO+nSpYvJeRXiYSQTcCEeYu7u7hw5coQtW7bYOitCNOqf//wnrVq14u233wbgiy++oLKy0sa5Eo8a6RPF40p3Fbp79+5GP3/hhRcUxxkYGAjADz/8QHFxsX67Of25o6MjM2bMAGjwlvLi4mL27NlDZGSk4rwK8TCRCbgQQogWt3//fl566SX69OnD008/za1bt0hNTbV1toQQ4pHQoUMHAE6ePGn084EDB5KWlmZ2/A4ODvr/N7c//81vfkOnTp04fvw4ly9frvf5rl27GD58OD4+PmbnU4iHQStbZ0A07erVq6xfv57Tp0/z4MEDevTowZw5c9i5cyeZmZkATJw4kSeeeII//elPAPTr148dO3YAkJ6ezty5cwFo166dQQdcWVlJcnIy+/bt4/vvv0er1eLj48OkSZOYPHkyjo41v9GkpKSwaNEi/fe++OILNm3aRGZmJkVFRQCkpqbi5eVlkN+Kigr8/PwMvlubqek3pbCwkK1bt3L8+HFu3rxJmzZt6N+/P3PmzKFXr15KqtusuOvWz9GjR1m3bh1paWm0bt2a4cOHs3TpUrRaLStXruT06dO4ubkREhLC4sWLcXd3V1wnddM8c+YMKpXKJuXMyMjAycmJgIAA1Gq1yYNnS+43natXr7JmzRrOnz/PgwcP6Nu3LwsWLKBfv35AzS/xSttNcHAwWq3WaHoODg4kJyfTuXNnoOZ5to8//piUlBRu3LiBq6srAQEBTJ8+nUGDBgGWr9fG6sLUtgmW2z9FRUWcOHGCP/zhD0DNSVhcXBz79++v9yyaOXVhqX7kUSJ9onX6RIDy8nK2bdvG0aNHuX79OiqVin79+jFp0iRCQkIaPf7soZ4aG89r9195eXl4eXnx5JNPEhoayq9//Wt9/Sptg0r7IlP60aaYWhZT07PkvrNEGfv374+3tzcZGRnMnTuXyMhIBgwY0Kz+7/Tp0wD4+vri4eEBKOvP63J2dmb69OnExsaybds23n//ff1npaWl/OUvfyEhIYE7d+6YlL/i4mKGDBlisG3+/PnMnj2byspKnn32Wf32MWPGsG7dugbjUtKOm9O/Kml/StJRcnzr3Lp1y6Ljq6nnRjJmyxVwu3ft2jUiIiK4ePEi69atIzU1lXfffZfPPvuMy5cv4+zsjEajISYmhtmzZ6PRaHB1dTWIY9iwYWg0Gvz8/OrFn56ezuLFiwkKCuLgwYMkJycTFhamX6lZp+7CDTExMYSHh/Pll1+ya9cufWOpm98TJ06wbNkyPvroI3766Sez029Mfn4+4eHhHD16lGXLlpGRkUF8fDxFRUVMmTLFpBU3mxt3dd1QzQAAD+VJREFU3fpZs2YNkZGRHD9+nOjoaA4dOkR0dDSrV69m/vz5fPXVV7z66qvs27ePDz/80Kw6seRiGuaWc/Xq1UydOpWUlBTef/99MjMzWbJkiUXTbI7S0lJWrFjB//7v/3Ls2DG2b99OUVERM2bM4MyZMwBmtRuAzMxM/YI1Go2G+fPnA7Bw4UL95LugoIDw8HAOHz6MWq0mLS2N3bt34+LiwsyZM9m3bx9g2XptiNK2acn9k5SUREBAAF27dgXgxRdfpFWrVqSmpnL79m2DsObUhSX6kUeJ9InW6xMBVq5cya5du3jjjTfIyMjg4MGDPPnkkyxcuJCzZ882mo491FND47mu/0pKStL3X4mJiQQGBrJs2TL9QllK0gblfZGp/WhjlJTF3H67OfvOEmV0c3Nj7dq1dOnShfT0dCIjIxk5ciRqtZqkpCTu37/fZBw6Wq2WY8eOERcXR6tWrYiOjtZ/pqQ/NyYsLIwOHTqQnJzMjz/+qN/+17/+lUGDBvGrX/3K5Hy2adMGjUbD0KFDcXR0JCkpSb9gm5OTExqNhoCAAGJjYxudfIPp7bi5/aup7U9JOkqO79pqj69r167l3LlzzR5fTTk3kjFbJuB2b8OGDRQXF6NWqwkODsbNzQ1fX1/i4uK4d++eRdIIDAxk5syZtG3bFi8vLyZPnsy4ceP47LPPGvwla8aMGQQGBuLi4kLfvn25cOECXl5eRvPbo0cP3n33XQoKCiyWfm0bNmwgNzeXJUuWMHz4cH0drVmzhurqalauXGl23Zgb98SJE/Hz88PV1ZXQ0FB8fX1JT09n2rRp9OrVCzc3N8LCwujatavR27aaWyfWKuekSZMICAjA1dWVwYMHExISQnZ2NoWFhS2WphJarZZFixbRr18/3Nzc6NOnD6tXr+bBgwesXr262fHrHD16lM2bN/PSSy8xc+ZM/fYPPviAn3/+mejoaEJCQvDw8KBbt27ExsbSsWNHVq1axa1bt+rF15x6bYjStmnJ/bN//35+85vf6P/28vIiJCSEyspKvvjii0a/a2pdWLvN2DPpE5tPSTm//vprfH19CQ4ORqVS0aFDB1577TW6deumOF1b1FND47mu/1Kr1YSEhODu7k6HDh2YPXs2w4YNMzttpX2Ruf2osThMKYu56TVn31mijFBzFfzw4cO89957jBw5krKyMg4fPkx0dDRjxozhyJEjDX73q6++0r+easiQISxfvpyAgAB27tzJ4MGD9eGa059DzWJsr7zyClVVVXz88ccA3L9/nx07djBr1qwmv2+MLj7dHWw658+f5/r16zz//PNNxmFqO7Z0/9rY+bSp6Shtqzq1x9egoCBGjBhh0fG1oXOj5sT5qJAJuJ3LyMgAYOjQoQbbdbeWNFdISAjx8fH1tvfs2ZOKiooGXy3xzDPPGN3eUH47depk9GTE3PRrO3bsGI6OjowYMcJgu7e3N0899RTffvsteXl5TcZjybj79Olj8HfHjh2Nbu/cuTP5+fkG2yxRJ0qZW866x4Fu5dK6ZbJkmkqoVCr8/f0NtvXo0YNOnTpx6dIlk/JpzMmTJ3FzcwNqXsHy5ptvMmDAAP2CNDrHjh0DqFdGZ2dngoKCKCsr07eZ2ppTrw1R2jYttX8uX77MtWvXGDNmjMF23QlcU6vnmlIXtmgz9kz6xOZTUs5hw4bxzTffEBMTQ1ZWln4F9kOHDukXsTKVLeqpofFc138ZO4HfsmULU6dONSttc/oiUN6PmlsWc9Nrzr6zRBlrf2fChAls3LiRjIwMPvnkE8aOHcudO3dQq9V89913Rr9X+zVkWVlZpKWlsXHjRoPjo7n9uU54eDjt2rUjKSmJa9eukZiYSN++fXn66adN+n5dQ4YMoUePHhw4cMDg9vVPP/2UiIgIWrVq+olbU9uxpfvXxtqfqekoOb4bS1t3hdrc8dXUcyMZs+UZcLtWXl5OSUkJKpVKf0DX1rZt22anodVqSUhI4NixY+Tl5Rmscgk0eMtS3dt1Tclv+/btycnJsUj6tdPU/VLW2OudcnJy9B2LqZoTd91nuxwdHXF0dMTFxaXe9rqvy2lunSjVnHLqngnT0Q1yTb0CqCX3W22enp4GC8fotG/fnps3b3L79m39SZI5rl+/zsKFC+nSpQsffPABrVu31n+mK6NKpap3PMB/FswxdsXH3HptiNK2acn9s3//fkpKShqciPzwww9oNJp6P5TomFIX1m4z9kz6xOZTWs4333yTgIAA/va3v+lXeR4wYABhYWE899xzitK2RT01NJ431n/VZWra5vZF5vSj5pSlOemZu+8sUcaGODk5ERQURFBQEL/4xS+Ij48nOTlZ//owpZrbn+u4ubkxZcoU/vSnP7F582bOnDnDxo0bzcqTztSpU/njH//Inj17mD17Njk5OZw6dYoVK1aY9H1T2nFL9K+NtT9T0vHy8lLUVmurO77qzpeaO742dm5kbpyPGpmA2zFnZ2fc3d0pKSmhtLS03mDV0LM2jo6OPHjwoN72ugc4wLx58zh37hxqtZpx48bRrl07HBwc2LlzJ3FxcVRXV1ssv3fv3rV4+s7OzrRp04bS0lLOnj2Lk5OTyfk1pTwtFXdjLLlPTGGLclorzYZuY9K1nfbt2+u3KWk3ACUlJcybN4+Kigo2b96Mp6enwefOzs54eHig1WopKSmpNzDqbif09vY2vUBmUto2LbV/KioqOHz4MDt37jRYDEcnLi6OnTt3cuDAgSZP2Bpj7TZjz6RPbD6l5XRwcCA0NJTQ0FAqKio4ffo0CQkJREVFsXjxYl555RWL5q8hlh7PG+u/zE3bnL6ouf2okrLYot+2VJrnz58nKiqKEydOGP180KBBxMfHGz0XM4Wl+/OIiAgSEhJISkpi2LBh9e4UUGr8+PFs2LCBv/zlL0yfPp2EhAQmTJhg8sUqU9qxtfpApekoaatKKe1Xmjo3MifOR5Hcgm7ndLeTpKenG2wvKCiodzVZx9vbm5s3b9YLf/36dYNtVVVVfPPNN3h7exMREYGXl5f+16+ysjKL5rewsJCrV6+2SPqjR4+msrKS8+fP1/ssPj6eMWPGmP2+4ZaM25iW2CemsHY5rZVmaWkply5dMtj2/fffc/PmTXr27Glw9dvUdgM1+2nx4sX6lXxr3zb5hz/8gZSUFAD9r+Z1n/crLy8nMzMTlUpV7zbMlqKkbYJl9s/x48dp166d0ZM1qHlmEmoW9TH3+LZVm7Fn0ic2n5JyBgcH69tQq1atCA4OZuPGjTg4OFjtVXstUU+6/svYq6vCwsKIi4szK22lfZEl+lFTy2Kp9JSyRJrV1dXcvn2brKwso59fvHgRwOy3IFi6P/fw8GDatGl4eHjoF05rDmdnZ8LDw7l9+zbbt2/n8OHDTJkyxeTvm9qOrdUHKklHyfGthNK2bcq5kYzZNWQCbucWLVqEp6cnsbGxnDx5ktLSUn744QfeeuutBn8NHTJkCDdv3mT37t2Ulpby008/sXr1aoOrfVBzxS8wMJCCggI+/fRTCgsLKSsr49SpUw2umGhOfq9cucLSpUvr/dJtqfSjoqLw8fHhrbfeIj09Ha1WS1FREXv37mXLli28/vrrZv9K2ZJxG9MS+8QU1i6ntdJ0dXVl5cqVZGVlce/ePS5evIharaZ169ao1WqDsKa2G4DY2FjS0tJYvnx5o894RkVF0bVrV2JjYzlx4gQlJSXk5OQQHR1Nfn4+arVaf3thS1PSNnV5b+7+OXDgAL/97W8b/NzX1xd/f3+0Wi1ffvmlWeVS2mZyc3MJCAjA39+/wWchH3bSJzaf0nK+8847XL58mfLycm7fvk18fDzV1dUmvyKruVqinnT9V1xcHKmpqZSUlJCXl8eKFSvIz8/XP1eqNG1z+qLm9qOmlsVS6SllyTRfe+01kpKSuHnzJuXl5eTm5pKQkMDWrVvx8/NjwoQJZuWxJfrzOXPmcPLkyQYn9Uq9/PLLqFQqNm3axODBg/mv//ovRd83pR1bqw9Uko6S41sJpW3blHMjGbNrOFQ/Dtf5rezatWtm3+JjTE5ODuvWrePUqVNUVFTQq1cvoqKi2Lx5MxqNRv+eRh2tVsv7779Pamoqd+/epU+fPixZsoR33nmHb7/9FoDIyEh+//vfU1hYyKZNm0hLS6OgoABPT0+GDRuGt7c3f/7znwHw8/PjzTffJCIiol7eNBpNo/nVvbd87ty57Nixw+C95TExMSanv2fPnkbrqKioiG3btunfn9mmTRt69+7N9OnT9at3JiQksHbtWoPvzZo1iwULFjQ77qysrHr1M2vWLEaNGkV4eLjB9qioKPr168e0adMMts+dO5dXX33V5DqZPXt2vfemjh8/nl69elm9nAsWLKh3y9mIESPYvHlzs9NUut9qh+/UqRMbNmxg/fr1ZGdnU1lZib+/PwsXLtS/B1zH1Hbzwgsv8PLLLzdarg0bNjBq1Cig5t2cujLm5eXh4uKif7drUFAQYPl6bYiStgmm7R9j8vLyGD16tP7vvn37smvXLoMwubm5vPDCCwbbOnTowMaNGxXXhZJ+JDc3l7Fjx1JdXc2+ffvo0aOHojr08fExekudJWRnZ1ssLukTa7R0nwhw6dIl9uzZw9mzZ8nNzUWlUtGtWzcmTpzIxIkTja5DoWOLelIyntftv7y8vBg4cCDz5s0zuLqldCxX2heZ0o82xdSymJqeJfedJcpYVVXFhQsXSElJ4dy5c9y4cYNbt27h4uJC9+7dGT16NFOmTDF4Jn3QoEH13qjTvXt3g9XMm9OfHz9+vF4aQ4cOZevWrQ2Ww9jt62+88Qb/8z//00QN1IiJieHzzz8nISGBAQMGmPQdUNaOzR0bwfhxA8bbn5J0TDm+zTnXMLVtv/322yafG1lzzNZpaLE7W5EJeAuw9AS8IaGhoZSVlfGPf/yjxdMSQgjx8EzAhRDicXTgwAF2797d5IUb8Xixtwm43IJu5woKChg6dCgVFRUG23Nzc/npp5+sdnubEEIIIYQQ9iwxMbHenQZC2BuZgD8E7t69S0xMDDdu3OD+/ftoNBpef/11PDw8mDNnjq2zJ4QQQgghhNXt27ePRYsWUVpaSmJiInfv3q13O7wQ9kZeQ2bnvL29+eSTT9i9ezfTpk0jPz+ftm3bMnjwYGJjY/nlL39p6ywKIYQQQghhEykpKQwZMoSnnnqKNWvWWO0ViUKYS54BbwHWegZcCCGEdckz4EIIIcTDRZ4BF0IIIYQQQgghHkMyARdCCCGEEEIIIaxAJuBCCCGEEEIIIYQVyARcCCGEEEIIIYSwApmACyGEEEIIIYQQViATcCGEEEIIIYQQwgrkNWRCCCGEEEIIIYQVyBVwIYQQQgghhBDCCmQCLoQQQgghhBBCWIFMwIUQQgghhBBCCCtoBey1dSaEEEIIIYQQQohH3f8DwRiAkws/ofIAAAAASUVORK5CYII="></span></p>
<p>Como puedes ver, teóricamente el sistema funciona muy bien... ¿cuál es el problema entonces? ¿porqué a dia de hoy seguimos recibiendo <em>toneladas</em> de emails con spam, virus y demás <em>basura</em> digital? Pues porque desgraciadamente el uso de DKIM es completamente opcional, lo que significa que la inmensa mayoría de los servidores de correo de Internet <strong>no lo están usando</strong>.</p>
<p>Y al no usarlo, no solo están permitiendo de forma directa que alguien envíe emails haciéndose pasar por los legítimos usuarios de esos servidores, sino que tampoco están verificando que los emails que les llegan a ellos proceden de quien dicen proceder.</p>
<p>Es algo muy parecido a lo que sucede con el sistema <a href="https://es.wikipedia.org/wiki/Sender_Policy_Framework">SPF</a> (ya escribiré otro artículo sobre este sistema): no servirá de nada hasta que el 100% de los servidores de correo de Internet lo utilicen, pero al menos nos quitaremos un pequeño porcentaje (o grande, según el caso) de emails no deseados.</p>
<p>Vamos entonces a ver cómo se configura <a href="http://www.opendkim.org/">OpenDKIM</a>, que como ya dije al principio no es más (ni menos) que la implementación <a href="https://es.wikipedia.org/wiki/C%C3%B3digo_abierto">open-source</a> más utilizada del sistema DKIM.</p>
<h2>Instalación y configuración de OpenDKIM<a name="install"></a></h2>
<p>Para firmar los emails con OpenDKIM se utiliza el típico esquema de firma de certificados usando un par de claves (pública y privada), comúnmente conocido como <a href="https://es.wikipedia.org/wiki/Criptograf%C3%ADa_asim%C3%A9trica">criptografía asimétrica</a>. Es el esquema típico que se usa en cientos de aplicaciones y servicios, por lo que no entraré en profundidad en este tema.</p>
<p>Únicamente basta que con tengáis presente que para firmar algo con este sistema se necesitan 2 claves. La clave privada únicamente la tiene la persona que va a firmar el mensaje, y la pública está a disposición de todo el mundo para que puedan utilizarla para validar si el mensaje firmado con la clave privada es correcto. Una explicación muy sencilla (extraída de la página sobre <a href="https://es.wikipedia.org/wiki/Criptograf%C3%ADa_asim%C3%A9trica">criptografía asimétrica</a> de la <a href="https://es.wikipedia.org/">Wikipedia</a>) sería esta:</p>
<p><sub>De Dvdrodriguez - Trabajo propio, CC BY-SA 3.0, <a href="https://commons.wikimedia.org/w/index.php?curid=26102947">https://commons.wikimedia.org/w/index.php?curid=26102947</a></sub>
<img class="center" src="/images/posts/2017-11-10-firmando-emails-con-opendkim/firma_digital_asimetrica.png"></p>
<ol>
<li>David redacta un mensaje</li>
<li>David firma digitalmente el mensaje con su clave privada</li>
<li>David envía el mensaje firmado digitalmente a Ana a través de internet, ya sea por correo electrónico, mensajería instantánea o cualquier otro medio</li>
<li>Ana recibe el mensaje firmado digitalmente y comprueba su autenticidad usando la clave pública de David</li>
<li>Ana ya puede leer el mensaje con total seguridad de que ha sido David el remitente</li>
</ol>
<p>En nuestro caso, no será <em>David</em> (la persona que envía el email) quien firme el mensaje, sino que lo hará automáticamente su servidor de correo. Y tampoco será <em>Ana</em> (la persona que recibe el email) quien verifique con la clave pública de David si el mensaje es válido, sino que lo hará también de forma automática su servidor de correo al recibir el mensaje. Es decir, es un proceso <em>transparente</em> para el usuario.</p>
<p>Toda la <em>magia</em> del proceso se hará de forma automática en los respectivos servidores de correo tanto del remitente como del destinatario, sin que estos tengan que preocuparse de nada (como buenos <s>merluzos</s> usuarios).</p>
<p>Lo primero que haremos entonces es instalar los paquetes de OpenDKIM en nuestro servidor SMTP.</p>
<p>Como siempre, si usamos una distribución de Linux decente (como por ejemplo <a href="http://www.debian.org">Debian</a>), bastaría con ejecutar:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install opendkim opendkim-tools
</code></pre></div>
<p>Si por el contrario vendimos nuestra alma al Diablo, perdimos una apuesta o estamos realizando algún tipo de penitencia y usamos <a href="https://www.centos.org/">CentOS</a>, <a href="http://www.redhat.com/es">Redhat</a> o similares, podemos instalarlo también de forma sencilla con:</p>
<div class="highlight"><pre><span></span><code>$ sudo yum install opendkim
</code></pre></div>
<p>OpenDKIM se ejecuta en forma de <a href="https://es.wikipedia.org/wiki/Demonio_(inform%C3%A1tica)">demonio</a>, por lo que antes de iniciar el proceso hay que configurarlo.</p>
<p>El proceso de instalación habrá creado el archivo <code>/etc/opendkim.conf</code> y el directorio <code>/etc/opendkim</code>. Es decir, si todo ha ido bien tendréis algo parecido a esto en vuestro servidor:</p>
<div class="highlight"><pre><span></span><code><span class="err">├─ etc/</span>
<span class="err">│ ├─ opendkim.conf</span>
<span class="err">│ └─ opendkim/</span>
<span class="err">│ ├─ keys/</span>
<span class="err">│ ├─ KeyTable</span>
<span class="err">│ ├─ SigningTable</span>
<span class="err">│ └─ TrustedHosts</span>
</code></pre></div>
<p>No te preocupes si te falta algún archivo, o si en tu caso se llama de otra forma, la instalación puede variar dependiendo de la versión de OpenDKIM, así que una vez que sepas para qué es cada uno de ellos podrás adaptar la instalación a cualquier caso.</p>
<ul>
<li><strong>opendkim.conf</strong>: Como podrás imaginar, aquí estará la configuración principal del demonio OpenDKIM.</li>
<li><strong>opendkim/keys/</strong>: En este directorio es donde se guardarán las claves privadas con las que OpenDKIM firmará los emails que se envíen desde nuestro servidor.</li>
<li><strong>opendkim/KeyTable</strong>: En este archivo se configuran las claves que vamos a usar para cada dominio que vamos a firmar (es recomendable utilizar una firma diferente para cada dominio).</li>
<li><strong>opendkim/SigningTable</strong>: Este archivo le dice a OpenDKIM cómo debe firmar los mensajes, según el dominio del remitente.</li>
<li><strong>opendkim/TrustedHosts</strong>: Aquí especificamos la lista de dominios en los que confiamos, es decir, los dominios que no vamos a verificar (porque normalmente es nuestro servidor el que los firma).</li>
</ul>
<p>Empezaremos por el archivo de configuración <code>opendkim.conf</code>. Hay muchas directivas de configuración disponibles para este archivo, por lo que solo voy a explicar las necesarias para la mayoría de los casos. No obstante, te recomiendo que eches un ojo al archivo <code>/usr/share/doc/opendkim/examples/opendkim.conf.sample.gz</code> ya que en él se explican la mayoría de ellas (dicho archivo forma parte del paquete de instalación de OpenDKIM para Debian, pero desconozco si en los paquetes de CentOS o RedHat existe también).</p>
<p>Así es como debería estar el archivo de configuración:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">opendkim.conf</span><a href='/files/2017-11-10-firmando-emails-con-opendkim/opendkim.conf'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="c1"># This is a basic configuration that can easily be adapted to suit a standard</span>
<span class="c1"># installation. For more advanced options, see opendkim.conf(5) and/or</span>
<span class="c1"># /usr/share/doc/opendkim/examples/opendkim.conf.sample.</span>
<span class="c1"># Log to syslog</span>
Syslog yes
<span class="c1"># Required to use local socket with MTAs that access the socket as a non-</span>
<span class="c1"># privileged user (e.g. Postfix)</span>
UMask <span class="m">007</span>
KeyTable /etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
<span class="c1">## Identifies a set of "external" hosts that may send mail through the server as one</span>
<span class="c1">## of the signing domains without credentials as such.</span>
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
<span class="c1">## Identifies a set "internal" hosts whose mail should be signed rather than verified.</span>
InternalHosts refile:/etc/opendkim/TrustedHosts
<span class="c1"># Commonly-used options; the commented-out versions show the defaults.</span>
<span class="c1">#Canonicalization simple</span>
<span class="c1">#Mode sv</span>
<span class="c1">#SubDomains no</span>
<span class="c1"># Socket smtp://localhost</span>
<span class="c1">#</span>
<span class="c1"># ## Socket socketspec</span>
<span class="c1"># ##</span>
<span class="c1"># ## Names the socket where this filter should listen for milter connections</span>
<span class="c1"># ## from the MTA. Required. Should be in one of these forms:</span>
<span class="c1"># ##</span>
<span class="c1"># ## inet:port@address to listen on a specific interface</span>
<span class="c1"># ## inet:port to listen on all interfaces</span>
<span class="c1"># ## local:/path/to/socket to listen on a UNIX domain socket</span>
<span class="c1">#</span>
Socket inet:8892@localhost
<span class="c1">## PidFile filename</span>
<span class="c1">### default (none)</span>
<span class="c1">###</span>
<span class="c1">### Name of the file where the filter should write its pid before beginning</span>
<span class="c1">### normal operations.</span>
<span class="c1">#</span>
PidFile /var/run/opendkim/opendkim.pid
<span class="c1"># Always oversign From (sign using actual From and a null From to prevent</span>
<span class="c1"># malicious signatures header fields (From and/or others) between the signer</span>
<span class="c1"># and the verifier. From is oversigned by default in the Debian pacakge</span>
<span class="c1"># because it is often the identity key used by reputation systems and thus</span>
<span class="c1"># somewhat security sensitive.</span>
OversignHeaders From
<span class="c1">## ResolverConfiguration filename</span>
<span class="c1">## default (none)</span>
<span class="c1">##</span>
<span class="c1">## Specifies a configuration file to be passed to the Unbound library that</span>
<span class="c1">## performs DNS queries applying the DNSSEC protocol. See the Unbound</span>
<span class="c1">## documentation at http://unbound.net for the expected content of this file.</span>
<span class="c1">## The results of using this and the TrustAnchorFile setting at the same</span>
<span class="c1">## time are undefined.</span>
<span class="c1">## In Debian, /etc/unbound/unbound.conf is shipped as part of the Suggested</span>
<span class="c1">## unbound package</span>
<span class="c1">#ResolverConfiguration /etc/unbound/unbound.conf</span>
<span class="c1">## TrustAnchorFile filename</span>
<span class="c1">## default (none)</span>
<span class="c1">##</span>
<span class="c1">## Specifies a file from which trust anchor data should be read when doing</span>
<span class="c1">## DNS queries and applying the DNSSEC protocol. See the Unbound documentation</span>
<span class="c1">## at http://unbound.net for the expected format of this file.</span>
TrustAnchorFile /usr/share/dns/root.key
<span class="c1">## Userid userid</span>
<span class="c1">### default (none)</span>
<span class="c1">###</span>
<span class="c1">### Change to user "userid" before starting normal operation? May include</span>
<span class="c1">### a group ID as well, separated from the userid by a colon.</span>
<span class="c1">#</span>
UserID opendkim
</code></pre></div>
</figure>
<p>Como podéis ver, el archivo es bastante <em>autoexplicativo</em>, pero vamos a ver algunas de las directivas un poco más en detalle:</p>
<div class="highlight"><pre><span></span><code>KeyTable /etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
InternalHosts refile:/etc/opendkim/TrustedHosts
</code></pre></div>
<p>Estas cuatro directivas se usan para indicar al demonio de OpenDKIM la ruta a los archivos de configuración que vimos antes, donde estableceremos las claves que vamos a usar, los dominios cuyos emails vamos a firmar, etc.</p>
<div class="highlight"><pre><span></span><code>Socket inet:8892@localhost
</code></pre></div>
<p>Aquí especificamos donde estará <em>escuchando</em> el demonio de OpenDKIM (para que nuestro <em>SMTP</em> pueda conectarse a él). Puede escuchar en un <a href="https://es.wikipedia.org/wiki/Socket_Unix">socket</a> (<code>local:/path/to/socket</code>), en una IP y puerto concretos (<code>inet:port@address</code>) o en un puerto concreto de todos los interfaces de red del servidor (<code>inet:port</code>).</p>
<p>En este caso concreto estamos configurando OpenDKIM para que <em>escuche</em> en el puerto 8892 del interface de red local (es decir, el servicio únicamente sería accesible desde ese servidor, no desde los demás servidores de nuestra red).</p>
<p>Cuando tengamos el demonio de OpenDKIM y el demonio del SMTP instalado en el mismo servidor, podemos utilizas un socket. En caso de estar en servidores diferentes, tendremos que levantar el demonio en una ip/puerto concreto. No obstante, siempre que sea posible intento evitar el uso de sockets (independientemente de donde tengamos los demonios). Aunque ya digo que esto es personal, podéis configurarlo según vuestras necesidades o preferencias personales.</p>
<div class="highlight"><pre><span></span><code>PidFile /var/run/opendkim/opendkim.pid
</code></pre></div>
<p>Como en la mayoría de los demonios de Linux, hay que indicar un <em>path</em> para el <a href="https://es.wikipedia.org/wiki/Identificador_de_proceso">archivo PID</a>.</p>
<p>Como veis no hay ningún misterio, así que no creo que haga falta repasar todas las demás directivas. Vamos entonces a generar en primer lugar nuestro par de claves (pública y privada) para el dominio que vamos a firmar (pueden ser varios, por supuesto).</p>
<p>Por cuestiones de organización, creamos un directorio dentro de <code>/etc/opendkim/keys</code> por cada uno de los dominios que vayamos a firmar. En nuestro caso vamos a firmar los emails del dominio <code>pornohardware.com</code>, por lo que crearemos las claves dentro de <code>/etc/opendkim/keys/pornohardware.com</code>:</p>
<div class="highlight"><pre><span></span><code>$ mkdir /etc/opendkim/keys/pornohardware.com
</code></pre></div>
<p>Ahora generaremos las claves con el comando <code>opendkim-genkey</code>, especificando algunos parámetros:</p>
<ul>
<li><code>-d</code> o <code>--domain</code>: El dominio que queremos firmar</li>
<li><code>-D</code> o <code>--directory</code>: El directorio donde guardar las claves</li>
<li><code>-s</code> o <code>--selector</code>: El nombre que queramos darle a la clave (este es el nombre que tendrá el registro DNS de nuestro dominio donde pondremos la clave pública a disposición de todo el mundo, así que puedes poner el que prefieras)</li>
<li><code>-h</code> o <code>--hash-algorithms</code>: Con este parámetro indicamos el algoritmo de cifrado que queremos utilizar para generar las claves. Podemos usar cualquiera, pero según las Recomendaciones de Seguridad para el Correo Electrónico <a href="/files/2017-11-10-firmando-emails-con-opendkim/NIST.SP.800-177.pdf">NIST 800-177</a> (publicadas por el Instituto Nacional de Estándares y Tecnología), es preferible que utilicemos <a href="https://es.wikipedia.org/wiki/SHA-2">sha256</a> antes que cualquier otro.</li>
<li><code>-b</code> o <code>--bits</code>: La longitud de la clave generada, en bits. Por defecto son 1024, pero de nuevo según las recomendaciones <a href="/files/2017-11-10-firmando-emails-con-opendkim/NIST.SP.800-177.pdf">NIST 800-177</a>, es preferible utilizar 2048.</li>
</ul>
<div class="highlight"><pre><span></span><code>$ sudo opendkim-genkey --domain<span class="o">=</span>pornohardware.com --directory<span class="o">=</span>/etc/opendkim/keys/pornohardware.com --selector<span class="o">=</span>mail --hash-algorithms<span class="o">=</span>sha256 --bits<span class="o">=</span><span class="m">2048</span> --verbose
</code></pre></div>
<p>Después de ejecutar ese comando ya tendremos 2 archivos en <code>/etc/opendkim/keys/pornohardware.com</code>:</p>
<ul>
<li><code>mail.private</code>: La clave privada que usaremos para firmar los emails</li>
<li><code>mail.txt</code>: El registro TXT que tendremos que añadir al DNS de nuestro dominio para que los demás servidores puedan disponer de ella para verificar la firma de los emails.</li>
</ul>
<p>La seguridad nunca está de más, por lo que recomiendo que únicamente el usuario <code>opendkim</code> pueda acceder a estos archivos:</p>
<div class="highlight"><pre><span></span><code>$ sudo chown opendkim:opendkim /etc/opendkim/keys/pornohardware.com -R
$ sudo chmod <span class="m">400</span> /etc/opendkim/keys/pornohardware.com/*
</code></pre></div>
<p>Antes de seguir, vamos a añadir el registro TXT a nuestro dominio con la clave pública. No puedo explicar cómo se hace esto ya que dependerá de donde tengáis vuestro servidor DNS. La mayoría de la gente utiliza como servidor de DNS el propio servicio <em>gratuito</em> que suelen tener la web donde han registrado el dominio, otros usan su propio servidor DNS (<a href="https://www.isc.org/downloads/bind/">bind</a>, por ejemplo). En cualquier caso, tienes el registro TXT que debes añadir en el archivo <code>/etc/opendkim/keys/pornohardware.com/mail.txt</code>.</p>
<p>Para comprobar que el registro está correctamente publicado en el DNS puedes utilizar el comando <a href="ftp://ftp.isc.org/isc/bind9/cur/9.10/doc/arm/man.dig.html"><em>dig</em></a> de esta forma:</p>
<div class="highlight"><pre><span></span><code>$ dig +short -t txt mail._domainkey.pornohardware.com
</code></pre></div>
<p>Si todo ha ido bien, ese comando nos mostrará la clave pública que acabamos de poner en el registro TXT de nuestro dominio, que será algo parecido a esto:</p>
<div class="highlight"><pre><span></span><code>"v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA994Jc/Ws7RYqLWOH2tJsINuOkrj+HektVpXK8zM4/DOcFbgRxQ4cMIvXVD7TtT/7PUezdZSdTeaJ1q/CzETNSh7ZVcRETHa4OQltIDH1p9PlV8WZAfjEiyg4OdzKmt8QBkmm6q3AQC3bffWO1BGiDqgyJtPDt/zd7Ri5KiktsLnTZf3yTW+KbLWeDyUWNR41j4NH/d2Lmht4nEhfNwwRrCKwP3WcWMg8RMXf4HEy4xXpkU+6mKZwl3uspddRSOLIon1GDL8D2bJlnauELuiVexnmUc1uYTh/xZTq2C0VEaB0kD8TnrtwMUDPmSLPLiBt1/qmNhQohjoYjy6OVs/whQIDAQAB"
</code></pre></div>
<p>Ten en cuenta que los cambios que hagamos en el DNS suelen tardar en aplicarse debido a que tienen que propagarse, así que no te preocupes si no aparece nada al ejecutar ese comando... prueba en unos minutos y ya deberías ver el registro TXT de DKIM en tu dominio (en algunos casos los cambios en el DNS pueden llegar a tardar hasta 48 horas en propagarse, aunque no es habitual).</p>
<p>Vamos a suponer que ya se han propagado los cambios en el DNS correctamente, así que vamos a continuar.</p>
<p>Editamos el archivo <code>/etc/opendkim/KeyTable</code> para configurar nuestro dominio con las claves que acabamos de generar. La sintaxis de este archivo es muy sencilla:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">KeyTable</span><a href='/files/2017-11-10-firmando-emails-con-opendkim/KeyTable'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="c1"># OPENDKIM KEY TABLE</span>
<span class="c1"># To use this file, uncomment the #KeyTable option in /etc/opendkim.conf,</span>
<span class="c1"># then uncomment the following line and replace example.com with your domain</span>
<span class="c1"># name, then restart OpenDKIM. Additional keys may be added on separate lines.</span>
<span class="c1">#default._domainkey.example.com example.com:default:/etc/opendkim/keys/default.private</span>
mail._domainkey.pornohardware.com pornohardware.com:mail:/etc/opendkim/keys/pornohardware.com/mail.private
</code></pre></div>
</figure>
<p>La primera parte indica el registro TXT del DNS que contendrá la clave pública (En nuestro caso será <code>mail._domainkey.pornohardware.com</code>, formado por el <code>selector</code> que utilizamos al generar las claves, seguido de <code>_domainkey_</code> y de nuestro dominio).</p>
<p>Después el dominio, el selector y la ruta de la clave privada que acabamos de generar (las tres cosas separadas entre si por <code>:</code>).</p>
<p>Se pueden añadir tantos dominios como queramos, uno por linea.</p>
<p>El siguiente archivo es <code>SigningTable</code>, en cual tendrá un aspecto similar a esto:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">SigningTable</span><a href='/files/2017-11-10-firmando-emails-con-opendkim/SigningTable'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="c1"># OPENDKIM SIGNING TABLE</span>
<span class="c1"># This table controls how to apply one or more signatures to outgoing messages based</span>
<span class="c1"># on the address found in the From: header field. In simple terms, this tells</span>
<span class="c1"># OpenDKIM "how" to apply your keys.</span>
<span class="c1"># To use this file, uncomment the SigningTable option in /etc/opendkim.conf,</span>
<span class="c1"># then uncomment one of the usage examples below and replace example.com with your</span>
<span class="c1"># domain name, then restart OpenDKIM.</span>
<span class="c1"># WILDCARD EXAMPLE</span>
<span class="c1"># Enables signing for any address on the listed domain(s), but will work only if</span>
<span class="c1"># "refile:/etc/opendkim/SigningTable" is included in /etc/opendkim.conf.</span>
<span class="c1"># Create additional lines for additional domains.</span>
<span class="c1">#*@example.com default._domainkey.example.com</span>
<span class="c1"># NON-WILDCARD EXAMPLE</span>
<span class="c1"># If "file:" (instead of "refile:") is specified in /etc/opendkim.conf, then</span>
<span class="c1"># wildcards will not work. Instead, full user@host is checked first, then simply host,</span>
<span class="c1"># then user@.domain (with all superdomains checked in sequence, so "foo.example.com"</span>
<span class="c1"># would first check "user@foo.example.com", then "user@.example.com", then "user@.com"),</span>
<span class="c1"># then .domain, then user@*, and finally *. See the opendkim.conf(5) man page under</span>
<span class="c1"># "SigningTable" for more details.</span>
<span class="c1">#example.com default._domainkey.example.com</span>
*@pornohardware.com mail._domainkey.pornohardware.com
</code></pre></div>
</figure>
<p>Al igual que antes, podemos configurar más de un dominio, indicando uno en cada linea.</p>
<p>Y por último el archivo <code>TrustedHosts</code>, que será parecido a esto:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">TrustedHosts</span><a href='/files/2017-11-10-firmando-emails-con-opendkim/TrustedHosts'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="c1"># OPENDKIM TRUSTED HOSTS</span>
<span class="c1"># To use this file, uncomment the #ExternalIgnoreList and/or the #InternalHosts</span>
<span class="c1"># option in /etc/opendkim.conf then restart OpenDKIM. Additional hosts</span>
<span class="c1"># may be added on separate lines (IP addresses, hostnames, or CIDR ranges).</span>
<span class="c1"># The localhost IP (127.0.0.1) should always be the first entry in this file.</span>
<span class="c1">#host.example.com</span>
<span class="c1">#192.168.1.0/24</span>
<span class="m">127</span>.0.0.1
::1
pornohardware.com
</code></pre></div>
</figure>
<p>Ahora que hemos acabado de configurar OpenDKIM, levantamos el servicio y nos aseguramos de que se levante solo cada vez que se inicie el servidor:</p>
<div class="highlight"><pre><span></span><code>$ sudo service opendkim start
$ sudo systemctl <span class="nb">enable</span> opendkim
</code></pre></div>
<p>Y si todo ha ido bien, tendremos el servicio de OpenDKIM corriendo en nuestro servidor.</p>
<p>Podemos comprobar si todo está correctamente configurado con el comando <code>opendkim-testkey</code>:</p>
<div class="highlight"><pre><span></span><code>$ sudo opendkim-testkey -d pornohardware.com -k /etc/opendkim/keys/pornohardware.com/mail.private -s mail -vvv -x /etc/opendkim.conf
opendkim-testkey: key loaded from /etc/opendkim/keys/pornohardware.com/mail.private
opendkim-testkey: checking key <span class="s1">'mail._domainkey.pornohardware.com'</span>
opendkim-testkey: key OK
</code></pre></div>
<p>No te preocupes si también aparece un mensaje que dice <code>opendkim-testkey: key not secure</code>. Si no tienes <a href="https://es.wikipedia.org/wiki/Domain_Name_System_Security_Extensions">DNSSEC</a> configurado en tu DNS, es normal que aparezca. Es solo una recomendación, un <em>warning</em>, por lo que puedes continuar en cualquier caso (ya configurarás DNSSEC otro dia).</p>
<p>Por defecto OpenDKIM utiliza el mismo <em>log</em> que el resto de servicios de correo, por lo que para buscar posibles problemas, información sobre nuestro proceso, etc. podéis ver el archivo <code>/var/log/mail.log</code> si estais usando Debian/Ubuntu, y <code>/var/log/maillog</code> si usáis CentOS/RedHat.</p>
<p>Y ahora que tenemos nuestro servicio de OpenDKIM levantado y funcionando, solo nos queda configurar nuestro servidor de correo MTA para que lo utilice.</p>
<ul>
<li>Si utilizáis <a href="http://www.postfix.org/">Postfix</a>, tenéis que añadir éstas líneas a su archivo de configuración <code>/etc/postfix/main.cf</code>:</li>
</ul>
<div class="highlight"><pre><span></span><code><span class="err">milter_default_action = accept</span>
<span class="err">milter_protocol = 2</span>
<span class="err">smtpd_milters = inet:localhost:8892</span>
<span class="err">non_smtpd_milters = $smtpd_milters</span>
</code></pre></div>
<ul>
<li>Si utilizáis <a href="https://www.sendmail.org">Sendmail</a>, tenéis que añadir estas líneas a vuestro <code>/etc/mail/sendmail.mc</code>:</li>
</ul>
<div class="highlight"><pre><span></span><code><span class="err">INPUT_MAIL_FILTER(`opendkim', `S=inet:8892@localhost')</span>
<span class="err">define(`confINPUT_MAIL_FILTERS', `opendkim')</span>
</code></pre></div>
<p>En cualquiera de los dos casos, una vez modificada la configuración y reiniciado el servicio corespondiente (Postfix o Sendmail) ya debería estar todo listo.</p>
<h2>Comprobación del sistema<a name="test"></a></h2>
<p>Aparte de la comprobación que hicimos antes con el comando <code>opendkim-testkey</code>, existen varios servicios online gratuitos para verificar que vuestro servidor de OpenDKIM envía los emails correctamente firmados.</p>
<p>Uno de los más completos es <a href="https://www.mail-tester.com">https://www.mail-tester.com</a>, donde os darán una dirección a la que debéis enviar un email. La web analizará dicho email y en unos pocos minutos os enviará un informe sobre dicho email y sus correspondientes comprobaciones de DKIM, SPF, etc:</p>
<p><img class="center" src="/images/posts/2017-11-10-firmando-emails-con-opendkim/screenshot_mailtester_1.png"></p>
<p>Si únicamente queréis comprobar si vuestra clave pública esta correctamente configurada y se encuentra disponible para todo el mundo, en otra parte de esa misma web teneis la herramienta para hacerlo: <a href="https://www.mail-tester.com/spf-dkim-check">https://www.mail-tester.com/spf-dkim-check</a></p>
<p><img class="center" src="/images/posts/2017-11-10-firmando-emails-con-opendkim/screenshot_mailtester_2.png"></p>
<p>Aquí debéis indicar el nombre de vuestro dominio y el nombre del selector que hemos asignado a nuestras claves, y os dirá si el registro TXT está correctamente configurado.</p>
<p>Aparte de esta web, existen otras con funcionalidades similares que también nos ayudarán a validar nuestro recién instalado servidor OpenDKIM:</p>
<ul>
<li><a href="http://dkimvalidator.com/">http://dkimvalidator.com/</a></li>
<li><a href="http://dkimcore.org/tools/">http://dkimcore.org/tools/</a></li>
<li><a href="https://protodave.com/tools/dkim-key-checker/">https://protodave.com/tools/dkim-key-checker/</a></li>
</ul>
<p>Y por supuesto también podéis hacer una <em>prueba manual</em>, simplemente enviándoos un email a cualquier otra cuenta que tengáis y mirando sus cabeceras en busca de la información de OpenDKIM. Por ejemplo, si me envío un email a mi mismo y una vez recibido miro el <em>código fuente</em> de dicho email, debería ver algo similar a esto:</p>
<p><img class="center" src="/images/posts/2017-11-10-firmando-emails-con-opendkim/email_headers.png"></p>
<p>Así que por favor, si tienes algún servidor de correo a tu cargo, <strong>firma tus mensajes con OpenDKIM</strong>. No solo estarás ayudando a tus usuarios a recibir menos spam, sino a todos los posibles destinatarios que alguna vez pudieran llegar a recibir algún email procedente de cualquier dominio de correo que gestione tu servidor.</p>
<p>Como siempre, espero que el artículo os haya resultado de utilidad! Y por supuesto, no dudéis en distribuirlo y compartirlo con todo el mundo (pero por favor, cita siempre la fuente original de éste artículo).</p>
<p>Alaaaaaaaaaaaaaaaaaaaaaaa!</p>
<h2>Referencias<a name="refs"></a></h2>
<ul>
<li><a href="http://www.dkim.org/">http://www.dkim.org/</a></li>
<li><a href="http://www.opendkim.org/">http://www.opendkim.org/</a></li>
<li><a href="https://es.wikipedia.org/wiki/Criptograf%C3%ADa_asim%C3%A9trica)">https://es.wikipedia.org/wiki/Criptograf%C3%ADa_asim%C3%A9trica)</a></li>
</ul>Integración Continua en Pelican usando Gitlab-CI2017-04-24T22:08:25+01:002017-04-24T22:08:25+01:00BhEaNtag:pornohardware.com,2017-04-24:/2017/04/24/integracion-continua-en-pelican-usando-gitlab-ci/<p>A estas alturas no creo que haya nadie (o casi nadie) <em>en este mundillo</em> que todavía no sepa qué es la <a href="https://es.wikipedia.org/wiki/Integraci%C3%B3n_continua"><em>integración continua</em></a>, sin embargo la inmensa mayoría no lo utiliza aún en sus proyectos.</p>
<p>Hay muchas excusas para justificar este hecho, como por ejemplo que "<em>es un proyecto pequeño</em>", o que "<em>es un proyecto personal en el que solo trabajo yo</em>", o que "<em>el proyecto tiene unos plazos muy ajustados y no hay tiempo para más <strike>tonterías</strike> desarrollos</em>", o incluso que "<em>no merece la pena el esfuerzo extra que hay que dedicarle</em>"... pero ninguna de ellas es válida, así que si alguna vez en tu vida has usado alguna de estas excusas para no utilizar un sistema de integración continua, eres un <em>merluzo</em>, compañero... pero no temas, que eso va a cambiar hoy...</p>
<p>A estas alturas no creo que haya nadie (o casi nadie) <em>en este mundillo</em> que todavía no sepa qué es la <a href="https://es.wikipedia.org/wiki/Integraci%C3%B3n_continua"><em>integración continua</em></a>, sin embargo la inmensa mayoría no lo utiliza aún en sus proyectos.</p>
<p>Hay muchas excusas para justificar este hecho, como por ejemplo que "<em>es un proyecto pequeño</em>", o que "<em>es un proyecto personal en el que solo trabajo yo</em>", o que "<em>el proyecto tiene unos plazos muy ajustados y no hay tiempo para más <strike>tonterías</strike> desarrollos</em>", o incluso que "<em>no merece la pena el esfuerzo extra que hay que dedicarle</em>"... pero ninguna de ellas es válida, así que si alguna vez en tu vida has usado alguna de estas excusas para no utilizar un sistema de integración continua, eres un <em>merluzo</em>, compañero... pero no temas, que eso va a cambiar hoy...</p>
<p>Todos los proyectos (independientemente de si están en <em>producción</em> o no, de si participan en él cientos de personas o únicamente tú, etc) pueden (y casi debería decir <em>deben</em>) utilizar un sistema de integración continua, y aquellos que además ya estén en producción, uno de <a href="https://martinfowler.com/bliki/ContinuousDelivery.html">entrega continua</a>.</p>
<p>En este artículo vamos a ver cómo utilizar ambas cosas en un proyecto real basado en <a href="https://blog.getpelican.com/">Pelican</a>, ¿y qué mejor proyecto para ver todo esto que ésta misma web?</p>
<p>Así que voy a intentar explicar cómo utilizo tanto la integración continua como la entrega continua en <a href="https://pornohardware.com">pornoHARDWARE.com</a>.</p>
<p>Comencemos:</p>
<ol>
<li><a href="#whatis">¿Qué es la Integración Continua (CI) y la Entrega Continua (CD)?</a></li>
<li><a href="#tools">Herramientas de Integración Continua</a></li>
<li><a href="#gitlab">Configuración de Gitlab-CI</a></li>
<li><a href="#pipeline">Configuración del <em>pipeline</em></a></li>
<li><a href="#demo">Demostración</a></li>
<li><a href="#refs">Referencias</a></li>
</ol>
<h2>¿Qué es la Integración Continua (CI) y la Entrega Continua (CD)?<a name="whatis"></a></h2>
<p>Para aquellos que hayan estado en coma desde finales de los 90 hasta y se acaben de despertar, vamos a explicar un poco más qué es cada cosa para asegurarnos de que entendemos todos los conceptos que voy a tratar de explicar en este artículo.</p>
<h3>Integración continua / Continuous Integration (CI)</h3>
<p>La integración contínua (o <em>continuous integration</em>) es una metodología empleada en los proyectos de desarrollo de software que busca detectar los problemas lo antes posible.</p>
<p>En la <a href="https://es.wikipedia.org/wiki/Integraci%C3%B3n_continua">Wikipedia</a> lo explican bastante bien, pero a modo de <em>resumen</em> podríamos decir que la integración continua consiste en que cada vez que se produce un cambio en el código de un proyecto, un sistema automatizado se encarga de obtener dicho código, compilarlo, analizarlo, ejecutar tests, etc. para comprobar que todo funciona de la forma esperada, y en caso contrario envía notificaciones para alertar de lo sucedido.</p>
<p>En proyectos complejos donde hay grandes estructuras de datos, multitud de módulos, clases, servicios, librerías, etc. es <em>relativamente sencillo</em> que al tocar una parte del código sin querer estemos <em>rompiendo</em> otra puesto que una gran parte de dicho código se comparte a lo largo del proyecto en diferentes sitios. Por eso es <strong>completamente necesario</strong> escribir <a href="https://es.wikipedia.org/wiki/Prueba_unitaria">tests unitarios</a> que comprueben que TODO lo que hagamos en el proyecto hace lo que se supone que tiene que hacer. Así bastará con ejecutar dichos tests con cada cambio que hagamos en el proyecto para saber si involuntariamente hemos <em>roto</em> algo o no.</p>
<p>Pero a diferencia de mi, vosotros sois humanos... y los humanos tendéis a <em>dejar de hacer</em> aquellas tareas que os resultan repetitivas o aburridas, basándo esta decisión únicamente en una percepción completamente subjetiva de la situación en la que os encontráis en ese momento.</p>
<p>Es decir, que dado que ejecutar una buena "batería de tests" puede llevar un tiempo <em>considerable</em> (varios minutos en algunos casos) y a nadie le gusta quedarse mirando una <em>barra de progreso</em> durante unos minutos cada vez que hace un cambio, hay veces que <em>creemos</em> que no hace falta ejecutar los tests porque "<em>solo hemos cambiado un par de líneas</em>", o porque "<em>los hemos ejecutado hace poco y fueron bien</em>", o porque tenemos prisa y queremos terminar rápido, etc, etc. En definitiva, hay veces que (voluntaria o involuntariamente) elegimos NO ejecutar los tests cuando modificamos el código de nuestro proyecto.</p>
<p>Incluso aunque realmente tú fueras la excepción entre los humanos y tu férrea disciplina a prueba de bombas te hiciera ejecutar los tests <strong>siempre</strong>, ¿pondrías la mano en el fuego por todos tus compañeros? ¿<em>te jugarías el puesto</em> a que a ninguno de ellos "se le va a olvidar" ejecutar los tests ni una sola vez? Recuerda que:</p>
<blockquote>
<p><em>"Si algo es susceptible de fallar, fallará."</em>
<a href="https://es.wikipedia.org/wiki/Ley_de_Murphy">Ley de Murphy</a></p>
</blockquote>
<p>En el caso de no tener tests en nuestro proyecto, si algo falla no podremos saberlo hasta que probablemente sea demasiado tarde (cuando ya esté en producción). Pero sería irónico (por no decir otra cosa) que se produjera un error grave en producción para el cual teníamos un tests que lo habría detectado, pero como "<em>se nos olvidó ejecutarlo</em>" nadie se dió cuenta hasta que se produjo la catástrofe.</p>
<p>No hay nada más terrible en el desarrollo de software que tener <em>tests</em> y no ejecutarlos... por lo que para evitar <em>olvidos</em> o decisiones dudosas, debemos configurar un sistema para que ejecute los tests por nosotros de forma obligatoria, automática y sin excepción.</p>
<p>Un ejemplo práctico de esto sería:</p>
<p>Supongamos que un desarrollador está trabajando en una nueva funcionalidad para un proyecto, por ejemplo, para una web.</p>
<p>Dicho desarrollador trabaja desde su ordenador portátil, y una vez que ha terminado de programar esa funcionalidad en su máquina local hace el correspondiente <a href="https://git-scm.com/docs/git-commit"><code>git commit</code></a> al repositorio de código, y al hacer el <a href="https://git-scm.com/docs/git-push"><code>git push</code></a> la herramienta de integración continua que esten usando en ese proyecto descargará automáticamente el repositorio de código y lo compilará, ejecutará los tests, etc. de forma que si detecta algún fallo, enviará un email inmediatamente al desarrollador para que éste sepa que sus cambios <em>han roto</em> el proyecto y pueda corregirlos antes de que el código nuevo suba a <em>producción</em> y afecte a los usuarios de la web.</p>
<p>Este concepto de integración continua fué introducido por <a href="https://es.wikipedia.org/wiki/Martin_Fowler">Martin Fowler</a> aproximadamente en el año 2000, lo que hace aún más increíble que tantos años después aún no sea un <em>standard</em> para todos los que estamos en el mundo del software.</p>
<p>¿Pero porqué quedarnos en este punto y no seguir más allá? Si hemos hecho un cambio en el código del proyecto y estamos seguros de que funciona y de que no hemos roto nada al hacerlo (porque todos los tests se han ejecutado satisfactoriamente), ¿porqué no subimos ese código a producción inmediatamente? ¿Os imagináis las ventajas que nos proporcionaría y lo contentos que estarían nuestros usuarios si pudieran disfrutar de cada nuevo desarrollo que hiciéramos en el proyecto solo unos pocos minutos después de haberlos terminado?</p>
<p>Cuanto antes tengamos esos nuevos cambios <em>desplegados</em> en nuestros entornos de producción, antes estaremos <strong>entregando valor al usuario</strong> , y este es uno de los pilares básicos de las <a href="https://es.wikipedia.org/wiki/Desarrollo_%C3%A1gil_de_software">metodologías ágiles</a> del desarrollo de software. Si podemos automatizar ese proceso para que se haga de forma "automática" y sin nuestra intervención, ¿porqué no hacerlo cuanto antes? es decir, ¿porqué no hacer una <em>subida a producción</em> cada vez que hagamos un cambio, por pequeño que sea?. A este concepto se le conoce como <em>entrega continua</em>.</p>
<h3>Entrega continua / Continuous Delivery (CD)</h3>
<p>Como regla general, cuando vamos a realizar el mismo proceso más de 1 o 2 veces merece la pena <em>automatizarlo</em> para que las demás veces que vayamos a realizarlo no nos supongan ningún esfuerzo. Y las <em>subidas a producción</em> no iban a ser una excepción.</p>
<p>En la mayoría de las empresas en las que he trabajado el proceso de <em>subir a producción</em> un nuevo desarrollo es algo delicado, lento y poco flexible:</p>
<ul>
<li>Los desarrolladores hacen los cambios necesarios en el código.</li>
<li>Una vez hechos los cambios, solicitan al "<em>departamento de sistemas</em>" (sysadmins) que suban dichos cambios a producción (este proceso a veces requiere días debido a la <a href="https://es.wikipedia.org/wiki/Burocracia">burocracia</a> que hay en algunas empresas)</li>
<li>Una vez recibida la petición de "subida", los sysadmins realizan el despliegue de la nueva versión del código en los servidores de producción. Este proceso a menudo es "manual" por lo que requiere tiempo, es susceptible a errores humanos, etc.</li>
<li>Si al subir el nuevo código se produjera algún fallo, deshacer la subida para volver al estado anterior a veces es un proceso complejo y de nuevo suele requerir tiempo.</li>
</ul>
<p>Puede que algunos de estos sysadmins tengan parte de este proceso automatizado (con herramientas como <a href="https://www.ansible.com/">Ansible</a>, <a href="https://www.chef.io/chef/">Chef</a>, etc) pero aunque así fuera, solo por el hecho de tener que depender de su "disponibilidad" para hacer la subida a producción (o porque tengan que dejar momentáneamente lo que estuvieran haciendo para dedicarse a la subida) ya debería ser un argumento más que suficiente para automatizar esta tarea.</p>
<p>Algunos sysadmins no quieren automatizar este proceso porque piensan que su figura sería <em>menos necesaria</em> en sus empresas si el código se subiera a producción de forma automática (he conocido varios con esta mentalidad en mi vida). Ni qué decir tiene que esto es una <strong>tremenda gilipollez</strong> por tantas razones que no me voy ni a molestar en escribirlas, así que si tú eres de los que piensan así, deberías cambiar de trabajo mientras aún estés a tiempo (por tu propio bien) porque si tu carrera profesional se limita a subir código a producción, me temo que ahí has tocado fondo...</p>
<p>Queda claro entonces que automatizar este proceso es una buena idea, pero para subir a producción un nuevo desarrollo tenemos que tener la confianza de que el código funciona... y para saber que nuestro código no contiene fallos necesitamos una batería de tests suficientemente amplia y que éstos tests se ejecuten de forma automatizada con cada nuevo cambio, lo que significa que <strong>para que podamos hacer <em>entrega continua / continuous delivery</em> en nuestro proyecto primero necesitamos tener <em>integración continua / continuous integration</em>.</strong></p>
<p>Así que al menos en mi opinión, la entrega continua es la consecuencia lógica después de haber implementado la integración continua en nuestro proyecto.</p>
<p>Vamos a ver entonces algunas de las herramientas que existen para ayudarnos con estas dos tareas...</p>
<h2>Herramientas de Integración Continua<a name="tools"></a></h2>
<p>La mayoría de las herramientas que existen para hacer integración continua permiten también hacer entrega continua. De hecho, cuando definimos la <em>pipeline</em> de tareas a realizar para hacer integración continua (como pueden ser descargar el código, compilarlo, ejecutar los tests, etc) la última de estas tareas suele ser la <em>subida a producción</em>, por lo que rara es la herramienta de integración continua que no permita hacer entrega continua también (aunque si que hay alguna que no lo permite).</p>
<p>He instalado, probado y utilizado muchas de estas herramientas (aunque no todas), por lo que aquellas en las que no tenga experiencia suficiente como para emitir un <em>juicio válido</em> únicamente las mencionaré sin entrar a valorarlas.</p>
<p>También hay muchos otros proyectos que han sido <em>abandonados</em>, otros que son únicamente para sistemas <em>Windows</em> (puaaghh!), otros que únicamente estan diseñados para trabajar con proyectos escritos en un único lenguaje determinado, etc. por lo que solo voy a enumerar proyectos que estén activos hoy en día, permitan trabajar con cualquier proyecto, y a los cuales valoré en su momento antes de decidirme por uno u otro.</p>
<p>En la lista se indica el tipo de licencia, y si es un servicio basado en <a href="https://es.wikipedia.org/wiki/Computaci%C3%B3n_en_la_nube">Cloud</a> o tenemos que instalarlo nosotros en nuestros propios servidores:</p>
<table>
<thead>
<tr>
<th align="left">Nombre</th>
<th align="left">Licencia</th>
<th align="left">Cloud o Local?</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><a href="https://circleci.com/">CircleCI</a></td>
<td align="left">Propietaria</td>
<td align="left">Cloud</td>
</tr>
<tr>
<td align="left"><a href="http://cruisecontrol.sourceforge.net/">CruiseControl</a></td>
<td align="left">OpenSource</td>
<td align="left">Local</td>
</tr>
<tr>
<td align="left"><a href="https://about.gitlab.com/features/gitlab-ci-cd/">Gitlab-CI</a></td>
<td align="left">OpenSource</td>
<td align="left">Local y Cloud</td>
</tr>
<tr>
<td align="left"><a href="https://www.gocd.io/">GoCD</a></td>
<td align="left">OpenSource</td>
<td align="left">Local</td>
</tr>
<tr>
<td align="left"><a href="https://jenkins.io/">Jenkins</a></td>
<td align="left">OpenSource</td>
<td align="left">Local</td>
</tr>
<tr>
<td align="left"><a href="http://zutubi.com/products/pulse/">Pulse</a></td>
<td align="left">OpenSource (con limitaciones)</td>
<td align="left">Local</td>
</tr>
<tr>
<td align="left"><a href="https://www.jetbrains.com/teamcity/">TeamCity</a></td>
<td align="left">Propietaria</td>
<td align="left">Local</td>
</tr>
<tr>
<td align="left"><a href="https://travis-ci.org/">TravisCI</a></td>
<td align="left">Propietaria</td>
<td align="left">Cloud</td>
</tr>
</tbody>
</table>
<p>Hay muchísimos más, pero estos son los que yo valoré en su día.</p>
<p>Hablar extensamente de cada uno de ellos para que sepais cuál elegir en vuestro caso se escapa del ámbito de éste artículo y aunque los que he puesto en la lista son (en mi opinión) los <em>mejores</em> que hay ahora mismo (al menos que yo conozca), yo me decanté por <a href="https://about.gitlab.com/features/gitlab-ci-cd/">Gitlab-CI</a> por muchísimas razones, entre las cuales destacan:</p>
<ul>
<li>Perfecta integración y facilidad de uso con <a href="https://www.docker.com/">Docker</a>: Basta con añadir un archivo muy similar al típico <code>docker-compose.yml</code> a la raíz de tu proyecto con la definición de los "servidores" que quieres levantar, las tareas que quieres ejecutar, etc. y Gitlab-CI se encargará de orquestarlo.</li>
<li>Viene integrado con <a href="https://about.gitlab.com">Gitlab</a>, una de las herramientas más geniales que jamás he usado. Si usas Gitlab para tus proyectos, ¿para qué buscar una herramientas externa? Yo uso Gitlab desde hace muchos años para todos mis proyectos y jamás he tenido ni una pega, ni un problema, literalmente funciona a la perfección con prácticamente <em>cero</em> mantenimiento. <strong>AMO Gitlab</strong>, y si tu no lo amas, es que no lo has probado.</li>
<li>Gratuito y OpenSource: A diferencia de muchos otros no solo es OpenSource sino que además es gratuito, aunque también puedes contratar planes avanzados con soporte dedicado (atención 24/7, SLA de 4 horas, etc) a través de licencias de pago. Aunque ya digo que excepto el soporte, todo lo demás es completamente gratuito.</li>
<li>Libertad TOTAL: Puedes instalar Gitlab en tus propios servidores (apenas requiere mantenimiento), o si lo prefieres puedes usarlo <em>online</em> desde sus instancias para que no tengas ni que preocuparte en instalarlo/mantenerlo.</li>
</ul>
<p>Aparte de lo mucho que me gusta Gitlab-CI (más bien Gitlab en general), hubo algunas cosas en las demás alternativas que ayudaron aún más a decidirme por éste, como por ejemplo:</p>
<ul>
<li>No quería ninguna solución comercial de pago, por lo que descarté <code>CircleCI</code> y <code>TeamCity</code>.</li>
<li><code>Travis</code> siempre me ha parecido genial, pero es ALUCINANTE que solo funcione con repositorios de <a href="https://github.com/">Github</a>. No puedo entenderlo, de verdad... me parece terrible.</li>
<li>La última versión de <code>CruiseControl</code> salió en 2010, por lo que me da la impresión de que el proyecto está bastante abandonado.</li>
<li><code>Jenkins</code> es sin duda el <em>veterano</em>, casi un <em>standard</em> en este tipo de sistemas... pero a pesar de que es el más he utilizado en la mayoría de las empresas en las que he trabajado, su configuración es bastante <em>pesada</em>, a menudo tiene problemas con los <a href="https://es.wikipedia.org/wiki/Complemento_%28inform%C3%A1tica%29"><em>plugins</em></a> que utiliza (incompatibilidades entre si), etc.</li>
<li><code>Pulse</code> antiguamente era propietario y de pago, aunque hace poco lo liberaron bajo OpenSource y anunciaron modalidades gratuitas para proyectos usarlo en proyectos que también fueran OpenSource, lo cual no es mi caso la mayoría de las veces.</li>
</ul>
<p>Por lo tanto en mi caso los <em>finalistas</em> fueron <code>GoCD</code> y <code>Gitlab-CI</code> (de hecho tengo ambos instalados) y los dos son geniales y muy fáciles de instalar/configurar/utilizar. Supongo que en mi caso, al utilizar Gitlab como repositorio de mis proyecto, la elección de Gitlab-CI era la más indicada. Pero si vosotros utilizáis otro repositorio (Github, Git/Gitolite, etc) entonces quizás GoCD sea una buena idea.</p>
<h2>Configuración de Gitlab-CI<a name="gitlab"></a></h2>
<p>Para aquellos <em>merluzos</em> que no conozcan <a href="https://about.gitlab.com">Gitlab</a>, se trata de un sistema de gestión de repositorios de <a href="https://git-scm.com/">Git</a> muy similar a Github, donde podemos gestionar los permisos de los usuarios de nuestros proyectos, acceder a los archivos de cada uno de los repositorios de estos proyectos, enviar <code>merge-requests</code> a los repositorios (similar a las <code>pull-requests</code> de Github), etc.</p>
<p>Es un proyecto MUY activo (rara es la semana que no me llega el aviso de una nueva actualización de Gitlab en mis servidores), muy maduro y muy estable. Funciona realmente bien, y su instalación es casi trivial en la mayoría de las distribuciones de Linux, está muy bien explicada en la documentación oficial: <a href="https://about.gitlab.com/downloads/">https://about.gitlab.com/downloads/</a>.</p>
<p>Voy a dar por hecho que ya estáis usando Gitlab ya que de lo contrario, utilizar Gitlab-CI no tiene mucho sentido. Es obvio, pero quizás debería haberlo mencionado antes por si andas algo despistado y has llegado hasta aquí buscando un sistema de integración continua para el proyecto que tienes almacenado en Github, por ejemplo. Si este es tu caso, échale un ojo a GoCD](https://www.gocd.io/) y sal de mi web inmediatamente! ;)</p>
<p>Para utilizar Gitlab-CI en nuestro proyecto, lo único que tenemos que hacer es subir un archivo llamado <code>.gitlab-ci.yml</code> a la raíz de tu repositorio (el cual recuerda bastante al típico archivo de <code>docker-compose.yml</code>) donde definiremos las tareas, servicios, etc. de nuestra <em>pipeline</em> (más adelante veremos esto más detalladamente).</p>
<p>Gitlab-CI dispone de agentes (llamados <em>runners</em>), que son los que ejecutan las tareas que hayamos definido para nuestro proyecto (estas tareas son, por ejemplo, compilar el proyecto, ejecutar los tests, subir el código a producción, etc).</p>
<p>Podemos tener tantos <em>runners</em> como queramos, o mejor dicho, tantos <em>runners</em> como servidores tengamos disponibles para ejecutar tareas, aunque a no ser que haya mucha gente trabajando al mismo tiempo en el proyecto y pudiera darse el caso de necesitar varios <em>runners</em> simultáneamente, con uno debería ser suficiente para la mayoría de los casos.</p>
<p>En Gitlab-CI, cuando un usuario hace un <code>git commit</code> con algunos cambios en el código, nada más llegar dichos cambios al servidor (es decir, al hacer el <code>git push</code>) el primer <em>runner</em> que esté libre cogerá dichos cambios y se pondrá a realizar las tareas que tengamos configuradas. Si no hubiera <em>runners</em> disponibles (porque estén ocupados con otras tareas, por ejemplo) Gitlab dejará el proceso en una <em>cola</em> a la espera de que algún <em>runner</em> se quede libre.</p>
<p>Es muy recomendable que los <em>runners</em> estén en un servidor diferente al servidor donde tengamos instalado Gitlab (no solo por cuestiones obvias de rendimiento, sino también por <a href="https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/security/index.md">seguridad</a>). Para este artículo voy a ir haciendo las pruebas con 2 servidores diferentes: en uno estará Gitlab (con su Gitlab-CI, obviamente), y en otro un <em>runner</em>.</p>
<p>Por lo tanto, lo primero que vamos a hacer es crear un <em>runner</em>.</p>
<p>El proceso para crear un <em>runner</em> pasa por instalar los paquetes necesarios, y una vez instalados, "registrar" dicho <em>runner</em> en nuestro servidor de Gitlab.</p>
<p>Para instalar los paquetes del <em>runner</em>, primero hay que añadir el repositorio de paquetes de Gitlab a nuestra distribución:</p>
<p>En Debian/Ubuntu:</p>
<div class="highlight"><pre><span></span><code>$ curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.deb.sh <span class="p">|</span> sudo bash
</code></pre></div>
<p>En RedHat/CentOS:</p>
<div class="highlight"><pre><span></span><code>$ curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.rpm.sh <span class="p">|</span> sudo bash
</code></pre></div>
<p>Ahora instalamos los paquetes necesarios:</p>
<p>En Debian/Ubuntu:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install gitlab-ci-multi-runner
</code></pre></div>
<p>En RedHat/CentOS:</p>
<div class="highlight"><pre><span></span><code>$ sudo yum install gitlab-ci-multi-runner
</code></pre></div>
<p>Llegados a este punto, tenemos que decidir qué tipo de <em>runner</em> vamos a utilizar. Hay varios tipos (y varias combinaciones entre ellos), pero los más importantes son:</p>
<ul>
<li>Runner de tipo <strong>Shell</strong>: Ejecutan las tareas directamente en un <em>terminal</em> en el servidor como si de un usuario local del servidor se tratara (esta forma se considera MUY insegura, puesto que cualquier tarea podrían tener potencialmente acceso a cualquier archivo del servidor, incluyendo el código de otros proyectos que se esten ejecutando en ese momento).</li>
<li>Runner de tipo <strong>SSH</strong>: Parecido al anterior, solo que las tareas se ejecutarán en un servidor remoto al que se accederá por SSH (se considera también un método muy inseguro).</li>
<li>Runner de tipo <strong>Docker</strong>: Ejecuta las tareas dentro de un contenedor de Docker, lo que no solo hace que sea perfecto desde el punto de vista de la seguridad, sino que evita que tengamos que "<em>ensuciar</em>" el servidor que hace de <em>runner</em> instalando todos los paquetes y dependencias de nuestro proyecto para poder ejecutar las tareas. Además, nos asegura que una vez terminadas dichas tareas, el contenedor se destruye y el sistema queda limpio y preparado para la siguiente ejecución.</li>
</ul>
<p>La elección es obvia, por lo tanto añadimos el repositorio de paquetes de Docker a nuestro sistema:</p>
<p>En Debian/Ubuntu</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common
$ curl -fsSL https://download.docker.com/linux/debian/gpg <span class="p">|</span> sudo apt-key add -
$ sudo apt-key fingerprint 0EBFCD88
$ sudo add-apt-repository <span class="s2">"deb [arch=amd64] https://download.docker.com/linux/debian </span><span class="k">$(</span>lsb_release -cs<span class="k">)</span><span class="s2"> stable"</span>
</code></pre></div>
<p>En RedHat/CentOS</p>
<div class="highlight"><pre><span></span><code>$ sudo yum install -y yum-utils
$ sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
</code></pre></div>
<p>Y finalmente instalamos el paquete de Docker:</p>
<p>En Debian/Ubuntu</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get update
$ sudo apt-get install docker-engine
</code></pre></div>
<p>En RedHat/CentOS</p>
<div class="highlight"><pre><span></span><code>$ sudo yum update
$ sudo yum install docker-ce
</code></pre></div>
<p>Ahora que ya tenemos el paquete instalado, necesitamos generar un <a href="https://es.wikipedia.org/wiki/Token_de_seguridad">token</a> desde el servidor de Gitlab para registrar nuestro <em>runner</em>.</p>
<p>Abrimos nuestro Gitlab desde un navegador y vamos a <strong>Admin > Overview > Runners</strong>:
(O abrimos directamente la dirección: <a href="https://your-gitlab-host/admin/runners">https://your-gitlab-host/admin/runners</a>)</p>
<p><img alt="Gitlab" src="/images/posts/2017-04-24-integracion-continua-en-pelican-usando-gitlab-ci/screenshot_gitlab_runner_token.png" title="Obtener token para registrar un nuevo runner"></p>
<p>Guardamos el valor que aparece en <code>Registration token</code> y volvemos al terminal del servidor donde estamos instalando el <em>runner</em>.</p>
<p>Iniciamos el proceso de registro con el comando:</p>
<div class="highlight"><pre><span></span><code>$ sudo gitlab-ci-multi-runner register
</code></pre></div>
<p>El <em>runner</em> nos hará entonces una serie de preguntas:</p>
<ul>
<li><code>Please enter the gitlab-ci coordinator URL</code>: La dirección del servidor de Gitlab donde vamos a registrar nuestro <em>runner</em>.</li>
<li><code>Please enter the gitlab-ci token for this runner</code>: El token que hemos copiado en el paso anterior.</li>
<li><code>Please enter the gitlab-ci tags for this runner (comma separated)</code>: Aquí podemos indicar una serie de <em>tags</em> para identificar el <em>runner</em>. Util si vamos a tener <em>docenas</em> de ellos, sino, lo dejamos en blanco.</li>
<li><code>Whether to lock Runner to current project [true/false]</code>: Aquí debemos indicar si vamos a reservar este <em>runner</em> únicamente para trabajos del proyecto actual, o si el <em>runner</em> podrá ejecutar trabajos de cualquier proyecto. Seleccionamos <code>false</code> para que el <em>runner</em> pueda trabajar con cualquier proyecto que lo requiera.</li>
<li><code>Please enter the executor</code>: Aquí debemos seleccionar el tipo de <em>runner</em> que queremos que sea (<em>docker</em>, <em>docker-ssh</em>, <em>parallels</em>, <em>shell</em>, <em>virtualbox</em>, <em>docker+machine</em>, <em>kubernetes</em>, <em>ssh</em> o <em>docker-ssh+machine</em>). Tal y como comenté antes, yo recomiendo encarecidamente el tipo <code>docker</code>.</li>
<li><code>Please enter the default Docker image</code>: La imagen Docker que queremos usar por defecto. Esto dependerá de nuestro proyecto, pero podemos sobreescribir este valor desde el propio código del proyecto, así que no os preocupéis. No obstante, yo suelo elegir <code>debian:stable</code>.</li>
</ul>
<p>Hay información más detallada de esta parte en la documentación oficial, os recomiendo que le echéis un vistazo: <a href="https://docs.gitlab.com/ce/ci/runners/">https://docs.gitlab.com/ce/ci/runners/</a></p>
<p>Una vez hecho ésto, nuestro <em>runner</em> se conectará al servidor de Gitlab y se registrará, por lo que si accedemos de nuevo a la misma pantalla en la que nos aparecía el <code>token</code> de registro, deberíamos ver nuestro <em>runner</em> correctamente registrado y a la espera de tareas que realizar (en mi caso tengo 2):</p>
<p><img alt="Gitlab" src="/images/posts/2017-04-24-integracion-continua-en-pelican-usando-gitlab-ci/screenshot_gitlab_runner_added.png" title="Runner registrado y listo para trabajar!"></p>
<p>Podéis editar la descripción del <em>runner</em> desde esa misma pantalla para ponerle algo más descriptivo, como por ejemplo el nombre del servidor donde se está ejecutando y el tipo de <em>runner</em> que habeis elegido (en mi caso tengo a <code>SARAH</code> y a <code>SHARON</code>, ambos de tipo <code>Docker</code>)</p>
<p>Ahora que ya tenemos el <em>runner</em> registrado y listo, vamos a configurar las tareas de la integración continua de nuestro proyecto...</p>
<h2>Configuración del <em>pipeline</em><a name="pipeline"></a></h2>
<p>Llamamos <em>pipeline</em> al <em>flujo</em> de tareas que deberá seguir Gitlab-CI, ejecutándolas una a una hasta completarlas todas.</p>
<p>Una <em>pipeline</em> típica de integración continua y entrega continua en Gitlab-CI podría ser algo parecido a ésto:</p>
<p><span class="graphviz" style="text-align: center;"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABYMAAADpCAYAAAB2pSgYAAAABmJLR0QA/wD/AP+gvaeTAAAgAElEQVR4nOzdd3xUVf7/8Vd6pwZCkxKqFAFRBBUp6tcurquii2JBVlFXsRfECrq7woq6wOriWkBR4WfXwNKLlKUpBDAIaAiQQirpmczM74/rhJRJMjOZyUwy7+fjwQOYufeez7nlnHPPnHtugNVqtSIiIiIiIiIiIiIizdnSQG9HICIiIiIiIiIiIiKep85gERERERERERERET+gzmARERERERERERERP6DOYBERERERERERERE/oM5gERERERERERERET+gzmARERERERERERERP6DOYBERERERERERERE/oM5gERERERERERERET+gzmARERERERERERERP6DOYBERERERERERERE/oM5gERERERERERERET+gzmARERERERERERERP6DOYBERERERERERERE/oM5gERERERERERERET8Q7I6NlJWVkZeXR0FBAWVlZZjNZndsVkQaSXBwMBEREURHR9OyZUsCA5vH70QFBQXk5+dTWFhIeXk5FovF2yGJiIiIiIiP0f2QiDSmoKAgQkNDK8qc0NDQRk0/wGq1Wl1Z0Wq1kpGRQWpqKnl5eQQEBBAZGUlYWBhBQUHujlNEPMhkMlFcXExpaSlBQUHExsbSuXNnYmJivB2a00wmEydOnCA1NbUiP1FRUYSEhDSbRp2IiIiIiLiP7odEpDGZzWZKS0spKirCarXSsmVLOnbsSPv27QkICPB08ktd6gzOzc3l0KFDFBUVERsbS1xcHK1bt1bBItLElZaWkpWVRWpqKgUFBcTFxREfH9/ov1K5wmq1cvz4cZKTkwkICKBDhw60a9euSTbgRERERESk8el+SEQak8ViIScnh/T0dDIzM4mMjKRXr160atXKk8k61xlsNps5ePAgGRkZtG3blp49exIREeHJAEXESzIzMzl8+DAmk4n4+Hg6derk7ZBqVVBQwIEDBygpKeGMM86ga9eu+nFKRERERERcpvshEWlMxcXFHD58mKysLNq3b0+fPn08NfOC453BpaWlJCYmUlpaSr9+/WjTpo0nAhIRH2KxWDh69CjJycl07tyZnj17NsYjC07JysriwIEDxMTE0LdvX8LDw70dkoiIiIiINAO6HxKRxpadnc3PP/9MWFgYAwcOJCwszN1JONYZXFhYyJ49ewgJCWHgwIEqXET8zMmTJ/n5559p1aoVAwcO9JkG0IkTJzh06BAdOnSgd+/ePhOXiIiIiIg0H7ofEpHGVFJSQmJiIiaTibPOOouoqCh3bn5pvc8NmEwmEhMTiYiIYOjQoeoIFvFD7dq1Y8iQIeTl5XHw4EFvhwMYv4D/8ssvdOvWjT59+qjhIyLix8rLy7n33nsZOXIk33zzjbfDERGRZkb3QyLSmMLDwxk6dCgREREVncLuFFzXlxaLhcTERAAGDBhQ51wV9913H7t3767yWWBgIDExMfTs2ZNLL72Ua665xlPzXYgD5s6dy6effsodd9zBPffc4+1wfC6epmTixIkcOXKEf/3rXwwePLjez90hJiaG/v37V/w41LVrV7du3xmFhYUcOHCADh060K1bN6/FISLNm61tc9ttt3Hfffe5bbs33HADx48f59///jcDBw5023abG2fqtDfffJOffvqJqVOncs011zRShDWlpKTw1VdfsWvXroqXD8XExNCnTx/Gjh3LlVdeSUhIiNfis3HkHPRkm0JEpCny5/she/099nTu3Jlly5a5LV21mWqnNkfzFxQUxMCBA9m1axd79+5lyJAhbpsLvM7O4OTkZIqKihg6dKhLJ5HFYiEvL49du3axa9cuVqxYweuvv67RxSJNVJs2bejZsyeHDh2idevWXnkzrdVqZf/+/RUVnYiI+LcVK1awdOlSbr75ZiZNmuSVGCwWC/Pnz2fJkiVYLJYq3+Xk5LBt2za2bdvG+++/zwsvvKAbHRGRJkr3Q+JtanP4l+DgYAYOHMju3btJTk6mR48e7tlubV8UFxdz7NgxevbsSWRkpMMbrDx6xmQykZKSwpIlS/j222/58ccfee+995g6dWrDIxcRr+jcuTOZmZkcOnSIoUOHNnr6x48fp6SkhEGDBulRKBERP3f48GH++te/cvnll/Pggw96LY4ZM2awZs0aAEaOHMkf/vAH+vfvT8uWLSkoKODw4cOsW7eOb775hjlz5vDhhx96LVYREWkYf74fcvfTUuI8tTn8T2RkJN27d+fw4cN06NCBiIiIBm+z1s7gw4cPExERQceOHV3eeEhICPHx8UyfPp3s7Gw2b97M8uXL1Rks0sT17NmTXbt2kZ6eTlxcXKOlazKZSE5O5owzztATBiIizdxHH31U7zI9e/Zk7dq1jRBN7ZYtW1ZxU/bII49w4403Vvm+VatWDBs2jGHDhnHbbbc5lC9f0FTiFBHxBt0PiTeozeG/OnXqRGpqKocPH3bLlCl2O4MLCwvJyspy6y9No0aNYvPmzWRkZFBaWkpYWBgAV111FdnZ2Xz00UdkZ2fzySefsG/fPk6dOsWDDz7IhAkTAGOk8meffcbq1as5duwYVquVTp06MWbMGG655Raio6Ptpmu1WlmzZg0JCQns37+fgoIC2rZtS69evRg/fjznn39+jTk3rFYrq1ev5ttvvyUpKYmCggJatWrF0KFDmThxIn379q2RTkFBAR999BEbNmzgxIkTALRv357evXtzzTXXMHz48Br70tU81SUnJ4eFCxeyceNGcnNzadOmDRdccAGTJ0+ud11X8u1r8Th7HHJzc1m7di3r168nJSWFkydPEh4eTp8+fbjmmmu47LLL7MbmyHnr6XPbWe5MJzo6mri4OFJSUhq18XP8+HECAgK8Oj+XiAhUrQfy8/NZtGgRiYmJFBUV0alTJ6688kpuvfXWKm2M7777jpkzZ1b8f8qUKVW2OXXq1CrTHLhaL2dmZvLuu++yadMm8vLyaNOmDeeffz6TJ09m0aJFtc7X70i95Wq9acuPM22yuuaPc6VOc+WY1cdkMvH+++8DcMUVV9S4Kauuffv2PPzwwzU+b6z8OHMO1rb/Xd2PxcXFjBs3DoBNmzbZfY/InDlzWLZsGX/+85+58847q3zXkHNPRMTddD/kOE/XV47edzd2u8rd9ZbaHP7d5ggICCA+Pp69e/dSWFhIVFRUg7ZntzM4LS2NiIgI2rRp06CNO+PLL79k6dKlVT6zzX+SlZXFgw8+yJEjR6p8f+TIEY4cOcKKFSt46623aoxiLikp4dlnn+WHH36o8nlaWhppaWls2rSpxiTWZWVlPPvss2zcuLHKOpmZmaxcuZI1a9YwY8aMKge/sLCQyZMnc/To0SrrHD16lKNHj7J69Wo+/PBDevfuXfGdq3mqS2pqKvfeey8ZGRkVn6Wnp/P555+zYcOGOn89cCXfvhaPK8dh5syZNc4Pk8nEzp07K/4888wztcZZ13nryDKeOA/s8UQ6nTp1YteuXeTn5zfaXFlpaWl06NDBbZOmi4g01Pfff19jzrbk5GQWLFhASkoK06dPd2m7rtbLx44dY+rUqWRmZlZ8lp6ezhdffMHGjRsdGklQV73lar3pSpusNg2t09x5zLZv305WVhZgPDrrCl/KjzMaO92GttlERNxN90PO8XS9UVf7xRvtKnfXW2pzqM3Rpk0bIiIiSEtLo2fPng3alt3O4KysLGJjYxu04epsF1379u0rRgVXtnTpUs4991ymTp1Kr169qryw7sUXX+TIkSPExMTw8MMPM2rUKIKCgtiyZQtz5szh+PHjTJ8+nXfffbfKqM/XXnuNH374geDgYCZNmsTll19Ohw4dyM7O5tChQ3z55Zc1fiF4/fXX2bhxI7GxsUyePJkRI0bQunVrUlNTWbp0KZ9//jmzZs1iwIABdOnSBTAKnaNHjxIbG8vjjz/O4MGDiYyMJD09nV9++YWvvvqqxqhgV/NUl5deeomMjAxiY2N57LHHGD58OCaTiTVr1vDGG2+wbt26Wtd1Jd++Fo8rx6Ft27ZMnDiR0aNH07FjR1q0aEFGRgb//e9/ef/99/nmm2+46KKLuPDCC+3GWdd568gynjgP7PFEOjExMYSHh5OVldUojZ+CggJKS0tp166dx9MSEXHURx99xNlnn80999xDr169yM/PZ8mSJXz66ad8++23TJgwgV69egHG6IarrrrKobcqu1ovv/jii2RmZhIXF8ejjz7KueeeS3l5OevWrWPu3Ll11r02ddVbrtabrrTJatPQOs2ZY1afn376CYB27dq5/EKPxsyPM+dgfdy5Hx3R0DabiIi76X7IOZ6ur+pqv3ijXeXuekttDrU5AGJjY8nMzHR/Z7DJZKK4uJhWrVo1aMO2bR07doyPP/6YzZs3A9Q6srRz58784x//IDi4akiJiYls374dgJdffpnzzjuv4rtx48YRFxfH3XffzYEDB9i8eTMXXHABYPyykZCQAMALL7zAxRdfXLFeXFwccXFxFcvapKSk8PXXXxMZGcm8efOqPHrRvXt3Hn/8cSwWC19++SXLli1j2rRpFWkB3HnnnVx00UUV63Tp0oUuXbowduxYt+SpLnv27OHHH38E4O9//ztnnnkmABEREVx33XWEhIRUGaLvjnz7WjzOHgeAp59+usZnXbp04a677iIqKoq5c+fyzTff1HqR13beOrKMJ84DezyZTqtWrTh16pRLcTnr1KlTBAUFeeWNvSIitenXrx9vvfVWxQidyMhIpk2bxr59+0hM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vvqK1157rdZ1Xc23r8Xj7HGwvdzuiy++4LvvviMvL4/CwkL27NnDQw89xIYNGxzKq6s8cR54Mx0REXGMbWTGN998Q1ZWVo15zlytB4cMGcLAgQOxWq08/vjj/PDDDxV17/fff8+rr77aoLhdrTddaZPVxhfrtBtvvJExY8YAMGfOHB599FE2bdpETk4OZrOZvLw8du7cyZw5c7jpppuq3JR4Kz/1nYOeYsvDm2++yQ8//EBRUREZGRl8++23PP7447XOf+ftNpuIiHiHO+orb7SrPFVvqc3hOLU56ubzcwaDcePwwAMPkJyczAsvvFDj+44dOzJz5swak6k//vjj5OTksGXLFhYuXMjChQtrrDtp0qQq/3/00UcpKChg9erVvPfee7z33nt2Yxo6dGjFvzMzM1m5cmWtv8y0a9eOe+65xy15qstzzz3Hvffey8mTJ3nyySerfBcbG8t5553HunXr7K7rSr59LR5nj8MVV1zB0qVLOXz4MDNnzqyx/C233MKSJUvqy2aDeOI88GY6IiJSv8suu4w1a9awevVqVq9eXfH51KlTK9olrtbLzz//PPfeey9paWk89thjVb6LjY1l2LBhrF+/nuBg55uADak3XWmT1cbX6rSAgABmzpzJW2+9xdKlS9m8eTObN2+2u2zHjh159NFHq3zmjfw4cg56wp133sm6devIzMyscX527tyZoUOH2h097gttNhERMaYnqG9k5MqVK4mOjnZLeu6qrxq7XeWpekttDsepzVG3JtEZHBsby3vvvccnn3zC2rVrSUlJwWq10qlTJ8aMGcOf/vQnu4VNeHg4s2fPZtWqVXz33XckJSVRVFREu3bt6NmzJ9deey39+/evsk5ISAgzZ87kqquu4ptvviExMZHc3FwiIiJo164dffr0YcyYMRXTIADMnDmT9evXs3HjRo4ePUpGRgbBwcF06dKF888/n1tuuYWWLVu6JU916dy5M++//z4LFy5k06ZN5OXl0aZNG0aMGMGUKVPqLLRdybevxePscQgNDWXBggW88847bNiwgaysLKKjo+nXrx833HADQ4YM8fhF7onzwJvpiIhI/S666CJmzJjBsmXL+O233yguLq6xjKv1cpcuXSrq3h9++KGi7h05ciR333038+fPB3CpzG9IvelKm6w2vlinBQUFMW3aNK6//nq+/vprduzYQWpq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WERERERERERERMQPqDNYRERERERERERExA+oM1hERERERERERETED6gzWERERERERERERMQPqDNYRERERERERERExA+oM1hERERERERERETED6gzWERERERERERERMQPqDNYRERERERERERExA+oM1hERERERERERETED6gzWERERERERERERMQPBHs7AFekpaUxevToGp/PmzePSy65pOL/c+fOZcGCBVWWSUhIID4+3uMxin2rVq3i/vvvr/j/nj17CAsL82JEIp4XfRcUljq27PaX4Zx4mP0dPP6x8Vnn1nDsn56Lz199sgVu+X2/hoVAyfteDUfEKSpXpDHonGleVG6ISLNggVPbTlGws4Cy9DKsZVYCowMJ6xRGZL9IIvtHEtzad7u6Cn4sIOOjDAACggPo8WoPt227MLGQ9A/SK/7f49UeBAQHuG377uDJ/IvjmuTI4A4dOpCUlMQ//vEPAKZMmUJSUlKVjmCAadOmkZSUxPDhw5k5cyZJSUnqCHZQUVER//d//8c999zj1u1ecsklJCUlcfHFF7t1uyK+rOA/sPsV49/jh4H1I/t/WkaeXuexq4zPBnf1Tsz+4OaRxj6+eIC3IxFxnsoVcbeCEuj9CFw9+/RnOmeaF5UbTYvJDGc9BRe+6O1IRHxLxicZZH6RSeTASLo81oXus7rT6b5OhHYOJfOrTI7PPV5leUuphZS/pZD2nzQvRVxV9JBo4l+LJ6J3hNu3HTUwivjX4okaEOX2bdfFmX3syfyL45pkZ7B4ntVqxWKxYLFYvB2KiIiIiHiYFbBYQU0/Ed9hsRp/fFX0XeqslsZVmlJKwe4CYobH0GpMK4JbBhMQHEBI2xDaXN6GFiNb2F/R+vsfB/06/VdOzDvhlpj9hpP7WLzLd8fOi1dFRUWxatUqb4ch4ldy/+3tCESkuVG5Io6KCYfDr3s7CvEFKjd8Q0gQJP7N21GI+Jay9DIAQtuF2v0+enA0hT8WVvksMCyQM546w+Ox+TPt46ZHI4NFRLzswhfh/Q3ejkJEmhOVKyLiLJUbIuLrgqKDACj6pcju9+Hx4XR7sVtjhiTSJPnlyODqLzFbs2YNr732Gps2bSIwMJChQ4cyffp0unate3Ks+fPn88YbbwBw9tlns2TJEgA2btzI3XffDUCrVq3Ytm1bxTplZWUsWLCAhIQEUlNTCQ0NZdiw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"></span></p>
<p>En nuestro caso el <em>pipeline</em> será un poco diferente ya que al estar usando un proyecto basado en <a href="https://blog.getpelican.com/">Pelican</a> no tenemos ni que compilar el código ni que ejecutar tests, ya que como expliqué en el artículo "<a href="/2017/03/23/adios-octopress-hola-pelican/"><em>Adios Octopress, hola Pelican!</em></a>" de hace unas semanas, <em>Pelican</em> es un generador de sites estáticos (no hay que <em>programar</em> para añadir contenidos o gestionarlos) por lo que la <em>pipeline</em> de nuestro proyecto será más sencilla.</p>
<p>Pero que no haya que compilar código fuente ni haya tests no significa que siempre vaya a salir todo bien ni que no podamos equivocarnos, ya que dependiendo de qué elementos o <em>plugins</em> estemos usando al escribir los artículos de nuestro site en <em>Pelican</em> podrían darse errores al generar el site, por lo que podríamos utilizar ese mismo proceso de generación para validar que todo está bien. Si el site se genera correctamente, asumimos que todo es correcto y subimos el site a producción. En cambio si hay algún error a la hora de generar el site, interrumpimos el proceso y avisamos por email al desarrollador que ha hecho el último cambio en el repositorio.</p>
<p>Por lo tanto nuestra <em>pipeline</em> sería algo así:</p>
<p><span class="graphviz" style="text-align: center;"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB0MAAAG9CAYAAABnHt4tAAAABmJLR0QA/wD/AP+gvaeTAAAgAElEQVR4nOzdd3xUVf7/8dckJCQhQEJCE6SEphQBQQQRKeoqNnQXRRc7oqB+lbWtilhR1xVWLMiK7KKLiAo/qQpIrwERRAglNCEQEtJ7m8zc3x83E0kyCZlJmZT38/HgQXLn3ns+586dm3vmc885FsMwDERERERERERERERERERE6pZFXp6OQERERERERERERERERESkKigZKiIiIiIiIiIiIiIiIiJ1kpKhIiIiIiIiIiIiIiIiIlInKRkqIiIiIiIiIiIiIiIiInWSkqEiIiIiIiIiIiIiIiIiUicpGSoiIiIiIiIiIiIiIiIidZKSoSIiIiIiIiIiIiIiIiJSJykZKiIiIiIiIiIiIiIiIiJ1kpKhIiIiIiIiIiIiIiIiIlInKRkqIiIiIiIiIiIiIiIiInWSkqEiIiIiIiIiIiIiIiIiUicpGSoiIiIiIiIiIiIiIiIidZKSoSIiIiIiIiIiIiIiIiJSJykZKiIiIiIiIiIiIiIiIiJ1UoPK2EleXh6pqalkZGSQl5eHzWarjN2KSDVp0KAB/v7+BAYG0rRpU7y86s5zEro+iYiIiIiIiIiIiIh4jre3N76+voU5CF9f32ot32IYhuHOhoZhEBcXR0xMDKmpqVgsFgICAmjYsCHe3t6VHaeIVCGr1Up2dja5ubl4e3sTGhpKmzZtaNy4sadDc4uuTyIiIiIiIiIiIiIiNYPNZiM3N5esrCwMw6Bp06a0bt2aFi1aYLFYqrr4RW4lQ1NSUjh27BhZWVmEhobSsmVLgoOD61RvMpH6KDc3l8TERGJiYsjIyKBly5aEhYVV+1MaFaHrk4iIiIiIiIiIiIhIzWO320lOTubcuXMkJCQQEBBA586dCQoKqspiXUuG2mw2jhw5QlxcHCEhIXTq1Al/f/+qDFBEPCQhIYHjx49jtVoJCwvjoosu8nRIZdL1SURERERERERERESkdsjOzub48eMkJibSokULunbtWlUjO5Y/GZqbm0tERAS5ublccsklNGvWrCoCEpEaxG63ExUVxalTp2jTpg2dOnWqji7rLtP1SURERERERERERESk9klKSiIyMhJfX1969uxJw4YNK7uI8iVDMzMz2bdvHz4+PvTs2RM/P7/KDkREarD4+HgOHz5MUFAQPXv2rFEJUV2fRERERERERERERERqr5ycHCIiIrBarVx22WU0atSoMne/6IKT6FmtViIiIvD396dv375KNIjUQ82bN6dPnz6kpqZy5MgRT4dTSNcnEREREZHaKz8/nwkTJjBo0CCWL1/u6XBERERERMRD/Pz86Nu3L/7+/kRERJCXl1ep+y8zGWq324mIiACgR48eZY7V+/jjjzNo0KAi/wYPHsyNN97IE088wZIlS7DZbJUavLhmxowZDBo0iM8++8zToQA1L57aZOzYsQwaNIjffvutXMsrQ+PGjenevTvnzp0jKiqq0vfvKleuTyIiIiJSfzjapp9++mml7nf06NEMGjSo8B5UnHOlTfLRRx/x22+/MXHiRG699dZqiM6506dP88knn/Dwww8zcuRIhgwZwk033cSkSZNYunQpVqvVY7GdrzznYFW2CUVEREREqpK3t3fhyJQRERHY7fZK23eZydBTp06RlZVFr1698PHxcXnndrud1NRU9uzZw3vvvceTTz5JTk6O28GKiGc1a9aMTp068fvvv5Oenu7RWCp6fRIREREREc9ZvXo1Cxcu5O677+b+++/3SAx2u51PPvmEu+++m/nz53Po0CFSUlLIz88nOTmZnTt38o9//IO77rpLyUURERERkWrQoEEDevbsSXZ2NidPnqy0/ZaaDM3OzubMmTN07NiRgICAcu/wvvvuIzw8nPDwcDZv3sz8+fO55ZZbANi7dy9z586teNQi4jFt2rQhKCiIY8eOeSwGd69PIiIiIiLiecePH+cf//gHN954I0899ZTH4pgyZQrz58/HbrczaNAg/vnPf7JixQq2bNnCypUr+eSTTxg9ejTJyclMnz7dY3GKiIiIiNQnAQEBdOzYkTNnzpCdnV0p+2xQ2gvHjx/H39+f1q1bu71zHx8fwsLCmDx5MklJSWzfvp1Vq1YxceJEt/cpIp7XqVMn9uzZw7lz52jZsmW1l18Z1ycREREREal88+fPv+A6nTp1YsOGDdUQTekWLVrE+vXrAXjmmWe48847i7weFBREv3796NevH/fdd1+56lUT1JY4RURERETK0rp1a86ePcvx48fp2bNnhffnNBmamZlJYmIivXr1wmKxVLgQgCFDhrB9+3bi4uLIzc2lYcOGANx8880kJSUxf/58kpKS+Oabbzhw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v/9Ox44dXdq+ptXH03Jzc50u93SbW0RERETEocZ3r3IM4VLWHBKHDh0CoH379oXLwsLCANizZ0+5y+rUqRNQ/nkxnQkNDWXEiBFMmjSJb7/9ltGjR2O32/nqq68K13G3TmVxrBcZGen0dbvdXupcmpVR75oWT3neh19++QWA2267jYcffpiwsDAaNWpU2OvQMVxVVamK88CT5YiIiIiI1GWOJ5JL42475uKLLwYoHNmmOMMwOH78uEv7PJ+77R532tSlqWltkv79+xf26pw3b57L23uqPhc6B6vC+T1JSxvO1jFscHGebnOLiIiIiDjU+GToVVddBUBERAS7du0q8fqhQ4cIDw8vsi7AsGHDsFgsHDx4kA0bNpSrLMc2ERERrFq1qhKih8suuwygyNyY7tapLAMHDgRg586dThtkq1evJiYmxum2VVHvmhaPs/chLy8PAD8/vxLrG4bhVqPYFVVxHniyHBERERGRuszRbnAMkVqcu+2YQYMGAbBjxw6nD4xu2LDhgvOFlsXddo87berS1LQ2ia+vLw888AAAK1euZNGiRWWuHxcXxwcffFD4u6fqc6FzsCp4eXnRsmVLwHmiPyIigv379zvd1tNtbhERERERhxqfDO3Vqxf9+/cHYMqUKaxevZrMzEyys7PZsGEDL7zwAgCXXHJJYSMSzKdYR44cCZhzVPznP/8hOjqa/Px8zp07x7Zt23jhhRcKn9Z0bHPbbbcB8M477zB79mxOnjyJ1WolIyODEydOsGbNGl588UWWLFlSuN2rr77K9OnT2blzJ9HR0VitVtLT0wkPD2f27NkAdOnSpcJ1Kkvv3r0LE34vvPACmzdvJicnh4yMDJYuXcr7779f6rbu1rumxePq+9CtWzcAFi9ezA8//EBqaiqZmZns27ePp59+ms2bN5erru6qivPAk+WIiIiIiNRljt6Ay5cvJzExscScNe62Y/r06UPPnj0xDIPnn3+ebdu2FbadfvzxR959990Kxe1uu8edNnVpamKb5M4772TYsGEATJ8+nWeffZatW7eSnJyMzWYjNTWV3bt3M336dO66664iiUBP1edC52BVcdTho48+Ytu2bWRlZREXF8eKFSt4/vnnsdvtTrfzdJtbRERERMShxs8ZCmbD68knn+TUqVO8/vrrJV5v3bo1U6dOLRxqxeH5558nOTmZ8PBw5syZw5w5c0pse//99xf5/dlnnyUjI4N169Yxd+5c5s6d6zSmvn37Fv6ckJDAmjVrSn2atHnz5jz22GOVUqeyvPrqq0yYMIH4+Hj+/ve/F3ktNDSUK6+8ko0bNzrd1p1617R4XH0fRo4cycKFCzl+/DhTp04tsf4999zDggULLlTNCqmK88CT5YiIiIiI1FU33HAD69evZ926daxbt65w+cSJEwvble62q1577TUmTJhAbGwszz33XJHXQkND6devH5s2baJBA9eb8BVp97jTpi5NTWuTWCwWpk6dyscff8zChQvZvn0727dvd7pu69atefbZZ4ss80R9ynMOVoWHHnqIjRs3kpCQUOL8bNOmDX379nXae7gmtLlFRERERKCWJENDQ0OZO3cu33zzDRs2bOD06dMYhsFFF13EsGHD+Otf/0pgYGCJ7fz8/Jg2bRpr167lhx9+IDIykqysLJo3b06nTp247bbb6N69e5FtfHx8mDp1KjfffDPLly8nIiKClJQU/P39ad68OV27dmXYsGGFw8ACTJ06lU2bNrFlyxaioqKIi4ujQYMGtG3blquuuop77rmHpk2bVkqdytKmTRu++OIL5syZw9atW0lNTaVZs2YMHDiQ8ePHlzkEjTv1rmnxuPo++Pr6MmvWLGbPns3mzZtJTEwkMDCQSy65hNGjR9OnT58qb5hVxXngyXJEREREROqqa665hilTprBo0SJOnjxJdnZ2iXXcbVe1bdu2sO20bdu2wrbToEGDeOSRR/j0008B3Lpnr0i7x502dWlqYpvE29ubSZMm8ec//5lly5bxyy+/EBMTQ1ZWFo0bN6Zr166MGDGCkSNH4uPj4/H6lOccrAotWrRgzpw5fPbZZ+zatYvMzExCQ0MZOnQo48aN47PPPnO6XU1oc4uIiIiIAFiMYuOqxMfHc/DgQYYOHeqpmESklqju64WuTyIiIiJSH40dO5YTJ04wffr0aplTU0REREREpKbYtGkT3bt3p3nz5u7uYpHGxBQRERERERGpobZv386JEyfw8fGhV69eng5HRERERESk1qkVw+SKiIiIiIiI1FWHDh1iwYIF3HTTTXTs2JGQkBASExPZuHFj4RCkN910E40bN/ZwpCIiIiIiIrWPkqEiIiIiIiIiHmSz2VizZg1r1qxx+nq3bt148sknqzkqERERERGRukHJUBERERER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n2fq1Kl069aNd999lzZt2pgdloiIiIhHOZ1O/vrrL44ePUq7du1o1KiRp5tYXOFkKEBaWhpbtmwBoHXr1kRFRXk6IBGpIQoKCti9ezcHDhwgNDSUmJiYGjMjtDQan0RERERERKQu2rRpE2PGjGHnzp0899xzjB07FovFYnZYIiIiIqft8OHD7Ny5E4AOHTrQoEGD6mimcslQMBIku3bt4uDBgwQFBXHGGWcQGRmpN2EidUReXh6HDh1i3759gJFYbNy4sclRVYzGJxEREREREamLcnJymD59OjNnzmTQoEG89dZbNGnSxOywRERERCrN7XaTmJjIvn37SE9PJzo6mpYtW+Lj41NdTVY+GVokMzOT3bt3k5SUhNVqJSwsjKCgIHx9fbVEpUgt4na7KSgoIDs7m7S0NNLS0rDb7URHR9O8efMaPRu0LBqfREREREREpC767bffuOuuu0hKSuKpp55i1KhRZockIiIiUi6n00lubi4ZGRkcPXoUl8tFREQELVq0ICgoqLqbr3oytEhubi5JSUmkpKSQkZFBXl4eTqfTUwGKiBfY7Xb8/f0JCgoiPDyc8PBwrFar2WGdNo1PIiIiIiIiUtfk5OQwd+5cPvnkE/r168f9999fXUvKiYiIiHiEzWbD4XAQFBREaGgoERER+Pr6eqv500+GioiIiIiIiIiIiHf997//5dZbb6WgoIC5c+cydOhQs0MSERERqYkW1/6pXyIiIiIiIiIiIvXMRRddxKZNmxg+fDjDhw9n/PjxZGRkmB2WiIiISI2jmaEiIiIiIiIiIiK12KJFi7jjjjsIDg7mnXfe4fzzzzc7JBEREZGaQjNDRUREREREREREarPRo0ezefNmzjnnHAYMGMDEiRPJzc01OywREREbAzuCAAAgAElEQVSRGkHJUBERERERERERkVouKiqKzz77jHnz5jFv3jy6du3K+vXrzQ5LRERExHRKhoqIiIiIiIiIiNQRY8aMYePGjTRs2JBevXoxefJk8vPzzQ5LRERExDRKhoqIiIiIiIiIiNQhLVu25Pvvv+fVV1/llVdeoW/fvsTHx5sdloiIiIgplAwVERERERERERGpYywWC+PGjWPt2rUUFBTQuXNnnnnmGVwul9mhiYiIiHiVkqEiIiIiIiIiIiJ1VExMDKtXr2batGk89thjXHzxxezdu9fssERERES8xuJ2u91mByEiIiIiIiIiIiLVa+3atYwZM4aDBw/y7LPPMm7cOLNDqtFcLhepqalkZGSQnZ1NQUGB2SGJmMpms+FwOAgKCiIkJASHw2F2SCIiFbFYyVAREREREREREZF6Iicnh+nTp/Pcc89xySWX8OabbxIdHW12WDVKeno6+/fvJzExEafTia+vL/7+/vj4+JgdmoipnE4nubm5ZGVl4Xa7CQkJITo6mkaNGmGxWMwOT0SkLEqGioiIiIiIiIiI1Df/+9//uPHGG0lPT+eNN97gsssuMzsk0+Xl5bFz504OHz5MUFAQ0dHRRERE4Ovra3ZoIjWKy+Xi6NGjHD58mMTERAICAmjTpg2hoaFmhyYiUholQ0VEREREREREROqjtLQ0HnzwQebMmcPo0aOZPXs2YWFhZodlioMHD7Jjxw58fHw488wziYyMNDskkVohOzubHTt2kJSURKNGjTjrrLOw2WxmhyUiciIlQ0VEREREREREROqzpUuXctttt2G325k3bx4XXHCB2SF5jdvtZseOHezfv58WLVrQvHlzrFar2WGJ1DrJycnEx8fjcDiIjY3VjGoRqUkW6y+7iIiIiIiIiIhIPXbppZfy+++/061bNy688ELGjx9PZmam2WFVO7fbzZYtWzh48CAxMTG0bNlSiVCRKgoPD6dz58643W7Wr19fL8YQEak9NDNUREREREREREREAFi0aBG33347oaGhvPvuu/Tp08fskKpNfHw8CQkJxMXFERwcbHY4InWC0+lk06ZN5Obm0rlzZxwOh9khiYhomVwRERERERERERE57tChQ9x22218++23TJo0iccff7zOJTT++ecfdu/eTYcOHYiIiCiz3B133MGGDRvKra9p06YsXrzYY/GNGjWK/fv3M3fuXGJjYz1Wb12wd+9ePvvsM9avX8/BgwfJyMggODiYs846iwEDBjB48GB8fHzMDrNCP8PrrruOnTt38sYbbxAXF+flCKtPQUEB69evx26306lTJ824FhGzaZlcEREREREREREROa5x48Z88cUXzJo1i1mzZtGtWzd+//13s8PymPT0dHbt2sWZZ555ykSo1Cwul4tXX32Vq6++mgULFvDXX3+RkpJCQUEBR48eZc2aNTz99NNceeWV/PHHH2aHW6/Z7XZiY2PJzs5m9+7dZocjIoLd7ABERERERERERESkZrFYLIwbN45BgwZx00030bt3b6ZPn84DDzyAzWarcr1Op5O5c+fy3nvvsWXLFrKysmjYsCGdOnVi8ODBDB06lJYtW3quI6XYsWMHISEhNG3atMLPueGGG7jjjjuqMSopz2OPPcb3338PQO/evbnsssuIiYkhJCSEjIwMduzYwY8//sgXX3zB888/z3vvvWdyxPVbQEAArVq1Yvv27URHR+Pv7292SCJSj2lmqIiIiIiIiIiIiJSqVatW/PDDDzz99NNMmzaNvn378vfff1e5vhtuuIE777yTkSNHsmXLFtLT01mxYgWdO3fmnnvuoVu3bsXKZ2Rk0LZtW4YOHXq6XQHgyJEjpKWl0aZNG4/UJ96xePHiY4nQ+++/nxdeeIG+ffsSERGB3W4nNDSUrl27MmnSJD766CM6d+5scsQVs2DBAlatWlWnlsg9UXR0NAEBAezYscPsUESkntPMUBERERERERERESmT1Wpl4sSJDBw4kDFjxtCpUyeefPJJ7rnnHiwWS4XrWbt2LR988AFjx47loYceOnb8zDPPZMaMGaSkpLBw4cJiz3G73bhcLlwul0f68s8//9CoUSOCgoI8Ut+pDBkyhOTkZBYsWEB6ejrz589n8+bNZGVl0aRJEwYPHsz1119fbD/Fr776iieeeOLY92PHji1W54QJExgzZkyJ+pOTk/nwww/ZsmULaWlp3HPPPVx11VWAcQ6XL1/Ol19+SXx8PBkZGYSGhtK5c2euu+462rVrV2r8iYmJvPXWW6xcuZLU1FTCw8M599xzufXWW5k/fz4LFy7kpptuYvz48cWel5KSwg8//MBPP/3E3r17SUhIwM/Pj7POOothw4Zx8cUXV+o85ufn88477wBw6aWXMnr06FOWb9SoEffdd1+J49nZ2Xz00UcsX76cffv24Xa7adKkCf379+eaa64p9Xeiun+GZe0ZWpV2i/p4wQUXALBy5cpSZ3E///zzLF68mHHjxnHzzTcXe8zTPzuLxULr1q3ZtGkTmZmZBAYGVur5IiKeomSoiIiIiIiIiIiIlCs2NpY1a9YwY8YMJk2axNdff83bb79d4eVmt2zZAlBm8u3KK68skQwNDg722Kyy9PR0MjMzy2y/unz99dd88MEHxRK6e/bs4fXXX2fv3r1MmTLltOpfsmQJixYtKnasqK28vDweffRRVqxYUezxxMREvvvuO77//nsee+yxEkmuffv2MWHCBBITE48dO3z4MJ9++ikrVqwgNja2zHieeOIJ/ve//xU7lp+fz7p16459PPLIIxXu39q1a0lKSgKMmcVVkZSUxD333MPOnTuLHd+5cyc7d+7k22+/5ZVXXiE6OrrU51f3z7As3m7X0z87gPDwcPz9/Tl06BBnnnmmJ8MVEakwLZMrIiIiIiIiIiIiFeLj48P06dNZuXIlu3fvJjY2ljlz5lTouVFRUQB89913pT7er1+/Ysk3T0tKSsLPz4/g4OBqa6M0CxYsoFOnTsyePZvly5ezZMmSY7M2v/zyS7Zv336s7JAhQ1i1atWxBPPcuXNZtWrVsY+iGYUnWrRoEd27d+ftt9/m559/ZtWqVVxzzTUAvPji/2fvzuOkqu78/79v7VW9VO/N2g1NAFnirpiIRlyBn4ommmiMZKLR0UwS8xiDS4yJJjpqGONkoknIZIKOMQ4jKuKCShRxQTLGrxsMKhFaoYFeqveq6uqqe+/vj7Zbmq5uuprqLrp4PR8PHg+5de45n3MupT76zTn3Hr3yyisqKSnR9ddfr8cff1wvvfSSHn74YX35y1+WaZq6/fbbtXPnzl593nrrrWpoaFB5ebl+8YtfaN26dVq7dq1uuukmRaNRvfTSS/3Ot7i4WJdccol+//vf68knn9T69ev1yCOP6IorrpDb7daTTz6pV199ddDr984770iSSktLNXny5EHft+98tm3bpry8PP3kJz/pCYJvv/12FRUVqaamRjfddJNs2056/3A/w/6kMm46pPvZdSspKekJtAEgE9gZCgAAAAAAACAlJ5xwgt5++23deuutuvrqq/WXv/xFv/nNb1RSUtLvPSeddJLGjBmj5557TgsWLND111+vk08+uc9Rn91WrVql888/v+f30WhUPp9vyDW3traqoKBgSPc++OCDevDBB/v9PNlxsd0OO+ww/frXv+6ZZyAQ0A9+8ANt3rxZmzZt0saNGw/oHabjx4/XL3/5S7lcvX/Uu2PHDq1evVqBQED33XefKioqej6bNGmSlixZIsuytGrVKq1cuVI/+MEPJElvv/22Nm3aJMMwtHTpUk2dOrXnvrPPPls+n08333xzv/XceOONfa5NmDBBl112mXJycvRv//ZvevLJJzV37txBza++vr6nj6HYtGmT3njjDUnSz3/+c82ZM6fns1NPPVXl5eX69re/rS1btmjDhg068cQT+/Qx3M+wPyM9brqfXbeCggLt2LFD8Xhcbrc7XeUCwKCxMxQAAAAAAABAyvx+v+688049++yz2rhxo2bPnq3Vq1f32z43N1ePPPKIJk6cqGeffVbz5s3T2LFj9Y1vfEMPP/ywIpFIr/bnnXeebNvWokWL0lJvJBLJyDsLL7rooqSB79FHHy1J2rNnzwH1f/HFF/cJQiVp3bp1sixLJ554Yq8gdG/dx+O+9dZbPddef/11SV2B995BaLdTTz110Ecj7+vkk0+WJL3//vuDviccDkvqCgKHovvY15kzZ/YKQrvNmjVLX/jCFyRJGzZsSNrHcD/D/mRq3GSG8uy6dX/v9v2OA8BIYWcoAAAAAAAAgCE744wz9N577+m6667TokWLdOmll+q+++5Lehzt3LlztXXrVq1YsUKPPfaYXnzxRT300EN66KGHVFxcrHvvvVcXXXTRsNR5ILvSLr30Un3nO98Z0r39BZFFRUWSpI6OjiH1223SpElJr3cfobp27dp+jybu1tjY2PPPO3bskKSkQagkORwOTZkyRTU1NUk/t21b69at05o1a/Thhx+qqalJ8Xi8V5umpqYB69nbgQZpn3zyiaSuMLQ/M2bM0Ouvv66PP/446efD/Qz7M9LjpvvZdfN4PJLUpy8AGCmEoQAAAAAAAAAOSDAY1LJly3TmmWfqqquu0uGHH67ly5frlFNO6dPW6/Vq8eLFWrx4sRKJhF5++WX9x3/8h/77v/9b3/jGNzR9+nQdddRRaa/Rsqx+j+QdTl6vd8DP+3tP5WAVFhYmvd7W1jboPvYOqbpDx+7ALZmBPvvpT3+63/A1lVCstLRUkvq813SwuneWDlRz9/HO/QWuw/0M+zPS46b72XUzDEPS8K0TAOwPYSgAAAAAAACAtPjKV76ik046Sf/4j/+oU089VVdccYXuueeefo84dblcOvXUU3XqqaeqsrJSd911l1auXDksYeihpnvNU93V2n3f3rtF99XfZ6+++qrWrl0rh8Ohyy+/XKeccorKy8vl9/vlcDjU0tKi+fPnpzAL6YgjjpDU9e7Q7du3a/LkySnd372zdKD5NDQ0SBr6UbyjSSwWS3p9OJ4dABwseGcoAAAAAAAAgLQpKyvT448/rhUrVuiRRx7RcccdpzfffFOvvfaaysvL+71v3rx5koZ2DGe26d5JdyCmTJkiqff7QAdj4sSJkqStW7cm/dy2bX300UdJP/vb3/4mSTr33HN12WWXqaqqSjk5OT07cruP4E3Fscce27Or88EHH0z5/u6jZgd61+WWLVskSZWVlSn33590PMNU7b2TtL/vUfexwfsajmcHAAcLwlAAAAAAAAAAaXfhhRfqrbfeUnl5uU444QT99re/VV1dnTZu3Ji0fXcYw65QyefzSfrsiNehOOWUU2QYhjZt2qRnn3120Pd94QtfkCRt3Lix572je1u3bl2/7wvt7OyU9Fn9e7Nte0hhpsfj0Te/+U1J0po1a7Ry5coB29fV1emee+7p+f0Xv/hFSdKmTZv0xhtv9Gm/ZcsWvf76673apkM6nmGqHA5Hz184SBaCb9q0Se+9917Se4fj2QHAwYIwFAAAAAAAAMCwqKys1AsvvKD77rtPjz76qCTp/PPP15///Gft2rVLsVhM1dXV+td//Vf97Gc/0zHHHKPFixdnuOrM697N+OSTTyoUCg3pXYtVVVU699xzJUn/8i//ot///veqrq5WPB5Xe3u7tm3bprVr1+qGG27QqlWreu478sgjNXv2bNm2rSVLlui1115TR0eH2tvb9cwzz+iOO+7od8zp06dLkh5//HE9/fTTamlpUTgc1rvvvqtrrrlGL7/8csrzkLqC9e73z95999269tpr9eqrr6qpqUmmaaqlpUVvvvmm7r77bn31q1/tFQR+/vOf17HHHitJuvnmm/Xcc88pHA4rGo1q3bp1uu666yRJhx12WE8QnA7peIZD0T2Hf//3f9drr72mSCSiuro6PfXUU1qyZIksy0p633A9OwA4GPDOUAAAAAAAAADDxjAMXXnllTrxxBN14YUXauvWrbrhhhtkmqbq6urk9/s1ffp03XLLLbrmmmt6jvpctWqVzj///J5+/H6/LrnkEv3pT38a8Tk8+OCD+90Zt3btWuXm5qZlvLPOOksvvviiXnjhBb3wwgs916+++uqUwuJrr71W7e3teuGFF7R8+XItX748abt9d+P+9Kc/1VVXXaU9e/bohz/8Ya/PSkpKdMwxx2j9+vVyuXr/eHnBggV65JFH9NFHH+m2227rM87FF1+shx9+eND1dzMMQ7fddpt+/etf65FHHtGGDRu0YcOGpG3Hjh2ra6+9ts98vvvd7+rjjz/W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"></span></p>
<p>Ahora que ya tenemos claras las tareas que tienen que ejecutarse (y el orden en el que tienen que hacerlo) vamos a implementarlas en nuestro proyecto.</p>
<p>Como ya mencioné un poco más arriba, toda la configuración de Gitlab-CI se hace a través del archivo <code>.gitlab-ci.yml</code>. Este archivo tiene que estar situado en la raíz de nuestro proyecto para que Gitlab inicie la integración continua de forma automática cada vez que se haga un <code>git push</code> al repositorio.</p>
<p>La sintaxis de dicho archivo es muy sencilla, pero antes debemos aclarar un par de términos para poder entenderla:</p>
<h3>Tareas: <code>jobs</code></h3>
<p>Gitlab-CI se refiere como <code>jobs</code> a cada una de las acciones que vamos a ejecutar en la <em>pipeline</em>. Cada uno de estos <code>jobs</code> es una <em>tarea</em>, como por ejemplo compilar el código, ejecutar los tests, etc.</p>
<h3>Etapas: <code>stages</code></h3>
<p>Los <code>jobs</code> se agrupan en <code>stages</code>. Es decir, nosotros no definimos los <em>jobs</em> directamente, sino que definimos <em>stages</em>, y dentro de ellas definiremos los diferentes <code>jobs</code>.</p>
<p>Vamos a poner un ejemplo en el que habría 2 <em>stages</em>: una para construir el site y otra para subir el código a producción, y cada una de ellas tendrá las <em>subtareas</em> (<em>jobs</em>) correspondientes:</p>
<ul>
<li>Stage <em>build</em>: Aquí estarán las tareas que permiten generar el site, que a su ver serán:<ul>
<li>Job para establecer las variables de entorno necesarias.</li>
<li>Job para generar el site mediante <em>Pelican</em>.</li>
</ul>
</li>
<li>Stage <em>deploy</em>: Aquí estarán las tareas que permiten subir el site generado a producción, que a su ver serán:<ul>
<li>Job para subir los archivos del site generado a un servidor de producción.</li>
<li>Job para vaciar la caché de producción para que tenga en cuenta el código recién subido.</li>
</ul>
</li>
</ul>
<h3>Ejecuciones: <code>builds</code></h3>
<p>Se denomina <code>build</code> a la ejecución de una <em>pipeline</em> de integración continua. Podemos decir entonces que una <code>build</code> consta de <code>stages</code>, las cuales a su vez constan de <code>jobs</code>.</p>
<h3>Entornos: <code>environments</code></h3>
<p>Podemos definir varios entornos diferentes dependiendo de su finalidad, y ejecutar unas <em>stages</em> en unos y otras en otros según necesitemos.</p>
<p>Por ejemplo, podríamos definir un <code>environment</code> de producción donde se ejecutarían las <code>stages</code> que generan el site, ejecutan los tests, suben el código a los servidores de producción, avisan a los <em>jefes</em> de que una nueva versión acaba de ser subida a producción, etc., pero también podríamos querer definir un <code>environment</code> de <em>preproducción</em> donde probar en un entorno similar a producción los cambios antes de pasarlos a producción.</p>
<p>En este último ejemplo que he puesto ejecutaríamos las mismas <em>stages</em> que en producción salvo la que notifica a los <em>jefes</em> de la nueva versión, ya que no tiene sentido que les avisemos de una subida que aún NO está en producción.</p>
<h3>Variables: <code>variables</code></h3>
<p>Como su propio nombre indica, podemos definir una serie de <code>variables</code> para utilizarlas en cualquier punto del archivo <code>.gitlab-ci.yml</code>. Pero lo realmente interesante de esta parte es que no solo podemos definir los valores de dichas variables en el propio <code>.gitlab-ci.yml</code> sino que podemos definirlo también desde el propio Gitlab, lo cual es perfecto para definir <em>contraseñas</em> y demás datos "sensibles" sin que aparezcan reflejados en el código. Veremos cómo hacerlo un poco más adelante.</p>
<h3>Artefactos: <code>artifacts</code></h3>
<p>El concepto de <em>artefacto</em> es una parte muy importante en la integración continua, ya que permite (entre otras muchas cosas) garantizar que el código que está siendo probado en este momento y que ha pasado los tests es exactamente el código que subirá a producción.</p>
<p>En cada una de las <code>jobs</code> que se ejecutan podemos generar archivos, los cuales se pasarán automáticamente de <code>job</code> en <code>job</code> y de <code>stage</code> en <code>stage</code> hasta la finalización de la <code>build</code> actual. Estos archivos se llaman <code>artifacts</code>.</p>
<p>Intentaré explicarlo mejor: Gitlab-CI (y no solo él, sino también la mayoría de los sistemas de integración continua) ejecutan cada <code>stage</code> <em>desde cero</em>, clonando el repositorio con el código del proyecto al inicio de la misma y eliminándolo de nuevo antes de pasar a la siguiente, lo que significa que podría darse el caso en el que el código que sube a producción NO es exáctamente el mismo al que acabamos de pasar los tests.</p>
<p>Supongamos que entre el <code>job</code> que ejecuta los tests y el <code>job</code> que sube el código a producción (ambos en <code>stages</code> diferentes) alguien sube un nuevo cambio al repositorio. Eso provocaría que cuando se ejecute el <code>job</code> que sube el código a producción, el repositorio tendría un código diferente al que había cuando se ejecutó el <code>job</code> de los tests. Puede que éste nuevo código NO pase los tests, y aun así lo estaríamos subiendo a producción porque la <code>build</code> actual ya estaba empezada cuando se hizo este último <code>git push</code>:</p>
<p><span class="graphviz" style="text-align: center;"><img src="data:image/png;base64,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"></span></p>
<p>Sin embargo, si en la primera <code>job</code> que ejecutamos (la que genera el site estático, por ejemplo) definimos el directorio que contiene dicho código generado como un <code>artifact</code>, éste será el código que irá pasando a la siguiente <code>job</code> (la que ejecutará los tests), y si de nuevo en ese punto pasamos ese <code>artifact</code> con el código ya testeado a la siguiente <code>job</code> (la que sube el código a produccion), será ese mismo código (y no el que haya en ese momento en el repositorio) el que pasará a producción:</p>
<p><span class="graphviz" style="text-align: center;"><img src="data:image/png;base64,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jobdTVV0IFVoUSQSDRo0aMaMGdu2bXvxxReNRuPPP//ssCEndyfEY+3evfvtt9/evHnztWvXcnJySkpKlErlvXv3Vq9e/e9//xtAx44dLScZMXVZe/fulUqlLMuat5seG9y5c+f+/fuLiopUKtX169ffe++9EydOWLXYsWPH9u3bsyz78ccfnz59WqvVKpXKP/744+uvv7YNLy4uznR9u2jRonXr1j148ECv1yuVyrS0tMOHD8+cOXPXrl3mwqdPn+7Vq1evXr2USqX9o05ISHj88ccBfPLJJydOnDDFsHv37sWLF1czBpPCwsJ333335s2ber2+oKBg9erVO3fuBDBu3Dg7UXXo0KFr164A5s6de+jQIZVKpdFojh49+sknnwBo3bp1r169rHYZOXIkh8PZsWOHTCZr1aqV7cObnonGBRBCgAad0jZzJvfM5XIjIyPz8/OvXLkyePBgc8nk5OQbN25UodFKJdQJIXY07G6qogOpZouPP/74jh07LKcmqaghJ3cnxGPp9fpLly5dunSp3FdjYmLmz59vuWXIkCF//fVXUlKSafk6AG+99dZrr702dOjQ7du3379/32o5oTFjxmzdutWq2vnz50+dOjUvL++jjz4ybxSJRF26dDl+/LiXV5lLuQ8//FCpVCYlJf30008//fSTVVWdOnWqzOGWmjdv3tSpU8Vi8aeffmoZQ48ePWwXXq1sDC+88ML//ve/SZMmWW5MTEx0uEDj/Pnz33777YyMjM8//9xye6NGjRYuXGg7Y2V0dHSXLl3MaWL7lXsOntXpI4RYEovFAMLDw90diGvs3r37u+++Mw1NNxqNfD5fq9VmZmZu27Zt7dq1RqOxY8eOY8aMMZe/dOlSenq6Xq9PSEgQCoXmu0kSieTUqVN3794NDw+PjIxkGCYlJWXRokXmtWrNfXpUVNS5c+cKCgrOnj3btGnTiIgIrVZ75MiRxYsXm76pd+zY0ZTZBRASEiIWi1NTU8+cOaPX68PCwvz8/DQaTVZW1sWLF7///nulUmm+nD59+vTo0aN/+OGHV155hc/n2z/wX375RaPRaLXaS5cutWjRIiQkRCqVbtq0adu2bQDeffddy2nDMjIyUlJSbty40axZM5FIVFhYePTo0a+++so0OXCXLl0s/5L9/vvvhYWFw4cPNy8KYLUlKirqwoUL+fn5Z86cadKk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scJZQWODVOdVuts6ABCkCEKmhACARWupOl1lXeiexqGxurBEI0XcOC4AqM6p5D/WDk8QjRYFP+HRF7viqwpNjiZmYwzBePgT3f4YCSbBjmKLRoq43euUwghkhM0JU/ykMBQbKAvF7sq2Livg4cE26ixbj6XgzQLbFl5PXvjfwqHh2nZRUYZCQ0NfofpfldAZoa4rxEVubp2cezJOEtfQp1Kp9ObNmyNGjPAwN3DdFwAAZrO5uLjYaHScnhGhViASiUJDfTyFz7179+Ry+YABAzzdgSLhymuQ/1lLBoVQKyLoQGPCsCPQZYKHe2i12j///DM5OTkgIKBFQ2s3sJ1ByDewfWuksrKyr7/++vPPPy8qKho1atTChQufeeYZ61MADdmzZ0/37t2HDx/uIs13N7974+c3KNfTuyF/Ur67XJurjfl/MS03DQFywKAxhkUN2/XcLhdpmtAX4GbqQgaDERkZKRAIPM8RoWayzi4TGhrq844AAAgICNBqtRaL42QnDSLoMOBTGPg50Ln42CFq8wg68KPh8f96/kMZAGpqagiC4PG8sHhyB4HtDEI+gO2bxyiKyszMnDp1alRU1IcffpiWlnb79u1Tp05NmTLFdUcAAAwaNEgsFrtOk5aY1r9zfwYNn37ya8Wbis1VDxeyIatJhoiBHQGtiQJqzag1Xs/W/TIGNBqtU6dOERERLBbLepHm9SAQsicQCGJiYkQib06M0WSBgYEURVVVVTVut7iXYOId6DoFgAACf6mjNohgAoMPSf+E8bca+wytQqEIDAy0rReF3MJ2BqFWhe2bx5RKZUZGRu/evceOHVtQULB169aSkpL09PTYWG/OZE4A8d7o90gKn3vyd8pflRaDRZujNZQahEP8danv9ohBYywYuCAmKMbrOXvalvF4vKioqLCwMDabDf+7c4v9Aqj5bF8kGo0mFAojIyPDw8PddjO3GhaLFRgYWFFR4T6pA25nGPoNPHEJoqcBnQMAQGMBjYlzgCM/RdCAxno4KR23M/ReDRMLIOHvjb3tTJKkTCaTSDybCggBALYzCLU0bN8a78qVK4sWLercufObb745bNiw69evX758eeHChVyux/PqNUbvsN6vD3udwLbLj4VMDTGWGx988ED+ozz4yWDRCL+4adcRMGiMOEncssEtsuJpI664CIIQCoVCoZAkSa1WazAYSJJs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FjU5hzFjxuTl5Y0ePdqLUSGEEGpnsC8AIYQQQi1l+/btGRkZ77777qpVq+Li4thstlAoTE1NPXjwYKdOnebPn19QUGCfvn///jNmzPBVtH6CoiiLxWKxWHwdCEIIofYM+wIQQggh1CIKCwu3bt3aq1ev6dOnO3zE5XJXrVql0WjWrVvnk9j8GZ/Pz8zM3LFjh68DQQgh1J5hXwBCCCGEWsShQ4dIknziiSecfjpgwIDQ0NA//vijqKiolQNDCCGEEPYFIIQQQqhFXLp0CQASEhIaSmD96PLlywCwa9eu+Ph4nU539erV+Pj4+Pj4xMREAMjMzIz/n3v37i1fvjwlJcX6tqqqCgCUSuXGjRvHjBnTq1evgQMHzp8//+LFiw2VuH37duu+ticRzp8/b90yaNAgWzKj0Zienv7EE0/069dv4MCBL7300pkzZ0iS9DwHkiR//vnnF198cejQoX379h0/fvzXX39tG/bv4qC+/fZb20cGg8GWYaMO055MJnv11VcHDBiQkpKyaNGiBw8eeBikQ7m9e/d+7LHH5s6de/ToUb1eb0ugUCjWrVuXmpraq1evwYMHL1u27NatW54EhhBCyLewLwAhhBBCLaKiogIARCJRQwmsH1VWVgLAvHnz8vLyuFzuI488kpeXl5eXd/PmTag7Dd677747c+bMc+fOHTlyhE6nA4BMJnvuued+/PHH1atXX7x48dtvv+VyuXPmzPn222+dlrhkyRJrKbYtw4cPz8vL69Wrl32y999/f9++fe+8887FixdPnDgRGxu7ePHiK1eueJ7Db7/99tprrw0ePPjEiRPnzp2bNm3axo0bN23aZP3UxUE5nfavsYdpb/369XPmzDl//vynn356+fLlv//97x4GWb/co0ePpqSkvP3224cPH7YmkEqlzz333IkTJ957770///xz3759KpVq2rRpWVlZbgNDCCHkW9gXgBBCCKEWRBBEMxPYLFiwICUlhcvl9uvX7+bNm0FBQZs3by4uLl61alVqampAQEB0dPTmzZtDQkLWrVsnk8maHPOFCxe6d+8+dOhQDocjkUjeeuut6OjoxmZivQ8vFAqDgoJmz549fvz4vXv31tTUuD2o+lk15zCnTJmSlJTE5XIHDx6cmpp648YN63gKT4K0lrtmzZrU1FQ+ny+RSJYsWTJ8+HD7wEpLS1euXDlixAge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"></span></p>
<h3>Dependencias: <code>dependencies</code></h3>
<p>Las dependencias de los <code>jobs</code> se usan para definir el orden de ejecución de dichos <code>jobs</code> dentro de un <code>stage</code>. Hay <code>jobs</code> que requieren que otros <code>jobs</code> se hayan ejecutado previamente para poder ejecutarse ellos, por lo que éstos últimos tendrán configurado como una <em>dependencia</em> el <code>job</code> anterior. No se pueden ejecutar el <code>job</code> que lanza los tests sobre el código si no se ha ejecutado previamente el <code>job</code> que genera dicho código, por ejemplo.</p>
<p>Ahora que ya tenemos más o menos claros casi todos los conceptos que intervienen en una <em>pipeline</em>, vamos a echar un ojo al archivo de configuración de dicha <em>pipeline</em>: el ya mencionado <code>.gitlab-ci.yml</code>:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">.gitlab-ci.yml</span><a href='/files/2017-04-24-integracion-continua-en-pelican-usando-gitlab-ci/gitlab-ci.yml'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="nt">image</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">debian:testing</span>
<span class="nt">variables</span><span class="p">:</span>
<span class="nt">GIT_STRATEGY</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">clone</span>
<span class="nt">GIT_SUBMODULE_STRATEGY</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">none</span>
<span class="nt">SERVER_RSYNC_PARAMS</span><span class="p">:</span> <span class="s">"--recursive</span><span class="nv"> </span><span class="s">--compress</span><span class="nv"> </span><span class="s">--checksum</span><span class="nv"> </span><span class="s">--force</span><span class="nv"> </span><span class="s">--delete</span><span class="nv"> </span><span class="s">--stats</span><span class="nv"> </span><span class="s">--itemize-changes"</span>
<span class="nt">SERVER_RSYNC_HOST</span><span class="p">:</span> <span class="s">"pornohardware.com"</span>
<span class="nt">SERVER_RSYNC_PORT</span><span class="p">:</span> <span class="s">"873"</span>
<span class="c1">#SERVER_RSYNC_USER -> Passed with "Secret Variables" from Gitlab GUI</span>
<span class="c1">#SERVER_RSYNC_PASSWORD -> Passed with "Secret Variables" from Gitlab GUI</span>
<span class="c1">#SERVER_WEBSITE_ROOT_DIR -> Passed with "Secret Variables" from Gitlab GUI</span>
<span class="nt">stages</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">build</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">deploy</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">notify-sites</span>
<span class="nt">build</span><span class="p">:</span>
<span class="nt">stage</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">build</span>
<span class="nt">script</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">apt-get -q update && apt-get -q -y install locales</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">echo "es_ES.UTF-8 UTF-8" > /etc/locale.gen && echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen && locale-gen</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">apt-get -q update && apt-get -q -y install pelican python-markdown python-typogrify python-bs4 graphviz</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">cd src && pelican -s publishconf.py</span>
<span class="nt">artifacts</span><span class="p">:</span>
<span class="nt">name</span><span class="p">:</span> <span class="s">"${CI_PROJECT_NAME}_${CI_COMMIT_REF_NAME}_artifacts"</span>
<span class="nt">expire_in</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">1 week</span>
<span class="nt">paths</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="s">"src/output"</span>
<span class="p p-Indicator">-</span> <span class="s">"conf"</span>
<span class="nt">deploy</span><span class="p">:</span>
<span class="nt">stage</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">deploy</span>
<span class="nt">script</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">apt-get -q update && apt-get -q -y install rsync</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">export RSYNC_PASSWORD=${SERVER_RSYNC_PASSWORD}</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">mv src/output http</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">rsync ${SERVER_RSYNC_PARAMS} http conf rsync://${SERVER_RSYNC_USER}@${SERVER_RSYNC_HOST}:${SERVER_RSYNC_PORT}/${SERVER_RSYNC_NAME}</span>
<span class="nt">only</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">master</span>
<span class="nt">dependencies</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">build</span>
<span class="nt">environment</span><span class="p">:</span>
<span class="nt">name</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">production</span>
<span class="nt">url</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">https://pornohardware.com</span>
<span class="nt">notify-sites</span><span class="p">:</span>
<span class="nt">stage</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">notify-sites</span>
<span class="nt">script</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">apt-get -q update && apt-get -q -y install python python-requests</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">cd src && python notify_sites.py</span>
<span class="nt">only</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">master</span>
</code></pre></div>
</figure>
<p>Si estáis familiarizados con Docker (mejor dicho, con <a href="https://docs.docker.com/compose/">Docker-compose</a>) la estructura os resultará similar.</p>
<p>Recordad que hemos registrado nuestro <em>runner</em> especificando el tipo <em>Docker</em>, lo que significa que Gitlab-CI va a <em>levantar</em> un contenedor Docker con la configuración que tengamos en este archivo.</p>
<p>Por eso, la primera línea indica qué imagen vamos a utilizar para levantar nuestro contenedor:</p>
<div class="highlight"><pre><span></span><code><span class="nt">image</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">debian:testing</span>
</code></pre></div>
<p>Lo más sensato en la mayoría de los proyecto sería especificar la misma imagen que tengáis en el servidor de producción donde vayáis a ejecutar vuestro proyecto, pero en nuestro caso (al tratarse de un site estático pre-generado) es completamente irrelevante. En mi caso he elegido <code>debian:testing</code>.</p>
<p>Lo siguiente es la declaración de variables:</p>
<div class="highlight"><pre><span></span><code><span class="nt">variables</span><span class="p">:</span>
<span class="nt">GIT_STRATEGY</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">clone</span>
<span class="nt">GIT_SUBMODULE_STRATEGY</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">none</span>
<span class="nt">SERVER_RSYNC_PARAMS</span><span class="p">:</span> <span class="s">"--recursive</span><span class="nv"> </span><span class="s">--compress</span><span class="nv"> </span><span class="s">--checksum</span><span class="nv"> </span><span class="s">--force</span><span class="nv"> </span><span class="s">--delete</span><span class="nv"> </span><span class="s">--stats</span><span class="nv"> </span><span class="s">--itemize-changes"</span>
<span class="nt">SERVER_RSYNC_HOST</span><span class="p">:</span> <span class="s">"pornohardware.com"</span>
<span class="nt">SERVER_RSYNC_PORT</span><span class="p">:</span> <span class="s">"873"</span>
<span class="c1">#SERVER_RSYNC_USER -> Passed with "Secret Variables" from Gitlab GUI</span>
<span class="c1">#SERVER_RSYNC_PASSWORD -> Passed with "Secret Variables" from Gitlab GUI</span>
<span class="c1">#SERVER_WEBSITE_ROOT_DIR -> Passed with "Secret Variables" from Gitlab GUI</span>
</code></pre></div>
<p>Vamos a ver para qué son cada una de ellas:</p>
<ul>
<li><code>GIT_STRATEGY</code>:
Esta es una variable predefinida de Gitlab-CI, y su valor establece cómo debe el <em>runner</em> descargar los archivos del repositorio. Se puede establecer como <code>clone</code> para que el <em>runner</em> traiga el repositorio entero en cada ejecución, o <code>fetch</code> para que únicamente descargue los ultimos cambios. Yo prefiero garantizar un entorno limpio en cada ejecución, por lo que siempre uso el valor <code>clone</code> aunque sea un pelín más lento que <code>fetch</code>.</li>
<li><code>GIT_SUBMODULE_STRATEGY</code>:
Esta también es una variable predefinida, y es la que le dice al <em>runner</em> cómo debe gestionar los posibles submódulos de <code>git</code> que haya en el repositorio. Si la establecemos a <code>none</code> el <em>runner</em> NO descargará los submódulos cuando descargue el repositorio. Si la establecemos a <code>normal</code> únicamente se traerá aquellos submódulos que estén en el primer nivel en el árbol de directorios del proyecto, y si la establecemos a <code>recursive</code> se traerá todos los submódulos que haya en el repositorio. Como no tengo ningún submódulo en este proyecto, he establecido el valor <code>none</code>.</li>
<li><code>SERVER_RSYNC_PARAMS</code>:
Los parámetros con los que se llamará al comando <code>rsync</code> para subir los archivos a producción.</li>
<li><code>SERVER_RSYNC_HOST</code>:
El nombre del servidor de producción donde se subirán los archivos.</li>
<li><code>SERVER_RSYNC_PORT</code>:
El puerto para conectarse al servidor de producción a través de <code>rsync</code>.</li>
<li><code>SERVER_RSYNC_USER</code>, <code>SERVER_RSYNC_PASSWORD</code> y <code>SERVER_WEBSITE_ROOT_DIR</code>:
El usuario, la contraseña y el directorio que usará el <em>runner</em> para conectarse al servidor de producción y subir los archivos. Estas variables NO están establecidas en el archivo (si os fijáis, las 3 están comentadas, únicamente aparecen a modo de recordatorio) sino que están definidas desde el propio Gitlab para evitar tener que poner sus valores reales aquí. De esta forma, únicamente quien gestiona/administra el servidor de Gitlab conoce dichos valores, evitando que cualquiera que tenga acceso al repositorio conozca el valor de dichas variables.</li>
</ul>
<p>Se las conoce como "<em>variables secretas</em>", y se configuran en <strong>Project Settings > CI/CD Pipelines > Secret Variables</strong>:</p>
<p><img alt="Gitlab" src="/images/posts/2017-04-24-integracion-continua-en-pelican-usando-gitlab-ci/screenshot_gitlab_secret_variables.png" title="Variables secretas"></p>
<p>Tienes más información sobre ellas en la documentación oficial: <a href="https://docs.gitlab.com/ce/ci/variables/README.html#secret-variables">https://docs.gitlab.com/ce/ci/variables/README.html#secret-variables</a>.</p>
<p>Lo siguiente que vemos en el archivo es la definición de <code>stages</code>, que en nuestro caso van a ser 3:</p>
<div class="highlight"><pre><span></span><code><span class="nt">stages</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">build</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">deploy</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">notify-sites</span>
</code></pre></div>
<p>La primera de ellas (<code>build</code>) es la que generará el site estático. La segunda (<code>deploy</code>) es la que subirá el código generado en la <code>stage</code> anterior a producción. Y por último, la tercera (<code>notify-sites</code>) se encargará de <em>decir</em> a algunos buscadores y agregadores que hay contenido nuevo en la web para que sepan que tienen que <a href="https://es.wikipedia.org/wiki/Indexaci%C3%B3n"><em>indexarlo</em></a> (luego os pasaré el script por si alguno quiere echarle un ojo o utilizarlo en su web).</p>
<p>Ahora que ya hemos definido las <code>stages</code>, vamos a empezar definiendo los <code>jobs</code> que tendrá cada una de ellas. Empezamos con el <code>job</code> de la primera <code>stage</code>, al que también llamaremos <code>build</code>:</p>
<div class="highlight"><pre><span></span><code><span class="nt">build</span><span class="p">:</span>
<span class="nt">stage</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">build</span>
<span class="nt">script</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">apt-get -q update && apt-get -q -y install locales</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">echo "es_ES.UTF-8 UTF-8" > /etc/locale.gen && echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen && locale-gen</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">apt-get -q update && apt-get -q -y install pelican python-markdown python-typogrify python-bs4 graphviz</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">cd src && pelican -s publishconf.py</span>
<span class="nt">artifacts</span><span class="p">:</span>
<span class="nt">name</span><span class="p">:</span> <span class="s">"${CI_PROJECT_NAME}_${CI_COMMIT_REF_NAME}_artifacts"</span>
<span class="nt">expire_in</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">1 week</span>
<span class="nt">paths</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="s">"src/output"</span>
<span class="p p-Indicator">-</span> <span class="s">"conf"</span>
</code></pre></div>
<p>Como puedes ver lo primero que hacemos es definir el nombre del <code>job</code>, que en este caso es <code>build</code>. Después definimos a qué <code>stage</code> pertenece este <code>job</code>, que casualmente también la hemos llamado <code>stage</code>.</p>
<p>A continuación especificamos los comandos que vamos a ejecutar en el contenedor Docker para instalar todo lo que necesitamos para generar el site estático, definir el idioma del contenedor (para el formato de fecha/hora, por ejemplo) a <code>es_ES.UTF-8</code>, etc.</p>
<p>Y después le decimos que genere el site con el comando:</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">cd</span> src <span class="o">&&</span> pelican -s publishconf.py
</code></pre></div>
<p>Como ya dije antes (pero os lo recuerdo de nuevo), si quereis ampliar la información sobre cómo se genera un site estático con Pelican, echad un ojo al artículo que escribí sobre el tema hace unas semanas: <a href="/2017/03/23/adios-octopress-hola-pelican/"><em>Adios Octopress, hola Pelican!</em></a>.</p>
<p>Con el comando anterior, Pelican generará el site en el directorio <code>/src/output</code>. Por ese motivo, una vez generado el site, metemos dicho directorio y el de la configuración (<code>/conf</code>) en un <code>artifact</code> para poder pasárselo al siguiente <code>job</code>:</p>
<div class="highlight"><pre><span></span><code> <span class="nt">artifacts</span><span class="p">:</span>
<span class="nt">name</span><span class="p">:</span> <span class="s">"${CI_PROJECT_NAME}_${CI_COMMIT_REF_NAME}_artifacts"</span>
<span class="nt">expire_in</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">1 week</span>
<span class="nt">paths</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="s">"src/output"</span>
<span class="p p-Indicator">-</span> <span class="s">"conf"</span>
</code></pre></div>
<p>Gitlab permite además que nos descarguemos los <code>artifacts</code> que se hayan generado en cada <code>job</code>, pero para evitar que se guarden indefinidamente y se llene el disco duro del servidor, podemos indicar un <em>tiempo de vida</em> para los artefactos (en nuestro caso, 1 semana). Para el nombre del artefacto hemos utilizado un par de variables predefinidas de Gitlab-CI que contienen el nombre del proyecto actual (<code>${CI_PROJECT_NAME}</code>) y el nombre de la <code>branch</code> de <code>git</code> que estemos utilizando.</p>
<p>Con esto quedaría definido nuestro primer <code>job</code>.</p>
<p>Ahora vamos con el siguiente, que es el que se encargará de subir el código generado a producción:</p>
<div class="highlight"><pre><span></span><code><span class="nt">deploy</span><span class="p">:</span>
<span class="nt">stage</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">deploy</span>
<span class="nt">script</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">apt-get -q update && apt-get -q -y install rsync</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">export RSYNC_PASSWORD=${SERVER_RSYNC_PASSWORD}</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">mv src/output http</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">rsync ${SERVER_RSYNC_PARAMS} http conf rsync://${SERVER_RSYNC_USER}@${SERVER_RSYNC_HOST}:${SERVER_RSYNC_PORT}/${SERVER_RSYNC_NAME}</span>
<span class="nt">only</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">master</span>
<span class="nt">dependencies</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">build</span>
<span class="nt">environment</span><span class="p">:</span>
<span class="nt">name</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">production</span>
<span class="nt">url</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">https://pornohardware.com</span>
</code></pre></div>
<p>Este otro <code>job</code> solo se ejecutará si el <code>job</code> anterior termina correctamente.</p>
<p>Es muy similar al anterior, solo hay un par de cosas nuevas:</p>
<p>Al igual que en el anterior <code>job</code>, primero definimos a qué <code>stage</code> pertenece, qué comandos vamos a ejecutar para subir el código (nosotros usaremos <code>rsync</code>, pero se puede usar cualquier cosa), etc. Pero vemos 3 <em>directivas</em> nuevas: <code>only</code>, <code>dependencies</code> y <code>environment</code>:</p>
<ul>
<li><code>only</code>: Esta directiva permite especifica en qué rama (<code>branch</code>) de nuestro repositorio se va a ejecutar el <code>job</code>. En este caso, y puesto que el <code>job</code> se encargará de subir el código a producción, debemos asegurarnos de que únicamente se ejecute cuando el <code>git push</code> que ha lanzado la <code>build</code> se haya hecho en la rama <code>master</code>. Si un usuario hace un <code>git push</code> a una rama que no sea la especificada aquí, este <code>job</code> NO se ejecutará.</li>
<li><code>dependencies</code>: No podemos subir ningún site a producción si dicho site no se ha generado aún, por lo que con ésta directiva le decimos a Gitlab-CI que primero debe haberse ejecutado el <code>job</code> cuyo nombre es <code>build</code> (que es el que se encarga de generar el site).</li>
<li><code>environment</code>: Y por último, definimos el nombre y URL del entorno al que estamos subiendo el código. Este valor es únicamente para poder acceder a él fácilmente desde el panel de Gitlab. Si en lugar de subir el código a producción lo estuviéramos subiendo a un entorno de pre-producción (staging, integración o como quieras llamarlo), aquí pondríamos los valores correspondientes.</li>
</ul>
<p>Es decir, este <code>job</code> se va a ejecutar siempre DESPUÉS del <code>job</code> llamado <code>build</code> y únicamente cuando los cambios que han <em>disparado</em> este proceso se hayan hecho en la rama <code>master</code>.</p>
<p>Por último tenemos la definición del último <code>job</code>:</p>
<div class="highlight"><pre><span></span><code><span class="nt">notify-sites</span><span class="p">:</span>
<span class="nt">stage</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">notify-sites</span>
<span class="nt">script</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">apt-get -q update && apt-get -q -y install python python-requests</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">cd src && python notify_sites.py</span>
<span class="nt">only</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">master</span>
</code></pre></div>
<p>Pertenece a la <code>stage</code> llamada <code>notify-sites</code>, únicamente se ejecutará cuando los cambios en el repositorio se hayan hecho en la rama <code>master</code> y ejecuta únicamente los 2 comandos que hay definidos en <code>script</code> (qué consisten en instalar <code>python</code> y algunas de sus dependencias, y después ejecutar el script <code>notify_sites.py</code>).</p>
<p>Este script es solo una <em>tontería</em> para notificar a algunos buscadores que la web ha cambiado para que sepan que tienen que venir a reindexarla lo antes posible:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">notify_sites.py</span><a href='/files/2017-04-24-integracion-continua-en-pelican-usando-gitlab-ci/notify_sites.py'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="ch">#!/usr/bin/env python</span>
<span class="kn">from</span> <span class="nn">pelicanconf</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">import</span> <span class="nn">requests</span>
<span class="n">SERVICES_TO_NOTIFY</span> <span class="o">=</span> <span class="p">(</span>
<span class="c1"># ('name', 'host', 'target', 'params'),</span>
<span class="p">(</span><span class="s1">'Google'</span><span class="p">,</span> <span class="s1">'https://www.google.com/webmasters/tools/ping?sitemap='</span> <span class="o">+</span> <span class="n">SITEURL</span> <span class="o">+</span> <span class="s1">'/sitemap.xml'</span><span class="p">),</span>
<span class="p">(</span><span class="s1">'Bing'</span><span class="p">,</span> <span class="s1">'https://www.bing.com/webmaster/ping.aspx?siteMap='</span> <span class="o">+</span> <span class="n">SITEURL</span> <span class="o">+</span> <span class="s1">'/sitemap.xml'</span><span class="p">),</span>
<span class="p">(</span><span class="s1">'Archive.org'</span><span class="p">,</span> <span class="s1">'http://web.archive.org/save/'</span> <span class="o">+</span> <span class="n">SITEURL</span><span class="p">),</span>
<span class="p">)</span>
<span class="n">headers</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">"Content-type"</span><span class="p">:</span> <span class="s2">"text/html; charset=UTF-8"</span><span class="p">,</span>
<span class="s2">"Accept"</span><span class="p">:</span> <span class="s2">"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"</span><span class="p">,</span>
<span class="s2">"Accept-Language"</span><span class="p">:</span> <span class="s2">"en-US,es;q=0.7,en;q=0.3"</span><span class="p">,</span>
<span class="s2">"Referer"</span><span class="p">:</span> <span class="n">SITEURL</span>
<span class="p">}</span>
<span class="nb">print</span> <span class="s2">"Notifying services about new version of"</span><span class="p">,</span> <span class="n">SITEURL</span>
<span class="k">for</span> <span class="n">service</span> <span class="ow">in</span> <span class="n">SERVICES_TO_NOTIFY</span><span class="p">:</span>
<span class="n">sName</span> <span class="o">=</span> <span class="n">service</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">sRequest</span> <span class="o">=</span> <span class="n">service</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="nb">print</span> <span class="s2">"> Connecting with:"</span><span class="p">,</span> <span class="n">sName</span>
<span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sRequest</span><span class="p">)</span>
<span class="k">if</span> <span class="n">r</span><span class="o">.</span><span class="n">status_code</span> <span class="o">!=</span> <span class="mi">200</span><span class="p">:</span>
<span class="nb">print</span> <span class="s1">'ERROR'</span><span class="p">,</span> <span class="n">r</span><span class="o">.</span><span class="n">status_code</span>
<span class="nb">print</span> <span class="s1">''</span>
<span class="nb">print</span> <span class="n">r</span><span class="o">.</span><span class="n">content</span>
<span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="nb">print</span> <span class="s2">" Request sent OK"</span>
<span class="nb">print</span> <span class="s2">"Process finished successfully!"</span>
<span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</code></pre></div>
</figure>
<p>Como veis es muy sencillo. Únicamente hace un <code>import</code> de la propia configuración de vuestro site en Pelican (<code>pelicanconf.py</code>) para tener acceso a la variable <code>SITEURL</code> y después efectúa una petición a cada una de las URLs que tiene definidas para <em>avisarles</em> del nuevo contenido.</p>
<p>Y poco más... con esto ya tendríamos nuestra <em>pipeline</em> terminada!</p>
<p>Solo hemos utilizado una pequeña parte de todas las directivas que existen en Gitlab-CI, por lo que a pesar de que con lo que acabamos de ver podemos generar <em>pipelines</em> más que suficientes para la mayoría de los proyectos, os recomiendo que le echéis un ojo a la documentación sobre los comandos y opciones disponibles en el archivo <code>.gitlab-ci.yml</code> en la documentación oficial: <a href="https://docs.gitlab.com/ce/ci/yaml/README.html">https://docs.gitlab.com/ce/ci/yaml/README.html</a>.</p>
<p>Ahora que ya tenemos el archivo <code>.gitlab-ci.yml</code> completo y guardado en la raíz de nuestro proyecto, vamos a hacer una prueba real de cómo funcionaría todo el proceso.</p>
<h2>Demostración <a name="demo"></a></h2>
<p>Hay varias formas de trabajar con ramas en <code>git</code>, pero la más extendida cuando son proyectos personales (es decir, proyectos en los que únicamente trabajamos nosotros) es más o menos así:</p>
<p>El repositorio tiene siempre 2 ramas: <code>master</code> y <code>development</code>.
La rama <code>master</code> (que es la que refleja lo que está instalado en producción en este momento) está protegida para que NADIE pueda hacer <code>push</code> directamente a ella (esto se configura en el propio Gitlab).</p>
<p>De esta forma garantizamos que <code>master</code> siempre será un reflejo fiel del entorno de producción, y la única manera de subir código a ella es mediante un <code>merge request</code> desde la rama de <code>development</code> (los típicos <code>pull request</code> de Github).</p>
<p>Cuando vamos a desarrollar una nueva funcionalidad (o a escribir un nuevo artículo, como sería mi caso en el proyecto de la web de pornoHARDWARE.com) siempre trabajamos en la rama <code>development</code>, y al finalizar el desarrollo y hacer los <code>commits</code> necesarios, creamos un nuevo <code>merge request</code> hacia la rama <code>master</code> para que podamos revisar los cambios que queremos pasar a producción manualmente.</p>
<p>Si la <code>merge request</code> es aceptada (en nuestro caso la aceptaremos nosotros mismos) los cambios se incorporan a la rama <code>master</code>, lo que provocará que la <em>pipeline</em> de nuestra integración continua se lance, ejecutando los <code>jobs</code> uno a uno hasta el final.</p>
<p>Tal y como hemos configurado la <em>pipeline</em>, cuando subamos los cambios a la rama <code>development</code> se ejecutará únicamente la <code>stage</code> llamada <code>build</code> (para generar el código a modo de test), pero si incorporamos los cambios a la rama <code>master</code> se ejecutarán también las <code>stages</code> llamadas <code>deploy</code> y <code>notify-sites</code>.</p>
<p>Mola, verdad? Pues vamos a verlo:</p>
<p>Nos situamos en el directorio de nuestro proyecto, nos cambiamos a la rama <code>development</code>, hacemos un pequeño cambio en el código y lo subimos al repositorio con el <code>commit</code> y el <code>push</code> correspondiente:</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">cd</span> src/pornohardware
$ git checkout development
Already on <span class="s1">'development'</span>
$ <span class="nb">echo</span> <span class="s2">"Archivo de prueba"</span> > dumy-file.txt
$ git add dumy-file.txt
$ git commit -m <span class="s2">"Cambio de prueba para probar la pipeline"</span> dumy-file.txt
<span class="o">[</span>development c45fbfa<span class="o">]</span> Cambio de prueba para probar la pipeline
<span class="m">1</span> file changed, <span class="m">1</span> insertion<span class="o">(</span>+<span class="o">)</span>
create mode <span class="m">100644</span> dumy-file.txt
$ git push
Counting objects: <span class="m">30</span>, <span class="k">done</span>.
Delta compression using up to <span class="m">12</span> threads.
Compressing objects: <span class="m">100</span>% <span class="o">(</span><span class="m">25</span>/25<span class="o">)</span>, <span class="k">done</span>.
Writing objects: <span class="m">100</span>% <span class="o">(</span><span class="m">30</span>/30<span class="o">)</span>, <span class="m">919</span>.62 KiB <span class="p">|</span> <span class="m">0</span> bytes/s, <span class="k">done</span>.
Total <span class="m">30</span> <span class="o">(</span>delta <span class="m">12</span><span class="o">)</span>, reused <span class="m">0</span> <span class="o">(</span>delta <span class="m">0</span><span class="o">)</span>
remote:
remote: To create a merge request <span class="k">for</span> development, visit:
remote: https://<gitlab-url>/pornohardware/merge_requests/new?merge_request%5Bsource_branch%5D<span class="o">=</span>development
remote:
To code.vandalsweb.com:vandalsweb/pornohardware
d3535db..c45fbfa development -> development
</code></pre></div>
<p>Si nos vamos al Gitlab y pulsamos en <strong>Pipelines</strong> (dentro de nuestro proyecto) veremos algo parecido a esto:</p>
<p><img alt="Gitlab" src="/images/posts/2017-04-24-integracion-continua-en-pelican-usando-gitlab-ci/screenshot_gitlab_pipeline_dev_running.png" title="Stage ejecutándose"></p>
<p>Si os fijáis en el círculo grande que he marcado en naranja veréis cómo vuestro commit (<em>"Cambio de prueba para probar la pipeline"</em>) ha lanzado la <code>build</code>, y en este momento el estado de ejecución de dicha <em>pipeline</em> es <code>running</code>.</p>
<p>Esto significa que el <em>runner</em> ha cogido el <code>commit</code> y ahora mismo está descargando el repositorio y ejecutando el <code>job</code>.</p>
<p>Si esperáis un poco (solo llevará unos segundos) veréis que esa pantalla pasa de esto:</p>
<p><img alt="Gitlab" src="/images/posts/2017-04-24-integracion-continua-en-pelican-usando-gitlab-ci/pipeline_dev_running.png" title="Stage ejecutándose"></p>
<p>a esto otro:</p>
<p><img alt="Gitlab" src="/images/posts/2017-04-24-integracion-continua-en-pelican-usando-gitlab-ci/pipeline_dev_ok.png" title="Stage ejecutada satisfactoriamente"></p>
<p>lo que significa que el <code>job</code> ha terminado correctamente!</p>
<p>Ahora, si quisiéramos pasar estos cambios a producción, solo tendríamos que crear una <code>merge request</code> a la rama <code>master</code> para que se lanzara de nuevo la <em>pipeline</em> (pero esta vez en la rama <code>master</code>, lo que incluirá no solo el <code>job</code> de <code>build</code> sino también el de subir el código a producción y todos los demás).</p>
<p>Para crear la <code>merge request</code> podemos ir a Gitlab y pulsar en el icono <code>Create merge request</code> que aparecerá en el apartado <strong>Project -> Home</strong> de nuestro proyecto</p>
<p><img alt="Gitlab" src="/images/posts/2017-04-24-integracion-continua-en-pelican-usando-gitlab-ci/screenshot_gitlab_merge_request.png" title="Crear 'merge request'"></p>
<p>O directamente hacer <em>click</em> en el enlace que nos apareció cuando hicimos el <code>git push</code> desde la línea de comandos:</p>
<div class="highlight"><pre><span></span><code><span class="o">[</span>...<span class="o">]</span>
remote:
remote: To create a merge request <span class="k">for</span> development, visit:
remote: https://<gitlab-url>/pornohardware/merge_requests/new?merge_request%5Bsource_branch%5D<span class="o">=</span>development
remote:
<span class="o">[</span>...<span class="o">]</span>
</code></pre></div>
<p>En cualquier caso, una vez que lo hagamos y lo aprobemos comenzará la ejecución de la pipeline en la rama <code>master</code>:</p>
<p><img alt="Gitlab" src="/images/posts/2017-04-24-integracion-continua-en-pelican-usando-gitlab-ci/screenshot_gitlab_pipeline_master_running.png" title="Stage ejecutándose"></p>
<p><img class="left" src="/images/posts/2017-04-24-integracion-continua-en-pelican-usando-gitlab-ci/stages_icons_master.png"> Ahora, en lugar de aparecer un solo icono como antes, aparecen tres (porque antes en la rama <code>development</code> solo se ejecutaba un <code>job</code> y ahora en <code>master</code> se ejecutan todos).</p>
<p>Si todo va bien, <code>stage</code> tras <code>stage</code> se irán ejecutando todos los <code>jobs</code> y en un par de minutos (al menos en mi caso) deberíais ver la <em>pipeline</em> completamente terminada y sin errores en ninguno de los <code>jobs</code>:</p>
<p><img alt="Gitlab" src="/images/posts/2017-04-24-integracion-continua-en-pelican-usando-gitlab-ci/pipeline_master_ok.png" title="Stage ejecutada satisfactoriamente"></p>
<p>Si durante (o después) de la ejecución de un <code>job</code> queréis ver qué es lo que está pasando en el contenedor Docker que está ejecutando vuestra <em>pipeline</em>, podéis pulsar en el icono del <code>stage</code> que queráis y podréis ver la <a href="https://es.wikipedia.org/wiki/Entrada_est%C3%A1ndar">salida standard</a> de los comandos que habéis configurado en el <code>.gitlab-ci.yml</code>:</p>
<p><img class="left" src="/images/posts/2017-04-24-integracion-continua-en-pelican-usando-gitlab-ci/screenshot_gitlab_pipeline_stdout_icon.png"></p>
<p><img alt="Gitlab" src="/images/posts/2017-04-24-integracion-continua-en-pelican-usando-gitlab-ci/screenshot_gitlab_pipeline_stdout.png" title="Salida stdout de la ejecución del 'job'"></p>
<p>Y ya está, con solo hacer un <code>git push</code> hemos desencadenado toda una cadena de acciones que han desembocado en una nueva versión de nuestra web en producción de forma automática y controlada...</p>
<p>¿No es increíble poder subir a producción automáticamente nuestros proyectos, estando además tranquilos de que lo que estamos subiendo funciona? (y eso que en este proyecto no tiene sentido tener tests, pero si los tuviera, mucho más tranquilidad aún).</p>
<p>Hoy en día el mercado se mueve a toda velocidad, por lo que hay que minimizar lo máximo posible el tiempo que pasa desde que se tiene una idea hasta que ésta se plasma en un proyecto final y <em>entregable</em>.</p>
<p>Puede que subir un proyecto a producción en cuestión de minutos no te haga rico, pero el hecho de no tardar horas o días en hacerlo seguramente sí que te ahorre tiempo y dinero.</p>
<p>Como siempre, espero que el artículo os haya resultado de utilidad! Y por supuesto, no dudéis en distribuirlo y compartirlo con todo el mundo (pero por favor, cita siempre la fuente original de éste artículo).</p>
<p>Alaaaaaaaaaaaaaaaaaaaaaaa!</p>
<h2>Referencias<a name="refs"></a></h2>
<ul>
<li><a href="https://www.martinfowler.com/articles/continuousIntegration.html">https://www.martinfowler.com/articles/continuousIntegration.html</a></li>
<li><a href="https://martinfowler.com/bliki/ContinuousDelivery.html">https://martinfowler.com/bliki/ContinuousDelivery.html</a></li>
<li><a href="https://gitlab.com/">https://gitlab.com/</a></li>
</ul>Adios Octopress, hola Pelican!2017-03-23T23:24:54+01:002017-03-23T23:24:54+01:00BhEaNtag:pornohardware.com,2017-03-23:/2017/03/23/adios-octopress-hola-pelican/<p>Efectivamente, ha llegado la hora de <em>enterrar</em> a nuestro antiguo <a href="http://octopress.org/">Octopress</a> y dar la bienvenida al nuevo <a href="https://www.getpelican.com">Pelican</a>.
Y no solo porque este último esté hecho en <a href="https://www.python.org/">Python</a> (que me gusta mil veces más que <a href="https://www.ruby-lang.org/es/">Ruby</a>, todo sea dicho) sino porque estoy más que harto de esperar la <em>maldita</em> versión 3 de Octopress desde hace literalmente <strong>más de 2 años</strong>, y no solo no ha salido aún (de hecho, ha pasado más de 1 año desde el último <em>commit</em> que hicieron en cualquiera de las ramas de su repositorio de <a href="https://github.com/imathis/octopress">Github</a>) sino que además sus desarrolladores han anunciado que ésta nueva versión <strong>NO</strong> es compatible con las anteriores, por lo que ni siquiera puedo migrar el blog. Tendría que hacerlo de nuevo desde cero (incluyendo los plugins que he hecho, el <em>theme</em>, etc).</p>
<p>Así que como se suele decir: <em>Con Octopress, va a ser que no</em>...</p>
<p>Efectivamente, ha llegado la hora de <em>enterrar</em> a nuestro antiguo <a href="http://octopress.org/">Octopress</a> y dar la bienvenida al nuevo <a href="https://www.getpelican.com">Pelican</a>.
Y no solo porque este último esté hecho en <a href="https://www.python.org/">Python</a> (que me gusta mil veces más que <a href="https://www.ruby-lang.org/es/">Ruby</a>, todo sea dicho) sino porque estoy más que harto de esperar la <em>maldita</em> versión 3 de Octopress desde hace literalmente <strong>más de 2 años</strong>, y no solo no ha salido aún (de hecho, ha pasado más de 1 año desde el último <em>commit</em> que hicieron en cualquiera de las ramas de su repositorio de <a href="https://github.com/imathis/octopress">Github</a>) sino que además sus desarrolladores han anunciado que ésta nueva versión <strong>NO</strong> es compatible con las anteriores, por lo que ni siquiera puedo migrar el blog. Tendría que hacerlo de nuevo desde cero (incluyendo los plugins que he hecho, el <em>theme</em>, etc).</p>
<p>Así que como se suele decir: <em>Con Octopress, va a ser que no</em>...</p>
<p>Hace un par de semanas decidí dar el paso y comencé la búsqueda de una buena alternativa a Octopress.</p>
<p>Y es una pena, porque Octopress me gustó mucho desde el primer momento que empecé a usarlo (incluso le he dedicado varios <a href="/categories/blogs/">artículos</a>) pero ha llegado el momento de renovarse, que el mundo es muy grande como para <em>atarse</em> a un único generador de sites estáticos.</p>
<p>Comencemos:</p>
<ol>
<li><a href="#whatis">¿Qué son los generadores de sites estáticos?</a></li>
<li><a href="#alternatives">Alternativas a Octopress</a></li>
<li><a href="#pelican">Acerca de Pelican</a></li>
<li><a href="#install">Instalación</a></li>
<li><a href="#configure">Configuración y adaptación</a></li>
<li><a href="#migrate">Migración desde Octopress a Pelican</a></li>
<li><a href="#release">Subida a producción</a></li>
<li><a href="#refs">Referencias</a></li>
</ol>
<h2>¿Qué son los generadores de sites estáticos?<a name="whatis"></a></h2>
<p>Antes de empezar a <em>picar código</em> vamos a asegurarnos de que todos sabemos de lo qué estamos hablando:
Un generador de sites estáticos es un <em>software</em> que, partiendo de archivos de texto formateado, bases de datos o cualquier otro origen de datos, permite generar todas las páginas web que formarían un site de forma estática, para que puedan servirse desde cualquier servidor web sin necesidad de tener servidores de aplicaciones, intérpretes, bases de datos, etc.</p>
<p>Por ejemplo, en el caso de un blog y partiendo de que cada artículo del blog estaría escrito en un archivo (por ejemplo, utilizando <a href="/2014/07/02/markdown-el-lenguaje-de-marcado-para-texto-plano/">Markdown</a>), un generador estático crearía una página principal únicamente en <a href="https://es.wikipedia.org/wiki/HTML">HTML</a> con el listado de artículos, otra página con cada uno de los artículos, etc. de forma que el resultado sería únicamente HTML puro.</p>
<p>Esto permite ahorrar muchos recursos en los servidores, puesto que solo tienen que servir páginas HTML. También se reduce el tiempo necesario para administrar dichos servidores, la complejidad de los mismos, etc.</p>
<p>Muchos de estos generadores de sites permiten también, de forma automatizada, el envío de nuestro código al <em>entorno de producción</em> una vez que el site ha sigo generado.</p>
<p>Vamos a ilustrar todo el proceso con un ejemplo: Esta misma web de <a href="/">pornoHARDWARE.com</a> está hecha utilizando un generador de sites estáticos. Eso significa que cuando yo quiero escribir un nuevo artículo, cojo un ordenador, escribo el texto del artículo (utilizando <em>Markdown</em>) y cuando he terminado, ejecuto un comando en ese mismo ordenador para poder ver el resultado de cómo quedaría dicho artículo en la web. Si todo es correcto y está a mi gusto, ejecuto otro comando y el generador crea todos los archivos necesarios de la web, y después mediante otro comando envío todos esos archivos al servidor donde está alojada la web para que todos los demás usuarios (los cientos de miles de millones que me leéis cada dia xDD) podais acceder y leer el nuevo artículo.</p>
<p>Y durante todo ese proceso no he tenido que crear ninguna base de datos, ni utilizar ningún lenguaje de programación, ni instalar ningún servicio ni hacer absolutamente nada. Simplemente escribo mi artículo y lo subo al servidor. Simple, rápido y <em>barato</em> de mantener.</p>
<p>¿Entonces porqué no todo el mundo usa un generador de sites estáticos? Pues porque obviamente estos generadores tienen ciertas limitaciones con respecto a qué se puede y qué no se puede hacer. Pero si la web que quieres hacer es únicamente un <a href="https://es.wikipedia.org/wiki/Blog">blog</a>, un sitio de noticias, una página personal donde exponer tu currículum o cualquier otro tipo de web en la que los usuarios no necesiten interactuar con ella, un site estático es la opción más rápida, barata y sencilla de mantener.</p>
<h2>Alternativas a Octopress<a name="alternatives"></a></h2>
<p>En el momento en el que empecé a valorar alternativas, mis requisitos a la hora de escoger un nuevo generador de sites estáticos fueron:</p>
<ul>
<li>Facilidad y rapidez de uso: No quiero tener que instalar un montón de librerías, paquetes y dependencias en cada ordenador desde el que quiera construir el site.</li>
<li>Open Source: Obviamente, el proyecto tiene que ser libre y gratuito.</li>
<li>Personalización: Sea el que sea, tiene que permitir total personalización no solo a nivel gráfico, sino también a la facilidad de desarrollar mis propios plugins para extender la funcionalidad original.</li>
<li>Comunidad activa: Para que no me pase como con Octopress, el proyecto tiene que estar <em>vivo</em>. Y con esto me refiero a que no hayan pasado varios años desde la última vez que alguien hizo un <em>commit</em> en el repositorio del proyecto, y que las librerías que usen, las dependencias, etc. estén mínimamente actualizadas.</li>
</ul>
<p>Después de mucho buscar y leer al respecto, encontré varios proyectos que parecían muy interesantes:</p>
<ul>
<li>Nanoc: <a href="https://nanoc.ws">https://nanoc.ws</a></li>
<li>Jekyll: <a href="http://jekyllrb.com/">http://jekyllrb.com/</a></li>
<li>Hugo: <a href="https://gohugo.io/">https://gohugo.io/</a></li>
<li>Sculpin: <a href="https://sculpin.io/">https://sculpin.io/</a></li>
<li>Couscous: <a href="http://couscous.io/">http://couscous.io/</a></li>
<li>Hexo: <a href="https://hexo.io/">https://hexo.io/</a></li>
<li>Pelican: <a href="https://blog.getpelican.com/">https://blog.getpelican.com/</a></li>
</ul>
<p>Hay muchísimos más, por supuesto... pero fueron descartados por diferentes motivos (ser demasiado minoritarios, utilizar lenguajes que no me apetece NADA utilizar, etc). No obstante, si quieres consultar muchos más y comparar todos los generadores estáticos que se te ocurran, échale un ojo a la web <a href="https://www.staticgen.com/">StaticGen</a>, ya que en ella se listan, analizan y comparan decenas y decenas de estos generadores (a mi me ayudó mucho).</p>
<p>Los pros y contras de cada uno, desde mi <em>humilde</em> opinión personal, son:</p>
<h3>Nanoc</h3>
<p>Es uno de los primeros que "analicé", y pese a que me gustó bastante (es un proyecto muy activo, tiene muchísimos colaboradores, etc) ya he tenido <em>Ruby</em> suficiente con <em>Octopress</em> como para un par de vidas, así que lo descarté.</p>
<h3>Jekyll</h3>
<p>Sin duda el proyecto de generación de sites estáticos más famoso y utilizado de todos... pero pasa lo mismo que con Nanoc: odio Ruby, lo siento.
Además, <em>Octopress</em> está basado precisamente en Jekyll, por lo que puestos a cambiar, quería que fuera algo diferente.</p>
<h3>Hugo</h3>
<p>Su desarrollador es el creador del proyecto <a href="https://github.com/spf13/spf13-vim">spf13-vim</a>, la <em>distribución</em> de plugins, opciones y personalizaciones para <a href="http://www.vim.org/">VIM</a> más genial que he visto (de hecho, mi <a href="https://code.vandalsweb.com/bhean/vimprofile">configuración personal de VIM</a> se basa en muchos de los plugins y adaptaciones de ese proyecto), por lo que a priori despertó mucho interés en mi.</p>
<p>Además, parece que ahora mismo es "el proyecto de moda", con una comunidad muy grande y activa, así como abundante documentación, themes, etc. Peeeeeeeero (algo tenía que tener) está hecho en <a href="https://golang.org/">Go</a>, y la verdad es que no tengo nada contra Go, pero si contra los desgraciados de <a href="http://huyedelacorporacion.com/">Google</a> (que son quienes desarrollan Go)... así que como TODO lo que tiene que ver con ellos, no pienso tocarlo ni con un palo, por lo tanto: Hugo descartado (Fuck Google!)</p>
<h3>Sculpin</h3>
<p>Tenía muy buena pinta. Una gran comunidad, un montón de documentación, etc... pero había algunas cosas que no estaban <em>maduras</em> aún (según su propia documentación), aunque el motivo principal para descartarlo fué precisamente que está hecho en <a href="http://www.php.net/">PHP</a> (uno de los lenguajes que mejor conozco) y como dije al principio, uno de los motivos de este cambio era precisamente el de aprender cosas nuevas.</p>
<h3>Couscous</h3>
<p>La verdad es que no investigué este proyecto demasiado, ya que al parecer únicamente está pensado para generar el site en <a href="https://pages.github.com/">Github Pages</a>, y alojar webs en servidores de terceros es precisamente lo último que quiero hacer en este momento...</p>
<h3>Hexo</h3>
<p>Lo descarté muy rápido, tampoco lo examiné en profundidad ya que al igual que los anteriores está hecho en <em>Ruby</em>, utiliza <em>Github Pages</em>, etc. Es decir, completamente al revés de lo que busco.</p>
<h3>Pelican</h3>
<p>Pese a que en un primer momento pensé que no era lo que estaba buscando (sobre todo al ver su <em>espartana</em>, por no decir <em>espantosa</em> <a href="https://blog.getpelican.com/">página web</a>) a medida que fuí leyendo e investigando un poco me fué gustando cada vez mas.</p>
<p>Desarrollado en <a href="https://www.python.org/">Python</a> (otro de mis lenguajes favoritos, aunque aún no puedo decir que lo tenga completamente dominado) y con una enorme comunidad, constantes aportaciones en su repositorio, muchísimos <em>themes</em>, plugins, etc, se convirtió en el generador de sites elegido (aunque ahora que lo conozco bien, reconozco que aún le faltan algunas <em>cosillas</em>... pero nada grave, irreparable o que no pueda hacer uno mismo para además contribuir con el proyecto).</p>
<p>Por lo tanto, el elegido fue <strong>Pelican</strong>...</p>
<h2>Acerca de Pelican<a name="pelican"></a></h2>
<p>La primera versión de Pelican fué liberada en 2010 por su autor, <a href="https://blog.notmyidea.org/">Alexis Métaireau</a>. Está escrito en <em>Python</em>, y tiene una serie de características que lo hacen muy atractivo para cualquiera que quiera tener un blog o página web sin tener que montar toda la estructura "típica" de las webs dinámicas convencionales (base de datos, servidores de aplicaciones, etc).</p>
<p>Es compatible con varios lenguajes de formateado de texto, como por ejemplo <a href="https://daringfireball.net/projects/markdown/">Markdown</a>, <a href="http://docutils.sourceforge.net/rst.html">reStructuredText</a>, <a href="https://www.w3.org/html/">HTML</a> o <a href="http://www.methods.co.nz/asciidoc/">AsciiDoc</a>, y utiliza <a href="http://jinja.pocoo.org/">Jinja</a> como sistema de plantillas, lo cual es genial porque facilita enormemente la creación de <a href="http://www.pelicanthemes.com/"><em>themes</em></a>.</p>
<p>Permite el resaltado de sintaxis (para los bloques de código que queramos escribir en nuestros artículos) con <a href="http://pygments.org/">Pygments</a>, el cual soporta prácticamente todos los lenguajes de programación y formatos que existen.</p>
<p>Además, es uno de los pocos que está preparado para soportar <em>multilenguaje</em>. Es decir, no solo la <em>interface</em> puede ser multilenguaje gracias a <a href="https://es.wikipedia.org/wiki/Gettext">gettext</a>, sino que también podemos escribir un artículo en varios idiomas, y Pelican nos mostrará uno u otro en función del idioma que hayamos seleccionado para ver la web.</p>
<p>También está preparado para subir de forma <em>automatizada</em> el site que hagamos generado por FTP, por SSH, a una cuenta de <em>Dropbox</em> (aunque os aconsejo que <a href="http://www.drop-dropbox.com/">NO uséis Dropbox</a>), a un <a href="https://aws.amazon.com/es/s3/">bucket S3</a> de <a href="https://aws.amazon.com/es">AWS</a>, a un contenedor de <a href="https://www.rackspace.com/es">Rackspace</a> o incluso a <a href="https://pages.github.com/">GitHub Pages</a>.</p>
<p>La documentación no está mal, aunque tampoco es <em>excesivamente buena</em> (muchas cosas tendrás que buscarlas en Internet por tu cuenta o adentrarte en el propio código fuente del proyecto Pelican, ya que o no vienen reflejadas en la documentación, o viene reflejadas <em>a medias</em>), pero en cualquier caso resulta de utilidad, y se puede consultar la de la última versión estable aquí: <a href="http://docs.getpelican.com/en/stable/">http://docs.getpelican.com/en/stable/</a></p>
<h2>Instalación<a name="install"></a></h2>
<p>Hay algunos paquetes que, aunque no son obligatorios para que Pelican funcione, se recomienda su instalación para poder utilizar algunas funcionalidades <em>extra</em>. Estos paquetes son:</p>
<ul>
<li><a href="http://pygments.org">Pygments</a>: Para resaltar la sintaxis de los bloques de código fuente.</li>
<li><a href="https://pythonhosted.org/Markdown/">Markdown</a>: Para escribir los artículos utizando este formato.</li>
<li><a href="https://pypi.python.org/pypi/typogrify">Typogrify</a>: Para mejorar el rendimiento de las tipografías utilizadas en las plantillas.</li>
</ul>
<p>Dependiendo del método de instalación que utilicemos se instalarán automáticamente (ya que estarán marcados como <em>dependencias</em> de Pelican) o en caso contrario habrá que instalarlos manualmente.</p>
<p>Estos métodos de instalación son:</p>
<ul>
<li>Utilizando <a href="https://es.wikipedia.org/wiki/Pip_%28administrador_de_paquetes%29">pip</a>.</li>
<li>Utilizando el gestor de paquetes de la distribución que estemos utilizando (<a href="https://es.wikipedia.org/wiki/Advanced_Packaging_Tool">apt</a>, <a href="https://es.wikipedia.org/wiki/Yellowdog_Updater,_Modified">yum</a>, etc)</li>
<li>Clonando el proyecto desde su repositorio de <a href="https://github.com/getpelican/pelican">Github</a>.</li>
</ul>
<p>Ellos recomiendan instalarlo a través de <em>pip</em>, para lo cual (si ya tenemos <em>pip</em> instalado, obviamente) debería bastar con:</p>
<div class="highlight"><pre><span></span><code>$ sudo pip install pelican
$ sudo pip install Markdown
$ sudo pip install typogrify
</code></pre></div>
<p>Pero yo prefiero utilizar el gestor de paquetes de nuestra distribución, ya que aunque de ésta forma seguramente no tendremos la última versión (porque ésta dependerá del <em>mantenedor</em> de dicho paquete, no de la gente de Pelican) tendremos la comodidad de saber que toda la gestión, actualización, etc. de Pelican y de sus dependencias será realizada por nuestro gestor de paquetes junto con la del resto del sistema, y no tendremos que preocuparnos de instalar las dependencias, hacer los binarios accesibles para cualquier usuario de la máquina que estemos usando, etc.</p>
<p>Por lo tanto, si utilizamos distribuciones <em>hechas y derechas</em> (como <a href="https://www.debian.org/">Debian</a>, por ejemplo) bastaría con ejecutar:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install pelican python-typogrify
</code></pre></div>
<p>En <a href="https://www.centos.org/">CentOS</a> (y supongo que en <a href="https://www.redhat.com">RedHat</a> también) estos paquetes no están disponible en sus repositorios oficiales, por lo que si utilizáis estas distribuciones os recomiendo que los instaléis a través de <em>pip</em> (y que os cambiéis a Debian, por supuesto... que ya va siendo hora, pardillos!)</p>
<p>Para actualizar Pelican a la última versión, en caso de haberlo instalado a través de <em>pip</em>, bastará con ejecutar:</p>
<div class="highlight"><pre><span></span><code>$ sudo pip install --upgrade pelican
</code></pre></div>
<h2>Configuración y adaptación<a name="configure"></a></h2>
<p>Independientemente de cómo hayamos instalado Pelican (con <em>pip</em> o con un gestor de paquetes) una vez lo hayamos hecho dispondremos de un par de nuevos <em>comandos</em> en nuestro sistema que nos permitirán generar la estructura de directorios y archivos que usa Pelican para crear un nuevo site, seleccionar el <em>theme</em> que queremos utilizar, etc.</p>
<p>En primer lugar vamos a generar la estructura de directorios y archivos. Para ello utilizaremos el comando <code>pelican-quickstart</code>.</p>
<p>Vamos a crear un nuevo site que nos sirva de ejemplo, al cual (en un alarde de imaginación sin precedentes) llamaremos <em>superproyectoestatico</em>.</p>
<p>Lo primero será crear un directorio donde meter toda la estructura de archivos que necesitamos:</p>
<div class="highlight"><pre><span></span><code>$ mkdir -p ~/projects/superproyectoestatico
$ <span class="nb">cd</span> ~/projects/superproyectoestatico
</code></pre></div>
<p>Ahora ejecutamos el comando <code>pelican-quickstart</code>, el cual nos hará una serie de preguntas para generar el proyecto según nuestras necesidades:</p>
<div class="highlight"><pre><span></span><code>$ pelican-quickstart
</code></pre></div>
<p>Nos mostrará algo parecido a ésto:</p>
<p><img src="/images/posts/adios-octopress-hola-pelican/terminal_01.png"></p>
<p>Son bastante preguntas, (si, es un verdadero interrogatorio), pero una vez contestadas todas, prácticamente tendremos nuestro site listo, por lo que merece la pena ir contestándolas paso a paso para que la configuración sea la mejor posible. Además, algunas preguntas nos las mostrará dependiendo de lo que hayamos contestado en otras, por lo que dependiendo de nuestras respuestas nos hará más o menos preguntas (es decir, únicamente si le decimos que queremos usar un servidor <a href="https://es.wikipedia.org/wiki/File_Transfer_Protocol">FTP</a> para subir nuestro site nos preguntará también el nombre de dicho servidor, el usuario para conectarse a él, etc. Sino, lógicamente no nos preguntará esos últimos datos). Así que no te asustes si ves muchas preguntas en esta lista, seguramente no todas serán necesarias en tu caso.</p>
<h4>Preguntas sobre la configuración de nuestro site</h4>
<p>Las preguntas que nos irá haciendo son bastante simples, no deberías tener ningún problema con ninguna de ellas (a no ser que no tengas ni idea de inglés xDD). No obstante, vamos a verlas una por una.</p>
<ol>
<li>
<p><code>Where do you want to create your new web site?</code> <em>¿Dónde quieres crear el nuevo site?.</em>
Aquí tenemos que decirle la ruta donde queremos que nos guarde los archivos que va a generar. Como ya estamos dentro del directorio que queremos, en <code>~/projects/superproyectoestatico</code>, pulsamos <code>INTRO</code> para aceptar el valor por defecto <code>.</code>.</p>
</li>
<li>
<p><code>What will be the title of this web site?</code> <em>¿Cuál será el título de este site?.</em>
Aquí nos está preguntando por el nombre que le vamos a dar a nuestro nuevo site. Por lo tanto, en nuestro caso pondremos <code>superproyectoestatico</code>.</p>
</li>
<li>
<p><code>Who will be the author of this web site?</code> <em>¿Quién será el autor de este site?.</em>
Aquí pondremos el nombre del autor del site, es decir, nuestro nombre. No confundir con el autor de cada artículo que vayamos a escribir, ya que éstos pueden ser el mismo u otros diferentes (lo veremos más adelante).</p>
</li>
<li>
<p><code>What will be the default language of this web site?</code> <em>¿Cuál será el idioma por defecto?.</em>
Aquí hay que indicar cuál va a ser el idioma por defecto de nuestro site, en formato <a href="https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes">ISO 639-1</a>, es decir, en formato <em>2 carácteres</em>. Por ejemplo, para seleccionar <em>español</em> pondremos <code>es</code>, para seleccionar <em>inglés</em> pondremos <code>en</code>, etc.</p>
</li>
<li>
<p><code>Do you want to specify a URL prefix? e.g., http://example.com (Y/n)</code> <em>¿Quieres especificar un prefijo en las URLs?</em>
Aquí tenemos que decir si queremos anteponer algo a todas las URLs que se generen en nuestro site (por ejemplo, un dominio concreto, un subdirectorio dentro de dicho dominio, etc).</p>
</li>
<li>
<p><code>What is your URL prefix? (see above example; no trailing slash)</code> <em>¿Cuál es el prefijo en las URLs que quieres usar? (sin barra <code>/</code> al final).</em>
Si en la anterior pregunta hemos seleccionado <code>Y</code> (es decir, que SI queremos anteponer algo a las URLs de nuestro sitio) aquí tendremos que especificar qué es lo que queremos anteponer. Normalmente se suele indicar aquí el dominio (incluyendo el protocolo <code>http</code> o <code>https</code> según corresponda). Por ejemplo, en nuestro caso sería: <code>http://www.superproyectoestatico.com</code> (sin barra al final).</p>
</li>
<li>
<p><code>Do you want to enable article pagination? (Y/n)</code> <em>¿Quieres activar la paginación del listado de artículos?.</em>
Aquí indicaremos si queremos o no que la lista de artículos que tengamos aparezca paginada o no. Dependerá del uso que vayamos a dar a nuestra web, pero si vamos a tener más de 5 o 10 artículos, os recomiendo que utilicéis la paginación.</p>
</li>
<li>
<p><code>How many articles per page do you want? [10]</code> <em>¿Cuántos artículos por página quieres ver?.
En caso de haber elegido _si</em> en la pregunta anterior, ahora hay que especificar cuántos artículos quieres que haya en cada página.</p>
</li>
<li>
<p><code>What is your time zone? [Europe/Paris]</code> <em>¿Cuál es la zona horaria?.</em>
Aquí hay que introducir la zona horaria en la que estemos. En mi caso sería <em>Europe/Madrid</em>.</p>
</li>
<li>
<p><code>Do you want to generate a Fabfile/Makefile to automate generation and publishing? (Y/n)</code> <em>¿Quieres generar archivos Fabfile/Makefile para automatizar tareas de generación y publicación?.</em>
Aquí nos está preguntando si queremos que nos genere un archivo <a href="https://es.wikipedia.org/wiki/Make">Makefile</a> y otro <a href="http://www.fabfile.org">Fabfile</a> para <em>automatizar</em> algunas de las tareas de creación/administración del site. Personalmente me gusta mucho este sistema, por lo que te recomiendo que lo hagas (más adelante explicaré cómo usar dicho <em>Makefile</em>, por ejemplo).</p>
</li>
<li>
<p><code>Do you want an auto-reload & simpleHTTP script to assist with theme and site development? (Y/n)</code> <em>¿Quieres generar un sencillo servidor web integrado para ayudarte con el desarrollo del site o del theme?.</em>
Si seleccionamos <code>yes</code> en este caso, se generará un pequeño <a href="https://es.wikipedia.org/wiki/Script">script</a> para <em>levantar</em> un <a href="https://es.wikipedia.org/wiki/Servidor_web">servidor web</a> que permita ver cómo va quedando nuestro site, lo que nos ayudará muchísimo durante el proceso de desarrollo o durante la creación de un nuevo <em>theme</em>.</p>
</li>
</ol>
<h4>Preguntas sobre el paso a producción <em>(deploy)</em> de nuestro site</h4>
<p>Continuamos con las preguntas, ésta vez sobre cómo/dónde queremos enviar nuestro site una vez generado (aunque parezcan muchas preguntas, normalmente solo tendremos un único sitio al que subir el site, por lo que todas las demás opciones no serán necesarias</p>
<ol>
<li>
<p><code>Do you want to upload your website using FTP? (y/N)</code> <em>¿Quieres subir el site a un servidor FTP?.</em>
Esta opción es por si queremos subir nuestro site a producción (cuando esté acabado, claro) mediante FTP.</p>
</li>
<li>
<p><code>What is the hostname of your FTP server? [localhost]</code> <em>¿Cuál es el nombre del servidor FTP donde subir el site?</em>
Si hemos contestado <code>yes</code> a <em>subir el site a un FTP</em>, ahora debemos indicar el <code>host</code> de dicho servidor FTP.</p>
</li>
<li>
<p><code>What is your username on that server?</code> <em>¿Cuál es el nombre de usuario de ese servidor FTP?.</em>
Si hemos contestado <code>yes</code> a <em>subir el site a un FTP</em>, ahora debemos indicar el <code>usuario</code> para conectarnos a dicho servidor FTP.</p>
</li>
<li>
<p><code>Where do you want to put your web site on that server?</code> <em>¿A qué directorio del servidor FTP quieres subir el site?*:
Si hemos contestado <code>yes</code> a _subir el site a un FTP</em>, ahora debemos indicar el <code>directorio</code> dentro del servidor FTP donde queremos subir nuestro site.</p>
</li>
<li>
<p><code>Do you want to upload your website using SSH? (y/N)</code> <em>¿Quieres subir el site a un servidor SSH?.</em>
Igual que la anterior, pero mediante <a href="https://es.wikipedia.org/wiki/Secure_Shell">SSH</a> (mejor dicho, mediante <a href="https://es.wikipedia.org/wiki/Secure_Copy">SCP</a>).</p>
</li>
<li>
<p><code>What is the hostname of your SSH server? [localhost]</code> <em>¿Cuál es el nombre del servidor SSH?.</em>
Si hemos contestado <code>yes</code> a <em>subir el site por SSH</em>, ahora debemos indicar el <code>host</code> de dicho servidor SSH.</p>
</li>
<li>
<p><code>What is the port of your SSH server? [22]</code> <em>¿Cuál es el puerto del servidor SSH?.</em>
Si hemos contestado <code>yes</code> a <em>subir el site por SSH</em>, aquí podemos especificar el puerto en el que está <em>escuchando</em> el servidor SSH al que subiremos nuestro site.</p>
</li>
<li>
<p><code>What is your username on that server? [root]</code> <em>¿Cuál es el nombre del usuario para conectar con el servidor SSH?.</em>
De nuevo, si hemos contestado <code>yes</code> a <em>subir el site por SSH</em>, ahora debemos indicar aquí el nombre del usuario con el que nos conectaremos.</p>
</li>
<li>
<p><code>Where do you want to put your web site on that server? [/var/www]</code> <em>¿A qué directorio quieres subir el site en ese servidor?.</em>
Una vez más, si hemos contestado <code>yes</code> a <em>subir el site por SSH</em>, aquí debemos indicar el directorio dentro del servidor SSH al que queremos subir nuestro site.</p>
</li>
<li>
<p><code>Do you want to upload your website using Dropbox? (y/N)</code> <em>¿Quieres subir el site a una cuenta de _Dropbox</em>?.<em>
Podemos subir también el site generado a una cuenta de _Dropbox</em>, pero como ya dije antes, os aconsejo que <a href="http://www.drop-dropbox.com/">NO uséis Dropbox</a> por tener a una <a href="https://es.wikipedia.org/wiki/Condoleezza_Rice">fascista</a> como dirigente, así que no voy a explicar la configuración relativa a ésta opción.</p>
</li>
<li>
<p><code>Do you want to upload your website using S3? (y/N)</code> <em>¿Quieres subir el site a un bucket S3?.</em>
Si queremos subir nuestro site directamente a un bucket de S3, selecciona <code>yes</code>.</p>
</li>
<li>
<p><code>What is the name of your S3 bucket? [my_s3_bucket]</code> <em>¿Cuál es el nombre del bucket de S3?.</em>
Si hemos contestado <code>yes</code> a <em>subir el site a S3</em>, aquí debemos indicar el nombre del bucket al que queremos subir el site.</p>
</li>
<li>
<p><code>Do you want to upload your website using Rackspace Cloud Files? (y/N)</code> <em>¿Quieres subir el site a Rackspace?.</em>
Selecciona <code>yes</code> si quieres subir el site generado a <a href="https://www.rackspace.com/es">Rackspace</a>.</p>
</li>
<li>
<p><code>What is your Rackspace Cloud username? [my_rackspace_username]</code> <em>¿Cuál es el nombre de usuario de Rackspace?.</em>
Si hemos contestado <code>yes</code> a <em>subir el site a Rackspace</em>, aquí debemos indicar nuestro nombre de usuario de <em>Rackspace</em>.</p>
</li>
<li>
<p><code>What is your Rackspace Cloud API key? [my_rackspace_api_key]</code> <em>¿Cuál es tu clave API de Rackspace?.</em>
De nuevo, si hemos contestado <code>yes</code> a <em>subir el site a Rackspace</em>, aquí debemos indicar la clave API que vayamos a usar.</p>
</li>
<li>
<p><code>What is the name of your Cloud Files container? [my_cloudfiles_container]</code> <em>¿Cuál es el nombre del contenedor?.</em>
Una vez más, si hemos contestado <code>yes</code> a <em>subir el site a Rackspace</em>, aquí debemos indicar el nombre del contenedor al que queramos subirlo.</p>
</li>
<li>
<p><code>Do you want to upload your website using GitHub Pages? (y/N)</code> <em>¿Quieres subir el site a GitHub Pages?.</em>
También podemos subir el site a GitHub Pages contestando <code>yes</code> a esta opción.</p>
</li>
<li>
<p><code>Is this your personal page (username.github.io)? (y/N)</code> <em>¿Es ésta tu página personal (nombreusuario.github.io)?.</em>
Si hemos contestado <code>yes</code> a <em>subir el site a GitHub Pages</em> y la dirección de nuestra página personal es nombreusuario.github.io, contesta <code>yes</code> a esta pregunta.</p>
</li>
</ol>
<p>Después del interminable interrogatorio, Pelican generará la estructura de archivos y directorios necesarios para crear el site en el directorio que le hayamos indicado en la primera pregunta.</p>
<p>Los archivos y directorios que nos habrá generado son:</p>
<div class="highlight"><pre><span></span><code>~/projects/superproyectoestatico
├── content/
├── output/
├── develop_server.sh
├── fabfile.py
├── Makefile
├── pelicanconf.py
└── publishconf.py
</code></pre></div>
<ul>
<li>
<p>Directorio <code>content/</code>
En este directorio es donde guardaremos los artículos que escribamos, las páginas de nuestra web, las imágenes que mostraremos en ella, etc. En definitiva, todo el <em>contenido</em> que usaremos en nuestro site. Como aún no tenemos ningún contenido estará vacío.</p>
</li>
<li>
<p>Directorio <code>output/</code>
En este directorio es donde Pelican generará todo nuestro site. Es decir, este directorio será el que tendremos que <em>subir</em> a nuestro servidor para poder lanzar nuestro site <em>a produccion</em>. Dicho de otra forma, este directorio será el <code>DocumentRoot</code> de nuestro servidor web, por lo que ahora mismo esta completamente vacío.</p>
</li>
<li>
<p>Archivo <code>develop_server.sh</code>
Este script escrito en <a href="https://es.wikipedia.org/wiki/Bash">Bash</a> (y que solo aparecerá si durante el proceso de configuración hemos respondido afirmativamente a la pregunta <code>Do you want an auto-reload & simpleHTTP script to assist with theme and site development? (Y/n)</code>) es el que nos permitirá ir viendo cómo está quedando nuestro site sin necesidad de tener que subirlo a ningún servidor para probarlo.</p>
</li>
<li>
<p>Archivos <code>fabfile.py</code> y <code>Makefile</code>
Estos 2 archivos (el primero para <a href="http://www.fabfile.org">Fabric</a> y el segundo para <a href="https://es.wikipedia.org/wiki/Make">Make</a>) (y que al igual que en el caso anterior, solo aparecerán si durante el proceso de configuración hemos respondido afirmativamente a la pregunta <code>Do you want an auto-reload & simpleHTTP script to assist with theme and site development? (Y/n)</code>) contienen <em>comandos</em> para ejecutar mediante Python o Make (respectivamente) acciones de Pelican, como por ejemplo generar el site, limpiar los archivos temporales, subir el site a nuestro entorno de producción, etc.</p>
</li>
<li>
<p>Archivo <code>pelicanconf.py</code>
Este es el archivo con la configuración principal de Pelican. Todas las opciones y personalizaciones sobre nuestro site estarán aquí. Se genera en base a lo que hayamos respondido en el <em>interrogatorio</em> del proceso de configuración. Lo veremos en detalle más adelante.</p>
</li>
<li>
<p>Archivo <code>publishconf.py</code>
En este archivo es donde está la configuración sobre la publicación del site, es decir, los datos que introducimos durante el <em>interrogatorio</em> sobre los servidores y servicios donde vamos a subir el site una vez terminado (es decir, la configuración sobre el entorno de producción).</p>
</li>
</ul>
<p>Vamos a añadir contenido a nuestro nuevo site. Supongamos que es un blog de noticias, por lo que empecemos escribiendo un pequeño artículo.</p>
<p>Como comenté anteriormente, se pueden escribir los artículos y páginas de Pelican utilizando Markdown, reStructuredText, AsciiDoc, etc. así que podeis hacerlo con el lenguaje de formato de texto que queráis.</p>
<p>Si no sabéis por cuál decidiros, os recomiento Markdown tanto por facilidad de uso como por su velocidad de aprendizaje (enseguida os hareis con él). Para saber cómo se haría con los otros lenguajes, podéis echarle un ojo a la <a href="http://docs.getpelican.com/en/stable/content.html">documentación oficial</a>.</p>
<p>Por lo tanto, creamos un subdirectorio llamado <code>posts/</code> dentro del directorio <code>content/</code>. Ahí es donde vamos a ir metiendo todos los artículos que escribamos en nuestro site:</p>
<div class="highlight"><pre><span></span><code>$ mkdir ~/projects/superproyectoestatico/content/posts
</code></pre></div>
<p>Ahora, abrimos nuestro editor favorito y comenzamos a escribir nuestro artículo utilizando esta plantilla como base (todos los artículos deben basarse en ella). Recordad que vale cualquier editor de texto, no hace falta usar un <a href="https://es.wikipedia.org/wiki/Entorno_de_desarrollo_integrado">IDE especializado</a> porque precisamente una de las ventajas de los generadores de sites estáticos es que el contenido se añade simplemente añadiendo archivos de texto plano:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">2017-04-02-nuestra-primera-noticia.markdown</span><a href='/files/adios-octopress-hola-pelican/2017-04-02-nuestra-primera-noticia.markdown'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="n">Title</span><span class="o">:</span> <span class="n">Nuestra</span> <span class="n">primera</span> <span class="n">noticia</span><span class="o">!</span>
<span class="n">Date</span><span class="o">:</span> <span class="mi">2017</span><span class="o">-</span><span class="mi">04</span><span class="o">-</span><span class="mi">02</span> <span class="mi">03</span><span class="o">:</span><span class="mi">33</span>
<span class="n">Modified</span><span class="o">:</span> <span class="mi">2017</span><span class="o">-</span><span class="mi">04</span><span class="o">-</span><span class="mi">02</span> <span class="mi">03</span><span class="o">:</span><span class="mi">33</span>
<span class="n">Category</span><span class="o">:</span> <span class="n">Noticias</span>
<span class="n">Tags</span><span class="o">:</span> <span class="n">pelican</span><span class="o">,</span> <span class="n">internet</span>
<span class="n">Authors</span><span class="o">:</span> <span class="n">BhEaN</span>
<span class="n">Summary</span><span class="o">:</span> <span class="n">Esta</span> <span class="n">es</span> <span class="n">la</span> <span class="n">primera</span> <span class="n">noticia</span> <span class="n">que</span> <span class="n">hacemos</span> <span class="n">en</span> <span class="n">nuestro</span> <span class="n">nuevo</span> <span class="n">site</span><span class="o">!</span>
<span class="n">Nuestra</span> <span class="n">primera</span> <span class="n">noticia</span> <span class="n">trata</span> <span class="n">de</span> <span class="n">blablabla</span><span class="o">,</span> <span class="n">hablaremos</span> <span class="n">de</span> <span class="n">blablabla</span> <span class="n">y</span> <span class="n">comentaremos</span> <span class="n">todo</span> <span class="n">lo</span> <span class="n">relativo</span> <span class="n">a</span> <span class="n">los</span> <span class="n">blablabla</span> <span class="n">porque</span> <span class="n">es</span> <span class="n">muy</span> <span class="n">importante</span> <span class="n">que</span> <span class="n">haya</span> <span class="n">blablablabla</span> <span class="n">y</span> <span class="n">todo</span> <span class="n">eso</span><span class="o">.</span>
</code></pre></div>
</figure>
<p>Os recomiendo que nombréis los artículos que escribáis siguiendo el formato de <code>año-mes-dia-titulo.markdown</code> (en el título obviamente hay que sustituir por guiones los espacios en blanco y caracteres especiales, así como quitar acentos, mayúsculas, etc), ya que os será mucho más claro encontrar uno en concreto cuando tengáis muchos, y en los listados que hagáis dentro de ese directorio podréis verlos ordenados según su fecha.</p>
<p>Por lo tanto, guardamos el archivo con el nombre <code>2017-04-02-nuestra-primera-noticia.markdown</code> en el directorio <code>content/posts/</code>.</p>
<p>Vamos a escribir una segunda noticia para que haya algo de contenido antes de generar nuestro site. De nuevo utilizamos la plantilla anterior para escribir otro artículo:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">2017-04-03-la-segunda-noticia-de-nuestra-web.markdown</span><a href='/files/adios-octopress-hola-pelican/2017-04-03-la-segunda-noticia-de-nuestra-web.markdown'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="n">Title</span><span class="o">:</span> <span class="n">La</span> <span class="n">segunda</span> <span class="n">noticia</span> <span class="n">de</span> <span class="n">nuestra</span> <span class="n">web</span>
<span class="n">Date</span><span class="o">:</span> <span class="mi">2017</span><span class="o">-</span><span class="mi">04</span><span class="o">-</span><span class="mi">03</span> <span class="mi">13</span><span class="o">:</span><span class="mi">27</span>
<span class="n">Modified</span><span class="o">:</span> <span class="mi">2017</span><span class="o">-</span><span class="mi">04</span><span class="o">-</span><span class="mi">03</span> <span class="mi">13</span><span class="o">:</span><span class="mi">27</span>
<span class="n">Category</span><span class="o">:</span> <span class="n">Noticias</span>
<span class="n">Tags</span><span class="o">:</span> <span class="n">pelican</span><span class="o">,</span> <span class="n">markdown</span>
<span class="n">Authors</span><span class="o">:</span> <span class="n">BhEaN</span>
<span class="n">Summary</span><span class="o">:</span> <span class="n">Esta</span> <span class="n">es</span> <span class="n">la</span> <span class="n">segunda</span> <span class="n">noticia</span> <span class="n">que</span> <span class="n">escribimos</span> <span class="n">para</span> <span class="n">probar</span> <span class="n">nuestra</span> <span class="n">nueva</span> <span class="n">web</span>
<span class="n">En</span> <span class="n">esta</span> <span class="n">segunda</span> <span class="n">noticia</span> <span class="n">vamos</span> <span class="n">a</span> <span class="n">contaros</span> <span class="n">todo</span> <span class="n">lo</span> <span class="n">relativo</span> <span class="n">a</span> <span class="n">blablabla</span> <span class="n">que</span> <span class="n">podais</span> <span class="n">imaginar</span><span class="o">,</span> <span class="n">porque</span> <span class="n">cuando</span> <span class="n">sepais</span> <span class="n">que</span> <span class="n">blablabla</span> <span class="n">y</span> <span class="n">que</span> <span class="n">blablabla</span> <span class="n">ya</span> <span class="n">sera</span> <span class="n">demasiado</span> <span class="n">tarde</span> <span class="n">para</span> <span class="n">blablablabla</span><span class="o">.</span>
</code></pre></div>
</figure>
<p>Nuestro árbol de archivos y directorios ahora mismo será algo parecido a ésto:</p>
<div class="highlight"><pre><span></span><code>~/projects/superproyectoestatico
├── content/
│ └── posts/
│ ├── 2017-04-02-nuestra-primera-noticia.markdown
│ └── 2017-04-03-la-segunda-noticia-de-nuestra-web.markdown
├── output/
├── develop_server.sh
├── fabfile.py
├── Makefile
├── pelicanconf.py
└── publishconf.py
</code></pre></div>
<p>Ahora que ya tenemos un par de artículos, podemos decirle a Pelican que construya el site para ir viendo cómo va quedando.</p>
<p>Lo primer que tenemos que hacer es decirle dónde y con qué nombre tenemos los artículos que queremos incluir en nuestro site, por lo que editamos el archivo de configuración de Pelican ('pelicanconf.py`) y añadimos la línea:</p>
<div class="highlight"><pre><span></span><code><span class="n">ARTICLE_PATHS</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'posts'</span><span class="p">]</span>
</code></pre></div>
<p>Esta ruta es relativa a la ruta que haya en la variable <code>PATH</code> (que por defecto es <code>content</code>), por lo que con esa línea le estaríamos diciendo a Pelican que nuestros artículos están en el directorio <code>content/posts</code>. En este punto ya podríamos generar el site para ver cómo va quedando.</p>
<p>Para ello hay varias formas, por ejemplo, usando el comando de Pelican:</p>
<div class="highlight"><pre><span></span><code>$ pelican
</code></pre></div>
<p>O usando el Makefile (si lo tenemos):</p>
<div class="highlight"><pre><span></span><code>$ make html
</code></pre></div>
<p>El ejecutar uno de estos dos comandos, Pelican comenzará a generar nuestro site. Si todo ha ido bien, veremos que ha generado una serie de archivos y directorios dentro del directorio <code>output/</code>:</p>
<div class="highlight"><pre><span></span><code>~/projects/superproyectoestatico/output
├── 2017/
│ └── 04/
│ ├── 02/
│ │ └── nuestra-primera-noticia/
│ │ └── index.html
│ └── 03/
│ └── la-segunda-noticia-de-nuestra-web/
│ └── index.html
├── author/
│ └── bhean.html
├── category/
│ └── noticias.html
├── tag/
│ ├── internet.html
│ ├── markdown.html
│ └── pelican.html
├── theme/
│ ├── css/
│ │ ├── main.css
│ │ ├── pygments.css
│ │ └── ...
│ └── images/
│ └── icons/
│ ├── aboutme.png
│ ├── rss.png
│ └── ...
├── archives.html
├── authors.html
├── categories.html
├── index.html
└── tags.html
</code></pre></div>
<p>Esos archivos son los que forman nuestro site.</p>
<p>Si os fijáis, Pelican ha guardado los artículos siguiendo una ruta basada en la fecha que hemos especificado en la plantilla de cada archivo Markdown, concretamente en la fecha que hemos puesto como valor de la directiva <code>Date:</code> de cada uno de los dos archivos Markdown que hemos escrito.</p>
<p>Pelican guardará entonces cada artículo usando el formato <code>año/mes/dia/titulo/index.html</code>, de forma que para acceder a la página con la primera de nuestras noticias, tendremos que ir a la URL <a href="http://localhost/2017/04/02/nuestra-primera-noticia">http://localhost/2017/04/02/nuestra-primera-noticia</a> lo cual es una URL genial desde el punto de vista del <a href="https://es.wikipedia.org/wiki/Posicionamiento_en_buscadores">SEO</a> ya que de esta forma facilitamos que los buscadores indexen mejor las URLs de nuestro site (esto se conoce como <a href="https://es.wikipedia.org/wiki/URL_sem%C3%A1ntica">URLs semánticas</a>, o <em>friendly URLs</em>).</p>
<p>También nos ha creado una página llamada <code>output/authors.html</code> que contendrá la lista de autores de los artículos de nuestro site. Estos autores se obtienen de la directiva <code>Author:</code> que hemos especificado en cada artículo Markdown que hemos escrito, por lo que como en este ejemplo hemos puesto el mismo <code>Author:</code> en cada uno de los dos archivos Markdown, solo tendremos un autor en dicho listado.</p>
<p>En el directorio <code>output/authors/</code> nos habrá creado una página por cada uno de los autores que tengamos, y en ella estará el listado de artículos que ha escrito cada uno de ellos. Al igual que en el caso anterior, como solo tenemos un autor, Pelican solo nos habrá generado una página dentro de este directorio.</p>
<p>Lo mismo ocurrirá con las <em>categorías</em> y los <em>tags</em>. En los archivos <code>output/categories.html</code> y en <code>output/tags.html</code> tendremos un listado con todas las categorías y tags que hayamos definido en nuestros artículos Markdown, y en los directorios <code>output/category/</code> y <code>output/tags/</code> tendremos un archivo con el listado de artículos de cada categoría y cada tag que tengamos.</p>
<p>Vale, ya tenemos el site generado entonces... pero cómo lo vemos? Para ver qué aspecto tiene nuestra web en este momento también hay varias formas...</p>
<p>Por ejemplo, con el script <code>develop_server.sh</code>:</p>
<div class="highlight"><pre><span></span><code>$ ./develop_server.sh start
</code></pre></div>
<p>O usando el Makefile (si lo tenemos):</p>
<div class="highlight"><pre><span></span><code>$ make devserver
</code></pre></div>
<p>En ambos casos se ejecutará un <a href="https://es.wikipedia.org/wiki/Demonio_%28inform%C3%A1tica%29">demonio</a> en el puerto 8000 con nuestro directorio <code>output/</code> como _DocumentRoot`, por lo que podemos abrir desde un navegador la dirección: <a href="http://localhost:8000">http://localhost:8000</a> y veremos algo parecido a esto:</p>
<p><img alt="screenshot" src="/images/posts/adios-octopress-hola-pelican/screenshot.png"></p>
<p>Si, es cierto... es una web feísima... así que antes de seguir, o bien te haces tu propio <em>theme</em> o bien instalas alguno de los que ya hay disponibles para su uso en (por ejemplo) <a href="http://www.pelicanthemes.com">http://www.pelicanthemes.com</a>, donde se muestran previsualizaciones de la mayoría de los <em>themes</em> que hay en su <a href="https://github.com/getpelican/pelican-themes">repositorio oficial de temas</a>.</p>
<p>Vamos a instalar cualquiera de ellos, por ejemplo <em>Alchemy</em>.</p>
<p>Antes de nada, comprobamos los <em>themes</em> que tenemos instalados actualmente. Para ello vamos a usar un comando de Pelican llamado <code>pelican-themes</code> (con el parámetro <code>-l</code> o <code>--list</code> para ver la lista de <em>themes</em> instalados):</p>
<div class="highlight"><pre><span></span><code>bhean@vader:~/projects/newsite$ pelican-themes -l
notmyidea
simple
</code></pre></div>
<p>Ahora, descargamos el repositorio oficial de pelican-themes desde GitHub a un directorio DIFERENTE al que estamos usando para nuestra web. Esto es así en lugar de descargarlo a nuestro directorio porque podríamos querer usar el mismo tema en diferentes sites, y así evitaríamos tener que descargarlo para cada uno de ellos. Podemos <em>registrarlo</em> en nuestro Pelican a nivel <em>global</em> (físicamente guardado en un único sitio) y sin embargo usarlo desde tantos sites como queramos.</p>
<p>Para hacer esto, creamos (por ejemplo) el directorio <code>~/projects/pelican-themes</code>, y descargamos ahí repositorio. Después, como este repositorio contiene a su vez referencias a otros repositorios (algunos temas tienen su propio repositorio, por lo que son <a href="https://git-scm.com/book/en/v2/Git-Tools-Submodules">submódulos</a> dentro del repositorio principal), descargamos dichos submódulos también:</p>
<div class="highlight"><pre><span></span><code>$ mkdir ~/projects/pelican-themes
$ git clone git@github.com:getpelican/pelican-themes.git ~/projects/pelican-themes
Cloning into <span class="s1">'/home/bhean/projects/pelican-themes'</span>...
remote: Counting objects: <span class="m">5165</span>, <span class="k">done</span>.
remote: Compressing objects: <span class="m">100</span>% <span class="o">(</span><span class="m">6</span>/6<span class="o">)</span>, <span class="k">done</span>.
remote: Total <span class="m">5165</span> <span class="o">(</span>delta <span class="m">0</span><span class="o">)</span>, reused <span class="m">0</span> <span class="o">(</span>delta <span class="m">0</span><span class="o">)</span>, pack-reused <span class="m">5159</span>
Receiving objects: <span class="m">100</span>% <span class="o">(</span><span class="m">5165</span>/5165<span class="o">)</span>, <span class="m">24</span>.27 MiB <span class="p">|</span> <span class="m">12</span>.36 MiB/s, <span class="k">done</span>.
Resolving deltas: <span class="m">100</span>% <span class="o">(</span><span class="m">2614</span>/2614<span class="o">)</span>, <span class="k">done</span>.
$ <span class="nb">cd</span> ~/projects/pelican-themes
$ git submodule init
$ git submodule update
</code></pre></div>
<p>Después de un rato, ya tendremos todos los submódulos del repositorio, por lo que vamos a instalar el que hemos elegido (<em>Alchemy</em>):</p>
<div class="highlight"><pre><span></span><code>$ sudo pelican-themes -i ~/projects/pelican-themes/alchemy/ -v
Installing themes...
Copying <span class="s1">'~/projects/pelican-themes/alchemy/'</span> to <span class="s1">'/usr/lib/python2.7/dist-packages/pelican/themes/alchemy'</span> ...
</code></pre></div>
<p>Es importante que lo hagamos con el parámetro <code>-v</code> o <code>--verbose</code> para que nos diga en qué directorio ha instalado el <em>theme</em>.</p>
<p>Comprobamos de nuevo la lista de <em>themes</em> instalados para ver si todo ha ido bien:</p>
<div class="highlight"><pre><span></span><code>bhean@vader:~/projects/newsite$ pelican-themes -l
notmyidea
simple
alchemy
</code></pre></div>
<p>Perfecto, ya tenemos el nuevo <em>theme</em> instalado en Pelican. Vamos a generar de nuevo nuestra web, ésta vez utilizando el recién instalado <em>theme</em>. Podemos hacerlo de 2 formas:</p>
<ul>
<li>Añadiendo la variable <code>THEME</code> al archivo de configuración de nuestro site (<code>pelicanconf.py</code>) indicando la ruta del directorio donde está instalado dicho <em>theme</em>. Por ejemplo:</li>
</ul>
<div class="highlight"><pre><span></span><code><span class="n">THEME</span><span class="o">=</span><span class="s1">'/usr/lib/python2.7/dist-packages/pelican/themes/alchemy/alchemy'</span>
</code></pre></div>
<p>Y generando de nuevo el site:</p>
<div class="highlight"><pre><span></span><code>$ pelican
</code></pre></div>
<ul>
<li>O generando de nuevo el site indicándo al comando de Pelican donde esta instalado el <em>theme</em> que queremos usar:</li>
</ul>
<div class="highlight"><pre><span></span><code>$ pelican -t /usr/lib/python2.7/dist-packages/pelican/themes/alchemy/alchemy/
</code></pre></div>
<p>En cualquiera de los casos, si ahora recargamos la página que estábamos viendo en <a href="http://localhost:8000">http://localhost:8000</a> deberíamos ver nuestro site con el nuevo <em>theme</em> que hemos elegido:</p>
<p><img alt="screenshot" src="/images/posts/adios-octopress-hola-pelican/screenshot_theme_alchemy.png"></p>
<p>Si quieres saber más sobre la creación o modificación de los <em>themes</em> de Pelican, échale un ojo a la <a href="http://docs.getpelican.com/en/stable/themes.html">documentación oficial</a>.</p>
<p>Vamos a configurar un poco las opciones que nos ofrece el archivo de configuración de Pelican <code>pelicanconf.py</code>.</p>
<p>En primer lugar, si te fijas en el site que acabamos de generar verás que hay un <em>menú de opciones</em> justo debajo del nombre del proyecto (<em>superproyectoestatico</em>). Estas opciones estan definidas en el archivo de configuración, concretamente en la lista llamada <code>LINKS</code>.</p>
<p>Si abrimos el archivo <code>pelicanconf.py</code> y buscamos dicha lista, veremos algo parecido a ésto:</p>
<div class="highlight"><pre><span></span><code><span class="c1"># Blogroll</span>
<span class="n">LINKS</span> <span class="o">=</span> <span class="p">((</span><span class="s1">'Pelican'</span><span class="p">,</span> <span class="s1">'http://getpelican.com/'</span><span class="p">),</span>
<span class="p">(</span><span class="s1">'Python.org'</span><span class="p">,</span> <span class="s1">'http://python.org/'</span><span class="p">),</span>
<span class="p">(</span><span class="s1">'Jinja2'</span><span class="p">,</span> <span class="s1">'http://jinja.pocoo.org/'</span><span class="p">),</span>
<span class="p">(</span><span class="s1">'You can modify those links in your config file'</span><span class="p">,</span> <span class="s1">'#'</span><span class="p">),)</span>
</code></pre></div>
<p>Aunque no sepais nada de Python, es evidente que el primer valor de cada entrada de esa lista es el texto del enlace y el segundo es la URL a la que apunta... por lo que podemos poner las opciones que queramos según nuestras necesidades, por ejemplo, podemos poner algo así:</p>
<div class="highlight"><pre><span></span><code><span class="c1"># Blogroll</span>
<span class="n">LINKS</span> <span class="o">=</span> <span class="p">((</span><span class="s1">'Inicio'</span><span class="p">,</span> <span class="n">SITEURL</span><span class="p">),</span>
<span class="p">(</span><span class="s1">'pornoHARDWARE.com'</span><span class="p">,</span> <span class="s1">'https://pornohardware.com'</span><span class="p">),</span>
<span class="p">(</span><span class="s1">'Ayuda'</span><span class="p">,</span> <span class="s1">'/ayuda.html'</span><span class="p">),)</span>
</code></pre></div>
<p>Para evitar duplicar información teniendo que volver a escribir nuestra URL, he aprovechado la variable <code>SITEURL</code> (que está definida en ese mismo archivo de configuración, normalmente arriba del todo). Al generar de nuevo el site veremos que nuestro menú de opciones ha cambiado y ahora es así:</p>
<p><img alt="screenshot" src="/images/posts/adios-octopress-hola-pelican/screenshot_theme_alchemy_menu.png"></p>
<p>Hay 2 tipos de opciones en el archivo de configuración:</p>
<ul>
<li>Las que afectan al funcionamiento <em>interno</em> de Pelican (es decir, las opciones púramente de configuración del entorno).</li>
<li>Las que afectan únicamente al <em>theme</em> que estemos utilizando.</li>
</ul>
<p>Al primer grupo pertenecen (por citar algunas) aquellas que definen los directorios donde guardamos los archivos Markdown de los artículos o las demás páginas, el formato que tendrá la fecha/hora que usaremos en nuestra web, etc. Y al segundo grupo pertenecerían aquellas que definen si mostrar o no un determinado <em>pié de página</em>, las que definen la imagen que usaremos como logo, etc.</p>
<p>Explicar las del segundo grupo no tiene sentido porque dependen únicamente del <em>theme</em> que estemos usando (en unos casos habrá unas, y en otros habrá otras diferentes) por lo que siempre hay que leer la documentación del <em>theme</em> que estemos utilizando (normalmente esta documentación está en el archivo <code>README.md</code> en el raíz del repositorio del <em>theme</em> que vayamos a usar).</p>
<p>Y explicar las del primer grupo tampoco tiene mucho sentido ya que están explicadas en la propia <a href="http://docs.getpelican.com/en/stable/settings.html#basic-settings">documentación oficial</a> de Pelican, por lo que os recomiendo que lo miréis allí.</p>
<p>Llegados a este punto ya deberías ser capaz de añadir contenido a tu web, no obstante si vienes de otros generadores de sites estáticos (como Octopress, en mi caso) voy a explicar las principales modificaciones que tendrás que hacer para <em>migrar</em> tu actual site a Pelican.</p>
<h2>Migración desde Octopress a Pelican<a name="migrate"></a></h2>
<p>Lo primero que hay que hacer si estamos migrando los artículos de Octopress a Pelican es, obviamente, copiar estos archivos al directorio donde le hemos dicho a Pelican que iban a estar los artículos: <code>~/projects/superproyectoestatico/content/posts</code></p>
<div class="highlight"><pre><span></span><code>$ cp /ruta-del-antiguo-octopress/source/_posts/* ~/projects/superproyectoestatico/content/posts/
</code></pre></div>
<p>Si nuestros artículos de Octopress estaban escritos en Markdown <em>puro</em>, no deberíamos tener grandes problemas al migrar a Pelican ya que el intérprete de Markdown es <em>bastante</em> similar (aunque no es exáctamente igual).</p>
<p>En mi caso, los artículos de Octopress estaban escritos más o menos así:</p>
<div class="highlight"><pre><span></span><code><span class="err">---</span>
<span class="c">layout: post</span>
<span class="c">title: "Título de ejemplo del artículo"</span>
<span class="c">date: 2015-12-28 17:13:04 +0100</span>
<span class="c">reading-time: true</span>
<span class="c">comments: true</span>
<span class="c">published: true</span>
<span class="c">categories: [Categoria1, Categoria2]</span>
<span class="c">keywords: tag1, tag2, tag3, etc.</span>
<span class="c">description: Breve descripcion del articulo.</span>
<span class="err">---</span>
<span class="err">Y aqui va todo el texto que forma el contenido del articulo...</span>
</code></pre></div>
<p>Como veis es bastante parecido a los artículos que hemos escrito para Pelican unos párrafos más arriba, pero no es exáctamente igual.</p>
<p>Podeis ver que hay una primera línea con 3 guiones. Después se definen una serie de <em>variables</em> (<code>layout</code>, <code>title</code>, etc), después hay otra línea con 3 guiones y finalmente el texto del artículo.</p>
<p>Markdown no nos obliga a empezar y acabar el <em>bloque de variables</em> con 3 guiones, sino que es algo que hicimos así en su día porque en Octopress se hacía así.</p>
<p>Pelican no va a fallar si dejáis dichas líneas con los 3 guiones, pero os <em>recomiendo que intentéis utilizar Markdown puro</em> en la medida de lo posible para minimizar los problemas futuros si algún dia queréis volver a migrar a otro generador de sites distinto que también permita Markdown. Por lo tanto, os recomiendo que eliminéis ambas líneas.</p>
<p>Lo siguiente que hay que hacer es eliminar aquellas cabeceras que eran específicas de Octopress y que no se usan en Pelican, como por ejemplo:</p>
<ul>
<li>
<p><code>layout</code>
En Octopress esta cabecera podía tener el valor <code>post</code> o <code>page</code> dependiendo de si era un artículo u otra página del site. En Pelican no hace falta porque los artículos se guardan en un directorio diferente al de las páginas. Estos directorios se definen en el archivo de configuración (<code>pelicanconf.py</code>) con las variables <code>ARTICLE_PATHS</code> y <code>PAGE_PATHS</code> respectivamente.</p>
</li>
<li>
<p><code>reading-time</code>
Esta cabecera era utilizada por un plugin de Octopress que mostraba en cada artículo el tiempo estimado de lectura de dicho artículo en base al número de palabras del mismo. Ese plugin obviamente no funciona en Pelican, por lo que esta cabecera tampoco es necesaria ya (aunque tenemos otros plugins en Pelican que implementan esa misma funcionalidad).</p>
</li>
<li>
<p><code>published</code>
Para no publicar artículos que aún no estuvieran terminados (borradores, o <em>drafts</em>), se podía especificar el valor <code>false</code> en ésta cabecera, de forma que el artículo no se tendría en cuanto a la hora de generar el site. Una vez terminado se pondría a <code>true</code>, momento a partir del cual el artículo sería publicado junto a los demás. En Pelican para hacer ésto se usa la cabecera <code>Status</code>, cuyos valores pueden ser <code>published</code> o <code>draft</code>.</p>
</li>
<li>
<p><code>categories</code>
Esta cabecera es igual tanto en Octopress como en Pelican, solo que a diferente del primero Pelican no permite que un mismo artículo pertenezca a más de una categoría. Esto no será un problema si tus artículos están solo en una categoría, pero en mi caso todos los artículos estaban en varias categorías a la vez, por lo que en lugar de usar el concepto de <em>categorías</em> de Pelican he utilizado el de <em>tags</em>.
Los <em>tags</em> en Pelican sí que pueden ser ilimitados, por lo que en lugar de la cabecera <code>Category</code> (como hace Pelican) he usado para ésto la cabecera <code>Tags</code>.</p>
</li>
<li>
<p><code>keywords</code>
En Octopress, el contenido de esta cabecera se muestra en la etiqueta HTML <meta name="keywords">, y se usa principalmente para temas de SEO (como ya expliqué en <a href="https://es.wikipedia.org/wiki/Posicionamiento_en_buscadores">éste artículo </a>). En Pelican no existe dicha cabecera, pero cualquier cabecera que nos inventemos estará disponible dentro de los <em>templates</em> del <em>theme</em> que estemos usando, por lo tanto le he cambiado el nombre por <code>Metakeywords</code>, y he añadido la siguiente línea en el <em>template</em> que muestra los artículos:</p>
<div class="highlight"><pre><span></span><code><span class="x"><meta name="keywords" content="</span><span class="cp">{{</span> <span class="nv">article.metakeywords</span> <span class="cp">}}</span><span class="x">" /></span>
</code></pre></div>
</li>
<li>
<p><code>description</code>
Exactamente igual que con <code>keywords</code>. La he renombrado a <code>Metadescription</code> y he hecho lo mismo que con la cabecera anterior. En la misma plantilla que hemos editado antes ahora pondríamos también ésta nueva linea:</p>
<div class="highlight"><pre><span></span><code><span class="x"><meta name="description" content="</span><span class="cp">{{</span> <span class="nv">article.metadescription</span> <span class="cp">}}</span><span class="x">" /></span>
</code></pre></div>
</li>
</ul>
<p>Aparte de estos cambios, he aprovechado también para poner la primera letra de cada cabecera en mayúsculas ya que aunque Pelican convierte el nombre de todas las cabeceras a minúsculas, así es como lo explican en la documentación oficial, por lo que únicamente he seguido sus indicaciones.</p>
<p>Por último, he añadido la cabecera <code>Authors</code>, aunque en mi caso es un poco inútil ya que soy el único <em>autor</em> que publica en mi blog. No obstante he querido ponerla igualmente por si en un futuro decido publicar algún artículo que no haya escrito yo.</p>
<p>Con éstas últimas modificaciones el artículo quedaría entonces más o menos así:</p>
<div class="highlight"><pre><span></span><code><span class="n">Title</span><span class="p">:</span> <span class="ss">"Título de ejemplo del artículo"</span>
<span class="n">Authors</span><span class="p">:</span> <span class="n">BhEaN</span>
<span class="nb">Date</span><span class="p">:</span> <span class="mi">2015</span><span class="o">-</span><span class="mi">12</span><span class="o">-</span><span class="mi">28</span> <span class="mi">17</span><span class="p">:</span><span class="mi">13</span><span class="p">:</span><span class="mi">04</span> <span class="o">+</span><span class="mi">0100</span>
<span class="n">Category</span><span class="p">:</span>
<span class="n">Tags</span><span class="p">:</span> <span class="n">Categoria1</span><span class="p">,</span> <span class="n">Categoria2</span>
<span class="n">Metakeywords</span><span class="p">:</span> <span class="n">tag1</span><span class="p">,</span> <span class="n">tag2</span><span class="p">,</span> <span class="n">tag3</span><span class="p">,</span> <span class="n">etc</span><span class="p">.</span>
<span class="n">Metadescription</span><span class="p">:</span> <span class="n">Breve</span> <span class="n">descripcion</span> <span class="n">del</span> <span class="n">articulo</span><span class="p">.</span>
<span class="n">Status</span><span class="p">:</span> <span class="n">published</span>
<span class="n">Y</span> <span class="n">aqui</span> <span class="n">va</span> <span class="n">todo</span> <span class="n">el</span> <span class="n">texto</span> <span class="n">que</span> <span class="n">forma</span> <span class="n">el</span> <span class="n">contenido</span> <span class="n">del</span> <span class="n">articulo</span><span class="p">...</span>
</code></pre></div>
<p>Con esto ya casi tendríamos <em>migrados</em> los artículos de Octopress a Pelican, pero falta lo más complicado: lo que haya en el contenido del artículo (es decir, el propio texto).</p>
<p>A no ser que el site de Octopress que estáis migrando estuviera formado por artículos que únicamente tuvieran texto y dicho texto además estuviera formateado utilizando <em>Markdown puro</em>, habrá que hacer algunos cambios antes de poder dar por concluida la migración a Pelican.</p>
<p>Como ya deberíais saber (y sino, estáis tardando en leer <a href="/2014/07/02/markdown-el-lenguaje-de-marcado-para-texto-plano/">éste artículo</a>) para insertar una imagen en Markdown se usa esta expresión:</p>
<div class="highlight"><pre><span></span><code><span class="o">!</span><span class="p">[</span><span class="n">Texto</span> <span class="n">alternativo</span><span class="p">](</span><span class="nl">https</span><span class="p">:</span><span class="c1">//pornohardware.com/images/cylon.png "Título de la imagen")</span>
</code></pre></div>
<p>Por lo tanto, si habeis usado ésta forma de insertar imágenes en vuestros artículos, perfecto! No tendréis que hacer nada ya que el intérprete de Markdown de Pelican seguirá tratándolas igual que lo hacía el de Octopress... pero casi con total seguridad no todas las imágenes las tenéis así, ya que <a href="https://shopify.github.io/liquid/">Liquid</a> (el sistema de plantillas que usa Octopress) ofrecía una forma propia de insertar imágenes que nos permitía tener un mayor control sobre ellas del que nos ofrece Markdown (como por ejemplo la alineación con respecto al texto que rodea la imagen) y que se usaba de ésta forma:</p>
<div class="highlight"><pre><span></span><code><span class="err">{% img right https://pornohardware.com/images/cylon.png % }</span>
</code></pre></div>
<p>Por desgracia éste era mi caso, por lo que a priori pensé que tendría que cambiar la forma en la que insertaba las imágenes en todos mis artículos...</p>
<p>Y peor aún! Octopress también ofrecía algunas otras características propias que no formaban parte del <em>standar</em> de Markdown por lo que tampoco iban a funcionar bien en Pelican, como por ejemplo:</p>
<ul>
<li>
<p><code>{% codeblock % }</code> y <code>{% endblock % }</code>
Octopress permite insertar trozos de código entre éstos dos <em>tags</em>, resaltando la sintaxis según el lenguaje que le indiquemos. Lo más correcto en este caso hubiera sido utilizar la forma que tiene Markdow de hacerlo (poniendo el código entre tres comillas invertidas: ```), pero en su dia no lo hice así, así que también tenía que cambiar todas estas partes para poder migrar los artículos a Pelican.</p>
</li>
<li>
<p><code>{% include % }</code>
Para <em>incluir</em> archivos dentro de los artículos.</p>
</li>
<li>
<p><code>{% vimeo % }</code>
Esto no es algo propio de Octopress sino que es un <a href="/2014/09/27/jekyll-vimeo-lazyloading-un-nuevo-plugin-para-mostrar-videos-de-vimeo-en-octopress/">plugin que hice yo mismo</a> en Ruby (el lenguage de Octopress) para poder insertar videos de <a href="https://www.vimeo.com">Vimeo</a> en nuestros artículos y obviamente dicho plugin no funciona en Pelican, por lo que pensé que además de cambiar todo lo anterior tendría que rehacer el plugin en Python para hacerlo funcionar aquí.</p>
</li>
</ul>
<p>Pero entonces, casi por casualidad, descubrí el plugin [Liquid-style Tags](https://github.com/getpelican/pelican-plugins/tree/master/liquid_tags, que como su propio nombre indica permite utilizar los tags de <em>Liquid</em> (Octopress) en Pelican (aprovecho para enviar todo mi agradecimiento a su autor, <em>Jake Vanderplas</em>!).</p>
<p>Instalar plugins en Pelican es muy sencillo: solo tenemos que bajar el plugin en cuestión, decirle a Pelican en qué directorio lo hemos guardado y configurarlo (esto último solo si es necesario ya que no todos los plugins necesitan configuración).</p>
<p>Al igual que con los <em>themes</em>, Pelican dispone de un repositorio en GitHub que agrupa todos los plugins oficiales: <a href="https://github.com/getpelican/pelican-plugins">https://github.com/getpelican/pelican-plugins</a>.</p>
<p>Lo más sencillo es instalar <em>de golpe</em> todos los plugins del repositorio, ya que como hay que decirle a Pelican explícitamente cuáles son los plugins que queremos usar, podemos instalarlos todos configurándolo para que únicamente cargue los que nosotros queramos.</p>
<p>Para hacer esto, creamos un directorio donde almacenar todos los plugins y descargamos ahí el repositorio. Después, igual que pasaba con el repositorio de <em>themes</em>, éste repositorio de plugins contiene a su vez otros repositorios como <a href="https://git-scm.com/book/en/v2/Git-Tools-Submodules">submódulos de GIT</a>, por lo que los descargamos también:</p>
<div class="highlight"><pre><span></span><code>$ mkdir -p ~/projects/superproyectoestatico/plugins
$ git clone git@github.com:getpelican/pelican-plugins.git ~/projects/superproyectoestatico/plugins/pelican-plugins
Cloning into <span class="s1">'/home/bhean/projects/superproyectoestatico/plugins/pelican-plugins'</span>...
remote: Counting objects: <span class="m">4289</span>, <span class="k">done</span>.
remote: Total <span class="m">4289</span> <span class="o">(</span>delta <span class="m">0</span><span class="o">)</span>, reused <span class="m">0</span> <span class="o">(</span>delta <span class="m">0</span><span class="o">)</span>, pack-reused <span class="m">4288</span>
Receiving objects: <span class="m">100</span>% <span class="o">(</span><span class="m">4289</span>/4289<span class="o">)</span>, <span class="m">2</span>.39 MiB <span class="p">|</span> <span class="m">1</span>.91 MiB/s, <span class="k">done</span>.
Resolving deltas: <span class="m">100</span>% <span class="o">(</span><span class="m">1990</span>/1990<span class="o">)</span>, <span class="k">done</span>.
$ <span class="nb">cd</span> ~/projects/superproyectoestatico/plugins/pelican-plugins
$ git submodule init
$ git submodule update
</code></pre></div>
<p>Con eso ya tenemos todos los submódulos del repositorio.</p>
<p>Ahora hay que decirle a Pelican en qué directorio tiene que buscar los plugins (con una ruta relativa a la raiz de nuestro proyecto), por lo que abrimos el archivo de configuración (<code>pelicanconf.py</code>) y añadimos la linea:</p>
<div class="highlight"><pre><span></span><code><span class="n">PLUGIN_PATHS</span> <span class="o">=</span> <span class="p">[</span>
<span class="s1">'plugins/pelican-plugins'</span><span class="p">,</span>
<span class="p">]</span>
</code></pre></div>
<p>Y ahora le decimos qué plugins queremos utilizar:</p>
<div class="highlight"><pre><span></span><code><span class="n">PLUGINS</span> <span class="o">=</span> <span class="p">[</span>
<span class="sa">u</span><span class="s1">'liquid_tags.img'</span><span class="p">,</span>
<span class="sa">u</span><span class="s1">'liquid_tags.include_code'</span><span class="p">,</span>
<span class="sa">u</span><span class="s1">'liquid_tags.vimeo'</span><span class="p">,</span>
<span class="p">]</span>
</code></pre></div>
<p>A partir de ahora Pelican intentará cargar los plugins que haya en el directorio que le hemos indicado en <code>PLUGIN_PATHS</code>, en este será únicamente <code>liquid_tags</code>, y dentro de dicho plugin cargará concretamente los módulos <code>img</code>, <code>include_code</code> y <code>vimeo</code>.</p>
<p>Únicamente hay que hacer un cambio en nuestros artículos, y es que el formato para <em>include</em> en Octopress era:</p>
<div class="highlight"><pre><span></span><code><span class="cp">{%</span> <span class="k">include</span> <span class="nv">ruta</span><span class="o">/</span><span class="nv">archivo.txt</span> <span class="cp">%}</span><span class="x"></span>
</code></pre></div>
<p>y ahora tiene que ser:</p>
<div class="highlight"><pre><span></span><code><span class="cp">{%</span> <span class="k">include_code</span> <span class="nv">ruta</span><span class="o">/</span><span class="nv">archivo.txt</span> <span class="cp">%}</span><span class="x"></span>
</code></pre></div>
<p>Nada que no podamos resolver ejecutando un sencillo comando para reemplazara todas las apariciones de <code>{% include</code> por <code>{% include_code</code> en el directorio donde tengamos los archivos de los artículos:</p>
<div class="highlight"><pre><span></span><code>$ find ~/projects/superproyectoestatico/content/posts -type f -exec sed -i <span class="s1">'s/{% include /{% include_code /g'</span> <span class="o">{}</span> +
</code></pre></div>
<p>Si habéis estado atentos veréis que aún nos quedan los <em>malditos</em> <code>{% codeblock %}</code>, verdad? Convertirlos a formato Markdown es también muy sencillo. Supongamos que tenemos un artículo en el que hablamos (por ejemplo) de <a href="https://es.wikipedia.org/wiki/SQL">SQL</a>:</p>
<div class="highlight"><pre><span></span><code><span class="err">{% codeblock %}</span>
<span class="err">SELECT tabla.columna1, tabla.columna2 FROM tabla WHERE tabla.columna1 = 'blablabla';</span>
<span class="err">{% endcodeblock %}</span>
</code></pre></div>
<p>En Markdown, para poner fragmentos de código hay que poner tanto al principio como al final del código 3 comillas invertidas, de forma que el fragmento anterior sería similar a ésto:</p>
<div class="highlight"><pre><span></span><code><span class="err">```</span>
<span class="err">SELECT tabla.columna1, tabla.columna2 FROM tabla WHERE tabla.columna1 = 'blablabla';</span>
<span class="err">```</span>
</code></pre></div>
<p>Pero qué pasa cuando tenemos especificado el <em>lenguaje</em> del código que estamos mostrando? Este tipo de comandos en Octopress permitían especificar el lenguaje del código para resaltar la sintaxis según fuera un lenguaje u otro. En como si en nuestro ejemplo anterior en lugar usar <code>{% codeblock %}</code> hubiéramos usado <code>{% codeblock lang:sql %}</code> de ésta forma:</p>
<div class="highlight"><pre><span></span><code><span class="err">{% codeblock lang:sql %}</span>
<span class="err">SELECT tabla.columna1, tabla.columna2 FROM tabla WHERE tabla.columna1 = 'blablabla';</span>
<span class="err">{% endcodeblock %}</span>
</code></pre></div>
<p>Pelican también permite especificar el lenguaje del código que vamos a mostrar (la lista lenguajes soportados podéis consultarla aquí: <a href="http://pygments.org/docs/lexers/">http://pygments.org/docs/lexers/</a>), poniéndo su nombre detrás del grupo inicial de comillas invertidas. En nuestro ejemplo se haría así:</p>
<div class="highlight"><pre><span></span><code><span class="err">```sql</span>
<span class="err">SELECT tabla.columna1, tabla.columna2 FROM tabla WHERE tabla.columna1 = 'blablabla';</span>
<span class="err">```</span>
</code></pre></div>
<p>Por lo tanto, sustituir ambos casos es muy sencillo, podemos usar de nuevo el <em>todopoderoso</em> <a href="https://www.gnu.org/software/sed/">sed</a> para sustituir el antiguo formato por el nuevo con éstos sencillos comandos:</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">cd</span> ~/projects/superproyectoestatico/content/posts
$ find . -type f -exec sed -i -E <span class="s1">'s/\{% codeblock lang:(.+) %\}/```\1/g'</span> <span class="o">{}</span> +
$ find . -type f -exec sed -i <span class="s1">'s/{% codeblock %}/```/g'</span> <span class="o">{}</span> +
$ find . -type f -exec sed -i <span class="s1">'s/{% endcodeblock %}/```/g'</span> <span class="o">{}</span> +
</code></pre></div>
<p>A partir de este momento, Pelican <em>debería entender</em> sin problemas nuestros artículos existentes.</p>
<p>En cualquier caso, os recomiendo que le echéis un ojo a los demás plugins por si alguno os resulta de utilidad. Hay algunos muy interesantes, como por ejemplo:</p>
<ul>
<li><a href="https://github.com/getpelican/pelican-plugins/tree/master/sitemap">Sitemap</a>: Genera los archivos <a href="https://es.wikipedia.org/wiki/Extensible_Markup_Language">XML</a> del <a href="https://www.sitemaps.org/es/">sitemap</a> de nuestra web.</li>
<li><a href="https://github.com/getpelican/pelican-plugins/tree/master/summary">Summary</a>: Permite utilizar la funcionalidad que teníamos en Octopress con el tag <code><!-- more --></code> para mostrar únicamente un fragmento del artículo en los listados, y un botón de <code>Leer más...</code> para ver el texto completo.</li>
<li><a href="https://github.com/getpelican/pelican-plugins/tree/master/post_stats">Post Statistics</a>: Muestra algunas estadísticas de los artículos, como por ejemplo el número de palabras de cada uno, el tiempo medio de lectura, etc.</li>
<li><a href="https://github.com/getpelican/pelican-plugins/tree/master/liquid_tags">Liquid-style Tags</a>: Éste plugin ya lo conocéis ;)</li>
<li><a href="https://github.com/silentlamb/pelican-deadlinks">Dead Links</a>: Comprueba que los enlaces que tenéis especificados en los artículos no apuntan a páginas que ya no existan.</li>
</ul>
<h2>Subida a producción<a name="release"></a></h2>
<p>¿Pero de qué nos sirve tener nuestro site funcionando si no lo subimos a nuestro entorno de producción para que todo el mundo pueda acceder a él? Vamos con el último paso: la subida al entorno de producción que vayamos a usar.</p>
<p>Como ya expliqué en este mismo artículo, Pelican permite subir fácilmente el código generado a varios <em>entornos de producción</em> diferentes y de varias formas, como por ejemplo a un bucket de Amazon S3, a un contenedor de Rackspace, a un servidor on-premise (servidores físicos, para los que vengáis de la <a href="https://es.wikipedia.org/wiki/Educaci%C3%B3n_Secundaria_Obligatoria">ESO</a>) mediante SSH, etc.</p>
<p>En mi caso, voy a subirlo a un servidor virtual, por lo que utilizaré SSH para enviarle el código mediante SCP.</p>
<p>Si habeis respondido correctamente a las preguntas del comando <code>pelican-quickstart</code> que expliqué en el apartado <a href="#install">Instalación de Pelican</a>, ya deberíais tener configurados los archivos necesarios.</p>
<p>La información sobre vuestro entorno de producción puede estar en uno o varios de estos archivos (dependiendo de si vais a usar el archivo Makefile, el Fabfile, etc):</p>
<ul>
<li><code>publishconf.py</code></li>
<li><code>Makefile</code></li>
<li><code>fabfile.py</code></li>
</ul>
<p>Yo voy a hacerlo con el comando <code>make</code>, por lo que utilizaré el archivo <code>Makefile</code>.</p>
<p>Dicho archivo tiene una serie de variables para configurar todos los entornos de producción a los que Pelican permite subir el código generado. En mi caso voy a usar <a href="https://rsync.samba.org/">RSYNC</a> para transferir los archivos a través de SSH, pero vosotros podéis usar el entorno que queráis (solo tendréis que configurar unas variables u otras).</p>
<p>Abrimos el archivo <code>Makefile</code> y verificamos el valor de las variables de SSH:</p>
<div class="highlight"><pre><span></span><code><span class="nv">SSH_HOST</span><span class="o">=</span>pornohardware.com
<span class="nv">SSH_PORT</span><span class="o">=</span><span class="m">22</span>
<span class="nv">SSH_USER</span><span class="o">=</span>deploy
<span class="nv">SSH_TARGET_DIR</span><span class="o">=</span>/var/www/
</code></pre></div>
<p>Es decir, Pelican subirá el código generado al directorio <code>/var/www</code> del servidor <code>pornohardware.com</code>, al cual se conectará por SSH a través del puerto <code>22</code> y utilizando el usuario <code>deploy</code>.</p>
<p>Este usuario <code>deploy</code> es un usuario que tengo creado en el servidor que únicamente tiene permisos de escritura en el directorio <code>/var/www</code>.</p>
<p>Para que Pelican genere el código de nuestro site utilizando las variables del entorno de producción y luego suba dicho código al servidor, bastaría con ejecutar el comando:</p>
<div class="highlight"><pre><span></span><code>$ make rsync_upload
</code></pre></div>
<p>Y listo! Nuestro site debería haberse subido correctamente al directorio <code>/var/www</code> del servidor!
Obviamente doy por hecho que vuestro servidor tiene un <a href="http://nginx.org/">Nginx</a>, un <a href="https://httpd.apache.org/">Apache</a> o cualquier otro servidor web cuyo <code>DocumentRoot</code> es <code>/var/www</code>. Si no es así, tendréis que configurarlo... pero esa parte sí que está fuera del ámbito de éste artículo.</p>
<p>Espero que el artículo os haya resultado de utilidad! Y por supuesto, no dudéis en distribuirlo y compartirlo con todo el mundo (pero por favor, citar siempre la fuente de éste artículo).</p>
<p>Alaaaaaaaaaaaaaaaaaaaaaaa</p>
<h2>Referencias<a name="refs"></a></h2>
<ul>
<li><a href="http://www.getpelican.com/">http://www.getpelican.com/</a></li>
<li><a href="https://www.staticgen.com">https://www.staticgen.com</a></li>
<li><a href="http://jinja.pocoo.org">http://jinja.pocoo.org</a></li>
<li><a href="http://pygments.org">http://pygments.org</a></li>
<li><a href="http://www.pelicanthemes.com">http://www.pelicanthemes.com</a></li>
</ul>Accede a tu biblioteca multimedia (audio y video) desde cualquier parte con Ampache2015-12-28T17:13:04+01:002015-12-28T17:13:04+01:00BhEaNtag:pornohardware.com,2015-12-28:/2015/12/28/accede-a-tu-biblioteca-multimedia-audio-y-video-desde-cualquier-parte-con-ampache/<p>Según la definición que aparece en <a href="https://es.wikipedia.org">Wikipedia</a>, <a href="https://github.com/ampache/ampache/">Ampache</a> es un <a href="https://es.wikipedia.org/wiki/Administrador_de_archivos">administrador de archivos</a> y servidor de <a href="https://es.wikipedia.org/wiki/Streaming">streaming</a> multimedia que se ejecuta sobre un <a href="https://es.wikipedia.org/wiki/Servidor_web">servidor web</a>. Es decir, un software que os permitirá mantener organizada vuestra biblioteca multimedia (generalmente música y películas) y que os permitirá reproducir dicha biblioteca desde un navegador, un smartphone, una tablet, etc.</p>
<p><img class="right" src="/images/logos/logo_ampache.png"/>
Empresas como <a href="https://www.spotify.com">Spotify</a>, <a href="http://www.deezer.com">Deezer</a>, <a href="https://www.jamendo.com">Jamendo</a>, los <em>asquerosos</em> de <a href="https://play.google.com/music/">Google Play Music</a> o la recién llegada <a href="http://www.apple.com/es/music">Apple Music</a> (entre muchas otras) ofrecen casi toda la música del mundo a solo un par de <em>clicks</em> de distancia, y como cada vez hay más competencia en este tipo de servicios de audio en <a href="https://es.wikipedia.org/wiki/Streaming">streaming</a>, todas ellas se esfuerzan en mejorar la calidad de sus servicios, aumentar su catálogo y mejorar sus cada vez más atractivos precios de suscripción.</p>
<p>¿Porqué montar entonces un servicio propio de streaming? Intentaré explicarlo para que <strong>incluso tu</strong>, insignificante humano, lo entiendas...</p>
<p>Según la definición que aparece en <a href="https://es.wikipedia.org">Wikipedia</a>, <a href="https://github.com/ampache/ampache/">Ampache</a> es un <a href="https://es.wikipedia.org/wiki/Administrador_de_archivos">administrador de archivos</a> y servidor de <a href="https://es.wikipedia.org/wiki/Streaming">streaming</a> multimedia que se ejecuta sobre un <a href="https://es.wikipedia.org/wiki/Servidor_web">servidor web</a>. Es decir, un software que os permitirá mantener organizada vuestra biblioteca multimedia (generalmente música y películas) y que os permitirá reproducir dicha biblioteca desde un navegador, un smartphone, una tablet, etc.</p>
<p><img class="right" src="/images/logos/logo_ampache.png">
Empresas como <a href="https://www.spotify.com">Spotify</a>, <a href="http://www.deezer.com">Deezer</a>, <a href="https://www.jamendo.com">Jamendo</a>, los <em>asquerosos</em> de <a href="https://play.google.com/music/">Google Play Music</a> o la recién llegada <a href="http://www.apple.com/es/music">Apple Music</a> (entre muchas otras) ofrecen casi toda la música del mundo a solo un par de <em>clicks</em> de distancia, y como cada vez hay más competencia en este tipo de servicios de audio en <a href="https://es.wikipedia.org/wiki/Streaming">streaming</a>, todas ellas se esfuerzan en mejorar la calidad de sus servicios, aumentar su catálogo y mejorar sus cada vez más atractivos precios de suscripción.</p>
<p>¿Porqué montar entonces un servicio propio de streaming? Intentaré explicarlo para que <strong>incluso tu</strong>, insignificante humano, lo entiendas...</p>
<p>En primer lugar, por no depender de un tercero... cosa que aunque os parezca una tontería, es MUY importante.</p>
<p>Y no me refiero solo a que depender de ellos hasta el punto de tener que <em>pasar por el aro</em> si el día de mañana deciden subir sus precios de repente, o si deciden meter publicidad entre canción y canción (a pesar de estar pagando un servicio <em>premium</em>). Me refiero a mucho más...</p>
<p>Piensa que quizás algún día te apetezca escuchar una canción, y al acudir a tu <em>maravilloso proveedor</em> (al cual estas <strong>pagando</strong> mes a mes por tu suscripción <em>premium</em>) descubres tristemente que dicha canción no está disponible en su catálogo. Bien porque la discográfica que publicó ese disco no firmó ningún acuerdo con ellos, o bien porque sea de algún sello alternativo que no use los canales de distribución habituales de la llamada <a href="https://es.wikipedia.org/wiki/Industria_musical"><em>Industria Músical</em></a> o incluso porque la empresa con la que tengas contratado el servicio de <em>streaming</em> decida que la temática de las letras de dicho grupo van en contra de sus <em>políticas</em> (si, estoy hablando ni más ni menos de <strong>censura</strong>, como la que suele hacer Google o Apple cuando les viene en gana). En cualquiera de los casos, si es otro quien decide lo que puedes escuchar y lo qué no, es lógico que tarde o temprano quieras escuchar algo que ellos no te permitan, es solo una cuestión de tiempo.</p>
<p>Pero aunque todo esto no sucediera nunca (JA!), qué hay de la satisfacción de hacer las cosas uno mismo y no depender de nadie? Si el maravilloso mundo del <a href="https://www.gnu.org/philosophy/free-sw.es.html">software libre</a> nos ofrece un producto que funciona bien, que podemos utilizar fácilmente y que hace exáctamente lo que queremos que haga, porqué no íbamos a usarlo?</p>
<p><a href="http://ampache.org/">Ampache</a> es precisamente uno de los proyectos más importantes en éste sentido, así que es del que voy a hablar en éste artículo.</p>
<p>Si sois como yo (lo cual es raro, la verdad) seguro que tenéis una buena <a href="https://es.wikipedia.org/wiki/Multimedia"><em>biblioteca multimedia</em></a> ordenada, categorizada y almacenada en alguna parte. En mi caso la tengo (junto a muchas otras cosas) en una maravillosa <a href="http://es.wikipedia.org/wiki/Network-attached_storage">NAS</a> (la <a href="http://www.allnet.de/es/">Allnet ALL6600</a> de 10TB de la que ya os hablé <a href="/2014/07/09/un-paseo-por-el-datacenter-en-el-que-vivo/">en éste artículo</a>).</p>
<p>Vamos a utilizar Ampache para poder acceder a todo ese contenido desde cualquier parte, gratuitamente y sin intermediarios o terceras partes que decidan lo que podemos o no podemos escuchar.</p>
<ol>
<li><a href="#historia">Un poco de historia sobre Ampache</a></li>
<li><a href="#instalacion">Instalación</a></li>
<li><a href="#configuracion">Configuración</a></li>
<li><a href="#refs">Referencias</a></li>
</ol>
<h2>Un poco de historia sobre Ampache<a name="historia"></a></h2>
<p>Un programador llamado <em>Scott Kveton</em> inició el proyecto Ampache en 2001, y a partir de 2003 fue <em>Karl Vollmer</em> quien se encargó de su desarrollo.</p>
<p>Ampache está escrito en <a href="http://php.net/">PHP</a>, y aunque originalmente se diseñó como <em>complemento</em> a <a href="http://freecode.com/projects/mod_mp3">mod_mp3</a> (un módulo del servidor web <a href="http://httpd.apache.org/">Apache</a> que permitía reproducir archivos de audio <a href="https://es.wikipedia.org/wiki/MP3">MP3</a> en streaming), finalmente desarrolló su propio servicio de streaming y de organización/búsqueda de archivos.</p>
<p>Es decir, Ampache permite que desde cualquier <a href="https://es.wikipedia.org/wiki/Navegador_web">navegador</a> (o dispositivo/aplicación compatible) consultemos nuestra música, realicemos búsquedas en ella, mostremos los datos de las canciones y de sus artistas y, por supuesto, que reproduzcamos dichos archivos <em>al vuelo</em> sin necesidad de descargarlos previamente (streaming).</p>
<p>Dispone de una <a href="https://es.wikipedia.org/wiki/Interfaz_de_programaci%C3%B3n_de_aplicaciones">API</a> que permite a los desarrolladores integrar sus programas con nuestra música, lo que ha permitido desarrollar aplicaciones con las que acceder a nuestro servidor Ampache sin necesidad de un navegador web, así como <a href="https://es.wikipedia.org/wiki/Complemento_%28inform%C3%A1tica%29">plugins</a> para muchos otros reproductores de música existentes (como <a href="https://wiki.gnome.org/Apps/Rhythmbox/">Rhythmbox</a>, <a href="https://amarok.kde.org/">Amarok</a>, etc).</p>
<p>En la actualidad continua siendo un proyecto activo y en continuo desarrollo, del que se lanzan nuevas versiones cada cierto tiempo con corrección de errores y nuevas funcionalidades.</p>
<p>Se puede consultar la lista de versiones en este enlace: <a href="https://github.com/ampache/ampache/releases">Releases de Ampache en Github</a>.</p>
<h2>Instalación<a name="instalacion"></a></h2>
<p>Desde la versión 3.3 (liberada a mediados de 2005) Ampache dispone de un instalador web que facilita enormemente la instalación. Aún así voy a explicar paso a paso el proceso desde 0 para aquellos <em>merluzos</em> que acaben de salir de Matrix y estén aún un poco desorientados...</p>
<p>En mi caso, voy a instalar Ampache en una <a href="https://es.wikipedia.org/wiki/Raspberry_Pi">Raspberry PI</a> (concretamente en una <a href="https://www.raspberrypi.org/products/raspberry-pi-2-model-b/">Raspberry PI 2 Model B</a>, porque si lo haceis en modelos de Raspberry PI anteriores irá lentísimo, lo digo por experiencia) porque mi intención es tenerla encendida siempre para poder acceder a mi música cuando y desde donde quiera, y dado que el consumo eléctrico de la Raspberry PI es casi despreciable (entre 2,5W y 4W dependiendo del modelo), puede estar encendida siempre sin que yo tenga que prostituirme para pagar la factura de la luz (pero obviamente el procedimiento es el mismo si queréis instalar Ampache en un servidor <em>normal</em>, en vuestro ordenador o donde sea).</p>
<p>Partimos de la base de que ya tenemos la Raspberry PI con el sistema operativo instalado, por lo que si no es así, ya expliqué <a href="/2014/08/01/instalacion-de-raspbian-en-la-nueva-raspberry-pi-b-plus/">en éste otro artículo como instalar Raspbian</a> ¿A qué esperas? Hazlo antes de seguir adelante!</p>
<p>Una vez tengamos la Raspberry PI lista y funcionando (o el servidor donde vayamos a instalar nuestro Ampache) instalamos todas las dependencias que Ampache necesita.</p>
<p>Si nuestro sistema operativo es <a href="https://www.debian.org/">Debian</a> (o <a href="http://www.raspbian.org/">Raspbian</a> en la Raspberry PI) simplemente bastaría con ejecutar:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install apache2 mysql-server php5 php5-curl php5-mysql php5-gd
</code></pre></div>
<p>Si por el contrario somos masoquistas y usamos <a href="https://www.centos.org/">CentOS</a>, <a href="http://www.redhat.com/es">Redhat</a> o distribuciones similares, tendremos que ejecutar:</p>
<div class="highlight"><pre><span></span><code>$ sudo yum install httpd mysql-server php php-curl php-mysql php-gd
</code></pre></div>
<p>Ahora tenemos que descargar Ampache, y esto podemos hacerlo de varias formas:</p>
<ul>
<li>Descargar la última versión <a href="https://github.com/ampache/ampache/archive/master.tar.gz">desde aqui</a>.</li>
<li>Descargar la versión que queramos desde su página de <a href="https://github.com/ampache/ampache/tags">Github</a>.</li>
<li>Clonar la rama <em>master</em> de su repositorio de <a href="https://www.git-scm.com/">GIT</a>: <code>git clone https://github.com/ampache/ampache.git</code></li>
</ul>
<p>Independientemente de cómo lo hagáis, a partir de la versión 3.8.1 tendréis también que actualizar las dependencias de PHP a través de <a href="https://getcomposer.org/">Composer</a>. Para hacer esto bastaría con situaros en el directorio donde hayas descomprimido el código de Ampache que os acabáis de bajar, y ejecutar:</p>
<div class="highlight"><pre><span></span><code>$ composer install --prefer-source --no-interaction
</code></pre></div>
<p>Pero si no disponéis de Composer (o no queréis usarlo) podéis bajar una versión de Ampache que ya lleve todas las dependencias de PHP necesarias incluidas. Estas versiones se llaman `ampache-x.x.x_all.zip, y podéis encontrarlas en la página de descargas de Ampache, en esta dirección: https://github.com/ampache/ampache/releases/latest</p>
<p>En este momento la última versión estable de Ampache es la 3.8.1, por lo que la descargamos en el directorio temporal del sistema <code>/tmp</code> y la descomprimimos en el directorio donde lo vamos a dejar (y que tiene que ser accesible para el servidor web Apache):</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">cd</span> /tmp
$ wget https://github.com/ampache/ampache/releases/download/3.8.1/ampache-3.8.1_all.zip
$ sudo mkdir /var/www/ampache
$ <span class="nb">cd</span> /var/www/ampache
$ sudo unzip /tmp/ampache-3.8.1_all.zip
</code></pre></div>
<p>Necesitamos que el programa de instalación pueda escribir en el directorio de Ampache (para generar el archivo de configuración, entre otras cosas), por lo que asignamos los permisos y propietarios necesarios en el recién creado directorio:</p>
<div class="highlight"><pre><span></span><code>$ sudo chown www-data:www-data /var/www/ampache -R
$ sudo chmod <span class="m">755</span> /var/www/ampache -R
</code></pre></div>
<p>Una vez hecho esto, ya podemos iniciar al programa de instalación: abrimos el navegador y accedemos a la dirección del servidor donde hayamos instalado Ampache.</p>
<p>En mi caso, mi Raspberry PI tiene la IP 172.26.0.11, por lo que la dirección a la que tengo que acceder es: <code>http://172.26.0.11/ampache/install.php</code>.</p>
<p>Si todo ha ido bien hasta ahora, deberíamos estar viendo una pantalla como ésta:</p>
<p><img class="center" src="/images/posts/ampache/ampache_install_01.png"></p>
<p>Seleccionamos el idioma que queramos, y continuamos con la instalación...</p>
<p>El programa de instalación comprobará las dependencias y requisitos de Ampache y nos indicará si alguno de ellos no está instalado o configurado correctamente:</p>
<p><img class="center" src="/images/posts/ampache/ampache_install_02.png"></p>
<p>En este caso podemos ver 2 <em>advertencias</em>, la primera relativa al tamaño máximo de los archivos que podemos subir a nuestro servidor (Ampache recomienda que fijemos dicho valor al menos a 20Mb), y la otra es acerca del tamaño máximo de los archivos que Ampache puede manejar (se recomienda que Ampache sea capaz de manejar archivos mayores a 2Gb, pero como esto generalmente requiere un sistema operativo de <a href="https://es.wikipedia.org/wiki/64_bits">64 bits</a>, y la Raspberry PI no lo soporta, en nuestro caso no podemos hacerlo).</p>
<p>Ambos avisos son únicamente advertencias, lo que significa que son recomendables pero no necesarios, por lo que podemos ignorarlos y seguir adelante con la instalación.</p>
<p>En el caso de querer solucionarlos, para el primero deberíamos configurar el valor de la directiva <code>upload_max_filesize</code> al menos a <code>20M</code> en el archivo de configuración de PHP <code>/etc/php5/apache2/php.ini</code>. Una vez configurado debemos reiniciar Apache para que aplique el cambio con:</p>
<div class="highlight"><pre><span></span><code>$ sudo service apache2 restart
</code></pre></div>
<p>Y para solucionar la segunda advertencia, poco podemos hacer salvo instalar Ampache en un sistema operativo de 64 bits, lo que requerirá que lo hagamos en un servidor cuyo procesador/procesadores sean de 64 bits (cualquier servidor medianamente actual utiliza procesadores de 64 bits).</p>
<p>Si hubiera algún otro punto que debiéramos corregir, se nos indicaría en esa pantalla. Normalmente bastaría con instalar la dependencia que Ampache nos diga y recargar la página de nuevo para que el programa de instalación nos permitiera continuar.</p>
<p>En la siguiente pantalla debemos configurar el acceso a la base de datos.</p>
<p><img class="center" src="/images/posts/ampache/ampache_install_03.png"></p>
<p>Por motivos obvios de seguridad, no es una buena idea que Ampache utilice un usuario de base de datos con más permisos de los necesarios para su funcionamiento. Es decir, que el usuario de base de datos de Ampache únicamente debería tener permisos para acceder a las tablas de la base de datos de Ampache, y <strong>no a las demás bases de datos</strong> que pudiéramos tener en el servidor.</p>
<p>Para hacer esto normalmente accederíamos a la base de datos con un usuario administrador, y una vez dentro creamos la base de datos que vayamos a utilizar y un usuario normal que solo disponga de permisos sobre dicha base de datos, pero en éste caso el propio programa de instalación de Ampache se encarga de hacerlo todo él solito, por lo que únicamente debemos indicarle el usuario/contraseña de un usuario administrador de MySQL, marcar las casillas de <em>"Crear base de datos"</em>, <em>"Crear tablas"</em> y <em>"Crear nuevo usuario"</em> (indicando el nombre de usuario y contraseña que queramos para éste nuevo usuario), y él lo hará todo.</p>
<p>Si todo ha ido bien, después de la creación de la base de datos se nos mostrará una pantalla como ésta:</p>
<p><img class="center" src="/images/posts/ampache/ampache_install_04.png"></p>
<p>En esta pantalla debemos configurar el tipo de instalación que queremos hacer, los programas de <a href="https://es.wikipedia.org/wiki/Transcodificar">transcodificación</a> y los <a href="https://es.wikipedia.org/wiki/Interfaz_de_programaci%C3%B3n_de_aplicaciones">interfaces</a> que queremos habilitar.</p>
<p>En cuanto al tipo de instalación, debemos elegir entre:</p>
<ul>
<li><strong>Instalación por defecto</strong>: La instalación <em>normal</em> de Ampache, con la mayoría de funcionalidades ya habilitadas.</li>
<li><strong>Instalación mínima</strong>: Únicamente se instalarán las opciones mínimas para poder reproducir nuestra música desde un navegador web.</li>
<li><strong>Instalación de comunidad</strong>: Podemos configurar nuestro servidor Ampache para dar servicio a una comunidad musical (un grupo de amigos con gustos musicales en común, por ejemplo) de forma que puedan interactuar entre ellos recomendándose canciones, creando listas de reproducción compartidas, etc.</li>
</ul>
<p>Los programas de transcodificación se utilizan para convertir determinados formatos musicales en otros. Ampache puede hacer esto <em>al vuelo</em>, convirtiendo de un formato a otro (por necesidades específicas del reproductor que estemos usando, por ejemplo) utilizando <a href="https://ffmpeg.org/">FFmpeg</a> u otros programas similares. Obviamente debemos tener éstos programas ya instalados para poder utilizar ésta opción.</p>
<p>En cuanto a los interfaces que podemos habilitar, Ampache es capaz de soportar (aparte del propio acceso web desde cualquier navegador) una <a href="https://es.wikipedia.org/wiki/Interfaz_de_programaci%C3%B3n_de_aplicaciones">API</a> (utilizada por los plugins de algunos reproductores, como <a href="https://amarok.kde.org/">Amarok</a> o <a href="https://wiki.gnome.org/Apps/Rhythmbox/">Rhythmbox</a>), protocolos de contenido multimedia (como <a href="http://daap.sourceforge.net/">DAAP</a>, <a href="https://es.wikipedia.org/wiki/Universal_Plug_and_Play">UPnP</a>, etc) y algunos más.</p>
<p>Al igual que con los programas de transcodificación, debemos tener instalados y configurados éstos interfaces para poder utilizarlos con Ampache, tal y como explican en su <a href="https://github.com/ampache/ampache/wiki/API">página Wiki</a>.</p>
<p>Por el momento nosotros somos vamos a utilizar <code>Web interface</code> (para acceder desde el navegador) y <code>Ampache API</code> (para acceder desde <a href="https://wiki.gnome.org/Apps/Rhythmbox/">Rhythmbox</a>).</p>
<p>Pero lo más importante de ésta pantalla del instalador es lo que hay en la parte de abajo:</p>
<p><img class="center" src="/images/posts/ampache/ampache_install_05.png"></p>
<p>Estos son los archivos que el programa de instalación necesita crear para que Ampache funcione correctamente, y os está indicando que dichos archivos NO existen, <strong>lo cual es completamente correcto</strong> (y tiene que ser así) ya que es el propio programa de instalación el que debe encargarse de crearlos. Por lo tanto, <strong>SIN pulsar</strong> en los botones de <em>"Guardar"</em> que hay junto a cada archivo, pulsamos directamente el botón de <em>"Crear configuración"</em> (<em>"Create config"</em> si habéis elegido el inglés como idioma en el primer paso) para que sea el instalador quien cree los archivos. Si no lo hacéis así y generáis los archivos individualmente, el instalador fallará en el siguiente paso porque creerá que los archivos ya existen.</p>
<p>Hecho esto, se os mostrará la última parte de la instalación:</p>
<p><img class="center" src="/images/posts/ampache/ampache_install_06.png"></p>
<p>Aquí ya únicamente debemos crear la cuenta de administrador de nuestro Ampache, la cual utilizaremos únicamente para entrar la primera vez y crearnos un usuario (porque recordar que como regla general en todos los ámbitos, <strong>NUNCA</strong> se trabaja con el usuario administrador).</p>
<p>Si todo ha ido bien, el programa de instalación debería haberos redirigido a la pantalla de <em>login</em>, por lo que deberíais estar viendo algo parecido a esto:</p>
<p><img class="center" src="/images/posts/ampache/ampache_install_07.png"></p>
<p>Enhorabuena, ya tienes tu Ampache instalado!</p>
<h2>Configuración<a name="configuracion"></a></h2>
<p>La instalación de Ampache es muy sencilla, pero su configuración lo es aún más.</p>
<p>Realmente solo necesitaríamos configurar un <em>catálogo</em> para que Ampache empezara a leerlo en busca de música, películas, etc. Los catálogos no son más que <em>orígenes</em> de datos, directorios o unidades montadas en nuestro servidor donde almacenamos los archivos de nuestra biblioteca multimedia.</p>
<p>Como os comenté al principio del artículo, en mi caso todo lo tengo en una NAS, la cual he montado a través de <a href="https://es.wikipedia.org/wiki/Samba_%28programa%29">SAMBA</a> en la <em>Raspberry PI</em> donde he instalado Ampache... de forma que para éste último es como si todo estuviera en un directorio local.</p>
<p>Accedemos a través del menú principal a la sección de <em>"Administración"</em>, y desde ahí nos vamos a <em>"Añadir un catálogo"</em>:</p>
<p><img class="center" src="/images/posts/ampache/ampache_install_08.png"></p>
<p>En ésta versión de Ampache el catálogo puede ser <em>local</em> (un directorio del servidor donde se ejecuta Ampache) o <em>remoto</em> (otro servidor Ampache que tengamos montado en otra parte y del que queramos extraer la música).</p>
<p>Le damos un nombre al catálogo, seleccionamos que es de tipo <em>local</em>, el tipo de contenido que hay en el (música, en éste caso) y la ruta del directorio donde hayamos montado la NAS o donde tengamos la música. Pulsamos en <em>"Añadir catálogo"</em> y listo... ya tenemos a Ampache trabajando para examinar todo el contenido del catálogo.</p>
<p>Dependiendo del tamaño de nuestra biblioteca multimedia y del hardware del servidor donde hayamos instalado Ampache, tardaremos más o menos tiempo en tener los datos disponibles. Pero una vez finalizado el proceso, podemos acceder a través del menú lateral al listado de canciones, álbumes, artistas o lo que queramos:</p>
<p><img class="center" src="/images/posts/ampache/ampache_install_09.png"></p>
<p>Es importante que tengáis la música con sus <a href="https://es.wikipedia.org/wiki/ID3">etiquetas ID3</a> correctamente definidas, ya que es en ellas en lo que se basa Ampache para obtener los datos de las canciones, carátulas de los discos, nombres de los artistas, etc, etc.</p>
<p>Si seleccionamos el modo <code>Reproductor Web</code> (o <code>Web Player</code> si habéis elegido el idioma ingles) en el desplegable de la esquina superior derecha de Ampache, solo tenéis que pulsar el <code>PLAY</code> de alguna canción para que comience a reproducirse:</p>
<p><img class="center" src="/images/posts/ampache/ampache_install_10.png"></p>
<p>Si por el contrario, seleccionais <code>Streaming</code> en lugar de <code>Reproductor Web</code>, al pulsar el <code>PLAY</code> de una canción se os devolverá un archivo con extensión <a href="https://es.wikipedia.org/wiki/M3U">M3U</a> que podréis abrir desde cualquier reproductor de sonido que admita dicho formator de lista de reproducción en streaming, como por ejemplo <a href="http://www.xmms.org/">XMMS</a>, <a href="http://www.apple.com/es/itunes/">iTunes</a>, <a href="http://www.videolan.org/vlc/">VLC</a>, etc.</p>
<p>A partir de aquí solo os queda familiarizaros con el interface de Ampache, probar sus diferentes opciones, arreglar los tags ID3 de aquellas canciones que Ampache no reconozca (para lo cual os recomiendo el programa <a href="http://quodlibet.readthedocs.org/en/latest/">Ex Falso / Quod Libet</a>), probar si va igual de bien con la reproducción de video en lugar de únicamente con el audio (esto aún no lo he probado yo tampoco), etc.</p>
<p>Espero que Ampache os haya resultado como mínimo interesante, y que éste artículo os haya servidor de ayuda a la hora de probarlo. A mi desde luego me va a proporcionar muchas horas de música allá donde esté y sin depender de nadie!</p>
<p>Alaaaaaaaaaaaaaaaaaaaaaaa</p>
<h2>Referencias<a name="refs"></a></h2>
<ul>
<li><a href="http://ampache.org/">http://ampache.org/</a></li>
<li><a href="https://github.com/ampache/ampache/wiki/Installation">https://github.com/ampache/ampache/wiki/Installation</a></li>
<li><a href="http://www.my.oltrans.bg/en/ubuntu/faqs/40-general/110-how-to-audio-video-streaming-and-file-sharing-with-ampache.html">http://www.my.oltrans.bg/en/ubuntu/faqs/40-general/110-how-to-audio-video-streaming-and-file-sharing-with-ampache.html</a></li>
</ul>Creación de un bot de Telegram en PHP2015-08-12T19:48:53+02:002015-08-12T19:48:53+02:00BhEaNtag:pornohardware.com,2015-08-12:/2015/08/12/creacion-de-un-bot-de-telegram-en-php/<p>Siempre defiendo que <a href="https://telegram.org/">Telegram</a> es <a href="/2014/11/18/telegram-aun-hay-esperanza-para-las-apps-de-mensajeria">la mejor app de mensajería</a> que existe a día de hoy, no solo porque de verdad se preocupen por la seguridad y privacidad de las comunicaciones de sus usuarios (no como <a href="https://www.eff.org/who-has-your-back-government-data-requests-2015#whatsapp-report">otros</a>), ni por la calidad de sus apps frente a las de sus <em>competidores</em>, sino porque entre muchas otras cosas, mantienen un ritmo muy alto de actualizaciones que hacen que cada poco tiempo tengamos disponibles nuevas versiones con nuevas y mejores funcionalidades.</p>
<p>En este artículo hablaré de una de sus últimas funcionalidades, concretamente de la <a href="https://es.wikipedia.org/wiki/Interfaz_de_programaci%C3%B3n_de_aplicaciones">API</a> que la gente de Telegram ha liberado para su uso público, y que permite a cualquier programador crear <a href="https://es.wikipedia.org/wiki/Bot">bots</a> para interactuar con otros usuarios a través de conversaciones de Telegram.</p>
<p>Y no solo a programadores, sino que gracias a algunas herramientas (como por ejemplo <a href="http://paquebot.io/">paquebot.io</a>) cualquier persona con un mínimo de interés y ganas de <em>trastear</em> un poco puede hacerlo.</p>
<p>Pero esto es un blog técnico, no una web de noticias para <a href="https://es.wikipedia.org/wiki/Luser"><em>lusers</em></a>, así que déjate de asistentes, <a href="https://es.wikipedia.org/wiki/Interfaz_gr%C3%A1fica_de_usuario">GUIs</a> y demás <em>mariconadas</em> y vamos a programar...</p>
<p>Siempre defiendo que <a href="https://telegram.org/">Telegram</a> es <a href="/2014/11/18/telegram-aun-hay-esperanza-para-las-apps-de-mensajeria">la mejor app de mensajería</a> que existe a día de hoy, no solo porque de verdad se preocupen por la seguridad y privacidad de las comunicaciones de sus usuarios (no como <a href="https://www.eff.org/who-has-your-back-government-data-requests-2015#whatsapp-report">otros</a>), ni por la calidad de sus apps frente a las de sus <em>competidores</em>, sino porque entre muchas otras cosas, mantienen un ritmo muy alto de actualizaciones que hacen que cada poco tiempo tengamos disponibles nuevas versiones con nuevas y mejores funcionalidades.</p>
<p>En este artículo hablaré de una de sus últimas funcionalidades, concretamente de la <a href="https://es.wikipedia.org/wiki/Interfaz_de_programaci%C3%B3n_de_aplicaciones">API</a> que la gente de Telegram ha liberado para su uso público, y que permite a cualquier programador crear <a href="https://es.wikipedia.org/wiki/Bot">bots</a> para interactuar con otros usuarios a través de conversaciones de Telegram.</p>
<p>Y no solo a programadores, sino que gracias a algunas herramientas (como por ejemplo <a href="http://paquebot.io/">paquebot.io</a>) cualquier persona con un mínimo de interés y ganas de <em>trastear</em> un poco puede hacerlo.</p>
<p>Pero esto es un blog técnico, no una web de noticias para <a href="https://es.wikipedia.org/wiki/Luser"><em>lusers</em></a>, así que déjate de asistentes, <a href="https://es.wikipedia.org/wiki/Interfaz_gr%C3%A1fica_de_usuario">GUIs</a> y demás <em>mariconadas</em> y vamos a programar...</p>
<ol>
<li><a href="#bot">Qué es un bot?</a></li>
<li><a href="#apitelegrambot">Introducción a la API de Telegram Bot</a></li>
<li><a href="#registrarbot">Registro de un nuevo bot</a></li>
<li><a href="#updates">Formas de obtener los mensajes de Telegram</a></li>
<li><a href="#coding">Programación del bot</a></li>
<li><a href="#refs">Referencias</a></li>
</ol>
<h2>Qué es un bot?<a name="bot"></a></h2>
<p>Antes de explicar cómo hacerlos, hay que entender qué son exactamente los bots.</p>
<p>La <a href="https://es.wikipedia.org">Wikipedia</a> define los bots como <em>programas informáticos que imitan el comportamiento de un humano</em>, es decir, como mi exnovia.</p>
<p>Por lo tanto, si estamos hablando de un bot para Telegram, en realidad estamos hablando de un programa con el que podríamos <em>hablar</em> del mismo modo que haríamos con cualquier persona, como si de una conversación normal entre personas se tratase, solo que uno de los interlocutores sería un programa informático.</p>
<p>Por poner un ejemplo práctico y fácilmente entendible <strong>incluso</strong> para vosotros, humanos, podríamos hacer un bot en PHP que estuviera en uno de nuestros servidores, y desde la app de Telegram podríamos abrir una conversación con él, enviándole comandos para ver (por ejemplo) el número de registros que hay en una tabla de una base de datos, la cantidad de espacio en disco libre que nos queda, o cualquier otra cosa que os imaginéis. Nosotros le preguntamos, y el nos contesta.</p>
<p>Telegram únicamente nos brinda (que no es poco) una serie de <a href="https://es.wikipedia.org/wiki/Localizador_de_recursos_uniforme">URL's</a> (llamadas <em>endpoints</em>) a través de las cuales podemos enviar o recibir datos de una conversación de la app de Telegram.</p>
<p>Es decir, el funcionamiento del bot y lo que se pueda hacer con él depende únicamente de ti, Telegram solo hace de <em>intermediario</em> en la comunicación entre el usuario y el bot, encriptando toda la transmisión con su genial protocolo <a href="https://core.telegram.org/mtproto">MTProto</a> para que tu no tengas que preocuparte de la comunicación, sino del contenido de la misma.</p>
<p>La comunicación entre nuestro bot y la <a href="https://core.telegram.org/bots/api">API de Telegram</a> se hace a través del lenguaje de marcado <a href="https://es.wikipedia.org/wiki/JSON">JSON</a>. Nosotros enviamos un JSON con los comandos y parámetros necesarios para lo que queramos hacer, y ellos nos devuelven otro JSON con el resultado.</p>
<p>Vista la teoría, vamos con un poco de práctica...</p>
<h2>Introducción a la API de Telegram Bot<a name="apitelegrambot"></a></h2>
<p>Como he comentado en el punto anterior, la <a href="https://core.telegram.org/bots/api">API de Telegram Bot</a> está formada por una serie de URL's (de ahora en adelante las llamaré <em>endpoints</em>) en el servidor de Telegram a través de las cuales podemos obtener y enviar datos utilizando JSON.</p>
<p><img class="left" src="/images/logos/logo_telegram.png">
Éstos datos pueden ser mensajes de una conversación, información sobre el usuario que está hablando con el bot, una imagen enviada a través de Telegram, etc.</p>
<p>Todos éstos endpoints tienen que ser llamados a través de <a href="https://es.wikipedia.org/wiki/Hypertext_Transfer_Protocol_Secure">HTTPS</a> por cuestiones obvias de seguridad, y en todas las llamadas debemos enviar el <a href="https://es.wikipedia.org/wiki/Token_%28inform%C3%A1tica%29">token</a> de nuestro bot, es decir, el identificador que Telegram le haya asignado a nuestro bot... porque lo primero que hay que hacer para programar un bot en Telegram es decirle a Telegram que queremos programar un bot. En ese momento ellos nos asignarán un identificador único que les permitirá saber que es nuestro bot y no otro el que les está <em>hablando</em> (ya veremos más adelante cómo obtener éste token, no os preocupéis ahora por esto).</p>
<p>Para que todo esto os quede más claro, vamos con un ejemplo:
Existe un endpoint llamado <code>getMe</code> que devuelve algunos datos de nuestro bot, y es el que se suele utilizar para comprobar que nuestro bot está registrado correctamente.</p>
<p>Las URL's de los endpoints de la API de Telegram están formadas por:</p>
<ul>
<li>Protocolo a utilizar: <em>htt<b></b>ps://</em></li>
<li>Servidor de la API de Telegram Bot: <em>api.telegram.org/</em></li>
<li>La palabra <code>bot</code> seguida del token que nos hayan asignado al registrarlo: <em>bot13724466:AAETkFQjiQGlLeJMchaZr2Kfjih3V3h6uua</em></li>
<li>El comando al que estemos llamando: <em>getMe</em></li>
</ul>
<p>Es decir, según nuestro ejemplo la URL a la que tendríamos que llamar tendría este aspecto:
<code>https://api.telegram.org/bot13724466:AAETkFQjiQGlLeJMchaZr2Kfjih3V3h6uua/getMe</code></p>
<p>Si hacemos una llamada a dicho endpoint, el servidor de Telegram nos devolverá un JSON con los datos de nuestro propio bot:</p>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">"ok"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="nt">"result"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">13724466</span><span class="p">,</span>
<span class="nt">"first_name"</span><span class="p">:</span> <span class="s2">"pornoHARDWARE.com"</span><span class="p">,</span>
<span class="nt">"username"</span><span class="p">:</span> <span class="s2">"PornoHardwareBot"</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>Ahora que hemos visto más o menos como funciona, vamos a registrar nuestro bot para que nos asignen un token.</p>
<h2>Registro de un nuevo bot<a name="registrarbot"></a></h2>
<p>¿Qué mejor forma de iniciarse en la programación de un bot que usando uno de ellos para poder empezar a programar el nuestro? Eso es lo que debieron pensar los <em>cachondos</em> que hay detrás de Telegram, por lo que para poder registrar nuestros bots y que se nos asigne un token debemos utilizar un bot llamado <strong><em>Botfather</em></strong>.</p>
<p><em>Botfather</em> es un bot desde el cual podemos solicitar el token para un nuevo bot, cambiar la descripción de un bot que ya hayamos registrado, cambiar el <em>username</em> de nuestro bot, su imagen de perfil, etc.</p>
<p>Solo tenemos que abrir nuestra app de Telegram desde el móvil o desde nuestro ordenador y comenzar una conversación con el usuario <strong>@bothfather</strong>:</p>
<p><img class="center" src="/images/posts/telegrambot/screenshot_01.png"></p>
<p>Nada más empezar, nos indica la lista de comandos disponibles:</p>
<ul>
<li>/newbot</li>
<li>/token</li>
<li>/revoke</li>
<li>/setname</li>
<li>/setdescription</li>
<li>/setabouttext</li>
<li>/setuserpic</li>
<li>etc...</li>
</ul>
<p>Ya os habréis dado cuenta de que los comandos que se usan para <em>hablar</em> con los bots llevan la barra <code>/</code> delante, verdad?</p>
<p>En el caso de los comandos de Botfather, todos tienen un nombre bastante autodescriptivo, pero aún así explicaré algunos un poco para aquellos que vengáis de la <a href="https://es.wikipedia.org/wiki/Ley_Org%C3%A1nica_de_Ordenaci%C3%B3n_General_del_Sistema_Educativo_de_Espa%C3%B1a">LOGSE</a>:</p>
<h3>/newbot</h3>
<p>Con éste comando le decimos al bot de Telegram que queremos registrar un nuevo bot.
Botfather comenzará entonces una serie de preguntas para registrar nuestro bot, como por ejemplo el nombre <em>común</em> del bot, su nombre de usuario (<a href="https://es.wikipedia.org/wiki/Alias">nickname</a>), etc. Para el nombre <em>común</em> del bot podemos utilizar lo que queramos, pero para el nombre de usuario hay que tener en cuenta que todos los bots de Telegram deben terminar en <strong>bot</strong> o en <strong>_bot</strong>.</p>
<p>Para nuestro ejemplo utilizaremos como nombre común <code>pornoHARDWARE.com</code> y como nombre de usuario <code>PornoHardwareBot</code>.</p>
<p>Cuando hayáis terminado de registrar el bot, Botfather os responderá con el <em>token</em> que os haya asignado, el cual debéis guardar para poder utilizar la API de Telegram Bot.</p>
<p>A partir de este punto, vuestro bot estará registrado y nadie salvo vosotros podrá utilizar el nombre de usuario que hayáis elegido (hay un máximo de 20 bots por <em>persona</em> (supongo que serán 20 bots por cada usuario de Telegram) por lo que si se os va la mano registrando bots (como me pasó a mi el día que salió éste tema xDD) botfather se encargará de avisaros de que ya no podéis registrar más (con una genial cita de la aún más genial película <em>El Padrino</em>, cuyo título original es <em>Godfather</em>, de ahí la parodia de <em>Botfather</em>):</p>
<p><img class="center" src="/images/posts/telegrambot/screenshot_02.png">
<em>No puedo hacer eso. Vienes a mi preguntando por más de 20 bots, pero no lo pides con respeto, no me ofreces tu amistad, ni siquiera me llamas <em>botfather</em>...</em></p>
<h3>/token</h3>
<p>Este comando genera un nuevo token para el bot que le indiquemos a Botfather. Obviamente solo podemos cambiar el token de aquellos bots que hayamos registrado nosotros.</p>
<h3>/revoke</h3>
<p>Invalida el token actual del bot que le indiquemos, de forma que el bot deje de tener acceso inmediatamente. Supongo que es por seguridad, por si alguna vez alguien nos roba el token y tenemos que generar uno nuevo.</p>
<h3>/setname</h3>
<p>Especifica el nombre común del usuario del bot que le indiquemos. Éste nombre es el que le aparecerá a los usuarios cuando, por ejemplo, nuestro bot les envíe una <a href="https://es.wikipedia.org/wiki/Tecnolog%C3%ADa_Push">notificación <em>push</em></a>.</p>
<h3>/setdescription</h3>
<p>Por defecto, la primera vez que un usuario abre una conversación con nuestro bot, le aparecerá el mensaje que indiquemos aquí. Se usa como mensaje de <em>bienvenida</em>, así como para explicar brevemente a sus usuarios en qué consiste nuestro bot.</p>
<p>Es recomendable que nos tomemos un tiempo en establecer una descripción adecuada, con un texto claro y simple que explique a los usuarios qué pueden hacer con nuestro bot.</p>
<h3>/setabouttext</h3>
<p>Parecido al anterior, pero aquí indicamos un breve texto sobre el autor del bot (nosotros).</p>
<h3>/setuserpic</h3>
<p>Establece la imagen que le enviemos como icono de nuestro bot. La imagen debe ser lo suficientemente grande como para que al aumentarla de tamaño se siga viendo bien (dependiendo de donde se muestro, a veces Telegram redimensiona la imagen y si no tiene la resolución necesaria, ésta se verá muy <a href="https://es.wikipedia.org/wiki/Pixelado">pixelada</a>).</p>
<p>Tiene que ser cuadrada, y recomiendo que tenga al menos unas dimensiones de 250px x 250px, aunque cuanto mayor sea, mejor (Telegram se encargará de reducir la imagen según sus necesidades).</p>
<h3>/setcommands</h3>
<p>Indica la lista de comandos que tendrá nuestro bot. Aunque no pongamos aquí todos los comandos que tengamos, éstos funcionarán igual. Supongo que ésta opción es solo para uso interno suyo (de Telegram), estadísticos o para mostrar la lista en alguna parte... pero vamos, que no hace falta que los indiquéis todos aquí para que funcionen.</p>
<h3>/setjoingroups</h3>
<p>Con este comando podemos establecer si nuestro bot puede participar en conversaciones de grupo o solo en conversaciones <em>privadas</em> con un usuario.</p>
<p>A no ser que tengamos una buena razón para hacerlo (por motivos de seguridad o privacidad), no veo porqué habríamos de limitar el funcionamiento de nuestro bot únicamente a conversaciones privadas.</p>
<h3>/setprivacy</h3>
<p>Este comando es importante, ya que establece algunas políticas de seguridad para nuestro bot.</p>
<p>Podemos activar o desactivar el <em>modo privacidad</em>, lo que provoca que nuestro bot <strong>NO recibirá</strong> ningún mensaje que le enviemos en aquellas conversaciones de grupo en las que esté, a excepción de:</p>
<ul>
<li>Los mensajes que empiecen por <code>/</code>.</li>
<li>Los mensajes que mencionen al bot a través de <em>@nombrebot</em>.</li>
<li>Los mensajes que sean respuestas a los propios mensajes enviados por el bot, es decir, cuando respondamos a uno de los mensajes del bot.</li>
<li>Los mensajes de <em>servicio</em>, es decir, los mensajes que indican que <em>fulanito</em> ha sido añadido o eliminado del grupo, y cosas así.</li>
</ul>
<p>De esta forma podemos añadir nuestro bot a una conversación de grupo donde hay más gente sin que le lleguen al bot todos los mensajes que se <em>digan</em> en dicha conversación a partir de ese momento.</p>
<p>Una vez que hayamos registrado nuestro bot, tengamos el token correspondiente y hayamos configurado la descripción, imagen, modo privacidad, etc. con los comandos anteriores, podemos empezar con la programación del bot... aunque os recomiendo que llegados a éste punto, abráis vuestro cliente de Telegram e intentéis abrir una conversación con vuestro recién registrado bot.</p>
<p>Solo tenéis que abrir una nueva conversación, y cuando os pida que seleccionéis el destinatario de dicha conversación, tecleáis el nombre de vuestro bot... y una vez os aparezca en la lista de <em>contactos</em> que coinciden con dicho nombre, lo seleccionáis y empezáis a <em>hablar con el</em> (todavía no os contestará nada, pero podéis probar a decirle <code>/start</code> o <code>/help</code> o cualquier otra cosa).</p>
<h2>Formas de obtener los mensajes de Telegram<a name="updates"></a></h2>
<p>Para este ejemplo vamos a utilizar <a href="http://php.net/">PHP</a> (que por mucho que <em>le joda</em> a los talibanes de <a href="https://www.python.org/">Python</a>, es un lenguaje cojonudo... al igual que éste último, por supuesto) pero podríamos hacer nuestro bot con cualquier lenguaje de programación que pudiera hacer llamadas a una dirección HTTPS, aunque según cómo lo diseñemos, podría ser necesario poder recibirlas también... tener esto en cuenta, aunque ya lo explicaré un pelín más adelante.</p>
<p>Como la API que Telegram ha publicado está formada por un conjunto de <em>endpoints</em> accesibles por HTTPS, podríamos programar nuestro bot con código propio, sin depender de ninguna librería de terceros, tan solo realizando peticiones con <a href="http://php.net/manual/es/book.curl.php">cURL</a>, <a href="http://php.net/manual/es/function.fopen.php">fopen</a> o cualquier otro <em>wrapper</em> HTTP, pero haremos un código mucho más limpio y mantenible si utilizamos alguna de las librerías de PHP para Telegram Bot de código libre que existen.</p>
<p>Hay muchas de éstas librerías, pero después de probar algunas de ellas, la que más me ha gustado ha sido <a href="https://github.com/TelegramBot/Api">TelegramBot/API: Native PHP Wrapper for Telegram Bot API</a>.</p>
<p>No solo me ha parecido la más sencilla y completa que he visto, sino que yo mismo he colaborado con algunos <a href="https://help.github.com/articles/using-pull-requests"><em>pull requests</em></a> con pequeñas nuevas funcionalidades y bugfixes (que espero que su autor haya aceptado antes de que termine éste artículo xDD).</p>
<p>Antes de empezar a programar el bot, debéis tener claro de qué forma vamos a obtener los mensajes de los usuarios que <em>hablen</em> con nuestro bot a través de Telegram.</p>
<p>Existen 2 formas de hacer esto, y ambas son distintas e incompatibles entre si:</p>
<ul>
<li><em>getUpdates</em>: Que seamos nosotros los que le pidamos a Telegram cada cierto tiempo que nos envíe los mensajes nuevos que haya desde la última vez que se los pedimos.</li>
<li><em>Webhook</em>: Que sea Telegram quien haga una petición a nuestro bot cada vez que nos envíen un mensaje con el contenido del mismo.</li>
</ul>
<p>Como podéis ver, en el primer caso (<code>getUpdates</code>)seríamos nosotros los que pediríamos a Telegram un listado de los mensajes que hubieran enviado los usuarios a nuestro bot, y en el segundo caso (<code>Webhook</code>) sería Telegram quien se conectaría a nuestro bot cada vez que recibiera un mensaje, enviándoselo <em>casi</em> en tiempo real.</p>
<p>Ambas formas pueden ser útiles según las necesidades de nuestro bot, y debemos pensar en ellas a la hora de diseñarlo, ya que o utilizamos una o utilizamos otra, pero no podemos usar las dos.</p>
<p>Para la mayoría de los casos, y a no ser que vayáis a tener un tráfico brutal de peticiones o tengáis problemas de <a href="https://es.wikipedia.org/wiki/Computaci%C3%B3n_concurrente">concurrencia</a>, creo que la mejor opción es la segunda, ya que no tendréis que <em>llevar la cuenta</em> de qué mensajes habéis procesado ya, sino que Telegram os irá enviando uno a uno cada nuevo mensaje que los usuarios escriban a vuestro bot casi en el mismo instante en el que los escriban (y e incluso si vuestro bot está <em>caído</em>, reintentarán el envío <em>unas cuantas veces</em> pasado unos segundos/minutos). Telegram llama a ésta forma de obtener los mensajes <code>Webhook</code>.</p>
<p>Sin embargo, si estimáis que el número de mensajes que vais a recibir podría ser <em>ingente</em> o podríais tener problemas si os llegaran varios mensajes al mismo tiempo (lo que provocaría varias <a href="https://es.wikipedia.org/wiki/Instancia_%28inform%C3%A1tica%29">instancias</a> de vuestro bot levantadas al mismo tiempo), entonces es mejor que uséis la primera opción y seáis vosotros los que vayáis pidiendo a Telegram la <em>actualización</em> de mensajes de forma <em>controlada</em> por vosotros. Telegram llama a ésta forma de obtener los mensajes <code>getUpdates</code>, ya que es así como se llama el <em>endpoint</em> encargado de hacerlo.</p>
<p>Vamos a ver cómo sería el código en cada caso.</p>
<h3>getUpdates</h3>
<p>Como ya vimos anteriormente, los <em>endpoints</em> de la API de Telegram Bot están formados por <code>URL</code> + <code>token</code> + <code>comando</code>, y dado que el comando en éste caso se llama <code>getUpdates</code>, la URL a la que deberíamos acceder para que Telegram nos devuelva los mensajes recibidos por nuestro bot sería:
https://api.telegram.org/bot13724466:AAETkFQjiQGlLeJMchaZr2Kfjih3V3h6uua/getUpdates</p>
<p>Opcionalmente, el <em>endpoint</em> <code>getUpdates</code> acepta 3 parámetros:</p>
<ul>
<li><strong>offset</strong>: ID del primer mensaje a devolver. Debe ser como mínimo uno más que el último ID de mensaje recibido. Es decir, si ahora pedimos el 150, el siguiente debe ser al menos el 151.</li>
<li><strong>limit</strong>: Número de mensaje a devolver (puede ser un valor de 0 a 100).</li>
<li><strong>timeout</strong>: Tiempo máximo de espera en segundos para esperar la respuesta del servidor de Telegram.</li>
</ul>
<p>Si todo ha ido bien, al hacer ésta llamada obtendremos un JSON con los últimos mensajes recibidos por el bot (aquellos mensajes que le enviamos en el punto anterior al terminar de registrar el bot mediante botfather). En éste caso, deberías obtener un JSON parecido a éste:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">getUpdates.json</span><a href='/files/telegrambot/telegrambot_getUpdates.json'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">"ok"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="nt">"result"</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span>
<span class="nt">"update_id"</span><span class="p">:</span> <span class="mi">546</span><span class="p">,</span>
<span class="nt">"message"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"message_id"</span><span class="p">:</span> <span class="mi">638</span><span class="p">,</span>
<span class="nt">"from"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">353453</span><span class="p">,</span>
<span class="nt">"first_name"</span><span class="p">:</span> <span class="s2">"BhEaN"</span><span class="p">,</span>
<span class="nt">"username"</span><span class="p">:</span> <span class="s2">"BhEaN"</span>
<span class="p">},</span>
<span class="nt">"chat"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">353453</span><span class="p">,</span>
<span class="nt">"first_name"</span><span class="p">:</span> <span class="s2">"BhEaN"</span><span class="p">,</span>
<span class="nt">"username"</span><span class="p">:</span> <span class="s2">"BhEaN"</span>
<span class="p">},</span>
<span class="nt">"date"</span><span class="p">:</span> <span class="mi">1439679501</span><span class="p">,</span>
<span class="nt">"text"</span><span class="p">:</span> <span class="s2">"\/start"</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="p">{</span>
<span class="nt">"update_id"</span><span class="p">:</span> <span class="mi">578</span><span class="p">,</span>
<span class="nt">"message"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"message_id"</span><span class="p">:</span> <span class="mi">640</span><span class="p">,</span>
<span class="nt">"from"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">353453</span><span class="p">,</span>
<span class="nt">"first_name"</span><span class="p">:</span> <span class="s2">"BhEaN"</span><span class="p">,</span>
<span class="nt">"username"</span><span class="p">:</span> <span class="s2">"BhEaN"</span>
<span class="p">},</span>
<span class="nt">"chat"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">353453</span><span class="p">,</span>
<span class="nt">"first_name"</span><span class="p">:</span> <span class="s2">"BhEaN"</span><span class="p">,</span>
<span class="nt">"username"</span><span class="p">:</span> <span class="s2">"BhEaN"</span>
<span class="p">},</span>
<span class="nt">"date"</span><span class="p">:</span> <span class="mi">1439679516</span><span class="p">,</span>
<span class="nt">"text"</span><span class="p">:</span> <span class="s2">"prueba de mensaje"</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">]</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>En éste JSON se puede ver 2 mensajes: uno con el <em>id</em> 546 y el otro con el 578 (es solo un ejemplo con datos inventados). Ambos mensajes fueron enviados por el usuario <em>id</em> 353453 con nombre <em>BhEaN</em>, y con los textos <code>/start</code> y <code>prueba de mensaje</code> respectivamente.</p>
<p>Pero como ya he dicho antes, si en lugar de hacer la petición HTTPS nosotros directamente lo hacemos a través de la API de PHP que os recomendé, el código PHP quedaría así de simple:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">getUpdates.php</span><a href='/files/telegrambot/telegrambot_getUpdates.php'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/BotApi.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Exception.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/InvalidArgumentException.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/BaseType.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/TypeInterface.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Message.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/User.php'</span><span class="p">);</span>
<span class="c1">// Inicializar bot con el token</span>
<span class="nb">define</span><span class="p">(</span><span class="nx">TOKEN</span><span class="p">,</span> <span class="s1">'13724466:AAETkFQjiQGlLeJMchaZr2Kfjih3V3h6uua'</span><span class="p">);</span>
<span class="nv">$bot</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">\TelegramBot\Api\BotApi</span><span class="p">(</span><span class="nx">TOKEN</span><span class="p">);</span>
<span class="c1">// Obtener actualizaciones de mensajes</span>
<span class="k">try</span>
<span class="nv">$aUpdates</span> <span class="o">=</span> <span class="nv">$bot</span><span class="o">-></span><span class="na">getUpdates</span><span class="p">();</span>
<span class="k">catch</span> <span class="p">(</span><span class="nx">\TelegramBot\Api\Exception</span> <span class="nv">$e</span><span class="p">)</span>
<span class="k">echo</span> <span class="s1">'ERROR!: '</span> <span class="o">.</span> <span class="nv">$e</span><span class="o">-></span><span class="na">getMessage</span><span class="p">());</span>
<span class="k">catch</span> <span class="p">(</span><span class="nx">\TelegramBot\Api\InvalidArgumentException</span> <span class="nv">$e</span><span class="p">)</span>
<span class="k">echo</span> <span class="s1">'ERROR!: '</span> <span class="o">.</span> <span class="nv">$e</span><span class="o">-></span><span class="na">getMessage</span><span class="p">());</span>
<span class="c1">// Recorrer resultados</span>
<span class="k">foreach</span> <span class="p">(</span><span class="nv">$aUpdates</span> <span class="k">as</span> <span class="nv">$aUpdate</span><span class="p">)</span> <span class="p">{</span>
<span class="nv">$oMessage</span> <span class="o">=</span> <span class="nv">$aUpdate</span><span class="p">[</span><span class="s1">'message'</span><span class="p">];</span>
<span class="c1">// Aquí ya podemos acceder a los datos de cada mensaje devuelto</span>
<span class="k">echo</span> <span class="s1">'ID del mensaje: '</span> <span class="o">.</span> <span class="nv">$oMessage</span><span class="o">-></span><span class="na">getMessageId</span><span class="p">();</span>
<span class="k">echo</span> <span class="s1">'Contenido del mensaje: '</span> <span class="o">.</span> <span class="nv">$oMessage</span><span class="o">-></span><span class="na">getText</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Una vez que hayamos obtenido y procesado los mensajes según las necesidades de nuestro bot, haremos las siguientes llamadas a <code>getUpdates</code> indicando como parámetro <em>offset</em> el último <code>MessageId</code> que hayamos obtenido + 1.</p>
<h3>Webhook</h3>
<p>A diferencia del método <code>getUpdates</code>, cuando utilizamos <code>Webhook</code> no hace falta llevar la cuenta de qué mensajes llevamos procesados para ir solicitando solo los que no, ya que será Telegram quien nos vaya enviado cada nuevo mensaje de forma individual.</p>
<p>Solo tenemos que decirle a Telegram la URL de nuestro bot, y ellos se encargarán de hacer una petición a dicha URL por cada mensaje que los usuarios envíen a nuestro bot... pero ojo! hay algo MUY importante que hay que tener en cuenta a la hora de utilizar <code>Webhook</code>, y es que de la misma forma que cuando nosotros hacemos una llamada a la API de Telegram debemos hacerlo utilizando HTTPS, Telegram también utilizará HTTPS cuando haga una llamada a nuestro bot, lo que significa que <strong>éste deberá estar alojado en un servidor que utilice SSL</strong>. Y es lógico... porque para qué se iba a molestar Telegram en encriptar los mensajes con su <em>súper algoritmo</em> <a href="https://core.telegram.org/mtproto">MProto</a>, proteger la privacidad de sus usuarios, implementar mecanismos de seguridad en los bots públicos, etc. si luego nosotros vamos a enviar todas las comunicaciones de nuestros bots a través de protocolos inseguros?.</p>
<p>Lo malo es que no solo nuestro bot debe estar alojado en un servidor que utilice certificados <a href="https://es.wikipedia.org/wiki/Transport_Layer_Security">SSL</a>, sino que dichos certificados deben ser certificados <strong>válidos</strong>: NO sirven certificados SSL autofirmados por nosotros, caducados o emitidos a un dominio distinto del nuestro, así que si no tenemos un certificado SSL válido nos tocará <em>pasar por caja</em> y comprar uno.</p>
<p>Pero no os preocupéis, comprar un certificado SSL ya no significa tener que <em>soltar varios cientos de euros</em> al año, sino que gracias a <a href="http://en.wikipedia.org/wiki/Lords_of_Kobol">los Dioses</a> existen sitios donde poder comprar certificados SSL <em>de bajo coste</em> (pero perfectamente válidos) por unos 5 € al año, como por ejemplo el <a href="http://www.dondominio.com/products/ssl/comodo-positive-ssl/">certificado SSL <em>positive</em> de Comodo en DonDominio.com</a> (que es el mismo que utilizo en <a href="http://pornohardware.com">pornoHARDWARE.com</a> y en muchas otras de mis webs).</p>
<p>Ahora que éste punto ha quedado claro, vamos a decirle a Telegram en qué URL está nuestro bot para que nos envíe los mensajes.</p>
<p>Para eso existe un método en la API de Telegram Bot llamado <code>setWebhook</code>, el cual tiene un único parámetro, que es precisamente la URL a la que debe llamar Telegram cuando un usuario envíe un mensaje a nuestro bot. Si nuestro bot estuviera alojado en la URL <code>https://nuestroserver.com/telegrambot.php</code> (por ejemplo), la URL de la API de Telegram a la que tendríamos que llamar podría ser algo parecido a:
https://api.telegram.org/bot13724466:AAETkFQjiQGlLeJMchaZr2Kfjih3V3h6uua/setWebhook?url=https://nuestroserver.com/telegrambot.php</p>
<p>Si accedemos a esa URL y Telegram registra nuestro comando correctamente, deberíamos obtener un JSON similar a éste:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">setWebhook_ok.json</span><a href='/files/telegrambot/telegrambot_setWebhook_ok.json'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">"ok"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="nt">"result"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="nt">"description"</span><span class="p">:</span> <span class="s2">"Webhook was set"</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>A partir de éste momento, Telegram enviará a la URL que le hayamos especificado cada uno de los mensajes que los usuarios envíen a nuestro bot. Y también a partir de éste momento <strong>ya no podremos usar el método <code>getUpdates</code></strong> (como ya os dije, o <code>getUpdates</code> o <code>Webhook</code>, no ambos).</p>
<p>Si intentamos llamar al método <code>getUpdates</code> habiendo activado el <code>Webhook</code> obtendremos un JSON de error como éste:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">setWebhook_ko.json</span><a href='/files/telegrambot/telegrambot_setWebhook_ko.json'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">"ok"</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
<span class="nt">"error_code"</span><span class="p">:</span> <span class="mi">409</span><span class="p">,</span>
<span class="nt">"description"</span><span class="p">:</span> <span class="s2">"Error: Conflict: another webhook is active"</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Si en algún momento quisiéramos cancelar el <code>Webhook</code> (porque queremos volver a utilizar <code>getUpdates</code> o por cualquier otro motivo) solo tenemos que volver a hacer la misma llamada a la API de Telegram que hicimos para registrarlo, pero ésta vez sin especificar ninguna URL.</p>
<p>En nuestro caso sería algo así como: <a href="https://api.telegram.org/bot13724466:AAETkFQjiQGlLeJMchaZr2Kfjih3V3h6uua/setWebhook">https://api.telegram.org/bot13724466:AAETkFQjiQGlLeJMchaZr2Kfjih3V3h6uua/setWebhook</a></p>
<p>Lo que nos devolvería un JSON parecido a éste:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">removeWebhook_ok.json</span><a href='/files/telegrambot/telegrambot_removeWebhook_ok.json'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">"ok"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="nt">"result"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="nt">"description"</span><span class="p">:</span> <span class="s2">"Webhook was deleted"</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Si en lugar de hacer las llamadas a éstas URL's directamente utilizamos desde código PHP la API de Telegram que os he recomendado, registrar el <code>Webhook</code> con código PHP sería algo así:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">telegrambot_register_webhook.php</span><a href='/files/telegrambot/telegrambot_register_webhook.php'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/BotApi.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Exception.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/InvalidArgumentException.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/BaseType.php'</span><span class="p">);</span>
<span class="c1">// Inicializar bot con el token</span>
<span class="nb">define</span><span class="p">(</span><span class="nx">TOKEN</span><span class="p">,</span> <span class="s1">'13724466:AAETkFQjiQGlLeJMchaZr2Kfjih3V3h6uua'</span><span class="p">);</span>
<span class="nv">$bot</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">\TelegramBot\Api\BotApi</span><span class="p">(</span><span class="nx">TOKEN</span><span class="p">);</span>
<span class="c1">// Activar Webhook</span>
<span class="nb">define</span><span class="p">(</span><span class="nx">URL_BOT</span><span class="p">,</span> <span class="s1">'https://nuestroserver.com/telegrambot.php'</span><span class="p">);</span>
<span class="nv">$result</span> <span class="o">=</span> <span class="nv">$bot</span><span class="o">-></span><span class="na">setWebhook</span><span class="p">(</span><span class="nx">URL_BOT</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">$result</span><span class="p">)</span>
<span class="k">echo</span> <span class="s1">'Webhook registrado correctamente'</span><span class="p">;</span>
<span class="k">else</span>
<span class="k">echo</span> <span class="s1">'Error al registrar el Webhook'</span><span class="p">;</span>
</code></pre></div>
</figure>
<p>No tiene misterio, verdad? Utilizar la API de Telegram es bastante sencillo e <em>intuitivo</em>, y aún más si lo hacemos a través de la librería de PHP.</p>
<p>No parece que sea muy buena idea dejar que <em>cualquiera</em> pueda acceder a nuestro bot directamente (es decir, que cualquiera pueda hacer una llamada HTTPS directamente hasta nuestro bot en lugar de ser Telegram quien la haga), por lo que una de las cosas que recomiendan hacer es utilizar como nombre de nuestro bot el propio token, ya que se supone que es algo que nadie excepto Telegram y nosotros mismos conoce. Me refiero a que en lugar de llamar al archivo PHP que contiene el código de nuestro bot <code>telegrambot.php</code> lo llamemos <code>AAETkFQjiQGlLeJMchaZr2Kfjih3V3h6uua.php</code>, por ejemplo.</p>
<p>Ahora que ya habéis visto cómo se usa, lo suyo es que veamos un ejemplo de código que reciba los mensajes de Telegram y haga una cosa u otra en función de qué mensaje (<em>comando</em>) sea el que nos envían.</p>
<h2>Programación del bot<a name="coding"></a></h2>
<p>Básicamente voy a hacer un programa en PHP utilizando la librería de acceso a la API de Telegram Bot que admita una serie de comandos y responda al usuario una cosa u otra según nos haya enviado un comando u otro.</p>
<p>Para no complicar el tema, los comandos harán cosas muy sencillas, como por ejemplo mostrar la fecha o la hora.</p>
<p>La forma de recibir los mensajes de Telegram será a través del método <code>Webhook</code>, de forma que no tendremos que preocuparnos por qué mensajes hemos procesado ya, sino que Telegram nos los irá entregando uno a uno en cada petición.</p>
<p>Doy por hecho que si estáis leyendo éste artículo sabéis programar en PHP, por lo que espero que el código sea lo suficientemente autoexplicativo para que incluso vosotros, simples humanos, lo entendáis.</p>
<p>El funcionamiento del programa será más o menos éste:</p>
<ul>
<li>Se lee la entrada de datos (que será el JSON que Telegram nos enviará con cada mensaje) usando el <a href="http://php.net/manual/es/wrappers.php.php">wrapper de entrada de PHP <em>php://input</em></a>.</li>
<li>Mediante una <a href="https://es.wikipedia.org/wiki/Expresi%C3%B3n_regular">expresión regular</a> se identifica qué comando (mensaje) nos ha escrito el usuario.</li>
<li>Preparamos una respuesta u otra mediante un <a href="https://es.wikipedia.org/wiki/Switch_case"><em>switch case</em></a>, dependiendo de la funcionalidad que queramos dar con nuestro bot.</li>
<li>Si el comando es <code>/fecha</code>, respondemos al usuario con la fecha actual.</li>
<li>Si el comando es <code>/hora</code>, respondemos al usuario con la hora actual.</li>
<li>Si todo ha ido bien, respondemos al usuario con el texto obtenido en el paso anterior.</li>
</ul>
<p>Aparte de <code>/fecha</code> y <code>/hora</code>, que son los 2 comandos cuya funcionalidad vamos a implementar, también permitiremos los comandos <code>/start</code> y <code>/help</code>, ya que Telegram por defecto ejecuta el comando <code>/start</code> la primera vez que empezamos a hablar con el bot (por lo que lo usaremos para dar la bienvenida al usuario), y también es recomendable tener un <code>/help</code> para que el usuario pueda consultar la lista de comandos que permitimos en el bot.</p>
<p>El código del bot podría ser algo así:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">telegrambot_example01.php</span><a href='/files/telegrambot/telegrambot_example01.php'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="nb">openlog</span><span class="p">(</span><span class="s1">'TelegramBot'</span><span class="p">,</span> <span class="nx">LOG_PID</span> <span class="o">|</span> <span class="nx">LOG_PERROR</span><span class="p">,</span> <span class="nx">LOG_LOCAL0</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/BotApi.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Exception.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/InvalidArgumentException.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/BaseType.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/TypeInterface.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Types/ArrayOfArrayOfPhotoSize.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Types/ArrayOfPhotoSize.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Types/Audio.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Types/Chat.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Types/Contact.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Types/Document.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Types/ForceReply.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Types/GroupChat.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Types/Location.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Types/Message.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Types/PhotoSize.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Types/ReplyKeyboardHide.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Types/ReplyKeyboardMarkup.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Types/Sticker.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Types/User.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Types/UserProfilePhotos.php'</span><span class="p">);</span>
<span class="k">include</span><span class="p">(</span><span class="s1">'TelegramBot/Api/Types/Video.php'</span><span class="p">);</span>
<span class="nb">syslog</span><span class="p">(</span><span class="nx">LOG_DEBUG</span><span class="p">,</span> <span class="s1">'['</span> <span class="o">.</span> <span class="nb">getmypid</span><span class="p">()</span> <span class="o">.</span> <span class="s1">'] - Peticion WebHook recibida desde '</span> <span class="o">.</span> <span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">'REMOTE_ADDR'</span><span class="p">]);</span>
<span class="c1">// Inicializar bot con el token</span>
<span class="nb">define</span><span class="p">(</span><span class="nx">TOKEN</span><span class="p">,</span> <span class="s1">'13724466:AAETkFQjiQGlLeJMchaZr2Kfjih3V3h6uua'</span><span class="p">);</span>
<span class="nv">$bot</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">\TelegramBot\Api\BotApi</span><span class="p">(</span><span class="nx">TOKEN</span><span class="p">);</span>
<span class="nv">$returnArray</span> <span class="o">=</span> <span class="k">true</span><span class="p">;</span>
<span class="nv">$rawData</span> <span class="o">=</span> <span class="nb">file_get_contents</span><span class="p">(</span><span class="s1">'php://input'</span><span class="p">);</span>
<span class="nv">$response</span> <span class="o">=</span> <span class="nb">json_decode</span><span class="p">(</span><span class="nv">$rawData</span><span class="p">,</span> <span class="nv">$returnArray</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="k">empty</span><span class="p">(</span><span class="nv">$rawData</span><span class="p">))</span> <span class="p">{</span>
<span class="nb">syslog</span><span class="p">(</span><span class="nx">LOG_ERR</span><span class="p">,</span> <span class="s1">'['</span> <span class="o">.</span> <span class="nb">getmypid</span><span class="p">()</span> <span class="o">.</span> <span class="s1">'] Peticion incorrecta: no hay datos'</span><span class="p">);</span>
<span class="k">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">try</span> <span class="p">{</span>
<span class="nv">$oMessage</span> <span class="o">=</span> <span class="nx">\TelegramBot\Api\Types\Message</span><span class="o">::</span><span class="na">fromResponse</span><span class="p">(</span><span class="nv">$response</span><span class="p">[</span><span class="s1">'message'</span><span class="p">]);</span>
<span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">\TelegramBot\Api\InvalidArgumentException</span> <span class="nv">$e</span><span class="p">)</span> <span class="p">{</span>
<span class="nb">syslog</span><span class="p">(</span><span class="nx">LOG_ERR</span><span class="p">,</span> <span class="s1">'['</span> <span class="o">.</span> <span class="nb">getmypid</span><span class="p">()</span> <span class="o">.</span> <span class="s1">'] Error obteniendo mensajes (argumento invalido): '</span> <span class="o">.</span> <span class="nv">$e</span><span class="o">-></span><span class="na">getMessage</span><span class="p">()</span> <span class="o">.</span> <span class="s1">' - Rawdata: '</span> <span class="o">.</span> <span class="nv">$rawData</span><span class="p">);</span>
<span class="p">}</span>
<span class="nv">$oUserFrom</span> <span class="o">=</span> <span class="nv">$oMessage</span><span class="o">-></span><span class="na">getFrom</span><span class="p">();</span>
<span class="nv">$oChat</span> <span class="o">=</span> <span class="nv">$oMessage</span><span class="o">-></span><span class="na">getChat</span><span class="p">();</span>
<span class="nv">$msg</span> <span class="o">=</span> <span class="s1">'Comando recibido ['</span> <span class="o">.</span> <span class="nv">$oMessage</span><span class="o">-></span><span class="na">getText</span><span class="p">()</span> <span class="o">.</span> <span class="s1">'] del usuario ['</span> <span class="o">.</span> <span class="nv">$oUserFrom</span><span class="o">-></span><span class="na">getFirstName</span><span class="p">()</span> <span class="o">.</span> <span class="s1">'] el ['</span> <span class="o">.</span> <span class="nb">date</span><span class="p">(</span><span class="s1">'Y/m/d H:i:s'</span><span class="p">,</span> <span class="nv">$oMessage</span><span class="o">-></span><span class="na">getDate</span><span class="p">())</span> <span class="o">.</span> <span class="s1">']'</span><span class="p">;</span>
<span class="nb">syslog</span><span class="p">(</span><span class="nx">LOG_DEBUG</span><span class="p">,</span> <span class="s1">'['</span> <span class="o">.</span> <span class="nb">getmypid</span><span class="p">()</span> <span class="o">.</span> <span class="s1">'] '</span> <span class="o">.</span> <span class="nv">$msg</span><span class="p">);</span>
<span class="c1">// Obtener comando (y sus posibles parametros)</span>
<span class="nv">$regExp</span> <span class="o">=</span> <span class="s1">'#^(\/[a-zA-Z0-9\/]+?)(\ .*?)$#i'</span><span class="p">;</span>
<span class="nv">$tmp</span> <span class="o">=</span> <span class="nb">preg_match</span><span class="p">(</span><span class="nv">$regExp</span><span class="p">,</span> <span class="nv">$oMessage</span><span class="o">-></span><span class="na">getText</span><span class="p">(),</span> <span class="nv">$aResults</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">isset</span><span class="p">(</span><span class="nv">$aResults</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span> <span class="p">{</span>
<span class="nv">$cmd</span> <span class="o">=</span> <span class="nb">trim</span><span class="p">(</span><span class="nv">$aResults</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
<span class="nv">$cmd_params</span> <span class="o">=</span> <span class="nb">trim</span><span class="p">(</span><span class="nv">$aResults</span><span class="p">[</span><span class="mi">2</span><span class="p">]);</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nv">$cmd</span> <span class="o">=</span> <span class="nb">trim</span><span class="p">(</span><span class="nv">$oMessage</span><span class="o">-></span><span class="na">getText</span><span class="p">());</span>
<span class="nv">$cmd_params</span> <span class="o">=</span> <span class="s1">''</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// Reply message data</span>
<span class="nv">$msg</span> <span class="o">=</span> <span class="k">array</span><span class="p">();</span>
<span class="nv">$msg</span><span class="p">[</span><span class="s1">'chat_id'</span><span class="p">]</span> <span class="o">=</span> <span class="nv">$oChat</span><span class="o">-></span><span class="na">getId</span><span class="p">();</span>
<span class="nv">$msg</span><span class="p">[</span><span class="s1">'text'</span><span class="p">]</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
<span class="nv">$msg</span><span class="p">[</span><span class="s1">'disable_web_page_preview'</span><span class="p">]</span> <span class="o">=</span> <span class="k">true</span><span class="p">;</span>
<span class="nv">$msg</span><span class="p">[</span><span class="s1">'reply_to_message_id'</span><span class="p">]</span> <span class="o">=</span> <span class="nv">$oMessage</span><span class="o">-></span><span class="na">getMessageId</span><span class="p">();</span>
<span class="nv">$msg</span><span class="p">[</span><span class="s1">'reply_markup'</span><span class="p">]</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
<span class="c1">// Comandos</span>
<span class="k">switch</span> <span class="p">(</span><span class="nv">$cmd</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="s1">'/start'</span><span class="o">:</span>
<span class="nv">$msg</span><span class="p">[</span><span class="s1">'text'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'Hola '</span> <span class="o">.</span> <span class="nv">$oUserFrom</span><span class="o">-></span><span class="na">getFirstName</span><span class="p">()</span> <span class="o">.</span> <span class="s1">'!'</span> <span class="o">.</span> <span class="nx">PHP_EOL</span><span class="p">;</span>
<span class="nv">$msg</span><span class="p">[</span><span class="s1">'text'</span><span class="p">]</span> <span class="o">.=</span> <span class="s1">'¿Qué puedo hacer por ti? Puedes ver una lista de las opciones disponibles con el comando /help'</span><span class="p">;</span>
<span class="nv">$msg</span><span class="p">[</span><span class="s1">'reply_to_message_id'</span><span class="p">]</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="s1">'/help'</span><span class="o">:</span>
<span class="nv">$msg</span><span class="p">[</span><span class="s1">'text'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'Los comandos disponibles son:'</span> <span class="o">.</span> <span class="nx">PHP_EOL</span><span class="p">;</span>
<span class="nv">$msg</span><span class="p">[</span><span class="s1">'text'</span><span class="p">]</span> <span class="o">.=</span> <span class="s1">'/start Inicializa el bot'</span><span class="p">;</span>
<span class="nv">$msg</span><span class="p">[</span><span class="s1">'text'</span><span class="p">]</span> <span class="o">.=</span> <span class="s1">'/fecha Muestra la fecha actual'</span><span class="p">;</span>
<span class="nv">$msg</span><span class="p">[</span><span class="s1">'text'</span><span class="p">]</span> <span class="o">.=</span> <span class="s1">'/hora Muestra la hora actual'</span><span class="p">;</span>
<span class="nv">$msg</span><span class="p">[</span><span class="s1">'text'</span><span class="p">]</span> <span class="o">.=</span> <span class="s1">'/help Muestra esta ayuda'</span><span class="p">;</span>
<span class="nv">$msg</span><span class="p">[</span><span class="s1">'reply_to_message_id'</span><span class="p">]</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="s1">'/fecha'</span><span class="o">:</span>
<span class="nv">$msg</span><span class="p">[</span><span class="s1">'text'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'La fecha actual es '</span> <span class="o">.</span> <span class="nb">date</span><span class="p">(</span><span class="s1">'d/m/Y'</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="s1">'/hora'</span><span class="o">:</span>
<span class="nv">$msg</span><span class="p">[</span><span class="s1">'text'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'La hora actual es '</span> <span class="o">.</span> <span class="nb">date</span><span class="p">(</span><span class="s1">'H:i:s'</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">default</span><span class="o">:</span>
<span class="nv">$msg</span><span class="p">[</span><span class="s1">'text'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'Lo siento '</span> <span class="o">.</span> <span class="nv">$oUserFrom</span><span class="o">-></span><span class="na">getFirstName</span><span class="p">()</span> <span class="o">.</span> <span class="s1">', pero ['</span> <span class="o">.</span> <span class="nv">$cmd</span> <span class="o">.</span> <span class="s1">'] no es un comando válido.'</span> <span class="o">.</span> <span class="nx">PHP_EOL</span><span class="p">;</span>
<span class="nv">$msg</span><span class="p">[</span><span class="s1">'text'</span><span class="p">]</span> <span class="o">.=</span> <span class="s1">'Prueba /help para ver la lista de comandos disponibles'</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">try</span> <span class="p">{</span>
<span class="nb">syslog</span><span class="p">(</span><span class="nx">LOG_DEBUG</span><span class="p">,</span> <span class="s1">'['</span> <span class="o">.</span> <span class="nb">getmypid</span><span class="p">()</span> <span class="o">.</span> <span class="s1">'] Enviando mensaje de respuesta ('</span> <span class="o">.</span> <span class="nb">strlen</span><span class="p">(</span><span class="nv">$msg</span><span class="p">[</span><span class="s1">'text'</span><span class="p">])</span> <span class="o">.</span> <span class="s1">' bytes) al usuario'</span><span class="p">);</span>
<span class="nv">$bot</span><span class="o">-></span><span class="na">sendMessage</span><span class="p">(</span><span class="nv">$msg</span><span class="p">[</span><span class="s1">'chat_id'</span><span class="p">],</span> <span class="nv">$msg</span><span class="p">[</span><span class="s1">'text'</span><span class="p">],</span> <span class="nv">$msg</span><span class="p">[</span><span class="s1">'disable_web_page_preview'</span><span class="p">],</span> <span class="nv">$msg</span><span class="p">[</span><span class="s1">'reply_to_message_id'</span><span class="p">],</span> <span class="nv">$msg</span><span class="p">[</span><span class="s1">'reply_markup'</span><span class="p">]);</span>
<span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">\TelegramBot\Api\Exception</span> <span class="nv">$e</span><span class="p">)</span> <span class="p">{</span>
<span class="nb">syslog</span><span class="p">(</span><span class="nx">LOG_ERR</span><span class="p">,</span> <span class="s1">'['</span> <span class="o">.</span> <span class="nb">getmypid</span><span class="p">()</span> <span class="o">.</span> <span class="s1">'] ERROR Exception al enviar el mensaje: '</span> <span class="o">.</span> <span class="nv">$e</span><span class="o">-></span><span class="na">getMessage</span><span class="p">());</span>
<span class="k">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
<span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">\TelegramBot\Api\InvalidArgumentException</span> <span class="nv">$e</span><span class="p">)</span> <span class="p">{</span>
<span class="nb">syslog</span><span class="p">(</span><span class="nx">LOG_ERR</span><span class="p">,</span> <span class="s1">'['</span> <span class="o">.</span> <span class="nb">getmypid</span><span class="p">()</span> <span class="o">.</span> <span class="s1">'] ERROR InvalidArgumentException al enviar el mensaje: '</span> <span class="o">.</span> <span class="nv">$e</span><span class="o">-></span><span class="na">getMessage</span><span class="p">());</span>
<span class="k">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
<span class="nb">syslog</span><span class="p">(</span><span class="nx">LOG_DEBUG</span><span class="p">,</span> <span class="s1">'['</span> <span class="o">.</span> <span class="nb">getmypid</span><span class="p">()</span> <span class="o">.</span> <span class="s1">'] > Ejecucion del bot terminada correctamente!'</span><span class="p">);</span>
<span class="k">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</code></pre></div>
</figure>
<p>Os recomiendo que leáis detenidamente la <a href="https://core.telegram.org/bots/api">documentación de la API de Telegram Bot</a> para conocer en profundidad los métodos disponibles, así como los parámetros que podéis usar con ellos, los tipos de mensajes que puede enviaros los usuarios (textos, imágenes, audio, localizaciones, etc) y todas las demás cosas que Telegram os ofrece para programar bots.</p>
<p>Una vez que pongáis éste código en vuestro servidor y hayáis registrado el <code>Webhook</code> correspondiente (como vimos en el paso anterior), ya podréis empezar a hablar con el bot desde vuestro teléfono, y veréis lo divertido que puede llegar a ser <em>hablar</em> con uno de vuestros propios programas (y créeme, si estas leyendo éste blog a éstas horas, probablemente esa sea la conversación más larga que vayas a mantener en tu vida sin que tu interlocutor acabe pensando que estas mal de la cabeza, pedazo de friki! xDDD).</p>
<p>Ah! Casi se me olvida: puedes utilizar tu propio sistema de estadísticas para hacer el seguimiento y monitorización del uso de tu bot, o puedes utilizar alguno de los sistemas que ya estan apareciendo específicamente diseñados para este tipo de bots, como por ejemplo <a href="http://botan.io/">Botan.io</a> (basado en el proveedor de estadísticas <a href="https://appmetrica.yandex.com/">Yandex.AppMetrika</a>).</p>
<p>Espero que os haya resultado útil el artículo, y que os sirva al menos como base para empezar a programar bots en Telegram, ya que cuando yo empecé a hacerlo apenas había ninguna referencia, ejemplo o documentación alternativa a la <em>oficial</em>, que aunque es cojonuda, a veces (sobre todo al principio, cuando aún no tienes claro el funcionamiento de los bots) puede resultar insuficiente.</p>
<p>Alaaaaaaaaaaaaaaaaaaaaaaa</p>
<h2>Referencias<a name="refs"></a></h2>
<ul>
<li><a href="https://core.telegram.org/bots">https://core.telegram.org/bots</a></li>
<li><a href="https://core.telegram.org/api">https://core.telegram.org/api</a></li>
<li><a href="https://github.com/TelegramBot/Api">https://github.com/TelegramBot/Api</a></li>
</ul>LCARS: el sistema operativo de la Flota Estelar2015-07-02T23:03:45+02:002015-07-02T23:03:45+02:00BhEaNtag:pornohardware.com,2015-07-02:/2015/07/02/lcars-el-sistema-operativo-de-la-flota-estelar/<p>Hace tiempo que quería escribir este artículo, sobre todo porque se dice que hay gente por ahí que no saben qué es LCARS (si, lo se... es alucinante.. yo tampoco me lo creía) y como a mi siempre me ha parecido un tema curioso, a partir de ahora cuando hable de este tema con alguien que no lo conozca me resultará mucho más fácil enviarle el enlace a éste artículo que tener que explicar una y otra vez de qué va ésto.</p>
<p>Antes de seguir, y sobre todo si eres una de esas <em>personas</em> (por llamarte de alguna forma) que no ha oido nunca hablar de LCARS, quiero dejar claro que éste artículo no trata de tecnología real, ni de un nuevo sistema operativo, ni de ninguna nueva plataforma de desarrollo asombrosa para que la implementes en tus proyectos.</p>
<p>LCARS <strong>NO EXISTE</strong>, es pura fantasía, y solo un pequeño e inocente niño pensaría que realmente existe más allá de la imaginación de algunos (al igual que los <a href="https://es.wikipedia.org/wiki/Reyes_Magos">Reyes Magos</a>, el <a href="https://es.wikipedia.org/wiki/Ratoncito_P%C3%A9rez">Ratoncito Pérez</a> o la <a href="http://www.eldiario.es/economia/Rajoy-millones-desempleados-afiliados-legislatura_0_458454228.html">política de empleo de Mariano Rajoy</a>.</p>
<p>Hace tiempo que quería escribir este artículo, sobre todo porque se dice que hay gente por ahí que no saben qué es LCARS (si, lo se... es alucinante.. yo tampoco me lo creía) y como a mi siempre me ha parecido un tema curioso, a partir de ahora cuando hable de este tema con alguien que no lo conozca me resultará mucho más fácil enviarle el enlace a éste artículo que tener que explicar una y otra vez de qué va ésto.</p>
<p>Antes de seguir, y sobre todo si eres una de esas <em>personas</em> (por llamarte de alguna forma) que no ha oido nunca hablar de LCARS, quiero dejar claro que éste artículo no trata de tecnología real, ni de un nuevo sistema operativo, ni de ninguna nueva plataforma de desarrollo asombrosa para que la implementes en tus proyectos.</p>
<p>LCARS <strong>NO EXISTE</strong>, es pura fantasía, y solo un pequeño e inocente niño pensaría que realmente existe más allá de la imaginación de algunos (al igual que los <a href="https://es.wikipedia.org/wiki/Reyes_Magos">Reyes Magos</a>, el <a href="https://es.wikipedia.org/wiki/Ratoncito_P%C3%A9rez">Ratoncito Pérez</a> o la <a href="http://www.eldiario.es/economia/Rajoy-millones-desempleados-afiliados-legislatura_0_458454228.html">política de empleo de Mariano Rajoy</a>.</p>
<p><img class="left" src="/images/posts/lcars-el-sistema-operativo-de-la-flota-estelar/lcars_interface_01.png">
Por lo tanto este artículo trata sobre la cienca ficción, y más concretamente sobre un pequeñísimo detalle minúsculo en el inmenso Universo de <a href="http://www.startrek.com">Star Trek</a>: el <a href="https://es.wikipedia.org/wiki/Sistema_operativo">sistema operativo</a> (o al menos el <a href="https://es.wikipedia.org/wiki/Interfaz_gr%C3%A1fica_de_usuario">interface gráfico de usuario</a>) que se utiliza en las naves y ordenadores de dicha serie, y que sin ser parte protagonista de ninguna de las tramas, está tan definido que cuesta pensar que no es <em>real</em>, y por lo tanto enriquece y aporta un enorme valor a la historia, tal y como la <a href="https://es.wikipedia.org/wiki/Tengwar">escritura Élfica</a> (por poner otro ejemplo similar) lo hace en el Universo de <a href="https://es.wikipedia.org/wiki/El_Se%C3%B1or_de_los_Anillos">El Señor de los Anillos</a>.</p>
<p>Pero aunque sea algo irreal en una historia de ficción, me ha parecido siempre un diseño tan acertado que he creido que quizás os resultaría interesante a vosotros tambien. Si hablar <em>seriamente</em> de algo que no es real os resulta extraño, podeis imaginar que estamos hablando de un nuevo <a href="https://es.wikipedia.org/wiki/Gestor_de_ventanas">gestor de ventanas</a> para vuestro <em>GNU/Linux</em>, o de un <a href="https://es.wikipedia.org/wiki/Skin_%28software%29">skin</a> para vuestro <a href="https://es.wikipedia.org/wiki/Navegador_web">navegador</a> habitual.</p>
<h2>Qué es LCARS?</h2>
<p>Su nombre corresponde a las siglas de <strong>Library Computer Access and Retrieval System</strong>, y se podría definir como el sistema operativo (o al menos el entorno gráfico de éste) que utilizan las naves y ordenadores de Star Trek.</p>
<p>LCARS es un sistema ficticio creado para dar más realismo a la serie en aquellos planos en los que aparecían pantallas de ordenadores o en los que se se interactuaba con algún sistema a través de una pantalla (normalmente táctil), y fué utilizado por primera vez en la serie <a href="https://es.wikipedia.org/wiki/Star_Trek:_La_nueva_generaci%C3%B3n">Star Trek: La Nueva Generación</a>.</p>
<p><img class="right" src="/images/posts/lcars-el-sistema-operativo-de-la-flota-estelar/lcars_okuda.jpg">
Fué diseñado por <a href="https://es.wikipedia.org/wiki/Michael_Okuda">Michael Okuda</a>, quien no solo participó en la serie Star Trek con el diseño de éste sistema, sino que también asesoró a los guionistas sobre otras tecnologías utilizadas en la serie, como el <a href="https://es.wikipedia.org/wiki/Teletransportador_%28Star_Trek%29">transportador</a> y el <a href="https://es.wikipedia.org/wiki/Curvatura_%28Desplazamiento%29">motor Warp</a>. Algunas veces los diseños del sistema LCARS son llamados también <em>Okudagramas</em>, en honor a su autor.</p>
<p>Aparte de éstos trabajos para Star Trek, Okuda también trabajó para la <a href="http://www.nasa.gov/">NASA</a>, diseñando los logotipos de muchas de sus misiones, como por ejemplo la misión <a href="http://www.nasa.gov/mission_pages/shuttle/shuttlemissions/sts125/main/index.html">STS-125</a> al telescopio <a href="http://www.nasa.gov/mission_pages/hubble/main/index.html">Hubble</a>, el vuelo de prueba del <a href="http://edition.cnn.com/2009/TECH/space/10/27/ares.nasa.rocket/index.html?eref=igoogle_cnn">Ares I-X</a>, la nave espacial <a href="http://www.nasa.gov/exploration/systems/orion/index.html">Orion</a>, el vehículo lunar <a href="https://es.wikipedia.org/wiki/LSAM">LSAM</a> del proyecto <a href="http://www.nasa.gov/centers/ames/research/exploringtheuniverse/constellation.html">Constelación</a>, el transbordador espacial <a href="http://www.nasa.gov/topics/shuttle_station/features/135numbers.html">Atlantis</a> y algunos más, por lo que en 2009 recibió la medalla por servicio público excepcional de la NASA en el <a href="http://www.nasa.gov/centers/johnson/home/index.html">Centro Espacial Johnson</a>, en Houston (Texas, EEUU).</p>
<h2>Características</h2>
<p>LCARS está diseñado para controlar las funciones típicas de un sistema informático mediante el uso de paneles táctiles. Con el se realiza desde la configuración y gestión de los diferentes sistemas de las naves, hasta la representación de los datos que previamente hayamos solicitado al ordenador.</p>
<p>Se supone que el sistema LCARS incluye también una característica típica de la serie Star Trek, y es la del control absoluto de la mayoría de las funciones del ordenador a través de la voz, utilizando un lenguaje natural que el sistema es capaz de reconocer e interpretar a la perfección (ya le gustaría a <a href="https://www.apple.com/es/siri/">Siri</a>, a <a href="http://www.windowsphone.com/es-es/how-to/wp8/cortana/meet-cortana">Cortana</a> o a <em>como-se-llame</em> el equivalente en <em>Android</em>) pero no entraremos en éste punto en éste artículo, el reconocimiento de voz lo dejaremos para otra ocasión.</p>
<p><img class="center" src="/images/posts/lcars-el-sistema-operativo-de-la-flota-estelar/lcars_interface_02.png">
Ejemplo de una aplicación basada en el diseño del interface de LCARS</p>
<p>LCARS se basa en la representación gráfica de las diferentes pantallas mediante un diseño limpio, formado por <em>barras</em> rectangulares (pero con bordes redondeados para dar aspecto de suavidad, aunque sea un diseño completamente <em>rectangular</em>) y utilizando colores con fuerte contraste, alternando entre amarillo/blanco (como los usados en la nave <a href="http://en.memory-alpha.wikia.com/wiki/USS_Enterprise_%28NCC-1701-D%29">USS Enterprise-D</a>) o azul/blanco (como en el <a href="http://en.memory-alpha.wikia.com/wiki/USS_Enterprise_%28NCC-1701-E%29">USS Entreprise-E</a>).</p>
<p><img class="center" src="/images/posts/lcars-el-sistema-operativo-de-la-flota-estelar/lcars_interface_03.jpg">
Otro ejemplo del interface de LCARS</p>
<p>He encontrado un video en <a href="http://www.vimeo.com">Vimeo</a> con algunos ejemplos del sistema LCARS que han aparecido en algunos capítulos de la serie, y donde se puede ver (y escuchar, ya que tiene un sonido también muy característico) cómo funciona éste sistema:</p>
<p><span class="videobox">
<iframe
src="//player.vimeo.com/video/11540428?title=0&byline=0&portrait=0"
width="640" height="390" frameborder="0"
webkitAllowFullScreen mozallowfullscreen allowFullScreen>
</iframe>
</span></p>
<p>Existen multitud de apps para movil y tablet que imitan éste sistema, así como <em>skins</em> inspirados en LCARS para multitud de aplicaciones... y si algún dia lo termino, el sistema de alarma de mi casa también será controlado desde un panel con éste diseño.</p>
<p>Espero que con éste pequeño <em>resumen</em> quede un poco más claro éste sistema, creo que no hay mucho más que añadir, pero si encuentro algo más podeis estar seguros de que lo haré...</p>
<p>Larga vida y prosperidad,</p>
<h2>Referencias</h2>
<ul>
<li><a href="https://en.wikipedia.org/wiki/LCARS">https://en.wikipedia.org/wiki/LCARS</a></li>
<li><a href="http://www.startrek.com/database_article/michael-okuda">http://www.startrek.com/database_article/michael-okuda</a></li>
<li><a href="http://en.memory-alpha.wikia.com/wiki/LCARS">http://en.memory-alpha.wikia.com/wiki/LCARS</a></li>
</ul>Teclados mecánicos: ¿a qué esperas para comprarte uno?2015-03-15T00:58:48+01:002015-03-15T00:58:48+01:00BhEaNtag:pornohardware.com,2015-03-15:/2015/03/15/teclados-mecanicos-a-que-esperas-para-comprarte-uno/<p><img class="left" height="292" src="/images/posts/mech-keyboard/keyboard.jpg" width="334"/>
La inmensa mayoría de las personas que utilizan un ordenador a diario utilizan teclados de membrana, y la inmensa mayoría de ellos ni siquiera saben de la existencia de otros tipos de teclados.</p>
<p>En éste artículo explicaré las características más representativas de los teclados mecánicos, los diferentes tipos de mecanismos de teclas que existen para éstos teclados y en definitiva, todas las <em>sensaciones</em> que aporta el uso de uno de éstos teclados.</p>
<p>Y es que al contrario de lo que piensa la mayoría, estos teclados no solo para <a href="http://es.wikipedia.org/wiki/Jugador_de_videojuegos">gamers</a>, sino para cualquier persona o político que utilice un ordenador habitualmente..</p>
<p>Solo existen 2 tipos de personas en el mundo: los que adoran los teclados mecánicos, y los que aún no los han probado.</p>
<p><img class="left" src="/images/posts/mech-keyboard/keyboard.jpg" width="334" height="292">
La inmensa mayoría de las personas que utilizan un ordenador a diario utilizan teclados de membrana, y la inmensa mayoría de ellos ni siquiera saben de la existencia de otros tipos de teclados.</p>
<p>En éste artículo explicaré las características más representativas de los teclados mecánicos, los diferentes tipos de mecanismos de teclas que existen para éstos teclados y en definitiva, todas las <em>sensaciones</em> que aporta el uso de uno de éstos teclados.</p>
<p>Y es que al contrario de lo que piensa la mayoría, estos teclados no solo para <a href="http://es.wikipedia.org/wiki/Jugador_de_videojuegos">gamers</a>, sino para cualquier persona o político que utilice un ordenador habitualmente..</p>
<p>Solo existen 2 tipos de personas en el mundo: los que adoran los teclados mecánicos, y los que aún no los han probado.</p>
<h2>Tipos de teclados</h2>
<p>Quizás eras de los que no sabían que existe vida más allá de los teclados convencionales (membrana) hasta ahora, por lo que antes de hablar en profundidad de los teclados mecánicos, vamos a ver los diferentes tipos de teclados que existen.</p>
<ol>
<li><a href="#membrana">Teclados de membrana</a></li>
<li><a href="#proyectados">Teclados proyectados</a></li>
<li><a href="#mecanicos">Teclados mecánicos</a></li>
</ol>
<h3>Teclados de membrana<a name="membrana"></a></h3>
<p>En la actualidad (según vuestro punto de vista del tiempo: 2015) casi todos los teclados que se utilizan son de éste tipo.</p>
<p>Este tipo de teclados están formado por 2 láminas plásticas (que contienen las pistas conductoras del circuito) entre las cuales hay otra membrana agujereada donde se situan las teclas.</p>
<p><img class="center" src="/images/posts/mech-keyboard/keyboard_silicon.jpg">
Teclado de membrana</p>
<p>Es también el mismo sistema que se utiliza habitualmente en el mando a distancia de la tele, los teclados de los móviles antiguos, y prácticamente cualquier aparato que tenga un <em>panel</em> de teclas.</p>
<p><img class="right" src="/images/posts/mech-keyboard/switch_rubber-dome.gif">
Encima de cada uno de estos agujeros de la membrana (que corresponden a cada una de las teclas) se coloca una <em>cúpula de goma</em> (denominada <em>rubber dome</em>).</p>
<p>Al pulsar dicha cúpula, las 2 partes de las láminas plásticas se juntan y se transmite la pulsación del teclado hasta el ordenador.</p>
<p>Este sistema es mucho más barato que tener un interruptor por cada tecla (como en el caso de los teclados mecánicos), por lo que es el sistema que más se ha extendido, llegando en la actualidad a estar presente en el 90% de los teclados que se fabrican.</p>
<p><img class="right" src="/images/posts/mech-keyboard/switch_scissor.gif">
En los teclados de los portátiles se utiliza también este sistema de membrana, aunque en estos casos lo que se busca es que el recorrido de las teclas (y las propias teclas) sea mucho más pequeño, por lo que el sistema es muy parecido, pero con un perfil mucho más bajo formado por 2 piezas cruzadas en forma de tijera (por eso éste sistema se denomina <em>scissor</em>).</p>
<p>Este sistema <em>scissor</em> es el que se utiliza en prácticamente la totalidad de ordenadores portátiles, salvo en unos pocos modelos que se fabrican con teclados mecánicos, pero son muuuuuy pocos.</p>
<p>Desde éste año existe además una variante de éste sistema <em>scissor</em> llamada <em>butterfly</em> y desarrollada por <a href="http://www.apple.com">Apple</a> para sus portátiles <a href="http://www.apple.com/macbook/">Macbook</a>, pero simplemente es una variación del sistema para hacer aún más pequeño el recorrido de las teclas y poder así tener teclados más planos y finos para ordenadores portátiles.</p>
<h3>Teclados proyectados<a name="proyectados"></a></h3>
<p>Parece algo nuevo, pero llevan mucho tiempo entre nosotros (la primera vez que probé uno fué en 2005 o 2006)... y aunque parece algo genial a simple vista, por ahora no han llegado a conquistar el mercado debido a sus limitaciones.</p>
<p>Consiste en un aparato que proyecta mediante laser, infrarrojos, etc. la imagen de un teclado sobre cualquier superficie... y que es capaz de detectar qué <em>teclas</em> estamos tocando, por lo que permite convertir cualquier superficie (preferiblemente plana) en un teclado.</p>
<p><img class="center" src="/images/posts/mech-keyboard/keyboard_infrared.jpg">
Teclado proyectado</p>
<p>Suelen sincronizarse mediante <a href="http://es.wikipedia.org/wiki/Bluetooth">bluetooth</a> o <a href="http://es.wikipedia.org/wiki/Universal_Serial_Bus">USB</a>, de forma que no solo se usan en ordenadores, sino que también pueden conectarse con teléfonos móviles, PDAs y cualquier otro dispositivo que permita éste tipo de conexiones.</p>
<p>Pero como ya digo, de momento continuan sin hacerse un hueco en el mercado debido a que aún tienen algunos problemas que dificultan su uso, como por ejemplo que dependiendo de la luz ambiente que haya en el sitio donde lo estemos usando, el teclado puede funcionar mejor o peor. O que como la reflexión afecta a su uso, es complicado encontrar una superfice perfecta para utilizarlo, ya que la mayoría de las superficies tienen algun nivel de reflexión (y llevar encima una superficie especialmente diseñada para su uso hace que éste dispositivo <em>pierda su gracia</em>, porque para eso nos llevamos un teclado normal, y listo).</p>
<p>Su precio es bastante más alto que el del resto de teclados que existen, aunque sin llegar a ser prohibitivo, ya que se pueden encontrar por unos 200 € aprox. sin tener que buscar demasiado.</p>
<h3>Teclados mecánicos<a name="mecanicos"></a></h3>
<p>Después de hablar un poco sobre los teclados de membrana y los proyectados, por fin llegamos al <em>kit de la cuestión</em>: los teclados mecánicos.</p>
<p><img class="center" src="/images/posts/mech-keyboard/keyboard_mech.jpg">
El teclado mecánico desde el que estoy escribiendo ahora mismo</p>
<p>Resistencia al pulsar cada tecla, profundidad de la pulsación, sonido <em>click</em> al pulsarlas y personalización absoluta de las teclas son solo algunas de las cosas que puedes hacer con éstos teclados.</p>
<p>Antes de nada, si no habeis probado éste tipo de teclados no podreis saber realmente de lo que os estoy hablando... ya que aunque intentaré describir sus características y opciones lo mejor posible, son las sensaciones que experimentareis al utilizarlo lo que os hará decantaros por uno u otro, y eso difícilmente se puede explicar en un artículo (aunque sea en uno tan bueno como éste).</p>
<p>Hay mucha gente que piensa que los teclados mecánicos no son más que aquellos ruidosos teclados que se usaban en los 90. Y en parte tienen razón, ya que éste tipo de teclados es el que se utilizaba antes. Pero ha llovido mucho desde entonces, y aunque el coste infinitamente inferior de los teclados de membrana haya hecho que apenas se usen teclados de otros tipos, poco a poco parece que éstos teclados mecánicos estan empezando a proliferar entre el público en general, ya que hasta ahora únicamente eran populares entre <em>gamers</em> por su respuesta táctil perfecta para juegos.</p>
<p><img class="right" src="/images/posts/mech-keyboard/switch_cherry.png">
En los teclados mecánicos, cada tecla tiene su propio <em>interruptor</em>, que es el que se encarga de enviar la señal de cada tecla pulsada al ordenador. Y aquí es precisamente donde radica una de las mejores características de éste tipo de teclados: existen muchos y muy diferentes tipos de interruptores, por lo que podemos escoger entre un tipo u otro en función de nuestros gustos personales. Además, cada uno de estos interruptores estan sellados y protegidos en el interior de su carcasa, de la que únicamente sobresale un pequeño cilindro plástico donde se colocar la tecla para accionarlo. Esto hace que un teclado mecánico sea casi indestructible, y que sus interruptores duren muchísimos años soportando decenas de millones de pulsaciones sin variar su comportamiento durante todo ese tiempo, a diferencia de los teclados de membrana, en los que con el paso del tiempo se puede apreciar que el tacto de las teclas va cambiando. Podeis probarlo en vuestros teclados de membrana comparando el tacto de aquellas teclas que useis con menos frecuencia (por ejemplo, F7) con aquellas que useis habitualmente (por ejemplo, la letra A o el espacio).</p>
<p>El principal fabricante de interruptores para teclados mecánicos es <a href="http://cherryamericas.com/product-category/keyswitch/">Cherry</a></p>
<p><img class="left" src="/images/logos/logo_cherry.png">
Prácticamente todos los teclados mecánicos llevan interruptores Cherry, por lo que únicamente voy a explicar las características de estos, aunque hay algunos otros fabricantes de teclados que o bien fabrican los suyos propios (como empezó a hacer <a href="https://www.razerzone.com">Razer</a> el año pasado) o bien utilizan interruptores de otros fabricantes.</p>
<p>Cherry dispone en la actualidad de 2 clases (series) de interruptores:</p>
<ul>
<li>Serie ML</li>
<li>Serie MX</li>
</ul>
<p>La linea ML es mucho más pequeña (6,9 mm de altura) y está diseñada para aquellos poquísimos portátiles que utilizan teclados mecánicos. En cambio, la linea MX tiene 15,2 mm de altura, por lo que se utiliza en los teclados <em>normales</em> de sobremesa.</p>
<p>¿Y qué tienen de especial estos interruptores? Pues que algunos ofrecen más o menos resistencia que otros, algunos apenas hay que pulsarlos para que marquen la tecla mientras que en otros hay que pulsar hasta el final, algunos de ellos tienen un sonido <em>click</em> característico al pulsarlos y otros no, etc.</p>
<p>Los tipos de interruptores Cherry que existen actualmente son:</p>
<ul>
<li>MX Black</li>
<li>MX Red</li>
<li>MX Brown</li>
<li>MX Clear</li>
<li>MX Blue</li>
</ul>
<p>Vamos viendo cada uno de ellos un poco más en detalle:</p>
<p><img class="left" src="/images/posts/mech-keyboard/Cherry-MX-Black.gif"></p>
<h3>MX Black</h3>
<p>Estos interruptores son los que más fuerza necesitan para activarse (unos 60 gr) y tambien los que menos ruido hacen.</p>
<p>El hecho de necesitar más fuerza para presionar cada tecla que en otros teclados hace que el <em>doble tecleo</em> involuntario se reduzca, pero hará que los dedos se cansen más después de escribir durante mucho tiempo.</p>
<p>Tienen un recorrido de 4 mm y 2 mm de activación... es decir, podemos pulsar la tecla desplazándola hacia abajo un total de 4 mm, pero a partir de 2 mm ya enviará la señal de la tecla pulsada al ordenador.</p>
<p><img class="left" src="/images/posts/mech-keyboard/Cherry-MX-Red.gif"></p>
<h3>MX Red</h3>
<p>En estos interruptores solo necesitamos 45 gramos de presión para pulsar cada tecla. Su recorrido es totalmente linear, sin respuesta táctil: esto significa que desde que empezamos a pulsar hasta que la tecla está completamente pulsada no hay ninguna variación en el tacto ni tampoco el sonido <em>click</em> que hacen algunos otros interruptores cuando se marca la pulsación. Por tanto, al igual que los MX Black, son los que menos ruido hacen (aunque obviamente cualquier teclado mecánico hace mucho más ruido que uno de membrana, eso debeis tenerlo claro y tenerlo presente a la hora de elegir un teclado si para vosotros el ruido de las teclas es importante).</p>
<p>Al no necesitar excesiva fuerz para pulsarlos resultan muy recomendables para la escritura en general, ya que evitará que se nos cansen los dedos como con los <em>MX Black</em>. Personalmente son los que más me gustan (y ya deberíais saber que mi opinión es la única que importa).</p>
<p>Su recorrido también es de 4 mm en total, y 2 mm de activación.</p>
<p><img class="left" src="/images/posts/mech-keyboard/Cherry-MX-Brown.gif"></p>
<h3>MX Brown</h3>
<p>Son iguales que los MX Red en cuanto a recorrido y resistencia a la pulsación pero a diferencia de éstos, los MX Brown si tienen respuesta táctil: hacen un <em>click</em> al activarse la pulsación (a los 2 mm de pulsarlos), por lo que hacen más ruido que los MX Black o MX Red, y su recorrido no es lineal.</p>
<p>También tienen 4 mm de recorrido total, y 2 mm de activación.</p>
<p>
</p>
<p><img class="left" src="/images/posts/mech-keyboard/Cherry-MX-Clear.gif"></p>
<h3>MX Clear</h3>
<p>En este caso, los interruptores MX Clear (tambien llamados MX White, transparent, etc) son iguales a los anteriores MX Brown, pero es necesaria una presión de 55 gramos para activarlos.</p>
<p>Tampoco tienen por lo tanto un recorrido lineal, y también emiten el <em>click</em> al pulsarlos, por lo que quizás no sea el interruptor adecuado para los teclados de una sala de redactores de una revista escribiendo sin parar (a no ser que quieras que les duela la cabeza).</p>
<p>
</p>
<p><img class="left" src="/images/posts/mech-keyboard/Cherry-MX-Blue.gif"></p>
<h3>MX Blue</h3>
<p>Los MX Blue tienen una particularidad que no tienen ninguno de los demás, y es que estan formados por 2 piezas en lugar de solo por 1, de forma que los primeros 2 mm de recorrido son muy suaves y apenas se necesita presión para pulsarlos, pero los 2 mm siguientes (hasta completar los 4 mm de recorrido total) necesitan de hasta 50 gramos para llegar hasta el final, con lo cual se nota mucho el punto de activación.</p>
<p>Son los que mayor respuesta táctil tienen, también desde el punto de vista auditivo, ya que emiten el <em>click</em> más fuerte que los anteriores... sin embargo, es la mejor opción para escribir grandes textos y durante periodos muy largos sin que nuestros dedos se cansen.</p>
<p> </p>
<p><img class="center" src="/images/posts/mech-keyboard/switch_table.png"></p>
<p>Si queréis conocer detalles más avanzados de éstos interruptores Cherry podéis encontrar toda la información sobre sus esquemas, medidas, tipos, etc. en éste <a href="/files/2015-03-15-teclados-mecanicos-a-que-esperas-para-comprarte-uno/cherry_switch_mx_specs.pdf">archivo PDF</a>.</p>
<p>Y aquí teneis un video oficial de Cherry sobre los interruptores MX (solo está en ingles, sorry):</p>
<p><span class="videobox">
<iframe
src="//player.vimeo.com/video/122343687?title=0&byline=0&portrait=0"
width="640" height="390" frameborder="0"
webkitAllowFullScreen mozallowfullscreen allowFullScreen>
</iframe>
</span></p>
<h2>Ventajas e inconvenientes</h2>
<p>Ahora que ya conocéis un poco más a fondo los diferentes tipos de teclados, vamos a ver el porqué de la buena fama de los teclados mecánicos.</p>
<p>Vamos a empezar por lo obvio después de haber visto los tipos de interruptores que existen: la posibilidad de elección de un interruptor u otro en función de nuestras preferencias.</p>
<p>Si nos gusta que suene un <em>click</em> al pulsar una tecla o lo queremos más silencioso, o si queremos que sea necesaria más o menos fuerza para pulsarlas son sólo algunas de las cosas que podemos escoger en un teclado mecánico, pero NO en ninguno de los otros tipos de teclados.</p>
<p>La durabilidad es un factor determinante también: un teclado de membrana se supone que aguanta unos 7 millones de pulsaciones de cada tecla, que puede no estar mal en determinados casos... pero no tiene nada que hacer frente a las más de 50 millones de pulsaciones por tecla que permiten los teclados mecánicos. Y al margen de las pulsaciones, los propios materiales que componen éstos teclados son mucho mejores y más resistentes que los de membrana, aunque ésto hace que los de membrana sean por lo tanto mucho más baratos que los mecánicos: no es raro encontrar teclados de membrana por 10 €, sin embargo un teclado mecánico <em>normalito</em> no suele costar menos de 75 € (como poco).</p>
<p>Siguiendo con el tema de la durabilidad, no solo me refiero a la durabilidad del teclado en general, sino a la de cada tecla individualmente, ya que los interruptores siempre se comportarán de la misma forma desde el primer dia hasta el último, en cambio en los teclados de membrana el tacto de la pulsación de las teclas va cambiando a medida que va pasando el tiempo (por el propio desgaste del material), llegando al punto en el que se notan diferencias entre aquellas teclas que usamos más habitualmente con respecto a las que menos usamos.</p>
<p>La sensación al teclear, aunque cueste creerlo, para mi es completamente <strong>placentera</strong>. Hace ya varios meses que tengo éste teclado (al cual doy un uso intensivo literalmente todos los dias), y aun me llama la atención lo agradable que resulta utilizarlo. Al igual que Matrix, la sensación al teclear con uno de éstos teclados no se puede expresar con palabras: has de verlo por ti mismo.</p>
<p>Leí un comentario muy gracioso en una de las webs que usé para documentarme sobre éste tema, y es que comparaban la sensación de teclear en un teclado de membrana con la de <em>teclear sobre una fila de chicles masticados</em>, y aunque te parezca una exageración, el dia que pruebes un teclado mecánico y luego uses de nuevo uno de membrana te acordarás de éstas palabras...</p>
<p>Si te desagrada el sonido de éstos teclados (gente rara hay en todas partes) existe una solución, y es que aparte de los propios interruptores mecánicos de diferentes tipos (unos más silenciosos que otros) existen unos pequeños <em>aros</em> de goma (llamados <em>rubber o-rings</em>) que se colocan en el interior de cada tecla para amortiguar las pulsaciones y reducir el sonido y el tacto según queramos.</p>
<p><img class="right" src="/images/posts/mech-keyboard/orings.jpg">
Existen diferentes tipos de <em>o-rings</em>, según queramos amortiguar más o menos cada pulsación. Personalmente no me gustan nada, y cuando compré el teclado mecánico que uso ahora (un flamante <a href="http://www.corsair.com/es-es/vengeance-k70-rgb-fully-mechanical-gaming-keyboard-anodized-black-cherry-mx-red">Corsair K70 RGB</a> con interruptores Cherry MX Red) compré también éstos anillos por si acaso el sonido de las teclas me resultaba molesto (puesto que llevaba muchos años acostumbrado a los teclados de membrana) y fué llegar el teclado, probarlo durante unas horas y escuchar el increible sonido de sus teclas, y tirar la bolsita de <em>o-rings</em> a la basura).</p>
<p>Y aunque no es una característica exclusiva de los teclados mecánicos, hay una característica en ellos llamada <strong>NKRO</strong> (abreviatura de <a href="http://en.wikipedia.org/wiki/Rollover_%28key%29">N-Key Rollover</a>), que consiste en la capacidad de éstos teclados de pulsar varias teclas al mismo tiempo sin que el teclado pierda ninguna de ellas, registrando todas las pulsaciones al mismo tiempo.</p>
<p>Esto es muy útil en juego, por ejemplo, pero también puede resultar de utilidad en otras actividades.</p>
<p>Hay teclados de membrana que también permiten pulsaciones múltiples, pero pocas y siempre teclas determinadas (en esos teclados lo llaman <em>gaming matrix</em> o tambien <em>anti-ghosting</em>).</p>
<p>En cuanto a la personalización del teclado, las teclas de los teclados mecánicos suelen ser <a href="http://es.wikipedia.org/wiki/Est%C3%A1ndar">estándars</a>, por lo que se pueden comprar teclas sueltas personalizadas, con diferentes texturas, colores, sin el maldito logo de <em>güindous</em>, etc, etc. (por ejemplo, las geniales teclas de la gente de <a href="http://www.wasdkeyboards.com/index.php/products/keycap-mod-packs.html">WASD</a>).</p>
<p>Resumiendo: no hay color entre uno y otro... y si no estas completamente convencido es porque no has probado uno aún, así que mi consejo es que probeis uno, y después de unos dias estoy seguro de que no querréis volver a uno de membrana nunca más.</p>
<p>En mi caso es una de las mejores comprar que he hecho nunca (o al menos, una de las que más satisfacción me produce), y en cuanto le eche valor y me ponga a probar la distribución de teclas <a href="http://es.wikipedia.org/wiki/Teclado_Dvorak">DVORAK</a> (que tengo muchas ganas de hacerlo) seguro que no solo aumentaré muchísimo la velocidad de escritura, sino que además no terminaré con sensación de <em>cansancio</em> en los dedos después de toda una noche teclando...</p>
<p><img class="center" src="/images/posts/mech-keyboard/corsair-k70-rgb.jpg"></p>
<p>Alaaaaaaaaaaaaaaaaaaaaa</p>
<h2>Referencias<a name="refs"></a></h2>
<ul>
<li><a href="http://www.wasdkeyboards.com">http://www.wasdkeyboards.com</a></li>
<li><a href="http://www.disfrutadelcastigo.com/2013/10/todo-lo-que-nunca-quisiste-saber-sobre.html">http://www.disfrutadelcastigo.com/2013/10/todo-lo-que-nunca-quisiste-saber-sobre.html</a></li>
<li><a href="http://misteclados.weebly.com/blog/teclados-proyectados-con-laser-virtuales">http://misteclados.weebly.com/blog/teclados-proyectados-con-laser-virtuales</a></li>
<li><a href="http://blog.pmkirsten.es/2013/07/teclados-mecanicos-y-de-mebrana.html">http://blog.pmkirsten.es/2013/07/teclados-mecanicos-y-de-mebrana.html</a></li>
</ul>Instalación y configuración de un servidor de correo completo en Linux2015-01-01T11:03:39+02:002015-01-01T11:03:39+02:00BhEaNtag:pornohardware.com,2015-01-01:/2015/01/01/instalacion-y-configuracion-de-un-servidor-de-correo-completo-en-linux/<p><img class="right" src="/images/logos/logo_email.png"/>
Uno de los servicios más importantes de Internet es sin duda el correo electrónico, y al igual que con muchos otros servicios, no hay nada que gestione mejor el correo que GNU/Linux.</p>
<p>Hay muchos proyectos conocidísimos y de gran importancia en el mundo de GNU/Linux, como por ejemplo el servidor web <a href="https://projects.apache.org/project.html?httpd-http_server">Apache</a>, las bases de datos <a href="http://dev.mysql.com/">MySQL</a> y <a href="http://www.postgresql.org/">PostgreSQL</a>, el servidor de nombres <a href="http://www.isc.org/downloads/bind/">Bind</a> y muchísimos más... pero hay 2 de estos grandísimos proyectos que no suelen ser tan conocidos para <em>el ciudadano de a pié</em>, y sin embargo son una parte fundamental de Internet. Me estoy refiriendo a <a href="http://www.postfix.org/">Postfix</a> y a <a href="http://www.courier-mta.org/">Courier</a>, la pareja perfecta para hacerse cargo de algo tan importante hoy en dìa como es el correo electrónico.</p>
<p>Y es que la combinación de estos 2 sistemas no solo funciona, sino que además lo hace increíblemente bien.</p>
<p><img class="right" src="/images/logos/logo_email.png">
Uno de los servicios más importantes de Internet es sin duda el correo electrónico, y al igual que con muchos otros servicios, no hay nada que gestione mejor el correo que GNU/Linux.</p>
<p>Hay muchos proyectos conocidísimos y de gran importancia en el mundo de GNU/Linux, como por ejemplo el servidor web <a href="https://projects.apache.org/project.html?httpd-http_server">Apache</a>, las bases de datos <a href="http://dev.mysql.com/">MySQL</a> y <a href="http://www.postgresql.org/">PostgreSQL</a>, el servidor de nombres <a href="http://www.isc.org/downloads/bind/">Bind</a> y muchísimos más... pero hay 2 de estos grandísimos proyectos que no suelen ser tan conocidos para <em>el ciudadano de a pié</em>, y sin embargo son una parte fundamental de Internet. Me estoy refiriendo a <a href="http://www.postfix.org/">Postfix</a> y a <a href="http://www.courier-mta.org/">Courier</a>, la pareja perfecta para hacerse cargo de algo tan importante hoy en dìa como es el correo electrónico.</p>
<p>Y es que la combinación de estos 2 sistemas no solo funciona, sino que además lo hace increíblemente bien.</p>
<p>Viendo que este artículo puede resultar bastante extenso, voy a dividirlo un poco y a crear un pequeño índice:</p>
<ol>
<li><a href="#init">Un poco de historia antes de empezar</a></li>
<li><a href="#dns">Configuración del DNS del dominio para recibir emails</a></li>
<li><a href="#db">Creación de la base de datos de usuarios</a></li>
<li><a href="#postfix">Instalación de Postfix como servidor SMTP</a></li>
<li><a href="#sasl">Configuración de SASL para autenticación de Postfix</a></li>
<li><a href="#courier">Instalación de Courier como servidor POP/IMAP</a></li>
<li><a href="#amavis">Instalación de antivirus y antispam</a></li>
<li><a href="#stats">Estadísticas y monitorización</a></li>
<li><a href="#refs">Referencias</a></li>
</ol>
<p>Vamos con el primero de los puntos...</p>
<h2>Un poco de historia antes de empezar<a name="init"></a></h2>
<p>Si de verdad tienes muchísima prisa en montar tu servidor de correo, puedes saltarte ésta parte e ir directamente al <a href="#db">capítulo 2</a>, pero es importante saber qué vas a instalar, porqué lo vas a hacer y cómo funciona realmente el mundo del correo electrónico.</p>
<p>Hay 2 procesos completamente diferenciados en el tema del correo electrónico:</p>
<ul>
<li><strong>El envío del mensaje</strong>: realizado mediante el protocolo <a href="http://es.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol">SMTP</a> por programas llamados <a href="http://es.wikipedia.org/wiki/Mail_Transport_Agent">MTA</a>.</li>
<li><strong>La lectura del mensaje</strong>: realizada mediante los protocolos <a href="http://es.wikipedia.org/wiki/Post_Office_Protocol">POP</a> o <a href="http://es.wikipedia.org/wiki/Internet_Message_Access_Protocol">IMAP</a>.</li>
</ul>
<p>Estos procesos no tiene nada que ver uno con otro, y como el uso del correo electrónico es totalmente transparente para el usuario, la mayoría de ellos ni los entiende ni los diferencia (y no me refiero solo a tus abuelos o a los míos, sino incluso a gente <em>del gremio</em> de la informática), ni falta que les hace... pero tranquilo, que si estás leyendo éste artículo significa que gracias a <a href="http://en.wikipedia.org/wiki/Lords_of_Kobol">los Dioses</a>, tu no formas parte de esa mayoría de usuarios <em>zombis</em>, <em><a href="http://es.wikipedia.org/wiki/Lamer_%28inform%C3%A1tica%29">lamers</a></em> y <em>catetos varios</em>.</p>
<p>Todo el sistema de correo electrónico se puede entender fácilmente siguiendo la <em>analogía</em> que tiene con el sistema de correo postal <em>de toda la vida</em>, en el que hay oficinas de correos, carteros, buzones, etc.</p>
<p>Cuando tú quieres escribir una carta postal a alguien (olvídate del email o el móvil, haz un esfuerzo e imagínatelo, hombre!), una vez redactada la metes en un sobre indicando el remitente y el destinatario, y la metes en el buzón. Un cartero recoge esa carta, y la lleva a la oficina de correos de tu barrio, donde si la carta es válida (lleva la dirección del destinatario, el sobre está cerrado, etc) es clasificada según sea su destino, momento en el cual un transportista (o cartero) la recoge de esa oficina y la entrega en la oficina de correos del barrio de dicho destinatario. En esa oficina, otros carteros recogen las cartas recién llegadas y las llevan al buzón del destinatario, el cuál a partir de ese momento ya puede abrir su buzón cuando lo desee y coger las cartas (y leerlas en ese momento o cuando él prefiera).</p>
<p>Éste es exactamente el mismo proceso que sigue el correo electrónico.</p>
<p>Cuando tu quieres escribir un email a alguien, una vez escrito en tu cliente de correo favorito (<a href="https://www.mozilla.org/es-ES/thunderbird/">Thunderbird/Icedove</a>, <a href="https://wiki.gnome.org/Apps/Evolution/">Evolution</a>, ~~<a href="https://www.outlook.com/owa/">Outlook</a>~~, ~~<a href="https://mail.google.com/">GMail</a>~~, etc), estos lo envían a tu servidor de correo saliente (la <em>oficina de correos</em> de tu barrio). Allí, si el email es valido (hay un remitente y un destinatario cuyo dominio existe, su servidor de correo responde, etc) se mira en el DNS del dominio al que va dirigido el correo cuál es el servidor SMTP de dicho dominio, y se le reenvía el mensaje a dicho servidor (<em>la oficina de correos del barrio del destinatario</em>). Allí, si el destinatario existe, se deja el email en su buzón (mailbox) a la espera de que éste se conecte a éste servidor (mediante un cliente de correo) y se descargue los mensajes que en él pudiera haber (y ya los leerá cuando él quiera).</p>
<p>Ves la analogía, verdad? Es prácticamente lo mismo (voy a tratar de ilustrar el ejemplo con una gráfica utilizando el genial <a href="http://www.graphviz.org/">Graphviz</a>, del cual ya hablé <a href="/2014/09/18/diagramas-mapas-de-red-y-demas-graficas-estructuradas-con-graphviz">en éste otro artículo</a>):</p>
<p><a name="mailprocess"></a>
<span class="graphviz" style="text-align: center;"><img src="data:image/png;base64,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XbtWVla2Z88e6eaKzpk8eXJkZOR77733008/lZSUnDlzZvr06VeuXJkxY4Z0GYytNWvWPP3007bL77zzznbt2hUXF2/dutXO6qKiov7v//4vIyOjuLi4sLAwLS3ts88+mzp1qvnjTDv7R4p27ty5O3bsKCkpycnJmTVr1pUrVxz+OMcOPz+/2bNnHzp06Pr160eOHJkxY4a3t/eMGTPkB2xLTjdwgnPB2Kd6j1K92YbwnrJVWVl58eLFv//97xs3bmzSpAkfhwO2ODnYPzm89NJLBoPhvffey87OLi0tPXXq1P/93//ZflXuxIBVm8FIlYHMYSOuGC6tAnB4KO33PVfsFisqdmBF22KHnAPn3DTP/lzOltW749dff3311VetrhhX/SjDkqaW10nCLQoLC63utl+tBx54wP4dNefOnduzZ88vv/zygw8+MC984YUXXnzxxWrLFxcXz5s3b8eOHUVFRW3atHnllVfefvvto0ePCiGee+65l19++fjx4ytXrvz5558vXryo1+tbtGjRv3///v37m3864rCFa9euzZ8/f+fOnXl5eQaDISEhoVGjRv/617+EEPfdd9/rr78+dOhQy5AOHz4s/cfySYBCiCeffFK6v2JBQcEXX3whPXLQ19dXespfly5dbLcuJyfH/FCQ9u3bW95b5eLFiz169DD/GR4evn379mp3UWFhobS6y5cvBwUF3XvvvaNHj46Li5Nedbh/LKMNDQ2NjY2dOHGidF+KQ4cOyd/2e+65RzqmTZo0+eijj1JTU//zn/9UVla2a9du0qRJlne1tR9wtewfxEcffdQyTqk7WV5X//DDD3/66adK957V5r/wwgvdu3cfMmSIecnkyZM7dOhg+Wu98ePHT5gwwX6PGjduXE27zjJ+21DtN9uzZ0/eU2a2JyKNRuPv73/bbbd17dp15MiRMj+gCQ4Ojo6OllMSUNHZs2ctL62sCQOuqPOTw5kzZ1JSUvbs2VNRUXHPPfdMnjz5s88+279/v+WThOzvhJiYmGo3RP5gZLlbJIpG1Zr6g8NGahOhnADsH0qHfc+Wx47viral9kffzjTPublcTW9G87tDekr8+PHjFy9ebH5K/FtvveWKo2zGeE2CXS/JTLAB4JbBgA23kJlgwxM8//zzVgk2gLrHeM0l4gAAAAAAqIAEGwAAAAAAFZBgAwAAoB7btGlT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NBRKx8F9+/aNGjXq9ttv9/X1DQkJ6dy589tvv11QUFDLZjMyMjQazfbt260qzps3T9RiPmD16smTJzUaTVxcnCq7AnAdZQn2lCliyhQXRQKgPhk+fPjEiRP79et35MgRo9G4c+fODh06TJo0KTY2VioQGBhoMpn2798v/fnOO+9U205+fv6CBQuEEEOHDjWZTG+88YYQIi0tzfSHcePGCSE2bdpkXjJ48GCpbnFxsdR+3759pZeuXbv2xRdfZGdnd+3adevWrS7eBwAAuJOicfDVV1+Ni4sLDQ1dv359QUHB6dOnZ86cuXr16rvvvjszM9PpZoUQa9euDQsLS0hIZLyDKgAAIABJREFUsKo4depUUbv5gKVFixYJIXbv3n306NFa7grApZQl2HFxooaPjQA0IHv37l2+fPmYMWNeeeWV2267zdfXt1WrVu++++748eNtC/v5+bVo0WLTpk379u2zfTU1NTUqKkqtwAwGw9NPP52SklJeXj558mS1mgUAoF6oaRycNWvWnDlzPv3009TU1LZt2/r6+oaGhvbu3TszMzM6Orpnz57Hjh1zollJenr6k08+qdPp7MdWm/lAVVXV4sWLO3ToIP7ItB1iSgB34RJxAIodOXJECNG6dWur5YMGDbItrNVqZ8yYIYSwvdyroKDgs88+mz59uuXCAwcODBw40M7aV6xYYfvBtqVu3bpJQdpe9gYAwC3Pahw8derUW2+91bFjR+miMEv+/v6pqalGo3HSpElKm5UcO3bsxIkTffv2dVhd6XzA0vfff6/T6b744gshxJIlSyoqKhyuzk7MgEuRYANQLCIiQgixZcsWq+WJiYl5eXm25UePHh0ZGbl27dpDhw5ZLv/444979erVqlUrdcMzmUzSfzQajbotAwDg+azGwQULFlRUVCQlJVVb+KGHHmrevPmWLVt+++03Rc1K0tPT9Xp9jx495ATm9Hxg4cKFo0aNio2Nbd++fU5OzsaNG+WsrqaYAZciwQag2EMPPdS0adPNmzf37Nlz+/btVVVV9svr9fpp06aZTKZ3333XvLC4uHj+/Pmvvfaa6uFt375dCNGmTRuDwaB64wAAeDircfCnn34SQsTExNRUXnpp586dipqVrF27tnv37oGBgXICc24+cPXq1XXr1o0cOVIIMXr0aCHEwoUL5ayuppgB+ZJFcrJIVlSFBBuA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"></span></p>
<p>Por lo tanto el primer paso necesario en ésta cadena es el envío de correo, es decir, el <a href="http://es.wikipedia.org/wiki/Mail_Transport_Agent">MTA</a>.</p>
<p>Hay muchos programas en GNU/Linux que actúan de MTA. El más famoso de todos seguramente sea <a href="http://www.sendmail.org">Sendmail</a>, que fue uno de los primeros MTA que existieron, y fue utilizado durante mucho tiempo en prácticamente todos los servidores SMTP de Internet. No obstante siempre se le ha considerado <em>difícil de configurar</em>, lo que unido a los numerosos problemas de seguridad que ha tenido en su historia, hoy en día podríamos decir que ha sido reemplazado por otros MTAs como por ejemplo <a href="www.qmail.org">Qmail</a>, <a href="http://www.exim.org/">Exim</a> o <a href="http://www.postfix.org/">Postfix</a>.</p>
<p>Éste último es sin duda mi preferido, y es el que voy a explicar en este artículo.</p>
<p>Una vez tengamos el SMTP funcionando, necesitaremos otros sistemas que accedan a los emails que el MTA nos haya dejado. Para esto también tenemos diferentes y buenas opciones, como por ejemplo <a href="http://dovecot.org/">Dovecot</a> o <a href="http://www.courier-mta.org/imap/">Courier</a>.</p>
<p>He probado ambos, y aunque Dovecot funciona muy bien, siempre me ha gustado mucho más Courier... por lo tanto, es el que voy a explicar en este artículo.</p>
<p>Montar cualquiera de estos servicios basándose en los usuarios locales del servidor no tiene ningún misterio, aparte de ser algo <strong>muy poco recomendable</strong> ya que supondría que tendríamos que crear un usuario en el servidor por cada usuario de correo que fuéramos a utilizar (solo el imaginarlo ya me da urticaria!). Por lo tanto, los usuarios de nuestro servidor de correo van a ser usuarios virtuales cuyos datos van a estar almacenados en una base de datos (que podría ser <a href="http://www.mysql.org">MySQL</a>, <a href="http://www.postgresql.org/">PostgreSQL</a> o incluso <a href="http://www.openldap.org/">OpenLDAP</a>).</p>
<p>Y tal y como indica el título del artículo, vamos a explicar como montar el servidor COMPLETO, y no sería verdaderamente un servidor de correo completo si no tuviera también detección de <a href="http://es.wikipedia.org/wiki/Spam">SPAM</a>, antivirus, filtros de correo, <a href="http://es.wikipedia.org/wiki/Transport_Layer_Security">SSL</a> en todos estos servicios e incluso estadísticas y gráficas para la monitorización de todo el sistema.</p>
<p>Ahora que hemos visto un poco los fundamentos básicos del sistema de correo electrónico, vamos a entrar en materia...</p>
<h2>Configuración del DNS del dominio para recibir emails<a name="dns"></a></h2>
<p>Hay una parte fundamental para <em>entender</em> cómo funciona el correo electrónico en Internet, y aunque es sumamente obvia y básica para los que conocemos el tema, voy a explicarla simplemente para asegurarme de que entiendes lo que estamos haciendo, no sea que después de todo el <em>rollo</em> que estoy contando en este artículo, todavía no tengas claros algunos conceptos básicos sobre el funcionamiento de los servidores de correo (y si los conoces, pues te aguantas y lo lees de nuevo, que seguro que te va a costar a ti mucho menos leerlo que a mi escribirlo xDDDD).</p>
<p>Supongamos que ya tenemos nuestro flamante servidor de correo listo y funcionando, preparado para recibir el correo de las direcciones de email de (por ejemplo) <em>pornohardware.com</em> (me refiero a direcciones del tipo usuario@pornohardware.com y similares).</p>
<p>Puede que el servidor esté funcionando, pero... ¿cómo sabe <em>la gente</em> que éste servidor que acabo de configurar es a donde tienen que enviar los emails que vayan a la dirección <a href="mailto:usuario@pornohardware.com">usuario@pornohardware.com</a>, por ejemplo?</p>
<p>La respuesta está, como casi todo lo relativo a los nombres de los dominios, en el <a href="https://es.wikipedia.org/wiki/Domain_Name_System">DNS</a>.</p>
<p>Doy por sentado que conoces el servicio de DNS de un dominio, y que sabes perfectamente que éste DNS se encarga de decirle a tu <em>navegador</em> (por ejemplo) que la <a href="https://es.wikipedia.org/wiki/Direcci%C3%B3n_IP">dirección IP</a> del servidor de pornoharware.com es la 188.165.118.8, verdad?</p>
<p>El DNS se configura a base de <em>registros</em>, y los hay de varios tipos. Uno de los más utilizados es el <strong>registro de tipo A</strong>, que se encarga precisamente de esto último que acabo de decir: traducir el nombre de un dominio a una dirección IP.</p>
<p>Sin embargo, hay otros tipos de registros en un DNS que son igual de importantes que el A, como por ejemplo el que atañe al correo de dicho dominio, llamado <strong>registro de tipo MX</strong>.</p>
<p>Si un registro de tipo A del dominio de pornohardware.com diría que "<em>la dirección www.pornohardware.com es en realidad la IP 188.165.118.8</em>", un registro de tipo MX del dominio de pornohardware.com diría que "<em>el servidor que se encarga del correo de las direcciones acabadas en @pornoharware.com es la IP 141.8.224.25 (por ejemplo)</em>".</p>
<p>Por eso, cuando enviamos un email a una dirección, nuestro servidor hace una consulta al DNS del dominio del destinatario para saber cuál es la IP del servidor de correo de dicho destinatario... y una vez obtenida, se intenta conectar a esa dirección para pasarle el email.</p>
<p>Éste tipo de registros DNS tienen además una <em>particularidad</em> que no tienen los demás, y es que es posible asignar más de 1 servidor de correo a cada dominio, definiendo diferentes prioridades a cada uno de ellos... es decir, que podemos configurar 2 servidores de correo diferentes para que se hagan cargo del correo de un dominio determinado, y decirle al DNS que el servidor de correo <em>habitual</em> será el 1... pero que en aquellos casos en los que el servidor 1 esté caído por cualquier motivo, puede enviar el email también al servidor 2.</p>
<p>También podemos configurar 2 servidores de correo diferentes para el mismo dominio, y asignarles <strong>la misma prioridad</strong>. En éste se iría utilizando un servidor u otro indistintamente, siendo esto muy útil para <a href="https://es.wikipedia.org/wiki/Balance_de_carga">balancear</a> la carga entre ambos.</p>
<h3>Un ejemplo práctico</h3>
<p>En cualquier distribución de GNU/Linux tenemos disponible el comando <code>nslookup</code>, que sirve para conectarse a un servidor DNS y hacerle consultas.</p>
<p>No entraré a explicar su sintaxis, únicamente tenéis que ver que con el siguiente comando le estoy pidiendo al servidor DNS 208.67.222.222 (uno de los servidores DNS públicos de <a href="http://www.opendns.com/">OpenDNS</a>) que me diga cuál es la IP del servidor de <em>pornohardware.com</em>:</p>
<div class="highlight"><pre><span></span><code>bhean@vader:~$ nslookup pornohardware.com <span class="m">208</span>.67.222.222
Server: <span class="m">208</span>.67.222.222
Address: <span class="m">208</span>.67.222.222#53
Non-authoritative answer:
Name: pornohardware.com
Address: <span class="m">188</span>.165.118.8
</code></pre></div>
<p>Como veis, primero nos dice a qué servidor DNS le estamos haciendo la consulta (en éste caso: <code>208.67.222.222</code>) y a través de qué puerto (<code>208.67.222.222#53</code>), y luego nos da lo que le hemos pedido: <strong><code>Address: 188.165.118.8</code></strong>.</p>
<p>Si en lugar de pedirle la IP de la dirección web, le pedimos las IPs de su servidor/servidores de correo, el comando sería:</p>
<div class="highlight"><pre><span></span><code>bhean@vader:~$ nslookup -type<span class="o">=</span>mx pornohardware.com <span class="m">208</span>.67.222.222
Server: <span class="m">208</span>.67.222.222
Address: <span class="m">208</span>.67.222.222#53
Non-authoritative answer:
pornohardware.com mail <span class="nv">exchanger</span> <span class="o">=</span> <span class="m">5</span> mail.pornohardware.com.
</code></pre></div>
<p>En éste caso, nos dice que el servidor de correo de <em>pornohardware.com</em> es <em>mail.pornohardware.com</em>.</p>
<p>Si hacemos la misma prueba pero con un dominio que tenga configurados varios servidores de correo, por ejemplo <code>debian.org</code>, veremos esto:</p>
<div class="highlight"><pre><span></span><code>bhean@vader:~$ nslookup -type<span class="o">=</span>mx debian.org <span class="m">208</span>.67.222.222
Server: <span class="m">208</span>.67.222.222
Address: <span class="m">208</span>.67.222.222#53
Non-authoritative answer:
debian.org mail <span class="nv">exchanger</span> <span class="o">=</span> <span class="m">5</span> mailly.debian.org.
debian.org mail <span class="nv">exchanger</span> <span class="o">=</span> <span class="m">10</span> muffat.debian.org.
</code></pre></div>
<p>Vemos que los servidores de correo del dominio <code>debian.org</code> son 2:</p>
<ul>
<li><strong>mailly.debian.org</strong>: con prioridad 5</li>
<li><strong>muffat.debian.org</strong>: con prioridad 10</li>
</ul>
<p>Como uno tiene una establecida una prioridad de 5 y el otro de 10, el que tenga el valor más bajo es el que se considera <em>servidor principal</em>, y en caso de estar caído, se utilizaría el otro.</p>
<p>Es decir, <strong>a MENOR valor, MÁS prioridad tendrá ese servidor con respecto a los demás</strong>.</p>
<p>Ahora que ya tenemos claro cómo <em>anunciar</em> a todo Internet que nuestro servidor va a ser el encargado de manejar el correo de determinado dominio, vamos <em>al turrón</em>...</p>
<h2>Creación de la base de datos de usuarios<a name="db"></a></h2>
<p>Como ya he dicho antes, que los usuarios del sistema de correo sean los usuarios locales que haya en el servidor (que es el funcionamiento por defecto) es algo <strong>completamente desaconsejable</strong>, y da igual que penséis que <em>para un par de usuarios que vais a usar no merece la pena una base de datos</em>, o <em>que solo es una prueba y si va bien ya lo montaréis con base de datos más adelante</em> o cualquier otra excusa que se os ocurra.</p>
<p>Mi experiencia como <em>sysadmin</em> me ha demostrado una y otra vez que éstas cosas, al cabo de no mucho tiempo, nunca son como eran cuando se pensaron y montaron inicialmente. Es decir, que si ahora piensas que solo vas a usar 2 usuarios, cuando te quieras dar cuenta tendrás una docena de ellos... y si algo molesta sobremanera a un <em>sysadmin <a href="http://es.wikipedia.org/wiki/Bastard_Operator_from_Hell">bofh</a></em> es trabajar 2 veces para lo mismo, así que vamos a hacer las cosas bien desde el principio, que no cuesta nada! xDD</p>
<p>Lo primero es elegir si vas a utilizar base de datos o LDAP para almacenar los usuarios, ya que son métodos MUY diferentes.</p>
<p>Yo recomiendo base de datos (y más concretamente <a href="http://www.postgresql.org/">PostgreSQL</a>), pero si vas a implementar el servidor de correo en un entorno en el que ya dispones de un <em>directorio activo</em> u <a href="http://www.openldap.org/">OpenLDAP</a>, también puedes hacerlo.</p>
<p>Para éste artículo usaré base de datos, concretamente PostgreSQL (aunque si hubiera alguna diferencias en alguna parte con respecto a MySQL, intentaré explicarla). Llegados a éste punto doy por hecho que ya tenéis vuestro servidor de base de datos instalado y funcionando, por lo que si no es así, instala y configura el servidor de base de datos antes de continuar.</p>
<p>Si quieres hacer que prácticamente toda la información del sistema se almacene y gestione en la base de datos, puedes hacerlo. Yo normalmente solo uso la base de datos para la información de los <em>usuarios</em> y para la de sus <em>alias de correo</em>.</p>
<p>Para almacenar ésta información tenemos que crear una tabla para cada cosa, y que contenga la información necesaria tanto para Postfix como para Courier.
Un ejemplo completamente válido y que llevo utilizando muchísimos años en diferentes servidores de correo que administro es el siguiente:</p>
<h3>Tabla para usuarios</h3>
<table>
<thead>
<tr>
<th align="left">Nombre columna</th>
<th align="left">Tipo columna</th>
<th align="left">Valor por defecto</th>
<th align="left">Nulos?</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">user_id</td>
<td align="left">integer</td>
<td align="left">nextval('user_id_seq')</td>
<td align="left">NO</td>
</tr>
<tr>
<td align="left">name</td>
<td align="left">character varying(64)</td>
<td align="left">NULL</td>
<td align="left">SI</td>
</tr>
<tr>
<td align="left">surname</td>
<td align="left">character varying(128)</td>
<td align="left">NULL</td>
<td align="left">SI</td>
</tr>
<tr>
<td align="left">login</td>
<td align="left">character varying(32)</td>
<td align="left">NULL</td>
<td align="left">NO</td>
</tr>
<tr>
<td align="left">password_crypt</td>
<td align="left">character varying(64)</td>
<td align="left">NULL</td>
<td align="left">NO</td>
</tr>
<tr>
<td align="left">email_local</td>
<td align="left">character varying(255)</td>
<td align="left">NULL</td>
<td align="left">NO</td>
</tr>
<tr>
<td align="left">insert_date</td>
<td align="left">timestamp without time zone</td>
<td align="left">now()</td>
<td align="left">NO</td>
</tr>
<tr>
<td align="left">description</td>
<td align="left">character varying(255)</td>
<td align="left">NULL</td>
<td align="left">SI</td>
</tr>
<tr>
<td align="left">imap_access</td>
<td align="left">character(1)</td>
<td align="left">0</td>
<td align="left">NO</td>
</tr>
<tr>
<td align="left">smtp_access</td>
<td align="left">character(1)</td>
<td align="left">0</td>
<td align="left">NO</td>
</tr>
<tr>
<td align="left">path_maildir</td>
<td align="left">character varying(255)</td>
<td align="left">'/'</td>
<td align="left">NO</td>
</tr>
<tr>
<td align="left">user_active</td>
<td align="left">character(1)</td>
<td align="left">0</td>
<td align="left">NO</td>
</tr>
</tbody>
</table>
<h3>Tabla para alias de correo</h3>
<table>
<thead>
<tr>
<th align="left">Nombre columna</th>
<th align="left">Tipo columna</th>
<th align="left">Valor por defecto</th>
<th align="left">Nulos?</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">email_local</td>
<td align="left">character varying(255)</td>
<td align="left">NULL</td>
<td align="left">NO</td>
</tr>
<tr>
<td align="left">email_alias</td>
<td align="left">character varying(255)</td>
<td align="left">NULL</td>
<td align="left">NO</td>
</tr>
</tbody>
</table>
<p>Ahora veremos las <em>querys</em> necesarias para crear esas tablas... primer tómate unos segundos para examinar los campos de dichas tablas y hacerte una idea aproximada de los datos que vamos a guardar en ellas: todos los campos son más o menos auto explicativos, pero por si acaso comentaré para qué se van a usar:</p>
<h3>Tabla para usuarios</h3>
<ul>
<li><strong>user_id</strong>: Ésta será la <em><a href="http://es.wikipedia.org/wiki/Clave_primaria">clave primaria</a></em> de la tabla, por eso su valor por defecto en PostgreSQL es la <a href="http://www.postgresql.org/docs/9.3/static/sql-createsequence.html">secuencia</a> <code>user_id_seq</code>, y en MySQL será un campo <em><a href="http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html">AUTOINCREMENT</a></em>.</li>
<li><strong>name</strong>: En éste campo se almacenará el nombre del usuario (me refiero a su nombre de pila, que es necesario para algunas cosas, no el nick).</li>
<li><strong>surname</strong>: En éste campo se almacenarán los apellidos del usuario.</li>
<li><strong>login</strong>: Nick del usuario</li>
<li><strong>password_crypt</strong>: La contraseña del usuario (utilizando el algoritmo de cifrado <code>crypt</code> basado en <a href="http://es.wikipedia.org/wiki/Data_Encryption_Standard">DES</a>).</li>
<li><strong>email_local</strong>: La dirección de email que vamos a crear para el usuario.</li>
<li><strong>insert_date</strong>: Fecha de creación del usuario</li>
<li><strong>description</strong>: Como su nombre indica, es la descripción que queramos hacer de la cuenta de éste usuario.</li>
<li><strong>imap_access</strong>: Usaremos este campo para permitir o no permitir que el usuario se conecte al servidor IMAP para leer correo.</li>
<li><strong>smtp_access</strong>: Usaremos este campo para permitir o no permitir que el usuario se conecte al servidor SMTP para enviar correo.</li>
<li><strong>path_maildir</strong>: Aquí indicaremos la ruta física en el disco duro del servidor del <em>mailbox</em> del usuario.</li>
<li><strong>user_active</strong>: Con este campo habilitaremos o no la cuenta del usuario.</li>
</ul>
<h3>Tabla para alias de correo</h3>
<ul>
<li><strong>email_local</strong>: La dirección de correo del usuario al que vamos a crear un <em>alias</em>.</li>
<li><strong>email_alias</strong>: El alias de correo que vamos a crear.</li>
</ul>
<p>Una vez explicados los campos de ambas tablas, el código <a href="http://es.wikipedia.org/wiki/SQL">SQL</a> necesario para crearlas sería el siguiente:</p>
<p>Para la tabla de <em>usuarios</em> en <strong>PostgreSQL</strong>:</p>
<div class="highlight"><pre><span></span><code><span class="k">CREATE</span> <span class="k">DATABASE</span> <span class="n">email</span><span class="p">;</span>
<span class="err">\\</span><span class="n">c</span> <span class="n">email</span>
<span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">users</span> <span class="p">(</span>
<span class="s s-Name">"user_id"</span> <span class="nb">integer</span> <span class="k">DEFAULT</span> <span class="n">nextval</span><span class="p">((</span><span class="s1">'user_id_seq'</span><span class="o">::</span><span class="nb">text</span><span class="p">)</span><span class="o">::</span><span class="n">regclass</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
<span class="s s-Name">"name"</span> <span class="nb">character</span> <span class="k">varying</span><span class="p">(</span><span class="mf">64</span><span class="p">)</span> <span class="k">DEFAULT</span> <span class="k">NULL</span><span class="o">::</span><span class="nb">character</span> <span class="k">varying</span><span class="p">,</span>
<span class="s s-Name">"surname"</span> <span class="nb">character</span> <span class="k">varying</span><span class="p">(</span><span class="mf">128</span><span class="p">)</span> <span class="k">DEFAULT</span> <span class="k">NULL</span><span class="o">::</span><span class="nb">character</span> <span class="k">varying</span><span class="p">,</span>
<span class="s s-Name">"login"</span> <span class="nb">character</span> <span class="k">varying</span><span class="p">(</span><span class="mf">32</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
<span class="s s-Name">"password_crypt"</span> <span class="nb">character</span> <span class="k">varying</span><span class="p">(</span><span class="mf">64</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
<span class="s s-Name">"email_local"</span> <span class="nb">character</span> <span class="k">varying</span><span class="p">(</span><span class="mf">255</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
<span class="s s-Name">"insert_date"</span> <span class="nb">timestamp</span> <span class="nb">without time zone</span> <span class="k">DEFAULT</span> <span class="n">now</span><span class="p">()</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
<span class="s s-Name">"description"</span> <span class="nb">character</span> <span class="k">varying</span><span class="p">(</span><span class="mf">255</span><span class="p">)</span> <span class="k">DEFAULT</span> <span class="k">NULL</span><span class="o">::</span><span class="nb">character</span> <span class="k">varying</span><span class="p">,</span>
<span class="s s-Name">"imap_access"</span> <span class="nb">character</span><span class="p">(</span><span class="mf">1</span><span class="p">)</span> <span class="k">DEFAULT</span> <span class="mf">0</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
<span class="s s-Name">"smtp_access"</span> <span class="nb">character</span><span class="p">(</span><span class="mf">1</span><span class="p">)</span> <span class="k">DEFAULT</span> <span class="mf">0</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
<span class="s s-Name">"path_maildir"</span> <span class="nb">character</span> <span class="k">varying</span><span class="p">(</span><span class="mf">255</span><span class="p">)</span> <span class="k">DEFAULT</span> <span class="s1">'/'</span><span class="o">::</span><span class="nb">character</span> <span class="k">varying</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
<span class="s s-Name">"user_active"</span> <span class="nb">character</span><span class="p">(</span><span class="mf">1</span><span class="p">)</span> <span class="k">DEFAULT</span> <span class="mf">0</span> <span class="k">NOT</span> <span class="k">NULL</span>
<span class="p">);</span>
<span class="k">ALTER</span> <span class="k">TABLE</span> <span class="k">ONLY</span> <span class="n">users</span>
<span class="k">ADD</span> <span class="k">CONSTRAINT</span> <span class="n">users_pkey</span> <span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="p">(</span><span class="s s-Name">"user_id"</span><span class="p">);</span>
<span class="k">ALTER</span> <span class="k">TABLE</span> <span class="k">ONLY</span> <span class="n">users</span>
<span class="k">ADD</span> <span class="k">CONSTRAINT</span> <span class="s s-Name">"users_email_local_key"</span> <span class="k">UNIQUE</span> <span class="p">(</span><span class="s s-Name">"email_local"</span><span class="p">);</span>
<span class="k">ALTER</span> <span class="k">TABLE</span> <span class="k">ONLY</span> <span class="n">users</span>
<span class="k">ADD</span> <span class="k">CONSTRAINT</span> <span class="s s-Name">"users_login_key"</span> <span class="k">UNIQUE</span> <span class="p">(</span><span class="s s-Name">"login"</span><span class="p">);</span>
<span class="k">CREATE</span> <span class="k">SEQUENCE</span> <span class="n">user_id_seq</span>
<span class="k">START</span> <span class="k">WITH</span> <span class="mf">1</span>
<span class="k">INCREMENT</span> <span class="k">BY</span> <span class="mf">1</span>
<span class="k">NO</span> <span class="k">MINVALUE</span>
<span class="k">NO</span> <span class="k">MAXVALUE</span>
<span class="k">CACHE</span> <span class="mf">1</span><span class="p">;</span>
</code></pre></div>
<p>Para la tabla de <em>usuarios</em> en <strong>MySQL</strong>:</p>
<div class="highlight"><pre><span></span><code><span class="k">CREATE</span> <span class="k">DATABASE</span> <span class="n">email</span><span class="p">;</span>
<span class="k">use</span> <span class="n">email</span><span class="p">;</span>
<span class="k">CREATE</span> <span class="k">TABLE</span> <span class="nf">users</span> <span class="p">(</span>
<span class="n">user_id</span> <span class="kt">int</span><span class="p">(</span><span class="mi">7</span><span class="p">)</span> <span class="k">NOT</span> <span class="no">NULL</span> <span class="kp">AUTO_INCREMENT</span><span class="p">,</span>
<span class="n">name</span> <span class="kt">varchar</span><span class="p">(</span><span class="mi">64</span><span class="p">)</span> <span class="k">DEFAULT</span> <span class="no">NULL</span><span class="p">,</span>
<span class="n">surname</span> <span class="kt">varchar</span><span class="p">(</span><span class="mi">128</span><span class="p">)</span> <span class="k">DEFAULT</span> <span class="no">NULL</span><span class="p">,</span>
<span class="n">login</span> <span class="kt">varchar</span><span class="p">(</span><span class="mi">32</span><span class="p">)</span> <span class="k">NOT</span> <span class="no">NULL</span> <span class="k">DEFAULT</span> <span class="s1">''</span><span class="p">,</span>
<span class="n">password_crypt</span> <span class="kt">varchar</span><span class="p">(</span><span class="mi">64</span><span class="p">)</span> <span class="k">NOT</span> <span class="no">NULL</span><span class="p">,</span>
<span class="n">email_local</span> <span class="kt">varchar</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span> <span class="k">NOT</span> <span class="no">NULL</span> <span class="k">DEFAULT</span> <span class="s1">''</span><span class="p">,</span>
<span class="n">insert_date</span> <span class="kt">datetime</span> <span class="k">NOT</span> <span class="no">NULL</span><span class="p">,</span>
<span class="n">description</span> <span class="kt">text</span><span class="p">,</span>
<span class="n">imap_access</span> <span class="kt">char</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="k">NOT</span> <span class="no">NULL</span> <span class="k">DEFAULT</span> <span class="s1">'0'</span><span class="p">,</span>
<span class="n">smtp_access</span> <span class="kt">char</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="k">NOT</span> <span class="no">NULL</span> <span class="k">DEFAULT</span> <span class="s1">'0'</span><span class="p">,</span>
<span class="n">path_maildir</span> <span class="kt">varchar</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span> <span class="k">NOT</span> <span class="no">NULL</span> <span class="k">DEFAULT</span> <span class="s1">'/'</span><span class="p">,</span>
<span class="n">user_active</span> <span class="kt">char</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="k">NOT</span> <span class="no">NULL</span> <span class="k">DEFAULT</span> <span class="s1">'1'</span><span class="p">,</span>
<span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="p">(</span><span class="n">user_id</span><span class="p">),</span>
<span class="k">UNIQUE</span> <span class="k">KEY</span> <span class="nf">email_local</span> <span class="p">(</span><span class="n">email_local</span><span class="p">),</span>
<span class="k">KEY</span> <span class="nf">imap_access</span> <span class="p">(</span><span class="n">imap_access</span><span class="p">),</span>
<span class="k">KEY</span> <span class="nf">smtp_access</span> <span class="p">(</span><span class="n">smtp_access</span><span class="p">)</span>
<span class="p">)</span> <span class="kp">ENGINE</span><span class="o">=</span><span class="n">MyISAM</span> <span class="kp">AUTO_INCREMENT</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span>
</code></pre></div>
<p>Para la tabla de <em>alias de usuarios</em> en <strong>PostgreSQL</strong>:</p>
<div class="highlight"><pre><span></span><code><span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">users_aliases</span> <span class="p">(</span>
<span class="s s-Name">"email_local"</span> <span class="nb">character</span> <span class="k">varying</span><span class="p">(</span><span class="mf">255</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
<span class="s s-Name">"email_alias"</span> <span class="nb">character</span> <span class="k">varying</span><span class="p">(</span><span class="mf">255</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span>
<span class="p">);</span>
<span class="k">ALTER</span> <span class="k">TABLE</span> <span class="k">ONLY</span> <span class="n">users_aliases</span>
<span class="k">ADD</span> <span class="k">CONSTRAINT</span> <span class="n">users_emails_ukey</span> <span class="k">UNIQUE</span> <span class="p">(</span><span class="s s-Name">"email_local"</span><span class="p">,</span> <span class="s s-Name">"email_alias"</span><span class="p">);</span>
</code></pre></div>
<p>Para la tabla de <em>alias de usuarios</em> en <strong>MySQL</strong>:</p>
<div class="highlight"><pre><span></span><code><span class="k">CREATE</span> <span class="k">TABLE</span> <span class="nf">users_aliases</span> <span class="p">(</span>
<span class="n">email_local</span> <span class="kt">varchar</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span> <span class="k">NOT</span> <span class="no">NULL</span> <span class="k">DEFAULT</span> <span class="s1">''</span><span class="p">,</span>
<span class="n">email_alias</span> <span class="kt">varchar</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span> <span class="k">NOT</span> <span class="no">NULL</span> <span class="k">DEFAULT</span> <span class="s1">''</span><span class="p">,</span>
<span class="k">UNIQUE</span> <span class="k">KEY</span> <span class="nf">email_local</span> <span class="p">(</span><span class="n">email_local</span><span class="p">,</span> <span class="n">email_alias</span><span class="p">)</span>
<span class="p">)</span> <span class="kp">ENGINE</span><span class="o">=</span><span class="n">MyISAM</span> <span class="kp">AUTO_INCREMENT</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span>
</code></pre></div>
<p>Aparte de las tablas (y la secuencia, en el caso de PostgreSQL) necesitaremos crear también los usuarios que van a utilizar tanto Postfix como Courier para acceder a la base de datos. Siempre es recomendable crear un usuario para cada uno en lugar de crear uno en común.</p>
<p>Os recomiendo utilizar contraseñas complejas (que contengan letras, números y caracteres especiales, y cuya longitud no sea nunca inferior a 10 caracteres) generadas de forma aleatoria, ya que una vez tengáis los servicios configurados, no necesitaréis recordarlas.</p>
<p>Una web bastante útil y sencilla para generar contraseñas complejas de forma aleatoria es http://www.clavesegura.org/</p>
<p>Crearemos entonces 3 usuarios, uno para cada uno de los servicios que vamos a configurar más adelante (Postfix, Courier y SASL), por lo tanto ejecutamos éstas querys en nuestra base de datos para crear dichos usuarios y para darles permisos sobre las tablas que acabamos de crear.</p>
<p><strong>No hay que confundir estos usuarios</strong> (que son los que usará Postfix, por ejemplo, para obtener los datos del destinatario de un email) <strong>con los usuarios de nuestro correo</strong> (es decir, las personas que van a disponer de direcciones de email gestionadas por nuestro servidor).</p>
<p>Para crear los usuarios que usarán estos servicios (Postfix, Courier y SASL) para conectarse a la base de datos en <strong>PostgreSQL</strong>:</p>
<div class="highlight"><pre><span></span><code><span class="k">CREATE</span> <span class="k">ROLE</span> <span class="n">app_postfix</span><span class="p">;</span>
<span class="k">ALTER</span> <span class="k">ROLE</span> <span class="n">app_postfix</span> <span class="k">WITH</span> <span class="n">NOSUPERUSER</span> <span class="k">INHERIT</span> <span class="n">NOCREATEROLE</span> <span class="n">NOCREATEDB</span> <span class="n">LOGIN</span> <span class="n">NOREPLICATION</span> <span class="k">PASSWORD</span> <span class="s1">'QZrRP-fzuq'</span><span class="p">;</span>
<span class="k">CREATE</span> <span class="k">ROLE</span> <span class="n">app_courier</span><span class="p">;</span>
<span class="k">ALTER</span> <span class="k">ROLE</span> <span class="n">app_courier</span> <span class="k">WITH</span> <span class="n">NOSUPERUSER</span> <span class="k">INHERIT</span> <span class="n">NOCREATEROLE</span> <span class="n">NOCREATEDB</span> <span class="n">LOGIN</span> <span class="n">NOREPLICATION</span> <span class="k">PASSWORD</span> <span class="s1">'OQ5JQ3+pNR'</span><span class="p">;</span>
<span class="k">CREATE</span> <span class="k">ROLE</span> <span class="n">app_sasl</span><span class="p">;</span>
<span class="k">ALTER</span> <span class="k">ROLE</span> <span class="n">app_sasl</span> <span class="k">WITH</span> <span class="n">NOSUPERUSER</span> <span class="k">INHERIT</span> <span class="n">NOCREATEROLE</span> <span class="n">NOCREATEDB</span> <span class="n">LOGIN</span> <span class="n">NOREPLICATION</span> <span class="k">PASSWORD</span> <span class="s1">'hb9mwJGcc'</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">SELECT</span> <span class="k">ON</span> <span class="k">TABLE</span> <span class="n">users</span> <span class="k">TO</span> <span class="n">app_postfix</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">SELECT</span> <span class="k">ON</span> <span class="k">TABLE</span> <span class="n">users</span> <span class="k">TO</span> <span class="n">app_courier</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">SELECT</span> <span class="k">ON</span> <span class="k">TABLE</span> <span class="n">users</span> <span class="k">TO</span> <span class="n">app_sasl</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">SELECT</span> <span class="k">ON</span> <span class="k">TABLE</span> <span class="n">users_aliases</span> <span class="k">TO</span> <span class="n">app_postfix</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">SELECT</span> <span class="k">ON</span> <span class="k">TABLE</span> <span class="n">users_aliases</span> <span class="k">TO</span> <span class="n">app_courier</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">SELECT</span> <span class="k">ON</span> <span class="k">TABLE</span> <span class="n">users_aliases</span> <span class="k">TO</span> <span class="n">app_sasl</span><span class="p">;</span>
</code></pre></div>
<p>Y para crear los usuarios que usarán estos servicios (Postfix, Courier y SASL) para conectarse a la base de datos en <strong>MySQL</strong>:</p>
<div class="highlight"><pre><span></span><code><span class="k">CREATE</span> <span class="n">USER</span> <span class="s1">'app_postfix'</span><span class="o">@</span><span class="s1">'localhost'</span> <span class="n">IDENTIFIED</span> <span class="k">BY</span> <span class="n">PASSWORD</span> <span class="s1">'QZrRP-fzuq'</span><span class="p">;</span>
<span class="k">CREATE</span> <span class="n">USER</span> <span class="s1">'app_courier'</span><span class="o">@</span><span class="s1">'localhost'</span> <span class="n">IDENTIFIED</span> <span class="k">BY</span> <span class="n">PASSWORD</span> <span class="s1">'OQ5JQ3+pNR'</span><span class="p">;</span>
<span class="k">CREATE</span> <span class="n">USER</span> <span class="s1">'app_sasl'</span><span class="o">@</span><span class="s1">'localhost'</span> <span class="n">IDENTIFIED</span> <span class="k">BY</span> <span class="n">PASSWORD</span> <span class="s1">'hb9mwJGcc'</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">SELECT</span> <span class="k">ON</span> <span class="n">email</span><span class="p">.</span><span class="n">users</span> <span class="k">TO</span> <span class="s1">'app_postfix'</span><span class="o">@</span><span class="s1">'localhost'</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">SELECT</span> <span class="k">ON</span> <span class="n">email</span><span class="p">.</span><span class="n">users</span> <span class="k">TO</span> <span class="s1">'app_courier'</span><span class="o">@</span><span class="s1">'localhost'</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">SELECT</span> <span class="k">ON</span> <span class="n">email</span><span class="p">.</span><span class="n">users</span> <span class="k">TO</span> <span class="s1">'app_sasl'</span><span class="o">@</span><span class="s1">'localhost'</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">SELECT</span> <span class="k">ON</span> <span class="n">email</span><span class="p">.</span><span class="n">users_aliases</span> <span class="k">TO</span> <span class="s1">'app_postfix'</span><span class="o">@</span><span class="s1">'localhost'</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">SELECT</span> <span class="k">ON</span> <span class="n">email</span><span class="p">.</span><span class="n">users_aliases</span> <span class="k">TO</span> <span class="s1">'app_courier'</span><span class="o">@</span><span class="s1">'localhost'</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">SELECT</span> <span class="k">ON</span> <span class="n">email</span><span class="p">.</span><span class="n">users_aliases</span> <span class="k">TO</span> <span class="s1">'app_sasl'</span><span class="o">@</span><span class="s1">'localhost'</span><span class="p">;</span>
<span class="k">FLUSH</span> <span class="n">PRIVILEGES</span><span class="p">;</span>
</code></pre></div>
<p>En el caso de PostgreSQL, es necesario especificar en su archivo de configuración de accesos <code>pg_hba.conf</code> habilitemos el acceso de los 3 usuarios que acabamos de crear.</p>
<p>Editamos el archivo y especificamos que estos 3 últimos usuarios pueden conectarse a la base de datos <code>email</code> para leer. <strong>Repito: únicamente en el caso de PostgreSQL. Si estamos configurando el servidor únicamente para MySQL, entonces NO hay que hacer esto</strong>:</p>
<div class="highlight"><pre><span></span><code>#
# Database administrative login by Unix domain socket
local all postgres peer
# TYPE DATABASE USER ADDRESS METHOD
host email app_postfix 127.0.0.1/32 md5
host email app_courier 127.0.0.1/32 md5
host email app_sasl 127.0.0.1/32 md5
# "local" is for Unix domain socket connections only
local all all peer
# IPv4 local connections:
host all all 127.0.0.1/32 md5
# IPv6 local connections:
host all all ::1/128 md5
# Allow replication connections from localhost, by a user with the
# replication privilege.
#local replication postgres peer
#host replication postgres 127.0.0.1/32 md5
#host replication postgres ::1/128 md5
</code></pre></div>
<p>Por último, comprobamos que podemos conectarnos a las tablas de nuestra base de datos, que en el caso de <strong>PostgreSQL</strong> se hace así:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> psql -h <span class="m">127</span>.0.0.1 -U app_postfix -W --command<span class="o">=</span><span class="s1">'SELECT COUNT(*) FROM users;'</span> email
<span class="go"> count</span>
<span class="go">-------</span>
<span class="go"> 0</span>
<span class="go">(1 row)</span>
</code></pre></div>
<p>Y en el caso de <strong>MySQL</strong> se hace así:</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">echo</span> <span class="s2">"SELECT COUNT(*) FROM users;"</span> <span class="p">|</span> mysql -h <span class="m">127</span>.0.0.1 -u app_postfix -p email
COUNT<span class="o">(</span>*<span class="o">)</span>
<span class="m">0</span>
</code></pre></div>
<p>Al ejecutar estos últimos comandos se os pedirá la contraseña del usuario que vayáis a probar (en éste caso el usuario es <code>app_postfix</code>). Una vez introducida debería ejecutarse la <em>query</em> correctamente... si por el contrario obtenéis algun mensaje de error, seguramente se deba a problemas con los permisos de los usuarios. Échale un ojo a lo que has ido haciendo, averigua en qué punto <em>la has cagado</em> y arréglalo... xDDD</p>
<p>Si todo ha ido bien, ésta parte ya la hemos acabado... ahora solo nos quedaría insertar un usuario para probar, y también algun alias. Es importante recordar que <strong>conviene insertar un registro en la tabla de <em>aliases</em> que contenga la propia dirección local del usuario que estamos creando</strong> (es decir, un alias de si mismo, aparte de los demás alias que vayamos a configurar para ese usuario) ya que en algunas circunstancias Postfix únicamente consulta la existencia de un usuario mirando en la tabla de <em>aliases</em>, por lo que si no tenemos un registro ahí que especifique la dirección <em>normal</em> del usuario, Postfix no lo encontrará y pensará que dicho usuario no existe, aunque sí que exista en la tablas <em>users</em>.</p>
<p>La password del usuario tiene que ir cifrada por motivos obvios de seguridad, para que nadie (incluso quien pudiera tener acceso a consultar la tabla en la que se almacena) pudiera verla.</p>
<p>El algoritmo de encriptación que vamos a usar es el mismo que utiliza <a href="https://es.wikipedia.org/wiki/GNU/Linux">GNU/Linux</a> para almacenar las contraseñas de los usuarios del sistema, y que si no me equivoco, es el utilizado en la función <em>CRYPT</em> mediante el algoritmo <a href="https://es.wikipedia.org/wiki/Data_Encryption_Standard">DES</a>.</p>
<p>Pero no os preocupéis si no estáis muy puestos en <em>criptografía</em>... existe un comando que os permitirá generar el <em><a href="https://es.wikipedia.org/wiki/Funci%C3%B3n_hash">hash</a></em> de la contraseña que queráis utilizando diferentes algoritmos. Éste comando se llama <code>authpasswd</code> y forma parte del paquete <code>courier-authlib</code>, por lo que debemos instalarlo.</p>
<p>De nuevo, si usamos <strong>Debian/Ubuntu</strong>, basta con:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install courier-authlib
</code></pre></div>
<p>Y si usamos <strong>CentOS/RedHat</strong>, me temo que estos paquetes no forman parte de sus repositorios oficiales, por lo que tendríais que compilar el código vosotros mismos. Si es vuestro caso, podéis bajarlo desde aquí: http://www.courier-mta.org/download.htmls</p>
<p>En cualquier caso, una vez que tengáis el paquete <code>courier-authlib</code> instalado, y por tanto el comando <code>authpasswd</code> disponible, solo tenéis que ejecutarlo especificando el algoritmo <em>CRYPT</em> y después de introducir la password que queráis. Eso os devolverá el <em>hash</em> correspondiente a dicha password, que por ejemplo, en el usuario de prueba que vamos a crear ésta password va a ser <code>galactica</code> :</p>
<div class="highlight"><pre><span></span><code>$ authpasswd crypt
Password:
Reenter password:
<span class="o">{</span>CRYPT<span class="o">}</span>V1TBTcBUTkibk
</code></pre></div>
<p>Por lo tanto, la password encriptada de <em>galactica</em> es <strong>V1TBTcBUTkibk</strong>.</p>
<p>Con éstas <em>querys</em> deberíamos ser capaces de insertar un usuario de prueba con 1 alias y con la password cifrada en nuestra recién creada base de datos:</p>
<div class="highlight"><pre><span></span><code><span class="c1">-- Insertamos el usuario</span>
<span class="k">INSERT</span> <span class="k">INTO</span>
<span class="n">users</span>
<span class="p">(</span>
<span class="k">name</span><span class="p">,</span>
<span class="n">surname</span><span class="p">,</span>
<span class="n">login</span><span class="p">,</span>
<span class="n">password_crypt</span><span class="p">,</span>
<span class="n">email_local</span><span class="p">,</span>
<span class="n">description</span><span class="p">,</span>
<span class="n">imap_access</span><span class="p">,</span>
<span class="n">smtp_access</span><span class="p">,</span>
<span class="n">path_maildir</span><span class="p">,</span>
<span class="n">user_active</span>
<span class="p">)</span>
<span class="k">VALUES</span>
<span class="p">(</span>
<span class="s1">'William'</span><span class="p">,</span>
<span class="s1">'Adama'</span><span class="p">,</span>
<span class="s1">'bill'</span><span class="p">,</span>
<span class="s1">'V1TBTcBUTkibk'</span><span class="p">,</span>
<span class="s1">'adama@pornohardware.com'</span><span class="p">,</span>
<span class="s1">'Email del Comandante Adama'</span><span class="p">,</span>
<span class="mf">1</span><span class="p">,</span>
<span class="mf">1</span><span class="p">,</span>
<span class="s1">'/srv/maildirs/pornohardware.com/adama/'</span><span class="p">,</span>
<span class="mf">1</span>
<span class="p">);</span>
<span class="c1">-- Insertamos el alias de si mismo</span>
<span class="k">INSERT</span> <span class="k">INTO</span>
<span class="n">users_aliases</span>
<span class="p">(</span>
<span class="n">email_local</span><span class="p">,</span>
<span class="n">email_alias</span>
<span class="p">)</span>
<span class="k">VALUES</span>
<span class="p">(</span>
<span class="s1">'adama@pornohardware.com'</span><span class="p">,</span>
<span class="s1">'adama@pornohardware.com'</span>
<span class="p">);</span>
<span class="c1">-- Insertamos un alias para el usuario</span>
<span class="k">INSERT</span> <span class="k">INTO</span>
<span class="n">users_aliases</span>
<span class="p">(</span>
<span class="n">email_local</span><span class="p">,</span>
<span class="n">email_alias</span>
<span class="p">)</span>
<span class="k">VALUES</span>
<span class="p">(</span>
<span class="s1">'adama@pornohardware.com'</span><span class="p">,</span>
<span class="s1">'william.adama@pornohardware.com'</span>
<span class="p">);</span>
</code></pre></div>
<p>Una vez ejecutados estos <code>INSERT</code> ya tendremos configurado nuestro usuario con sus alias, así que ahora vamos a ver cómo los utilizamos...</p>
<h2>Instalación de Postfix como servidor SMTP<a name="postfix"></a></h2>
<p>Ahora que ya tenemos la base de datos creada y nuestro primer usuario de prueba guardado en ella, vamos a preparar un servidor SMTP para que cuando le llegue un email para nuestro usuario, sepa que efectivamente es para él y lo guarde en su <em>mailbox</em> para que éste pueda leerlo cuando quiera.</p>
<p><img class="left" src="/images/logos/logo_postfix.png">
Como ya comenté anteriormente, el SMTP que utilizo normalmente es <a href="http://www.postfix.org/">Postfix</a>.</p>
<p>No es perfecto, pero en mi opinión es el mejor SMTP que hay hoy en día, aunque como en casi todo hay varios bandos <em>enfrentados</em> (en éste caso el otro bando son los defensores de <a href="http://exim.org/">Exim</a>, otro gran SMTP).</p>
<p>Hay que tener claro de antemano que la tarea de configurar un servidor SMTP se divide en 2 subtareas:</p>
<ul>
<li>Configurar el servidor para que nuestros usuarios puedan enviar emails a otras personas.</li>
<li>Configurar el servidor para que cuando le llegue un email a uno de nuestros usuarios, éste lo guarde para que el usuario pueda leerlo.</li>
</ul>
<p>Quiero que quede clara la división porque aunque sea Postfix quien se encargue de ambas, son 2 procesos diferentes.</p>
<p>Vamos con la primera...</p>
<p>Un servidor SMTP es un servicio que corre normalmente <strong>en el puerto 25</strong> (y/o en el <strong>puerto 465</strong> si nos conectamos a través de <a href="https://es.wikipedia.org/wiki/Transport_Layer_Security">SSL</a>).</p>
<p>Esto significa que cuando queramos enviar un email, debemos conectarnos a éste servidor y mediante <a href="https://es.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#Resumen_simple_del_funcionamiento_del_protocolo_SMTP">los comandos propios de su protocolo</a> debemos indicar quienes somos, a quién queremos enviar el email, con qué texto queremos enviarlo, etc. y si lo hemos hecho bien, nuestro servidor enviará dicho email al SMTP del destinatario (como ya dije en el <a href="#mailprocess">esquema de funcionamiento del correo que puse arriba</a>).</p>
<p>Sin embargo, el SMTP no puede estar <em>abierto a cualquiera</em> (situación conocida como <em>open relay</em>), ya que entonces los <a href="https://es.wikipedia.org/wiki/Spam">spammers</a> lo utilizarán para enviar emails publicitarios o de cualquier otro tipo a todo el mundo, lo que aparte de generar numerosos problemas, podría hacer que la IP de nuestro servidor de correo fuera incluida en alguna base de datos pública de <em>spammers</em>, lo que provocaría que la mayor parte de los servidores de correo del mundo rehusaran recibir nuestros emails (aunque éstos fueran emails legítimos enviados normalmente por nosotros).</p>
<p>Únicamente nuestros usuarios (aquellos que mediante su <em>login</em> y <em>password</em> se autentiquen satisfactoriamente) debería tener permisos para poder enviar emails a través de este SMTP.</p>
<p><strong>El SPAM es una lacra</strong>, y no solo es molesto, sino que puede llegar a causar problemas de verdad... así que, por favor, pon especial atención a proteger tu servidor para que ésta panda de desgraciados no pueda servirse de él.</p>
<p>Así que debemos configurar Postfix para que únicamente acepte emails de los usuarios que se autentiquen. Como estos usuarios los tenemos en una base de datos, vamos a configurar Postfix para que se conecte a ella y los busque.</p>
<p>Lo primero es instalar los paquetes de Postfix según la base de datos que estemos usando (ya sea MySQL o PostgreSQL).
Y como siempre, esta instalación es trivial si usamos una distribución de GNU/Linux decente como por ejemplo <a href="http://www.debian.org">Debian</a>. En éste caso (o en el de las que se basan en ella, como por ejemplo <a href="http://www.ubuntu.com">Ubuntu</a>), bastaría con:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install postfix postfix-mysql postfix-pgsql
</code></pre></div>
<p>Si por algun motivo (por ejemplo, que seamos masoquistas) utilizamos <a href="https://www.centos.org/">CentOS</a>, <a href="http://www.redhat.com/es">Redhat</a> o similares, podemos instalarlo también de forma muy fácil con:</p>
<div class="highlight"><pre><span></span><code>$ sudo yum install postfix
</code></pre></div>
<p>Ahora que ya lo tenemos instalado vamos a configurarlo. Los 2 archivos de configuración principal de Postfix son <code>master.cf</code> y <code>main.cf</code> (ambos en el directorio <code>/etc/postfix</code>).</p>
<p>En el primero de ellos (<code>/etc/postfix/master.cf</code>) se especifican las opciones del proceso demonio de nuestro servidor SMTP, tales como filtros, configuración de <em><a href="https://es.wikipedia.org/wiki/Chroot">chroot</a></em>, etc. Es normal que las primeras veces que se examina éste archivo puede parecer algo <em>complejo</em> de manejar... pero al final es tan simple como el resto de Postfix.</p>
<p>Un ejemplo de éste archivo podría ser el siguiente:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">/etc/postfix/master.cf</span><a href='/files/mailserver_postfix-master.cf'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="c1"># Postfix master process configuration file. For details on the format</span>
<span class="c1"># of the file, see the master(5) manual page (command: "man 5 master").</span>
<span class="c1">#</span>
<span class="c1"># ==========================================================================</span>
<span class="c1"># service type private unpriv chroot wakeup maxproc command + args</span>
<span class="c1"># (yes) (yes) (yes) (never) (100)</span>
<span class="c1"># ==========================================================================</span>
smtp inet n - n - - smtpd
<span class="c1">#submission inet n - - - - smtpd</span>
<span class="c1"># -o smtpd_tls_security_level=encrypt</span>
<span class="c1"># -o smtpd_sasl_auth_enable=yes</span>
<span class="c1"># -o smtpd_client_restrictions=permit_sasl_authenticated,reject</span>
<span class="c1"># -o milter_macro_daemon_name=ORIGINATING</span>
smtps inet n - n - - smtpd
-o <span class="nv">smtpd_tls_wrappermode</span><span class="o">=</span>yes
-o <span class="nv">smtpd_sasl_auth_enable</span><span class="o">=</span>yes
-o <span class="nv">smtpd_client_restrictions</span><span class="o">=</span>permit_sasl_authenticated,reject
-o <span class="nv">milter_macro_daemon_name</span><span class="o">=</span>ORIGINATING
<span class="c1">#628 inet n - - - - qmqpd</span>
pickup fifo n - - <span class="m">60</span> <span class="m">1</span> pickup
cleanup unix n - - - <span class="m">0</span> cleanup
qmgr fifo n - n <span class="m">300</span> <span class="m">1</span> qmgr
<span class="c1">#qmgr fifo n - - 300 1 oqmgr</span>
tlsmgr unix - - - <span class="m">1000</span>? <span class="m">1</span> tlsmgr
rewrite unix - - - - - trivial-rewrite
bounce unix - - - - <span class="m">0</span> bounce
defer unix - - - - <span class="m">0</span> bounce
trace unix - - - - <span class="m">0</span> bounce
verify unix - - - - <span class="m">1</span> verify
flush unix n - - <span class="m">1000</span>? <span class="m">0</span> flush
proxymap unix - - n - - proxymap
<span class="c1">#proxywrite unix - - n - 1 proxymap</span>
smtp unix - - - - - smtp
<span class="c1"># When relaying mail as backup MX, disable fallback_relay to avoid MX loops</span>
relay unix - - - - - smtp
-o <span class="nv">smtp_fallback_relay</span><span class="o">=</span>
<span class="c1"># -o smtp_helo_timeout=5 -o smtp_connect_timeout=5</span>
showq unix n - - - - showq
error unix - - - - - error
retry unix - - - - - error
discard unix - - - - - discard
<span class="nb">local</span> unix - n n - - <span class="nb">local</span>
virtual unix - n n - - virtual
lmtp unix - - - - - lmtp
anvil unix - - - - <span class="m">1</span> anvil
scache unix - - - - <span class="m">1</span> scache
<span class="c1">#</span>
<span class="c1"># ====================================================================</span>
<span class="c1"># Interfaces to non-Postfix software. Be sure to examine the manual</span>
<span class="c1"># pages of the non-Postfix software to find out what options it wants.</span>
<span class="c1">#</span>
<span class="c1"># Many of the following services use the Postfix pipe(8) delivery</span>
<span class="c1"># agent. See the pipe(8) man page for information about ${recipient}</span>
<span class="c1"># and other message envelope options.</span>
<span class="c1"># ====================================================================</span>
<span class="c1">#</span>
<span class="c1"># maildrop. See the Postfix MAILDROP_README file for details.</span>
<span class="c1"># Also specify in main.cf: maildrop_destination_recipient_limit=1</span>
<span class="c1">#</span>
maildrop unix - n n - - pipe
<span class="nv">flags</span><span class="o">=</span>DRhu <span class="nv">user</span><span class="o">=</span>vmail <span class="nv">argv</span><span class="o">=</span>/usr/bin/maildrop -d <span class="si">${</span><span class="nv">recipient</span><span class="si">}</span>
<span class="c1">#</span>
<span class="c1"># See the Postfix UUCP_README file for configuration details.</span>
<span class="c1">#</span>
uucp unix - n n - - pipe
<span class="nv">flags</span><span class="o">=</span>Fqhu <span class="nv">user</span><span class="o">=</span>uucp <span class="nv">argv</span><span class="o">=</span>uux -r -n -z -a<span class="nv">$sender</span> - <span class="nv">$nexthop</span>!rmail <span class="o">(</span><span class="nv">$recipient</span><span class="o">)</span>
<span class="c1">#</span>
<span class="c1"># Other external delivery methods.</span>
<span class="c1">#</span>
ifmail unix - n n - - pipe
<span class="nv">flags</span><span class="o">=</span>F <span class="nv">user</span><span class="o">=</span>ftn <span class="nv">argv</span><span class="o">=</span>/usr/lib/ifmail/ifmail -r <span class="nv">$nexthop</span> <span class="o">(</span><span class="nv">$recipient</span><span class="o">)</span>
bsmtp unix - n n - - pipe
<span class="nv">flags</span><span class="o">=</span>Fq. <span class="nv">user</span><span class="o">=</span>bsmtp <span class="nv">argv</span><span class="o">=</span>/usr/lib/bsmtp/bsmtp -t<span class="nv">$nexthop</span> -f<span class="nv">$sender</span> <span class="nv">$recipient</span>
mailman unix - n n - - pipe
<span class="nv">flags</span><span class="o">=</span>FR <span class="nv">user</span><span class="o">=</span>list <span class="nv">argv</span><span class="o">=</span>/usr/lib/mailman/bin/postfix-to-mailman.py
<span class="si">${</span><span class="nv">nexthop</span><span class="si">}</span> <span class="si">${</span><span class="nv">user</span><span class="si">}</span>
scalemail-backend unix - n n - <span class="m">2</span> pipe
<span class="nv">flags</span><span class="o">=</span>R <span class="nv">user</span><span class="o">=</span>scalemail <span class="nv">argv</span><span class="o">=</span>/usr/lib/scalemail/bin/scalemail-store <span class="si">${</span><span class="nv">nexthop</span><span class="si">}</span> <span class="si">${</span><span class="nv">user</span><span class="si">}</span> <span class="si">${</span><span class="nv">extension</span><span class="si">}</span>
smtp-amavis unix - - n - <span class="m">2</span> smtp
-o <span class="nv">smtp_data_done_timeout</span><span class="o">=</span><span class="m">1200</span>
-o <span class="nv">disable_dns_lookups</span><span class="o">=</span>yes
<span class="c1"># Amavis filter</span>
<span class="m">127</span>.0.0.1:10025 inet n - - - - smtpd
-o <span class="nv">content_filter</span><span class="o">=</span>
-o <span class="nv">local_recipient_maps</span><span class="o">=</span>
-o <span class="nv">relay_recipient_maps</span><span class="o">=</span>
-o <span class="nv">smtpd_restriction_classes</span><span class="o">=</span>
-o <span class="nv">smtpd_client_restrictions</span><span class="o">=</span>
-o <span class="nv">smtpd_helo_restrictions</span><span class="o">=</span>
-o <span class="nv">smtpd_sender_restrictions</span><span class="o">=</span>
-o <span class="nv">smtpd_recipient_restrictions</span><span class="o">=</span>permit_mynetworks,reject
-o <span class="nv">mynetworks</span><span class="o">=</span><span class="m">127</span>.0.0.0/8
-o <span class="nv">strict_rfc821_envelopes</span><span class="o">=</span>yes
-o <span class="nv">smtpd_sasl_auth_enable</span><span class="o">=</span>yes
</code></pre></div>
</figure>
<p>La estructura del archivo es sencilla: se empieza con el nombre del <em>servicio</em> que estamos configurando, seguido de <code>-</code> o <code>n</code> dependiendo de si queremos activar o desactivar las diferentes funcionalidades (cada <em>columna</em> del archivo corresponde a una funcionalidad), y en la línea siguiente se especifican las diferentes opciones que pudiera tener el servicio.</p>
<p>La primera línea que debemos modificar es la 8, que corresponde al servicio <code>smtp</code>.
En ella debemos desactivar el <em><a href="https://es.wikipedia.org/wiki/Chroot">chroot</a></em>, aunque si bien no lo recomiendo, es posible instalarlo utilizando la jaula del chroot (de hecho, el resultado sería mucho más seguro), pero la complejidad del sistema aumenta tantísimo que personalmente no creo que sea necesario.</p>
<p>Ten en cuenta que ahora estamos únicamente configurando Postfix, pero cuando termines de leer éste artículo tendremos un sistema de correo en el que además de él habrá muchos otros servicios que deben <em>interactuar</em>, y tener a Postfix <em>encerrado</em> en un chroot dificultaría las cosas muchísimo. Hay muchas otras formas de proteger el sistema... pero obviamente esto es solo una recomendación mía. Si eres el <em>sysadmin</em> de la NSA y estás montando el Postfix personal de Obama en el mismo servidor en el que él guarda sus fotos más comprometidas, quizás sí que sería buena idea que dejaras el <em>chroot</em> activado... xDDD</p>
<p>Lo mismo haremos con la linea 14, que corresponde al servicio <code>smtps</code> (es decir, el servicio a través del protocolo seguro <a href="https://es.wikipedia.org/wiki/Transport_Layer_Security">SSL</a>): descomentamos las lineas (si es que estaban comentadas) y desactivamos el <em>chroot</em>. Más adelante ya hablaremos de cómo utilizar el SSL en todos los servicios de nuestro servidor de correo.</p>
<p>Si te fijas en las líneas que van de la 74 a la 76 y las que van de la 79 a la 94 del archivo <code>master.cf</code> que he puesto de ejemplo, verás que se trata de la configuración de 2 filtros: uno llamado <code>mailman</code> y otro llamado <code>smtp-amavis</code>. Pero de momento no te preocupes por esto, no lo configures aún... ya hablaremos de estos servicios cuando tengamos el resto terminado...</p>
<p>Una vez terminado <code>master.cf</code> (al menos de momento), si abrimos el otro archivo de configuración <code>/etc/postfix/main.cf</code> nos encontraremos todas las directivas que vienen <em>preconfiguradas</em> por defecto. Podéis echarle un ojo para familiarizaros con el archivo y con sus directivas, la mayoría de ellas tienen un nombre bastante descriptivo.</p>
<p>Un ejemplo de éste archivo (remarcando las directivas más relevantes) sería algo así:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">/etc/postfix/main.cf</span><a href='/files/mailserver_postfix-main.cf'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="c1"># Debian specific: Specifying a file name will cause the first</span>
<span class="c1"># line of that file to be used as the name. The Debian default</span>
<span class="c1"># is /etc/mailname.</span>
<span class="nv">myorigin</span> <span class="o">=</span> <span class="s2">"pornohardware.com"</span>
<span class="nv">smtpd_banner</span> <span class="o">=</span> <span class="nv">$myhostname</span> ESMTP <span class="nv">$mail_name</span> <span class="o">(</span>Debian/GNU<span class="o">)</span>
<span class="nv">biff</span> <span class="o">=</span> no
<span class="c1"># appending .domain is the MUA's job.</span>
<span class="nv">append_dot_mydomain</span> <span class="o">=</span> no
<span class="c1"># Uncomment the next line to generate "delayed mail" warnings</span>
<span class="nv">delay_warning_time</span> <span class="o">=</span> 4h
<span class="c1"># TLS parameters</span>
<span class="nv">smtpd_tls_cert_file</span><span class="o">=</span>/srv/sites/conf/ssl/mail.pornohardware.com.crt
<span class="nv">smtpd_tls_key_file</span><span class="o">=</span>/srv/sites/conf/ssl/mail.pornohardware.com.key
<span class="nv">smtpd_use_tls</span> <span class="o">=</span> yes
<span class="nv">smtpd_tls_session_cache_database</span> <span class="o">=</span> btree:<span class="si">${</span><span class="nv">data_directory</span><span class="si">}</span>/smtpd_scache
<span class="nv">smtp_tls_session_cache_database</span> <span class="o">=</span> btree:<span class="si">${</span><span class="nv">data_directory</span><span class="si">}</span>/smtp_scache
<span class="c1"># See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for</span>
<span class="c1"># information on enabling SSL in the smtp client.</span>
<span class="nv">myhostname</span> <span class="o">=</span> pornohardware.com
<span class="nv">mydomain</span> <span class="o">=</span> pornohardware.com
<span class="nv">alias_maps</span> <span class="o">=</span> hash:/etc/aliases
<span class="nv">alias_database</span> <span class="o">=</span> hash:/etc/aliases
<span class="nv">mydestination</span> <span class="o">=</span> pornohardware.com
<span class="nv">relay_domains</span> <span class="o">=</span> <span class="nv">$mydestination</span>,
pornosoftware.com
<span class="nv">mynetworks</span> <span class="o">=</span> <span class="m">127</span>.0.0.0/8, <span class="m">188</span>.165.118.8
<span class="nv">mailbox_command</span> <span class="o">=</span> procmail -a <span class="s2">"</span><span class="nv">$EXTENSION</span><span class="s2">"</span>
<span class="nv">mailbox_size_limit</span> <span class="o">=</span> <span class="m">0</span>
<span class="nv">recipient_delimiter</span> <span class="o">=</span> +
<span class="nv">inet_interfaces</span> <span class="o">=</span> all
<span class="nv">transport_maps</span> <span class="o">=</span> hash:/etc/postfix/transport
<span class="nv">message_size_limit</span> <span class="o">=</span> <span class="m">25600000</span>
<span class="c1"># MySQL</span>
<span class="nv">virtual_mailbox_base</span> <span class="o">=</span> /
<span class="nv">virtual_uid_maps</span> <span class="o">=</span> static:102
<span class="nv">virtual_gid_maps</span> <span class="o">=</span> static:8
<span class="nv">virtual_mailbox_maps</span> <span class="o">=</span> mysql:/etc/postfix/mysql/mysql_virt.cf
<span class="nv">virtual_maps</span> <span class="o">=</span> mysql:/etc/postfix/mysql/alias.cf
<span class="nv">local_transport</span> <span class="o">=</span> virtual
<span class="c1"># Amavis</span>
<span class="nv">content_filter</span> <span class="o">=</span> smtp-amavis:<span class="o">[</span><span class="m">127</span>.0.0.1<span class="o">]</span>:10024
<span class="c1"># No backscatter</span>
<span class="nv">soft_bounce</span> <span class="o">=</span> no
<span class="nv">unknown_local_recipient_reject_code</span> <span class="o">=</span> <span class="m">550</span>
<span class="c1"># SASL2 Auth</span>
<span class="nv">smtpd_sasl_auth_enable</span> <span class="o">=</span> yes
<span class="nv">smtpd_sasl_security_options</span> <span class="o">=</span> noanonymous
<span class="nv">smtpd_sasl_local_domain</span> <span class="o">=</span> <span class="nv">$myhostname</span>
<span class="nv">broken_sasl_auth_clients</span> <span class="o">=</span> yes
<span class="nv">smtpd_recipient_restrictions</span> <span class="o">=</span> permit_mynetworks,
reject_invalid_hostname,
reject_non_fqdn_sender,
reject_non_fqdn_recipient,
reject_unknown_sender_domain,
reject_unknown_recipient_domain,
permit_sasl_authenticated,
reject_unauth_destination,
<span class="c1"># check_policy_service unix:private/policy,</span>
check_policy_service inet:127.0.0.1:10023,
regexp:/etc/postfix/blacklist,
permit
<span class="nv">maps_rbl_domains</span> <span class="o">=</span> rbl.maps.vix.com,
relays.mail-abuse.org,
relays.ordb.org,
dev.null.dk,
spews.relays.osirusoft.com,
spamhaus.relays.osirusoft.com,
relays.visi.com
</code></pre></div>
</figure>
<h3>Directiva: myorigin, myhostname y mydomain</h3>
<p>La primera de las directivas que tenemos que configurar es <code>myorigin</code> (línea 4 del archivo). Con ésta variable definimos el nombre del dominio por defecto desde el que vamos a enviar los emails.</p>
<p>Por ejemplo, si la configuramos con el valor <em>pornohardware.com</em>, cuando enviemos un email desde ese servidor (desde la línea de comandos, con el usuario <em>root</em>, por ejemplo), el destinatario de dicho email vería como remitente la dirección <em>root@pornohardware.com</em>.</p>
<p>Conviene saber que ésta directiva acepta 2 tipos de valores: o bien el nombre del dominio, o bien la ruta de un archivo que contenga dicho nombre.
Es decir, podemos poner:</p>
<div class="highlight"><pre><span></span><code><span class="nv">myorigin</span> <span class="o">=</span> pornohardware.com
</code></pre></div>
<p>O bien podemos crear un archivo llamado <code>/etc/mailname</code> que únicamente contenga <code>pornohardware.com</code>, y configurar la directiva así:</p>
<div class="highlight"><pre><span></span><code><span class="nv">myorigin</span> <span class="o">=</span> /etc/mailname
</code></pre></div>
<p>Ambos casos sería iguales, así que hacerlo como más o guste. Personalmente prefiero el primer caso por facilidad y simplicidad, así la configuración está en un único archivo en lugar de en varios, pero hasta que me alce como vuestro Líder en un <a href="https://es.wikipedia.org/wiki/Nuevo_Orden_Mundial_%28conspiraci%C3%B3n%29">Nuevo Orden Mundial</a>, esto es un <em>mundo libre</em>, por lo que podéis hacerlo como queráis (aunque insisto: solo de momento xDD).</p>
<p>Así mismo, la directiva <code>myhostname</code> (<em>línea 25</em>) especifica el nombre de nuestro servidor (<em>host</em>), y <code>mydomain</code> (<em>línea 26</em>) el nombre del dominio principal (ambas no tienen porqué coincidir, aunque es frecuente que lo hagan).</p>
<h3>Directiva: smtpd_banner</h3>
<p>La directiva <code>smtpd_banner</code> (<em>línea 6</em>) permite definir el texto que nuestro servidor mostrará cuando se establezca una conexión al puerto del SMTP. Normalmente no es algo que el usuario vea, por lo que es indiferente lo que pongamos aquí, pero ten en cuenta que si nos conectamos manualmente (con <code>telnet</code>, por ejemplo) al puerto del SMTP, veremos ese texto... y un atacante podría usar la información que mostremos en él (nombre del servidor SMTP que estamos usando, sistema operativo que tenemos instalado, etc) para recopilar datos sobre nuestro servidor como primer paso a un ataque... pero bueno, eso ya depende de vuestro grado de <em>paranoya</em>. Personalmente no me gusta dar nunca más información de la necesaria, pero no pasa nada porque mostremos el nombre del software de servidor SMTP que estamos usando (<em>Postfi</em>x) ni el sistema operativo (<em>GNU/Linux</em>).</p>
<h3>Directivas: smtpd_tls_key_file y smtpd_use_tls</h3>
<p>Si disponéis de un certificado SSL válido para el servidor de correo que estáis montando, debéis especificar la ruta de los archivos <em>crt</em> y <em>key</em> de dicho certificado. Para eso debéis usar las directivas <code>smtpd_tls_cert_file</code>, <code>smtpd_tls_key_file</code> y <code>smtpd_use_tls</code> (<em>líneas 16 a 20</em>). El uso, generación y firma de certificados SSL escapa al ámbito de éste artículo, así que no lo explicaré ahora (ya escribiré otro artículo explicando esto en cuanto pueda, mientras tanto asumiré que si vas a usar dichas opciones, ya sabes manejar éste tipo de certificados).</p>
<h3>Directivas: alias_maps y alias_database</h3>
<p>Estas directivas (<em>líneas 27 y 28</em>) se utilizan para indicar la relación de alias de los usuarios locales del servidor. Es decir, si queremos evitar (por ejemplo) que el correo que se envíe al usuario <em>root</em> local del sistema se redirija a otro usuario (o a otra dirección), podemos definir un <em>alias</em> para ese usuario, de forma que los correos que se le envíen serán redirigidos al <em>alias</em> automáticamente.</p>
<p>Una recomendadísima práctica en la administración de servidores de correo suele ser la de definir un alias como mínimo al usuario <em>root</em>, de forma que los emails que se le podrían llegar a enviar sean redirigidos a otro usuario. Esto se hace para evitar que alguien pudiera colapsar el servidor llenando el buzón de correo del usuario <em>root</em> con miles de enormes emails (ya que normalmente el usuario <em>root</em> no suele tener establecida una <em>quota</em> de disco, ni un límite de emails, ni ninguna otra restricción).</p>
<p>Postfix utiliza una <em>base de datos</em> propia para almacenar ésta información, y la forma de generar dicha base de datos es mediante el comando <code>newaliases</code>, que convierte el archivo <code>/etc/aliases</code> (texto plano) en <code>/etc/aliases.db</code> (la base de datos que Postfix utiliza). Por lo tanto, nosotros debemos trabajar siempre con <code>/etc/aliases</code>, y una vez modificado, ejecutar de nuevo el comando para convertirlo en el archivo que Postfix espera.</p>
<p>Un ejemplo de <code>/etc/aliases</code> podría ser éste:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-title">/etc/aliases</span><a href='/files/mailserver_postfix-aliases'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="c1"># /etc/aliases</span>
mailer-daemon: postmaster
postmaster: root
nobody: root
hostmaster: root
usenet: root
webmaster: root
www: root
abuse: root
noc: root
security: root
root: fulanito
fulanito: fulanito@dominio.com
</code></pre></div>
</figure>
<p>Según éste archivo, todo el correo enviado al usuario local <em>mailer-daemon</em> se redirigiría al usuario <em>postmaster</em>... y éste a su vez se redirigiría al usuario <em>root</em>.</p>
<p>También se redirigiría al usuario <em>root</em> el correo enviado a <em>nobody</em>, <em>hostmaster</em>, <em>usenet</em>, <em>webmaster</em>, etc..</p>
<p>Finalmente, todo el correo enviado hacia <em>root</em> será redirigido al usuario <em>fulanito</em> (para evitar llena el buzón de <em>root</em>), el cual a su vez será reenviado a la cuenta externa <em>fulanito@dominio.com</em>.</p>
<h3>Directiva: mydestination</h3>
<p>Aquí (<em>línea 29</em>) especificamos los dominios de correo de los que nuestro servidor se va a encargar. Es decir, cuando recibamos un email que vaya a algun usuario de alguno de estos dominios, asumiremos que es nuestro e intentaremos entregárselo al usuario en cuestión (buscándolo en la base de datos que habíamos creado antes, o en el archivo <code>/etc/aliases</code>). Y si recibimos un email dirigido a un dominio que no es uno de los nuestros (es decir, un dominio que NO esté especificado en ésta directiva) buscaremos el servidor de correo que se encarga de los emails de dicho dominio, y se lo pasaremos para que sea él quien trate de entregárselo al destinatario.</p>
<h3>Directiva: relay_domains</h3>
<p>Con ésta directiva (<em>línea 30</em>) podemos decirle a nuestro servidor SMTP una serie de dominios de los cuales SI debe aceptar los emails, aunque dichos dominios NO sean de los que nos encargamos en éste servidor. Es decir, con <code>relay_domains</code> podemos decirle a nuestro Postfix que acepte emails de determinados dominios aunque estos no estén especificados en <code>mydestination</code>. Esto es útil como <em>backup</em> de correo, ya que si disponemos de 2 servidores de correo diferentes, podemos hacer que cada uno tenga configurado al otro en ésta directiva, de forma que si algun día uno de los 2 está fuera de servicio, el otro iría recogiendo el correo del servidor caído, y se los entregaría posteriormente cuando éste volviera a estar disponible. Para esto hay que especificar también éste segundo servidor de correo en el registro MX del DNS del dominio, así como utilizar la directiva <code>transport_maps</code> para indicar el servidor al que entregar todo el correo <em>ajeno</em> que estamos aceptando al usar ésta directiva (ya lo veremos más adelante).</p>
<p>No obstante, <code>relay_domains</code> únicamente se utiliza en instalaciones un poco más <em>avanzadas</em> de lo normal... si lo que estáis configurando es un servidor de correo normal para gestionar los emails de alguno de vuestros dominios, normalmente no os hará falta utilizarla.</p>
<h3>Directiva: mynetworks</h3>
<p>Aquí indicamos las direcciones de red de aquellas máquinas que queremos que nuestro servidor considere como <em>máquinas de nuestra red</em>. Esto es útil sobre todo para indicar el servidor que el envío de correo debe estar autenticado cuando dichos emails proceden de <em>Internet</em> (para que nadie pueda usarnos para enviar SPAM), pero los demás servidores de nuestra red sí que pueden enviar emails sin necesidad de autenticación.</p>
<h3>Directiva: inet_interfaces</h3>
<p>Como su propio nombre indica, aquí podemos especificar en qué interfaces queremos que <em>escuche</em> nuestro servidor SMTP. Normalmente el valor que usaremos será <code>all</code>, ya que lo más habitual es que queramos que el servidor SMTP esté accesible en todos los interfaces de red que haya en nuestro servidor, pero podría darse algun caso en el que nos interese que únicamente podamos conectarnos al servidor SMTP desde <em>localhost</em> o desde un interface de red determinado, ignorando las conexiones desde los demás.</p>
<h3>Directiva: transport_maps</h3>
<p>Como dije antes, para poder utilizar nuestro servidor también como <em>backup</em> del correo de otro dominio es necesario el uso de ésta directiva, pero también se usa para enviar el correo que queramos a un filtro determinado (configurando dicho filtro previamente en <code>master.cf</code>) o para indicar la dirección del servidor SMTP de un dominio concreto de forma manual.</p>
<p>El valor que debemos indicar en ésta directiva es la ruta donde se encuentra el archivo que contiene la información de <em>transporte</em> del correo. Es decir, algo como :</p>
<div class="highlight"><pre><span></span><code><span class="nv">transport_maps</span> <span class="o">=</span> hash:/etc/postfix/transport
</code></pre></div>
<p>El formato de éste archivo es el mismo que con el archivo <code>aliases</code> que expliqué antes. Debemos utilizar el archivo <code>/etc/postfix/transport</code> (en texto plano) para indicar la información que queramos, y una vez modificado y guardado dicho archivo, debemos generar el archivo en el formato que utiliza Postfix... que en éste caso, a diferencia del archivo <code>aliases</code> (que había que ejecutar el comando <code>newaliases</code> para generarlo) se hace mediante el comando <code>postmap</code> de ésta forma:</p>
<div class="highlight"><pre><span></span><code>sudo postmap /etc/postfix/transport
</code></pre></div>
<p>Después de ejecutar ese comando, obtendremos el archivo <code>/etc/postfix/transport.db</code>, que no es más que el archivo <code>transport</code> pero en el formato requerido por Postfix.</p>
<p>Algunos ejemplos de archivo <code>transport</code> que pueden ayudar a entender mejor su funcionamiento podrían ser estos:</p>
<ul>
<li>
<p>Configurar <code>transport</code> para que el correo que llegue para el dominio <code>fulanito.com</code> a nuestro servidor se reenvíe a otro servidor SMTP distinto. Esto se usa normalmente para <em>backup</em> de correo, configurando el DNS del dominio de <code>fulanito.com</code> para que nuestro servidor sea uno de sus servidores de correo (<a href="#dns">añadiéndolo como registro MX</a>) pero indicando un número de prioridad mayor (para que solo envíen mensaje de ese dominio a nuestro servidor cuando el <em>principal</em> esté caído:</p>
<p>Para hacer esto, lo primero sería añadir nuestro servidor al registro DNS de <code>fulanito.com</code>:</p>
<div class="highlight"><pre><span></span><code><span class="err">MX 5 mail.fulanito.com</span>
<span class="err">MX 10 nuestro-servidor.com</span>
</code></pre></div>
<p>Cuando <code>mail.fulanito.com</code> (que como tiene la prioridad más baja, es el servidor de correo principal de ese dominio) no funcione, se enviarán los emails a <code>nuestro-servidor.com</code>, y éste a su vez estará configurado para aceptar los emails que vayan a dicho dominio, pero en lugar de guardarlos en el mailbox del usuario en cuestión, los encolará e irá intentando cada cierto tiempo conectarse a <code>mail.fulanito.com</code> para entregarle dichos emails.</p>
<p>Lo primero sería decirle a nuestro Postfix que aunque nos encarguemos del correo de los dominios especificados en la directiva <code>mydestination</code> del <code>/etc/postfix/main.cf</code> (que en éste caso son los del dominio <code>pornoharware.com</code>), también debe aceptar los correos para los dominios especificados en la directiva <code>relay_domains</code> (que serán los que vayan dirigidos al dominio <code>fulanito.com</code>):</p>
<div class="highlight"><pre><span></span><code><span class="err">mydestination = pornohardware.com</span>
<span class="err">relay_domains = fulanito.com</span>
</code></pre></div>
<p>Y por último, en el archivo <code>transport</code> está la dirección del servidor SMTP que se encarga de esos emails</p>
<div class="highlight"><pre><span></span><code><span class="err">fulanito.com smtp:mail.fulanito.com:25</span>
</code></pre></div>
<p>Con ésta configuración, nuestro servidor de correo será el encargado de gestionar los emails del dominio <code>pornoharware.com</code>, pero también aceptará los que vayan al dominio <code>fulanito.com</code> mientras el servidor principal de éste esté caído. Y a diferencia de los emails que le lleguen a nuestro servidor y que vayan a <code>pornohardware.com</code> (que serán guardados en el mailbox del destinatario en cuestión), los que vayan a <code>fulanito.com</code> los iremos encolando, y tan pronto vuelva a funcionar el servidor principal de ese dominio, le reenviaremos todos los que hayamos encolado hasta ese momento, de forma que no se habrá perdido ningún email durante el tiempo que su servidor estuvo caído.</p>
</li>
<li>
<p>Configurar <code>transport</code> para que el correo que llegue a un dominio entero y a una dirección concreta, sean enviados a un script en Perl (para que éste haga lo que sea con ellos). Éste script lo habremos configurado previamente en el archivo <code>master.cf</code> de la siguiente forma:</p>
<div class="highlight"><pre><span></span><code><span class="err">filtro_script unix - n n - - pipe</span>
<span class="err"> flags=B user=nobody argv=/usr/bin/perl /opt/scripts/parse_emails.pl</span>
</code></pre></div>
<p>Con esas 2 lineas habremos configurado un <em>filtro</em> llamado <code>filtro_script</code>, que enviará el contenido del email mediante <a href="https://es.wikipedia.org/wiki/Tuber%C3%ADa_%28inform%C3%A1tica%29">pipe</a> al comando especificado en el parámetro <code>argv</code>.</p>
<p>Ahora debemos indicar en el archivo <code>transport</code> qué emails son los que deben pasar por ese filtro:</p>
<div class="highlight"><pre><span></span><code><span class="err">admin@fulanito.com filtro_script:</span>
<span class="err">menganito.com filtro_script:</span>
</code></pre></div>
<p>Con ésta configuración (y una vez generado el archivo <code>transport.db</code> con el comando <code>postmap</code> como expliqué antes) nuestro servidor reenviaría al script que habíamos configurado en <code>master.cf</code> con el nombre de <code>filtro_script</code> aquellos emails cuyo destinatario sea la dirección <code>admin@fulanito.com</code> y cualquier dirección del dominio <code>menganito.com</code>.</p>
</li>
</ul>
<h3>Directiva: message_size_limit</h3>
<p>Esta directiva es muy fácil: como su propio nombre indica, especifica el tamaño máximo que podrán tener los emails que manejará nuestro servidor Postfix.</p>
<p>El valor debe ir en <em>bytes</em>, por lo que si queremos establecer un tamaño máximo de archivo de 25Mb(que para mi es el límite máximo que debería permitirse, ya que <strong>para archivos más grandes no deberíamos utilizar el email</strong>), debemos multiplicar <code>25 * 1024000</code>, es decir:</p>
<div class="highlight"><pre><span></span><code><span class="nv">message_size_limit</span> <span class="o">=</span> <span class="m">25600000</span>
</code></pre></div>
<h3>Directivas: virtual_*</h3>
<p>Aquí viene <em>lo bueno</em>...</p>
<p>Estas directivas son las que van a permitir a Postfix conectarse a nuestra base de datos para comprobar la existencia de los usuarios a los que van dirigidos los emails que recibamos.</p>
<p>Cada vez que nuestro Postfix reciba un email dirigido a una dirección de correo de uno de los dominios de los que él se hace cargo (los especificados en la directiva <code>mydestination</code>) se conectará a la base de datos que indiquemos aquí para comprobar que dicho destinatario existe, y en caso afirmativo, de cuál es el mailbox (directorio del disco del servidor) donde tiene que almacenar dicho email.</p>
<p>Las directivas principales son:</p>
<ul>
<li><strong>virtual_mailbox_base</strong>: La <em>base</em> de la ruta física en el disco duro del servidor donde están los <em>mailbox</em> de cada usuario. El valor más indicado es <code>/</code>, ya que la ruta de cada mailbox la especificaremos en la base de datos, segun sea un usuario u otro.</li>
<li><strong>virtual_uid_maps</strong>: El <a href="https://es.wikipedia.org/wiki/Identificador_de_usuario">uid</a> del usuario que ejecuta el demonio de Postfix. Normalmente es el usuario <em>postfix</em>, y su <em>uid</em> se puede ver con el comando <code>vipw</code>. Si éste valor fuera por ejemplo el 102, el valor que habría que configurar para ésta directiva sería <code>static:102</code>.</li>
<li><strong>virtual_gid_maps</strong>: Igual que el valor anterior, pero ésta vez en lugar del <em>uid</em> hace referencia al <a href="https://es.wikipedia.org/wiki/Identificador_de_grupo">gid</a> del grupo <em>mail</em>. Éste valor se puede ver con el comando <code>vigr</code>, y si dicho valor fuera por ejemplo el 8, el valor que habría que configurar para ésta directiva sería: <code>static:8</code>.</li>
<li><strong>virtual_mailbox_maps</strong>: Aquí vamos a indicar la ruta física del mailbox del usuario, que como en nuestro caso está en la base de datos, hay que crear un archivo de texto plano con la configuración necesaria para que Postfix pueda conectarse a dicha base de datos. Por lo tanto, el valor que pondremos en ésta directiva será <code>pgsql:/etc/postfix/db/users.cf</code> o <code>mysql:/etc/postfix/mysql/users.cf</code> (después crearemos dicho archivo).</li>
<li><strong>virtual_maps</strong>: En ésta directiva podemos configurar dónde debe Postfix buscar los posibles <em>alias</em> del usuario que esté buscando, y dado que en nuestro caso ésta información está también en la base de datos, hay que crear un archivo de texto plano con la configuración necesaria para que Postfix pueda conectarse a dicha base de datos. Por lo tanto, el valor que pondremos en ésta directiva será <code>mysql:/etc/postfix/db/alias.cf</code> o <code>pgsql:/etc/postfix/db/alias.cf</code> (después crearemos éste archivo también).</li>
</ul>
<p>A modo de resumen, la configuración de éstas directivas sería algo así:</p>
<p>Para <strong>PostgreSQL</strong>:</p>
<div class="highlight"><pre><span></span><code><span class="nv">virtual_mailbox_base</span> <span class="o">=</span> /
<span class="nv">virtual_uid_maps</span> <span class="o">=</span> static:102
<span class="nv">virtual_gid_maps</span> <span class="o">=</span> static:8
<span class="nv">virtual_mailbox_maps</span> <span class="o">=</span> pgsql:/etc/postfix/db/users.cf
<span class="nv">virtual_maps</span> <span class="o">=</span> pgsql:/etc/postfix/db/aliases.cf
</code></pre></div>
<p>Para <strong>MySQL</strong>:</p>
<div class="highlight"><pre><span></span><code><span class="nv">virtual_mailbox_base</span> <span class="o">=</span> /
<span class="nv">virtual_uid_maps</span> <span class="o">=</span> static:102
<span class="nv">virtual_gid_maps</span> <span class="o">=</span> static:8
<span class="nv">virtual_mailbox_maps</span> <span class="o">=</span> mysql:/etc/postfix/db/users.cf
<span class="nv">virtual_maps</span> <span class="o">=</span> mysql:/etc/postfix/db/aliases.cf
</code></pre></div>
<p>Como veis, únicamente se diferencian en las lineas que están resaltadas (lineas 45 y 46), a la hora de especificar qué tipo de base de datos vamos a usar (PostgreSQL o MySQL).</p>
<p>Y en esos archivos (<code>/etc/postfix/db/users.cf</code> y <code>/etc/postfix/db/aliases.cf</code>) únicamente tenemos que especificar la base de datos a la que Postfix tiene que conectarse para buscar los usuarios y sus alias, el nombre de las tablas, la <em>query</em> SQL que necesitamos para obtener los datos que queremos, etc.</p>
<p>Por lo tanto, dichos archivos (según la base de datos de usuarios que habíamos creado antes) serían algo así:</p>
<p>Para <strong>PostgreSQL</strong>:</p>
<div class="highlight"><pre><span></span><code><span class="c1"># Configuracion de Postfix para obtener los datos de los</span>
<span class="c1"># usuarios virtuales que hay en la base de datos</span>
<span class="c1">#</span>
<span class="nv">hosts</span> <span class="o">=</span> localhost
<span class="nv">user</span> <span class="o">=</span> app_postfix
<span class="nv">password</span> <span class="o">=</span> QZrRP-fzuq
<span class="nv">dbname</span> <span class="o">=</span> email
<span class="nv">query</span> <span class="o">=</span> SELECT <span class="s2">"path_maildir"</span> FROM users WHERE <span class="s2">"email_local"</span> <span class="o">=</span> <span class="s1">'%s'</span> AND <span class="s2">"user_active"</span> <span class="o">=</span> <span class="s1">'1'</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="c1"># Configuracion de Postfix para obtener los alias de los</span>
<span class="c1"># usuarios virtuales que hay en la base de datos</span>
<span class="c1">#</span>
<span class="nv">hosts</span> <span class="o">=</span> localhost
<span class="nv">user</span> <span class="o">=</span> app_postfix
<span class="nv">password</span> <span class="o">=</span> QZrRP-fzuq
<span class="nv">dbname</span> <span class="o">=</span> email
<span class="nv">query</span> <span class="o">=</span> SELECT <span class="s2">"email_local"</span> FROM users_aliases WHERE <span class="s2">"email_alias"</span> <span class="o">=</span> <span class="s1">'%s'</span>
</code></pre></div>
<p>Para <strong>MySQL</strong>:</p>
<div class="highlight"><pre><span></span><code><span class="c1"># Configuracion de Postfix para obtener los datos de los</span>
<span class="c1"># usuarios virtuales que hay en la base de datos</span>
<span class="c1">#</span>
<span class="nv">hosts</span> <span class="o">=</span> localhost
<span class="nv">user</span> <span class="o">=</span> app_postfix
<span class="nv">password</span> <span class="o">=</span> QZrRP-fzuq
<span class="nv">dbname</span> <span class="o">=</span> email
<span class="nv">query</span> <span class="o">=</span> SELECT path_maildir FROM users WHERE <span class="nv">email_local</span> <span class="o">=</span> <span class="s1">'%s'</span> AND <span class="nv">user_active</span> <span class="o">=</span> <span class="s1">'1'</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="c1"># Configuracion de Postfix para obtener los alias de los</span>
<span class="c1"># usuarios virtuales que hay en la base de datos</span>
<span class="c1">#</span>
<span class="nv">hosts</span> <span class="o">=</span> localhost
<span class="nv">user</span> <span class="o">=</span> app_postfix
<span class="nv">password</span> <span class="o">=</span> QZrRP-fzuq
<span class="nv">dbname</span> <span class="o">=</span> email
<span class="nv">query</span> <span class="o">=</span> SELECT email_local FROM users_aliases WHERE <span class="nv">email_alias</span> <span class="o">=</span> <span class="s1">'%s'</span>
</code></pre></div>
<p>Como podeis ver, la única diferencia que hay entre si utilizamos PostgreSQL o Mysql es que en éste último los nombres de las columnas NO pueden ir entre comillas, mientras que en PostgreSQL es obligatorio.</p>
<p>Y con esto, ya deberíamos tener toda la parte de configuración básica de nuestro servidor SMTP (Postfix) terminada...</p>
<p>Vamos a intentar iniciar el servicio (o reiniciarlo, si ya estaba levantado) para ver si hemos configurado todo correctamente:</p>
<div class="highlight"><pre><span></span><code>$ sudo /etc/init.d/postfix start
<span class="o">[</span> ok <span class="o">]</span> Starting Postfix Mail Transport Agent: postfix
</code></pre></div>
<p>Podemos echar un ojo al log para ver si el servicio se ha iniciado correctamente. El log de los servicios de correo se encuentra en <code>/var/log/mail.log</code> en Debian y similares, y en <code>/var/log/maillog</code> en CentOS/RedHat.</p>
<p>Si vemos algo parecido a esto en el log (sin ningún otro mensaje <em>chungo</em>), podemos alegrarnos:</p>
<div class="highlight"><pre><span></span><code>postfix/master<span class="o">[</span><span class="m">27126</span><span class="o">]</span>: daemon started -- version <span class="m">2</span>.9.6, configuration /etc/postfix
</code></pre></div>
<p>Si vemos algun mensaje de error, Postfix debería ser lo suficientemente explícito como para darnos en el log una buena pista sobre donde está el problema, que si lo hay, a éstas alturas de la configuración seguramente no sea más que un error de sintaxis o alguna tontería que hayamos hecho en alguno de los archivos que hemos editado hasta ahora. Así que arréglalo!! xDD</p>
<p>Para probar que todo funciona correctamente, lo suyo es tratar de enviar un email al usuario que habíamos creado en la base de datos y ver si Postfix es capaz de aceptar el email, obtener la información del destinatario y guardar el email en su <em>mailbox</em>. Y para eso nada mejor que conectarnos mediante <a href="https://es.wikipedia.org/wiki/Telnet">telnet</a> al puerto del Postfix y teclear los comandos SMTP necesarios para enviar un email.</p>
<p>Primero nos conectamos:</p>
<div class="highlight"><pre><span></span><code>$ telnet localhost <span class="m">25</span>
Trying <span class="m">127</span>.0.0.1...
Connected to localhost.
Escape character is <span class="s1">'^]'</span>.
<span class="m">220</span> pornohardware.com ESMTP Postfix <span class="o">(</span>Debian/GNU<span class="o">)</span>
</code></pre></div>
<p>Y luego, mediante los comandos SMTP descritos en el <a href="https://tools.ietf.org/html/rfc2821">RFC2821</a>, primero <a href="https://tools.ietf.org/html/rfc2821#section-4.1.1.1"><em>saludamos</em> al servidor</a> con <code>HELO</code> (o EHLO), después <a href="https://tools.ietf.org/html/rfc2821#section-4.1.1.2">identificamos el remitente</a> del email con <code>MAIL FROM</code>, luego <a href="https://tools.ietf.org/html/rfc2821#section-4.1.1.3">especificamos al destinatario</a> con <code>RCPT TO</code> y después <a href="https://tools.ietf.org/html/rfc2821#section-4.1.1.4">escribimos el contenido del email</a> con <code>DATA</code>. Cuando hayamos terminado de escribir el contenido del email, debemos finalizar con una nueva linea y punto <code>.</code> para enviar el mensaje. Después <a href="https://tools.ietf.org/html/rfc2821#section-4.1.1.10">finalizamos la conexión</a> con <code>QUIT</code>.</p>
<p>Esto sería un ejemplo de la <em>conversación</em> que debemos mantener con el servidor SMTP:</p>
<div class="highlight"><pre><span></span><code>$ telnet localhost <span class="m">25</span>
Trying <span class="m">127</span>.0.0.1...
Connected to localhost.
Escape character is <span class="s1">'^]'</span>.
<span class="m">220</span> pornohardware.com ESMTP Postfix <span class="o">(</span>Debian/GNU<span class="o">)</span>
EHLO remitente.com
<span class="m">250</span>-remitente.com
<span class="m">250</span>-PIPELINING
<span class="m">250</span>-SIZE <span class="m">25600000</span>
<span class="m">250</span>-VRFY
<span class="m">250</span>-ETRN
<span class="m">250</span>-STARTTLS
<span class="m">250</span>-AUTH PLAIN
<span class="m">250</span>-AUTH<span class="o">=</span>PLAIN
<span class="m">250</span>-ENHANCEDSTATUSCODES
<span class="m">250</span>-8BITMIME
<span class="m">250</span> DSN
MAIL FROM: prueba@bhean.com
<span class="m">250</span> <span class="m">2</span>.1.0 Ok
RCPT TO: adama@pornohardware.com
<span class="m">250</span> <span class="m">2</span>.1.5 Ok
DATA
<span class="m">354</span> End data with <CR><LF>.<CR><LF>
Esto es una prueba para ver si todo funciona correctamente
.
<span class="m">250</span> <span class="m">2</span>.0.0 Ok: queued as BE75A100D0
QUIT
<span class="m">221</span> <span class="m">2</span>.0.0 Bye
Connection closed by foreign host.
</code></pre></div>
<p>Si hay algun problema lo veremos en el log del servidor, y también al ejecutar los comandos anteriores con el <code>telnet</code>.</p>
<p>Antes de dar por terminada la configuración del SMTP, hay un par de opciones muy interesantes que se pueden incluir en el <code>main.cf</code> y que pueden resultar muy útiles en algunas ocasiones:</p>
<ul>
<li><strong>blacklist</strong>: Se utiliza para especificar direcciones de email concretas (o dominios enteros) que deben ser rechazados (porque sepamos que son <em>spam</em> o slgo así).</li>
<li><strong>whitelist</strong>: Igual que el anterior, pero al revés. Permite configurar servidores de los que SI queremos aceptar emails.</li>
<li><strong>check_sender</strong>: Permite aceptar o rechazar emails en función de la dirección del remitente.</li>
<li><strong>check_body</strong>: Igual que el anterior, pero en función del cuerpo del email.</li>
</ul>
<p>Los 2 primeros (<code>blacklist</code>y <code>whitelist</code>) forman parte de la configuración de <code>smtpd_recipient_restrictions</code>, es decir, una serie de comprobaciones que Postfix hace cuando recibe un email.</p>
<p>Todas estas comprobaciones se irán ejecutando por orden de aparición. Postfix irá procesándolas una tras otra hasta que una de ellas concuerde con el email recibido. Si ninguna concuerda, el email será aceptado. Pero si alguna de ellas concuerda, se aceptará o rechazará dependiendo de lo que hayamos configurado en dicha comprobación.</p>
<p>Una configuración típica de <code>smtpd_recipient_restrictions</code> en el archivo <code>main.cf</code> sería:</p>
<div class="highlight"><pre><span></span><code><span class="nv">smtpd_recipient_restrictions</span> <span class="o">=</span> regexp:/etc/postfix/blacklist,
permit_mynetworks,
reject_invalid_hostname,
reject_non_fqdn_sender,
reject_non_fqdn_recipient,
reject_unknown_sender_domain,
reject_unknown_recipient_domain,
permit_sasl_authenticated,
reject_unauth_destination,
regexp:/etc/postfix/blacklist,
permit
</code></pre></div>
<p>Aquellas que comienzan por <em>regexp:</em> se utilizan para definir (en un archivo aparte) determinadas acciones (aceptar el email, rechazarlo, etc) mediante patrones de <a href="https://es.wikipedia.org/wiki/Expresi%C3%B3n_regular">expresiones regulares</a>. Por ejemplo, el archivo <code>/etc/postfix/blacklist</code> podría ser parecido a esto:</p>
<div class="highlight"><pre><span></span><code>/soyun@spamer<span class="se">\.</span>com$/ REJECT SPAM is not allowed here / El SPAM no esta permitido aqui
/@spam<span class="se">\.</span>com$/ REJECT SPAM is not allowed here / El SPAM no esta permitido aqui
</code></pre></div>
<p>Nota: Antes de nada, al igual que en los anteriores casos que hemos visto, hay que utilizar el comando <code>postmap</code> con estos archivos para que Postfix pueda utilizarlos. Simplemente ejecutamos:</p>
<div class="highlight"><pre><span></span><code>$ postmap blacklist
</code></pre></div>
<p>para que se genere el archivo <code>blacklist.db</code>, que no es más que el archivo <code>blacklist</code> que hemos creado, pero en un formato que Postfix sabe manejar.</p>
<p>Volviendo al ejemplo, segun el archivo <code>blacklist</code> que hemos creado y a la configuración de <code>smtpd_recipient_restrictions</code>, si recibiéramos un email de la dirección <code>soyun@spamer.com</code> o de cualquier dirección del dominio <code>@spam.com</code>, sería rechazado automáticamente (<em>REJECT</em>) utilizando "<em>SPAM is not allowed here / El SPAM no esta permitido aqui</em>" como razón del rechazo.</p>
<p>Pero si el email recibido no coincidiera con ninguna de las expresiones regulares de <code>blacklist</code>, entonces Postfix pasaría a la siguiente restricción que hubiera configurada en <code>smtpd_recipient_restrictions</code>, en éste caso <code>permit_mynetworks</code> (que significa que están permitidos los emails enviados desde las máquinas de nuestra red, es decir, los servidores cuyas IPs están especificadas en la directiva <code>mynetworks</code> del <code>main.cf</code>).</p>
<p>Del mismo modo podemos configurar también un archivo para hacer todo lo contrario, es decir, en lugar de rechazar aquellos emails que coincidan con las expresiones regulares que especifiquemos, podríamos querer que Postfix aceptara aquellos emails que coincidan con dichas expresiones.</p>
<p>Un ejemplo de un archivo <code>whitelist</code> podría ser algo así:</p>
<div class="highlight"><pre><span></span><code><span class="m">83</span>.138.165.68 OK
<span class="m">5</span>.153.231.4 OK
</code></pre></div>
<p>Cualquier email procedente de dichas IPs sería aceptado por nuestro servidor. Por supuesto, para utilizar éste archivo habría que generar también el correspondiente <code>whitelist.db</code> con el comando <code>postmap</code>.</p>
<p>Y por último, los archivos <code>check_sender</code> y <code>check_body</code> se basan en el mismo concepto que los anteriores... solo que como su propio nombre indican, estos comprueban coincidencias con el remitente del email y con el cuerpo del mismo, respectivamente.</p>
<p>Para utilizarlos, nuesto <code>main.cf</code> debería incluir algo parecido a esto:</p>
<div class="highlight"><pre><span></span><code><span class="nv">smtpd_sender_restrictions</span> <span class="o">=</span> regexp:/etc/postfix/check_sender
<span class="nv">body_checks</span> <span class="o">=</span> regexp:/etc/postfix/check_body
</code></pre></div>
<p>Y en dichos archivos se crearían las expresiones regulares que queramos comprobar, junto con el código de estado y el mensaje que queremos que se devuelva si alguna coincide:</p>
<div class="highlight"><pre><span></span><code>/@dominiospamer<span class="se">\.</span>com$/ <span class="m">550</span> No queremos SPAM
/@otrospamer<span class="se">\.</span>com$/ <span class="m">550</span> No queremos SPAM
</code></pre></div>
<div class="highlight"><pre><span></span><code>/Ryan Harding/ REJECT No queremos SPAM
/Bet2Day/ REJECT No queremos SPAM
</code></pre></div>
<p>Hay muchas otras opciones, por lo que os recomiendo que le echeis un ojo a la <a href="http://www.postfix.org/documentation.html">documentación oficial de Postfix</a> si quereis ver algo más en detalle.</p>
<p>En cuanto al SMTP, por el momento podemos darlo por terminado... pero recordar que si utilizais un <a href="https://es.wikipedia.org/wiki/Cortafuegos_%28inform%C3%A1tica%29">firewall</a> (y si no lo haceis, deberíais! insensatos!) debéis abrir los puertos necesarios, que en éste caso son el 25 para el SMTP y el 465 para el SMTP-<a href="https://es.wikipedia.org/wiki/Transport_Layer_Security">SSL</a>...</p>
<p>Ahora que ya tenemos Postfix funcionando para el servicio SMTP, vamos a continuar con una de las partes más importantes para evitar el spam: configurarlo para que únicamente nuestros usuarios puedan usarlo para el envío de emails.</p>
<h2>Configuración de SASL para autenticación de Postfix<a name="sasl"></a></h2>
<p>Postfix debe aceptar los emails que vayan destinados a nuestros usuarios... pero qué pasa con aquellos emails que nuestros usuarios quieran enviar a otras personas?</p>
<p>Un servidor SMTP abierto es el paraiso de cualquier <a href="http://es.wikipedia.org/w/index.php?title=Spam&redirect=no">spamer</a>, por lo que únicamente nuestros usuarios deben poder utilizar nuestro SMTP para enviar emails. De lo contrario, cualquiera que descubra nuestro servidor nos utilizará para enviar miles de emails a todo el mundo... y no solo debemos evitarlo para no contribuir con el envío de spam, sino que podrían meter la IP de nuestro servidor en alguna de las muchísimas <a href="http://es.wikipedia.org/wiki/Lista_negra">listas negras</a> de servidores de <em>spam</em> que hay en Internet, lo que haría que todos los servidores de emails del mundo rechazaran el correo enviado por nuestro servidor, incluso los emails legítimos enviados por nuestros usuarios.</p>
<p>Para evitarlo, debemos configurar Postfix para que solo nuestros usuarios puedan hacer uso de él. Para llevar a cabo ésta tarea debemos utilizar <a href="https://es.wikipedia.org/wiki/SASL">SASL</a>.</p>
<p>SASL hará que Postfix solo acepte enviar emails de los usuarios que se identifiquen, para lo cual consultará la base de datos a través de <a href="http://es.wikipedia.org/wiki/Pluggable_Authentication_Modules">PAM (Pluggable Authentication Modules)</a>, que es un sistema de autenticación muy extendido en el mundo <em>unix/linux</em>.</p>
<p>La instalación de los paquetes necesarios para la autenticación de Postfix, si utilizamos <strong>Debian/Ubuntu</strong>, se lleva a cabo de ésta forma:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install libgsasl7 libsasl2-2 libsasl2-modules libsasl2-modules-sql sasl2-bin libpam-mysql libpam-pgsql libpam-modules-bin libpam-modules
</code></pre></div>
<p>Y si utilizamos <strong>Redhat/CentOS</strong>, debemos descargar e instalar los paquetes manualmente, ya que no se encuentran en los repositorios oficiales de éstas distribuciones (elije Debian la próxima vez, jejejee) xDD</p>
<p>Una vez instalados tanto SASL2 como PAM, la configuración de ambos es muy sencilla: primero habilitamos la ejecución del demonio de SASL en el arranque del servidor y especificamos el método de autenticación <code>pam</code>, editando el archivo <code>/etc/default/saslauthd</code>:</p>
<div class="highlight"><pre><span></span><code><span class="c1">#</span>
<span class="c1"># Settings for saslauthd daemon</span>
<span class="c1"># Please read /usr/share/doc/sasl2-bin/README.Debian for details.</span>
<span class="c1">#</span>
<span class="c1"># Should saslauthd run automatically on startup? (default: no)</span>
<span class="nv">START</span><span class="o">=</span>yes
<span class="c1"># Which authentication mechanisms should saslauthd use? (default: pam)</span>
<span class="c1">#</span>
<span class="c1"># Available options in this Debian package:</span>
<span class="c1"># getpwent -- use the getpwent() library function</span>
<span class="c1"># kerberos5 -- use Kerberos 5</span>
<span class="c1"># pam -- use PAM</span>
<span class="c1"># rimap -- use a remote IMAP server</span>
<span class="c1"># shadow -- use the local shadow password file</span>
<span class="c1"># sasldb -- use the local sasldb database file</span>
<span class="c1"># ldap -- use LDAP (configuration is in /etc/saslauthd.conf)</span>
<span class="c1">#</span>
<span class="c1"># Only one option may be used at a time. See the saslauthd man page</span>
<span class="c1"># for more information.</span>
<span class="c1">#</span>
<span class="c1"># Example: MECHANISMS="pam"</span>
<span class="nv">MECHANISMS</span><span class="o">=</span><span class="s2">"pam"</span>
<span class="c1"># To know if your Postfix is running chroot, check /etc/postfix/master.cf.</span>
<span class="c1"># If it has the line "smtp inet n - y - - smtpd" or "smtp inet n - - - - smtpd"</span>
<span class="c1"># then your Postfix is running in a chroot.</span>
<span class="c1"># If it has the line "smtp inet n - n - - smtpd" then your Postfix is NOT</span>
<span class="c1"># running in a chroot.</span>
<span class="nv">OPTIONS</span><span class="o">=</span><span class="s2">"-c -m /var/run/saslauthd -r"</span>
</code></pre></div>
<p>Después, configuramos PAM para que se conecte a nuestra base de datos para comprobar el login/password de nuestros usuarios. Para ello, editamos el archivo <code>/etc/pam.d/smtp</code> (si no existiera, lo crearíamos) con los valores de nuestra base de datos, y del usuario <code>app_sasl</code> que ya habíamos creado previamente para esto al comienzo de éste artículo:</p>
<div class="highlight"><pre><span></span><code>auth sufficient pam_pgsql.so <span class="se">\\</span>
<span class="nv">user</span><span class="o">=</span>app_sasl <span class="se">\\</span>
<span class="nv">passwd</span><span class="o">=</span>hb9mwJGcc <span class="se">\\</span>
<span class="nv">host</span><span class="o">=</span><span class="m">127</span>.0.0.1 <span class="se">\\</span>
<span class="nv">db</span><span class="o">=</span>email <span class="se">\\</span>
<span class="nv">table</span><span class="o">=</span>users <span class="se">\\</span>
<span class="nv">usercolumn</span><span class="o">=</span>login <span class="se">\\</span>
<span class="nv">passwdcolumn</span><span class="o">=</span>password_crypt <span class="se">\\</span>
<span class="nv">crypt</span><span class="o">=</span><span class="m">1</span> <span class="se">\\</span>
<span class="nv">where</span><span class="o">=</span><span class="nv">user_active</span><span class="o">=</span><span class="m">1</span> <span class="se">\\</span>
<span class="nv">debug</span><span class="o">=</span><span class="m">1</span>
auth sufficient pam_unix_auth.so
account required pam_pgsql.so <span class="se">\\</span>
<span class="nv">user</span><span class="o">=</span>app_sasl <span class="se">\\</span>
<span class="nv">passwd</span><span class="o">=</span>hb9mwJGcc <span class="se">\\</span>
<span class="nv">host</span><span class="o">=</span><span class="m">127</span>.0.0.1 <span class="se">\\</span>
<span class="nv">db</span><span class="o">=</span>email <span class="se">\\</span>
<span class="nv">table</span><span class="o">=</span>users <span class="se">\\</span>
<span class="nv">usercolumn</span><span class="o">=</span>login <span class="se">\\</span>
<span class="nv">passwdcolumn</span><span class="o">=</span>password_crypt <span class="se">\\</span>
<span class="nv">crypt</span><span class="o">=</span><span class="m">1</span> <span class="se">\\</span>
<span class="nv">where</span><span class="o">=</span><span class="nv">user_active</span><span class="o">=</span><span class="m">1</span> <span class="se">\\</span>
<span class="nv">debug</span><span class="o">=</span><span class="m">1</span>
account sufficient pam_unix_acct.so
</code></pre></div>
<p>Obviamente, si en lugar de PostgreSQL utilizamos MySQL, debemos cambiar <code>pam_pgsql.so</code> por <code>pam_mysql.so</code>.</p>
<p>El parámetro <code>debug</code> se puede establecer a <code>1</code> para aumentar la información que se mostrará en el log, algo muy útil para darnos pistas si algo no va bien. Si no queremos información de debug, lo dejamos a <code>0</code>.</p>
<p>Por último, editamos (o creamos, en el caso de no existir) el archivo <code>/etc/postfix/sasl/smtpd.conf</code>. En él indicaremos a Postfix que debe usar el demonio SASL para autenticar a los usuarios:</p>
<div class="highlight"><pre><span></span><code>pwcheck_method: saslauthd
saslauthd_path: /var/run/saslauthd/mux
mech_list: plain
log_level: <span class="m">5</span>
</code></pre></div>
<p>Es importante que el usuario <code>postfix</code> sea miembro del grupo <code>sasl</code>, ya que de lo contrario Postfix no tendrá permisos para acceder a SASL. Para eso basta con ejecutar:</p>
<div class="highlight"><pre><span></span><code>$ sudo usermod -G sasl postfix
</code></pre></div>
<p>Por último, debemos asegurarnos que las directivas de configuración de SASL están correctamente especificadas en el <code>main.cf</code> de Postfix:</p>
<div class="highlight"><pre><span></span><code><span class="nv">smtpd_sasl_path</span> <span class="o">=</span> smtpd
<span class="nv">smtpd_sasl_auth_enable</span> <span class="o">=</span> yes
<span class="c1">#smtpd_sasl2_auth_enable = yes</span>
<span class="nv">smtpd_sasl_security_options</span> <span class="o">=</span> noanonymous
<span class="nv">smtpd_sasl_local_domain</span> <span class="o">=</span> <span class="nv">$mydestination</span>
<span class="nv">broken_sasl_auth_clients</span> <span class="o">=</span> yes
</code></pre></div>
<p>Así como la restricción adecuada para rechazar aquellos usuarios que NO se identifiquen correctamente:</p>
<div class="highlight"><pre><span></span><code><span class="nv">smtpd_recipient_restrictions</span> <span class="o">=</span> permit_mynetworks,
reject_invalid_hostname,
reject_non_fqdn_sender,
reject_non_fqdn_recipient,
reject_unknown_sender_domain,
reject_unknown_recipient_domain,
permit_sasl_authenticated,
reject_unauth_destination,
check_client_access hash:/etc/postfix/whitelist,
permit
</code></pre></div>
<p>Y listo! Arrancamos el demonio de SASL:</p>
<div class="highlight"><pre><span></span><code>$ sudo /etc/init.d/saslauthd start
</code></pre></div>
<p>Y si todo ha ido bien, ya deberíamos tener el servidor Postfix correctamente.</p>
<p>Para comprobar que SASL está correctamente configurado y funciona como queremos, existe el comando <code>testsaslauth</code>. Es muy sencillo de utilizar, solo hay que pasarle el usuario, el password y el método de autenticación que queremos comprobar. Por ejemplo, en nuestro caso <em>bill</em> es el usuario (campo <code>login</code> de la tabla <code>users</code>), <em>galactica</em> la password (cuyo valor cifrado es el que habíamos guardado en el campo <code>password_crypt</code> de la tabla <code>users</code>) y <code>smtp</code> es lo que queremos comprobar, por lo que el comando quedaría así:</p>
<div class="highlight"><pre><span></span><code>$ testsaslauthd -s smtp -u bill -p galactica
<span class="m">0</span>: OK <span class="s2">"Success."</span>
</code></pre></div>
<p>Si ejecutamos el mismo comando, pero con el nombre de usuario o la password mal puesta, deberíamos ver algo parecido a:</p>
<div class="highlight"><pre><span></span><code>$ testsaslauthd -s smtp -u nobill -p nogalactica
<span class="m">0</span>: NO <span class="s2">"authentication failed"</span>
</code></pre></div>
<p>Si el resultado de éstos comandos no es el esperado (siempre os sale <em>authentication failed</em> o algo así), podeis habilitar el modo de depuración (debug) de SASL para que muestre la información de autentificación en el log, descomentando la linea <code>#debug</code> que os indiqué en el archivo <code>/etc/pam_pgsql.conf</code> o <code>/etc/pam_pgsql.conf</code>.</p>
<p>También podeis comprobar que todo funciona como debería intentando enviar un email de forma anónima (sin identificarnos) y comprobar que Postfix NO os deja hacerlo... y después hacer la misma prueba, pero ésta vez identificándonos correctamente antes.</p>
<p>Para hacerlo, de nuevo recurrimos al comando <code>telnet</code> para ir viendo paso a paso las respuestas que nos da el servidor. Pero ojo! No debeis conectaros con el comando <code>telnet</code> desde el propio servidor o desde cualquier otra máquina de vuestra red, ya que como habíamos especificado la opción <code>permit_mynetworks</code> en la directiva <code>smtpd_recipient_restrictions</code> del archivo de configuración de Postfix, todas las máquinas de nuestra red estan autorizadas a enviar emails SIN necesidad de autenticarse. Por eso, la prueba con <code>telnet</code> debeis hacerla desde un servidor FUERA de vuestra red (es decir, fuera de lo especificado en la directiva <code>mynetworks</code> del archivo <code>/etc/postfix/main.cf</code>)</p>
<p>Para comprobar que el servidor NO acepta que enviemos emails sin identificarnos:</p>
<div class="highlight"><pre><span></span><code>$ telnet ip-de-vuestro-servidort <span class="m">25</span>
Trying <span class="m">127</span>.0.0.1...
Connected to localhost.
Escape character is <span class="s1">'^]'</span>.
<span class="m">220</span> pornohardware.com ESMTP Postfix <span class="o">(</span>Debian/GNU<span class="o">)</span>
EHLO remitente.com
<span class="m">250</span>-remitente.com
<span class="m">250</span>-PIPELINING
<span class="m">250</span>-SIZE <span class="m">25600000</span>
<span class="m">250</span>-VRFY
<span class="m">250</span>-ETRN
<span class="m">250</span>-STARTTLS
<span class="m">250</span>-AUTH PLAIN
<span class="m">250</span>-AUTH<span class="o">=</span>PLAIN
<span class="m">250</span>-ENHANCEDSTATUSCODES
<span class="m">250</span>-8BITMIME
<span class="m">250</span> DSN
MAIL FROM: prueba@bhean.com
<span class="m">250</span> <span class="m">2</span>.1.0 Ok
RCPT TO: cualquiercosa@hotmail.com
<span class="m">554</span> <span class="m">5</span>.7.1 <cualquiercosa@hotmail.com>: Relay access denied
QUIT
<span class="m">221</span> <span class="m">2</span>.0.0 Bye
Connection closed by foreign host.
</code></pre></div>
<p>Como podéis ver, estamos intentando enviar un email desde nuestro servidor de correo a la dirección <code>cualquiercosa@hotmail.com</code>, a lo cuál éste nos responde con un <code>Relay access denied</code>. Es decir, que NO podemos enviar emails a direcciones que no sean las de nuestro propio servidor, a no ser que nos identifiquemos previamente.</p>
<p>Si en lugar del mensaje <code>554 5.7.1 Relay access denied</code> obtenéis un <code>250 2.1.5 Ok</code> significa que vuestro servidor está aceptando CUALQUIER EMAIL para CUALQUIER DESTINATARIO (es decir, sois lo que se considera un <em>Open Relay</em>), y de ser así, para cuando hayais terminado de leer ésta frase ya habrá <code>medio internet</code> conectado a vuestro servidor enviando spam a todo el planeta... así que parar <strong>inmediatamente</strong> Postfix, cerrar el puerto SMTP en el firewall o lo que queráis, pero detener el servicio inmediatamente y revisar la configuración de SASL, PAM y Postfix antes de volver a abrirlo a Internet...</p>
<p>Quizás haya algo en el log que os ayude a encontrar el problema. Recordar que el log de los servicios de correo se encuentra en /var/log/mail.log en Debian y similares, y en /var/log/maillog en CentOS/RedHat.</p>
<h2>Instalación de Courier como servidor POP/IMAP<a name="courier"></a></h2>
<p>Así como para poder enviar emails necesitamos un servidor SMTP, para poder acceder a ellos para su lectura necesitamos un servidor POP o IMAP, que son los 2 protocolos más extendidos para ese fin.</p>
<p>Podéis montar ambos o únicamente uno... aunque la verdad es que POP no tiene prácticamente ninguna ventaja hoy en día, cada vez se usa menos, y en mi opinión no tiene ningún sentido mantenerlo. Si os quedásteis anclados en los 90 y echáis de menos <a href="http://es.wikipedia.org/wiki/GeoCities">geocities</a>, los <a href="http://es.wikipedia.org/wiki/Graphics_Interchange_Format">gifs animados</a> con símbolos de @rrobas dando vueltas, o simplemente eres un <a href="http://es.wikipedia.org/wiki/Amish">Amish</a> montando el servidor de correo de tu aldea, POP es lo que buscas. Para todos los demás, IMAP es la solución.</p>
<p>No quiero extenderme mucho, pero para que quede un poco más claro, os pondré una pequeña tabla comparativa sobre algunas de las diferencias más notables entre ambos protocolos:</p>
<table>
<thead>
<tr>
<th align="left"> </th>
<th align="left">POP3</th>
<th align="left">IMAP4</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">Permite trabajar offline</td>
<td align="left"><strong>Si</strong></td>
<td align="left">Depende del cliente</td>
</tr>
<tr>
<td align="left">Número de transacciones</td>
<td align="left">Bajo</td>
<td align="left"><strong>Alto</strong></td>
</tr>
<tr>
<td align="left">Permite trabajar online</td>
<td align="left">No</td>
<td align="left"><strong>Si</strong></td>
</tr>
<tr>
<td align="left">Ver emails/cabeceras sin descargarlos previamente</td>
<td align="left">No</td>
<td align="left"><strong>Si</strong></td>
</tr>
<tr>
<td align="left">Nº de carpetas gestionables</td>
<td align="left">1</td>
<td align="left"><strong>Ilimitado</strong></td>
</tr>
<tr>
<td align="left">Gestión de carpetas</td>
<td align="left">No</td>
<td align="left"><strong>Si</strong></td>
</tr>
<tr>
<td align="left">Buzones multiusuario (acceso múltiple)</td>
<td align="left">No</td>
<td align="left"><strong>Si</strong></td>
</tr>
<tr>
<td align="left">Estados/flags en mensajes</td>
<td align="left">No</td>
<td align="left"><strong>Si</strong></td>
</tr>
<tr>
<td align="left">Búsqueda en mensajes</td>
<td align="left">No</td>
<td align="left"><strong>Si</strong></td>
</tr>
<tr>
<td align="left">Gestión <a href="https://es.wikipedia.org/wiki/Multipurpose_Internet_Mail_Extensions">MIME</a></td>
<td align="left">No</td>
<td align="left"><strong>Si</strong></td>
</tr>
<tr>
<td align="left">Mecanismos de extensión de funciones</td>
<td align="left">No</td>
<td align="left"><strong>Si</strong></td>
</tr>
<tr>
<td align="left">Firma cifrada</td>
<td align="left">No</td>
<td align="left"><strong>Si</strong></td>
</tr>
<tr>
<td align="left">Autenticación protegida</td>
<td align="left">APOP</td>
<td align="left"><strong>Nativo</strong></td>
</tr>
</tbody>
</table>
<p>Como podéis ver, el uso de POP hoy en día no tiene ningún sentido... por lo que a no ser que necesiteis implementarlo por algún extraño motivo, usar <strong>siempre</strong> IMAP. De hecho, aunque se pueden utilizar ambos al mismo tiempo <strong>NO os recomiendo</strong> que lo hagais, ya que si un usuario (por ejemplo) se descarga el correo utilizando POP, si más tarde accede por IMAP no podrá ver nada ya que una vez que POP descarga el correo, éste se elimina del servidor. Y al no permitir POP el uso de carpetas, únicamente se descarga el correo del <em>INBOX</em> (bandeja de entrada), lo que significa que si habeis organizado vuestros mensajes en carpetas utilizando IMAP, esos mensajes no podreis descargarlos desde POP.</p>
<p>Lo dicho, <em>POP es de nenazas</em>, así que voy a explicar únicamente la de IMAP. No obstante, si quereis instalar también el servidor POP, su instalación es muy sencilla (y similar).</p>
<p><img class="right" src="/images/logos/logo_courier.png">
Vamos al tema: así como para el uso del SMTP utilizábamos <a href="http://www.postfix.org">Postfix</a>, para el uso de IMAP (o POP) vamos a utilizar <a href="http://www.courier-mta.org/">Courier</a>.</p>
<p>Courier es un servidor POP/IMAP que se encargará de acceder a los mensajes de correo electrónico que previsamente nuestro Postfix haya almacenado en los buzones de nuestros usuarios.</p>
<p>Como siempre, lo primero que tenemos que hacer es instalar los paquetes necesarios.</p>
<p>En <strong>Debian/Ubuntu</strong>:</p>
<div class="highlight"><pre><span></span><code>sudo apt-get install courier-authdaemon courier-imap courier-imap-ssl courier-authlib-mysql courier-authlib-postgresql
</code></pre></div>
<p>En <strong>Redhat/CentOS</strong>:</p>
<p>Por desgracia en éstas distribuciones no existen paquetes RPM en sus repositorios oficiales, así que o bien lo instalais compilando su código fuente a mano (<a href="http://www.courier-mta.org/repo.html">podéis descargarlo aquí</a>) o bien generais los RPMs vosotros mismos tal y como <a href="http://www.courier-mta.org/rpm.html">se explica aquí</a>. Obviamente es mucho más <em>incómodo</em> que utilizar los paquetes de los repositorios oficiales, pero si hubiérais elegido una <a href="http://www.debian.org/">distribución como Dios manda</a> no tendríais que preocuparos...</p>
<p>En cualquier caso, una vez instalado, la configuración de Courier es muy sencilla: únicamente hay que editar 3 archivos:</p>
<ul>
<li>/etc/courier/authdaemonrc</li>
<li>/etc/courier/imapd</li>
<li>/etc/courier/authpgsqlrc (o /etc/courier/authmysqlrc, según lo que estemos usando)</li>
</ul>
<p>En el primero de ellos (<code>/etc/courier/authdaemonrc</code>) únicamente hay que indicar qué módulo es el que se va a encargar de autenticar a los usuarios (authpgsql, authmysql, etc).</p>
<div class="highlight"><pre><span></span><code><span class="c1">##NAME: authmodulelist:2</span>
<span class="c1">#</span>
<span class="c1"># The authentication modules that are linked into authdaemond. The</span>
<span class="c1"># default list is installed. You may selectively disable modules simply</span>
<span class="c1"># by removing them from the following list. The available modules you</span>
<span class="c1"># can use are: authuserdb authpam authpgsql authldap authmysql authcustom authpipe</span>
<span class="nv">authmodulelist</span><span class="o">=</span><span class="s2">"authpgsql"</span>
</code></pre></div>
<p>En el archivo <code>/etc/courier/imapd</code> se pueden configurar varias cosas (dirección de red y puerto en el que <em>escuchará</em> nuestro servidor, opciones que se pasarán al demonio <code>imapd</code>, etc) pero nosotros solo vamos a cambiar 2 de ellas: MAXPERIP e IMAPDSTART.</p>
<p>La primera de ellas indica el número de conexiones por IP que nuestro servidor IMAP puede atender. El valor por defecto suele ser válido en la mayoría de los casos, pero en el protocolo IMAP se establece una conexion por cada carpeta IMAP a la que nos conectemos, por lo que si tenemos varias cuentas y leemos el correo de varias carpetas, puede que necesitemos aumentarlo. El valor por defecto es 50, pero yo suelo configurarlo a 120:</p>
<div class="highlight"><pre><span></span><code><span class="c1">##NAME: MAXPERIP:0</span>
<span class="c1">#</span>
<span class="c1"># Maximum number of connections to accept from the same IP address</span>
<span class="nv">MAXPERIP</span><span class="o">=</span><span class="m">120</span>
</code></pre></div>
<p>Y en cuanto a IMAPDSTART, simplemente hay que establecerlo a <code>YES</code> para que el servicio IMAP se inicie automáticamente al arrancar el servidor:</p>
<div class="highlight"><pre><span></span><code><span class="c1">##NAME: IMAPDSTART:0</span>
<span class="c1">#</span>
<span class="c1"># IMAPDSTART is not used directly. Rather, this is a convenient flag to</span>
<span class="c1"># be read by your system startup script in /etc/rc.d, like this:</span>
<span class="c1">#</span>
<span class="c1"># . /etc/courier/imapd</span>
<span class="c1">#</span>
<span class="c1"># case x$IMAPDSTART in</span>
<span class="c1"># x[yY]*)</span>
<span class="c1"># /usr/lib/courier/imapd.rc start</span>
<span class="c1"># ;;</span>
<span class="c1"># esac</span>
<span class="c1">#</span>
<span class="c1"># The default setting is going to be NO, so you'll have to manually flip</span>
<span class="c1"># it to yes.</span>
<span class="nv">IMAPDSTART</span><span class="o">=</span>YES
</code></pre></div>
<p>Ya solo quedaría el archivo <code>/etc/courier/authpgsqlrc</code> (o <code>/etc/courier/authmysqlrc</code>, según proceda), que es el archivo en que se especifican los valores de la base de datos necesarios para que Courier pueda acceder a ella para identificar a los usuarios, obtener la rutas hacia sus <em>mailbox</em> (los directorios que contendrán los mensajes de cada usuario) y el resto de información necesaria.</p>
<p>Lo primero es la información de conexión (servidor, usuario/password, etc). Dicho usuario/password son los que ya habíamos creado cuando instalamos la base de datos (arriba, en el apartado <a href="#db">Creación de la base de datos de usuarios</a>).</p>
<p>Esta información de conexión se indica utilizando las directivas:</p>
<ul>
<li><strong>PGSQL_HOST</strong>: Dirección del servidor de base de datos. En nuestro caso es <em>localhost</em>, ya que tanto Courier como la base de datos están en el mismo servidor.</li>
<li><strong>PGSQL_PORT</strong>: Puerto en el que está <em>escuchando</em> la base de datos. El puerto por defecto de PostgreSQL es el 5432 y el de MySQL es el 3306.</li>
<li><strong>PGSQL_USERNAME</strong>: Usuario que utilizará Courier para conectarse a la base de datos. Nosotros habíamos creado el usuario <em>app_courier</em> para esto.</li>
<li><strong>PGSQL_PASSWORD</strong>: Password del usuario definido en <strong>PGSQL_USERNAME</strong>.</li>
</ul>
<p><em>NOTA: Si por algún motivo quisiéramos conectar a un servidor de base a través de un <a href="https://es.wikipedia.org/wiki/Socket_de_Internet">socket local</a> en lugar de a través de la red, debemos eliminar la directiva PGSQL_HOST e indicar en la directiva PGSQL_PORT el número de dicho socket. Por ejemplo, si nuestro socket local de base de datos es <code>/tmp/.s.PGSQL.5400</code>, debemos indicar el valor <code>5400</code> en PGSQL_PORT</em>.</p>
<p>El archivo de configuración quedaría entonces así:</p>
<div class="highlight"><pre><span></span><code><span class="c1">##NAME: LOCATION:0</span>
<span class="c1">#</span>
<span class="c1"># The server hostname, port, userid, and password used to log in.</span>
PGSQL_HOST localhost
PGSQL_PORT <span class="m">5432</span>
PGSQL_USERNAME app_courier
PGSQL_PASSWORD OQ5JQ3+pNR
</code></pre></div>
<p>Por supuesto, si en lugar de PostgreSQL estuviéramos utilizando MySQL, debemos cambiar el PGSQL_ por MYSQL_ en las directivas del archivo de configuración. Ya se que es obvio, pero lo comento por si acaso os estáis limitando a copiar-y-pegar sin enterder lo que estamos haciendo (merluzos!! hay que leerlo todo, que para algo llevo semanas escribiendo éste artículo! xDDD).</p>
<p>El resto del archivo de configuración es muy sencillo, y casi todas sus directivas son autoexplicativas, pero vamos a dar un pequeño repaso al resto de ellas:</p>
<ul>
<li><strong>PGSQL_DATABASE</strong>: Aquí se indica el nombre de la base de datos que contiene las tablas donde se encuentra la información de los usuarios.</li>
<li><strong>PGSQL_USER_TABLE</strong>: Nombre de la tabla que contiene la información de los usuarios.</li>
<li><strong>PGSQL_CRYPT_PWFIELD</strong>: Nombre del campo (columna) que contiene la <em>password</em> cifrada de los usuarios.</li>
<li><strong>DEFAULT_DOMAIN</strong>: Si definimos éste parámetro, si alguien intenta autenticarse (por ejemplo) con el usuario <em>fulanito</em>, Courier lo sustituirá po <em>fulanito@DEFAULT_DOMAIN</em>. Esto es útil cuando el <em>username</em> de nuestros usuarios es su dirección de email, y nuestro servidor únicamente se usa para el correo de un solo dominio, de forma que la gente puede utilizar el <em>username</em> sin tener que teclear el resto hasta completar la dirección (@DEFAULT_DOMAIN).</li>
<li><strong>PGSQL_UID_FIELD</strong>: <a href="https://es.wikipedia.org/wiki/Identificador_de_usuario">UID</a> del usuario local del servidor que se usará para acceder a los emails del servidor. Típicamente se suele utilizar el usuario del sistema <em>postfix</em>, ya que al guardarse dichos emails usando ese usuario, nos aseguramos así de tener permisos para acceder a dichos archivos. Para saber qué UID tiene un usuario en cuestión podemos usar el comando <code>id</code> (pasándole como parámetro el nombre del usuario del que queremos obtener la información). Por ejemplo: <code>id postfix</code>. En nuestro caso el valor obtenido es el 103, pero asegúrate de comprobar cuál es el que necesitas tu ya que puede variar de un sistema a otro.</li>
<li><strong>PGSQL_GID_FIELD</strong>: En éste caso hay que indicar el <a href="https://es.wikipedia.org/wiki/Identificador_de_grupo">GID</a> del grupo que utilizaremos para acceder a los emails del servidor. Típicamente se suele utilizar el grupo <em>mail</em>, por lo que para averiguar el gid de dicho grupo podemos utilizar de nuevo el comando <code>id mail</code>. En nuestro caso el valor obtenido es el 8, pero al igual que antes, asegúrate de comprobar cuál es éste gid en tu sistema.</li>
<li><strong>PGSQL_LOGIN_FIELD</strong>: Nombre del campo (columna) que contiene los <em>usernames</em> de los usuarios.</li>
<li><strong>PGSQL_HOME_FIELD</strong>: Nombre del campo (columna) que contiene la ruta a la <em>home</em> del usuario (no confundir con la ruta de los mailbox).</li>
<li><strong>PGSQL_MAILDIR_FIELD</strong>: Nombre del campo (columna) que contiene la ruta de los <em>mailboxes</em> de los usuarios. Normalmente los mailbox suelen estar en la ruta <code>$HOME/Maildir</code>, donde <code>$HOME</code> es el valor especificado en PGSQL_HOME_FIELD.</li>
<li><strong>PGSQL_QUOTA_FIELD</strong>: Nombre del campo (columna) que contiene la información sobre la <a href="https://es.wikipedia.org/wiki/Cuota_de_disco">cuota de disco</a> de los usuarios.</li>
<li><strong>PGSQL_WHERE_CLAUSE</strong>: Aquí podemos indicar una condición que deberán cumplir los usuarios para poder identificarse en nuestro servidor. La condición aquí especificada se añadirá como <a href="https://es.wikipedia.org/wiki/SQL#Cl.C3.A1usula_WHERE"><em>WHERE</em></a> en la consulta <a href="https://es.wikipedia.org/wiki/SQL">SQL</a> que Courier ejecutará cuando un usuario intente autenticarse en nuestro servidor. Es muy útil para (por ejemplo) restringir temporalmente el acceso a un usuario en concreto sin tener que eliminarlo, simplemente utilizando una columna "user_active" como la que hemos creado en la tabla de usuario, o algo similar. Os quedará más claro viendo el ejemplo del archivo de configuración que pondré a continuación.</li>
</ul>
<p>Por lo tanto el archivo <code>/etc/courier/authpgsqlrc</code> debería quedar más o menos así:</p>
<div class="highlight"><pre><span></span><code>PGSQL_HOST localhost
PGSQL_PORT <span class="m">5432</span>
PGSQL_USERNAME app_courier
PGSQL_PASSWORD OQ5JQ3+pNR
PGSQL_DATABASE email
PGSQL_USER_TABLE users
PGSQL_CRYPT_PWFIELD <span class="s2">"password_crypt"</span>
PGSQL_UID_FIELD <span class="m">103</span>
PGSQL_GID_FIELD <span class="m">8</span>
PGSQL_LOGIN_FIELD <span class="s2">"login"</span>
PGSQL_HOME_FIELD <span class="s1">'/'</span>
PGSQL_NAME_FIELD concat<span class="o">(</span><span class="s2">"name"</span>, <span class="s2">" "</span>, <span class="s2">"surname"</span><span class="o">)</span>
PGSQL_MAILDIR_FIELD <span class="s2">"path_maildir"</span>
PGSQL_WHERE_CLAUSE <span class="s2">"imap_access"</span><span class="o">=</span><span class="s1">'1'</span> AND <span class="s2">"user_active"</span><span class="o">=</span><span class="s1">'1'</span>
</code></pre></div>
<p>Y con esto ya deberíamos tener Courier listo... así que ya solo queda levantar los servicios. Primero <code>authdaemon</code> (para autenticar a los usuarios) y luego los servicios propios de <code>IMAP</code> e <code>IMAP-SSL</code>:</p>
<div class="highlight"><pre><span></span><code>$ sudo /etc/init.d/courier-authdaemon start
$ sudo /etc/init.d/courier-imap start
$ sudo /etc/init.d/courier-imap-ssl start
</code></pre></div>
<p>Configurar el servicio IMAP a través de <a href="https://es.wikipedia.org/wiki/Transport_Layer_Security">SSL</a> (algo MUY importante) no tiene ningún misterio. Si vais a utilizar certificados SSL generados por vosotros mismos y autofirmados, basta con que levanteis el servicio <code>courier-imap-ssl</code> sin más. Y si tenéis certificados SSL propios y firmados, solo hay que configurar dichos certificados en el archivo <code>/etc/courier/imapd-ssl</code> antes de levantar el servicio, y listo.</p>
<p>Es importante que os aseguréis de tener instalado en el servidor el servicio <a href="https://people.gnome.org/~veillard/gamin/">Gamin</a>, un sub-sistema de <a href="https://savannah.nongnu.org/projects/fam/">FAM (File Alteration Monitor)</a>. Se trata de un demonio encargado de notificar a algunos programas (a Courier, por ejemplo) los cambios que se producen en algunos archivos del disco. Es necesario instalarlo porque Courier-imap necesita <em>estar al tanto</em> de esos cambios a la hora de notificar a los clientes de correo. Si no lo instalamos, algunos clientes de correo podrían mostrar incómodos mensajes de error (aunque el funcionamiento del correo no debería verse afectado en la mayoría de los casos).</p>
<p>De todas formas, instalarlo es tan sencillo como siempre:</p>
<p>En <strong>Debian/Ubuntu</strong>:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install gamin
</code></pre></div>
<p>En <strong>RedHat/CentOS</strong>:</p>
<div class="highlight"><pre><span></span><code>$ sudo yum install gamin
</code></pre></div>
<p>Una vez hecho esto, ya debería funcionar perfectamente (tanto la recepción de emails mediante SMPT->Postfix como el acceso a ellos mediante IMAP->Courier). Así que si todo ha ido bien, ya deberíais poder configurar la cuenta en vuestro cliente de correo. Existen muchísimos clientes de correo diferentes (<a href="https://www.mozilla.org/es-ES/thunderbird/">Thunderbird</a>, <a href="https://wiki.gnome.org/Apps/Evolution/">Evolution</a>, <a href="https://userbase.kde.org/KMail/es">KMail</a>, etc) por lo que no entraré en detalles sobre cómo configurar una cuenta en ellos, pero no tiene ningún misterio... es igual que cualquier otra cuenta de correo que hayais configurado, solo que indicando los datos de conexión de vuestro servidor (la dirección del host donde lo habeis instalado) y los datos de acceso a vuestra cuenta (según el ejemplo que os he puesto, usuario <code>bill</code>, password <code>galactica</code> y dirección de email <code>adama@pornohardware.com</code>).</p>
<p>Por supuesto, y al igual que hicimos al configurar Postfix, debemos abrir los puertos necesarios para los servicios de IMAP e IMAP-SSL en nuestro firewall. Debeis abrir el puerto 143 para IMAP y el 993 para IMAP-SSL.</p>
<p>Si llegados a éste punto no pudiérais conectaros, o no pudiérais acceder con el usuario/password o hubiera algun otro error o comportamiento extraño, podéis editar el archivo <code>/etc/courier/authdaemonrc</code> y habilitar la directiva <code>DEBUG_LOGIN=1</code> para aumentar el nivel de detalle en los <em>logs</em> del proceso de autenticación. Si lo haceis, no olvideis reiniciar los servicios de (courier-authdaemon, courier-imap y courier-imap-ssl) para que se reflejen los cambios.</p>
<p>El log por defecto donde se guarda toda la información relativa al correo (Postfix, Courier, etc) es <code>/var/log/mail.log</code> en Debian/Ubuntu, o <code>/var/log/maillog</code> en Redhat/CentOS.</p>
<h2>Instalación de antivirus y antispam<a name="amavis"></a></h2>
<p>No se concibe un servidor de correo hoy en día sin estos 2 servicios.</p>
<p>Debido a la ingente cantidad de emails que se intercambian cada día en Internet, el correo electrónico se ha convertido para los virus en el medio preferido para transmitirse por todo el mundo.</p>
<p>En <em>mis tiempos</em>, la única forma de coger un virus en tu ordenador era que alguien te pasara un <a href="https://es.wikipedia.org/wiki/Disquete">disquete</a> infectado (muchos no sabréis ni lo que es éso del <em>disquete</em>, jejeje). El número de virus en aquella época era bajísimo, e incluso los mejores de ellos tardaban muchísimo tiempo en propagarse (y aun así, jamás lograban expandirse como lo hacen hoy en día).</p>
<p>La llegada del correo electrónico facilitó la comunicación entre personas y sistemas por todo el mundo, sin importar las distancias físicas que hubiera entre los interlocutores de dichas comunicaciones. Rápidamente los virus aprovecharon ésta via para propagarse como lo hacen hoy en día.</p>
<p>Por desgracia, el usuario <em>en general</em> sigue siendo un mero <em>usuario tonto</em> (es decir, que prácticamente desconoce el funcionamiento de cualquier sistema, y se limita únicamente a <em>usarlo casi a ciegas</em>) por lo que no se puede confiar en que tengan un antivirus actualizado en sus ordenadores. Esta es una de las razones principales por las que es responsabilidad del servidor de correo interceptar y eliminar los virus antes de que lleguen al usuario (además, es más sencillo y tiene más sentido acabar con ellos ANTES de que lleguen a su destinatario que dejar ésta labor en sus manos).</p>
<p>Y con respecto al <a href="https://es.wikipedia.org/wiki/Spam">spam</a>, la <em>lacra</em> de Internet que más odio, sucede exactamente lo mismo.</p>
<p>Cualquier persona con unos <em>minimísimos</em> conocimientos tecnológicos puede enviar miles de emails a millones de personas en cuestión de minutos sin invertir ni un solo euro, y además sin que los destinatarios de dichos emails puedan saber incluso quién se los está enviado.</p>
<p>Esto es aprovechado cada minuto del día por miles de <em>spammers</em>, que inundan los <em>mailbox</em> de todo el mundo con publicidad no solicitada.</p>
<p>Y aunque parezca una práctica <em>inofensiva</em>, el spam no solo cuesta ingentes candidades de dinero a las empresas y organizaciones que <em>sostienen</em> Internet debido a las grandes y sobredimensionadas infraestructuras que deben manejar para cubrir éste <em>uso extra</em> del correo electrónico (<a href="http://bits.blogs.nytimes.com/2009/03/31/spam-back-to-94-of-all-e-mail/?apage=2&_r=0">se estima que el 94% del correo mundial es spam</a>, sino que provoca una enorme pérdida de tiempo y recursos personales a quienes <em>padecen</em> éste tormento.</p>
<p>Por todos estos motivos, un buen antivirus y algunos filtros antispam son absolutamente necesarios en todos los servidores de correo del mundo.</p>
<p>Para instalar y configurar estos elementos, la mejor forma de hacerlo es mediante un filtro de contenidos. Y en mi opinión, el mejor en éste campo es <a href="http://www.amavis.org/">Amavis</a>.</p>
<p>Podríamos definir Amavis (o mejor dicho, amavisd-new, que es como se llama realmente) como un <a href="https://es.wiktionary.org/wiki/interfaz"><em>interface</em></a> que conecta el servidor de correo con otros programas (antivirus, antispams, etc) de forma transparente para el usuario.</p>
<p>Cuando un email llega a nuestro servidor de correo, éste se lo entrega a amavisd-new, el cual se encarga de pasárselo a los distintos filtros que tengamos configurados, y si el mensaje los supera, el servidor de correo lo almacena en el buzón del destinatario correspondiente. En caso contrario se pueden llevar a cabo diferentes acciones dependiendo de qué filtro haya sido el que ha bloqueado el email. Por ejemplo, se puede configurar para que si un email contiene un virus, automáticamente se envíe un mensaje a la persona que ha enviado el email advirtiéndole de que su ordenador podría estar infectado.</p>
<p><img class="right" src="/images/logos/logo_clamav.png">
Existen varios programas antivirus libres, gratuitos y que funcionan muy bien en GNU/Linux. Personalmente el que más me gusta es <a href="http://www.clamav.net/">ClamAV</a>.</p>
<p>Uno de los puntos más importantes en este tipo de software es la rápida localización e inclusión en sus bases de datos de los nuevos virus que se van encontrando.</p>
<p>Gracias a los propios usuarios de ClamAV y a sitios como <a href="https://www.virustotal.com/">Virustotal.com</a> a medida que se van identificando nuevos virus, <a href="https://es.wikipedia.org/wiki/Troyano_%28inform%C3%A1tica%29">troyanos</a> o cualquier otro tipo de <a href="https://es.wikipedia.org/wiki/Malware">malware</a>, estos son rápidamente introducidos en ClamAV, por lo que se su base de datos de virus se actualiza diariamente para que nuestro servidor se mantenga siempre al día.</p>
<p>El software que se encarga de mantener ClamAV actualizado es el llamado <em>Freshclam</em>, el cual forma parte del paquete ClamAV.</p>
<p>Y con respecto a los filtros antispam, también existen varios... aunque el que más destaca en el mundo open-source es <a href="http://spamassassin.apache.org/">SpamAssassin</a>.</p>
<p><img class="center" src="/images/logos/logo_spamassassin.png">
Dispone de multitud de filtros y reglas, y se le puede <em>entrenar</em> para que vaya aprendiendo a identificar qué mensajes son spam y cuáles no.</p>
<p>El funcionamiento normal de SpamAssassin es el de ir sometiendo los mensajes a diferentes <em>tests</em>, los cuales van emitiendo una <em>puntuación</em> en función de si consideran el mensaje <em>sospechoso de ser spam</em> o no. Estas puntuaciones individuales de cada test se van sumando, y si al finalizar todos el número obtenido supera el umbral que hayamos definido, el mensaje se considerará spam y o bien será rechazado (de forma que el destinatario jamás llegará ni siquiera a verlo) o bien se entregará a su destinatario normalmente, pero añadiendo una serie de cabeceras al email que lo identifiquen como spam para que sea el usuario el que determine qué hacer con él.</p>
<p>Ambos programas (ClamAV y SpamAssassin) están perfectamente integrados en Amavis, por lo que la instalación de todo esto es (como de costumbre) algo trivial en GNU/Linux:</p>
<p>En <strong>Debian/Ubuntu</strong>:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install amavisd-new spamassassin clamav-daemon clamav-freshclam
</code></pre></div>
<p>En <strong>RedHat/CentOS</strong>:</p>
<div class="highlight"><pre><span></span><code>$ sudo yum install amavisd-new clamav spamassassin
</code></pre></div>
<p>Los virus en los emails suelen ir en los archivos adjuntos que hay en ellos... pero dichos archivos a veces están comprimidos, lo cual impide que el antivirus pueda analizarlos. Para evitar esto, debemos instalar los descompresores de los formatos más comunes (<a href="http://es.wikipedia.org/wiki/Formato_de_compresi%C3%B3n_ZIP">zip</a>, <a href="http://es.wikipedia.org/wiki/ARJ">arj</a>, <a href="http://es.wikipedia.org/wiki/RAR">rar</a>, etc).</p>
<p>Para ello, instalamos los siguientes paquetes:</p>
<p>En <strong>Debian/Ubuntu</strong>:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install bzip2 gzip xzip rpm lzop unrar-free arj p7zip-full zoo arc cabextract
</code></pre></div>
<p>En <strong>RedHat/CentOS</strong>:</p>
<div class="highlight"><pre><span></span><code>$ sudo yum install bzip2 gzip rpm lzop arj p7zip unzoo arc cabextract
</code></pre></div>
<p>Para configurar Amavis debemos editar algunos archivos:</p>
<ul>
<li><strong>/etc/amavis/conf.d/05-domain_id</strong>: En éste archivo debemos indicar el dominio principal de nuestro servidor. Hay dos formas de hacerlo: o bien asignando directamente el nombre del dominio a la variable <em>$mydomain</em>, o bien indicando en dicha variable que obtenga el valor del archivo <code>/etc/mailname</code>, con lo que indicaríamos el dominio en dicho archivo. En nuestro caso utilizamos <code>pornohardware.com</code>.</li>
<li><strong>/etc/amavis/conf.d/05-node_id</strong>: En éste archivo debemos indicar (del mismo modo que en el anterior) el nombre del servidor. En nuestro caso utilizamos <code>mail.pornohardware.com</code>.</li>
<li><strong>/etc/amavis/conf.d/15-content_filter_mode</strong>: Descomentando la linea correspondiente en éste archivo habilitaremos el uso del antivirus (en éste caso, ClamAV) y del antispam (Spamassassin). Si por algún motivo no quisiéramos que Amavis utilizara alguno de los dos, bastaría con dejar comentada la linea correspondiente.</li>
<li><strong>/etc/amavis/conf.d/20-debian_defaults</strong>: La mayoría de las opciones de configuración se encuentran aquí. Los nombres de las variables son bastante descriptivos y hay bastantes comentarios en el archivo. Las principales opciones que debemos configurar son:<ul>
<li><code>$sa_spam_subject_tag</code>: Aquí definimos el <em>prefijo</em> que se antepondrá al título de los emails que Amavis considere como spam. Yo suelo utiliza <code>[SPAM]</code> (incluyendo un espacio en blanco al final).</li>
<li><code>$final_banned_destiny</code>: Aquí definimos la acción que queremos que Amavis lleve a cabo cuando un mensaje sea <a href="http://es.wikipedia.org/wiki/Ban">*baneado</a> por contener un virus. Los posibles valores son:<ul>
<li><code>D_DISCARD</code>: Rechaza el mensaje SIN informar al remitente.</li>
<li><code>D_BOUNCE</code>: Rechaza el mensaje informando al remitente a través de amavisd-new (éste es el valor que yo suelo utilizar).</li>
<li><code>D_REJECT</code>: Rechaza el mensaje informando a través del MTA.</li>
<li><code>D_PASS</code>: Acepta el mensaje.</li>
</ul>
</li>
<li><code>$final_spam_destiny</code>: Lo mismo que en el caso anterior, pero para los mensajes que Amavis haya marcado como spam.</li>
</ul>
</li>
</ul>
<p>Después, debemos añadir el usuario sobre el que se ejecuta el demonio de ClamAV (<code>clamav</code>) al grupo <code>amavis</code> para que éste tenga los permisos necesarios. Para ello utilizamos el comando <code>vigr</code>, o si lo prefieres, a través del comando:</p>
<div class="highlight"><pre><span></span><code>$ sudo usermod -G amavis clamav
</code></pre></div>
<p>En cuanto a Spamassassin, por ahora únicamente editamos el archivo <code>/etc/default/spamassassin</code> para que el demonio se inicie, poniendo a <code>1</code> el valor de la directiva <code>ENABLED</code>:</p>
<div class="highlight"><pre><span></span><code><span class="c1"># /etc/default/spamassassin</span>
<span class="c1"># Duncan Findlay</span>
<span class="c1"># WARNING: please read README.spamd before using.</span>
<span class="c1"># There may be security risks.</span>
<span class="c1"># Change to one to enable spamd</span>
<span class="nv">ENABLED</span><span class="o">=</span><span class="m">1</span>
</code></pre></div>
<p>Para <em>conectar</em> Amavis a nuestro SMTP, debemos indicar en la configuración de Postfix el puerto en el que Amavis escucha. Editamos su configuración (archivo <code>master.cf</code>) y lo indicamos:</p>
<div class="highlight"><pre><span></span><code><span class="c1">#</span>
<span class="c1"># Other external delivery methods.</span>
<span class="c1">#</span>
ifmail unix - n n - - pipe
<span class="nv">flags</span><span class="o">=</span>F <span class="nv">user</span><span class="o">=</span>ftn <span class="nv">argv</span><span class="o">=</span>/usr/lib/ifmail/ifmail -r <span class="nv">$nexthop</span> <span class="o">(</span><span class="nv">$recipient</span><span class="o">)</span>
bsmtp unix - n n - - pipe
<span class="nv">flags</span><span class="o">=</span>Fq. <span class="nv">user</span><span class="o">=</span>bsmtp <span class="nv">argv</span><span class="o">=</span>/usr/lib/bsmtp/bsmtp -t<span class="nv">$nexthop</span> -f<span class="nv">$sender</span> <span class="nv">$recipient</span>
scalemail-backend unix - n n - <span class="m">2</span> pipe
<span class="nv">flags</span><span class="o">=</span>R <span class="nv">user</span><span class="o">=</span>scalemail <span class="nv">argv</span><span class="o">=</span>/usr/lib/scalemail/bin/scalemail-store <span class="si">${</span><span class="nv">nexthop</span><span class="si">}</span> <span class="si">${</span><span class="nv">user</span><span class="si">}</span> <span class="si">${</span><span class="nv">extension</span><span class="si">}</span>
mailman unix - n n - - pipe
<span class="nv">flags</span><span class="o">=</span>FR <span class="nv">user</span><span class="o">=</span>list <span class="nv">argv</span><span class="o">=</span>/usr/lib/mailman/bin/postfix-to-mailman.py
<span class="si">${</span><span class="nv">nexthop</span><span class="si">}</span> <span class="si">${</span><span class="nv">user</span><span class="si">}</span>
smtp-amavis unix - - y - <span class="m">2</span> smtp
-o <span class="nv">smtp_data_done_timeout</span><span class="o">=</span><span class="m">1200</span>
-o <span class="nv">disable_dns_lookups</span><span class="o">=</span>yes
<span class="c1"># Filtro para Amavis/Postfix</span>
<span class="m">127</span>.0.0.1:10025 inet n - y - - smtpd
-o <span class="nv">content_filter</span><span class="o">=</span>
-o <span class="nv">local_recipient_maps</span><span class="o">=</span>
-o <span class="nv">relay_recipient_maps</span><span class="o">=</span>
-o <span class="nv">smtpd_restriction_classes</span><span class="o">=</span>
-o <span class="nv">smtpd_client_restrictions</span><span class="o">=</span>
-o <span class="nv">smtpd_helo_restrictions</span><span class="o">=</span>
-o <span class="nv">smtpd_sender_restrictions</span><span class="o">=</span>
-o <span class="nv">smtpd_recipient_restrictions</span><span class="o">=</span>permit_mynetworks,reject
-o <span class="nv">mynetworks</span><span class="o">=</span><span class="m">127</span>.0.0.0/8
-o <span class="nv">strict_rfc821_envelopes</span><span class="o">=</span>yes
</code></pre></div>
<p>Ahora solo hay que indicar en el otro archivo de configuración de Postfix (<code>main.cf</code>) que el filtro de contenidos que vamos a usar está en dicho puerto:</p>
<div class="highlight"><pre><span></span><code><span class="nv">virtual_mailbox_maps</span> <span class="o">=</span> mysql:/etc/postfix/mysql/mysql_virt.cf
<span class="nv">virtual_maps</span> <span class="o">=</span> mysql:/etc/postfix/mysql/alias.cf
<span class="nv">local_transport</span> <span class="o">=</span> virtual
<span class="c1"># Amavis</span>
<span class="nv">content_filter</span> <span class="o">=</span> smtp-amavis:<span class="o">[</span><span class="m">127</span>.0.0.1<span class="o">]</span>:10024
<span class="nv">soft_bounce</span> <span class="o">=</span> no
<span class="nv">unknown_local_recipient_reject_code</span> <span class="o">=</span> <span class="m">550</span>
</code></pre></div>
<p>Ahora que está todo configurado, iniciamos los servicios que acabamos de instalar y configurar, y reiniciamos Postfix:</p>
<div class="highlight"><pre><span></span><code>$ sudo /etc/init.d/clamav-daemon start
$ sudo /etc/init.d/clamav-freshclam start
$ sudo /etc/init.d/spamassassin start
$ sudo /etc/init.d/amavis start
$ sudo /etc/init.d/postfix restart
</code></pre></div>
<p>Si hubiera algún problema o alguno de los demonios no se iniciara correctamente, ya sabes que toda la información de los procesos relacionados con el email está en <code>/var/log/mail.log</code> (si usas Debian/Ubuntu) o en <code>/var/log/maillog</code> (si usas Redhat/CentOS).</p>
<p>Pero contra el SPAM nunca se está completamente protegido... y obviamente Spamassasin nos ayudará a frenarlo, pero no lo evitará al 100%. Por lo tanto, aún hay más cosas que podemos hacer para completar nuestro sistema.</p>
<h3>PostGrey</h3>
<p>La primera de ellas se llama <a href="http://postgrey.schweikert.ch/">PostGrey</a>, y aunque hay gente que piensa que es tan efectiva como molesta para el usuario, es una de las mejores medidas que podemos implantar para reducir la cantidad de spam que llegue a nuestros buzones.</p>
<p>El protocolo de envío de correo establece que si se intenta enviar un email a un servidor, y éste responde con un código de error 45x (error temporal), se debe intentar volver a enviar el email pasado un tiempo (normalmente 5 minutos después).</p>
<p>La mayoría de los servidores de correo que utilizan los <em>spamers</em> no están configurados correctamente, y NO reintentan el envío de un email si éste falla.</p>
<p>Postgrey hará que siempre que nos llegue un email de un destinatario desconocido, se rechace el email y se responda con un error 45x. Si el servidor está correctamente configurado, reintentará de nuevo la entrega pasados unos minutos... y cuando lo haga, Postgrey lo aceptará. Además, se guardará dicho remitente en una base de datos propia de Postgrey, por lo que a partir de ese momento se aceptarán los emails de éste remitente a la primera, sin necesidad de volver a rechazarlos.</p>
<p>Puede que sea un poco molesto en alguna circunstancia (sobre todo si necesitamos recibir un email urgente de alguien que no nos ha escrito antes) ya que tardaremos más de lo normal en recibir dicho email, pero gracias a esto evitaremos recibir un montón de spam.</p>
<p>La instalación de Postgrey es igual de sencilla que el resto:</p>
<p>En <strong>Debian/Ubuntu</strong>:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install postgrey
</code></pre></div>
<p>En <strong>RedHat/CentOS</strong>:</p>
<div class="highlight"><pre><span></span><code>$ sudo yum install postgrey
</code></pre></div>
<p>Una vez instalado, el puerto por defecto en el que estará <em>escuchando</em> PostGrey es el 10023, así que tenemos que añadirlo como una nueva <em>restricción</em> en nuestro Postfix (en el mismo sitio donde anteriormente habíamos configurado las <em>blacklists</em> y el resto de restricciones):</p>
<div class="highlight"><pre><span></span><code><span class="nv">smtpd_recipient_restrictions</span> <span class="o">=</span> regexp:/etc/postfix/blacklist,
permit_mynetworks,
reject_invalid_hostname,
reject_non_fqdn_sender,
reject_non_fqdn_recipient,
reject_unknown_sender_domain,
reject_unknown_recipient_domain,
permit_sasl_authenticated,
reject_unauth_destination,
check_policy_service inet:127.0.0.1:10023,
regexp:/etc/postfix/blacklist,
permit
</code></pre></div>
<p>Ya podemos iniciar el demonio de PostGrey:</p>
<div class="highlight"><pre><span></span><code>$ sudo /etc/init.d/postgrey start
</code></pre></div>
<p>Y reiniciar Postfix para que tenga en cuenta la nueva restricción:</p>
<div class="highlight"><pre><span></span><code>$ sudo /etc/init.d/postfix restart
</code></pre></div>
<p>A partir de éste momento, cada vez que nos llegue un email, Postfix lo rechazará temporalmente para que el servidor de correo del remitente lo intente de nuevo pasados unos minutos.</p>
<p>Si transcurrido ese tiempo el servidor de correo de dicho remitente reintenta el envío de nuevo, Postfix lo aceptará normalmente, y marcará en su base de datos interna que ya no será necesario volver a rechazar correos de ese destinatario en el futuro.</p>
<p>Si alguna vez migrais el servidor de correo a otro servidor diferente, y quereis conservar ésta base de datos interna con los datos que PostGrey haya conseguido hasta ese momento, basta con que migreis también el contenido de <code>/var/lib/postgrey/</code> al nuevo servidor.</p>
<p>Y por supuesto, podéis especificar también excepciones (<em>whitelists</em>) para que PostGrey no rechace los emails ni siquiera la primera vez editando los archivos <code>/etc/postgrey/whitelist_recipients</code> y <code>/etc/postgresy/whitelist_clients</code>.</p>
<p>No olvideis que ~~podéis~~ debéis revisar el <em>log</em> del servidor de correo a menudo por si hubiera algún problema o algún comportamiento no deseado, que como ya sabeis se encuentra en <code>/var/log/mail.log</code> si usais Debian o similares, y en <code>/var/log/maillog</code> si usais CentOS/RedHat.</p>
<p>Y para poder dar por terminadas las configuraciones relativas al <em>spam</em>, solo nos faltaría implementar el sistema SPF en nuestro servidor:</p>
<h3>SPF (Sender Policy Framework)</h3>
<p>El sistema <a href="http://es.wikipedia.org/wiki/Sender_Policy_Framework">SPF</a> intenta disminuir el spam evitando la falsificación de las direcciones de correo electrónico de los mensajes. Y su principal implementación es el proyecto <a href="https://www.open-spf.org/">OpenSPF</a>.</p>
<p>Bajo mi punto de vista es una medida de seguridad MUY buena, y realmente sería útil si <strong>todos</strong> los servidores de correo lo utilizaran de forma predeterminada y obligatoria... pero por desgracia no lo hacen, y lo que es aún peor, muchos de los <em>administradores de sistemas</em> que gestionan servidores de correo ni siquiera saben de su existencia.</p>
<p>Su funcionamiento es muy simple: dado que la dirección del <em>remitente</em> de un email viene indicada únicamente en una de las cabeceras del email, cualquiera puede manipular dicha cabecera y enviar un email con un remitente falso.</p>
<p>No se necesitan grandes conocimientos ni herramientas avanzadas, cualquier <a href="http://es.wikipedia.org/wiki/Lamer_%28inform%C3%A1tica%29">lamer</a> puede enviar un email a cualquier persona haciéndose pasar por cualquiera. Y los spamers utilizan esto a diario para simular emails de personas conocidas o de sitios webs de interés, de forma que aumentan las posibilidades de que al recibir esos emails, <em>caigamos en la trampa</em> y los leamos.</p>
<p>SPF intenta evitar esto, rechazando los emails que provengan de servidores de correo que NO son los servidores de correo <em>oficiales</em> de dicho dominio. Es decir, si el servidor de correo de <em>pornohardware.com</em> tiene la IP 1.2.3.4 (por ejemplo), si un servidor de correo recibe un email de una dirección del tipo <em>@pornohardware.com</em> que proviene de la IP 5.6.7.8, automáticamente lo rechazará porque asumirá que no se trata de un email legítimo. SPF da por sentado que para enviar emails del dominio <em>@pornoharware.com</em> únicamente se van a utilizar unos servidores determinados (los que el Todopoderoso administrador de <em>pornohardware.com</em> haya configurado), por lo que si un email proviene de otro sevidor dirente, muy seguramente se trate de un email NO legítimo (spam).</p>
<p>El sistema SPF consta de 2 partes:</p>
<ul>
<li>Incluir un registro en el DNS de nuestro dominio que sirva para que los demás servidores de correo sepan cuales son nuestros servidores legítimos, y rechacen emails que (aunque parezca que provinien de nosotros) hayan sido enviados desde otros servidores.</li>
<li>Configurar nuestro servidor de correo para que cuando nos llegue un email, comprobemos en el DNS del dominio del remitente del email si efectivamente dicho mensaje proviene de un servidor autorizado o no.</li>
</ul>
<p>El paso 1 es tan sencillo como incluir un registro de tipo <a href="http://es.wikipedia.org/wiki/Domain_Name_System#Tipos_de_registros_DNS">TXT</a> que indique quiénes son los servidores que pueden enviar nuestros emails.</p>
<p>La sintaxis de estos registros es muy sencilla:</p>
<ul>
<li><strong>v</strong>: Con éste parámetro se indica la versión de SPF (que actualmente es la 1).</li>
<li><strong>mx</strong>: Con éste parámetro se indica que los servidores de correo configurados en el registro de tipo <a href="http://es.wikipedia.org/wiki/Domain_Name_System#Tipos_de_registros_DNS">MX</a> de nuestro dominio están autorizados a enviar email de dicho dominio.</li>
<li><strong>ptr</strong>: Con éste parámetro se indica que los servidores correspondientes a subdominios de nuestro dominio están autorizados a enviar nuestros emails. Es decir, cualquier servidor cuyo nombre sea *.pornohardware.com.</li>
<li><strong>all</strong>: Dependiendo del código que indiquemos aquí, los servidores serán más o menos estrictos a la hora de recibir nuestros correos. Los posibles valores de éste parámetro son:<ul>
<li><strong>-all</strong>: NO se deben aceptar emails nuestros que provengan de servidores que NO son los especificados en el registro SPF de nuestro DNS.</li>
<li><strong>~all</strong>: Se deben aceptar emails nuestros aunque provengan de servidores que NO son los especificados en el registro SPF de nuestro DNS, pero marcando dichos emails como <strong>posible SPAM</strong>, de forma que sea los clientes de correo de los usuarios finales quiens puedan establecer reglas para aceptar o no dichos emails.</li>
<li><strong>?all</strong>: Se deben aceptar emails nuestros aunque provengan de servidores que NO son los especificados en el registro SPF de nuestro DNS.</li>
</ul>
</li>
</ul>
<p>Vistas éstas opciones, un ejemplo de registro TXT para el SPF del dominio <em>pornohardware.com</em> sería:</p>
<div class="highlight"><pre><span></span><code>pornohardware.com. IN TXT <span class="s2">"v=spf1 mx a:mail.ejemplo1.com a:mail.ejemplo2.com -all"</span>
</code></pre></div>
<p>Éste registro especificaría como válidos para enviar emails de nuestro dominio a aquellos servidores que estén definidos en los registros MX de nuestro dominio, y también los servidores <em>mail.ejemplo1.com</em> y <em>mail.ejemplo2.com</em>. Y al haber especificado <code>-all</code>, aquellos servidores que reciban un email proveniente de un servidor <strong>diferente</strong> a los que acabamos de mencionar, deben RECHAZAR dicho email.</p>
<p>Existen muchos servicios en Internet que os pueden ayudar a configurar <em>online</em> el registro SPF de vuestro dominio, como por ejemplo <a href="http://www.spfwizard.net/es/">SPF Wizard</a>.</p>
<p>De ésta forma hemos configurado nuestro DNS para que los demás servidores de correo del mundo sepan cuáles son nuestros servidores... pero ahora tenemos que hacer que nuestro servidor haga esa misma comprobación cuando llegue un email de los demás, y rechazar dichos emails si hubieran sido enviados por servidores distintos a los que esos dominios hayan <em>autorizado</em>.</p>
<p>Para eso necesitamos <code>postfix-policyd-spf-python</code> o <code>postfix-policyd-spf-perl</code>, un programa escrito en <a href="https://www.python.org/">Python</a> o <a href="http://www.perl.org/">Perl</a> respectivamente, y que permite a Postfix consultar el registro SPF del dominio de los emails que llegan a nuestro servidor para determinar la acción a realizar en cada caso.</p>
<p>En distribuciones basadas en Redhat/CentOS no existe una versión precompilada disponible en los repositorios oficiales, por lo que debereis descargarlo desde <a href="https://www.open-spf.org/Software">https://www.open-spf.org/Software</a> e instalarlo de forma manual (únicamente hay que copiarlo en el directorio <em>apropiado</em>, como <code>/usr/bin</code> o algo similar).</p>
<p>En distribuciones basadas en <strong>Debian/Ubuntu</strong>, como siempre es tan fácil como ejecutar:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install postfix-policyd-spf-python
</code></pre></div>
<p>Después, editamos de nuevo el archivo <code>master.cf</code> de Postfix, y lo incluimos justo después de la configuración que habíamos creado para Amavis:</p>
<div class="highlight"><pre><span></span><code><span class="c1"># Filtro para Amavis/Postfix</span>
<span class="m">127</span>.0.0.1:10025 inet n - y - - smtpd
-o <span class="nv">content_filter</span><span class="o">=</span>
-o <span class="nv">local_recipient_maps</span><span class="o">=</span>
-o <span class="nv">relay_recipient_maps</span><span class="o">=</span>
-o <span class="nv">smtpd_restriction_classes</span><span class="o">=</span>
-o <span class="nv">smtpd_client_restrictions</span><span class="o">=</span>
-o <span class="nv">smtpd_helo_restrictions</span><span class="o">=</span>
-o <span class="nv">smtpd_sender_restrictions</span><span class="o">=</span>
-o <span class="nv">smtpd_recipient_restrictions</span><span class="o">=</span>permit_mynetworks,reject
-o <span class="nv">mynetworks</span><span class="o">=</span><span class="m">127</span>.0.0.0/8
-o <span class="nv">strict_rfc821_envelopes</span><span class="o">=</span>yes
<span class="c1"># postfix-policyd-spf-python</span>
policyd-spf unix - n n - - spawn
<span class="nv">user</span><span class="o">=</span>nobody <span class="nv">argv</span><span class="o">=</span>/usr/bin/policyd-spf
</code></pre></div>
<p>Y por último, editamos también el archivo <code>main.cf</code> para indicar a Postfix que use el <em>filtro</em> que acabamos de configurar (justo en la sección de <em>restricciones</em> que habíamos utilizado para añadir el filtro de PostGrey):</p>
<div class="highlight"><pre><span></span><code><span class="nv">smtpd_recipient_restrictions</span> <span class="o">=</span> regexp:/etc/postfix/blacklist,
permit_mynetworks,
reject_invalid_hostname,
reject_non_fqdn_sender,
reject_non_fqdn_recipient,
reject_unknown_sender_domain,
reject_unknown_recipient_domain,
permit_sasl_authenticated,
reject_unauth_destination,
check_policy_service inet:127.0.0.1:10023,
check_policy_service unix:private/policyd-spf,
regexp:/etc/postfix/blacklist,
permit
</code></pre></div>
<p>Reiniciamos Postfix, y ya tenemos nuestro servidor preparado para hacer frente al maldito spam!</p>
<div class="highlight"><pre><span></span><code>$ sudo /etc/init.d/postfix restart
</code></pre></div>
<h2>Estadísticas y monitorización<a name="stats"></a></h2>
<p>Ahora que ya tenemos el servidor completo funcionando al 100% no podemos <em>abandonarlo</em> a su suerte y esperar que siga funcionando durante el resto de nuestras vidas sin ni siquiera dedicarle un mínimo de atención. No me refiero a que haya que estar pendiente de él cada día, pero sí que conviene al menos tener monitorizados algunos de sus valores, sobre todo a la hora de identificar posibles <a href="https://es.wikipedia.org/wiki/Cuello_de_botella">cuellos de botella</a> o picos de actividad que puedan darnos algún indicativo de que algo no va bien, o de que necesitamos ampliar el <em>hardware</em> de nuestros sistemas para hacer frente a la demanda...</p>
<p>Dejando al margen las recomendaciones obvias sobre monitorización propia de los servicios de nuestro sistema (me refiero a algún software para detectar y avisar si alguno de ellos cae, tipo <a href="http://www.nagios.org/">Nagios</a> o similar) lo que pretendo explicar es la monitorización del USO que se le da a nuestro sistema.</p>
<p>Los 3 principales programas que yo conozco y suelo utilizar para monitorizar el uso de mis servidores de correo son:</p>
<ul>
<li><strong>mailgraph</strong>: Éste programa muestra gráficas en tiempo real sobre el uso de Postfix, tales como emails recibidos, emails enviados, etc. y genera gráficas con la información diaria, semanal, mensual y anual.</li>
<li><strong>queuegraph</strong>: Lo mismo que el anterior, pero con información acerca de la cola de mensajes (número de mensajes encolados, mensajes mensajes enviados, etc).</li>
<li><strong>couriergraph</strong>: Lo mismo que los dos anteriores, pero con información sobre las conexiones a Courier (conexiones IMAP, conexiones POP, etc).</li>
</ul>
<p>Los 3 programas son muy parecidos, y se basan en RDD para almacenar la información, por lo que no necesitan servidores de base de datos a los que conectarse ni tienen apenas ninguna dependencia. Simplemente se instalan en el mismo servidor donde están los servicios que queremos monitorizar, y desde un navegador accedemos a una URL concreta para ver las gráficas generadas.</p>
<p>La instalación, como siempre, no puede ser más sencilla en distribuciones basadas en <strong>Debian/Ubuntu</strong>:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install mailgraph queuegraph couriergraph
</code></pre></div>
<p>Y en distribuciones basadas en <strong>Redhat/CentOS</strong>:</p>
<div class="highlight"><pre><span></span><code>$ sudo yum install mailgraph queuegraph couriergraph
</code></pre></div>
<p>En el caso de distribuciones basadas en Redhat/CentOS, quizás <code>couriergraph</code> no se encuentre en los repositorios oficiales (ahora mismo no lo está, aunque juraría que lo ha estado) por lo que si es vuestro caso, debereis instalarlo manualmente en lugar de a través de <code>yum</code>.</p>
<p>Una vez los hayais instalado, basta con abrir un navegador y acceder a dichos <a href="http://es.wikipedia.org/wiki/Interfaz_de_entrada_com%C3%BAn">CGIs</a> tecleando en la barra de direcciones: http://localhost/cgi-bin/mailgraph.cgi, http://localhost/cgi-bin/queuegraph.cgi o http://localhost/cgi-bin/couriergraph.cgi (en lugar de <code>localhost</code>, quizás en vuestro caso debais poner la dirección del servidor donde los hayais instalado).</p>
<p>Si lo habeis instalado bien, al acceder a esas URLs deberías ver algo parecido a esto:</p>
<h3>mailgraph:</h3>
<p><img class="center" src="/images/posts/mailserver/mailgraph.png"></p>
<h3>queuegraph:</h3>
<p><img class="center" src="/images/posts/mailserver/queuegraph.png"></p>
<h3>couriergraph:</h3>
<p><img class="center" src="/images/posts/mailserver/couriergraph.png"></p>
<p>Y con respecto a tener un informe más o menos detalladado sobre el número de emails que se han enviado/recibido, destinatarios que más correo han enviado/recibido, dias que más emails se han enviado/recibido, etc. yo recomiendo el programa <a href="http://www.enderunix.org/isoqlog/">Isoqlog</a>.</p>
<p>Con este software, y a base de la información que se obtiene del log del servidor (<code>/var/log/mail.log</code> o <code>/var/log/maillog</code>) se pueden generar informes bastante detallados y útiles sobre la actividad individual de cada usuario y obtener así una visión mucho más amplia del uso que se le da a nuestro servidor.</p>
<p>De nuevo la instalación es trivial en <strong>Debian/Ubuntu</strong>:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install isoqlog
</code></pre></div>
<p>Y para el resto de distribuciones, se puede descargar tanto el código fuente como <a href="http://es.wikipedia.org/wiki/RPM_Package_Manager">paquetes RPM</a> desde la web del proyecto: http://www.enderunix.org/isoqlog/</p>
<p>Una vez instalado, únicamente hay que definir un <a href="http://es.wikipedia.org/wiki/Cron_%28Unix%29">cron</a> para que genere los informes cada cierto tiempo. Yo lo suelo hacer cada 12 horas, así tengo los informes detallados actualizados 2 veces al día, pero realmente puedes ponerlo cuando quieras.</p>
<p>La configuración es extremadamente simple: basta con indicar en el archivo de configuración (generalmente <code>/etc/isoqlog/isoqlog.conf</code>) la ruta donde está el log del servidor de correo, el directorio donde queremos que se guarden los informes que se irán generando, el idioma en el que queremos dichos informes, etc. Y en el archivo <code>/etc/isoqlog/isoqlog.domains</code> únicamente indicamos la lista de dominios a los que nuestro servidor de correo prestará servicio (es decir, los dominios que habíamos configurado en las directivas <code>mydestination</code> y <code>relay_domains</code> del archivo <code>/etc/postfix/main.cf</code>)</p>
<ul>
<li>
<p>/etc/isoqlog/isoqlog.conf</p>
<div class="highlight"><pre><span></span><code><span class="o">#</span><span class="n">isoqlog</span> <span class="mi">2</span><span class="p">.</span><span class="mi">0</span> <span class="n">Configuration</span> <span class="n">file</span>
<span class="n">logtype</span> <span class="o">=</span> <span class="ss">"postfix"</span>
<span class="n">logstore</span> <span class="o">=</span> <span class="ss">"/var/log/mail.log"</span>
<span class="n">domainsfile</span> <span class="o">=</span> <span class="ss">"/etc/isoqlog/isoqlog.domains"</span>
<span class="n">outputdir</span> <span class="o">=</span> <span class="ss">"/var/www/reports"</span>
<span class="n">htmldir</span> <span class="o">=</span> <span class="ss">"/usr/share/isoqlog/htmltemp"</span>
<span class="n">langfile</span> <span class="o">=</span> <span class="ss">"/usr/share/isoqlog/lang/english"</span>
<span class="n">hostname</span> <span class="o">=</span> <span class="ss">"mail.pornohardware.com"</span>
<span class="n">maxsender</span> <span class="o">=</span> <span class="mi">100</span>
<span class="n">maxreceiver</span> <span class="o">=</span> <span class="mi">100</span>
<span class="n">maxtotal</span> <span class="o">=</span> <span class="mi">100</span>
<span class="n">maxbyte</span> <span class="o">=</span> <span class="mi">100</span>
</code></pre></div>
</li>
<li>
<p>/etc/isoqlog/isoqlog.domains</p>
<div class="highlight"><pre><span></span><code><span class="err">pornohardware.com</span>
<span class="err">pornosoftware.com</span>
</code></pre></div>
</li>
</ul>
<p>Para generar el informe de forma manual basta con ejecutar el comando:</p>
<div class="highlight"><pre><span></span><code>$ sudo isoqlog
</code></pre></div>
<p>Una vez generados, los informes son algo parecido a esto:</p>
<p><img class="center" src="/images/posts/mailserver/isoqlog_1.png">
<img class="center" src="/images/posts/mailserver/isoqlog_2.png"></p>
<p>Como veis la información que muestran todos estos sistemas de monitorización es MUY útil, por lo que sumado a la monitorización global del servidor (con <a href="http://cacti.net/">Cacti</a>, <a href="http://www.zabbix.com/">Zabbix</a> o similar) nos permitirán mantener nuestro recién instalado servidor en perfecto funcionamiento durante el tiempo que haga falta.</p>
<p>Y de momento aquí se acaba éste artículo, que ya va siendo hora!</p>
<p>Espero que toda ésta <em>chapa</em> que he escrito os sirva de ayuda a la hora de configurar vuestro propio servidor de correo, ya sea porque os lo han pedido en vuestra empresa o porque habeis decidido tener el control de vuestro propio correo personal, lo cual es una de las mejores cosas que podéis hacer en la vida si de verdad os preocupa lo más mínimo vuestra privacidad y la seguridad de vuestros datos y conversaciones. Por favor, no hagais como <em>la gran masa tonta</em> y delegueis la gestión de vuestro email a <strong>ladrones y estafadores con doble moralidad</strong> (como Google/Gmail y todas esas <em>grandes empresas</em>) que no dudarán en parsear, etiquetar y catalogar incluso vuestros emails más personales con la excusa de mostraros <em>publicidad más relevante</em> (como si además eso fuera algo <em>bueno</em>).</p>
<p>He tenido especial cuidado a la hora de enumerar los comandos, configuraciones, etc. y he ido contrastándolo paso a paso con mis actuales servidores de correo para verificar que toda la información que os he puesto es correcta... pero por supuesto he podido cometer algún fallo (ja-ja) xDDDD.</p>
<p>Si se ha dado éste remoto y extrañísimo caso, por favor, decírmelo (escribirlo en los comentarios del artículo) y lo corregiré lo antes posible.</p>
<p>Y por supuesto, no dudeis en distribuir y compartir ésta información con todo el mundo... pero por favor, citar siempre la fuente de éste artículo, que después de la cantidad de horas y trabajo que me ha costado escribirlo, al menos darme el reconocimiento apropiado! xDDD</p>
<p>Alaaaaaaaaaaaaaaaa</p>
<h2>Referencias<a name="refs"></a></h2>
<ul>
<li><a href="http://www.postfix.org/documentation.html">http://www.postfix.org/documentation.html</a></li>
<li><a href="http://www.courier-mta.org/status.html">http://www.courier-mta.org/status.html</a></li>
<li><a href="https://www.open-spf.org/">https://www.open-spf.org/</a></li>
<li><a href="https://whatismyipaddress.com/blacklist-check">https://whatismyipaddress.com/blacklist-check</a></li>
<li><a href="http://sopa.dis.ulpgc.es/ii-aso/portal_aso/leclinux/seguridad/pam/pam_doc.pdf">http://sopa.dis.ulpgc.es/ii-aso/portal_aso/leclinux/seguridad/pam/pam_doc.pdf</a></li>
</ul>Inicio automático de máquinas virtuales con XenServer2014-12-24T12:04:34+02:002015-01-01T11:03:39+02:00BhEaNtag:pornohardware.com,2014-12-24:/2014/12/24/inicio-automatico-de-maquinas-virtuales-con-xenserver/<p>Cuando se habla de virtualización a nivel <em>usuario</em>, la mayoría de la gente piensa en <a href="https://www.virtualbox.org/">Virtualbox</a> (que es una genial aplicación), y cuando se habla de virtualización a nivel <em>empresarial</em>, el software en el que casi todo el mundo piensa es <a href="http://www.vmware.com/es/">VMWare</a>.</p>
<p><img class="right" src="/images/logos/logo_citrix_xenserver.png"/>
Ambos son grandísimos productos, maduros y estables... pero desde que probé <a href="http://www.citrix.com/products/xenserver/overview.html?posit=glnav">XenServer</a>, éste genial sistema de virtualización de la empresa <a href="http://www.citrix.com/">Citrix</a> es el que más me gusta.</p>
<p>XenServer es (al igual que el resto de productos de Citrix) un software cerrado y de pago, pero también existe una version gratuita que se puede usar libremente en entornos de producción empresarial. Ésta versión gratuita únicamente tiene algunas limitaciones con respecto a la versión de pago, y una de ellas es precisamente la de configurar las máquinas virtuales para que se inicien automáticamente cuando se inicia el servidor.</p>
<p>Cuando se habla de virtualización a nivel <em>usuario</em>, la mayoría de la gente piensa en <a href="https://www.virtualbox.org/">Virtualbox</a> (que es una genial aplicación), y cuando se habla de virtualización a nivel <em>empresarial</em>, el software en el que casi todo el mundo piensa es <a href="http://www.vmware.com/es/">VMWare</a>.</p>
<p><img class="right" src="/images/logos/logo_citrix_xenserver.png">
Ambos son grandísimos productos, maduros y estables... pero desde que probé <a href="http://www.citrix.com/products/xenserver/overview.html?posit=glnav">XenServer</a>, éste genial sistema de virtualización de la empresa <a href="http://www.citrix.com/">Citrix</a> es el que más me gusta.</p>
<p>XenServer es (al igual que el resto de productos de Citrix) un software cerrado y de pago, pero también existe una version gratuita que se puede usar libremente en entornos de producción empresarial. Ésta versión gratuita únicamente tiene algunas limitaciones con respecto a la versión de pago, y una de ellas es precisamente la de configurar las máquinas virtuales para que se inicien automáticamente cuando se inicia el servidor.</p>
<p>Cuando tenemos un entorno de servidores virtuales, obviamente queremos que tras un reinicio del servidor principal donde éstos estan alojados, dichos servidores se inicien automáticamente... ya que de lo contrario tendríamos que acceder al servidor e ir <em>arrancando</em> las máquinas virtuales una a una de forma manual.</p>
<p>Por desgracia, a partir de la versión 6 de XenServer, la capacidad de configurar una máquina virtual como <em>autoarrancable</em> para que se inicie automáticamente ha sido eliminada de la versión gratuita. Supongo que es una decisión comercial para favorecer el uso de la versión de pago... pero en cualquier caso, únicamente se ha eliminado ésta funcionalidad desde el <em>cliente</em> de XenCenter, ya que es posible seguir utilizando ésta opción con un poco de configuración externa.</p>
<p>Para hacer ésto, hay que crear una <strong>vApp</strong>.</p>
<p>Una vApp es un grupo de máquinas virtuales que pueden ser administradas como una única entidad lógica, es decir, una agrupación de servidores.</p>
<p>Éste concepto fué introducido en la versión 6 de XenServer, y permite seleccionar un grupo de servidores virtuales, y asignar el orden en el que tienen que ir iniciándose cada uno de ellos cuando se inicie la vApp.</p>
<p><img class="center" src="/images/posts/xenserver/screenshot_01.png">
Cliente de XenCenter para <em>Güindous</em></p>
<p>Siento muchísimo tener que ilustrar éste artículo con capturas de pantalla del cliente de <em>Windows</em> (a mi también se me revuelve el estómago, lo siento), pero aunque existe una alternativa para GNU/Linux llamada <a href="http://sourceforge.net/projects/openxenmanager/">OpenXenManager</a>, lo cierto es que está aún <strong>muy</strong> verde... y no solo no permite aún utilizar la mayoría de las opciones de XenServer, sino que las que si permite, no funcionan del todo bien.</p>
<p>Espero que algún dia éste cliente sea lo suficientemente maduro como para poder reemplazar el cliente XenCenter de <em>Windows</em>... pero mientras tanto:</p>
<p><img class="center" src="/images/posts/xenserver/screenshot_02.png">
Crear un vApp con los servidores que queramos incluir en la secuencia de arranque</p>
<p>El primer paso es crear una vApp con los servidores que queramos incluir en la secuencia de inicio, y establecer el orden en el que queramos que se inicien, así como el tiempo que queremos que cada servidor <em>espere</em> antes de iniciarse (para dar tiempo a que se inicie correctamente el servidor anterior, por ejemplo):</p>
<p><img class="center" src="/images/posts/xenserver/screenshot_03.png">
Configuramos el orden en el que se iniciarán los servidores y el retardo entre el arranque de uno y de otro</p>
<p>Una vez tengamos la vApp creada y configurada, necesitamos saber su identificador (<a href="http://es.wikipedia.org/wiki/Universally_unique_identifier">UUID</a>), para lo cual lo más sencillo es ejecutar el comando <code>xe</code> (comando principal de XenServer) de ésta forma:</p>
<div class="highlight"><pre><span></span><code>$ sudo xe appliance-list
</code></pre></div>
<p>Lo que nos dará algo parecido a ésto:</p>
<div class="highlight"><pre><span></span><code> uuid ( RO): 6373fb13-520b-aafb-eae3-ea0cb47ca64a
name-label ( RW): Main vApp
name-description ( RW): vApp
VMs (SRO): 0e210b62-68ce-7d8f-ee61-7a8279cf7818
allowed-operations (SRO): clean_shutdown; hard_shutdown; shutdown
current-operations (SRO):
</code></pre></div>
<p>De cuya primera linea obtenemos el UUID de la vApp.</p>
<p>Ya solo nos quedará editar el archivo <code>/etc/rc.local</code> del servidor XenServer y añadir el comando para iniciar nuestra vApp:</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/bash</span>
touch /etc/boottime.stamp
/sbin/update-issue
clear </dev/tty1 >/dev/tty1
<span class="k">if</span> <span class="o">[</span> ! -e /etc/xensource/no_move_kernel_tty <span class="o">]</span>
<span class="k">then</span>
<span class="c1"># Put the kernel messages on tty2</span>
/usr/bin/openvt -c <span class="m">2</span> /bin/echo <span class="s2">"System Messages:"</span>
/opt/xensource/libexec/set-printk-console <span class="m">2</span>
<span class="k">fi</span>
<span class="c1"># Start the main vApp to boot the VMs</span>
xe appliance-start <span class="nv">uuid</span><span class="o">=</span>6373fb13-520b-aafb-eae3-ea0cb47ca64a
</code></pre></div>
<p>Y listo... cada vez que arranquemos nuestro servidor XenServer principal, se iniciará la vApp que hayamos definido, lo que iniciará los servidores virtuales que hayamos configurado en ella.</p>
<p>Espero que os haya resultado de utilidad!</p>
<p>Alaaaaaaaaaaaaaaaa</p>
<h2>Referencias</h2>
<ul>
<li><a href="http://error-capa8.blogspot.com.es/2013/06/xenserver-auto-iniciar-vm.html">http://error-capa8.blogspot.com.es/2013/06/xenserver-auto-iniciar-vm.html</a></li>
<li><a href="http://www.virtues.it/2012/01/howto-autostart-xs-vapp/comment-page-1/">http://www.virtues.it/2012/01/howto-autostart-xs-vapp/comment-page-1/</a></li>
<li><a href="http://databom.blogspot.fr/2012/07/xenserver-6-autostart-vms-or-vapps.html">http://databom.blogspot.fr/2012/07/xenserver-6-autostart-vms-or-vapps.html</a></li>
</ul>Promoción de Navidad de Leroy Merlin: Un buen ejemplo de como NO hacer las cosas2014-12-11T20:57:54+01:002014-12-11T20:57:54+01:00BhEaNtag:pornohardware.com,2014-12-11:/2014/12/11/promocion-de-navidad-de-leroy-merlin-un-buen-ejemplo-de-como-no-hacer-las-cosas/<p><img class="right" src="/images/posts/sms_pdu/leroy_merlin.png"/>
Dice mi mujer que cada vez tengo peor carácter, y que al final me acabaré convirtiendo en el típico viejo amargado que protesta por todo... y quizás tenga razón, pero no puedo evitarlo: no soporto la <em>chulería</em> ni los malos modales de la gente, y menos aún cuando no solo NO tienen razón sino que además se supone que deberían ser amables con sus propios clientes.</p>
<p>Pero empecemos desde el principio: os voy a contar la breve historia de lo que me sucedió la semana pasada con ésta conocida cadena de <em>herramientas y bricolaje</em>, y de cómo conseguí lo que me correspondía usando nuestra <strong>Querida Tecnología(TM)</strong>.</p>
<p><img class="right" src="/images/posts/sms_pdu/leroy_merlin.png">
Dice mi mujer que cada vez tengo peor carácter, y que al final me acabaré convirtiendo en el típico viejo amargado que protesta por todo... y quizás tenga razón, pero no puedo evitarlo: no soporto la <em>chulería</em> ni los malos modales de la gente, y menos aún cuando no solo NO tienen razón sino que además se supone que deberían ser amables con sus propios clientes.</p>
<p>Pero empecemos desde el principio: os voy a contar la breve historia de lo que me sucedió la semana pasada con ésta conocida cadena de <em>herramientas y bricolaje</em>, y de cómo conseguí lo que me correspondía usando nuestra <strong>Querida Tecnología(TM)</strong>.</p>
<p>Mi afición por <em>cacharrear</em> no se limita únicamente al hardware, el software y a las <em>cosas con cables</em>, sino que también disfruto con el bricolaje de todo tipo y a todos los niveles... y no me refiero únicamente a poner una lámpara o a colocar un mueble de IKEA, sino a levantar tabiques, realizar la instalación eléctrica completa de un local comercial o cualquier cosa que se me ponga por delante y me empeñe en hacer.</p>
<p>Seguro que muchos <em>profesionales</em> lo harían mejor y más rápido... pero la mayoría de las veces prefiero tardar un poco más (e incluso gastar un poco más de dinero en materiales y herramientas) solo por el hecho de "hacer las cosas yo mismo" y de aprender cómo se hacen.</p>
<p>El caso es que debido a un proyecto de éste tipo (y bastante grande, por cierto) en el que me vi inmerso el año pasado, durante todos éstos meses he gastado mucho dinero en <a href="http://www.leroymerlin.es/">Leroy Merlin</a> en la compra de herramientas y materiales de construcción (sé que hay sitios especializados mejores y más baratos, pero ninguno de ellos me pillaba NADA bien... y mi ya de por si escaso tiempo también vale dinero).</p>
<p>Cuando hablo de "mucho dinero" me refiero a unos cuantos miles de euros... y seguro que tienen clientes mucho mejores que yo, pero creo que ésta es una cifra nada despreciable... por lo que no me sorprendí cuando hace un par de semanas recibí un <a href="https://es.wikipedia.org/wiki/Sms">SMS</a> en el que me decian que con motivo de la Navidad me regalaban una <a href="https://es.wikipedia.org/wiki/Euphorbia_pulcherrima">Flor de Pascua</a> (la típica <em>poinsetia</em> de todos los años).</p>
<p>El SMS decía textualmente:</p>
<div class="highlight"><pre><span></span><code>PUBLI: Del 1 al 8 Dic por ser Socio te regalamos una Flor de Pascua.
Descúbrelo en http://lmes.es/florpascua Socio 8407xxxxxxxxxxxx
lmes.es/bajasms
</code></pre></div>
<p>La página que habían hecho informando de éste <em>regalo</em> era ésta:</p>
<p><img class="center" src="/images/posts/sms_pdu/promocion_leroymerlin.jpg"></p>
<p>No es que tuviera un especial interés en tener dicha planta (la cual además no cuesta más de 2 o 3 €) pero aprovechando que DE NUEVO tenía que ir a uno de sus establecimientos a comprar más cosas, fuí al mostrador de [INFORMACIÓN] a recoger dicha planta (que para una cosa que me regalan después del dineral invertido, encima no iba a rechazarla! xDDD)</p>
<p>Me acerqué al mostrador y pregunté a una de las chicas que había allí. Dije que <em>había recibido el SMS de la Flor de Pascua, y que quería saber dónde tenía que ir a recogerla</em>.</p>
<p>Hasta ahí todo bien, verdad? Pues no... para mi sorpresa, y con un tono chulesco y de bastante malas formas, me dice que <em>la deje mi movil para ver el SMS!!</em></p>
<p>"<em>Perdona???</em>" - contesté.</p>
<p>"<em>Si, me tienes que enseñar el SMS para ver que es cierto, y borrarlo delante mio si quieres que te demos la planta</em>" - respondió ella.</p>
<p>Así que me armé de paciencia y respondí - "<em>No acostumbro a guardar los SMS, señorita... según los leo los elimino... así que si necesitas comprobar que efectivamente me corresponde, aquí tienes mi tarjeta de socio de Leroy Merlín y mi DNI (que es lo que VOSOTROS MISMOS indicais en vuestra página web que debo entregar para recoger la planta"</em>.</p>
<p>"<em>Pues o me enseñas el SMS o no hay planta</em>" - volvió de nuevo a repetir con muy mal tono.</p>
<p>Yo no me podía creer que una empresa como Leroy Merlín fuera tan <strong>chapucera e ignorante</strong> como para hacer algo así... pero de nada sirvieron mis explicaciones, ni mi razonamiento sobre porqué era una estupidez que pidieran ver el SMS teniendo la tarjeta de socio, etc, etc... pero dió igual, la chica se cerró en banda y ni siquiera quiso seguir hablando. Me dijo que NO había planta sin que ella viera el SMS y lo borrara delante suyo, así que no me quedó más remedio que irme sin la puñetera planta...</p>
<p>Y si yo fuera una persona normal, ahí hubiera terminado la historia: volviendo a casa con las manos vacías y de mal humor por el tono con el que me acababan de atender...</p>
<p>...pero no es el caso, por lo que cuando se me pasó un poco el cabreo, me puse a buscar información sobre los dichosos SMS, su manipulación y las formas que hay de "falsificarlos".</p>
<p>Ni esa mierda de protocolo prehistórico en desuso ni la maldita cerda maleducada que "<em>me atendió</em>" iban a impedir que consiguiera mi planta! Faltaría más! xDDDD</p>
<p>Hasta ese momento no me había puesto nunca a investigar en profundidad acerca del servicio de mensajes cortos (SMS) más allá del uso normal que solemos (solíamos) darle... y lo cierto es que o bien existe poca documentación sobre el tema o bien yo no la supe encontrar, así que me costó un poco documentarme sobre el tema... pero después de unas horas de lectura, al final entendí más o menos su funcionamiento.</p>
<h2>Un poco de teoría acerca de los SMS</h2>
<p>Un mensaje SMS, como casi todos los mensajes que existen, no es más que uno o más "paquetes" de datos con diferentes "campos".</p>
<p>Uno de dichos campos es el "remitente", por lo tanto, <em>solo</em> hay que manipular ese campo para poder enviar mensajes suplantando la identidad que queramos, en éste caso la de <em>Leroy Merlín</em>.</p>
<p>Hay dos tipos de mensajes SMS:</p>
<ul>
<li>Modo texto</li>
<li>Modo PDU (Protocol Description Unit)</li>
</ul>
<p>La forma habitual de uso es la segunda (PDU), ya que en ella los mensajes se tratan como una cadena de carácteres de cuya codificación se obtiene el SMS en modo texto. Además, en una cadena PDU no solo va el contenido del mensaje, sino que se incluyen muchos otros datos, como por ejemplo el número del Centro de Servicio SMS (el "<em>servidor</em>" que gestionará el envio), la hora de llegada, <strong>información sobre el remitente del mensaje</strong>, caducidad de dicho mensaje, etc, etc.</p>
<p>La estructura típica de una trama SMS PDU sería algo así:</p>
<p><img class="center" src="/images/posts/sms_pdu/sms_01.png"></p>
<p>Cada campo corresponde a:</p>
<ul>
<li>
<p><strong>DCS</strong>: Número del Centro de Servicio. Éste campo está a su vez está dividido en:</p>
<p><img src="/images/posts/sms_pdu/sms_02.png"></p>
<ul>
<li><strong>LN</strong>: Longitud del número del Centro de Servicio, expresada como el número de octetos (pares de carácteres hexadecimales o decimales) que forman el nº.</li>
<li>
<p><strong>TTL</strong>: Tipo de llamada al Centro de Servicio, que puede ser:</p>
<ul>
<li>Nacional: Valor 81</li>
<li>Internacional: Valor 91<br /><br /></li>
</ul>
</li>
<li>
<p><strong>Nº CS</strong>: Número del centro de servicio, el cual debe ir en orden inverso por pares. Por ejemplo, para indicar el número 123456789 habría que poner 214365798. Y además, si el número de dígitos de dicho número es impar, hay que añadir una F en medio del último par de dígitos. Por lo tanto, el número final quedaría así: 21436579F8</p>
</li>
<li>Por lo tanto, teniendo en cuenta éstos 3 campos, si nuestro Centro de Servicio estuviera en el mismo pais desde el que estamos escribiendo, y su número fuera el +34123456789, el valor del campo <strong>DCS</strong> de la trama del SMS sería: 06814321436579F8<br /><br /></li>
</ul>
</li>
<li>
<p><strong>TIPO PDU</strong>: Tipo Protocolo de la Unidad de Datos</p>
<p><img src="/images/posts/sms_pdu/sms_03.png"></p>
<ul>
<li><strong>PC</strong>: Path contestación (0 -> No, 1 -> Si)</li>
<li><strong>CD</strong>: Cabecera de datos (0 -> Sin, 1 -> Con)</li>
<li><strong>PRE</strong>: Petición de reporte de estado (0 -> No, 1 -> Si)</li>
<li><strong>PV</strong>: Campo periodo vigencia presente</li>
<li><strong>RD</strong>: Permitir que el centro de Servicio acepte un <em>SMS-SUBMIT</em> para un mensaje que todavía está en el centro (0 -> Si, 1 -> No)</li>
<li><strong>TIPO</strong>: 0 1 Mensaje de envío<br /><br /></li>
</ul>
</li>
<li>
<p><strong>DD</strong>: Dirección del destinatario del mensaje. Se rellena igual que el campo <strong>DCS</strong> (Número del Centro de Servicio), pero poniendo el número del destinatario en lugar del número de dicho centro.</p>
</li>
<li><strong>PID</strong>: Protocolo de identificación</li>
<li><strong>NR</strong>: Número de referencia</li>
<li><strong>COD</strong>: Codificación de la trama de datos. Es decir, si la trama está codificada a 7 bits o 8 bits, y también indica el tipo de SMS (para mensajes SMS tipo <em>flash</em>, por ejemplo)</li>
</ul>
<div class="highlight"><pre><span></span><code>0000 0 0 00 7 bits
1111 0
0 7 bits
1 8 bits
00 Mensaje clase 0 (flash)
01 Mensaje clase 1 ME
10 Mensaje clase 2 SIM
11 Mensaje clase 3 TE
</code></pre></div>
<ul>
<li>
<p><strong>PV</strong>: Periodo de vigencia del mensaje (caducidad):</p>
<ul>
<li>0 a 143 -> (PV+1)*5 minutos</li>
<li>144 a 167 -> 12horas+(PV-143)*30 minutos</li>
<li>168 a 196 -> (PV-1) *1 día</li>
<li>197 a 255 -> (PV-192)*1 semana</li>
<li>Ejemplo AA: (AA=170-> 170-166=4 * 1 día=4 días )<br /><br /></li>
</ul>
</li>
<li>
<p><strong>LD</strong>: Longitud de los datos. Por ejemplo, si el mensaje está formado por la cadena C8 27 33 08, éste campo se rellenará con 04, ya que hay 4 octetos de 2 carácteres hexadecimales.</p>
</li>
<li><strong>DATOS</strong>: Aquí va el texto del mensaje que estemos enviando. Un ejemplo para que quede más claro cómo se rellenaría éste campo (con codificación de 7 bits):</li>
</ul>
<p>Supongamos que el mensaje que queremos enviar es la palabra <em>HOLA</em>:</p>
<table>
<thead>
<tr>
<th align="left"> </th>
<th align="center">H</th>
<th align="center">O</th>
<th align="center">L</th>
<th align="center">A</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">Hex</td>
<td align="center">48</td>
<td align="center">4F</td>
<td align="center">4C</td>
<td align="center">41</td>
</tr>
<tr>
<td align="left">Bin</td>
<td align="center">1001000</td>
<td align="center">1001111</td>
<td align="center">1001100</td>
<td align="center">1000001</td>
</tr>
</tbody>
</table>
<p>Para transformarlo a octetos se toma el número de caracteres de la siguiente letra que nos falten para llegar a 8, cuando se hayan tomado caracteres de una letra para la anterior, esta se queda sin esos caracteres y los debe tomar de la siguiente letra.</p>
<table>
<thead>
<tr>
<th align="center"> </th>
<th align="center"> </th>
<th align="center"> </th>
<th align="center"> </th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">1 1001000</td>
<td align="center"><strong>00</strong> 100111 ~~1~~</td>
<td align="center"><strong>001</strong> 10011 ~~00~~</td>
<td align="center">1000 ~~001~~</td>
</tr>
<tr>
<td align="center">C8</td>
<td align="center">27</td>
<td align="center">33</td>
<td align="center">08</td>
</tr>
</tbody>
</table>
<p>El valor a enviar en éste campo del SMS para decir "<em>HOLA</em>" sería: <strong>C8273308</strong></p>
<p>Por lo tanto solo tendríamos que hacernos con un <a href="https://es.wikipedia.org/wiki/M%C3%B3dem">módem</a> <a href="https://es.wikipedia.org/wiki/Sistema_global_para_las_comunicaciones_m%C3%B3viles">GSM</a>, calcular los valores de la trama de nuestro SMS cambiando el remitente del mensaje, y enviar a través del modem <a href="https://es.wikipedia.org/wiki/Conjunto_de_comandos_Hayes">los comandos AT</a> necesarios para mandarnos el mensaje a nosotros mismos (pero de parte de Leroy Merlín) para que la <em>asquerosa</em> que nos atendió nos entregue la puñetera planta!</p>
<p>Pero aquí se nos presentaba otro problema... y es que aunque SI que tengo un modem GSM (el <a href="https://learn.adafruit.com/adafruit-fona-mini-gsm-gprs-cellular-phone-module/overview">maravilloso módulo FONA</a> de <a href="https://www.adafruit.com">Adafruit</a>, con el que estoy preparando un "servidor de alertas" propio del que ya escribiré algún artículo) aún no lo tengo terminado, ni sé para cuándo lo tendré...</p>
<p><img class="center" src="/images/posts/sms_pdu/fona.jpg">
Módem GSM FONA de Adafruit</p>
<p>Por lo tanto, me resulta imposible enviar yo mismo el SMS manipulado para simular que ha sido Leroy Merlin... pero no hay problema, ya que después de un rato buscando en Internet encontré varias empresas que se dedican sobre todo a las campañas de marketing por SMS (el insufrible <em>spam</em>, vaya), operadoras virtuales que permiten el envio de SMS online, etc. y algunas de ellas (muy pocas) permiten además personalizar el remitente de los mensajes! Eureka, ya lo tenemos!</p>
<h2>Envio de SMS personalizados desde Internet</h2>
<p>De entre todas las empresas que encontré, la inmensa mayoría no permitían personalizar el remitente... pero una pequeñísima minoría si que daba la opción, por lo que únicamente tenía que registrarme en sus respectivas páginas webs y rellenar un formulario para enviar los SMS.</p>
<p>Os recomiendo 2 de ellas:</p>
<ul>
<li>Gratuita -> <a href="http://www.esendex.es">Esendex</a>: No es que sea realmente un servicio gratuito, pero te dan 15 o 20 emails gratis para probar el servicio... y funcionan francamente bien.</li>
<li>De pago -> <a href="https://www.fakesms.es">FakeSMS</a>: Si prefieres un servicio de pago (por aquello de tener algo más de <em>seguridad</em> acerca de si los mensajes van a llegar o no), ésta web ofrece éste servicio perfectamente... y aunque no es barata, tampoco es excesivamente cara, ya que por 6 € podeis enviar 10 mensajes completamente personalizados. Aunque si sois de esos que teneis Facebook, Google+ y esas mierdas, <a href="https://www.fakemysms.es/gratuito">tienen una promoción</a> en la que si les haces click en <em>Me gusta</em> te regalan 1 SMS, así que también podeis probarlos de forma <em>gratuita</em> (únicamente vendiendo vuestra alma, <strong>de nuevo</strong>).</li>
</ul>
<p><img class="right" src="/images/posts/sms_pdu/sms_final.png">
Poco más hay que contar llegados a éste punto. Utilicé el servicio de envio de SMS personalizados de ambas webs (probé con ambas porque estuve haciendo diferentes cosas aparte de ésto) y me envié un SMS de parte de Leroy Merlin con el texto exacto que había en el SMS original, y quedó como podeis ver en la foto...</p>
<p>Por lo que ya con el SMS en mi movil, volví al Leroy Merlín y después de enseñarle y borrar el dichoso SMS que tanto me habia costado conseguir, obtuve al fin la dichosa plantita...</p>
<p>Por fin! Misión cumplida!</p>
<p>Y ya está? Fin de la historia?... pues no, obviamente no.</p>
<p>Si el primer dia que fuí a por mi merecidísima planta me la hubieran dado (tal y como tenían que haber hecho) no hubiera pasado nada, y todos estaríamos felices y contentos. Pero como ésto no fué así, y en vista de lo importante que eran éstos SMS para ellos, tan pronto llegué de nuevo a mi casa volví a enviarme otro SMS exactamente igual, y al dia siguiente fuí de nuevo a por otra planta (como si fuera la primera vez). Y me la dieron, por supuesto... para eso tenía el SMS y lo borraba delante suya! Así que estuve haciendo lo mismo durante casi todos los dias hasta que acabó la promoción, el pasado dia 8 de diciembre... (normalmente me atendian personas diferentes, pero alguna vez fué ella de nuevo, y ni se acordaba de mi)</p>
<p>¿Pensáis que soy una mala persona por <em>aprovecharme</em> de ellos? Pues os equivocais en todo, ya que ni yo me considero malo, ni vosotros deberíais considerarme persona... pero si <em>vas de guay</em> enviando SMS a tus <em>buenos clientes</em> para hacerles un regalo por Navidad, no les vengas con éstas estupideces cuando vayan a recogerlo.</p>
<p><img class="center" src="/images/posts/sms_pdu/flordepascua.jpg">
Solo os enseñaré una planta, que no quiero dejar pruebas gráficas del <em>vivero</em> que me pude haber montado a su costa xDDD</p>
<p>Ahora si... fin de la historia! Espero que al menos os haya servido no solo para descojonaros de mi y de mis <em>aventuras</em> en el <em>Mundo Real(TM)</em>, sino para aprender un poquito más acerca de los SMS: esos grandes desconocidos que tan buen servicio nos dieron en el pasado, y que ahora casi nadie utiliza ya...</p>
<p>Alaaaaaaaaaaaaaaaaaaaaa</p>
<h2>Referencias</h2>
<ul>
<li><a href="https://es.wikipedia.org/wiki/Servicio_de_mensajes_cortos">https://es.wikipedia.org/wiki/Servicio_de_mensajes_cortos</a></li>
<li><a href="http://www.iearobotics.com/personal/juan/doctorado/sms/sms.pdf">http://www.iearobotics.com/personal/juan/doctorado/sms/sms.pdf</a></li>
<li><a href="http://www.blogelectronica.com/sms-pdu/">http://www.blogelectronica.com/sms-pdu/</a></li>
</ul>Modificar el espacio reservado en particiones con sistemas de archivos ext3 o ext42014-12-08T00:23:20+01:002014-12-08T00:23:20+01:00BhEaNtag:pornohardware.com,2014-12-08:/2014/12/08/modificar-el-espacio-reservado-en-particiones-con-sistemas-de-archivos-ext3-o-ext4/<p><img class="left" src="/images/posts/hdd.png"/>
Si llevais algun tiempo usando <a href="http://www.gnu.org/gnu/linux-and-gnu.html">GNU/Linux</a> y sois mínimamente observadores, habreis notado que siempre que montais un nuevo disco y lo formateais utilizando <a href="http://es.wikipedia.org/wiki/Ext3">ext3</a> o <a href="http://es.wikipedia.org/wiki/Ext4">ext4</a> como sistema de archivos, nunca se obtiene el 100% de la capacidad del disco.</p>
<p>Ésto se debe a que éstos sistemas de archivos reservan por defecto un 5% de la capacidad total del disco para uso del usuario <em>root</em> (para que en caso de llenar por completo el disco, todavía podamos acceder y realizar tareas de administración) y para prevenir problemas derivados de la fragmentación de archivos.</p>
<p>Y hace años, cuando el tamaño de los discos duros era ínfimo (comparado con el tamaño actual, quiero decir) éste valor podía tener sentido... pero hoy en dia, teniendo discos <a href="http://es.wikipedia.org/wiki/Serial_ATA">SATA</a> de hasta 6 TB, reservar un 5% es una <em>salvajada</em> que solo serviría para <em>perder</em> 300 GB!</p>
<p><img class="left" src="/images/posts/hdd.png">
Si llevais algun tiempo usando <a href="http://www.gnu.org/gnu/linux-and-gnu.html">GNU/Linux</a> y sois mínimamente observadores, habreis notado que siempre que montais un nuevo disco y lo formateais utilizando <a href="http://es.wikipedia.org/wiki/Ext3">ext3</a> o <a href="http://es.wikipedia.org/wiki/Ext4">ext4</a> como sistema de archivos, nunca se obtiene el 100% de la capacidad del disco.</p>
<p>Ésto se debe a que éstos sistemas de archivos reservan por defecto un 5% de la capacidad total del disco para uso del usuario <em>root</em> (para que en caso de llenar por completo el disco, todavía podamos acceder y realizar tareas de administración) y para prevenir problemas derivados de la fragmentación de archivos.</p>
<p>Y hace años, cuando el tamaño de los discos duros era ínfimo (comparado con el tamaño actual, quiero decir) éste valor podía tener sentido... pero hoy en dia, teniendo discos <a href="http://es.wikipedia.org/wiki/Serial_ATA">SATA</a> de hasta 6 TB, reservar un 5% es una <em>salvajada</em> que solo serviría para <em>perder</em> 300 GB!</p>
<p>Si tuviéramos un servidor en el que la partición principal del sistema estuviera literalmente al 100% de su capacidad (debido por ejemplo a un proceso que estuviera <em>como loco</em> escribiendo <a href="http://es.wikipedia.org/wiki/Log_%28registro%29"><em>logs</em></a> en el disco, o algo así), podría suceder que no pudiéramos ni siquiera conectarnos al servidor para solucionar el problema, porque al no haber literalmente ni un <em>byte</em> libre, no podríamos iniciar sesión...</p>
<p>Ésta reserva de espacio se hace para evitar ese problema, pero como ya he comentado antes, no es necesario que sea tan grande.</p>
<p>Como casi todo en éste grandísimo sistema operativo, podemos modificar ésta candidad según nuestras necesidades, y para hacerlo, vamos a utilizar el comando <code>tune2fs</code>.</p>
<h2>Instalación</h2>
<p>Lo más normal es que ya tengais éste comando instalado en vuestras máquinas, ya que el paquete que lo contiene (<code>e2fsprogs</code>) suele instalarse por defecto en la mayoría de las distribuciones... pero si no fuera así, instalarlo es tan sencillo como:</p>
<p>En <strong>Debian/Ubuntu</strong>:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install e2fsprogs
</code></pre></div>
<p>En <strong>Redhat/CentOS</strong>:</p>
<div class="highlight"><pre><span></span><code>$ sudo yum install e2fsprogs
</code></pre></div>
<h2>Utilización</h2>
<p>Éste comando permite ajustar muchas cosas relativas al sistema de archivos de un disco, pero nosotros únicamente vamos a ajustar la cantidad de espacio que queremos reservar, por lo que La sintaxis es muy sencilla: basta con indicar el porcentaje a reservar y el dispositivo correspondiente al disco que estamos tratando.</p>
<p>Un ejemplo sería:</p>
<div class="highlight"><pre><span></span><code>$ sudo tune2fs -m <span class="m">0</span>.5 /dev/sdc1
</code></pre></div>
<p>El parámetro <code>-m</code> indica el porcentaje que queremos reservar en el disco. En éste caso, un 0.5%, que ya debería ser suficiente... aunque si preferís ser un poco más <em>conservadores</em>, podeis reservar el 1%.
Y <code>/dev/sdc1</code> hace referencia a la partición 1 del disco <em>sdc</em>.</p>
<p>Si no sabeis exactamente cuál es el dispositivo donde está el disco que quereis modificar, éste comando os mostrará un <em>resumen</em> de los discos que teneis montados en vuestro sistema:</p>
<div class="highlight"><pre><span></span><code>$ df -T <span class="p">|</span> awk <span class="s1">'{print $1,$2,$NF}'</span> <span class="p">|</span> grep <span class="s2">"^/dev"</span>
</code></pre></div>
<p>Espero que os resulte de utilidad!</p>
<p>Alaaaaaaaaaaaaaaaaaaaaaaaa</p>
<h2>Referencias</h2>
<ul>
<li><a href="https://wiki.archlinux.org/index.php/Ext3#Reclaim_reserved_filesystem_space">https://wiki.archlinux.org/index.php/Ext3#Reclaim_reserved_filesystem_space</a></li>
<li><a href="http://www.redhat.com/archives/ext3-users/2009-January/msg00026.html">http://www.redhat.com/archives/ext3-users/2009-January/msg00026.html</a></li>
<li><a href="http://www.giganetic.com/ext3-ext4-liberar-espacio-reservado-con-tune2fs-linux/">http://www.giganetic.com/ext3-ext4-liberar-espacio-reservado-con-tune2fs-linux/</a></li>
</ul>Telegram: aún hay esperanza para las apps de mensajería2014-11-18T20:57:44+01:002014-11-18T20:57:44+01:00BhEaNtag:pornohardware.com,2014-11-18:/2014/11/18/telegram-aun-hay-esperanza-para-las-apps-de-mensajeria/<p><img class="right" src="/images/logos/logo_telegram.png"/>
Por si implementar un robusto <a href="https://es.wikipedia.org/wiki/Criptograf%C3%ADa">protocolo de encriptación</a>, tener una <em>app</em> para casi todos los sistemas operativos móviles mayoritarios que existen, haber <a href="https://telegram.org/apps#source-code">publicado su código fuente</a>, disponer de una <a href="https://core.telegram.org/api">API pública</a> para que cualquier desarrollador pueda integrar <a href="https://telegram.org/">Telegram</a> en sus programas o haber garantizado desde el primer momento que su sistema será <strong>gratis y libre de publicidad para siempre</strong> no fueran argumentos suficientes como para erigir a Telegram como <em>la mejor aplicación de mensajería instantánea que existe hoy en día</em>, ahora van y sacan aplicaciones de escritorio para Linux y Mac!! <em>(vaaaaale, para Windows también... pero a quién le importa ésto último?)</em></p>
<p>Y nada de <a href="https://es.wikipedia.org/wiki/Aplicaci%C3%B3n_web">webapps</a> (aunque si quieres, <a href="https://web.telegram.org/">también las tiene</a>) sino que se trata de aplicaciones nativas para cada sistema operativo (cuyo código fuente, además, <a href="https://github.com/telegramdesktop/tdesktop">también han publicado</a>).</p>
<p><img class="right" src="/images/logos/logo_telegram.png">
Por si implementar un robusto <a href="https://es.wikipedia.org/wiki/Criptograf%C3%ADa">protocolo de encriptación</a>, tener una <em>app</em> para casi todos los sistemas operativos móviles mayoritarios que existen, haber <a href="https://telegram.org/apps#source-code">publicado su código fuente</a>, disponer de una <a href="https://core.telegram.org/api">API pública</a> para que cualquier desarrollador pueda integrar <a href="https://telegram.org/">Telegram</a> en sus programas o haber garantizado desde el primer momento que su sistema será <strong>gratis y libre de publicidad para siempre</strong> no fueran argumentos suficientes como para erigir a Telegram como <em>la mejor aplicación de mensajería instantánea que existe hoy en día</em>, ahora van y sacan aplicaciones de escritorio para Linux y Mac!! <em>(vaaaaale, para Windows también... pero a quién le importa ésto último?)</em></p>
<p>Y nada de <a href="https://es.wikipedia.org/wiki/Aplicaci%C3%B3n_web">webapps</a> (aunque si quieres, <a href="https://web.telegram.org/">también las tiene</a>) sino que se trata de aplicaciones nativas para cada sistema operativo (cuyo código fuente, además, <a href="https://github.com/telegramdesktop/tdesktop">también han publicado</a>).</p>
<h2>Índice</h2>
<ol>
<li><a href="#whyuse">¿Por qué usar Telegram?</a></li>
<li><a href="#from">¿De dónde ha salido?</a></li>
<li><a href="#comp">Comparativa</a></li>
<li><a href="#notgold">Pero no es oro todo lo que reluce...</a></li>
<li><a href="#refs">Referencias</a></li>
</ol>
<h2>¿Por qué usar Telegram?<a name="whyuse"></a></h2>
<p>No lo voy a negar: ya era un fiel defensor de Telegram incluso antes de probarlo. Y es que basta con leer su <em>manifiesto</em> para darse cuenta de que ofrece todo lo que uno espera de una app de mensajería, y encima funciona bien (lo cual aunque debería estar implícito en un software de <em>producción</em>, aquellos que se muevan en éste <em>mundillo</em> sabrán que a menudo no es así).</p>
<p>Harto de la <em>bazofia</em> de Whatsapp (<em>no pongo enlace para no darles tráfico xDD</em>) y de sus <a href="http://www.taringa.net/posts/noticias/14232468/Revelan-4-vulnerabilidades-graves-en-WhatsApp.html">múltiples problemas de seguridad</a> (<a href="http://www.actualizanet.es/2013/03/la-vulnerabilidad-de-whatsapp-al.html">y más</a>, <a href="http://www.pcactual.com/noticias/actualidad/priyanka-nueva-vulnerabilidad-whatsapp-2_12504">y más</a>, <a href="http://www.elconfidencial.com/tecnologia/2014-12-02/un-fallo-de-seguridad-permite-bloquear-a-distancia-whatsapp-con-un-simple-mensaje_522165/">y aún más</a>, <a href="http://www.securitybydefault.com/2011/03/whatsapp-y-su-seguridad-pwn3d.html">y mil ejemplos más</a>), de las acusaciones sobre el espionaje de sus conversaciones para la <a href="https://es.wikipedia.org/wiki/Agencia_de_Seguridad_Nacional">NSA</a>, de sus cada vez más frecuentes <em>cuelgues</em> y <em>reinicios</em>, etc, etc. probé varios servicios de mensajería alternativos... como por ejemplo el insufrible y pesadísimo <a href="http://line.me/es/">LINE</a> (que si no eres un adolescente cuyo único interés en la vida es enviar <a href="https://es.wikipedia.org/wiki/Emoticono">emoticonos</a>, es una mierda), y otro (cuyo nombre ahora mismo no recuerdo) que prometía <em>encriptación militar</em> (suena más a <em>gancho comercial</em> que a otra cosa), pero que se hacía tan difícil de utilizar para el <em>público en general</em> que no lo usaba ni la familia de sus desarrolladores...</p>
<p>Todo parecía perdido... pero cuando estaba a punto de tirar la toalla y <em>conformarme</em> con el puto Whatsapp durante el resto de mi vida, <a href="http://www.elmundo.es/economia/2014/02/19/53052f1e268e3eed5d8b456c.html">llega Facebook y lo compra!</a>... y si hay algo que odio más que a los mentirosos de <a href="http://huyedelacorporacion.com/">Google</a> es sin ninguna duda a los ladrones de Facebook! Así que no tenía elección: solicité la eliminación de mi cuenta de Whatsapp (que eso da para otro post, lo prometo), desinstalé la aplicación de mi teléfono y me dispuse a ser una de las pocas <a href="https://es.wikipedia.org/wiki/Cylon">personas</a> de éste mundo que iban a seguir enviando mensajes <a href="https://es.wikipedia.org/wiki/Servicio_de_mensajes_cortos">SMS</a>.</p>
<p>Pero entonces sucedió!! Los planetas se alinearon y <a href="http://en.wikipedia.org/wiki/Lords_of_Kobol">los Dioses</a> (en su infinito saber) tuvieron a bien concedernos a <a href="https://telegram.org/">Telegram</a>!</p>
<p>Voy a dar solo unas pocas de las muchas razones por las que todos deberíamos usar ésta aplicación de mensajería en lugar de las demás:</p>
<ul>
<li>Implementa un protocolo de encriptación MUY robusto llamado <a href="https://core.telegram.org/mtproto">MTProto</a>, cuyos creadores (y quienes lo han analizado en profundidad) aseguran que <em>no se puede romper</em> (de hecho, hay una <a href="https://telegram.org/crypto_contest">recompensa de ~~200.000 $ a quien consiga hacerlo~~</a> <a href="https://telegram.org/blog/cryptocontest">nueva recompensa de 300.000 $</a>!).</li>
<li>Identificación por alias: Cada usuario puede asignar a su número un alias, de forma que podrá ser identificado por dicho alias en el caso de no figurar en el listado de contactos del dispositivo receptor.</li>
<li>Permite especificar chats con un tiempo de <em>auto-destrucción</em> configurable, de forma que pasado ese tiempo, todo el contenido de la conversación se elimina de los dispositivos de todos sus interlocutores (tanto si ellos quieren como si no), evitando que queden en el <em>historial</em> para siempre.</li>
<li>Las conversaciones pueden sincronizarse entre diferentes dispositivos, lo que permite conectarse desde el ordenador (por ejemplo) y ver los mensajes que hemos escrito y recibido desde el movil, y viceversa.</li>
<li>Es gratis, y está libre de publicidad. Y ésto, según sus autores, <strong>va a ser así SIEMPRE</strong>.</li>
<li>Incorpora marcas de verificación que permiten saber cuándo un mensaje ha sido enviado <em>al receptor</em>, y cuándo dicho mensaje ha sido leído (una característica que Whatsapp, por ejemplo, ha tardado 5 años en incorporar).</li>
<li>Se puede enviar cualquier tipo de archivos a través de Telegram, no solo fotos, audio y poco más (como en la mayoría de las apps de la competencia).</li>
<li>Dispone de una <a href="https://core.telegram.org/api">API</a> pública que cualquiera puede utilizar para integrar Telegram en sus propias aplicaciones (¿os imaginais recibir alertas o los resultados de vuestros <a href="https://es.wikipedia.org/wiki/Lenguaje_de_programaci%C3%B3n_interpretado">scripts</a> en vuestro movil a través de <em>Telegram</em>, hablándonos como si se tratara de cualquier otro de nuestros <em>contactos</em>?)</li>
<li>No solo tiene apps para <a href="https://www.apple.com/es/ios/">iOS</a>, <a href="http://www.android.com/">Android</a> o <a href="http://www.windowsphone.com/en-us">Windows Phone</a>, sino que además existen <a href="https://es.wikipedia.org/wiki/Aplicaci%C3%B3n_web">webapps</a> para <a href="http://www.google.com/chrome/">Chrome</a> y <a href="https://www.mozilla.org/es-ES/firefox/new/">Firefox</a> (y se encuentran en <a href="https://es.wikipedia.org/wiki/Fases_del_desarrollo_de_software#Beta">fase beta</a> las versiones para <a href="https://es.wikipedia.org/wiki/Firefox_OS">Firefox OS</a>, <a href="https://es.wikipedia.org/wiki/BlackBerry_OS">Blackberry OS 10</a>, e incluso un <em>plugin</em> para <a href="http://pidgin.im/">Pidgin</a>).</li>
<li>Y muchas otras cosas...</li>
</ul>
<h2>¿De donde ha salido?<a name="from"></a></h2>
<p>Telegram fué lanzado en 2013 por los 2 hermanos rusos Nikolai y Pavel Durov, que para los que no sepan aún quienes son, son también los creadores de <a href="http://vk.com/">VK</a> (o <a href="http://vk.com/">VKontakte</a>, la red social más grande de Rusia.</p>
<p>Según <a href="https://es.wikipedia.org">Wikipedia</a>: <em>VK Es el sitio más popular de Rusia, Ucrania y Bielorrusia. Debido a su diseño y funcionalidad, a menudo se afirma que VK es un clon de Facebook, no solo por ser un concepto similar, sino por ser un modelo de negocio comparable. Sin embargo, la incorporación de otras características hace que sea más un todo en uno. Similar a otros sitios como YouTube, Pandora, etc. con una interfaz que recuerda mucho a Facebook, pero de un uso más sencillo e intuitivo.</em></p>
<p>En 2014, sus creadores convirtieron la empresa (hasta ese momento llamada <em>Telegram LLC</em>) en una <em>organización sin ánimo de lucro</em>, y así se mantiene por ahora (y esperemos que ésto no cambie!).</p>
<h2>Comparativa<a name="comp"></a></h2>
<p>Antes de empezar a escribir éste artículo me propuse hablar únicamente de Telegram, y hacerlo de una forma imparcial, contando sus virtudes sin <em>atacar</em> directamente a las demás apps de mensajería que existen... pero es inútil escribir un post sobre una de éstas apps sin comparar sus ventajas e inconvenientes con respecto a las demás.</p>
<p>Por ir rompiendo el hielo en éste aspecto: en 2014, la <a href="https://www.eff.org/">Electronic Frontier Foundation</a> (junto a otras empresas) <a href="https://www.eff.org/secure-messaging-scorecard">organizó una comparativa en la que se pusieron a prueba 39 aplicaciones de mensajería</a>. Ésta comparativa consistía en la realización de 7 pruebas, de las cuales Telegram aprobó 5, igualando a <a href="https://www.apple.com/ios/messages/">iMessages</a> (de <a href="http://www.apple.com">Apple</a>) el cuál está considerado como uno de los sistemas más seguros del mundo, aunque por desgracia es (obviamente) un software propietario.</p>
<p>Dos factores críticos que redujeron la calificación de Telegram en ésta comparativa fueron la <em>posible</em> vulnerabilidad en descifrar mensajes con la clave de cifrado interceptada, incluso si los mensajes son almacenados localmente, y la falta de soporte de una empresa independiente.</p>
<p>La mayoría de las comparativas que existen en Internet siempre son entre Whatsapp, Telegram y LINE por ser éstas las 3 apps más utilizadas en la actualidad... pero dado que lo he mencionado antes, intentaré incluir en ésta comparativa también al <a href="https://www.apple.com/ios/messages/">iMessages</a> de Apple, que aunque no creo que sea una <em>competencia real</em> para ninguna de las demás (principalmente porque SOLO es para <em>iDevices</em>) merece estar en la comparativa por ser (desde el punto de vista de la seguridad) una de las mejores opciones, y por su increible (en mi opinion) usabilidad.</p>
<h3>En cuanto a seguridad y privacidad:</h3>
<p>Whatsapp siempre se ha caracterizado por preocuparse muy poco por la seguridad de sus comunicaciones. Muchas de sus vulnerabilidades han permitido que cualquier <a href="https://es.wikipedia.org/wiki/Script_kiddie">script kiddie</a> pudiera espiar las conversaciones de los demás. No se puede culpar a una app por tener <a href="https://es.wikipedia.org/wiki/Error_de_software">bugs</a>, ya que eso es normal en el desarrollo de software. Lo que no es normal es no solucionar éstos problemas en un tiempo razonable a pesar de ser bugs reportados. Supongo que durante años pensaron que podían hacer lo que quisieran, ya que eran monopolio y pensaron que <em>todo</em> el mundo iba a seguir utilizando su app a pesar de éstos problemas porque no había ninguna otra app que <em>les hiciera sombra</em>. Y con respecto a la privacidad... si los rumores de su colaboración con la NSA no fueran suficientes para ver la opinión de ésta gente acerca de la privacidad de sus usuarios, el haber sido comprada por Facebook obviamente no dice nada a su favor en éste aspecto, más bien todo lo contrario. De hecho, ésta app ha sido llevada a los tribunales en algunos paises (Canada, Holanda, ...) por vulnerar algunas leyes de privacidad.</p>
<p>En cuanto a LINE, acaba de incorporar el cifrado hace muy poco, ya que antes tampoco lo hacía, pero aunque no hay demasiada documentación sobre éste cifrado (o al menos yo no la he encontrado) no goza de <em>mala reputación</em> en éste aspecto. Por el momento solo ha tenido <a href="http://translate.google.com/translate?hl=es&sl=ja&tl=es&u=http%3A%2F%2Flineblog.naver.jp%2Farchives%2F12893561.html">una <em>brecha</em> de seguridad conocida</a> (enlace traducido automáticamente, ya que la noticia original está en japonés).</p>
<p>Telegram está cláramente orientada a la privacidad y a la seguridad en las comunicaciones, ya que sus creadores fueron conscientes desde el primer momento que éste tema era precisamente lo que podía hacer que su app se diferenciara del resto, y la gente la eligiera frente a las demás. Chats privados, tiempo configurable de eliminación de mensajes, fuerte cifrado basado en el protocolo <a href="https://core.telegram.org/mtproto">MTProto</a>, etc. hacen de ella una app muy segura. Y el hecho de utilizar un protocolo de cifrado y unas aplicaciones cuyo código fuente haya sido liberado, hacen que Telegram no tenga nada que ocultar (o al menos dan esa impresión).</p>
<p>En cuanto a iMessage, como casi todo lo que concierne a Apple, está envuelta en el secretismo hermético que caracteriza ésta empresa... y apenas se conocen datos claros y fiables sobre su funcionamiento interno (a pesar de las <a href="http://blog.cryptographyengineering.com/2012/08/dear-apple-please-set-imessage-free.html">peticiones que ha habido al respecto</a>). Siempre se ha presupuesto que era uno de los sistemas más seguros que había, como se podía comprobar <a href="http://www.cnnexpansion.com/tecnologia/2013/04/08/imessage-apple-iphone-mensajes-dea">en el documento de la DEA (Agencia Antidroga Estadounidense) que se filtró en Internet</a> y en el que se decía <em>supuestamente que ellos no podían interceptar y leer los mensajes enviados con éste sistema</em>. Apple se apresuró entonces a confirmar que efectivamente ni la DEA ni siquiera ellos mismos pueden acceder al contenido de los mensajes (ni aunque quisieran hacerlo) debido a la fuerte seguridad de sus transmisiones. Pero <a href="http://www.enter.co/chips-bits/seguridad/estudio-apple-y-la-nsa-pueden-leer-lo-que-pasa-por-imessage/#!">recientes investigaciones</a> (hechas por el mismísimo <a href="http://www.pod2g.com/"><strong>pod2g</strong></a>) revelan que SI sería posible que se interceptaran y descifraran los mensajes enviados por éste medio, por lo que únicamente si confias ciégamente en Apple podrías considerar su iMessage como el sistema más seguro que hay (me descojono, jejeje).</p>
<h3>En cuanto a usabilidad:</h3>
<p>La <a href="http://es.wikipedia.org/wiki/Usabilidad">usabilidad</a> es un factor importantísimo a la hora de elegir una app de mensajería, ya que son apps que se suelen utilizar de forma muy frecuente... por lo que cuánto más facil, rápido y sencillo sea la forma de utilizarlas, mejor.</p>
<p>En éste aspecto yo diría que LINE es la peor de las 4, ya que no es que sea <em>extremadamente difícil</em> utilizarla (ninguna lo es), sino que dada la cantidad de opciones que se presentan en cada pantalla, menu, etc. resulta evidente que es la menos sencillez y facilidad de uso ofrece.</p>
<p>Whatsapp y Telegram son prácticamente iguales en éste aspecto, siendo el segundo casi un <em>clon</em> del primero, lo cual seguramente se deba a facilitar la migración de usuarios hacia Telegram (cuánto más parecida sea a la que los usuarios estan acostumbrados a usar, más facil será que éstos la utilicen). En cualquier caso, ya sea porque es a lo que la mayoría estamos acostumbrados o porque efectivamente el grado de usabilidad y facilidad que ofrecen es muy alto, ambas son muy sencillas de utilizar, incluso para personas que no estan acostumbradas a utilizar apps (siempre he pensado que si mis padres pueden usar una app significa que es sencilla e intuitiva, sino, no lo es xDDDD).</p>
<p>Pero iMessage es la gran ganadora en éste terreno, ya que si hay algo en lo que Apple es experto es en hacer que las cosas funcionen de forma <em>transparente</em> para el usuario final.</p>
<p>Todo el mundo (casi sin excepción) sabe cómo se envia un SMS, verdad? Pues en iMessage solo hace falta eso para saber utilizarlo, ya que no hay una app para ello, sino que está integrado en el envio/recepción de mensajes SMS de forma que al enviar dicho SMS, si el destinatario dispone de una cuenta de iMessage automáticamente dicho mensaje se enviará a través de éste servicio. Por el contrario, si el destinatario no tiene iMessage, se enviará como un SMS normal <em>de toda la vida</em>. Por lo tanto, no hay que hacer nada, configurar nada ni seleccionar nada. Solo escribes el mensaje y lo envias, nada más. Y para recibirlos es lo mismo: si tienes activado el uso de iMessage en tu <em>iDevice</em>, los recibirás en el mismo sitio donde recibirías los SMS de siempre. En éste caso si que se podría decir (como tanto le gusta decir a los de Apple) que <em>it's just works</em>.</p>
<h3>En cuanto a número de usuarios</h3>
<p>Ésta es la única ventaja de Whatsapp frente a las demás, y por desgracia es una de las más importantes para el público en general. Cuando hablo con algún familiar o conocido sobre porqué Whatsapp es tan inseguro y tan poco recomendable, y les explico porqué Telegram funciona tan bien, basta con exponer los mismos argumentos que he intentado exponer en éste artículo para que todos acaben siempre convencidos de que efectivamente es mucho mejor usar Telegram que Whatsapp... pero muchos de ellos, al cabo de muy poco tiempo vuelven de nuevo a utilizar Whatsapp... y cuando les pregunto el motivo, todos me dicen lo mismo: "<em>es que Whatsapp es lo que usa todo el mundo</em>".</p>
<p>Y por desgracia (de momento) tienen razón...</p>
<p>El motivo por el que usamos cualquiera de éstas apps es el de comunicarnos con los demás sin tener que pagar 0,15 € (o lo que sea, depende del operador y la tarifa) por cada mensaje que enviamos (como sucedía con los SMSs). Pero aunque haya apps mejores y apps peores, ¿de qué nos sirve tener una app cojonuda, si la persona con la que queremos comunicarnos NO dispone de dicha app? Las apps de mensajería no son compatibles unas con otras; no se puede enviar un mensaje desde Telegram y que el destinatario lo reciba en su Whatsapp, o viceversa (aunque es una buenísima idea, me lo apunto como futuro proyecto para hacerme rico xDDD). Por lo tanto, es muy importante que la app que queramos utilizar la tengan también nuestros interlocutores, sino, no servirá de nada porque no podremos usarla.</p>
<p>Whatsapp fué <em>el primero</em> en llegar, y durante mucho tiempo, el único. La poquísima (o nula) capacidad de reacción que tuvieron todas las demás empresas relacionadas con la comunicación en aquel momento (que no supieron ver el <strong>increible filón</strong> que Whatsapp había descubierto) propiciaron que Whatsapp fuera ganando usuarios... al principio poco a poco, y después de forma exagerada (conozco gente que compraron <em>smartphones</em> únicamente para poder utilizar Whatsapp). Y años después, TODO EL MUNDO (menos yo, y <em>tres o cuatro locos más</em>) la utilizan... por lo que hacerse un hueco hoy en dia para otra app de mensajería es muy difícil. De todas formas, la <em>hegemonía</em> de Whatsapp no durará siempre, y ya hay apps (como por ejemplo Telegram) que aumentan de usuarios a un ritmo increible... por lo que es únicamente cuestión de tiempo que el público en general se de cuenta de lo mal que hacen usando Whatsapp, y migren hacia otras apps más seguras, privadas, estables, etc.</p>
<p>Ya he comentado que iMessage es un sistema muy bueno (seguro, rápido, intuitivo, etc) pero al ser un sistema CERRADO y únicamente compatible con <a href="https://www.apple.com/es/ios/">iOS</a> y <a href="https://www.apple.com/es/osx/">Mac OS</a>, está limitadísimo en cuanto al número de usuarios que pueden usarlo, por lo que jamás será (ni de lejos) un competidor directo de ninguna de las demás apps de mensajería con las que lo estamos comparando.</p>
<p>Y en cuanto a LINE, desde que salió ha crecido a un ritmo tremendo, aumentando de usuarios exponencialmente (hoy en dia, noviembre de 2014, se estima que tiene más de 560 millones de usuarios)... pero tiene un problema enorme, y es que según <a href="http://www.dealerworld.es/redes-sociales/solo-el-30-de-los-usuarios-registrados-en-line-utiliza-el-servicio">varios artículos</a> reciéntemente publicados, únicamente el 30% de sus usuarios registrados realmente lo utilizan, lo cual no habla muy bien de LINE...</p>
<h3>En cuanto al número de plataformas que soportan</h3>
<p>En éste punto iMessage es la clara perdedora. Únicamente los llamados <em>iDevices</em> (iPhone, iPod, iPad y sistemas Mac OS) pueden utilizar iMessage, lo cual deja fuera (por ejemplo) a la totalidad de usuarios de Android (una cifra nada despreciable).</p>
<p>Le sigue Whatsapp, que permite su ejecución en los dispositivos iOS, Android, Windows Phone, Blackberry y Nokia, y si utilizamos un emulador de Android para PC, podemos utilizarlo en Windows también.</p>
<p>LINE se ejecuta en los mismos smartphones que Whatsapp, pero añade versiones nativas para Windows y Mac OS.</p>
<p>Pero el ganador indiscutible en éste punto es Telegram, disponible en iOs, Android y Windows Phone (y muy pronto en Blackberry 10, ya que <a href="https://telegram.org/blog/blackberry-contest">ofrecen 50.000$ a quien la porte a éste sistema</a>), y con aplicaciones nativas para Windows, Mac OS y Linux. Aunque realmente se puede utilizar desde <strong>cualquier parte</strong>, ya que dispone de un plugin para Chrome, así como un cliente de consola (*nix), webapps para acceder desde cualquier navegador e incluso un <a href="https://github.com/majn/telegram-purple">interface para el cliente de mensajería Pidgin</a>.</p>
<h3>En cuanto a funcionalidades que ofrece cada una</h3>
<p>De nuevo Telegram vuelve a ganar en éste punto, ya que es la que más y mejores funcionalidades ofrece. Es cierto que no dispone de llamadas de voz, cosa que LINE (e iMessage, a través de <a href="https://www.apple.com/es/ios/facetime/">Facetime</a>) si, pero la lista de opciones que ofrece (y cómo estan éstas implementadas) supera con creces a las demás.</p>
<p>Una de las primeras cosas que llaman la atención (o que más la llamaron en su dia) son los <em>chats secretos</em> y la posibilidad de configurar un <em>tiempo de eliminación</em> de los mensajes. Con Telegram, podemos establecer un chat privado punto a punto entre nosotros y nuestro interlocutor, el cual iría completamente cifrado (y ni siquiera dejaría rastro en los propios servidores de Telegram), en el que además podemos definir (por ejemplo) un tiempo de eliminación de 2 minutos. Cada vez que escribamos en dicho chat, aparte de transmitir el mensaje de forma segura y privada, éste se eliminará automáticamente tanto de nuestro móvil como del móvil del destinatario 2 minutos después de que éste lo haya recibido. De ésta forma evitamos que la conversación quede almacenada para siempre en el historial de la aplicación, en los servidores de Telegram o donde sea (reciéntemente LINE ha implementado también ésta funcionalidad).</p>
<p>En cuanto a los grupos de mensajes, con Whatsapp tenemos la limitación de 30/50 personas como máximo (dependiendo de si usamos la versión iOS o Android). Con Telegram podemos crear grupo de hasta 200 personas (lo cuál seguramente no vamos a usar nunca, a no ser que queramos volvernos locos, pero está bien que no tengamos dicha limitación). LINE está limitada a 100 personas como máximo.</p>
<p>En Whatsapp, hasta hace 2 semanas (después de tooodos estos años), no se podía saber si el mensaje que habíamos escrito había sido leído por el destinatario. Ahora acaban de lanzar una actualización que permite saberlo (aunque debido a las protestas recibidas por sus propios usuarios, se puede deshabilitar ésta opción). Con LINE, Telegram e iMessage se puede saber ésto desde el primer dia, de forma que cuando se envía un mensaje, se puede saber si el destinatario lo ha leído ya o aún no.</p>
<p>En cuanto al envío de archivos a través de éstas apps, con Whatsapp únicamente se pueden enviar imágenes, notas de voz, y algunas pocas cosas más. Y encima, el tamaño máximo del archivo que podemos enviar es de 12Mb, lo que ha provocado que circulen por éste multitud de imágenes pixeladas, videos entrecortados y con muy poca calidad, etc. Con iMessage tampoco se puede enviar algo que no sea una foto y poco más, y para colmo, el tamaño máximo es de 1Mb. Desconozco el tamaño máximo que se puede enviar a través de LINE, lo siento... pero de nuevo es Telegram quien gana (y por goleada) en éste aspecto también. Con Telegram, se puede enviar <strong>cualquier tipo de archivo</strong>, sea el que sea... y el tamaño máximo es de 1Gb, lo cual debería ser suficiente como para enviar cualquier cosa que pudiéramos necesitar.</p>
<p>Por último, pero no por ello menos importante, Telegram ofrece algo que a la mayoría de la gente no le servirá para nada (de hecho, la mayoría ni siquiera sabrá qué es) pero que supone un importantísimo avance y abre todo un nuevo mundo de posibilidades: una API pública.</p>
<p>Esta API va a permitir a los desarrolladores implementar Telegram en sus programas... y eso realmente puede suponer una revolución, ya que podríamos recibir y enviar a través de Telegram (por ejemplo) comandos para manejar nuestro ordenador de forma remota, controlar determinado software desde cualquier punto del mundo, recibir notificaciones e información de procesos que tengamos ejecutando en un servidor, etc, etc. Si sabeis lo que es una API, no hace falta que os enumere todo lo que podríais hacer con ésta. Y ésto es algo que SOLO Telegram ofrece.</p>
<p>Ah si! Olvidaba que LINE tiene <a href="http://es.wikipedia.org/wiki/Pegatina">stickers</a>... es decir, emoticonos con más variedad y más grandes... en fin... (y hay quien dice que es su mayor <a href="http://en.wikipedia.org/wiki/Killer_feature"><em>killer feature</em></a> xDDD).</p>
<h3>En cuanto al precio</h3>
<p>Poco hay que decir en éste aspecto. En la <a href="https://itunes.apple.com/es/app/whatsapp-messenger/id310633997?mt=8">App Store</a> de Apple únicamente hay que hacer un pago inicial de 0,89 € para bajar la app, y una ve pagado eso ya no hay que pagar nunca más (ésto es únicamente para dispositivos iOS). Para Android, su precio en <a href="https://play.google.com/store/apps/details?id=com.whatsapp&hl=es">Google Play</a> es gratuito el primer año, luego su precio es de 0,89 € al año. Todas las demás apps son gratuitas.</p>
<p>Sobre éste tema tengo que romper una lanza en defensa de Whatsapp, ya que como <em>desarrollador de software</em> que soy, me dió <strong>verdadero asco</strong> ver como la gente ponía el grito en el cielo cuando Whatsapp anunció que iba a cobrar 0,89 € al año a la gente que llevara más de 1 año usándola.</p>
<p>Por el precio de 3 o 4 SMS se puede tener una app que permite enviar INFINITOS mensajes GRATIS. Y aun así, la gente se quejaba, buscaba formas de saltarse el pago, hacian <a href="https://es.wikipedia.org/wiki/Jailbreak_%28iOS%29">jailbreak</a> en busca de <em>hacks</em>, reinstalaban el SO de sus móviles y mil cosas más solo por no pagar los 0,89 €!!! <strong>Vergüenza ajena...</strong></p>
<p>El problema es que la gente está acostumbrada (demasiado, diría yo) a obtenerlo todo gratis, ya sea porque realmente lo es o porque lo roban/cogen/copian/etc, así que cuando se ven obligados a pagar unos céntimos por un servicio que les ahorra CIENTOS de euros, se llevan las manos a la cabeza. Es triste, pero así es...</p>
<p>En fin... a modo de resumen, en la siguiente tabla podeis ver más o menos el resultado de la comparativa que acabamos de hacer:</p>
<table>
<thead>
<tr>
<th align="left"> </th>
<th align="left">Whatsapp</th>
<th align="left">LINE</th>
<th align="left">Telegram</th>
<th align="left">iMessage</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><strong>Seguridad</strong></td>
<td align="left">Inseguro</td>
<td align="left">Seguro</td>
<td align="left"><u><strong>Muy seguro</strong></u></td>
<td align="left"><u><strong>Muy seguro</strong></u></td>
</tr>
<tr>
<td align="left"><strong>Usabilidad</strong></td>
<td align="left">Fácil</td>
<td align="left">Poco intuitiva</td>
<td align="left">Fácil</td>
<td align="left"><u><strong>Muy fácil</strong></u></td>
</tr>
<tr>
<td align="left"><strong>Usuarios/mes</strong></td>
<td align="left"><u><strong>600 millones</strong></u></td>
<td align="left">170 millones</td>
<td align="left">35 millones</td>
<td align="left"><em>Desconocido</em></td>
</tr>
<tr>
<td align="left"><strong>Plataformas</strong></td>
<td align="left">Muchas</td>
<td align="left">Muchas</td>
<td align="left"><u><strong>Casi todas</strong></u></td>
<td align="left">Solo <em>iDevices</em></td>
</tr>
<tr>
<td align="left"><strong>Permite voz</strong></td>
<td align="left">No</td>
<td align="left"><u><strong>Si</strong></u></td>
<td align="left">No</td>
<td align="left"><u><strong>Si (Facetime)</strong></u></td>
</tr>
<tr>
<td align="left"><strong>Funcionalidades</strong></td>
<td align="left">Normal</td>
<td align="left">Normal</td>
<td align="left"><u><strong>Muchas</strong></u></td>
<td align="left">Muy pocas</td>
</tr>
<tr>
<td align="left"><strong>Precio</strong></td>
<td align="left">0,89 € / año</td>
<td align="left"><u><strong>Gratis</strong></u></td>
<td align="left"><u><strong>Gratis</strong></u></td>
<td align="left"><u><strong>Gratis</strong></u></td>
</tr>
</tbody>
</table>
<p>El resultado, a pesar de lo que la mayoría de la gente piensa, es que Whatsapp es una de las peores apps de mensajería que existen... pero tiene a su favor el factor más decisivo para la mayoría: todo el mundo la usa.</p>
<p>Telegram e iMessage son las ganadoras de la comparativa, por su privacidad, seguridad y usabilidad. Pero para la mayor parte de la gente, la privacidad no es importante. Ésto es MUY triste, pero es así.</p>
<p>Cualquier persona con la que habléis de la codificación de los mensajes, de la privacidad, del cifrado, etc. os dirá que eso da igual... que no somos "<em>tan importantes</em>" como para que quieran <em>espiarnos</em>... e incluso que si lo hacen, no les importa porque "<em>no tienen nada que ocultar</em>", y blablabla...</p>
<p>Y esa forma de pensar es la que hace que empresas como Google, Facebook y tantas otras hagan lo que les venga en gana, traficando con nuestros datos, perfiles, gustos, etc. Pero eso es otro tema, no nos desviemos ahora xDDD</p>
<p>Por lo tanto, y puesto que iMessage está limitada a los dispositivos iOS de Apple, Telegram es sin duda la ganadora de nuestra comparativa.</p>
<h2>Pero no es oro todo lo que reluce...<a name="notgold"></a></h2>
<p>No obstante, Telegram no es perfecta del todo, y aunque no tengo ninguna duda de que es la mejor app de mensajería que conozco, me provoca cierto <em>malestar</em> el hecho de que no hayan publicado realmente todo su código.</p>
<p>Ellos anuncian en su web que el código fuente está disponible, y así es... aunque ésto es solo verdad en parte. Únicamente se ha liberado y publicado el código fuente de algunas versiones muy antiguas de las apps para móvil, no la versión actual. Las apps para escritorio (Telegram Desktop) también han sido publicadas... pero no el código que usan los servidores de Telegram, y ahí es donde radica el principal problema de <em>confianza</em> que ésta app puede generar en los que somos tan <em>paranoicos</em>.</p>
<p>Al no disponer del código fuente completo de todo el sistema, no hay una <strong>garantía real</strong> de que funcione como ellos nos dicen. Aunque aun así, Telegram sigue siendo la mejor opción de todas, ya que ninguna de las demás apps ha publicado absolutamente nada.</p>
<p>En cualquier caso, el único problema real que existe ahora mismo con Telegram es que no es la app utilizada por la mayoría de la gente (aunque gana miles y miles de nuevos adeptos diariamente), por lo que lo mejor que puedes hacer para mejorar el mundo de las comunicaciones y de su privacidad es utilizarla, y convencer a todos tus amigos y familiares de que lo hagan también.</p>
<p>Es gratis, ocupa muy poco y funciona genial. ¿de verdad se te ocurre alguna buena razón para NO usarla a partir de ahora? Espero que no!</p>
<p>Como siempre, espero que éste artículo te resulte de utilidad... ya sea para iniciarte en Telegram o para conocer un poco más acerca de sus virtudes frente a las demás... así que no dudes en compartirlo con todo el mundo.</p>
<p>Alaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</p>
<h2>Referencias<a name="refs"></a></h2>
<ul>
<li><a href="https://telegram.org/">https://telegram.org/</a></li>
<li><a href="https://www.eff.org/secure-messaging-scorecard">https://www.eff.org/secure-messaging-scorecard</a></li>
<li><a href="http://www.tomsguide.com/us/is-apple-imessage-secure,news-17741.html">http://www.tomsguide.com/us/is-apple-imessage-secure,news-17741.html</a></li>
</ul>POODLE: En qué consiste esta vulnerabilidad del protocolo SSL y qué hacer para evitarla2014-10-20T10:34:19+02:002014-12-12T06:41:17+02:00BhEaNtag:pornohardware.com,2014-10-20:/2014/10/20/poodle-en-que-consiste-esta-vulnerabilidad-del-protocolo-ssl-y-que-hacer-para-evitarla/<p><img class="right" src="/images/logos/logo_poodlebleed.png"/></p>
<p>Ha sido un duro golpe el que ha recibido nuestro querido <a href="https://es.wikipedia.org/wiki/Transport_Layer_Security#SSL_3.0_2">SSL</a> (concretamente su versión 3.0) con el descubrimiento de ésta vulnerabilidad, ya que no existe una solución de verdad al problema salvo la de <strong>no utilizar</strong> esa versión en concreto.</p>
<p>Ésta vulnerabilidad no provoca una denegación de servicio (<a href="https://es.wikipedia.org/wiki/Ataque_de_denegaci%C3%B3n_de_servicio">DoS</a>), ni otorga acceso de administración a los servidores vulnerables, ni se puede utilizar para eliminar archivos, sino que permite a un atacante (mediante ataques <em><a href="https://es.wikipedia.org/wiki/Ataque_Man-in-the-middle">man in the middle</a></em>) acceder a la información que se transmite en una conexión que hasta ese momento se pensaba que era segura y privada, sin que los interlocutores de dicha comunicación lo sepan.</p>
<p><img class="right" src="/images/logos/logo_poodlebleed.png"></p>
<p>Ha sido un duro golpe el que ha recibido nuestro querido <a href="https://es.wikipedia.org/wiki/Transport_Layer_Security#SSL_3.0_2">SSL</a> (concretamente su versión 3.0) con el descubrimiento de ésta vulnerabilidad, ya que no existe una solución de verdad al problema salvo la de <strong>no utilizar</strong> esa versión en concreto.</p>
<p>Ésta vulnerabilidad no provoca una denegación de servicio (<a href="https://es.wikipedia.org/wiki/Ataque_de_denegaci%C3%B3n_de_servicio">DoS</a>), ni otorga acceso de administración a los servidores vulnerables, ni se puede utilizar para eliminar archivos, sino que permite a un atacante (mediante ataques <em><a href="https://es.wikipedia.org/wiki/Ataque_Man-in-the-middle">man in the middle</a></em>) acceder a la información que se transmite en una conexión que hasta ese momento se pensaba que era segura y privada, sin que los interlocutores de dicha comunicación lo sepan.</p>
<p>Aún nos estábamos recuperando del <em><a href="https://es.wikipedia.org/wiki/Heartbleed">Heartbleed</a></em> y de algunas otras vulnerabilidades que se han descubierto recientemente, cuando llega Google y (mal que me pese) descubren ésta importante nueva vulnerabilidad que pone en peligro las comunicaciones que hasta ahora creíamos seguras y a salvo.</p>
<p>Ésta vulnerabilidad ha sido bautizada como <strong>POODLE</strong> (en inglés: caniche) por su acrónimo <em>Padding Oracle On Downgraded Legacy Encryption</em>.</p>
<p>No voy a profundizar mucho en el tema, pero para saber más o menos de lo qué estamos hablamos debemos empezar por el principio:</p>
<p><a href="https://es.wikipedia.org/wiki/Transport_Layer_Security">SSL</a> se creó para dotar a las comunicaciones en Internet de una capa adicional de seguridad que permitiera no solo identificar a los interlocutores de dicha comunicación, sino que mediante la encriptación de esos datos, aportara la privacidad necesaria.</p>
<p>Vamos a poner un ejemplo centrándonos únicamente en la navegación web: si nos conectamos a una página web que NO utiliza SSL, básicamente tecleamos la URL en nuestro navegador y éste se conecta al servidor web de dicha página para mostrarnos el resultado. Toda esa <em>transferencia de datos</em> entre el servidor y nuestro navegador se hace <em>sin protección</em>, por lo que si hubiera alguien más <em>escuchando</em> en la red que estamos utilizando para conectarnos, podría ver lo que estamos haciendo.</p>
<p>Ahí es donde entra SSL, que hace que toda esa comunicación vaya encriptada y firmada mediante el intercambio de claves públicas y certificados (los cuales previamente han tenido que ser <em>firmados</em> por una Entidad Certificadora, lo que hace que no solo la comunicación sea <em>segura</em> y privada, sino que además nos garantiza que nuestro interlocutor es realmente quien dice ser).</p>
<p>El protocolo SSL ha ido evolucionando, como es lógico, y se ha ido revisando con el paso del tiempo, dando lugar a nuevas versiones.</p>
<p>Hubo un momento en el que SSL continuó <em>evolucionando</em> (a partir de la versión 3.0), y dió lugar a un nuevo protocolo que se denominó <a href="https://es.wikipedia.org/wiki/Transport_Layer_Security">TLS</a> (mucho más seguro y <em>moderno</em> que SSL).
Pero como los grandes cambios necesitan mucho tiempo para llevarse a cabo debido a que no todo el mundo se <em>actualiza</em> a la misma velocidad, y sobre todo para dotar al nuevo sistema de <em><a href="https://es.wikipedia.org/wiki/Retrocompatibilidad">retrocompatibilidad</a></em>, cuando el servidor y el cliente (en éste caso el navegador) no se ponen de acuerdo en la negociación inicial sobre qué algoritmo utilizar para la codificación TLS o cualquier otra cosa, ambos descartan entonces la utilización de TLS y vuelven al SSL <em>de toda la vida</em>, que es el que ambos conocen...</p>
<p>Ésta vulnerabilidad únicamente afecta a la última versión de SSL (la 3.0, ya que a partir de ahí se denominó TLS), por lo que si todos los servicios en Internet funcionaran con TLS no habría ningun problema... pero como SSL sigue estando presente para aquellos casos en los que la comunicación TLS no sea posible, es muy fácil provocar manualmente uno de éstos <em>conflictos</em> para que la comunicación crea que hay un problema y ambos interlocutores pasen entonces a utilizar SSL v3.0.</p>
<p>El primer paso para explotar ésta vulnerabilidad consiste en aprovechar precisamente ésta característica del protocolo, ocasionando de forma intencionada algun error en la conexion de los protocolos <em>seguros</em> (como TLS 1.2, 1.1 o 1.0) para forzar así el uso de SSL 3.0 (donde está presente la vulnerabilidad).</p>
<p>Seguramente ésta vulnerabilidad va a ser definitiva a la hora de dar por concluido el ciclo de vida de SSL (que ya tiene más de 15 años) ya que si bien es cierto que Poodle afecta únicamente al modo CBC (cifrado por bloques), y SSL permite también el <em>cifrado por flujo</em> (RC4), precisamente el año pasado se demostró que éste último método era vulnerable y un atancante podía obtener partes de un mensaje cifrado con éste método si éstas partes se repetían con cierta frecuencia (por ejemplo, una cookie de sesión en una cabecera HTTP). Por lo tanto, ya no quedan excusas para dar el salto definitivo a TLS y abandonar el uso de SSL (que ya se ha ganado de sobra la jubilación).</p>
<h2>¿Cómo se podría aprovechar ésta vulnerabilidad?</h2>
<p>Para efectuar un ataque aprovechando ésta vulnerabilidad lo primero sería forzar a los interlocutores de la comunicación que queremos <em>espiar</em> a utilizar un protocolo no-seguro en lugar de uno seguro. Como ya he comentado, para ésto bastaría con estar en la misma red que uno de los 2 interlocutores, y mediante la técnica del <em><a href="https://es.wikipedia.org/wiki/Ataque_Man-in-the-middle">hombre en el medio</a></em>, introducir algunos errores en la comunicación para que ambos decidan (de forma automática, obviamente) dejar de usar TLS y comenzar a utilizar SSL en dicha comunicación.</p>
<p>Dado que ya he dicho que el método de <em>cifrado por flujo</em> se considera inseguro desde hace más de 1 año, podemos suponer que el <em>sysadmin</em> del servidor web al que se está conectando nuestra víctima ya ha configurado dicho servidor para que no utilice ese método, por lo que lo normal será que la conexión esté utilizando el <em>cifrado por bloques</em>, que es precisamente el afectado por Poodle (y sino, tampoco hay problema... porque entonces podemos utilizar la otra vulnerabilidad ya conocida del cifrado por flujo).</p>
<p>En cualquiera de los 2 casos, el atacante podría entonces obtener partes de la conversación... lo cual es especialmente peligroso si esa parte es (por ejemplo) la cookie de sesión (o el usuario/contraseña) del servicio que está utilizando nuestra víctima en ese momento ya que podríamos suplantar su identidad, entrar en su cuenta, etc, etc.</p>
<h2>¿Cómo podemos protegernos?</h2>
<p>Por desgracia en éste caso el método más efectivo para no tener problemas con éste protocolo inseguro es <strong>no utilizarlo</strong>, y para eso basta con que los <em>sysadmins</em> configuren sus servidores para que NO utilicen el protocolo SSL si hay algun error en la comunicación TLS. De esa forma, un atacante no podría forzar nuestra comunicación segura para que utilice un protocolo inseguro.</p>
<p>Pero como no podemos esperar a que todos los <em>sysadmins</em> del mundo hagan su trabajo inmediatamente (porque algunos de nosotros estamos MUY ocupados con cosas mucho más importantes, como por ejemplo escribir éste artículo en éste grandioso blog), podemos tambien como <em>usuarios</em> configurar nuestros navegadores igualmente para que tampoco utilicen SSL si la comunicación con TLS falla (al fin y al cabo, la comunicación es cosa de 2: servidor y cliente).</p>
<p>Vamos primero a ver cómo configurar nuestro servidor web para hacer eso:</p>
<p>Lo primero de todo es comprobar que estamos afectados, ya que quizás el servidor web que estamos utilizando YA está configurado de forma que no permite la utilización de protocolos anteriores a TLS, por lo que podemos utilizar cualquiera de éstas 2 webs para comprobarlo:</p>
<ul>
<li>http://poodlebleed.com/server.php</li>
<li>https://www.tinfoilsecurity.com/poodle</li>
</ul>
<p>Solo tenemos que poner la URL de nuestro servidor, y nos dirá si podemos estar afectados por Poodle o no.</p>
<p>Y no os preocupeis si lo estais, ya que es MUY sencillo solucionarlo:</p>
<h3>Apache HTTPd server</h3>
<p>Basta con incluir ésta linea en la configuración del servidor para obligar a Apache a NO utilizar las versiones antiguas del protocolo:</p>
<div class="highlight"><pre><span></span><code><span class="nb">SSLProtocol</span> <span class="k">All</span> -SSLv2 -SSLv3
</code></pre></div>
<p>Y reiniciar el servicio (<code>sudo service apache2 restart</code>).</p>
<h3>Nginx</h3>
<p>También es muy sencillo hacerlo en Nginx, basta con incluir ésta linea en su configuración:</p>
<div class="highlight"><pre><span></span><code><span class="nb">ssl_protocols</span> TLSv1 TLSv1.1 TLSv1.2;
</code></pre></div>
<p>Y reiniciar el servicio (<code>sudo service nginx restart</code>).</p>
<h3>Lighttpd</h3>
<p>En versiones posteriores a la 1.4.28, no hay problema en configurar Lighttpd para que NO utilice SSLv2 ni SSLv3, pero en las versiones anteriores únicamente se puede deshabilitar el uso de SSLv2.</p>
<p>Por tanto, en éste servidor habría que editar el archivo <code>/etc/lighttpd/lighttpd.conf</code> y añadir las siguientes lines después de la directiva <code>ssl.engine = "enable"</code>:</p>
<div class="highlight"><pre><span></span><code><span class="k">ssl.use-sslv</span><span class="m">2</span> <span class="o">=</span> <span class="s2">"disable"</span>
<span class="k">ssl.use-sslv</span><span class="m">3</span> <span class="o">=</span> <span class="s2">"disable"</span>
</code></pre></div>
<p>Y reiniciar el servicio (<code>sudo service lighttpd restart</code>).</p>
<p>Todos los servicios que usen SSL se ven afectados por éste problema, por lo que aparte de los servidores web se puede explotar ésta vulnerabilidad (aunque es más complicado) en muchos otros servicios, como Postfix, Sendmail, Courier, Dovecot, OpenVPN, etc. Si quieres ver cómo <em>securizar</em> también éstos servicios, <a href="http://askubuntu.com/questions/537196/how-do-i-patch-workaround-sslv3-poodle-vulnerability-cve-2014-3566">aquí puedes ver detalladamente varios de ellos</a>.</p>
<p>Pero, ¿y si los <em>sysadmins</em> de los servidores web a los que os conectais habitualmente NO han leído aún éste maravilloso artículo de pornoHARDWARE.com, y aún no han actualizado sus servidores? No hay problema, ya que como dije antes, la comunicación es cosa de 2, así que si no tenemos control sobre el servidores al que nos conectamos, debemos configurar el cliente que se va a conectar a ese servidor (es decir, nuestro navegador):</p>
<h3>Firefox / Iceweasel</h3>
<p>Si usais éste genial navegador, solo teneis que acceder a la configuración avanzada de <em>propiedades</em>. Para hacer ésto, basta con abrir una nueva pestaña del navegador, y teclear <code>about:config</code> en la barra de direcciones.</p>
<p>Una vez hayamos hecho eso, solo tenemos que buscar la propiedad <code>security.tls.version.min</code> y poner su valor a <code>1</code>.</p>
<p><img class="center" src="/images/posts/firefox_properties_tlsmin.png"></p>
<p>Hay que reiniciar el navegador para cerrar las conexiones SSL que tuviéramos abiertas en ese momento, para que al abrirse de nuevo lo hagan utilizando el valor de la propiedad que acabamos de configurar.</p>
<h3>Google Chrome / Chromium (Linux únicamente)</h3>
<p>Tanto si usais <a href="https://www.chromium.org/Home">Chromium</a> como si utilizais el asqueroso, intrusivo y deleznable (aunque rápido, hay que reconocerlo) navegador de la empresa <a href="http://www.huyedelacorporacion.com">cuyo nombre no diré aquí</a>, debeis editar el archivo que se usa para <em>lanzar</em> la aplicación, y editar todas las lineas que comiencen por <code>Exec=</code> para incluir la opción <code>--ssl-version-min=tls1</code>.</p>
<p>Dependiendo de su usais Chrome o Chromium éstos archivos pueden ser:</p>
<ul>
<li>/usr/share/applications/google-chrome.desktop</li>
<li>/usr/share/applications/chromium.desktop</li>
</ul>
<p>Por ejemplo:</p>
<div class="highlight"><pre><span></span><code><span class="err">[Desktop</span> <span class="err">Entry]</span>
<span class="na">Version</span><span class="o">=</span><span class="s">1.0</span>
<span class="na">Name</span><span class="o">=</span><span class="s">Chromium Web Browser</span>
<span class="na">GenericName</span><span class="o">=</span><span class="s">Web Browser</span>
<span class="na">Comment</span><span class="o">=</span><span class="s">Access the Internet</span>
<span class="na">Exec</span><span class="o">=</span><span class="s">/usr/bin/chromium --ssl-version-min=tls1 %U</span>
<span class="na">Terminal</span><span class="o">=</span><span class="s">false</span>
<span class="na">X-MultipleArgs</span><span class="o">=</span><span class="s">false</span>
<span class="na">Type</span><span class="o">=</span><span class="s">Application</span>
<span class="na">Icon</span><span class="o">=</span><span class="s">chromium</span>
<span class="na">Categories</span><span class="o">=</span><span class="s">Network;WebBrowser;</span>
<span class="na">MimeType</span><span class="o">=</span><span class="s">text/html;text/xml;application/xhtml_xml;x-scheme-handler/http;x-scheme-handler/https;</span>
<span class="na">StartupWMClass</span><span class="o">=</span><span class="s">Chromium</span>
<span class="na">StartupNotify</span><span class="o">=</span><span class="s">true</span>
</code></pre></div>
<p>Al igual que antes, debemos reiniciar el navegador para cerrar las conexiones SSL que tuviéramos abiertas en ese momento.</p>
<h3>Apple Safari</h3>
<p>Según leo en Internet, el nuevo sistema operativo de Apple lanzado la semana pasada (Yosemite) ya está protegido contra ésta vulnerabilidad, y para las versiones anteriores (Mavericks y Mountain Lion) el problema está también solucionado si aplicais la actualización 2014-005 que salió hace 3 dias (17/Oct/2014), así que es bastante sencillo solucionar el problema si sois usuarios de la manzana...</p>
<h3>Internet Explorer</h3>
<p>Estás de coña, no? Obviamente ni se cómo solucionar éste problema en Explorer, ni me importa lo más mínimo! ;)</p>
<p>Así que lo dicho, esto es todo, amigos... espero que éste artículo os haya resultado útil, y todos podamos seguir disfrutando de la poquita privacidad que nos queda...</p>
<p>Alaaaaaaaaaaaaaaaaaaa</p>
<hr>
<p><em>Edito el 12/Dic/2014:</em> Parece que POODLE no solo afecta a SSL, sino que se ha descubierto que <a href="https://blog.qualys.com/ssllabs/2014/12/08/poodle-bites-tls">hay versiones de TLS que también se ven afectadas por ésta vulnerabilidad</a>!</p>
<h2>Referencias</h2>
<ul>
<li><a href="http://www.hackplayers.com/2014/10/poodle-o-como-un-caniche-mato-ssl.html">http://www.hackplayers.com/2014/10/poodle-o-como-un-caniche-mato-ssl.html</a></li>
<li><a href="http://poodlebleed.com/">http://poodlebleed.com/</a></li>
<li><a href="https://www.tinfoilsecurity.com/poodle">https://www.tinfoilsecurity.com/poodle</a></li>
<li><a href="http://askubuntu.com/questions/537196/how-do-i-patch-workaround-sslv3-poodle-vulnerability-cve-2014-3566">http://askubuntu.com/questions/537196/how-do-i-patch-workaround-sslv3-poodle-vulnerability-cve-2014-3566</a></li>
<li><a href="https://nakedsecurity.sophos.com/2014/10/17/apple-kills-the-poodle-also-fixes-shellshock-in-case-you-forgot/">https://nakedsecurity.sophos.com/2014/10/17/apple-kills-the-poodle-also-fixes-shellshock-in-case-you-forgot/</a></li>
</ul>jekyll-vimeo-lazyloading: Un nuevo plugin para mostrar videos de Vimeo en Octopress2014-09-27T02:13:36+02:002014-09-27T02:13:36+02:00BhEaNtag:pornohardware.com,2014-09-27:/2014/09/27/jekyll-vimeo-lazyloading-un-nuevo-plugin-para-mostrar-videos-de-vimeo-en-octopress/<p><img class="left" src="/images/logos/logo_vimeo.png"/>
Lo prometido es deuda... y tal y como comenté en mi artículo sobre <a href="/2014/07/12/seleccion-de-plugins-para-octopress">plugins para Octopress</a>, finalmente he desarrollado un nuevo plugin para mostrar los videos del genial <a href="https://www.vimeo.com">Vimeo</a> en aquellos blogs basados en <a href="http://jekyllrb.com/">Jekyll</a> y <a href="http://octopress.org/">Octopress</a> de forma que el reproductor embebido no se cargue hasta que el usuario no haga <em>click</em> en dicho video.</p>
<p>De ésta forma evitamos la carga innecesaria del <code>iframe</code> de Vimeo en aquellas páginas en las que el usuario no está interesado en reproducir los videos que hay en ella.</p>
<p>¿Nunca os ha pasado que al entrar en una página, varios videos (sobre todo del <em>asqueroso</em> <a href="https://www.youtube.com/">Youtube</a>) comienzan a reproducirse automaticamente (con audio incluido), molestandoos no solo a vosotros sino a todos los que os rodean (en caso de tener el volumen activado)?</p>
<p><img class="left" src="/images/logos/logo_vimeo.png">
Lo prometido es deuda... y tal y como comenté en mi artículo sobre <a href="/2014/07/12/seleccion-de-plugins-para-octopress">plugins para Octopress</a>, finalmente he desarrollado un nuevo plugin para mostrar los videos del genial <a href="https://www.vimeo.com">Vimeo</a> en aquellos blogs basados en <a href="http://jekyllrb.com/">Jekyll</a> y <a href="http://octopress.org/">Octopress</a> de forma que el reproductor embebido no se cargue hasta que el usuario no haga <em>click</em> en dicho video.</p>
<p>De ésta forma evitamos la carga innecesaria del <code>iframe</code> de Vimeo en aquellas páginas en las que el usuario no está interesado en reproducir los videos que hay en ella.</p>
<p>¿Nunca os ha pasado que al entrar en una página, varios videos (sobre todo del <em>asqueroso</em> <a href="https://www.youtube.com/">Youtube</a>) comienzan a reproducirse automaticamente (con audio incluido), molestandoos no solo a vosotros sino a todos los que os rodean (en caso de tener el volumen activado)?</p>
<p>Es terrible... por no mencionar el <em>coste</em> que supone para el navegador tener que cargar todos esos reproductores (que además la mayor parte de las veces estan hechos en <em><a href="http://es.wikipedia.org/wiki/Adobe_Flash_Player">aquel terrible invento cuyo nombre no diré aquí</a>)</em> provocando una lentitud innecesaria si vuestro equipo/linea no son lo suficientemente potentes.</p>
<p>Para evitar ésto se inventó el concepto del <em><a href="https://es.wikipedia.org/wiki/Lazy_loading">lazy loading</a></em>, que consiste en la inicialización de los objetos a medida que vayamos a usarlos, no antes.</p>
<p>Es decir, <em>lazy loading</em> es un patrón de diseño que aplicado a este tema de los videos, evitaría que cargáramos dichos reproductores a no ser que realmente vayamos a usarlos.</p>
<p>Este plugin utiliza la <a href="https://es.wikipedia.org/wiki/Interfaz_de_programaci%C3%B3n_de_aplicaciones">API</a> pública de Vimeo para mostrar un <a href="https://es.wikipedia.org/wiki/Thumbnail">thumbnail</a> (o previsualización) del video para que se vea <em>de qué va</em> dicho video, pero sin llegar a cargarlo... y cuando hacemos click en él, dicho thumbnail se sustituye por el video en cuestión.</p>
<p>Cono no tengo mucha idea de <a href="https://es.wikipedia.org/wiki/Ruby">Ruby</a>, me he basado en un plugin que hace ésto mismo pero para los videos de Youtube. Podeis ver éste plugin aquí: <a href="https://github.com/erossignon/jekyll-youtube-lazyloading">https://github.com/erossignon/jekyll-youtube-lazyloading</a></p>
<p>El repositorio está en mi <a href="https://code.vandalsweb.com/bhean/jekyll-vimeo-lazyloading">Gitlab personal</a>, pero lo he subido también a <a href="https://github.com/bhean/jekyll-vimeo-lazyloading">Github</a> para aquellos raros a los que os gusta más este último.</p>
<h2>Instalación</h2>
<p>La instalación del plugin no podría ser más sencilla. Únicamente teneis que descargar el código desde el <a href="https://github.com/bhean/jekyll-vimeo-lazyloading">repositorio público</a> y seguir las instrucciones del archivo <code>README</code>, que son básicamente éstas:</p>
<ol>
<li>Copiar el archivo <code>vimeo.rb</code> (el codigo del propio plugin) a vuestro directorio <code>plugins</code>.</li>
<li>Copiar el archivo <code>_rve.sccs</code> (los estilos <a href="https://es.wikipedia.org/wiki/Hoja_de_estilos_en_cascada">CSS</a>) a vuestro directorio <code>/sass/custom</code>.</li>
<li>Copiar los archivos <code>video-play-button.png</code> y <code>video-play-button-hover.png</code> (las imágenes de <em>PLAY</em> del video) a vuestro directorio <code>/source/images</code>.</li>
<li>Añadir <code>@import "custom/rve"</code> a vuestro archivo <code>/sass/screen.scss</code>.</li>
</ol>
<h2>Utilización</h2>
<p>Una vez instalado, se utiliza igual que cualquier otro <em>tag</em> de Jekyll/Octopress.</p>
<p>La forma de utilizarlo dentro de cualquier <em>post</em> de <em>Octopress</em> sería:</p>
<div class="highlight"><pre><span></span><code><span class="p">{</span><span class="o">%</span> <span class="n">vimeo</span> <span class="o"><</span><span class="n">video_id</span><span class="o">></span> <span class="p">[</span><span class="n">ancho</span><span class="p">]</span> <span class="p">[</span><span class="n">alto</span><span class="p">]</span> <span class="p">[</span><span class="n">texto</span> <span class="n">alternativo</span><span class="p">]</span> <span class="o">%</span><span class="p">}</span>
</code></pre></div>
<p>Los parámetros que admite el plugin son:</p>
<ul>
<li><em>video_id</em> (parámetro obligatorio): Especifica el ID del video que queremos utilizar. Es la parte numérica de la URL del video en Vimeo. Por ejemplo, en el video https://vimeo.com/49957083 el ID sería <strong>49957083</strong>.</li>
<li><em>ancho</em> (parametro opcional): Podemos utilizar éste parámetro para indicar un ancho fijo (en <em>pixeles</em>) al video. Si no lo especificamos, el video ocupará todo el ancho que le sea posible (100%).</li>
<li><em>alto</em> (parametro opcional): Al igual que el parámetro anterior, podemos utilizar indicar el alto (en <em>pixeles</em>) que ocupará el video. Si no lo especificamos, el video ocupará todo el alto que le sea posible (100%).</li>
<li><em>texto alternativo</em> (parámetro opcional): Este parámetro se usa para indicar el texto que queremos que aparezca al situar el puntero del ratón sobre el video (antes de reproducirlo). El valor por defecto del texto alternativo si no especificamos éste parámetro es "<em>Click here to play</em>".</li>
</ul>
<p>La forma más clara de ver su utilización es con un ejemplo.
Si utilizamos éste tag:</p>
<div class="highlight"><pre><span></span><code><span class="err">{% vimeo 102875092 Timelapse en Seseña / Toledo %}</span>
</code></pre></div>
<p>Se mostrará ésto (<em>Al dejar el ratón encima del video (antes de darle al "play") vereis el texto alternativo</em>):</p>
<p><span class="videobox">
<iframe
src="//player.vimeo.com/video/102875092?title=0&byline=0&portrait=0"
width="640" height="390" frameborder="0"
webkitAllowFullScreen mozallowfullscreen allowFullScreen>
</iframe>
</span></p>
<p><em>Nota</em>: <em>a raíz de la migración de esta web de Octopress a <a href="/2017/03/23/adios-octopress-hola-pelican/">Pelican</a>, el resultado del plugin no se va a mostrar correctamente aquí, obviamente... pero funciona perfectamente si vuestra web está hecha con <a href="http://jekyllrb.com/">Jekyll</a> u <a href="http://octopress.org/">Octopress</a></em>.</p>
<p>Espero que os resulte útil, y si encontrais algun <em>bug</em> o quereis añadir alguna cosa de utilidad al plugin, no dudeis en <a href="http://techtastico.com/post/como-colaborar-en-un-proyecto-github/">hacer un <em>fork</em> del repositorio y colaborar</a>.</p>
<p>Alaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</p>
<h2>Referencias</h2>
<ul>
<li><a href="https://github.com/erossignon/jekyll-youtube-lazyloading">https://github.com/erossignon/jekyll-youtube-lazyloading</a></li>
<li><a href="https://code.vandalsweb.com/bhean/jekyll-vimeo-lazyloading">https://code.vandalsweb.com/bhean/jekyll-vimeo-lazyloading</a></li>
</ul>Diagramas, mapas de red y demás gráficas estructuradas con Graphviz2014-09-18T09:53:36+02:002014-09-18T09:53:36+02:00BhEaNtag:pornohardware.com,2014-09-18:/2014/09/18/diagramas-mapas-de-red-y-demas-graficas-estructuradas-con-graphviz/<p>Hoy voy a hablar de <a href="http://www.graphviz.org">Graphviz</a>, un proyecto que tiene ya unos cuantos años, y que si has ido a la universidad seguramente ya conozcas (al parecer se usa en muchas de ellas).</p>
<p><img class="right" src="/images/logos/logo_graphviz.png"/>
Para los que no, es algo que os puede resultar muy util a la hora de hacer gráficas relacionales, mapas de red, diagramas de flujo y cualquier otro tipo de representación gráfica similar. Libre, gratuito, facil de usar, potente y se maneja desde la linea de comandos de Linux... es decir, que es uno de esos programas a los que solo les falta <em>tener tetas</em> para ser perfecto...</p>
<p>Graphviz permite generar imágenes (<a href="http://es.wikipedia.org/wiki/Portable_Network_Graphics">PNG</a>, <a href="http://es.wikipedia.org/wiki/Scalable_Vector_Graphics">SVG</a>, <a href="http://es.wikipedia.org/wiki/Graphics_Interchange_Format">GIF</a>, etc) a partir de los datos que definamos mediante texto plano en un archivo, y el resultado no tiene nada que envidiar a algunos de los mejores servicios <em>online</em> de diseño de gráficas de éste tipo (como por ejemplo el genial <a href="https://www.gliffy.com">Gliffy</a>, que esta muy bien y es gratuito para un par de gráficas... pero cuando necesitas hacer más o usar opciones avanzadas, hay que pagar, y no es NADA barato).</p>
<p>Hoy voy a hablar de <a href="http://www.graphviz.org">Graphviz</a>, un proyecto que tiene ya unos cuantos años, y que si has ido a la universidad seguramente ya conozcas (al parecer se usa en muchas de ellas).</p>
<p><img class="right" src="/images/logos/logo_graphviz.png">
Para los que no, es algo que os puede resultar muy util a la hora de hacer gráficas relacionales, mapas de red, diagramas de flujo y cualquier otro tipo de representación gráfica similar. Libre, gratuito, facil de usar, potente y se maneja desde la linea de comandos de Linux... es decir, que es uno de esos programas a los que solo les falta <em>tener tetas</em> para ser perfecto...</p>
<p>Graphviz permite generar imágenes (<a href="http://es.wikipedia.org/wiki/Portable_Network_Graphics">PNG</a>, <a href="http://es.wikipedia.org/wiki/Scalable_Vector_Graphics">SVG</a>, <a href="http://es.wikipedia.org/wiki/Graphics_Interchange_Format">GIF</a>, etc) a partir de los datos que definamos mediante texto plano en un archivo, y el resultado no tiene nada que envidiar a algunos de los mejores servicios <em>online</em> de diseño de gráficas de éste tipo (como por ejemplo el genial <a href="https://www.gliffy.com">Gliffy</a>, que esta muy bien y es gratuito para un par de gráficas... pero cuando necesitas hacer más o usar opciones avanzadas, hay que pagar, y no es NADA barato).</p>
<h2>Instalación</h2>
<p>La instalación de Graphviz es absolutamente trivial, al menos si usamos una distribución de Linux decente como por ejemplo <a href="http://www.debian.org">Debian</a>. En éste caso (o en el de las que se basan en ella, como por ejemplo <a href="http://www.ubuntu.com">Ubuntu</a>), bastaría con:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install graphviz
</code></pre></div>
<p>Si por algun motivo (por ejemplo, que seamos masoquistas) utilizamos <a href="https://www.centos.org/">CentOS</a>, <a href="http://www.redhat.com/es">Redhat</a> o similares, podemos instalarlo también de forma muy facil con:</p>
<div class="highlight"><pre><span></span><code>$ sudo yum install graphviz
</code></pre></div>
<p>Con ésto ya tendríamos instalado Graphviz y su <em>lenguaje</em> (llamado <a href="http://www.graphviz.org/content/dot-language">DOT</a>).</p>
<p>Graphviz incluye también varios algoritmos de trazado gráfico diferentes, cada uno de los cuales crea gráficas de diferente tipo. Los más utilizados son:</p>
<ul>
<li><a href="http://www.graphviz.org/pdf/dot.1.pdf">DOT</a>: Es el mejor para las gráfica de tipo <em>jerárquico</em>.</li>
<li><a href="http://www.graphviz.org/pdf/neato.1.pdf">NEATO</a>: Se utiliza para el dibujado de <em>gráficos indirectos</em>.</li>
<li><a href="http://www.graphviz.org/pdf/fdp.1.pdf">FDP</a>: También se utiliza para el dibujado de <em>gráficos indirectos</em>.</li>
<li><a href="http://www.graphviz.org/pdf/twopi.1.pdf">TWOPI</a>: Este algoritmo dibuja los elementos de la gráfica situándolos de forma circular alrededor del elemento raiz.</li>
</ul>
<p>En artículo vamos a utilizar fundamentalmente el algoritmo <code>DOT</code>, ya que es el más común (aunque dependiendo de tus necesidades, quizás te convenga más utilizar otro en algun momento.</p>
<h2>Utilización</h2>
<p>Hay muchísimos usos en la vida para una gráfica del tipo <em>relacional</em>: mapas de red, esquemas de bases de datos SQL, flujos de datos, organigramas, etc.</p>
<p>Un ejemplo simple para ilustrar el tema sería la preparación de una tortilla (estoy escribiendo ésto de madrugada y tengo mucha hambre, no se me ocurre otra cosa mejor ahora mismo, lo siento).</p>
<p>Partiríamos de un montón de ingredientes sobre la mesa:</p>
<ul>
<li>Huevos</li>
<li>Patatas</li>
<li>Aceite</li>
<li>Sal</li>
<li>Cebolla <em>(porque <a href="http://www.taringa.net/posts/noticias/17217717/Le-Disparan-por-no-ponerle-cebolla-a-la-tortilla.html">sin cebolla NO ES tortilla</a>, obviamente)</em></li>
</ul>
<p>Lo primero que tendríamos que hacer sería pelar las patatas...</p>
<p>Una vez peladas hay que cortarlas y freirlas un poco hasta que se hayan dorado.
Después, batimos los huevos, y echamos un poco de sal.
Ponemos las patatas ya doradas en otra sartén, echamos los huevos batidos, y esperamos a que se haga un poco.</p>
<p>Al cabo del rato, le damos la vuelta a la tortilla y esperamos a que se haga éste otro lado tambien... y cuando esté lista, la servimos en un plato y <em>pa'dentro</em>.</p>
<p>Se podría <em>esquematizar</em> este proceso de la siguiente forma:</p>
<div class="highlight"><pre><span></span><code><span class="err">Ingredientes -> pelar patatas -> cortar patatas -> dorar patatas -> batir huevos -> echar sal -> mezclar huevos y patatas -> cocinar -> plato terminado</span>
</code></pre></div>
<p>Cualquiera que vea ésto enseguida identifica un <em>flujo</em>, una <strong>serie de pasos</strong> que hay que hacer uno detrás del otro, y en un orden predefinido.</p>
<p>Pues bien, para dibujar una gráfica que represente precisamente ésto, con Graphviz únicamente tendríamos que definir las <em>acciones</em> y el orden en el que deben producirse. Por lo tanto, utilizando el lenguaje <code>dot</code>, el código sería algo así:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-filename">tortilla_v1.dot</span><a href='/graphviz/tortilla_v1.dot'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="n">digraph</span> <span class="n">tortilla_v1</span> <span class="p">{</span>
<span class="n">ingredientes</span> <span class="o">-></span> <span class="n">pelar_patatas</span>
<span class="n">pelar_patatas</span> <span class="o">-></span> <span class="n">cortar_patatas</span>
<span class="n">cortar_patatas</span> <span class="o">-></span> <span class="n">freir_patatas</span>
<span class="n">freir_patatas</span> <span class="o">-></span> <span class="n">esperar_a_que_se_doren</span>
<span class="n">esperar_a_que_se_doren</span> <span class="o">-></span> <span class="n">batir_huevos</span>
<span class="n">batir_huevos</span> <span class="o">-></span> <span class="n">echar_sal</span>
<span class="n">echar_sal</span> <span class="o">-></span> <span class="n">mezclar_huevos_patatas</span>
<span class="n">mezclar_huevos_patatas</span> <span class="o">-></span> <span class="n">cocinar</span>
<span class="n">cocinar</span> <span class="o">-></span> <span class="n">dar_la_vuelta</span>
<span class="n">dar_la_vuelta</span> <span class="o">-></span> <span class="n">cocinar_de_nuevo</span>
<span class="n">cocinar_de_nuevo</span> <span class="o">-></span> <span class="n">servir</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Sencillísimo, verdad? Ahora ejecutamos Graphviz (a través del comando <code>dot</code>) con el archivo que acabamos de crear (<code>tortilla.dot</code>) de ésta forma:</p>
<div class="highlight"><pre><span></span><code>$ dot -Tpng tortilla.dot -o tortilla.png
</code></pre></div>
<p>Obtendremos un archivo llamado <code>tortilla.png</code> con ésta imagen:</p>
<p><span class="graphviz" style="text-align: center;"><img src="data:image/png;base64,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"></span></p>
<p>El parámetro <code>-T</code> se utiliza para definir el formato que tendrá nuestra gráfica (png, svg, etc), y el <code>-o</code> indica el archivo donde guardaremos la gráfica generada.</p>
<p>No tiene mala pinta, no? Pues ahora vamos a darle una vuelta de tuerca más para profundizar en las opciones de Graphviz.</p>
<p>Podemos definir no solo las relaciones, sino la forma que tendrán éstas, colores (fondo, letra, etc), tamaños, incluso utilizar imágenes para los nodos, y mil cosas más (todas ellas explicadas en la <a href="http://www.graphviz.org/Documentation.php">documentación oficial de Graphviz</a>.</p>
<p>Si pensamos en la forma en la que hemos descrito el proceso para hacer la tortilla, realmente no es un proceso lineal, sino que hay cosas que se pueden hacer al mismo tiempo. Es decir, no tenemos que esperar a que las patatas se doren para batir los huevos, sino que podemos batirlos mientras las patatas se estan dorando. Por lo tanto, el proceso ya no es lineal, sino que se puede dividir en 2 procesos paralelos.</p>
<p>Para representar ésto, basta con crear 2 subfunciones dentro de la función principal que hemos definido (una para cada proceso), pero únicamente para las acciones que vamos a realizar en paralelo, el resto de acciones siguen en la función principal igual que antes.</p>
<p>Es MUY importante que el nombre de estas funciones comience por <code>cluster_</code>, ya que de lo contrario no funcionará):</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-filename">tortilla_v2.dot</span><a href='/graphviz/tortilla_v2.dot'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="n">digraph</span> <span class="n">tortilla_v2</span> <span class="p">{</span>
<span class="n">subgraph</span> <span class="n">cluster_patatas</span> <span class="p">{</span>
<span class="n">esperar_a_que_se_doren</span> <span class="o">-></span> <span class="n">echar_sal_patatas</span>
<span class="p">}</span>
<span class="n">subgraph</span> <span class="n">cluster_huevos</span> <span class="p">{</span>
<span class="n">batir_huevos</span> <span class="o">-></span> <span class="n">echar_sal_huevos</span>
<span class="p">}</span>
<span class="n">ingredientes</span> <span class="o">-></span> <span class="n">pelar_patatas</span>
<span class="n">pelar_patatas</span> <span class="o">-></span> <span class="n">cortar_patatas</span>
<span class="n">cortar_patatas</span> <span class="o">-></span> <span class="n">freir_patatas</span>
<span class="n">freir_patatas</span> <span class="o">-></span> <span class="n">esperar_a_que_se_doren</span>
<span class="n">freir_patatas</span> <span class="o">-></span> <span class="n">batir_huevos</span>
<span class="n">echar_sal_patatas</span> <span class="o">-></span> <span class="n">mezclar_huevos_patatas</span>
<span class="n">echar_sal_huevos</span> <span class="o">-></span> <span class="n">mezclar_huevos_patatas</span>
<span class="n">mezclar_huevos_patatas</span> <span class="o">-></span> <span class="n">cocinar</span>
<span class="n">cocinar</span> <span class="o">-></span> <span class="n">dar_la_vuelta</span>
<span class="n">dar_la_vuelta</span> <span class="o">-></span> <span class="n">cocinar_de_nuevo</span>
<span class="n">cocinar_de_nuevo</span> <span class="o">-></span> <span class="n">servir</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Y el resultado después de ejecutar el comando <code>dot</code> igual que antes sería:</p>
<p><span class="graphviz" style="text-align: center;"><img src="data:image/png;base64,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jg6jYtkXOzs7ODk5GRVtlUoFV1dXuLq6Gh6rVCoe8iYiU2LZJKKRqWfv30+nnvmtra2GgqfRaKDX641KYGtrK9rb2wEYl8UePXscf8rW1rbXHtQby6qZmVmfpdbOzg5yuRxKpdLw9capZ2+to6MjlEolLCwsTPTOERHdFpZNIiJTk8lk2Lt3L+677z6poxARDbb9vLYIEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZmMhdQBiIiGk5ycHHR2dvaaX1JSgrNnzxrNCwwMhJ2d3WBFIyKShEwIIaQOQUQ0XKxcuRIHDx685XJWVlaora2Fg4PDIKQiIpLMfh5GJyIaQGvXrr3lMubm5li6dCmLJhGNCCybREQDKD4+HjY2Nj+7THd3N9avXz9IiYiIpMWySUQ0gKysrJCQkAC5XH7TZaytrbF48eJBTEVEJB2WTSKiAXb//ff3eZIQAMjlcqxevRpWVlaDnIqISBosm0REA2zBggVwcnLq87nOzk7cf//9g5yIiEg6LJtERAPMwsICa9eu7fNQ+qhRozB37lwJUhERSYNlk4jIBNauXdvrULpCocD69ethbm4uUSoiosHHsklEZAJRUVHw8PAwmtfR0dGvSyMREQ0nLJtERCYgk8mwYcMGo0PpXl5emD59uoSpiIgGH8smEZGJ3HgoXaFQYNOmTZDJZBKnIiIaXCybREQmEhoaCj8/PwA/HkJfs2aNxImIiAYfyyYRkQlt2rQJABAcHIyJEydKnIaIaPBZSB2AiGioa29vR2trK9ra2qDT6dDS0oKOjg4AQFNTE/R6fa/X9CyjVCohk8kQFhaG/fv3A8BNr8Hp6OgIMzMzyGQyKJVKmJubw8HBARYWFrC3tzfdBhIRmZBMCCGkDkFEZAo6nQ719fWoq6tD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"></span></p>
<p>Vamos a modificar otra cosa más...</p>
<p>La acción de <code>dar_la_vuelta</code> y <code>cocinar</code> puede repetirse tantas veces como sea necesario hasta que la tortilla quede en su punto, verdad? Por lo tanto, hay que modificar el código para indicar que esas acciones se pueden repetir varias veces. Para eso, basta con indicar que al igual que <code>dar_la_vuelta</code> <em>cuelga</em> de <code>cocinar</code>, ahora <code>cocinar</code> tambien colgará de <code>dar_la_vuelta</code>:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-filename">tortilla_v3.dot</span><a href='/graphviz/tortilla_v3.dot'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="n">digraph</span> <span class="n">tortilla_v3</span> <span class="p">{</span>
<span class="n">subgraph</span> <span class="n">cluster_patatas</span> <span class="p">{</span>
<span class="n">esperar_a_que_se_doren</span> <span class="o">-></span> <span class="n">echar_sal_patatas</span>
<span class="p">}</span>
<span class="n">subgraph</span> <span class="n">cluster_huevos</span> <span class="p">{</span>
<span class="n">batir_huevos</span> <span class="o">-></span> <span class="n">echar_sal_huevos</span>
<span class="p">}</span>
<span class="n">ingredientes</span> <span class="o">-></span> <span class="n">pelar_patatas</span>
<span class="n">pelar_patatas</span> <span class="o">-></span> <span class="n">cortar_patatas</span>
<span class="n">cortar_patatas</span> <span class="o">-></span> <span class="n">freir_patatas</span>
<span class="n">freir_patatas</span> <span class="o">-></span> <span class="n">esperar_a_que_se_doren</span>
<span class="n">freir_patatas</span> <span class="o">-></span> <span class="n">batir_huevos</span>
<span class="n">echar_sal_patatas</span> <span class="o">-></span> <span class="n">mezclar_huevos_patatas</span>
<span class="n">echar_sal_huevos</span> <span class="o">-></span> <span class="n">mezclar_huevos_patatas</span>
<span class="n">mezclar_huevos_patatas</span> <span class="o">-></span> <span class="n">cocinar</span>
<span class="n">cocinar</span> <span class="o">-></span> <span class="n">dar_la_vuelta</span>
<span class="n">dar_la_vuelta</span> <span class="o">-></span> <span class="n">cocinar</span>
<span class="n">dar_la_vuelta</span> <span class="o">-></span> <span class="n">servir</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Con esa modificación, la imagen resultante sería ésta:</p>
<p><span class="graphviz" style="text-align: center;"><img src="data:image/png;base64,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jg6jYtkXOzs7ODk5GRVtlUoFV1dXuLq6Gh6rVCoe8iYiU2LZJKKRqWfv30+nnvmtra2GgqfRaKDX641KYGtrK9rb2wEYl8UePXscf8rW1rbXHtQby6qZmVmfpdbOzg5yuRxKpdLw9capZ2+to6MjlEolLCwsTPTOERHdFpZNIiJTk8lk2Lt3L+677z6poxARDbb9vLYIEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZkMyyYRERERmQzLJhERERGZDMsmEREREZmMhdQBiIiGk5ycHHR2dvaaX1JSgrNnzxrNCwwMhJ2d3WBFIyKShEwIIaQOQUQ0XKxcuRIHDx685XJWVlaora2Fg4PDIKQiIpLMfh5GJyIaQGvXrr3lMubm5li6dCmLJhGNCCybREQDKD4+HjY2Nj+7THd3N9avXz9IiYiIpMWySUQ0gKysrJCQkAC5XH7TZaytrbF48eJBTEVEJB2WTSKiAXb//ff3eZIQAMjlcqxevRpWVlaDnIqISBosm0REA2zBggVwcnLq87nOzk7cf//9g5yIiEg6LJtERAPMwsICa9eu7fNQ+qhRozB37lwJUhERSYNlk4jIBNauXdvrULpCocD69ethbm4uUSoiosHHsklEZAJRUVHw8PAwmtfR0dGvSyMREQ0nLJtERCYgk8mwYcMGo0PpXl5emD59uoSpiIgGH8smEZGJ3HgoXaFQYNOmTZDJZBKnIiIaXCybREQmEhoaCj8/PwA/HkJfs2aNxImIiAYfyyYRkQlt2rQJABAcHIyJEydKnIaIaPBZSB2AiGioa29vR2trK9ra2qDT6dDS0oKOjg4AQFNTE/R6fa/X9CyjVCohk8kQFhaG/fv3A8BNr8Hp6OgIMzMzyGQyKJVKmJubw8HBARYWFrC3tzfdBhIRmZBMCCGkDkFEZAo6nQ719fWoq6tD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"></span></p>
<p>Y añadiendo algunas cosas al código, podemos personalizar aún más la gráfica. Por ejemplo, vamos a cambiar la forma y el color de la acción inicial (<code>ingredientes</code>) y la acción final (<code>servir</code>) para que se diferencien de las demás, a meter los procesos que realizamos en paralelo en un cuadro, y un par de retoques más.</p>
<p>El código quedaría así:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-filename">tortilla_v4.dot</span><a href='/graphviz/tortilla_v4.dot'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="n">digraph</span> <span class="n">tortilla_v4</span> <span class="p">{</span>
<span class="n">subgraph</span> <span class="n">cluster_patatas</span> <span class="p">{</span>
<span class="n">node</span> <span class="p">[</span><span class="n">style</span><span class="o">=</span><span class="n">filled</span><span class="p">];</span>
<span class="n">esperar_a_que_se_doren</span> <span class="o">-></span> <span class="n">echar_sal_patatas</span>
<span class="n">label</span> <span class="o">=</span> <span class="s2">"Patatas"</span><span class="p">;</span>
<span class="n">color</span><span class="o">=</span><span class="n">blue</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">subgraph</span> <span class="n">cluster_huevos</span> <span class="p">{</span>
<span class="n">node</span> <span class="p">[</span><span class="n">style</span><span class="o">=</span><span class="n">filled</span><span class="p">];</span>
<span class="n">batir_huevos</span> <span class="o">-></span> <span class="n">echar_sal_huevos</span>
<span class="n">label</span> <span class="o">=</span> <span class="s2">"Huevos"</span><span class="p">;</span>
<span class="n">color</span><span class="o">=</span><span class="n">blue</span>
<span class="p">}</span>
<span class="n">ingredientes</span> <span class="o">-></span> <span class="n">pelar_patatas</span>
<span class="n">pelar_patatas</span> <span class="o">-></span> <span class="n">cortar_patatas</span>
<span class="n">cortar_patatas</span> <span class="o">-></span> <span class="n">freir_patatas</span>
<span class="n">freir_patatas</span> <span class="o">-></span> <span class="n">esperar_a_que_se_doren</span>
<span class="n">freir_patatas</span> <span class="o">-></span> <span class="n">batir_huevos</span>
<span class="n">echar_sal_patatas</span> <span class="o">-></span> <span class="n">mezclar_huevos_patatas</span>
<span class="n">echar_sal_huevos</span> <span class="o">-></span> <span class="n">mezclar_huevos_patatas</span>
<span class="n">mezclar_huevos_patatas</span> <span class="o">-></span> <span class="n">cocinar</span>
<span class="n">cocinar</span> <span class="o">-></span> <span class="n">dar_la_vuelta</span>
<span class="n">dar_la_vuelta</span> <span class="o">-></span> <span class="n">cocinar</span>
<span class="n">dar_la_vuelta</span> <span class="o">-></span> <span class="n">servir</span>
<span class="n">ingredientes</span> <span class="p">[</span> <span class="n">shape</span><span class="o">=</span><span class="n">Msquare</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">lightgrey</span><span class="p">,</span> <span class="n">style</span><span class="o">=</span><span class="n">filled</span> <span class="p">];</span>
<span class="n">servir</span> <span class="p">[</span> <span class="n">shape</span><span class="o">=</span><span class="n">Msquare</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">lightgrey</span><span class="p">,</span> <span class="n">style</span><span class="o">=</span><span class="n">filled</span> <span class="p">];</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Y la imagen resultante, así:</p>
<p><span class="graphviz" style="text-align: center;"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAApsAAAQcCAYAAADa91A+AAAABmJLR0QA/wD/AP+gvaeTAAAgAElEQVR4nOzdeXxU9b3/8fckmewrZAOSsISABJKAAWU1RBatglSoKAhoaxGrrUuvtw9ae6vVtu74UMu1pS5or7WUoggut8qqQLABgbAoBGQJhJAJJBOyZ5Lv7w9/mWsMIEtODiSv5+MxjyRnzpzzOQPiK2c2hzHGCAAAAGh9i33sngAAAADtF7EJAAAAyxCbAAAAsIyf3QMAuPTV19erqqrqvG9vjJHD4WjFidCWLvTPz+l0Kjg4uBUnAnAxITYBXLCqqioVFBTYPQYuUeHh4UpKSrJ7DAAW4WF0AAAAWIbYBAAAgGWITQAAAFiG2AQAAIBliE0AAABYhtgEAACAZYhNAAAAWIbYBAAAgGWITQAAAFiG2AQAAIBliE0AAABYhtgEAACAZYhNAAAAWIbYBAAAgGWITQAXzBhj9wi4hDU2Nto9AgALEZsALpjD4bB7BFzCfHz4XxHQnvFfOAAAACxDbAIAAMAyxCYAAAAsQ2wCAADAMsQmAAAALENsAgAAwDLEJgAAACxDbAIAAMAyxCYAAAAsQ2wCAADAMsQmAAAALENsAgAAwDLEJgAAACxDbAIAAMAyxCYAAAAsQ2wCAADAMsQmAAAALENsAgAAwDLEJgAAACxDbAIAAMAyxCYAAAAsQ2wCAADAMsQmAAAALENsAgAAwDLEJgAAACxDbAIAAMAyxCYAAAAsQ2wCAADAMsQmAAAALENsAgAAwDLEJgAAACxDbAIAAMAyxCYAAAAsQ2wCAADAMsQmAAAALENsAgAAwDLEJgAAACxDbAIAAMAyxCYAAAAsQ2wCAADAMsQmAAAALENsAgAAwDLEJgAAACxDbAIAAMAyxCYAAAAsQ2wCAADAMsQmALSyDz/8UGlpaUpLS1NmZqbd4wCArYhNALaoqqrS9ddfr3vuucfuUVrd9773PW3fvl1XXnlli+va83EDwKkQmwBsYYxRY2OjGhsb7R6lTdl13FdccYVmzZrVpvsEAEnys3sAAB1TSEiIPvzwQ7vHaHMd9bgBdFyc2QQAAIBlOLMJoM2tWrVK9913n/fnTZs2KSAgoMXyf/3rX5o3b57Wr18vX19fZWRkaO7cuUpMTGy2vf379+u5555Tbm6u6uvrlZKSorvuukt//etf9dlnn0mSJk+erKysrGbbX758uV588UV99tlncrvdkqRPPvlEUVFRKi0t1Z/+9CetWbNGxcXFCgsL0+WXX6677rpLl1122Wn37/F4lJqa2mw/33XcTc5mn+d6Hy1cuFDPPvusJGnLli1KS0uTJPn4+Gjbtm3ntG9Jqqur04IFC/Svf/1LR48eVUBAgAYNGqQpU6YoKytLPj6cwwDQnMMYY+weAsClze12q6Cg4Jxvd++992r16tUtoqtpeXZ2tu644w716dNH27Zt009/+lOlpKTorbfe8q576NAh3XLLLQoKCtLvfvc7ZWRkqLCwUE8++aR2796tyspKbd68+ZT7HTx4sO6++26lpaVpz549mjlzptasWSOPx6MZM2aotrZWjz32mDIzM1VYWKjf//732r59u1555RVlZGScdv9HjhzRM888owMHDqikpOS0+//mcbtcrrPe57neR9LXz9m87LLL9MYbb7T4cziXfT/yyCPewL388stVUVGhhQsXauHChXr11Vc1ZMiQc/57EB4erqSkpHO+HYBLwmJ+BQVw0ZoyZYoyMjIUFBSkoUOHKisrSzt27FBpaal3neeff14nT57U3LlzNWzYMAUHB6t379566qmnVF1dfcbt33HHHRoyZIgCAwOVnp6ubdu2KSoqSs8//7wKCwv1i1/8QqNGjfJu8+mnn5YxRn/4wx/OuP+UlBQ99thjKikpOetjPZd9nut91Jr73rhxo3r37q1hw4YpICBAnTt31n/8x3+oe/fuZ70/AB0LsQngojVgwIBmP8fHx0v6+kxck/Xr10uSRowY0WzdqKgo9ezZ85y232TlypXy8fHRVVdd1Wx5dHS0kpOTtWvXLh07duyM+4+NjT2nADuXfZ7pGE51H7XmvkeOHKmtW7fqt7/9rfLy8ryvqn/vvffO66wmgPaP52wCuGiFhoY2+9nP7+t/spoCp66uTpWVlQoICFBwcHCL24eHh59x+0FBQS2W1dXVqaKiQpI0bNiw09724MGDioqKOuP+O3XqpIMHD55xhnPdZ1xcXLNl33Uftfa+H3roIWVkZOjdd9/VHXfcIUnKzMzUTTfdpDFjxpzVPgF0LMQmgEuWv7+/QkJCVFlZqaqqqhbBd+LEifPaZlhYmKqqqrR582b5+vqecf0z7b+8vNySfZ4Ph8PRKvt2OByaOHGiJk6c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wyI2gXbuV7/6lebPn6+///3veuihh+Tr62v3SECbyM7O1saNG1VaWqprr71WJ0+etHskoEMiNoF2bMmSJXryySf18ssv66abbrJ7HKDN9erVSytWrFBBQYF+8pOf2D0O0CERm0A7VVlZqZ/+9KeaPXu2brvtNtvm+PaLeHJzczVmzBiFhYUpODhY2dnZWr9+fYvbuVwu3XvvverRo4f8/f0VExOjyZMna+vWrWe1X4/Ho0WLFmncuHGKj49XUFCQ0tLS9Pzzz6uxsdG73tKlS73zORwO7d69W1OnTlXnzp29y872IdjzOdaznbNp25WVlVq/fr13P35+frZuS5Jqa2v1m9/8RpdddpmCg4PVqVMnTZw4UcuWLVNDQ8NZ3XdW6tWrl15//XW9+eab+vjjj+0eB+h4DIB2af78+SY0NNS4XC67RzHGGJORkWFCQkLMsGHDzIYNG0xFRYXJzc016enpxt/f36xZs8a7bmFhoenevbuJi4sz77//vjl58qTZsWOHycrKMoGBgWbDhg0ttt2tW7dmy5YvX24kmT/84Q/mxIkTxuVymRdeeMH4+PiYBx98sMV8kyZNMpJMVlaWWb16tamsrDQbN240vr6+53wfnsuxnuucISEhZsSIEafcr13b+vGPf2wiIiLMRx99ZKqqqkxRUZF58MEHjSSzevXqc7jnrHX99debq6++2u4xgI7mH8Qm0E6NHz/eTJs2ze4xvDIyMowks2XLlmbL8/LyjCSTkZHhXXbbbbcZSebNN99stu7Ro0dNQECAyczMbLHtU8Xm6NGjW8wxY8YM43Q6jdvtbra8KTY/+OCD8zq+b89ztsd6rnN+VyDasa2ePXua4cOHt1i3T58+F1VsLl682Pj5+ZnS0lK7RwE6kn/wMDrQTuXn52vgwIF2j9FMSEhIi5nS0tLUtWtXbdu2TUePHpX09UPbPj4+mjBhQrN14+Pj1b9/f23evFmHDx8+474mTJig1atXt1iekZGh+vp67dy585S3u+KKK87lkE7rbI/1fOc8Fbu2de2112rDhg268847tXHjRu9D57t379bo0aPPep9WGzRokDwej7766iu7RwE6FL/vXgXApcjhcLR4bp3dIiMjT7k8NjZWhYWFKi4uVqdOneR2uyVJERERp91Wfn7+Gd/I3e1269lnn9U777yjw4cPq6ysrNn1VVVVp7xdSEjIdx3GWTmbY+3Spct5z3kqdm1r/vz5GjZsmF5//XWNGTNG0tdvsj5nzhzdeOONZ71PqxljJH393waAtsOZTaCdSklJ0bZt2+weo5njx497/4f/TcXFxZK+DrGAgABFRkbKz89P9fX1Msac8pKdnX3GfU2cOFGPPfaYZs+erT179qixsVHGGD333HOSdMo5WtPZHOv5zHmmULJrWw6HQzNnztSKFStUVlampUuXyhijyZMna968eafdR1vbsmWL/Pz81LNnT7tHAToUYhNopyZNmqT33ntPLpfL7lG8ampqlJub22zZ9u3bVVhYqIyMDHXp0kWSNHnyZHk8nlO+Sv3JJ59UUlKSPB7PaffT0NCg9evXKz4+Xvfee69iYmK8YVVdXd2KR3R6Z3Os5zNncHCw6urqvD/37dtXCxYssHVbkZGR+vLLLyVJTqdT48aN877K//333z/bu8xyr732mrKysk571hmANYhNoJ267bbbFBoaql/+8pd2j+IVERGhX/3qV8rJyVFlZaU2bdqkGTNmyN/fX88//7x3vccff1zJycn60Y9+pA8//FBut1snTpzQn//8Zz366KN65plnmr1Nz7f5+vpq9OjRKioq0tNPP62SkhJVV1dr9erV+tOf/tQWh3pWx3o+c15++eXas2ePCgoKlJOTo6+++kqjRo2yfVt33XWX8vLyVFtbq+LiYj311FMyxujqq69unTv0Ar3//vv68MMPL6r/HoAOo41fkQSgDb399tvG4XCYV1991e5RvK8Y37Vrl7nmmmtMWFiYCQoKMllZWWbdunUt1j9+/Lj5+c9/bnr16mWcTqeJiYkx48ePNx9//LF3naefftpIanZ56KGHjDHGuFwuM2fOHJOYmGicTqeJi4szt99+u5k7d6533czMTJOTk9NiGxf6T+O5HOvZztnkyy+/NKNGjTIhISEmMTHRzJ8/3/Ztbd261cyZM8f069fPBAcHm06dOpmhQ4eav/zlL6axsfGC7svWkJ+fb2JiYszMmTPtHgXoiP7hMMbiJy4BsNVDDz2kp556Sm+88YamTZtm2xwDBw5USUnJd76KvD3oSMd6sdu7d6/Gjh2r2NhYrVq1SqGhoXaPBHQ0i3k1OtDO/f73v1dtba1uvfVW7dmzR7/+9a/5fHR0CCtXrtQtt9yinj176n//938JTcAmPGcT6ACeeeYZ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9OhRLVq0SK+//rq2bt2q3r1767bbbtOsWbOUlJRk93gAiE2g4ygvL9dLL72kp59+WidPntT48eM1a9Ysff/73+cV42gXdu7cqb/+9a9auHChXC6XrrvuOj388MMaPHiw3aMBHRmxCbR3R44c0bx587RgwQIFBAToZz/7me65555W+axu4GJUX1+vJUuW6IknnlBeXp6uu+46zZ07VyNHjrR7NKAjWsxL+YB2qqamRg8//LCSk5O1aNEiPfroozpw4IAefvhhQhPtmtPp1C233KItW7bovffek9vt1qhRozRhwgTt37/f7vGADofYBNqhFStWKD09Xc8995wef/xxffXVV3rggQcUGhpq92hAm3E4HLruuuv06aefatWqVdq/f78GDBigJ554QvX19XaPB3QYxCbQjlRXV+tHP/qRxo0bpwEDBmjXrl164IEHeLN1dHjZ2dnaunWrHnroIT366KPKzMzU7t277R4L6BCITaCdKC4u1qhRo7R06VItXbpUb7/9dod8b8zQ0NAO99y81jzm9nz/OZ1O/epXv9KOHTsUHBysK6+8UitWrLB7LKDdIzaBdsDlcik7O1vl5eXKzc3VpEmT7B4JuGj16tVLa9eu1YQJEzRx4kR99NFHdo8EtGt+dg8A4MJ4PB7dfPPNqq6u1qeffqpu3brZPRJw0QsICNAbb7whh8OhqVOnKjc3VykpKXaPBbRLnNkELnEvvfSScnJy9M4771w0oXn8+HH9/Oc/V3JysgICApSQkKCxY8dq4cKFqq6uPu26/v7+ioqK0ve+9z2tXr3au87SpUvlcDi8l927d2vq1Knq3Lmzd9ncuXPlcDhUWVmp9evXe5f7+f3f79Qej0eLFi3SuHHjFB8fr6CgIKWlpen5559XY2PjOe2vpKTkrO6LZ555xnubhIQE5ebmasyYMQoLC1NwcLCys7O1fv36Zrc52zmbtt0ax9ya25Kk2tpa/eY3v9Fll12m4OBgderUSRMnTtSyZcvU0NBwVved1Xx8fPTyyy+rd+/emj17tt3jAO2XAXDJqq+vN/Hx8ebBBx+0exSvo0ePmp49e5r4+HizfPlyU15eboqKisxjjz1mJJnnnnuuxbpxcXFm+fLlxu12m927d5vJkycbh8Nh/vKXvzTb9qRJk4wkk5WVZVavXm0qKyvNxo0bja+vr3G5XMYYY0JCQsyI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TWpqKmlpaUydOtXUpfS5RYsWkZaWRlRUlKlLET3AzMyMCRMm8M9//pO1a9fS2NhIcnIy9913HzU1NaYur8+dOXOGCRMmsGjRIsaNG8f333/P008/PahGMaV/XXv/Gso/u/4iMDCQP//5z2zevJnExETuuusuUlJSyMzMNGldEjb7gF6vZ8WKFYwfPx47Ozs2btzIk08+iYeHh6lLE0NQUlISCxcu7HfP1d/Fx8fz0Ucf8eqrr/Ltt98SExPDjh07TF1Wn3nvvfcYM2YMjY2NfPbZZ/zlL3/By8vL1GUJITrh7e3Nc889x2effUZtbS1xcXF88MEHJqtHwmYva2lpYf78+Tz//PM88cQTrF69ekAurSKEOO/GG29k48aNxMTEMGPGDJM28L5gMBhYtmwZS5Ys4Z577uHjjz826QLTQojuGz58OJ988gl33XUXDz74IP/zP/9jkt3qcrrKXtTe3s6CBQvYtWsXH3zwAWPGjDF1SUKIHuDs7Mxrr73GO++8w4MPPoiFhQWLFi0ydVm94rHHHuPdd9/llVde6XDaPSHEwGBhYcHSpUuJiIjgqaeewsLCgpdffrlva+jT7zbE/O///i9bt25l9erVjB492tTldEmj0fDee++xfft21Go1jo6OjBkzht///veXjGDU1NSwevVqtm7dSnl5Oa6uroSGhjJr1ixmzpzZ6ZmMqqqqeP3119mzZw/m5ubExsayfPnyDnNVdTodP//8M1988QVZWVk0NDQQGBjIvHnz+O1vf6usMbp161aWLVumfN0333zDW2+9xYEDB6itrQVg586duLq6duu1t7W18f777/Pjjz9SWlqKtbU18fHxzJs3j8mTJyvft7v1Xa81a9bw2muvAeDl5cXKlSt58803SUtLQ6fTMXr0aB555BHi4+Ov+md34XMfO3aMUaNGAefnJZ44ccJkz3U170N/olKpePjhh9Hr9SxevJgxY8b067/za/Hll1/yxhtv8NJLL/XboCn9q//0r4td6We3atUq3n77beD8NJW1a9cCsHv3bv7whz8A4OLiwq5duzo875Xe8/r6eiZMmNDhax5++GEWL16MTqcjLi5OuX/GjBm8/vrrQMffj7KyMmxtbYmNjeXee+8lKSlJ+ZqB2K8AbrrpJgwGA8uXL2fixInMnj27z753//yJDALFxcU8//zzLF26tF//A6qo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PCQkpMGYy+XSU089pQEDBig4ONh9zeDy5cslSRUVFY1uy8/Pr3nD32Cea3niiSdUUVGh3/3ud5KknJwc7d+/XwsWLLjurJWVlXK5XKqrq1NgYGCD60MPHz4s6fKbkRth1WtiBfP/t7D28PCwOQlgP8omgGYTHh6uzMxMu2PI6XTK399fly5dUllZWYPlxcXFDcamTp2qn//851q4cKFycnJUV1cnY4x+9atfSfqqPLQUq/J897vfVVhYmNavX6/Kykq98MILWrhwofz9/RvMdTgcqqqqajD+9ftIOp1OBQUFycvLS9XV1TLGNPq47777rpnvauXsZvsZXU1GRoZ8fX11++232x0FsB1lE0Czuf/++5WSkqLc3Fy7o2jSpEmSvjqd/qVz584pOzu73lhtba1SU1PVtWtXLVmyRJ07d3aXHjvul2hlHi8vLy1dulSFhYV64YUX9MYbb2jJkiWNzg0NDW1wGrigoKDRn+/06dNVU1Oj1NTUBsvWrFmj7t27q6am5pr5fH196xXcvn37auPGjTfdz+haNm/erLi4OPn4+NgdBbAdZRNAs5kxY4buuOMO92lNO61evVq33Xabli1bpuTkZJWVlSkrK0uJiYkNTq17enpq9OjRKigo0Nq1a3Xu3DldvHhR+/bt04YNG1o8u9V5HnvsMQUGBmrVqlWaNm2aunXr1ui8CRMmKD8/X+vXr1dZWZk+/fRTLV26tNHLEJ5//nndeeed+t73vqd3331XLpdLxcXFeuWVV/Tcc89p3bp13+ia0MGDBysnJ0d5eXk6cOCAPvvsM40cOfKm+xldzfbt23XgwAGtWLHC7ijAzcGWzyUBaLPef/9943A4zPr16+2OYrKzs820adNMQECAad++vRkyZIjZtWuXGTt2rJFkJJn58+cbY4wpKioyixYtMmFhYcbb29t06dLFPProo2bFihXuuVFRUebAgQPuv//v43qsXbu2wXpWrlzZpDzXa/ny5UaSycjIuOKckpISs2DBAhMaGmrat29vYmJizIcffmiioqLcGX7yk5+453/xxRfmRz/6kendu7fx9vY2nTt3NhMmTDDJycnfaJ+NMeaTTz4xI0eONH5+fiYsLMz89re/dS+z+jVpDllZWSYoKKjBJ/6BW9ifPYy5iS5yAdAm/PKXv9RTTz2lTZs2ae7cuXbHAVrEJ598onHjxqln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"></span></p>
<p>Como veis, las posibilidades son casi infinitas... y más si le echais un ojo a la cantidad de <a href="http://www.graphviz.org/content/attrs">atributos que podeis utilizar para configurar vuestras gráficas</a>.</p>
<p>Veámos otro ejemplo, ésta vez en lugar de un <em>flujo</em> representaremos una <em>jerarquía</em>. Supongamos que tenemos que hacer un esquema que represente cómo será la jerarquía del <a href="http://es.wikipedia.org/wiki/Nuevo_orden_mundial">Nuevo Orden Mundial</a> el dia que finalmente yo gobierne vuestro mundo.
Obviamente yo estaría enlo alto de dicho organigrama, y por debajo irían <em>colgando</em> las demás personas que servirían bajo mis órdenes, algunos de los cuales tendrían a su vez otras personas a sus órdenes.</p>
<p>Ésto podría representarse <em>de forma muy básica</em> mediante éste <em>pseudo-código</em>:</p>
<div class="highlight"><pre><span></span><code><span class="err"> Yo, lider mundial</span>
<span class="err"> |</span>
<span class="err"> / \</span>
<span class="err"> / \</span>
<span class="err"> / \</span>
<span class="err">Kim Jong-un Chuck Norris</span>
<span class="err"> |</span>
<span class="err"> / \</span>
<span class="err"> / \</span>
<span class="err"> B. Obama El papa</span>
<span class="err"> | |</span>
<span class="err"> | |</span>
<span class="err"> M. Rajoy |</span>
<span class="err"> / \</span>
<span class="err"> / \</span>
<span class="err"> Larry Page Mark Zuckerberg</span>
</code></pre></div>
<p>Si trasladamos éste esquema al lenguaje <code>dot</code> de Graphviz, tendremos algo parecido a ésto:</p>
<figure class='code'>
<figcaption><span class="liquid-tags-code-filename">nuevo_orden_mundial.dot</span><a href='/graphviz/nuevo_orden_mundial.dot'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="n">graph</span> <span class="n">nuevo_orden_mundial</span> <span class="p">{</span>
<span class="o">//</span> <span class="n">Configuracion</span> <span class="k">global</span> <span class="n">de</span> <span class="n">la</span> <span class="n">grafica</span>
<span class="n">fontname</span> <span class="o">=</span> <span class="s2">"Verdana"</span><span class="p">;</span>
<span class="n">splines</span> <span class="o">=</span> <span class="n">ortho</span><span class="p">;</span>
<span class="n">fontsize</span> <span class="o">=</span> <span class="mi">20</span><span class="p">;</span>
<span class="n">style</span> <span class="o">=</span> <span class="n">dashed</span><span class="p">;</span>
<span class="n">shape</span> <span class="o">=</span> <span class="n">box</span><span class="p">;</span>
<span class="n">rankdir</span> <span class="o">=</span> <span class="n">R</span><span class="p">;</span>
<span class="n">ranksep</span> <span class="o">=</span> <span class="mf">0.5</span><span class="p">;</span>
<span class="o">//</span> <span class="n">Configuracion</span> <span class="n">de</span> <span class="n">los</span> <span class="n">elementos</span> <span class="n">de</span> <span class="n">la</span> <span class="n">grafica</span>
<span class="n">node</span> <span class="p">[</span>
<span class="n">fontname</span> <span class="o">=</span> <span class="s2">"Verdana"</span><span class="p">,</span>
<span class="n">style</span> <span class="o">=</span> <span class="n">filled</span><span class="p">,</span>
<span class="n">color</span> <span class="o">=</span> <span class="s2">"#FFFFFF"</span><span class="p">,</span>
<span class="n">fontcolor</span> <span class="o">=</span> <span class="s2">"#000000"</span><span class="p">,</span>
<span class="n">labelloc</span> <span class="o">=</span> <span class="n">b</span><span class="p">,</span>
<span class="n">shape</span> <span class="o">=</span> <span class="n">square</span><span class="p">,</span>
<span class="n">margin</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>
<span class="n">color</span> <span class="o">=</span> <span class="n">black</span><span class="p">,</span>
<span class="n">style</span> <span class="o">=</span> <span class="n">bold</span><span class="p">,</span>
<span class="n">fontsize</span> <span class="o">=</span> <span class="mi">8</span><span class="p">,</span>
<span class="n">fixedsize</span> <span class="o">=</span> <span class="n">true</span><span class="p">,</span>
<span class="n">width</span> <span class="o">=</span> <span class="mf">1.5</span>
<span class="p">];</span>
<span class="o">//</span> <span class="n">Elementos</span> <span class="n">de</span> <span class="n">la</span> <span class="n">grafica</span>
<span class="n">lider</span> <span class="p">[</span> <span class="n">label</span> <span class="o">=</span> <span class="s2">"Yo, lider mundial"</span><span class="p">,</span> <span class="n">image</span> <span class="o">=</span> <span class="s2">"cylon.png"</span> <span class="p">];</span>
<span class="n">kim</span> <span class="p">[</span> <span class="n">label</span> <span class="o">=</span> <span class="s2">"Kim Jong-un"</span><span class="p">,</span> <span class="n">image</span> <span class="o">=</span> <span class="s2">"kimjongun.jpeg"</span> <span class="p">];</span>
<span class="n">chuck</span> <span class="p">[</span> <span class="n">label</span> <span class="o">=</span> <span class="s2">"Chuck Norris"</span><span class="p">,</span> <span class="n">image</span> <span class="o">=</span> <span class="s2">"chucknorris.jpeg"</span> <span class="p">];</span>
<span class="n">obama</span> <span class="p">[</span> <span class="n">label</span> <span class="o">=</span> <span class="s2">"B. Obama"</span><span class="p">,</span> <span class="n">image</span> <span class="o">=</span> <span class="s2">"obama.jpeg"</span> <span class="p">];</span>
<span class="n">emperador</span> <span class="p">[</span> <span class="n">label</span> <span class="o">=</span> <span class="s2">"Emperador"</span><span class="p">,</span> <span class="n">image</span> <span class="o">=</span> <span class="s2">"emperador.jpeg"</span> <span class="p">];</span>
<span class="n">rajoy</span> <span class="p">[</span> <span class="n">label</span> <span class="o">=</span> <span class="s2">"M. Rajoy"</span><span class="p">,</span> <span class="n">image</span> <span class="o">=</span> <span class="s2">"rajoy.jpeg"</span> <span class="p">];</span>
<span class="n">larry</span> <span class="p">[</span> <span class="n">label</span> <span class="o">=</span> <span class="s2">"Larry Page"</span><span class="p">,</span> <span class="n">image</span> <span class="o">=</span> <span class="s2">"larry.jpeg"</span> <span class="p">];</span>
<span class="n">mark</span> <span class="p">[</span> <span class="n">label</span> <span class="o">=</span> <span class="s2">"Mark Zuckerberg"</span><span class="p">,</span> <span class="n">image</span> <span class="o">=</span> <span class="s2">"mark.jpeg"</span> <span class="p">];</span>
<span class="o">//</span> <span class="n">Relaciones</span> <span class="n">entre</span> <span class="n">los</span> <span class="n">elementos</span>
<span class="n">lider</span> <span class="o">--</span> <span class="n">kim</span>
<span class="n">lider</span> <span class="o">--</span> <span class="n">chuck</span>
<span class="n">chuck</span> <span class="o">--</span> <span class="n">obama</span>
<span class="n">chuck</span> <span class="o">--</span> <span class="n">emperador</span>
<span class="n">obama</span> <span class="o">--</span> <span class="n">rajoy</span>
<span class="n">emperador</span> <span class="o">--</span> <span class="n">larry</span>
<span class="n">emperador</span> <span class="o">--</span> <span class="n">mark</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<p>Si os parais a leer el código detenidamente, enseguida vereis que es sencillísimo y prácticamente autoexplicativo.</p>
<p>Simplemente se define una gráfica (en nuestro caso de tipo <code>graph</code> y con el nombre <code>nuevo_orden</code>), y luego se definen sus partes:</p>
<ul>
<li>Configuración general de la gráfica: tipos de letra, tamaños, tipos de <em>uniones</em> entre los elementos que la componen, etc.</li>
<li>Después podemos definir la configuración de los elementos (<em>nodos</em>) de la gráfica: colores, tipos de letra, forma geométrica del borde que lo rodeará, etc.</li>
<li>Luego se definen los <em>nodos</em>, es decir, las partes que se relacionarán en nuestra gráfica: nombre, imagen, y cualquier otra cosa que queramos.</li>
<li>Y por último se indica la relación que cada nodo tiene con los demás: Es decir, de quién es <em>hijo</em> cada uno de ellos.</li>
</ul>
<p>Solo tenemos que darle éste archivo que acabamos de crear a Graphviz para que nos genere la imagen de dicha gráfica. Por lo tanto, de nuevo ejecutamos el comando <code>dot</code> como las anteriores veces:</p>
<div class="highlight"><pre><span></span><code>$ dot -Tpng nuevo-orden-mundial.dot -o nuevo-orden-mundial.png
</code></pre></div>
<p>Y listo... una vez ejecutado ese comando tendremos en el directorio actual un archivo llamado <code>nuevo-orden-mundial.png</code>, que contendrá la imagen con nuestra gráfica. En éste último caso, la gráfica que representaría ésta <em>no-tan-lejana</em> situación con mis súbditos lacayos sería ésta:</p>
<p><img class="center" src="/images/posts/graphviz/graph.png"></p>
<p>Y si estais pensando en integrar éste tipo de gráficas en vuestros blogs creados con <a href="http://octopress.org/">Octopress</a>, hay varios plugins que os pueden ayudar a hacerlo y de los cuales ya hablé <a href="/2014/07/12/seleccion-de-plugins-para-octopress/">en éste otro post</a>.</p>
<p>Éstos han sido solo unos ejemplos muy básicos de las cosas que se pueden hacer... si probais las diferentes opciones veréis que se pueden crear gráficas increibles. Y para muestra, os pongo el código y la gráfica resultante de algunos de los ejemplos de la propia web de Graphviz, algunos de los cuales son absolutamente impresionantes (únicamente os muestro las gráficas ya generadas, no el código, para no aburriros... pero si quereis verlo, recordar que son imágenes SVG, por lo que únicamente teneis que darle a <code>Ver código fuente</code> de la imagen en cuestión desde vuestro navegador, y listo!):</p>
<h3>Ejemplo para relaciones entre tablas de una base de datos</h3>
<figure class='code'>
<figcaption><span class="liquid-tags-code-filename">demo_graphviz_1.dot</span><a href='/graphviz/demo_graphviz_1.dot'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="n">digraph</span> <span class="n">g</span> <span class="p">{</span>
<span class="n">graph</span> <span class="p">[</span>
<span class="n">rankdir</span> <span class="o">=</span> <span class="s2">"LR"</span>
<span class="p">];</span>
<span class="n">node</span> <span class="p">[</span>
<span class="n">fontsize</span> <span class="o">=</span> <span class="s2">"16"</span>
<span class="n">shape</span> <span class="o">=</span> <span class="s2">"ellipse"</span>
<span class="p">];</span>
<span class="n">edge</span> <span class="p">[</span>
<span class="p">];</span>
<span class="s2">"node0"</span> <span class="p">[</span>
<span class="n">label</span> <span class="o">=</span> <span class="s2">"<f0> 0x10ba8| <f1>"</span>
<span class="n">shape</span> <span class="o">=</span> <span class="s2">"record"</span>
<span class="p">];</span>
<span class="s2">"node1"</span> <span class="p">[</span>
<span class="n">label</span> <span class="o">=</span> <span class="s2">"<f0> 0xf7fc4380| <f1> | <f2> |-1"</span>
<span class="n">shape</span> <span class="o">=</span> <span class="s2">"record"</span>
<span class="p">];</span>
<span class="s2">"node2"</span> <span class="p">[</span>
<span class="n">label</span> <span class="o">=</span> <span class="s2">"<f0> 0xf7fc44b8| | |2"</span>
<span class="n">shape</span> <span class="o">=</span> <span class="s2">"record"</span>
<span class="p">];</span>
<span class="s2">"node3"</span> <span class="p">[</span>
<span class="n">label</span> <span class="o">=</span> <span class="s2">"<f0> 3.43322790286038071e-06|44.79998779296875|0"</span>
<span class="n">shape</span> <span class="o">=</span> <span class="s2">"record"</span>
<span class="p">];</span>
<span class="s2">"node4"</span> <span class="p">[</span>
<span class="n">label</span> <span class="o">=</span> <span class="s2">"<f0> 0xf7fc4380| <f1> | <f2> |2"</span>
<span class="n">shape</span> <span class="o">=</span> <span class="s2">"record"</span>
<span class="p">];</span>
<span class="s2">"node5"</span> <span class="p">[</span>
<span class="n">label</span> <span class="o">=</span> <span class="s2">"<f0> (nil)| | |-1"</span>
<span class="n">shape</span> <span class="o">=</span> <span class="s2">"record"</span>
<span class="p">];</span>
<span class="s2">"node6"</span> <span class="p">[</span>
<span class="n">label</span> <span class="o">=</span> <span class="s2">"<f0> 0xf7fc4380| <f1> | <f2> |1"</span>
<span class="n">shape</span> <span class="o">=</span> <span class="s2">"record"</span>
<span class="p">];</span>
<span class="s2">"node7"</span> <span class="p">[</span>
<span class="n">label</span> <span class="o">=</span> <span class="s2">"<f0> 0xf7fc4380| <f1> | <f2> |2"</span>
<span class="n">shape</span> <span class="o">=</span> <span class="s2">"record"</span>
<span class="p">];</span>
<span class="s2">"node8"</span> <span class="p">[</span>
<span class="n">label</span> <span class="o">=</span> <span class="s2">"<f0> (nil)| | |-1"</span>
<span class="n">shape</span> <span class="o">=</span> <span class="s2">"record"</span>
<span class="p">];</span>
<span class="s2">"node9"</span> <span class="p">[</span>
<span class="n">label</span> <span class="o">=</span> <span class="s2">"<f0> (nil)| | |-1"</span>
<span class="n">shape</span> <span class="o">=</span> <span class="s2">"record"</span>
<span class="p">];</span>
<span class="s2">"node10"</span> <span class="p">[</span>
<span class="n">label</span> <span class="o">=</span> <span class="s2">"<f0> (nil)| <f1> | <f2> |-1"</span>
<span class="n">shape</span> <span class="o">=</span> <span class="s2">"record"</span>
<span class="p">];</span>
<span class="s2">"node11"</span> <span class="p">[</span>
<span class="n">label</span> <span class="o">=</span> <span class="s2">"<f0> (nil)| <f1> | <f2> |-1"</span>
<span class="n">shape</span> <span class="o">=</span> <span class="s2">"record"</span>
<span class="p">];</span>
<span class="s2">"node12"</span> <span class="p">[</span>
<span class="n">label</span> <span class="o">=</span> <span class="s2">"<f0> 0xf7fc43e0| | |1"</span>
<span class="n">shape</span> <span class="o">=</span> <span class="s2">"record"</span>
<span class="p">];</span>
<span class="s2">"node0"</span><span class="p">:</span><span class="n">f0</span> <span class="o">-></span> <span class="s2">"node1"</span><span class="p">:</span><span class="n">f0</span> <span class="p">[</span>
<span class="nb">id</span> <span class="o">=</span> <span class="mi">0</span>
<span class="p">];</span>
<span class="s2">"node0"</span><span class="p">:</span><span class="n">f1</span> <span class="o">-></span> <span class="s2">"node2"</span><span class="p">:</span><span class="n">f0</span> <span class="p">[</span>
<span class="nb">id</span> <span class="o">=</span> <span class="mi">1</span>
<span class="p">];</span>
<span class="s2">"node1"</span><span class="p">:</span><span class="n">f0</span> <span class="o">-></span> <span class="s2">"node3"</span><span class="p">:</span><span class="n">f0</span> <span class="p">[</span>
<span class="nb">id</span> <span class="o">=</span> <span class="mi">2</span>
<span class="p">];</span>
<span class="s2">"node1"</span><span class="p">:</span><span class="n">f1</span> <span class="o">-></span> <span class="s2">"node4"</span><span class="p">:</span><span class="n">f0</span> <span class="p">[</span>
<span class="nb">id</span> <span class="o">=</span> <span class="mi">3</span>
<span class="p">];</span>
<span class="s2">"node1"</span><span class="p">:</span><span class="n">f2</span> <span class="o">-></span> <span class="s2">"node5"</span><span class="p">:</span><span class="n">f0</span> <span class="p">[</span>
<span class="nb">id</span> <span class="o">=</span> <span class="mi">4</span>
<span class="p">];</span>
<span class="s2">"node4"</span><span class="p">:</span><span class="n">f0</span> <span class="o">-></span> <span class="s2">"node3"</span><span class="p">:</span><span class="n">f0</span> <span class="p">[</span>
<span class="nb">id</span> <span class="o">=</span> <span class="mi">5</span>
<span class="p">];</span>
<span class="s2">"node4"</span><span class="p">:</span><span class="n">f1</span> <span class="o">-></span> <span class="s2">"node6"</span><span class="p">:</span><span class="n">f0</span> <span class="p">[</span>
<span class="nb">id</span> <span class="o">=</span> <span class="mi">6</span>
<span class="p">];</span>
<span class="s2">"node4"</span><span class="p">:</span><span class="n">f2</span> <span class="o">-></span> <span class="s2">"node10"</span><span class="p">:</span><span class="n">f0</span> <span class="p">[</span>
<span class="nb">id</span> <span class="o">=</span> <span class="mi">7</span>
<span class="p">];</span>
<span class="s2">"node6"</span><span class="p">:</span><span class="n">f0</span> <span class="o">-></span> <span class="s2">"node3"</span><span class="p">:</span><span class="n">f0</span> <span class="p">[</span>
<span class="nb">id</span> <span class="o">=</span> <span class="mi">8</span>
<span class="p">];</span>
<span class="s2">"node6"</span><span class="p">:</span><span class="n">f1</span> <span class="o">-></span> <span class="s2">"node7"</span><span class="p">:</span><span class="n">f0</span> <span class="p">[</span>
<span class="nb">id</span> <span class="o">=</span> <span class="mi">9</span>
<span class="p">];</span>
<span class="s2">"node6"</span><span class="p">:</span><span class="n">f2</span> <span class="o">-></span> <span class="s2">"node9"</span><span class="p">:</span><span class="n">f0</span> <span class="p">[</span>
<span class="nb">id</span> <span class="o">=</span> <span class="mi">10</span>
<span class="p">];</span>
<span class="s2">"node7"</span><span class="p">:</span><span class="n">f0</span> <span class="o">-></span> <span class="s2">"node3"</span><span class="p">:</span><span class="n">f0</span> <span class="p">[</span>
<span class="nb">id</span> <span class="o">=</span> <span class="mi">11</span>
<span class="p">];</span>
<span class="s2">"node7"</span><span class="p">:</span><span class="n">f1</span> <span class="o">-></span> <span class="s2">"node1"</span><span class="p">:</span><span class="n">f0</span> <span class="p">[</span>
<span class="nb">id</span> <span class="o">=</span> <span class="mi">12</span>
<span class="p">];</span>
<span class="s2">"node7"</span><span class="p">:</span><span class="n">f2</span> <span class="o">-></span> <span class="s2">"node8"</span><span class="p">:</span><span class="n">f0</span> <span class="p">[</span>
<span class="nb">id</span> <span class="o">=</span> <span class="mi">13</span>
<span class="p">];</span>
<span class="s2">"node10"</span><span class="p">:</span><span class="n">f1</span> <span class="o">-></span> <span class="s2">"node11"</span><span class="p">:</span><span class="n">f0</span> <span class="p">[</span>
<span class="nb">id</span> <span class="o">=</span> <span class="mi">14</span>
<span class="p">];</span>
<span class="s2">"node10"</span><span class="p">:</span><span class="n">f2</span> <span class="o">-></span> <span class="s2">"node12"</span><span class="p">:</span><span class="n">f0</span> <span class="p">[</span>
<span class="nb">id</span> <span class="o">=</span> <span class="mi">15</span>
<span class="p">];</span>
<span class="s2">"node11"</span><span class="p">:</span><span class="n">f2</span> <span class="o">-></span> <span class="s2">"node1"</span><span class="p">:</span><span class="n">f0</span> <span class="p">[</span>
<span class="nb">id</span> <span class="o">=</span> <span class="mi">16</span>
<span class="p">];</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<h3>Ejemplo con diferentes formas y colores</h3>
<figure class='code'>
<figcaption><span class="liquid-tags-code-filename">demo_graphviz_2.dot</span><a href='/graphviz/demo_graphviz_2.dot'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="n">digraph</span> <span class="s2">"unix"</span> <span class="p">{</span>
<span class="n">graph</span> <span class="p">[</span> <span class="n">fontname</span> <span class="o">=</span> <span class="s2">"Helvetica-Oblique"</span><span class="p">,</span>
<span class="n">fontsize</span> <span class="o">=</span> <span class="mi">36</span><span class="p">,</span>
<span class="n">label</span> <span class="o">=</span> <span class="s2">"</span><span class="se">\n\n\n\n</span><span class="s2">Object Oriented Graphs</span><span class="se">\n</span><span class="s2">Stephen North, 3/19/93"</span><span class="p">,</span>
<span class="n">size</span> <span class="o">=</span> <span class="s2">"6,6"</span> <span class="p">];</span>
<span class="n">node</span> <span class="p">[</span> <span class="n">shape</span> <span class="o">=</span> <span class="n">polygon</span><span class="p">,</span>
<span class="n">sides</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span>
<span class="n">distortion</span> <span class="o">=</span> <span class="s2">"0.0"</span><span class="p">,</span>
<span class="n">orientation</span> <span class="o">=</span> <span class="s2">"0.0"</span><span class="p">,</span>
<span class="n">skew</span> <span class="o">=</span> <span class="s2">"0.0"</span><span class="p">,</span>
<span class="n">color</span> <span class="o">=</span> <span class="n">white</span><span class="p">,</span>
<span class="n">style</span> <span class="o">=</span> <span class="n">filled</span><span class="p">,</span>
<span class="n">fontname</span> <span class="o">=</span> <span class="s2">"Helvetica-Outline"</span> <span class="p">];</span>
<span class="s2">"5th Edition"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">9</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"0.936354"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">28</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.126818"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">salmon2</span><span class="p">];</span>
<span class="s2">"6th Edition"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"0.238792"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">11</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.995935"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">deepskyblue</span><span class="p">];</span>
<span class="s2">"PWB 1.0"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"0.019636"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">79</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.440424"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">goldenrod2</span><span class="p">];</span>
<span class="n">LSX</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">9</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"-0.698271"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">22</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.195492"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">burlywood2</span><span class="p">];</span>
<span class="s2">"1 BSD"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"0.265084"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">26</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.403659"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">gold1</span><span class="p">];</span>
<span class="s2">"Mini Unix"</span> <span class="p">[</span><span class="n">distortion</span><span class="o">=</span><span class="s2">"0.039386"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.461120"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">greenyellow</span><span class="p">];</span>
<span class="n">Wollongong</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"0.228564"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">63</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.062846"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">darkseagreen</span><span class="p">];</span>
<span class="n">Interdata</span> <span class="p">[</span><span class="n">distortion</span><span class="o">=</span><span class="s2">"0.624013"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">56</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.101396"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">dodgerblue1</span><span class="p">];</span>
<span class="s2">"Unix/TS 3.0"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"0.731383"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">43</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.824612"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">thistle2</span><span class="p">];</span>
<span class="s2">"PWB 2.0"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">6</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"0.592100"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">34</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.719269"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">darkolivegreen3</span><span class="p">];</span>
<span class="s2">"7th Edition"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"0.298417"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">65</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.310367"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">chocolate</span><span class="p">];</span>
<span class="s2">"8th Edition"</span> <span class="p">[</span><span class="n">distortion</span><span class="o">=</span><span class="s2">"-0.997093"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">50</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.061117"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">turquoise3</span><span class="p">];</span>
<span class="s2">"32V"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"0.878516"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">19</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.592905"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">steelblue3</span><span class="p">];</span>
<span class="n">V7M</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"-0.960249"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">32</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.460424"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">navy</span><span class="p">];</span>
<span class="s2">"Ultrix-11"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"-0.633186"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.333125"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">darkseagreen4</span><span class="p">];</span>
<span class="n">Xenix</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"-0.337997"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">52</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.760726"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">coral</span><span class="p">];</span>
<span class="s2">"UniPlus+"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"0.788483"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">39</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.526284"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">darkolivegreen3</span><span class="p">];</span>
<span class="s2">"9th Edition"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"0.138690"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">55</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.554049"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">coral3</span><span class="p">];</span>
<span class="s2">"2 BSD"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"-0.010661"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">84</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.179249"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">blanchedalmond</span><span class="p">];</span>
<span class="s2">"2.8 BSD"</span> <span class="p">[</span><span class="n">distortion</span><span class="o">=</span><span class="s2">"-0.239422"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">44</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.053841"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">lightskyblue1</span><span class="p">];</span>
<span class="s2">"2.9 BSD"</span> <span class="p">[</span><span class="n">distortion</span><span class="o">=</span><span class="s2">"-0.843381"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">70</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.601395"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">aquamarine2</span><span class="p">];</span>
<span class="s2">"3 BSD"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"0.251820"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">18</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.530618"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">lemonchiffon</span><span class="p">];</span>
<span class="s2">"4 BSD"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"-0.772300"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">24</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.028475"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">darkorange1</span><span class="p">];</span>
<span class="s2">"4.1 BSD"</span> <span class="p">[</span><span class="n">distortion</span><span class="o">=</span><span class="s2">"-0.226170"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">38</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.504053"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">lightyellow1</span><span class="p">];</span>
<span class="s2">"4.2 BSD"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"-0.807349"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">50</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.908842"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">darkorchid4</span><span class="p">];</span>
<span class="s2">"4.3 BSD"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"-0.030619"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">76</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.985021"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">lemonchiffon2</span><span class="p">];</span>
<span class="s2">"Ultrix-32"</span> <span class="p">[</span><span class="n">distortion</span><span class="o">=</span><span class="s2">"-0.644209"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">21</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.307836"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">goldenrod3</span><span class="p">];</span>
<span class="s2">"PWB 1.2"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"0.640971"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">84</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.768455"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">cyan</span><span class="p">];</span>
<span class="s2">"USG 1.0"</span> <span class="p">[</span><span class="n">distortion</span><span class="o">=</span><span class="s2">"0.758942"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">42</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.039886"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">blue</span><span class="p">];</span>
<span class="s2">"CB Unix 1"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">9</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"-0.348692"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">42</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.767058"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">firebrick</span><span class="p">];</span>
<span class="s2">"USG 2.0"</span> <span class="p">[</span><span class="n">distortion</span><span class="o">=</span><span class="s2">"0.748625"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">74</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.647656"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">chartreuse4</span><span class="p">];</span>
<span class="s2">"CB Unix 2"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"0.851818"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">32</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.020120"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">greenyellow</span><span class="p">];</span>
<span class="s2">"CB Unix 3"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"0.992237"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">29</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.256102"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">bisque4</span><span class="p">];</span>
<span class="s2">"Unix/TS++"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">6</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"0.545461"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">16</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.313589"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">mistyrose2</span><span class="p">];</span>
<span class="s2">"PDP-11 Sys V"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">9</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"-0.267769"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">40</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.271226"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">cadetblue1</span><span class="p">];</span>
<span class="s2">"USG 3.0"</span> <span class="p">[</span><span class="n">distortion</span><span class="o">=</span><span class="s2">"-0.848455"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">44</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.267152"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">bisque2</span><span class="p">];</span>
<span class="s2">"Unix/TS 1.0"</span> <span class="p">[</span><span class="n">distortion</span><span class="o">=</span><span class="s2">"0.305594"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">75</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"0.070516"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">orangered</span><span class="p">];</span>
<span class="s2">"TS 4.0"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"-0.641701"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">50</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.952502"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">crimson</span><span class="p">];</span>
<span class="s2">"System V.0"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">9</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"0.021556"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">26</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.729938"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">darkorange1</span><span class="p">];</span>
<span class="s2">"System V.2"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">6</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"0.985153"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">33</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.399752"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">darkolivegreen4</span><span class="p">];</span>
<span class="s2">"System V.3"</span> <span class="p">[</span><span class="n">sides</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span> <span class="n">distortion</span><span class="o">=</span><span class="s2">"-0.687574"</span><span class="p">,</span> <span class="n">orientation</span><span class="o">=</span><span class="mi">58</span><span class="p">,</span> <span class="n">skew</span><span class="o">=</span><span class="s2">"-0.180116"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">lightsteelblue1</span><span class="p">];</span>
<span class="s2">"5th Edition"</span> <span class="o">-></span> <span class="s2">"6th Edition"</span><span class="p">;</span>
<span class="s2">"5th Edition"</span> <span class="o">-></span> <span class="s2">"PWB 1.0"</span><span class="p">;</span>
<span class="s2">"6th Edition"</span> <span class="o">-></span> <span class="n">LSX</span><span class="p">;</span>
<span class="s2">"6th Edition"</span> <span class="o">-></span> <span class="s2">"1 BSD"</span><span class="p">;</span>
<span class="s2">"6th Edition"</span> <span class="o">-></span> <span class="s2">"Mini Unix"</span><span class="p">;</span>
<span class="s2">"6th Edition"</span> <span class="o">-></span> <span class="n">Wollongong</span><span class="p">;</span>
<span class="s2">"6th Edition"</span> <span class="o">-></span> <span class="n">Interdata</span><span class="p">;</span>
<span class="n">Interdata</span> <span class="o">-></span> <span class="s2">"Unix/TS 3.0"</span><span class="p">;</span>
<span class="n">Interdata</span> <span class="o">-></span> <span class="s2">"PWB 2.0"</span><span class="p">;</span>
<span class="n">Interdata</span> <span class="o">-></span> <span class="s2">"7th Edition"</span><span class="p">;</span>
<span class="s2">"7th Edition"</span> <span class="o">-></span> <span class="s2">"8th Edition"</span><span class="p">;</span>
<span class="s2">"7th Edition"</span> <span class="o">-></span> <span class="s2">"32V"</span><span class="p">;</span>
<span class="s2">"7th Edition"</span> <span class="o">-></span> <span class="n">V7M</span><span class="p">;</span>
<span class="s2">"7th Edition"</span> <span class="o">-></span> <span class="s2">"Ultrix-11"</span><span class="p">;</span>
<span class="s2">"7th Edition"</span> <span class="o">-></span> <span class="n">Xenix</span><span class="p">;</span>
<span class="s2">"7th Edition"</span> <span class="o">-></span> <span class="s2">"UniPlus+"</span><span class="p">;</span>
<span class="n">V7M</span> <span class="o">-></span> <span class="s2">"Ultrix-11"</span><span class="p">;</span>
<span class="s2">"8th Edition"</span> <span class="o">-></span> <span class="s2">"9th Edition"</span><span class="p">;</span>
<span class="s2">"1 BSD"</span> <span class="o">-></span> <span class="s2">"2 BSD"</span><span class="p">;</span>
<span class="s2">"2 BSD"</span> <span class="o">-></span> <span class="s2">"2.8 BSD"</span><span class="p">;</span>
<span class="s2">"2.8 BSD"</span> <span class="o">-></span> <span class="s2">"Ultrix-11"</span><span class="p">;</span>
<span class="s2">"2.8 BSD"</span> <span class="o">-></span> <span class="s2">"2.9 BSD"</span><span class="p">;</span>
<span class="s2">"32V"</span> <span class="o">-></span> <span class="s2">"3 BSD"</span><span class="p">;</span>
<span class="s2">"3 BSD"</span> <span class="o">-></span> <span class="s2">"4 BSD"</span><span class="p">;</span>
<span class="s2">"4 BSD"</span> <span class="o">-></span> <span class="s2">"4.1 BSD"</span><span class="p">;</span>
<span class="s2">"4.1 BSD"</span> <span class="o">-></span> <span class="s2">"4.2 BSD"</span><span class="p">;</span>
<span class="s2">"4.1 BSD"</span> <span class="o">-></span> <span class="s2">"2.8 BSD"</span><span class="p">;</span>
<span class="s2">"4.1 BSD"</span> <span class="o">-></span> <span class="s2">"8th Edition"</span><span class="p">;</span>
<span class="s2">"4.2 BSD"</span> <span class="o">-></span> <span class="s2">"4.3 BSD"</span><span class="p">;</span>
<span class="s2">"4.2 BSD"</span> <span class="o">-></span> <span class="s2">"Ultrix-32"</span><span class="p">;</span>
<span class="s2">"PWB 1.0"</span> <span class="o">-></span> <span class="s2">"PWB 1.2"</span><span class="p">;</span>
<span class="s2">"PWB 1.0"</span> <span class="o">-></span> <span class="s2">"USG 1.0"</span><span class="p">;</span>
<span class="s2">"PWB 1.2"</span> <span class="o">-></span> <span class="s2">"PWB 2.0"</span><span class="p">;</span>
<span class="s2">"USG 1.0"</span> <span class="o">-></span> <span class="s2">"CB Unix 1"</span><span class="p">;</span>
<span class="s2">"USG 1.0"</span> <span class="o">-></span> <span class="s2">"USG 2.0"</span><span class="p">;</span>
<span class="s2">"CB Unix 1"</span> <span class="o">-></span> <span class="s2">"CB Unix 2"</span><span class="p">;</span>
<span class="s2">"CB Unix 2"</span> <span class="o">-></span> <span class="s2">"CB Unix 3"</span><span class="p">;</span>
<span class="s2">"CB Unix 3"</span> <span class="o">-></span> <span class="s2">"Unix/TS++"</span><span class="p">;</span>
<span class="s2">"CB Unix 3"</span> <span class="o">-></span> <span class="s2">"PDP-11 Sys V"</span><span class="p">;</span>
<span class="s2">"USG 2.0"</span> <span class="o">-></span> <span class="s2">"USG 3.0"</span><span class="p">;</span>
<span class="s2">"USG 3.0"</span> <span class="o">-></span> <span class="s2">"Unix/TS 3.0"</span><span class="p">;</span>
<span class="s2">"PWB 2.0"</span> <span class="o">-></span> <span class="s2">"Unix/TS 3.0"</span><span class="p">;</span>
<span class="s2">"Unix/TS 1.0"</span> <span class="o">-></span> <span class="s2">"Unix/TS 3.0"</span><span class="p">;</span>
<span class="s2">"Unix/TS 3.0"</span> <span class="o">-></span> <span class="s2">"TS 4.0"</span><span class="p">;</span>
<span class="s2">"Unix/TS++"</span> <span class="o">-></span> <span class="s2">"TS 4.0"</span><span class="p">;</span>
<span class="s2">"CB Unix 3"</span> <span class="o">-></span> <span class="s2">"TS 4.0"</span><span class="p">;</span>
<span class="s2">"TS 4.0"</span> <span class="o">-></span> <span class="s2">"System V.0"</span><span class="p">;</span>
<span class="s2">"System V.0"</span> <span class="o">-></span> <span class="s2">"System V.2"</span><span class="p">;</span>
<span class="s2">"System V.2"</span> <span class="o">-></span> <span class="s2">"System V.3"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<h3>Ejemplo de un organigrama empresarial</h3>
<figure class='code'>
<figcaption><span class="liquid-tags-code-filename">demo_graphviz_3.dot</span><a href='/graphviz/demo_graphviz_3.dot'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="n">digraph</span> <span class="n">Organigram</span> <span class="p">{</span>
<span class="o">/*</span> <span class="n">General</span> <span class="n">Layout</span> <span class="o">*/</span>
<span class="n">rankdir</span> <span class="o">=</span> <span class="n">LR</span><span class="p">;</span>
<span class="o">/*</span> <span class="n">Subgraph</span> <span class="n">Branches</span> <span class="o">*/</span>
<span class="n">Subgraph</span> <span class="n">cluster_Branches</span> <span class="p">{</span>
<span class="n">node</span> <span class="p">[</span><span class="n">shape</span> <span class="o">=</span> <span class="n">square</span><span class="p">,</span> <span class="n">fontsize</span> <span class="o">=</span> <span class="mi">8</span><span class="p">];</span>
<span class="n">BRANCHES</span> <span class="p">[</span><span class="n">style</span> <span class="o">=</span> <span class="n">bold</span><span class="p">];</span>
<span class="n">Denrie</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="n">Information</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="s2">"Quick ID"</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="n">Instrument</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="n">Biomaterial</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="n">Quality</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="n">Function</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="n">Role</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="n">style</span> <span class="o">=</span> <span class="n">dashed</span><span class="p">;</span>
<span class="p">}</span>
<span class="o">/*</span> <span class="n">Subgraph</span> <span class="n">Developers</span> <span class="o">*/</span>
<span class="n">Subgraph</span> <span class="n">cluster_Developers</span> <span class="p">{</span>
<span class="n">node</span> <span class="p">[</span><span class="n">shape</span> <span class="o">=</span> <span class="n">box</span><span class="p">,</span> <span class="n">fontsize</span> <span class="o">=</span> <span class="mi">8</span><span class="p">];</span>
<span class="n">DEVELOPERS</span> <span class="p">[</span><span class="n">style</span> <span class="o">=</span> <span class="n">bold</span><span class="p">];</span>
<span class="s2">"Coordinating Committee"</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="s2">"Developers Working Groups"</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="s2">"Supporting Working Groups"</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="s2">"Community Representatives"</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="s2">"Scientific Community"</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="n">style</span> <span class="o">=</span> <span class="n">dashed</span><span class="p">;</span>
<span class="p">}</span>
<span class="o">/*</span> <span class="n">Subgraph</span> <span class="n">Development</span> <span class="n">ORGANIZATION</span> <span class="o">*/</span>
<span class="n">Subgraph</span> <span class="n">cluster_ORGANIZATION</span> <span class="p">{</span>
<span class="n">node</span> <span class="p">[</span><span class="n">shape</span> <span class="o">=</span> <span class="n">box</span><span class="p">,</span> <span class="n">fontsize</span> <span class="o">=</span> <span class="mi">8</span><span class="p">]</span>
<span class="s2">"ORGANIZATION"</span> <span class="p">[</span><span class="n">style</span> <span class="o">=</span> <span class="n">bold</span><span class="p">];</span>
<span class="s2">"Mailinglists"</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="s2">"Conference Calls"</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="n">Documents</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="n">Workshops</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="n">WIKI</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="n">style</span> <span class="o">=</span> <span class="n">dashed</span><span class="p">;</span>
<span class="p">}</span>
<span class="o">/*</span> <span class="n">Sub</span> <span class="n">Cluster</span> <span class="n">Design</span> <span class="o">*/</span>
<span class="n">Subgraph</span> <span class="n">cluster_Design</span> <span class="p">{</span>
<span class="n">node</span> <span class="p">[</span><span class="n">shape</span> <span class="o">=</span> <span class="n">box</span><span class="p">,</span> <span class="n">fontsize</span> <span class="o">=</span> <span class="mi">8</span><span class="p">]</span>
<span class="n">DESIGN</span> <span class="p">[</span><span class="n">style</span> <span class="o">=</span> <span class="n">bold</span><span class="p">];</span>
<span class="s2">"TOOLS"</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="s2">"Design Patterns"</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="s2">"Design Principles"</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="s2">"Design Process"</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="s2">"Policy"</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="n">style</span> <span class="o">=</span> <span class="n">dashed</span><span class="p">;</span>
<span class="p">}</span>
<span class="o">/*</span> <span class="n">Sub</span> <span class="n">Evaluation</span> <span class="o">*/</span>
<span class="n">Subgraph</span> <span class="n">cluster_Evaluation</span> <span class="p">{</span>
<span class="n">node</span> <span class="p">[</span><span class="n">shape</span> <span class="o">=</span> <span class="n">box</span><span class="p">,</span> <span class="n">fontsize</span> <span class="o">=</span> <span class="mi">8</span><span class="p">]</span>
<span class="s2">"OBI Evaluation"</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="s2">"Terms + Use Cases"</span> <span class="p">[</span><span class="n">color</span> <span class="o">=</span> <span class="n">grey</span><span class="p">];</span>
<span class="n">style</span> <span class="o">=</span> <span class="n">dashed</span><span class="p">;</span>
<span class="p">}</span>
<span class="o">/*</span> <span class="n">Relations</span> <span class="o">*/</span>
<span class="n">node</span> <span class="p">[</span><span class="n">shape</span> <span class="o">=</span> <span class="n">box</span><span class="p">,</span> <span class="n">style</span> <span class="o">=</span> <span class="n">filled</span><span class="p">,</span> <span class="n">color</span> <span class="o">=</span> <span class="n">black</span><span class="p">,</span> <span class="n">fontcolor</span> <span class="o">=</span> <span class="n">white</span><span class="p">,</span> <span class="n">fontsize</span> <span class="o">=</span> <span class="mi">10</span><span class="p">];</span>
<span class="n">OBI</span> <span class="o">-></span> <span class="n">BRANCHES</span><span class="p">;</span>
<span class="n">BRANCHES</span> <span class="o">-></span> <span class="n">Denrie</span><span class="p">;</span>
<span class="n">BRANCHES</span> <span class="o">-></span> <span class="n">Information</span><span class="p">;</span>
<span class="n">BRANCHES</span> <span class="o">-></span> <span class="n">Instrument</span><span class="p">;</span>
<span class="n">BRANCHES</span> <span class="o">-></span> <span class="n">Biomaterial</span><span class="p">;</span>
<span class="n">BRANCHES</span> <span class="o">-></span> <span class="n">Quality</span><span class="p">;</span>
<span class="n">BRANCHES</span> <span class="o">-></span> <span class="n">Function</span><span class="p">;</span>
<span class="n">BRANCHES</span> <span class="o">-></span> <span class="n">Role</span><span class="p">;</span>
<span class="n">BRANCHES</span> <span class="o">-></span> <span class="s2">"Quick ID"</span><span class="p">;</span>
<span class="n">OBI</span> <span class="o">-></span> <span class="n">DEVELOPERS</span><span class="p">;</span>
<span class="n">DEVELOPERS</span> <span class="o">-></span> <span class="s2">"Coordinating Committee"</span><span class="p">;</span>
<span class="n">DEVELOPERS</span> <span class="o">-></span> <span class="s2">"Developers Working Groups"</span><span class="p">;</span>
<span class="n">DEVELOPERS</span> <span class="o">-></span> <span class="s2">"Supporting Working Groups"</span><span class="p">;</span>
<span class="n">DEVELOPERS</span> <span class="o">-></span> <span class="s2">"Community Representatives"</span><span class="p">;</span>
<span class="n">DEVELOPERS</span> <span class="o">-></span> <span class="s2">"Scientific Community"</span><span class="p">;</span>
<span class="s2">"Scientific Community"</span> <span class="o">-></span> <span class="s2">"Quick ID"</span><span class="p">;</span>
<span class="s2">"Community Representatives"</span> <span class="o">-></span> <span class="s2">"BRANCHES"</span><span class="p">;</span>
<span class="s2">"Supporting Working Groups"</span> <span class="o">-></span> <span class="s2">"BRANCHES"</span><span class="p">;</span>
<span class="s2">"Coordinating Committee"</span> <span class="o">-></span> <span class="s2">"BRANCHES"</span><span class="p">;</span>
<span class="s2">"Developers Working Groups"</span> <span class="o">-></span> <span class="s2">"BRANCHES"</span><span class="p">;</span>
<span class="n">OBI</span> <span class="o">-></span> <span class="n">ORGANIZATION</span><span class="p">;</span>
<span class="n">ORGANIZATION</span> <span class="o">-></span> <span class="s2">"Mailinglists"</span><span class="p">;</span>
<span class="n">ORGANIZATION</span> <span class="o">-></span> <span class="s2">"Conference Calls"</span><span class="p">;</span>
<span class="n">ORGANIZATION</span> <span class="o">-></span> <span class="n">Documents</span><span class="p">;</span>
<span class="n">ORGANIZATION</span> <span class="o">-></span> <span class="n">Workshops</span><span class="p">;</span>
<span class="n">ORGANIZATION</span> <span class="o">-></span> <span class="n">WIKI</span><span class="p">;</span>
<span class="n">OBI</span> <span class="o">-></span> <span class="n">DESIGN</span><span class="p">;</span>
<span class="n">DESIGN</span> <span class="o">-></span> <span class="s2">"Design Patterns"</span><span class="p">;</span>
<span class="n">DESIGN</span> <span class="o">-></span> <span class="s2">"Design Principles"</span><span class="p">;</span>
<span class="n">DESIGN</span> <span class="o">-></span> <span class="n">TOOLS</span><span class="p">;</span>
<span class="n">DESIGN</span> <span class="o">-></span> <span class="s2">"Design Process"</span><span class="p">;</span>
<span class="n">DESIGN</span> <span class="o">-></span> <span class="n">Policy</span><span class="p">;</span>
<span class="s2">"Design Process"</span> <span class="o">-></span> <span class="s2">"Terms + Use Cases"</span><span class="p">;</span>
<span class="s2">"Terms + Use Cases"</span> <span class="o">-></span><span class="s2">"OBI Evaluation"</span><span class="p">;</span>
<span class="s2">"OBI Evaluation"</span> <span class="o">-></span> <span class="n">DESIGN</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<h3>Ejemplo de una gráfica utilizando degradados de colores</h3>
<figure class='code'>
<figcaption><span class="liquid-tags-code-filename">demo_graphviz_4.dot</span><a href='/graphviz/demo_graphviz_4.dot'>download</a></figcaption>
<div class="highlight"><pre><span></span><code><span class="n">digraph</span> <span class="n">G</span> <span class="p">{</span><span class="n">bgcolor</span><span class="o">=</span><span class="s2">"red:cyan"</span> <span class="n">gradientangle</span><span class="o">=</span><span class="mi">0</span>
<span class="n">subgraph</span> <span class="n">cluster_0</span> <span class="p">{</span>
<span class="n">style</span><span class="o">=</span><span class="n">filled</span><span class="p">;</span>
<span class="n">color</span><span class="o">=</span><span class="n">lightgrey</span><span class="p">;</span>
<span class="n">fillcolor</span><span class="o">=</span><span class="s2">"blue:yellow"</span><span class="p">;</span>
<span class="n">gradientangle</span><span class="o">=</span><span class="mi">90</span><span class="p">;</span>
<span class="n">node</span> <span class="p">[</span><span class="n">fillcolor</span><span class="o">=</span><span class="s2">"yellow:green"</span> <span class="n">style</span><span class="o">=</span><span class="n">filled</span> <span class="n">gradientangle</span><span class="o">=</span><span class="mi">270</span><span class="p">]</span> <span class="n">a0</span><span class="p">;</span>
<span class="n">node</span> <span class="p">[</span><span class="n">fillcolor</span><span class="o">=</span><span class="s2">"green:red"</span><span class="p">]</span> <span class="n">a1</span><span class="p">;</span>
<span class="n">node</span> <span class="p">[</span><span class="n">fillcolor</span><span class="o">=</span><span class="s2">"red:cyan"</span><span class="p">]</span> <span class="n">a2</span><span class="p">;</span>
<span class="n">node</span> <span class="p">[</span><span class="n">fillcolor</span><span class="o">=</span><span class="s2">"cyan:blue"</span><span class="p">]</span> <span class="n">a3</span><span class="p">;</span>
<span class="n">a0</span> <span class="o">-></span> <span class="n">a1</span> <span class="o">-></span> <span class="n">a2</span> <span class="o">-></span> <span class="n">a3</span><span class="p">;</span>
<span class="n">label</span> <span class="o">=</span> <span class="s2">"process #1"</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">subgraph</span> <span class="n">cluster_1</span> <span class="p">{</span>
<span class="n">node</span> <span class="p">[</span><span class="n">fillcolor</span><span class="o">=</span><span class="s2">"yellow:magenta"</span>
<span class="n">style</span><span class="o">=</span><span class="n">filled</span> <span class="n">gradientangle</span><span class="o">=</span><span class="mi">270</span><span class="p">]</span> <span class="n">b0</span><span class="p">;</span>
<span class="n">node</span> <span class="p">[</span><span class="n">fillcolor</span><span class="o">=</span><span class="s2">"magenta:cyan"</span><span class="p">]</span> <span class="n">b1</span><span class="p">;</span>
<span class="n">node</span> <span class="p">[</span><span class="n">fillcolor</span><span class="o">=</span><span class="s2">"cyan:red"</span><span class="p">]</span> <span class="n">b2</span><span class="p">;</span>
<span class="n">node</span> <span class="p">[</span><span class="n">fillcolor</span><span class="o">=</span><span class="s2">"red:blue"</span><span class="p">]</span> <span class="n">b3</span><span class="p">;</span>
<span class="n">b0</span> <span class="o">-></span> <span class="n">b1</span> <span class="o">-></span> <span class="n">b2</span> <span class="o">-></span> <span class="n">b3</span><span class="p">;</span>
<span class="n">label</span> <span class="o">=</span> <span class="s2">"process #2"</span><span class="p">;</span>
<span class="n">color</span><span class="o">=</span><span class="n">blue</span>
<span class="n">fillcolor</span><span class="o">=</span><span class="s2">"blue:yellow"</span><span class="p">;</span>
<span class="n">style</span><span class="o">=</span><span class="n">filled</span><span class="p">;</span>
<span class="n">gradientangle</span><span class="o">=</span><span class="mi">90</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">start</span> <span class="o">-></span> <span class="n">a0</span><span class="p">;</span>
<span class="n">start</span> <span class="o">-></span> <span class="n">b0</span><span class="p">;</span>
<span class="n">a1</span> <span class="o">-></span> <span class="n">b3</span><span class="p">;</span>
<span class="n">b2</span> <span class="o">-></span> <span class="n">a3</span><span class="p">;</span>
<span class="n">a3</span> <span class="o">-></span> <span class="n">a0</span><span class="p">;</span>
<span class="n">a3</span> <span class="o">-></span> <span class="n">end</span><span class="p">;</span>
<span class="n">b3</span> <span class="o">-></span> <span class="n">end</span><span class="p">;</span>
<span class="n">start</span> <span class="p">[</span><span class="n">shape</span><span class="o">=</span><span class="n">Mdiamond</span> <span class="p">,</span>
<span class="n">fillcolor</span><span class="o">=</span><span class="s2">"yellow:brown"</span><span class="p">,</span>
<span class="n">gradientangle</span><span class="o">=</span><span class="mi">90</span><span class="p">,</span>
<span class="n">style</span><span class="o">=</span><span class="n">radial</span><span class="p">];</span>
<span class="n">end</span> <span class="p">[</span><span class="n">shape</span><span class="o">=</span><span class="n">Msquare</span><span class="p">,</span>
<span class="n">fillcolor</span><span class="o">=</span><span class="s2">"orange:blue"</span><span class="p">,</span>
<span class="n">style</span><span class="o">=</span><span class="n">radial</span><span class="p">,</span>
<span class="n">gradientangle</span><span class="o">=</span><span class="mi">90</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div>
</figure>
<h2>Referencias</h2>
<ul>
<li><a href="http://www.graphviz.org">http://www.graphviz.org</a></li>
<li><a href="http://www.graphviz.org/About.php">http://www.graphviz.org/About.php</a></li>
<li><a href="http://itsecworks.com/2012/03/16/networking-topology-with-graphviz/">http://itsecworks.com/2012/03/16/networking-topology-with-graphviz/</a></li>
</ul>Instalación de Raspbian en la Raspberry Pi B+2014-08-01T23:35:44+02:002014-08-01T23:35:44+02:00BhEaNtag:pornohardware.com,2014-08-01:/2014/08/01/instalacion-de-raspbian-en-la-nueva-raspberry-pi-b-plus/<p><img class="left" src="/images/logos/logo_raspberrypi.png"/>
Si tuviera que decir uno de los <em>inventos</em> que más posibilidades tiene de los últimos años, o el que más horas de diversión puede proporcionar a un coste verdaderamente asequible, sin duda uno de los primeros que se me pasaría por la cabeza sería la genial <a href="http://www.raspberrypi.org/">Raspberry Pi</a>.</p>
<p>Supongo que la mayoría de vosotros, consumidores habituales del <em>pornohardware</em> más variado, obviamente conoceréis este increíble proyecto... pero para aquellos que hayan pasado los últimos años aislados en una cueva sin poder salir o en una isla desierta alimentándose únicamente de cocos y ostras y sin el más mínimo contacto con <em>la civilización</em>, os comentaré a modo de resumen rápido que Raspberry Pi es un ordenador del tamaño de un paquete de tabaco, y que cuesta aproximadamente 35 € (dependiendo del sitio donde la compréis). Esta descripción debería ser suficiente como para que aquellos que no la conocíais sintáis en éste momento la necesidad de tocaros...</p>
<p>A dia de hoy (salen nuevos modelos más potentes y con nuevas funcionalidades cada cierto tiempo) funciona con un procesador <a href="http://es.wikipedia.org/wiki/Arquitectura_ARM">ARM</a> a 700MHz (aunque se puede hacer <a href="http://es.wikipedia.org/wiki/Overclock"><em>overclocking</em></a> hasta los 1000MHz), por lo que se puede instalar cualquier distribución de Linux que soporte dicha arquitectura. En nuestro caso, y como no podía ser de otra manera, utilizaremos <a href="http://www.raspbian.org">Raspbian</a>: una <em>Debian adaptada a la Raspberry Pi</em>.</p>
<p><img class="left" src="/images/logos/logo_raspberrypi.png">
Si tuviera que decir uno de los <em>inventos</em> que más posibilidades tiene de los últimos años, o el que más horas de diversión puede proporcionar a un coste verdaderamente asequible, sin duda uno de los primeros que se me pasaría por la cabeza sería la genial <a href="http://www.raspberrypi.org/">Raspberry Pi</a>.</p>
<p>Supongo que la mayoría de vosotros, consumidores habituales del <em>pornohardware</em> más variado, obviamente conoceréis este increíble proyecto... pero para aquellos que hayan pasado los últimos años aislados en una cueva sin poder salir o en una isla desierta alimentándose únicamente de cocos y ostras y sin el más mínimo contacto con <em>la civilización</em>, os comentaré a modo de resumen rápido que Raspberry Pi es un ordenador del tamaño de un paquete de tabaco, y que cuesta aproximadamente 35 € (dependiendo del sitio donde la compréis). Esta descripción debería ser suficiente como para que aquellos que no la conocíais sintáis en éste momento la necesidad de tocaros...</p>
<p>A dia de hoy (salen nuevos modelos más potentes y con nuevas funcionalidades cada cierto tiempo) funciona con un procesador <a href="http://es.wikipedia.org/wiki/Arquitectura_ARM">ARM</a> a 700MHz (aunque se puede hacer <a href="http://es.wikipedia.org/wiki/Overclock"><em>overclocking</em></a> hasta los 1000MHz), por lo que se puede instalar cualquier distribución de Linux que soporte dicha arquitectura. En nuestro caso, y como no podía ser de otra manera, utilizaremos <a href="http://www.raspbian.org">Raspbian</a>: una <em>Debian adaptada a la Raspberry Pi</em>.</p>
<p>El proyecto nació en Reino Unido, en 2006, y lo que pretendían sus creadores (la Fundación Raspberry Pi) era fomentar la informática y su aprendizaje en los colegios y escuelas... pero dada la enorme acogida que ha tenido por todo el mundo y gracias a los proyectos que la gente ha llevado a cabo con ellos, hoy en dia hay pocas cosas que no se puedan hacer con una de éstas placas.</p>
<p>A dia de hoy (mediados de 2014) existen 3 modelos:</p>
<ul>
<li><strong>Modelo A</strong>: 256Mb de RAM, 1 puerto USB, salida video HDMI y RCA, salida video DSI para LCD, salida audio 3.5mm, 8 x GPIO/SPI/I<sup>2</sup>C/UART</li>
</ul>
<p><img class="center" src="/images/posts/raspberrypi/raspberrypi_model_A.png"></p>
<ul>
<li><strong>Modelo B</strong>: 512Mb de RAM, 2 puertos USB, ethernet 10/100, salida video HDMI y RCA, salida video DSI para LCD, salida audio 3.5mm, 8 x GPIO/SPI/I<sup>2</sup>C/UART</li>
</ul>
<p><img class="center" src="/images/posts/raspberrypi/raspberrypi_model_B.png"></p>
<ul>
<li><strong>Modelo B+</strong>: 512Mb de RAM, 4 puertos USB, ethernet 10/100, salida video HDMI, salida video DSI para LCD, salida audio 3.5mm, 8 x GPIO/SPI/I<sup>2</sup>C/UART</li>
</ul>
<p><img class="center" src="/images/posts/raspberrypi/raspberrypi_model_B+.png"></p>
<p>Yo ya tengo 3 de ellas (dos del modelo B, y una del nuevo modelo B+) y las utilizo para diferentes cosas (monitorización de la temperatura y el consumo eléctrico de mi casa, media-center conectado por red a mi <a href="http://es.wikipedia.org/wiki/Dlna">servidor DLNA</a>, etc)... y tengo cientos de ideas (casi literalmente) para futuros proyectos, por lo que no voy a meterme en qué podeis hacer con ella y que no, únicamente voy a explicar cómo se <em>ponen en marcha</em> desde que la recibimos al comprarla hasta que la tenemos funcionando como cualquier otro de nuestros ordenadores...</p>
<h2>Antes de la instalación</h2>
<p>Las placas Raspberry Pi no llevan unidades de almacenamiento ni memorias no volátiles que nos permitan guardar cosas sin que se pierdan al desconectar la alimentación (como discos duros, memorias flash o similar), sino que permiten o bien conectar <em>pendrives</em> o discos duros por USB, o utilizar tarjetas SD (o microSD, en el caso del modelo B+). Ésta última es la opción más indicada para instalar el sistema, y una vez hecho, si queremos aumentar sustancialmente el espacio de nuestro disco por algun motivo, podremos usar aparte discos duros USB o pendrives igualmente..</p>
<p>Venden tarjetas SD/microSD preformateadas y con sistemas operativos orientados para Raspberry Pi precargados que podéis comprar si no queréis instalarlo vosotros... pero si no lo hacéis, cómo cojones pensáis aprender, panda de vagos??
En este artículo vamos a dar por sentado que ya dispones de una tarjeta microSD (que es el tipo de tarjeta que acepta el modelo B+) y que has elegido la distribución que vas a instalar de entre todas las disponibles:</p>
<ul>
<li>Raspbian: Distribución basada en <a href="http://www.debian.org">Debian</a>.</li>
<li>Pidora: Igual, pero basada en <a href="http://fedoraproject.org/es/">Fedora Project</a></li>
<li>OpenElec: Esta distribución está orientada a servir de media-center, para lo que utiliza el cojonudísimo <a href="https://kodi.tv">KODI</a> (anteriormente conocido como <em>XBMC</em>).</li>
<li>RaspBMX: Otra distribución orientada a media-center que utiliza Kodi.</li>
<li>Arch Linux: Distribución basada en <a href="https://www.archlinux.org/">Arch Linux</a>.</li>
<li>RiscOS: Porque no solo de Linux vive el hombre... xDD</li>
<li>NOOBS: Ésta <em>aplicación</em> permite instalar varias distribuciones (de hecho, todas las anteriores) en una tarjeta SD/microSD para que podamos probarlas cómodamente en nuestra Raspberry Pi simplemente eligiendo la que queremos utilizar durante el arranque de la Raspberry.</li>
<li><a href="http://es.wikipedia.org/wiki/Raspberry_Pi#Sistemas_operativos">Y muchos otros más</a>...</li>
</ul>
<p>Como ya he dicho antes, en éste ejemplo vamos a utilizar la que más me gusta (y he probado muchas ya), que es <strong>Raspbian</strong>.</p>
<h2>Instalación de Raspbian</h2>
<p>Raspbian es una distribución de Linux basada en Debian pero optimizada para ejecutarse en las placas Raspberry Pi.</p>
<p>Es un proyecto libre, y se ofrece de forma gratuita a todo el mundo, por lo que si quieres colaborar con ellos, <a href="http://www.raspbian.org/RaspbianDonate">una pequeña donación siempre es bien recibida</a> para ayudarles con los costes del proyecto y que puedan seguir ofreciendo Raspbian gratuitamente.</p>
<p>Existen imágenes de Raspbian lista para grabar en una tarjeta SD/microSD (que son las que aceptan las placas Raspberry Pi), por lo que lo primero que tenemos que hacer es descargar dicha imagen desde aquí: <a href="http://www.raspberrypi.org/downloads/">http://www.raspberrypi.org/downloads/</a></p>
<p>Una vez descargado el archivo (en mi caso se llama <code>2014-06-20-wheezy-raspbian.zip</code>), y dado que es un archivo comprimido con ZIP, lo descomprimimos para obtener la imagen:</p>
<div class="highlight"><pre><span></span><code>$ unzip <span class="m">2014</span>-06-20-wheezy-raspbian.zip
Archive: <span class="m">2014</span>-06-20-wheezy-raspbian.zip
inflating: <span class="m">2014</span>-06-20-wheezy-raspbian.img
</code></pre></div>
<p>Ahora que ya tenemos el archivo con la imagen, vamos a guardarlo en nuestra tarjeta SD/microSD, y para hacer eso vamos a utilizar el genial comando <code>dd</code>, que permite realizar copias de archivos a bajo nivel.</p>
<p>Solo tenemos que indicarle el origen (parámetro <code>if</code>: archivo imagen que acabamos de descargar) y el destino (parámetro <code>of</code>: dispositivo asociado a la tarjeta SD).</p>
<p>No lo he comentado antes, pero la tarjeta que vayamos a utilizar tiene que tener al menos 4Gb de capacidad para poder instalar el sistema, y obviamente todo lo que haya en ella será eliminado, así que aseguraros de copiar a otro sitio todos los archivos que pudiera haber en la SD que vais a usar. No me hago responsable de todas esas fotos guarras que podéis llegar a perder si no (que otra cosa podríais tener en una SD?)</p>
<p>Es MUY importante que indiquéis el dispositivo asociado a vuestra tarjeta SD directamente, nada de particiones... es decir, si vuestra tarjeta está en <code>/dev/sdf</code>, debéis especificar precisamente eso (NO <code>/dev/sdf1</code>), y por supuesto utilizando <code>sudo</code> para poder escribir en un dispositivo <code>/dev</code> desde un usuario no-privilegiado (que es como deberíais trabajar siempre en Linux).</p>
<p>El proceso tardará un buen rato, así que tener paciencia y no desesperéis:</p>
<div class="highlight"><pre><span></span><code>$ sudo dd <span class="k">if</span><span class="o">=</span><span class="m">2014</span>-06-20-wheezy-raspbian.img <span class="nv">of</span><span class="o">=</span>/dev/sdf
<span class="m">5785600</span>+0 records in
<span class="m">5785600</span>+0 records out
<span class="m">2962227200</span> bytes <span class="o">(</span><span class="m">3</span>.0 GB<span class="o">)</span> copied, <span class="m">919</span>.358 s, <span class="m">3</span>.2 MB/s
</code></pre></div>
<p>Una vez terminado, ya tendremos la tarjeta lista para meterla en la Raspberry Pi y encenderla...</p>
<h2>Configuración</h2>
<p>Para éste primer arranque, lo suyo es que conectéis únicamente un teclado USB para poder manejarla, un monitor (utilizando la salida HDMI de la Raspberry Pi) y el transformador de corriente (podéis conectar también un cable ethernet conectado a vuestra red para poder actualizar el sistema desde Internet e instalar los paquetes que querais).</p>
<p>Por defecto, los datos de acceso al sistema Raspbian son:</p>
<p><strong>Usuario: pi
Password: raspberry</strong></p>
<p>Y si necesitamos privilegios de <code>root</code>, podemos usar <code>sudo</code> desde ese mismo usuario.</p>
<p>Si todo ha ido bien (y debe haber ido así, ya que lo único que hemos hecho es copiar la imagen de Raspbian a la tarjeta SD) nuestra Raspberry Pi arrancará como si de un ordenador normal y corriente se tratara, y al ser el primer arranque de nuestra Raspbian nos aparecerá la pantalla de configuración:</p>
<p><img class="center" src="/images/posts/raspberrypi/raspberrypi_raspi-config.png">
Configuración del comando raspi-config durante el primer arranque de Raspbian</p>
<p>Ésta pantalla de configuración nos permite realizar algunas acciones con nuestra Raspberry, sobre todo acerca de la configuración de ésta.</p>
<p>Una de las más importantes es la primera, que dice algo así como <code>1 Expand Filesystem</code>. Esta opción redimensiona la partición que hemos creado al grabar la imagen de Raspbian para que ocupe el 100% de la tarjeta, de forma que si hemos usado una SD de 8Gb (por ejemplo) podamos hacer eso de todo el espacio, no solo de los 3Gb que ocupa la partición original de Raspbian.</p>
<p>La siguiente opción necesaria es la configuración del idioma y el teclado que queramos usar. Es la opción 4: <code>4 Internationalisation Options</code>.</p>
<p>El resto de opciones (activar el soporte para el uso de la <a href="http://es.wikipedia.org/wiki/Raspberry_pi#Accesorios">cámara original de Raspberry Pi</a>, overclocking, opciones avanzadas, etc) dependerá del uso que vayais a hacer de la Raspberry Pi, y queda fuera del ámbito de este artículo (pero seguro que no va a ser el último al respecto, sobre todo alguno hablando de la increíble cámara de Raspberry Pi)</p>
<p>Yo recomiendo, una vez configurada, que <em>aseguréis</em> un poco el sistema como haríais con cualquier otro servidor recién instalado, es decir: securizar el acceso por ssh, cambiar la password por defecto del usuario <code>pi</code> (esto no debería hacer falta ni decirlo, es <strong>lo primero que deberíais haber hecho</strong>, pero nunca se sabe <em>qué clase de gañán</em> puede estar leyendo este artículo), configurar la red, actualizar los paquetes de la distribución desde <code>apt-get</code>, etc, etc.</p>
<p>Espero que os haya resultado interesante(lo cierto es que lo es, y mucho), así que os animo a que compréis una y empecéis a <em>hacer cosillas</em> con ella...</p>
<p>Alaaaaaaaaaaaaaaaaaaaaaaa</p>Feliz dia del Administrador de Sistemas!2014-07-25T10:49:55+02:002014-07-25T10:49:55+02:00BhEaNtag:pornohardware.com,2014-07-25:/2014/07/25/feliz-dia-del-administrador-de-sistemas/<blockquote>
<p><em>"Las organizaciones gastan millones de dólares en firewalls y dispositivos de seguridad, pero tiran el dinero porque ninguna de estas medidas cubren el eslabón más débil de la cadena de seguridad: la gente que usa y administra los ordenadores."</em>
<br /><br />
<a href="http://es.wikipedia.org/wiki/Kevin_Mitnick">Kevin Mitnick</a>. Hacker, cracker, phreaker, leyenda.</p>
</blockquote>
<p>Y si no sabes de qué va éste post, échale un ojo a <a href="http://sysadminday.com">http://sysadminday.com</a> (o a su versión <a href="http://www.diadeladministradordesistemas.com/">en español</a>).</p>Búsquedas por similitud de trigramas en PostgreSQL con pg_trgm2014-07-23T20:54:53+02:002014-07-23T20:54:53+02:00BhEaNtag:pornohardware.com,2014-07-23:/2014/07/23/busqueda-por-similitud-de-trigramas-en-postgresql-con-pg-trgm/<p><a href="https://es.wikipedia.org/wiki/Oracle">Oracle</a> es la leche, eso no creo que haya nadie que pueda negarlo.
Sin duda es una de las mejores (si no la mejor) bases de datos del mundo... pero por desgracia para el común de <em>vosotros</em> los humanos, su código es privativo y su precio prohibitivo (<em>y juro que el pareado ha sido espontáneo!</em>).</p>
<p>Pero no desesperéis... no hace falta que recurráis a <a href="https://www.microsoft.com/es-es/sql-server/"><em>soluciones</em> inferiores</a> ni nada parecido.
Gracias a <a href="http://en.wikipedia.org/wiki/Lords_of_Kobol">los Dioses</a> tenemos <a href="http://www.postgresql.org/">PostgreSQL</a>, aunque en éste artículo no vamos a hablar de éste genial motor de base de datos, sino de uno de los módulos adicionales que incorpora para realizar búsquedas basandose en la similitud entre los trigramas de una cadena: <a href="http://www.postgresql.org/docs/current/static/pgtrgm.html">pg_trgm</a>.</p>
<p><a href="https://es.wikipedia.org/wiki/Oracle">Oracle</a> es la leche, eso no creo que haya nadie que pueda negarlo.
Sin duda es una de las mejores (si no la mejor) bases de datos del mundo... pero por desgracia para el común de <em>vosotros</em> los humanos, su código es privativo y su precio prohibitivo (<em>y juro que el pareado ha sido espontáneo!</em>).</p>
<p>Pero no desesperéis... no hace falta que recurráis a <a href="https://www.microsoft.com/es-es/sql-server/"><em>soluciones</em> inferiores</a> ni nada parecido.
Gracias a <a href="http://en.wikipedia.org/wiki/Lords_of_Kobol">los Dioses</a> tenemos <a href="http://www.postgresql.org/">PostgreSQL</a>, aunque en éste artículo no vamos a hablar de éste genial motor de base de datos, sino de uno de los módulos adicionales que incorpora para realizar búsquedas basandose en la similitud entre los trigramas de una cadena: <a href="http://www.postgresql.org/docs/current/static/pgtrgm.html">pg_trgm</a>.</p>
<p>Primero vamos con un poco de teoría: ¿qué es un <strong>trigrama?</strong>
En el contexto en el que estamos hablando, un trigrama se define como una palabra formada por 3 carácteres.</p>
<p>Para obtener éstos 3 carácteres, ésta extensión descompone las cadenas en algo parecido a las <em>sílabas</em> de la palabra (aunque realmente no son sílabas) y si es necesario concatena espacios en blanco delante o detrás de aquellas <em>sílabas</em> que no tengan 3 carácteres de longitud.</p>
<p>Únicamente se utilizan los carácteres alfanuméricos, por lo que puntos, comas, asteriscos, paréntesis o cualquier otro carácter que pudiera contener la cadena que <strong>no</strong> sea un número o una letra es ignorado.</p>
<p>Se ve mucho más claro con un ejemplo, así que primero vamos a ver qué trigramas forman la palabra <code>pornohardware</code>:</p>
<div class="highlight"><pre><span></span><code><span class="gp">postgres=#</span> <span class="k">select</span> <span class="n">show_trgm</span><span class="p">(</span><span class="s1">'pornohardware'</span><span class="p">);</span>
<span class="go"> show_trgm</span>
<span class="go">-----------------------------------------------------------------</span>
<span class="go"> {" p"," po",ard,are,dwa,har,noh,oha,orn,por,rdw,"re ",rno,war}</span>
<span class="go">(1 row)</span>
</code></pre></div>
<p>Como puedes ver, la palabra <code>pornohardware</code> está formada por 14 trigramas:
<code>__p</code>, <code>_po</code>, <code>ard</code>, <code>are</code>, <code>dwa</code>, <code>har</code>, <code>noh</code>, <code>oha</code>, <code>orn</code>, <code>por</code>, <code>rdw</code>, <code>re_</code>, <code>rno</code> y <code>war</code>.</p>
<p>Si quisiéramos comparar ésta palabra con otra, por ejemplo, con <code>pornosoftware</code> (<em>no es que esté obsesionado, es para que se note la similitud en la comparación xDDD</em>), los trigramas que forman ésta última serían:</p>
<div class="highlight"><pre><span></span><code><span class="gp">postgres=#</span> <span class="k">select</span> <span class="n">show_trgm</span><span class="p">(</span><span class="s1">'pornosoftware'</span><span class="p">);</span>
<span class="go"> show_trgm</span>
<span class="go">-----------------------------------------------------------------</span>
<span class="go"> {" p"," po",are,ftw,nos,oft,orn,oso,por,"re ",rno,sof,twa,war}</span>
<span class="go">(1 row)</span>
</code></pre></div>
<p>Es decir:
<code>__p</code>, <code>_po</code>, <code>are</code>, <code>ftw</code>, <code>nos</code>, <code>oft</code>, <code>orn</code>, <code>oso</code>, <code>por</code>, <code>re_</code>, <code>rno</code>, <code>sof</code>, <code>twa</code>, <code>war</code></p>
<p>De ésta forma, comparando las coincidencias entre los trigramas obtenidos, <code>pg_trgm</code> puede obtener un <em>porcentaje de similitud</em> entre ambas.
Y no creas que <em>parece bonito en teoría, pero luego no funciona del todo bien</em>... a la hora de la verdad cumple con creces lo esperado, no solo en la precisión de los resultados sino en eficiencia (obviamente es más costoso que una comparación normal entre cadenas, pero funciona realmente rápido).</p>
<p>Vamos a verlo:</p>
<div class="highlight"><pre><span></span><code><span class="gp">postgres=#</span> <span class="k">select</span> <span class="n">similarity</span><span class="p">(</span><span class="s1">'pornohardware'</span><span class="p">,</span> <span class="s1">'pornosoftware'</span><span class="p">);</span>
<span class="go"> similarity</span>
<span class="go">------------</span>
<span class="go"> 0.4</span>
<span class="go">(1 row)</span>
</code></pre></div>
<p>El resultado que devuelve la función <code>similarity</code> es un número entre 0 y 1, dependiendo de si las cadenas son <strong>completamente distintas</strong> (0) o <strong>completamente iguales</strong> (1).</p>
<p>Por tanto, multiplicando el resultado por 100 obtenemos el <em>porcentaje</em> de similitud entre ambas, que en éste caso es de un 40% (<code>pornohardware</code> y <code>pornosoftware</code> son similares al 40%).</p>
<p>Y ahora que más o menos sabemos de qué trata el asunto, vamos <em>al turrón</em>:</p>
<h2>Instalación</h2>
<p>Con versiones <em>antiguas</em> de PostgreSQL era algo engorrosa la instalación de dicho módulo, ya que había que ejecutar manualmente los comandos SQL que daban de alta en nuestra base de datos las funciones y librerias del módulo, lo que hacía que su mantenimiendo, acctualización o desinstalación no fuera tan limpia como debería.</p>
<p>No voy a explicar la instalación en éstos casos, ya que si a éstas alturas eres uno de esos malditos que continuan usando PostgreSQL 8.x (o incluso versiones anteriores) no solo no mereces ayuda, sino que algún dia (<em>en el Nuevo Orden Mundial, cuando por fin lidere a vuestra raza</em>) te perseguiré y daré caza como a una vulgar alimaña.</p>
<p>Para todos aquellos que utilizan versiones más o menos actuales de PostgreSQL (por ejemplo, 9.x en adelante), la instalación de <code>pg_trgm</code> es muy sencilla:</p>
<p>Primero debemos instalar el paquete <code>contrib</code> correspondiente a la versión de PostgreSQL que estemos utilizando.</p>
<p>Para aquellos hombres que usais <a href="http://www.debian.org"><strong>La Distribución</strong></a> (o distribuciones basadas en ella), basta con un simple:</p>
<div class="highlight"><pre><span></span><code>sudo apt-get install postgresql-contrib-9.3
</code></pre></div>
<p>Y para aquellos que utilizan <a href="">Redhat</a>, <a href="">CentOS</a> y similares bastaría con:</p>
<div class="highlight"><pre><span></span><code>sudo yum install postgresql93-contrib
</code></pre></div>
<p>Ésto siempre y cuando tengais las fuentes adecuadas en vuestros respectivos gestores de paquetes (<code>apt</code> y <code>yum</code>), claro.</p>
<p>Si éste no es vuestro caso, debeis añadir éstos archivos (dependiendo de nuevo de qué distribución useis):</p>
<p><strong>Debian y similares</strong>:</p>
<div class="highlight"><pre><span></span><code><span class="k">deb</span> <span class="s">http://apt.postgresql.org/pub/repos/apt/</span> <span class="kp">wheezy-pgdg</span> <span class="kp">main</span>
</code></pre></div>
<p><strong>Redhat/CentOS y similares</strong>:</p>
<div class="highlight"><pre><span></span><code><span class="err">[pgdg93]</span>
<span class="na">name</span><span class="o">=</span><span class="s">PostgreSQL 9.3 $releasever - $basearch</span>
<span class="na">baseurl</span><span class="o">=</span><span class="s">http://yum.postgresql.org/9.3/redhat/rhel-$releasever-$basearch</span>
<span class="na">enabled</span><span class="o">=</span><span class="s">1</span>
<span class="na">gpgcheck</span><span class="o">=</span><span class="s">1</span>
<span class="na">gpgkey</span><span class="o">=</span><span class="s">file:///etc/pki/rpm-gpg/RPM-GPG-KEY-PGDG-93</span>
<span class="err">[pgdg93-source]</span>
<span class="na">name</span><span class="o">=</span><span class="s">PostgreSQL 9.3 $releasever - $basearch - Source</span>
<span class="na">failovermethod</span><span class="o">=</span><span class="s">priority</span>
<span class="na">baseurl</span><span class="o">=</span><span class="s">http://yum.postgresql.org/srpms/9.3/redhat/rhel-$releasever-$basearch</span>
<span class="na">enabled</span><span class="o">=</span><span class="s">0</span>
<span class="na">gpgcheck</span><span class="o">=</span><span class="s">1</span>
<span class="na">gpgkey</span><span class="o">=</span><span class="s">file:///etc/pki/rpm-gpg/RPM-GPG-KEY-PGDG-93</span>
</code></pre></div>
<p>Una vez instalado el paquete <code>contrib</code>, accedemos a la consola de nuestra base de datos con el comando <code>psql</code> e instalamos la extensión con un sencillo <code>CREATE EXTENSION pg_trgm;</code>:</p>
<div class="highlight"><pre><span></span><code><span class="n">postgres</span><span class="o">@</span><span class="n">natalia</span><span class="p">:</span><span class="o">~</span><span class="err">$</span> <span class="n">psql</span>
<span class="n">psql</span> <span class="p">(</span><span class="mf">9.3.4</span><span class="p">)</span>
<span class="k">Type</span> <span class="s s-Name">"help"</span> <span class="k">for</span> <span class="n">help</span><span class="mf">.</span>
<span class="gp">postgres=#</span> <span class="k">CREATE</span> <span class="k">EXTENSION</span> <span class="n">pg_trgm</span><span class="p">;</span>
<span class="go">CREATE EXTENSION</span>
</code></pre></div>
<p>Y eso es todo... ya tenemos el módulo <code>pg_trgm</code> instalado en nuestro PostgreSQL.</p>
<p>Si quisiéramos desinstalar la extensión, simplemente bastaría con:</p>
<div class="highlight"><pre><span></span><code><span class="n">postgres</span><span class="o">@</span><span class="n">natalia</span><span class="p">:</span><span class="o">~</span><span class="err">$</span> <span class="n">psql</span>
<span class="n">psql</span> <span class="p">(</span><span class="mf">9.3.4</span><span class="p">)</span>
<span class="k">Type</span> <span class="s s-Name">"help"</span> <span class="k">for</span> <span class="n">help</span><span class="mf">.</span>
<span class="gp">postgres=#</span> <span class="k">DROP</span> <span class="k">EXTENSION</span> <span class="n">pg_trgm</span><span class="p">;</span>
<span class="go">DROP EXTENSION</span>
</code></pre></div>
<p>Y ahora vamos a ver cómo se usa...</p>
<h2>Funciones</h2>
<p>Una vez instalado el módulo, dispondremos de 4 nuevas funciones en nuestra base de datos:</p>
<ul>
<li>
<p><strong>similarity(text, text)</strong>
Ésta es la principal función que usaremos para comparar las cadenas.
Recibe 2 parámetros, que son las 2 cadenas que quedemos comparar, y devuelve un número <em>real</em> comprendido entre 0 y 1 según la similitud entre ambas cadenas.
Si las cadenas con completamente diferentes devolverá 0, y si son completamente iguales, devolverá 1 (por lo que si las cadenas son similares <em>a medias</em>, devolverá 0.5).</p>
</li>
<li>
<p><strong>show_trgm(text)</strong>
Ésta función recibe como parámetro una cadena, y devuelve un array con los trigramas que la forman. Se suele utilizar únicamente para depurar.</p>
</li>
<li>
<p><strong>set_limit(real)</strong>
Con ésta función podemos definir el umbral de similitud que debemos utilizar para considerar 2 cadenas como <em>similares</em>. Recibe como parámetro un número <em>real</em> de (de 0 a 1).
Por ejemplo, para entender mejor su funcionamiento, si llamamos a ésta función con el parámetro 0.39, significaría que cualquier cadena que al compararla con otra diera un valor superior a éste, sería considerada por el sistema como <em>similar</em> a dicha otra cadena.
Por lo tanto, según nuestro primer ejemplo al comparar <code>pornohardware</code> y <code>pornosoftware</code>, ambas se considerarían cadenas similares puesto que el resultado de su comparación fué 0.4.</p>
</li>
<li>
<p><strong>show_limit()</strong>
Ésta función únicamente muestra el umbral de similitud actual que hay definido en el sistema, es decir, el que previamente hemos establecido con <code>set_limit(real)</code>.</p>
</li>
</ul>
<h2>Ejemplos</h2>
<p>He escrito éste artículo porque he estado trabajando con éste módulo en <em>el curro</em> éstos últimos dias, y he quedado muy satisfecho con su funcionamiento en el proyecto en el que lo hemos estado utilizando, por lo que quizás es buena idea poner algunos usos reales que hemos hecho de él a modo de ejemplos de utilizacion (cambiando los nombres por cuestiones de privacidad):</p>
<p>Nuestro cliente disponía de una base de datos de clientes suyos (muy depurada a lo largo de los años, con información sobre localización, nombres, teléfonos, etc. de cada uno de ellos). Pero por motivos que no vienen al caso, le había llegado una segunda base de datos de clientes (mucho más desorganizada, con clientes duplicados, registros nulos, etc) de la que necesitaban obtener los clientes que ya tuvieran en su otra base de datos.</p>
<p>Su intención era relacionar aquellos clientes de la base de datos <em>sucia</em> con los de su base de datos <em>limpia</em>, y ésto no podía hacerse comparando de forma <em>tradicional</em> los nombres de los clientes o cualquier otro dato similar puesto que en la segunda base de datos había registros cuyos nombres estaban incorrectamente escritos, había faltas de ortografía en algunos campos, etc, etc.</p>
<p>La utilización de <code>pg_trgm</code> supuso la solución a éste problema, ya que pudimos comparar de forma automática cada registro de la base de datos <em>sucia</em> con los registros limpios y ordenados de la base de datos <em>limpia</em>, y listar éstos últimos ordenados en función de su similitud.</p>
<p>Después de varias pruebas, concluimos que necesitábamos establecer un umbral muy alto para estar seguros de que 2 clientes eran iguales.. por lo que después de unos cuantos intentos, asumimos que aquellos cuyos nombres nos dieran una similitud mayor al 0.75 eran en realidad el mismo cliente sin lugar a dudas (para el resto de clientes que no conseguíamos enlazar de forma automática e inequívoca mediante ésta comparación, utilizábamos otros sistemas... pero creo que el ejemplo es perfectamente válido para entender el funcionamiento de <code>pg_trgm</code>).</p>
<p>Antes de probar con <code>pg_trgm</code> lo intentamos a través del menor valor dado por <a href="http://es.wikipedia.org/wiki/Distancia_de_Damerau-Levenshtein">la distancia Levenshtein</a>, por comparación de las claves <a href="http://es.wikipedia.org/wiki/Soundex">Soundex</a> de las cadenas a buscar, etc, etc... y de todo lo que intentamos, éste genial módulo fué lo que mejor resultado dió.</p>
<p>Hicimos tambien comparaciones entre la dirección, el tipo de cliente y algunos otros datos... hasta que al final pudimos relacionar la inmensa mayoría de los clientes de la segunda base de datos con la primera con una altísima precisión, y simplemente utilizando <em>querys</em> parecidas a ésta:</p>
<div class="highlight"><pre><span></span><code><span class="k">SELECT</span>
<span class="n">id</span><span class="p">,</span>
<span class="k">name</span><span class="p">,</span>
<span class="n">address</span><span class="p">,</span>
<span class="n">city</span><span class="p">,</span>
<span class="n">region</span><span class="p">,</span>
<span class="n">similarity</span><span class="p">(</span><span class="s1">'Empresa 1 S.A.'</span><span class="p">,</span> <span class="k">name</span><span class="p">)</span> <span class="k">AS</span> <span class="n">similarity</span>
<span class="k">FROM</span>
<span class="n">clients_clean</span>
<span class="k">WHERE</span>
<span class="n">similarity</span><span class="p">(</span><span class="s1">'Empresa 1 S.A.'</span><span class="p">,</span> <span class="k">name</span><span class="p">)</span> <span class="o">></span> <span class="mf">0.34</span>
<span class="k">ORDER</span> <span class="k">BY</span>
<span class="n">similarity</span> <span class="k">DESC</span><span class="p">;</span>
</code></pre></div>
<p>Donde comparábamos al cliente <code>Empresa 1 S.A.</code> (obtenido de la base de datos <em>sucia</em>) con todos los clientes de la base de datos <em>limpia</em>, obteniendo algo parecido a ésto:</p>
<div class="highlight"><pre><span></span><code> <span class="n">id</span> <span class="o">|</span> <span class="k">name</span> <span class="o">|</span> <span class="n">address</span> <span class="o">|</span> <span class="n">city</span> <span class="o">|</span> <span class="n">region</span> <span class="o">|</span> <span class="n">similarity</span>
<span class="c1">--------+----------------+-------------+--------+----------+------------</span>
<span class="mf">169058</span> <span class="o">|</span> <span class="n">empresa</span> <span class="mf">1</span><span class="p">,</span> <span class="n">SA</span> <span class="o">|</span> <span class="n">ATOCHA</span><span class="p">,</span> <span class="mf">100</span> <span class="o">|</span> <span class="n">Madrid</span> <span class="o">|</span> <span class="n">MADRID</span> <span class="o">|</span> <span class="mf">0.733333</span>
<span class="mf">175138</span> <span class="o">|</span> <span class="n">empresarios</span> <span class="n">sa</span> <span class="o">|</span> <span class="n">PZA</span><span class="mf">.</span> <span class="n">MAYOR</span> <span class="o">|</span> <span class="n">Aviles</span> <span class="o">|</span> <span class="n">ASTURIAS</span> <span class="o">|</span> <span class="mf">0.450021</span>
<span class="mf">...</span>
</code></pre></div>
<h3>Índices con pg_rgm</h3>
<p>Aparte de los usos que acabamos de ver, se puede utilizar también <code>pg_trgm</code> para crear índices con los trigramas de las cadenas almacenadas en la tabla, de forma que podamos hacer búsquedas con el operador <code>LIKE</code> y sus comodines <code>%</code>, pero de forma mucho más eficiente que con éste.</p>
<p>Para crear uno de éstos índices, debe hacerse así:</p>
<div class="highlight"><pre><span></span><code><span class="k">CREATE</span> <span class="k">INDEX</span> <span class="n">idx_names</span> <span class="k">ON</span> <span class="n">table1</span> <span class="k">USING</span> <span class="n">GIN</span> <span class="p">(</span><span class="k">name</span> <span class="n">gin_trgm_ops</span><span class="p">);</span>
</code></pre></div>
<p>No obstante, y dado que el número de trigramas que forman las cadenas es grande (<em>véase el comienzo del artículo</em>), éstos índices tienden a crecer mucho cuanto más y más grandes sean las cadenas que almacenamos en la tabla donde definamos el índice, por lo tanto, aunque su uso es aconsejable si nos preocupa el rendimiento y utilizamos búsquedas de tipo <code>LIKE</code>, no debemos abusar de ellos si no queremos conseguir el efecto contrario y comprometer el rendimiento de nuestra base de datos.</p>
<p>Espero que os resulte tan útil e interesante como a mi!</p>
<p>Alaaaaaaaaaaaaaaaaaaaaaa</p>
<h2>Referencias</h2>
<ul>
<li><a href="http://www.postgresql.org/docs/9.3/static/pgtrgm.html">http://www.postgresql.org/docs/9.3/static/pgtrgm.html</a></li>
<li><a href="http://blog.2ndquadrant.com/indexando-ando-indices-gin">http://blog.2ndquadrant.com/indexando-ando-indices-gin</a></li>
</ul>Selección de plugins para Octopress2014-07-12T02:29:36+02:002014-07-12T02:29:36+02:00BhEaNtag:pornohardware.com,2014-07-12:/2014/07/12/seleccion-de-plugins-para-octopress/<p>Ya sea a modo de <em>chuleta</em> para mi mismo sobre los que utilizo en el blog, o bien por si a alguien le resulta útil, voy a escribir en éste artículo la lista de los mejores y más interesantes plugins para Octopress que he encontrado...</p>
<p>Ya sea a modo de <em>chuleta</em> para mi mismo sobre los que utilizo en el blog, o bien por si a alguien le resulta útil, voy a escribir en éste artículo la lista de los mejores y más interesantes plugins para Octopress que he encontrado...</p>
<h3>Tapir</h3>
<p>Tapir es un genial servicio web que se encarga de indexar el archivo RSS de nuestra web, y a través de su API, nos permite buscar en él. Está pensado para proveer de un buscador a aquellos sites estáticos (sin bases de datos o cualquier otro método de indexación para búsquedas) como por ejemplo los sites basados en Octopress, como éste.</p>
<p>Tiene un bug que impide su funcionamiento cuando los sites utilizan SSL (como en el caso de pornoHARDWARE.com), y aunque lo he reportado hace meses, ni me han contestado ni lo han corregido aún... así que si usais SSL en vuestro blog, mejor buscar otra alternativa para implementar las búsquedas estáticas.</p>
<p>Código fuente e instrucciones para su instalación en <a href="https://github.com/blimey85/octopress-tapir">éste repositorio de Github</a>.</p>
<h3>Image caption</h3>
<p>El comando <code>img</code> para mostrar imágenes en los artículos que trae Octopress por defecto es muy bueno, pero no permite demasiadas opciones... y una de las que más echaba de menos era la de poder poner algun tipo de texto o <em>pié de foto</em> en ellas.</p>
<p>Éste plugin implementa un nuevo comando (<code>imgcap</code>) que nos permite precisamente eso, mostrar una imagen con un texto a modo de explicación o título de la misma.
Código fuente e intrucciones para su instalación en <a href="http://blog.zerosharp.com/image-captions-for-octopress/">el Blog de Robert Anderson</a>.</p>
<h3>Emoji (emoticonos)</h3>
<p>Una de las prácticas más extendidas en las comunicaciones via SMS, email, Telegram, etc... son los conocidos <strong>emoticonos</strong>. Éstas <em>caritas</em> ayudan a expresar determinados sentimientos y aportan el toque necesario para entender el contexto emocional de una conversación (uno de los principales problemas de las conversaciones escritas).</p>
<p>Para implementar éstos emoticonos en nuestros artículos de Octopress solo teneis que instalar <a href="https://github.com/chriskempson/jekyll-emoji">éste plugin</a>.</p>
<h3>Appbox</h3>
<p>Éste plugin resulta de especial utilidad en aquellos blogs técnicos basados en Octopress en los que en algún artículo se habla de alguna <em>app</em> para smartphone, ya sea para <a href="https://www.apple.com/es/ios/">iOS</a> o <a href="http://www.android.com/">Android</a>.</p>
<p>Con él, podemos insertar de forma automática el nombre, icono, descripción, etc. de cualquier app con solo poner su ID.
Puede encontrarse en <a href="https://github.com/sotsy/appbox-octopress">éste repositorio de Github</a>.</p>
<h3>Octolayer y Mapbox</h3>
<p>Cualquiera de éstos 2 plugins nos permiten insertar mapas en los artículos de un blog de Octopress.</p>
<p>Con Octolayer, se utilizan los mapas de <a href="http://www.openstreetmap.org">Open Street Map</a>, mientras que con Mapbox utiliza (como su propio nombre indica) los mapas de <a href="https://www.mapbox.com/">Mapbox</a>.
El repositorio de <a href="http://mguentner.github.io/octolayer/">Octolayer se encuentra aqui</a> y el de <a href="https://github.com/tieubao/octopress-mapbox">Mapbox aquí</a>.</p>
<h3>Wikipedia</h3>
<p>Un plugin utilísimo para insertar cómodamente definiciones sobre cualquier tema que aparezca en la Wikipedia. Permite incluso elegir el idioma de la Wikipedia que queremos mostrar.</p>
<p>Forma parte de mi lista de <em>imprescindibles</em> desde el primer dia. Código fuente e instrucciones <a href="https://github.com/pferreir/octopress-wikipedia">en su repositorio de Github</a>.</p>
<h3>Calendar aside</h3>
<p>Éste plugin nunca me pareció especialmente útil, pero es bastante original, por lo que lo incluyo en ésta lista (aunque no creo que lo llegue a usar nunca).</p>
<p>Sirve para mostrar un calendario en la barra lateral del blog, remarcando los dias en los que se han escrito artículos. Podeis ver una demo en la web de su autor, <a href="https://www.neerajkumar.net/">Neeraj</a>, y descargar el código desde su <a href="https://github.com/neerajcse/octopress-calendar-aside">repositorio de Github</a>.</p>
<h3>Bootstrap image modal</h3>
<p>Imprescindible en cualquier web que se precie hoy en dia. Permite abrir ventanas modales (<em>layers</em>) con imágenes al pulsar sobre enlaces de texto o sobre los <a href="https://es.wikipedia.org/wiki/Thumbnail">thumbnails</a> de dichas imágenes.</p>
<p>Yo tuve problemas al implementarlo en mi blog, por lo que acabé haciéndo yo un plugin muy básico en HTML5 para eso mismo, pero si quereis probar suerte, el Código y las instrucciones <a href="https://github.com/rayfaddis/octopress-BootstrapModal">estan aquí</a>.</p>
<h3>Chuck Norris</h3>
<p>¿Qué se puede decir de éste plugin? Cualquier adjetivo resultaría insignificante para describirlo, por lo que al igual que Matrix, para entenderlo es mejor <a href="https://github.com/alestanis/octopress-chuck-norris">verlo con tus propios ojos</a>.</p>
<h3>Videos Lazzy Loading</h3>
<p>Éste plugin es muy util (lástima que sea solo para la <em><a href="https://www.youtube.com/">puta mierda de Youtube</a></em>) ya que nos permite no cargar el <code>iframe</code> de los videos que incrustemos en nuestros artículos hasta que el usuario haga <em>click</em> en ellos, evitando que se cargue en nuestra página el <a href="https://www.adobe.com/es/products/flashplayer.html">odioso Flash</a> incluso aunque no vayamos a reproducir el video.</p>
<p>Podeis <a href="https://github.com/erossignon/jekyll-youtube-lazyloading">descargarlo desde aquí</a>.</p>
<p>~~Prometo hacer uno igual para Vimeo en cuanto tenga tiempo (si es que no lo hay ya).~~
<strong>Edito para añadir</strong>: Tal y como os prometí, ya he terminado el plugin para disfrutar de ésta misma funcionalidad con los videos de <a href="https://vimeo.com">Vimeo</a>. Podeis verlo <a href="/2014/09/27/jekyll-vimeo-lazyloading-un-nuevo-plugin-para-mostrar-videos-de-vimeo-en-octopress">en éste artículo</a> que he escrito para explicarlo.</p>
<h3>Graphviz</h3>
<p>Con éste plugin podreis mostrar gráficas relacionales, mapas de red, etc. en vuestros blogs igual que lo haríais con la potentísima herramienta <a href="http://www.graphviz.org/">Graphviz</a> (de la cual hablo en detalle <a href="/2014/09/18/diagramas-mapas-de-red-y-demas-graficas-estructuradas-con-graphviz">en éste otro artículo</a>).</p>
<p>He encontrado 2 plugins diferentes para integrar Graphviz en Octopress. Cada uno tiene sus ventajas y sus inconvenientes, así que debeis elegir el que mejor se adapte a vuestras necesidades.</p>
<ul>
<li>El primer de ellos generar un objeto HTML5 a partir del código fuente de una gráfica (es decir, el navegador genera un SVG al interpretar el código). Util si no quereis tener que guardar físicamente en vuestro servidor web las imágenes de las gráficas, sino que preferís que se generen <em>on-demand</em> en el navegador del propio cliente. Podeis descargarlo de aqui: https://github.com/kui/octopress-graphviz</li>
<li>El segundo pregenera las imágenes con Graphviz, y las almacena en un directorio en el servidor. Al no ser el navegador quien las genera, sino el propio Graphviz, seguramente se puedan utilizar muchísimas más opciones que con el anterior plugin. Podeis descargarlo de aqui: http://www.idryman.org/blog/2012/04/04/jekyll-graphviz-plugin/</li>
</ul>
<h3>Obfuscate email</h3>
<p>Imprescindible si queréis evitar que la mayoría de los <a href="http://es.wikipedia.org/wiki/Bot">bots</a> recolectores de emails, <a href="http://es.wikipedia.org/wiki/Spam">spammers</a>, etc. capturen las direcciones de email que publiqueis en vuestros blogs y os suscriban a todos los <em>boletines de mierda</em> que se os ocurra...</p>
<p>No es 100% efectivo, ya que únicamente sustituye los carácteres que forman el email por sus correspondientes <a href="http://es.wikipedia.org/wiki/HTML#Entidades_HTML">entidades HTML</a> (lo que significa que el proceso puede hacerse también a la inversa, si el <em>bot</em> fuera lo suficientemente <em>listo</em>), pero para la inmensa mayoría de los casos funcionará perfectamente...</p>
<p>Podeis descargarlo desde su <a href="https://github.com/craigerm/email-obfuscate-octopress">repositorio en Github</a>.</p>
<h3>Reading time</h3>
<p>Uno de los plugins más sencillos pero más curiosos que he visto.
Calcula, segun el número de palabras de los artículos que escribamos en nuestro blog Octopress y según la media de lectura de palabras por minuto de una persona <em>media</em> (unas 180/200), el tiempo que se necesitará para leer el artículo.</p>
<p>Hay varios plugins que hacen ésto, pero por ahora el que más me gusta <a href="https://gist.github.com/zachleat/5792681">es éste</a>.</p>
<h3>Categories list and cloud</h3>
<p>Este plugin forma parte de los <em>clásicos</em> que deberían venir ya preinstalados <em>de serie</em> en Octopress (aunque se menciona en el <a href="https://github.com/imathis/octopress/wiki/3rd-party-plugins">listado <em>oficial</em> de plugins <em>3rd party</em> para Octopress</a>).</p>
<p>Permite generar una lista (o una <em>nube</em>) con las categorias de los artículos que tengamos en nuestro blog. Muy util para el menu lateral del blog, la página con el listado de categorías, etc.
Podeis descargarlo de su <a href="https://github.com/alswl/octopress-category-list">repositorio de Github</a>.</p>
<p>Iré ampliando el artículo a medida que vaya encontrando nuevos plugins que me parezcan interesantes. Si conoces alguno, por favor, indícalo en los <a href="#disqus_thread">comentarios</a> y le echaré un ojo! Gracias!</p>
<p>Alaaaaaaaaaaaaaaaaaaaaa</p>Un paseo por el datacenter en el que vivo2014-07-09T20:38:17+02:002014-07-09T20:38:17+02:00BhEaNtag:pornohardware.com,2014-07-09:/2014/07/09/un-paseo-por-el-datacenter-en-el-que-vivo/<p>Y no, no estoy hablando en sentido metafórico... hoy voy a enseñaros el <em>pequeño</em> <a href="https://es.wikipedia.org/wiki/Centro_de_procesamiento_de_datos">datacenter</a> que tengo montado en mi casa, donde <strike>mis servidores</strike> <em>mis niñas</em> funcionan sin interrupción para dar servicio tanto a mis <em>frikadas</em> como a algunas otras cosas un poco más serias.</p>
<p>Y cuando digo <em>datacenter</em> no me refiero a un par de ordenadores viejos sin monitor en una esquina del dormitorio, como teneis algunos (y vosotros os llamais <em>frikis</em>? <strong>debería daros vergüenza!</strong>), sino a varios racks con decenas de servidores, SAI's, cabinas de discos duros en RAID, switches redundantes y mil cosas más (como tenemos los <em>frikis</em> de verdad... así que tomar nota!!) xDD</p>
<p>Ha sido un proceso muy largo, y mentiría si dijera que ya ha terminado y que no voy a seguir <em>ampliando la infraestructura</em> de mi datacenter... pero a dia de hoy (mediados de 2014) puedo decir que (por suerte para mi y por desgracia para mi mujer) una de las habitaciones de mi casa tiene ésta pinta:</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_current.jpg"/></p>
<p>Y no, no estoy hablando en sentido metafórico... hoy voy a enseñaros el <em>pequeño</em> <a href="https://es.wikipedia.org/wiki/Centro_de_procesamiento_de_datos">datacenter</a> que tengo montado en mi casa, donde <strike>mis servidores</strike> <em>mis niñas</em> funcionan sin interrupción para dar servicio tanto a mis <em>frikadas</em> como a algunas otras cosas un poco más serias.</p>
<p>Y cuando digo <em>datacenter</em> no me refiero a un par de ordenadores viejos sin monitor en una esquina del dormitorio, como teneis algunos (y vosotros os llamais <em>frikis</em>? <strong>debería daros vergüenza!</strong>), sino a varios racks con decenas de servidores, SAI's, cabinas de discos duros en RAID, switches redundantes y mil cosas más (como tenemos los <em>frikis</em> de verdad... así que tomar nota!!) xDD</p>
<p>Ha sido un proceso muy largo, y mentiría si dijera que ya ha terminado y que no voy a seguir <em>ampliando la infraestructura</em> de mi datacenter... pero a dia de hoy (mediados de 2014) puedo decir que (por suerte para mi y por desgracia para mi mujer) una de las habitaciones de mi casa tiene ésta pinta:</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_current.jpg"></p>
<p>Para aquellos a los que (como a mi) os apasione el hardware, la informática, la tecnología y las máquinas en general, seguramente os parezca una habitación cojonuda... sin embargo los demás pensaréis (al igual que mi familia, mi mujer y la mayoría de mis amigos) que estoy loco y que se me ha ido de las manos, jejeje... así que si éste es vuestro caso, ¿qué <em>cojones</em> haceis en una web que se llama <em>pornoHARDWARE</em>??? Iros a descargar vuestras vergonzosas películas <em>screener</em> a otra parte, a actualizar vuestro estado en la mierda del <em>Feisbuk</em> o a reenviar <a href="https://es.wikipedia.org/wiki/Bulo">hoaxs</a> a vuestros amigos antes de que <em>Jon Henerd</em> os cierre <em>Hotmail</em> por no mandar el mensaje a 20 de vuestros contactos... lo siento, pero me temo que esta web no es para vosotros... ;)</p>
<p>A todos los demás, <strong>bienvenidos!</strong></p>
<h2>Indice</h2>
<p>Dado que éste post va a ser enoooorme, con muchísimas fotos y muchísimo texto, creo que no está de más un pequeño <em>índice</em> para facilitar la navegación:</p>
<ol>
<li><a href="#comienzo">El comienzo</a></li>
<li><a href="#primeracasa">Mi primera casa</a></li>
<li><a href="#primertraslado">El primer traslado</a></li>
<li><a href="#segundotraslado">El segundo traslado</a></li>
<li><a href="#trasladofinal">El traslado final</a><ul>
<li><a href="#capitulo1">Capítulo 1: Almacenamiento (compartido, local y en red</a></li>
<li><a href="#capitulo2">Capítulo 2: Servidores</a></li>
<li><a href="#capitulo3">Capítulo 3: Conectividad de las redes (ethernet y wifi)</a></li>
<li><a href="#capitulo4">Capítulo 4: SAIs, KVMs, ventilación y demás accesorios)</a></li>
</ul>
</li>
</ol>
<p>Y ahora, vamos <em>al lio</em>...</p>
<h2>El comienzo<a id="comienzo"></a></h2>
<p>Todo empezó hace muuuchos años, cuando aún vivía en casa de mis padres...</p>
<p>Hacía muy poco que teníamos Internet en casa... al principio una conexión con modem (a 56Kbps!) de esas que no solo costaban un <em>ojo de la cara</em>, sino que además te dejaban sin teléfono mientras estabas <em>conectado</em> (mucha gente <em>joven</em>, o al menos más joven que yo, alucina cuándo les cuentas ésto último xDDD).</p>
<p>Por aquel entonces yo era más que feliz con mi increible <a href="https://es.wikipedia.org/wiki/Pentium_III">Pentium III</a>, después de haber pasado por varios ordenadores hasta llegar a él.</p>
<p><img class="right" src="/images/posts/datacenter/datacenter_Amstrad_CPC_6128.png" title="Amstrad CPC 6128" alt="Amstrad CPC 6128">
Empecemos por el principio: mi primer contacto con la informática fué a raiz de los geniales (y más que educativos) <a href="https://es.wikipedia.org/wiki/Amstrad_CPC_464">Amstrad CPC 464</a> con monitor de <a href="https://es.wikipedia.org/wiki/Monitor_monocromo">fósforo verde</a>, el cuál me abrió las puertas a un mundo que me fascinó desde el primer momento (yo tendría unos 10 o 12 años en ese instante).</p>
<p>Al poco tiempo llegó el <a href="https://es.wikipedia.org/wiki/Amstrad_CPC_6128">Amstrad CPC 6128</a> (ya con monitor a color), con el que hice mis primeros programas en <a href="https://es.wikipedia.org/wiki/BASIC">BASIC</a> (el cual iba aprendiendo gracias a un libro que saqué de la biblioteca de mi colegio (si, todos cometemos errores... y yo lo reconozco: he estado en alguna biblioteca... espero que sepais perdonarme).</p>
<p>Pasé muchas horas <em>picando códigos</em> obtenidos de revistas de videojuegos y esperando paciéntemente a que se cargaran los programas almacenados en las lentísimas cintas de cassette del CP 464 y más tarde en los discos de 3" del CPC 6128. Ojalá tuviera cualquier de ellos en la actualidad...</p>
<p>Después vino mi primer PC, una auténtica maravilla de máquina... increíblemente veloz, potente y con un monton de cosas que no podía ni imaginar... y es que en aquel momento, tener un <a href="https://es.wikipedia.org/wiki/Intel_386">Intel 80386</a> eran palabras mayores!</p>
<p><img class="left" src="/images/posts/datacenter/datacenter_pentiumiii.jpg">
Mi primer Intel Pentium III</p>
<p>Pasé varios años con aquel increible 386... un <a href="http://www.olivetti.es/">Olivetti</a> que me dió innumerables horas de diversión. Y después llegó el <a href="https://es.wikipedia.org/wiki/Intel_80486">486</a>, y por fin aquel <a href="https://es.wikipedia.org/wiki/Pentium_III">Pentium III</a> que se convirtió en mi primer servidor..., y con él se desencadenó la locura...</p>
<p>Por aquel entonces yo programaba con algunos lenguajes de <em>Microsoft</em> <em>cuyo nombre no emplearé aquí</em>, y dado que comenzaba a montar algunas webs, decidí abrir aquel primer servidor a Internet y mantenerlo encendido las 24 horas...</p>
<p>Me costó muchas broncas con mi madre conseguir que no tirara del cable del enchufe cada vez que pasaba junto al servidor y veía que estaba encendido... y no puedo culparla! ¿Cómo iba mi madre a entender que aunque yo no estuviera delante, aunque el monitor estuviera apagado y no hubiera nadie junto a ese ordenador, algunas personas se conectaban a él diariamente y lo utilizaban?</p>
<p>Pero poco tiempo después ese servidor no fué suficiente, y tuve que hacerme con otro. No porque hubiera más tráfico y el servidor no tuviera recursos suficientes, sino porque mi atracción por la tecnología y los sistemas no había hecho más que empezar...</p>
<h2>Mi primera casa<a id="primeracasa"></a></h2>
<p>Durante varios años ocupé un pequeño rincón de la terraza cubierta de mis padres con mis 2 ordenadores... pero algunos años después (sobre 1999 o 2000) finalmente me independicé, y los siguientes 4 años estuve en un pequeño estudio en Hortaleza (Madrid)... lo que unido a mi descubrimiento de eBay y otras webs similares, dió lugar a que poco a poco se inundara la casi única habitación del estudio en el que vivía con todo tipo de hardware: SAIs, hubs, monitores, KVMs, más servidores, etc.</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_hortaleza_2.jpg">
<img class="center" src="/images/posts/datacenter/datacenter_hortaleza_5.jpg"></p>
<p>Y cuando ya casi no había espacio físico en mi casa para tantas máquinas, se me presentó la increible oportunidad de hacerme con un <a href="https://es.wikipedia.org/wiki/Rack">rack</a>! ¿os lo podeis imaginar? un rack en mi propia casa! Así que por supuesto (y en contra de lo que TODO el mundo me aconsejaba) me hice con él.</p>
<p>Un increible rack de <a href="https://es.wikipedia.org/wiki/Unidad_rack">42 U</a> de la (ahora extinguida) marca <a href="https://es.wikipedia.org/wiki/Compaq">Compaq</a>, con sus bandejas extraibles, sus guias pasacables, sus rejillas de ventilación, etc.</p>
<p>Pero el rack no vino solo. Junto a él llegaron cabinas de discos SCSI, servidores con 2 procesadores (algo que no se veía todos los dias por aquel entonces), robots de copia de seguridad en cintas DDS, etc... y después de muchas y muchas horas de lectura en Internet, configuraciones, controladoras SCSI, y mil cosas más, mi casa parecía una mezcla entre un viejo datacenter y un vertedero de chatarras bastante caras:</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_hortaleza_1.jpg">
Si, lo se... visto así parecía una pocilga... pero una vez ordenado no se estaba nada mal xDD</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_proliant.jpg"></p>
<p>Y tras mucho tiempo organizando y configurando todo, al final logré hacer un hueco para todo aquello en mi ya de por si reducido estudio:</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_hortaleza_3.jpg">
Mi primer Datacenter, en Hortaleza (Madrid), alrededor de 2004</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_hortaleza_4.jpg">
Nunca habías visto un salón tan chulo, eh?</p>
<p>Por aquel entonces, aparte de varias de mis webs personales, daba servicios de <a href="https://es.wikipedia.org/wiki/Internet_Message_Access_Protocol">IMAP</a> y <a href="https://es.wikipedia.org/wiki/Smtp">SMTP</a> a las empresas de algunos familiares. Tambien alojaba varios repositorios de código, servidores de desarrollo, etc... y todavía me sobraban servidores para enredar con nuevas tecnologías, probar cosas y aprender y aprender y aprender...</p>
<h2>El primer traslado<a id="primertraslado"></h2>
<p>Algunos años después dejé aquel estudio y me trasladé a otra casa un poco más <em>apañada</em>.
Era un duplex pequeño en Griñon, pero al menos había suficiente espacio como para poder dedicar una habitación entera a mi pequeño datacenter.</p>
<p>Fué una odisea aquella mudanza, y no solo por la cantidad de cosas y el tiempo que estuvieron los servidores <em>offline</em> (el cual únicamente fué de unas horas, después de muchas gestiones en paralelo para dar de alta la ADSL en la nueva casa, el transporte de los servidores y el rack, la replicación de la nueva IP en los <a href="https://es.wikipedia.org/wiki/Dns">DNS</a>s, etc), sino porque al ser un duplex y estar las habitaciones en la planta de arriba, hubo que subirlo todo a mano por las escaleras... y fué horrible.</p>
<p>Pero el resultado mereció la pena, y durante unos cuantos años más pude disfrutar de un Datacenter en mi propia casa no solo con todo lo necesario para seguir dando el mismo servicio de siempre, sino que durante ese tiempo fuí ampliando todo el hardware que pude, mejorando el rack hasta el punto de necesitar otro más (el cual conseguí a muy buen precio)... e incluso un pequeño rack mural para las comunicaciones (switches, patch panels, etc).</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_grinon_1.jpg">
Mi segundo Datacenter, en Griñon (Madrid), alrededor de 2008</p>
<h2>Segundo traslado<a id="segundotraslado"></a></h2>
<p>Aproximadamente en 2010 dejé aquel duplex y me mudé a una casa gigante en Illescas... y digo una casa gigante porque una de sus habitaciones (que además estaba en un sótano muy luminoso) medía cerca de 50m<sup>2</sup> (creo que era la habitación más grande de la casa), y nada más verla supe que sería el Datacenter perfecto... incluso antes de ver el resto de la casa, solo con ver aquella habitación e imaginarme lo que podía montar allí, ya estaba convencido a mudarme...</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_illescas_1.jpg">
<img class="center" src="/images/posts/datacenter/datacenter_illescas_2.jpg">
Mi tercer Datacenter, en Illescas (Toledo), alrededor de 2010</p>
<p>Tremenda habitación, verdad?
Espacio de sobra para todos mis servidores, para mi mesa de trabajo, una segunda mesa adicional, la pizarra gigante para el <a href="https://es.wikipedia.org/wiki/Programaci%C3%B3n_extrema">XP</a> (me refiero a la <a href="https://es.wikipedia.org/wiki/Desarrollo_%C3%A1gil_de_software">metodología de desarrollo ágil</a>, no el <a href="https://es.wikipedia.org/wiki/Windows_XP">sistema inoperativo</a> de <em>Microsoft</em>, idiota!), y después de todo aquello aún seguía sobrando espacio...</p>
<p>Y dado que la Naturaleza aborrece el vacio, quien soy yo para contradecirla?
Por lo tanto, y en vista que mi infraestructura no paraba de crecer y sin embargo había espacio de sobra, finalmente me hice con mi tercer rack... otra unidad exactamente igual que la primera (porque puestos a hacer las cosas bien, hagámoslas simétricas, no?)</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_illescas_3.jpg">
Una habitación normal y corriente, verdad?</p>
<p>3 racks completos alojando 3 cabinas Compaq de 14 discos duros SCSI cada una, 1 servidor HP Proliant con 2 procesadores, 4 switches de 24 puertos cada uno, 1 KVM switch para 16 equipos, 2 robots de copia de seguridad en cintas DDS, 1 SAI de 19", 1 NAS en RAID5 de 5 TB, 6 servidores en formato rack, y a saber qué más...</p>
<p>Pero no... este datacenter tampoco fué mi datacenter definitivo, ya que un par de años después por fin mi mujer y yo encontramos la casa <em>definitiva</em>, y allí es donde vivimos actualmente (aunque por suerte ella no sabe todo lo que hay en esa habitación en la que me paso gran parte del tiempo, jejeje).</p>
<h2>El traslado final<a id="trasladofinal"></a></h2>
<p>Año 2012, en Seseña (Toledo). Compramos un chalet con todo lo que siempre habíamos querido, y aunque el datacenter iba a contar con un espacio mucho más pequeño que el que tenía en la casa anterior por cómo estaban distribuidas las habitaciones, el hecho de tener al fin una casa en propiedad (hasta ahora siempre había ido de alquiler en alquiler) hizo que inconscientemente fuera poco a poco deshaciendome de aquel hardware obsoleto y que no iba a usar nunca más, y fuera renovándolo y quedándome únicamente con los servidores y las máquinas <em>pata negra</em>.</p>
<p>La meta era quedarse únicamente con 1 de los 3 racks... y casi 1 año después lo conseguí.
Fuí vendiendo y vendiendo cosas, y con el dinero obtenido iba comprando hardware más potente y más actual, hasta llegar a la <em>infraestructura</em> de la que dispongo ahora mismo.</p>
<p>Vamos a entrar un poco más en detalle...</p>
<h3>Capítulo 1: Almacenamiento (compartido, local y en red)<a id="capitulo1"></a></h3>
<p>Para satisfacer mis necesidades de almacenamiento, y después de haber aprendido por las malas (hace ya muchos años) que "<em>TARDE O TEMPRANO </em><em>TODOS LOS DISCOS DUROS MUEREN</em><em>©</em>" tenía muy claro desde el principio que TODOS mis servidores debían disponer de redundancia en sus discos, ya fuera <a href="http://es.wikipedia.org/wiki/RAID#RAID_1_.28Mirroring.29">RAID 1</a> o <a href="http://es.wikipedia.org/wiki/RAID#RAID_5">RAID 5</a> (dependiendo del número de discos disponibles en cada caso). da igual para qué se vaya a destinar el servidor, tiene que poder sobrevivir a un fallo de disco sin perder ni un <em>bit</em> de información.</p>
<p>Y aunque sea <em>"entre comillas"</em>, estamos hablando de un entorno de <em>producción</em> al fin y al cabo, así que aquí no sirven los lentísimos (aunque baratos) discos <a href="http://es.wikipedia.org/wiki/Sata">SATA</a> que teneis la mayoría de los humanos en vuestros ordenadores.</p>
<p>Aquí hacen falta discos <a href="http://es.wikipedia.org/wiki/Scsi">UltraSCSI</a>, <a href="http://es.wikipedia.org/wiki/Fibre_channel">FibreChannel</a> o <a href="http://es.wikipedia.org/wiki/Serial_Attached_SCSI">SAS</a>. Y si puede ser en cabinas de 19" para nuestro rack, mucho mejor! xDD</p>
<p>Pero como las que yo tenía por aquel entonces eran ya muuuy viejas, ruidosas y con un espacio de almacenamiento taaaaaaan limitado, tuve que <em>jubilarlas</em> para dejar sitio a nuevas generaciones...</p>
<p>{% imgcap center /images/posts/datacenter/datacenter_diskarray_old.jpg Mis antiguos arrays de discos SCSI %}</p>
<p>Me deshice de mis 2 preciados arrays <em>Compaq</em> de 14 discos SCSI de 3,6GB cada uno (que tantísimo tiempo me había costado conseguir), y en su lugar monté no 1 sino 5 arrays más! (los cuales conseguí a un precio <em>de risa</em>, prácticamente comprados <em>al peso</em> como si fuera chatarra).</p>
<ul>
<li>1 x IBM Exp Plus de 14 discos <a href="http://es.wikipedia.org/wiki/Scsi">UltraSCSI</a> (U160) de 73,4GB cada uno</li>
<li>1 x EMC array de 15 discos <a href="http://es.wikipedia.org/wiki/Fibre_channel">FibreChannel</a> de 146GB cada uno</li>
<li>3 x HP StorageWorks de 14 discos <a href="http://es.wikipedia.org/wiki/Scsi">UltraSCSI</a> (U320) de 36,4GB cada uno</li>
</ul>
<p>En total, una vez construidos los RAIDs, disponemos de más de 4TB de almacenamiento compartido, a muy alta velocidad y con fuentes de alimentación redundantes (2 fuentes cada cabina).</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_diskarray_hp_emc.jpg">
Arrays de discos HP y EMC</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_diskarray_hp_emc_back.jpg">
Fuentes de alimentación redundantes de los arrays de HP y EMC</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_diskarray_ibm.jpg">
Array de discos IBM</p>
<p>Con esos arrays de discos para almacenamiento compartido y los discos locales instalados en cada uno de los servidores (éstos últimos siempre en <a href="http://es.wikipedia.org/wiki/RAID">RAID</a> también) ya tenía resuelto el problema del almacenamiento para las necesidades del Datacenter... ¿pero qué hay de las necesidades del almacenamiento multimedia (películas, series, música, etc) para la red de mi casa?</p>
<p>No me parecía buena idea mezclar ésto con los datos de los servidores, por lo que para todas éstas cosas que considero <em>ocio</em> y que deben ser accesibles (a través de la red de mi casa) desde todos los reproductores que hay en ella (televisores, consolas, etc) utilizo mi querida <a href="http://es.wikipedia.org/wiki/Network-attached_storage">NAS</a> de <a href="http://www.allnet.de/es/">Allnet ALL6600</a> de 10TB, la cual consta de 5 discos SATA de 2TB cada uno configurados en <a href="http://es.wikipedia.org/wiki/RAID#RAID_5">RAID 5</a>, y que mediante <a href="http://es.wikipedia.org/wiki/NFS">NFS</a> y <a href="http://es.wikipedia.org/wiki/Samba_%28programa%29">SAMBA</a> ofrece mi colección de películas, series, música, fotografías, etc. a cualquier parte de mi casa (le dedicaré un artículo en exclusiva a ésta NAS en cuanto pueda, porque de verdad que lo merece).</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_nas.jpg">
Mi NAS de 10TB de almacenamiento RAID (y os juro que <em>no todo es porno</em>!)</p>
<h3>Capítulo 2: Servidores<a id="capitulo2"></a></h3>
<p>Tanto rack y tanto almacenamiento no sirve de nada por si solo. Únicamente tiene sentido si hay buenos servidores que los utilicen... y en éste caso sí que los hay.</p>
<p>Al principio (en mis <em>primeros datacenters</em> xDDD) llamaba <em>servidor</em> a cualquier ordenador normal y corriente que permanecía conectado las 24 horas del dia...</p>
<p>Primero los usaba tal cual, en sus <em>torres</em> o <em>semitorres</em>, puestos de pié uno al lado del otro bajo mi mesa... pero luego, con la llegada del primer rack, compré cajas en formato rack de 19" vacías y <em>transplanté</em> todos aquellos ordenadores a ellas para poder montarlos en el rack.</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_server_boxes_1.jpg"></p>
<p><img class="center" src="/images/posts/datacenter/datacenter_server_boxes_2.jpg"></p>
<p><em>Daban el pego</em>, la verdad. Y no funcionaban del todo mal... pero aunque parecían servidores, al fin y al cabo eran ordenadores normales y corrientes, y pronto vi que ni sus discos duros ni su refrigeración ni ninguno de sus componentes estaban diseñados para <em>prestar servicio</em> 24 horas al dia y 7 dias por semana.</p>
<p>Por ese motivo, cuando un dia encontré a través de <a href="http://www.ebay.com">eBay</a> un lote de modestos servidores <em>de verdad</em> en formato 19" para rack y a un precio muy bajo (debido a que incluso en aquel momento estaban completamente obsoletos ya xDDD) no me lo pensé y compré 3 unidades que si no recuerdo mal, me costaron 100 € cada uno (hace muuuuchos años ya).</p>
<p>Eran auténticas relíquias... sin fuentes de alimentación redundantes, con procesadores <a href="http://es.wikipedia.org/wiki/Intel_Xeon">Intel Xeon</a>, 2GB de <a href="http://es.wikipedia.org/wiki/Ram">RAM</a> y 2 discos duros <a href="http://es.wikipedia.org/wiki/Integrated_Drive_Electronics">IDE </a> (si, si... habeis oido bien: <strong>discos duros IDE!!</strong>) de 80GB cada uno (si no recuerdo mal)... pero para mi eran taaaaaan bonitos!</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_old_servers.jpg">
Mis primeros servidores "de verdad"</p>
<p>No hay que ser ningún experto en hardware para saber que cualquier teléfono de hoy en dia es bastante más potente que estos servidores... pero aun así, me dieron muy buen servicio durante muchos años.</p>
<p>Uno de ellos era el servidor de correo (<a href="http://es.wikipedia.org/wiki/Imap">IMAP</a> y <a href="http://es.wikipedia.org/wiki/Smtp">SMTP</a>), otro era el servidor de base de datos (<a href="http://www.mysql.com/">MySQL</a> al principio, y luego también <a href="http://www.postgresql.org/">PostgreSQL</a>) y el otro se encargaba de servir las webs (<a href="http://www.apache.org/">Apache</a>).</p>
<p>Pero ahora, después de tantos años, ya no estaban a la altura de las necesidades del <em>datacenter</em>, por lo que también tuve que jubilarlos y modernizar todos los servidores.</p>
<p>En ese momento, como si <a href="http://en.wikipedia.org/wiki/Lords_of_Kobol">los Dioses</a> me estuvieran enviando una señal, encontré un sitio donde vendían <em>servidores obsoletos de algunos datacenters muy importantes de Holanda</em> (segun me dijeron esos <em>vendedores</em>). Se vendían prácticamente como si fueran chatarra... como si fueran <em>servidores al peso</em>... y claro, se desató la locura... xDDD</p>
<p>No se si dicha procedencia sería verdad o no, pero al cabo de pocos meses me había hecho con decenas y decenas de máquinas de auténtico <em>pornohardware</em>, valoradas en <strong>cientos de miles de euros</strong>, y todo literalmente <em>por unos pocos cientos</em>!!</p>
<p>Muchos de ellos a su vez los vendí de nuevo, ganándoles un buen dinero a cada uno de ellos, lo que me permitió que todos aquellos que yo me quedé para mi uso personal me acabaron salieron prácticamente gratis.</p>
<p>Gracias a éstas operaciones de compra/venta no solo jubilé prácticamente todo el hardware que tenía en aquel momento, sino que además los reemplacé con servidores del <em>copón bendito</em>!</p>
<p>Pasaron muchos servidores por mi datacenter en aquellos meses, por lo que no voy a hablaros de todos ellos... pero hay algunos que sí que merecen una mención especial, como por ejemplo los <a href="https://support.hpe.com/hpesc/public/docDisplay?docId=emr_na-c00244802">HP Proliant DL380 G4</a>, los cuales no llegué a utilizar en mi datacenter porque los vendí bastante rápido.</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_server_hpdl380g4.jpg">
HP Proliant DL380 G4</p>
<p>También me hice con algunos <a href="http://www.dell.es/">Dell</a> (concretamente 3 <a href="http://www.dell.com/downloads/emea/products/pedge/es/PE2850_es.pdf">PowerEdge 2850</a> y 1 <a href="http://www.dell.com/downloads/emea/products/pedge/es/PE2950_Spec_Sheet_Quad.pdf">PowerEdge 2950</a>), pero nunca me ha gustado el hardware de Dell... por lo que los vendí tan pronto estuvieron a punto.</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_server_dellpoweredge.jpg">
Dell PowerEdge 2850 y PowerEdge 2950</p>
<p>Y otros 3 <a href="https://www.istoragenetworks.com/landings/HP_Servers/DL585G1.php">HP Proliant DL585 G1</a> un poco más antiguos que los demás, pero con 4 procesadores <a href="http://es.wikipedia.org/wiki/AMD_Opteron">AMD Opteron</a> (que no solo de <a href="http://es.wikipedia.org/wiki/Intel_Corporation">Intel</a> vive el hombre)... aunque los vendí poco después porque eran poco potentes para su tamaño (<a href="https://es.wikipedia.org/wiki/Unidad_rack">4 U</a> cada uno).</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_hpdl585.jpg">
HP Proliant DL585 G1</p>
<p>Pero de entre todos estos servidores, los que más me gustaban eran los maravillosos <a href="http://www8.hp.com/h20195/v2/getDocument.aspx?docname=c04286057">HP Proliant DL380 G5</a>, que fueron los primeros que compré.</p>
<p>Me hice con 4 de ellos, junto con un <em>lote</em> de 16 discos duros <a href="http://es.wikipedia.org/wiki/Serial_Attached_SCSI">SAS</a> de 73,4GB, aparte de los 2 que ya traía cada uno.</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_server_hpdl380g5_1.jpg">
HP Proliant DL380 G5</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_server_hpdl380g5_2.jpg">
16 discos duros "extra" dan para bastante...</p>
<p>Me encantaban estos servidores. Tanto, que fueron los que decidí quedarme para migrar mis pobres y obsoletos servidores-relíquia, y durante mucho tiempo fueron los que estuvieron sirviendo todos los servicios que tenía en mi datacenter.</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_sesena_rack_1.jpg"></p>
<p>Los servidores seguían llegando, por lo que al poco tiempo tuve que cambiar el rack (que por aquel entonces ya solo tenía 1) por otro un poco más grande. Así que tuve que mover y reorganizar todo el cableado de nuevo.</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_sesena_rack_2.jpg"></p>
<p>Por aquel entonces todo funcionaba a las mil maravillas.</p>
<p>Las poquitas empresas familiares que alojaban aquí sus páginas webs, su correo corporativo, etc. estaban muy contentas con <em>el servicio</em>, y Yo me divertia como nunca configurando y manteniendo mi propio <em>datacenter casero</em>... pero entonces apareció un problema con el cuál nunca pensé que iba a tener que lidiar: la factura de la luz.</p>
<p>Desde que me independicé de casa de mis padres y empecé a pagar mi propia factura de la luz (allá por 1999 o 2000), siempre tuve una factura <em>un pelín</em> más alta de lo normal (comparándola con amigos o compañeros de trabajo) pero jamás fué algo desorbitado ni preocupante. Mi factura tenía tan solo <em>unos euros</em> más de lo normal, y era lógico, puesto que yo tenía <em>algunos servidores más de lo normal</em> (xDDDD). De hecho, tenía el 100% más de servidores que mis amigos y compañeros de trabajo, jejejeje... aunque insisto en que en aquellos tiempos <em>ni siquiera notaba</em> un incremento en la factura de la luz.</p>
<p>Pero poco a poco, año tras año, el precio de la luz iba subiendo más y más (muchas gracias, <em>malditas Compañias Eléctricas de los cojones</em>!) y cuantos más servidores incorporaba a mi datacenter, mi consumo eléctrico subía también más y más... hasta que al cabo de los años, se hizo insostenible, por lo que me dispuse a reducir drásticamente el consumo eléctrico del datacenter. Y para ello, y gracias al proyecto <a href="https://openenergymonitor.org">Open Energy Monitor</a> (el cual os recomiendo encarecidamente, y prometo escribir un artículo sobre él en cuanto pueda) me puse a monitorizar el consume eléctrico de mi casa en tiempo real.</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_openenergymonitor.jpg">
Monitor inalámbrico del consumo eléctrico de mi casa en tiempo real</p>
<p>Como es imposible hacer que un servidor consuma menos electricidad (sin <em>recortar</em> su rendimiento, quiero decir), lo que tenía que hacer era reducir el número de servidores que estaban encendidos siempre.</p>
<p>Pero como todo <em>sysadmin</em> sabe (o debería), no es buena idea <em>concentrar</em> varios servicios diferentes en un mismo servidor (hay mil razones para ésto, no voy a explicarlas aquí)... por lo que meter todos los servicios en únicamente 1 o 2 servidores era algo que el Kharma no me iba a permitir hacer, por lo que después de muchas vueltas al fin encontré la solución: migrar los servidores físicos a <strong>servidores virtuales</strong>.</p>
<p><img class="right" src="/images/logos/logo_citrix_xenserver.png"></p>
<p>De esa forma, con únicamente 1 servidor físico <em>potente</em>, podía dar vida a muchos servidores virtuales... así que vendí mis queridos <a href="http://www8.hp.com/h20195/v2/getDocument.aspx?docname=c04286057">HP Proliant DL380 G5</a> y me hice con un par de <a href="http://www-07.ibm.com/systems/includes/content/x/hardware/enterprise/x3850m2/pdf/xso03033usen.pdf">IBM x3950 M2</a> (que por si no lo he dicho antes, IBM es la marca de hardware que más me gusta de vuestro mundo) con 32GB de RAM, 4 procesadores, etc. Por lo que después de muchas configuraciones con el genial <a href="http://www.citrix.com/products/xenserver/overview.html">Citrix XenServer</a> y varias <em>re-estructuraciones</em> físicas en el rack, por fin conseguí replicar toda la infraestructura que tenía antes únicamente con 1 servidor físico y 1 cabina de discos.</p>
<p>El consumo de 1 servidor y 1 cabina de discos sigue siendo un tanto elevado, pero es asumible, así que ésta configuración es la que tengo actualmente para alojar los 5 servidores virtuales que utilizo.</p>
<p>Pero como cualquier avispado amante del <em>pornohardware</em> debería haber notado nada más leer estos últimos párrafos, ésta configuración no cumple los requisitos de la <a href="http://es.wikipedia.org/wiki/Alta_disponibilidad">Alta Disponibilidad</a>, ya que no es tolerante a fallos puesto que si el servidor físico llegara a fallar, todo el sistema (los 5 servidore virtuales) fallaría.</p>
<p>Para evitar ésto, ambos <a href="http://www-07.ibm.com/systems/includes/content/x/hardware/enterprise/x3850m2/pdf/xso03033usen.pdf">IBM x3950 M2</a> estarán configurados en <a href="http://es.wikipedia.org/wiki/Cl%C3%BAster_de_alta_disponibilidad">clúster de alta disponibilidad</a>, de forma que si alguno de ellos llegara a fallar, el otro asumiría el "control" del sistema (<em>aunque a dia de hoy, agosto de 2014, aún no tengo terminada ésta configuración... únicamente uno de los dos IBM esta funcionando ahora mismo</em>).</p>
<p>Otro de los motivos por los que ésta configuración en clúster no está terminada aún es que todavía no he decidido si utilizar éstos 2 servidores IBM, o por el contrario (si el consumo eléctrico en comparación no es elevado, cosa que aún dudo) utilizar la mejor de todas las máquinas que poseo: <strong>el increible <a href="http://bladecenter.lenovofiles.com/help/index.jsp?topic=%2Fcom.lenovo.bladecenter.8677.doc%2Fbc_8677_product_page.html">IBM BladeCenter E</a></strong>.</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_bladecenter_front.jpg"></p>
<p>Éste increible monstruo es sencillamente acojonante, y aunque solo voy a comentarlo un poco por encima, merecería un artículo entero hablando únicamente sobre él (no descarto escribirlo algún dia).</p>
<p>Los <a href="http://es.wikipedia.org/wiki/Servidor_blade">servidores Blade</a> son servidores especialmente pensados para los Datacenters, donde hay que optimizar al máximo el espacio físico que ocupan los servidores en los racks, el consumo eléctrico, la administración de los mismos, etc.</p>
<p>Son como servidores normales y corrientes, pero en forma de "placas" o "tarjetas" que se insertan todos ellos en un chasis o <em>bastidor</em>, que se encarga de proveerlos de electricidad, red, etc...
El chasis es el que dispone de las <a href="http://es.wikipedia.org/wiki/Sistema_redundante#Fuentes_de_alimentaci.C3.B3n">fuentes de alimentación redundantes</a>, la conectividad de red, el acceso a cabinas externas de discos, los módulos de administración, <a href="http://www.digitalika.com/2010/07/kvm-switch-definicin-de-hoy/">KVM's</a>, etc. de forma que los servidores Blade pueden ser mucho más pequeños al no tener que incorporar ninguno de éstos elementos.</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_bladecenter_03.jpg"></p>
<p><img class="center" src="/images/posts/datacenter/datacenter_bladecenter_04.jpg"></p>
<p>Pues bien, mi BladeCenter está formado por el chasis (modelo E), que a su vez incluye:</p>
<ul>
<li>4 fuentes de alimentación de 2000W cada una</li>
<li>2 módulos de administración remota</li>
<li>2 switches de red Cisco de 20 puertos</li>
<li>2 Pass Thru óptico de 4 puertos</li>
<li>Lector DVD</li>
<li>Puerto USB</li>
<li>Switch KVM</li>
</ul>
<p>En esta imagen de la parte trasera se pueden ver todos esos componentes, los cuales son modulares y <a href="http://es.wikipedia.org/wiki/Hot_swap">hot-swap</a> (obviamente) para poder sustituirlos en caso necesario sin tener que interrumpir el servicio:</p>
<p><img class="right" src="/images/posts/datacenter/datacenter_bladecenter_back.jpg">
Esto es un culo, y no el de Jennifer López... xDDD</p>
<p>Pero el chasis por si solo no sirve de mucho sin los <a href="http://es.wikipedia.org/wiki/Servidor_blade">blades</a>, los cuales se insertan por delante (<a href="http://es.wikipedia.org/wiki/Hot_swap">hot-swap</a> también, por supuesto) y permiten disponer de hasta 14 servidores.</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_bladecenter_hs20_2.jpg">
Los 12 servidores IBM Blade HS20</p>
<p>En mi caso en lugar de 14 servidores solo tengo 12, ya que 2 de ellos ocupan el doble de espacio porque llevan un añadido para poder conectarles 2 discos duros de 3,5" a cada uno. Los 12 pertenecen al modelo <a href="http://publib.boulder.ibm.com/infocenter/bladectr/documentation/index.jsp?topic=/com.ibm.bladecenter.hs20.doc/bls_hs20_product_page.html">IBM Blade HS20</a>, y sus configuraciones son:</p>
<ul>
<li><strong>Servidor 01</strong>: 2 x Xeon 3.2 GHz, 8GB RAM, 2 x HDD 73GB 10.000 RPM</li>
<li><strong>Servidor 02</strong>: 2 x Xeon 3.4 GHZ, 5GB RAM, 2 x HDD 73GB 10.000 RPM</li>
<li><strong>Servidor 03</strong>: 2 x Xeon 3.4 GHZ, 8GB RAM, 2 x HDD 73GB 10.000 RPM</li>
<li><strong>Servidor 04</strong>: 2 x Xeon 3.4 GHZ, 5GB RAM, 2 x HDD 73GB 10.000 RPM</li>
<li><strong>Servidor 05</strong>: 2 x Xeon 3.4 GHZ, 8GB RAM, 2 x HDD 73GB 10.000 RPM</li>
<li><strong>Servidor 06</strong>: 2 x Xeon 3.2 GHZ, 8GB RAM, 2 x HDD 73GB 10.000 RPM</li>
<li><strong>Servidor 07</strong>: 2 x Xeon 3.4 GHZ, 5GB RAM, 2 x HDD 73GB 10.000 RPM</li>
<li><strong>Servidor 08</strong>: 2 x Xeon 3.4 GHZ, 8GB RAM, 2 x HDD 73GB 10.000 RPM</li>
<li><strong>Servidor 09</strong>: 2 x Xeon 3.4 GHZ, 8GB RAM, 2 x HDD 73GB 10.000 RPM</li>
<li><strong>Servidor 10</strong>: 2 x Xeon 3.4 GHZ, 8GB RAM, 2 x HDD 73GB 10.000 RPM</li>
<li><strong>Servidor 11</strong>: 2 x Xeon 3.2 GHZ, 4GB RAM, 2 x HDD 73GB 10.000 RPM</li>
<li><strong>Servidor 12</strong>: 2 x Xeon 3.2 GHZ, 4GB RAM, 2 x HDD 73GB 10.000 RPM</li>
</ul>
<p>De ésta forma se consigue que en un espacio de tan solo <a href="https://es.wikipedia.org/wiki/Unidad_rack">7 U</a> se puedan tener 12 servidores.
Y si después de leer eso no estais <em>cachondos</em>, yo ya no os entiendo, en serio!</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_bladecenter_hs20_open.jpg">
El interior de uno de los IBM Blade HS20</p>
<p>Eso si, los Blades son increibles, molan muchísimo, son mucho más eficientes... pero jooooder con el ruido que hacen!!! Más os vale tener un sueño profundo si alguno tiene uno de éstos cerca (vale... ya lo se... eso es bastante improbable, pero no se me ocurría ninguna otra forma de terminar esa frase).</p>
<p>Para aquellos pocos de vosotros que aún no acepten mi palabra como Verdad Universal (ya lo hareis tarde o temprano), os subo éste video al genial <a href="http://www.vimeo.com">Vimeo</a> (no a la mierda de Youtube, obviamente) para que lo podais comprobar vosotros mismos. Está en HD y con audio para que oigais el estruendo que hace al arrancar... y si, luego se calma bastante, pero al principio es terrible!</p>
<p><span class="videobox">
<iframe
src="//player.vimeo.com/video/106336883?title=0&byline=0&portrait=0"
width="640" height="390" frameborder="0"
webkitAllowFullScreen mozallowfullscreen allowFullScreen>
</iframe>
</span></p>
<p>Y con ésto creo que puedo concluir (por ahora xDD) la descripción de mis servidores...</p>
<p>El rack (a dia de hoy) ha quedado de ésta forma:</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_rack_2014.jpg"></p>
<p>Pero para que todo ésto funcione hacen falta muchos otros elementos, así que vamos a seguir con la <em>visita guiada por mi datacenter</em> viendo el resto de máquinas...</p>
<h3>Capítulo 3: Conectividad de las redes (ethernet y wifi)<a id="capitulo3"></a></h3>
<p>No creo que haya casi nadie hoy en dia que no tenga una red local en su casa. Ya sea para conectar un par de ordenadores o para acceder a Internet desde el movil, pero de una forma u otra casi todo el que tiene una conexión a Internet en su casa tiene una red local montada.</p>
<p>En mi caso tengo 4, todas independientes y con hardware dedicado físicamente para cada una de ellas, y todas con distintas finalidades:</p>
<ul>
<li>Red local <em>normal</em>: Por donde mis ordenadores, móviles, etc. acceden a Internet tanto de forma inalámbrica (<a href="http://es.wikipedia.org/wiki/Wi-Fi">Wifi</a>) como cableada (<a href="http://es.wikipedia.org/wiki/Ethernet">Ethernet</a>).</li>
<li>Red privada para servidores: La red que conecta los servidores entre si, la cual no es accesible desde la red <em>normal</em>.</li>
<li>Red privada de administración: Aquí es donde se conectan los interfaces de administración remota <a href="http://es.wikipedia.org/wiki/Integrated_Lights-Out">iLO</a> de los servidores HP, los <a href="http://en.wikipedia.org/wiki/IBM_Remote_Supervisor_Adapter">RSA</a> de IBM o los <a href="http://en.wikipedia.org/wiki/Dell_DRAC">DRAC</a> de Dell para su administración en caso de problemas en la red principal.</li>
<li>Red privada del sistema de alarma: Éste proyecto aún está en desarrollo, pero básicamente consiste en un sistema de alarma para mi casa con multitud de sensores, cámaras, y mil cosas más (y que por cuestiones obvias de seguridad se encuentra en una red independiente e inaccesible desde las demás). Algún dia hablaré de éste proyecto (con el que llevo años, jejeje) más detenidamente...</li>
</ul>
<p>Todas las redes utilizan <a href="http://es.wikipedia.org/wiki/Conmutador_%28dispositivo_de_red%29">switches</a> (no creo que quede nadie en el mundo usando <a href="http://es.wikipedia.org/wiki/Concentrador">hubs</a> para interconectar redes, o al menos eso espero xDD).</p>
<p>Aunque no es necesario, ya que algunas de mis redes no necesitan esa velocidad, todos los switches que utilizo son <em>10/100/1000</em> (salvo un viejo <a href="http://es.wikipedia.org/wiki/3Com">3COM</a> que uso para la red de administración, que es <em>10/100</em>). Eso significa que todos pueden funcionar a una velocidad de transmisión de 1000 Mbit/s.</p>
<p>Tengo un par de switches <em>normales</em> (pero que funcionan MUY bien) para los <em>equipos de escritorio</em> (mi ordenador personal, el router de Internet, el punto de acceso inalámbrico, etc) y otros en forma rack (19") instalados en el rack que comenté anteriormente, y en otro pequeño rack de <a href="https://es.wikipedia.org/wiki/Unidad_rack">6 U</a> destinado únicamente a <em>comunicaciones</em> que tengo también montado y del que hablaré después, ya que es una parte fundamental en la infraestructura de mi Datacenter casero.</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_switches_rack.jpg">
Switch Linksys principal, switch Linksys para servidores y switch 3COM para adminitración remota</p>
<p>Con éstos 3 switches (que se encuentran en el rack principal) se conectan la inmensa mayoría de servidores y dispositivos de mi datacenter, incluyendo los móviles de mi familia para su conexión a Internet, las televisiones y los reproductores multimedia para su conexión con la NAS de 10TB que <a href="#capitulo1">comenté en el capítulo sobre el almacenamiento</a> (y que contiene toda mi filmoteca/audioteca/fototeca), los servidores, etc.</p>
<p>Aparte de éstos switches, tengo otro en mi escritorio para conectar mi ordenador personal, el router de la ADSL, un par de <a href="http://www.raspberrypi.org/">Raspberrys PI</a> que uso para <em>cacharrear</em>, etc.</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_switch_escritorio.jpg">
Switch de escritorio, lector de DNIe, router ADSL y controlador de audio</p>
<p>Y por último, otro switch más en el pequeño rack de comunicaciones, que conecta el punto de acceso Wifi, otra <a href="http://www.raspberrypi.org/">Raspberry PI</a> con la que monitorizo el consumo eléctrico de mi casa mediante el proyecto <a href="https://openenergymonitor.org">Open Energy Monitor</a> del que os hablé antes, etc.</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_minirack_01.jpg">
El pequeño rack de comunicaciones al que llegan todas las estancias de mi casa</p>
<p>Este pequeño rack de comunicaciones es muy importante, no solo por albergar esos dispositivos, sino porque a él llegan (a través de 2 <a href="http://es.wikipedia.org/wiki/Panel_de_conexiones">patch panels</a>) las tomas de red de todas las estancias de mi casa, de forma que desde aquí tengo conexión directa ethernet con todas y cada una de las habitaciones, pasillos, jardín, garage, etc...</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_minirack_patchpanel.jpg">
Todas las conexiones de red de mi casa en un mismo panel</p>
<p>Ésto me permite no solo disponer de acceso a la red desde cualquier estancia de mi habitación, sino que es lo que permite a las televisiones conectarse a los 10TB de películas y series que hay en la NAS del datacenter, salir a Internet a las cámaras de video-vigilancia, etc, etc.</p>
<p>Aún no está completamente terminado, ya que me faltan varias estancias por cablear (es un <em>curro</em> cablear por el interior de las paredes e instalar tomas de <a href="">RJ45</a> en todas las habitaciones) pero cuando esté acabado el sistema de alarma no tendrá límites!</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_roseta_rj45.jpg">
Toma RJ45 de una de las habitaciones de mi casa</p>
<p>Y por favor, que a nadie se le ocurra decirme que haga éso mismo por Wifi, que ya me gustaría ver cómo funciona una red inalámbrica cuando más de una docena de cámaras están transmitiendo video mientras una televisión reproduce una película en HD en streaming desde la NAS mientras mi novia navega por Internet y mientras yo estoy descargando algo... por favor, seamos serios... la Wifi está muy bien para leer el correo desde el movil y mandar un par de mensajes por <a href="https://telegram.org/">Telegram</a>, pero nada más...</p>
<h3>Capítulo 4: SAIs, KVMs, ventilación y demás accesorios<a id="capitulo4"></a></h3>
<p>Todo aparato eléctrico que tiene que estar funcionando constantemente tiene un grave problema que hay que evitar a toda costa: los cortes en el suministro eléctrico.</p>
<p>Bien sea porque el proveedor de electricidad tiene que hacer alguna reparación, bien porque <em>mi novia conecta todos los aparatos y electrodomésticos de la casa al mismo tiempo</em> o bien por una tormenta puntual, hay ocasiones en las que nos quedamos <em>sin luz</em>. Y esos cortes bruscos de electricidad no solo no son nada saludables para los servidores, discos duros, etc. sino que además provocan un tiempo de inactividad durante el cual todas las webs, servicios de correo, etc. que se alojan en ellos dejan de estar disponibles, y eso es algo que no nos podemos permitir...</p>
<p>Para ello hace ya muchísimos años que utilizo 2 <a href="http://es.wikipedia.org/wiki/Sistema_de_alimentaci%C3%B3n_ininterrumpida">sistemas de alimentación ininterrumpida</a> (SAIs).</p>
<p>El primer de ellos no es nada del otro mundo. Es un simple SAI de tipo <a href="http://es.wikipedia.org/wiki/Sistema_de_alimentaci%C3%B3n_ininterrumpida#SAI_en_estado_de_espera_.28stand-by_power_systems.29">offline</a> que protege fundamentalmente la NAS, ya que 10TB de información no es algo que quiera arriesgarme a perder por un corte de luz.</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_sai_powerwalker.jpg">
SAI Powewalker VI 2000</p>
<p>Es un <a href="http://powerwalker.com/datasheet/Line-Interactive/PowerWalker%20VI%202000%20LCD.pdf">Powerwalker IV 2000</a>, de 2000VA (1200W). Es un modelo muy normal y no muy potente, pero más que suficiente para proteger la NAS ante picos de tensión, cortes de alimentación, etc.</p>
<p>El otro es un SAI de tipo <a href="http://es.wikipedia.org/wiki/Sistema_de_alimentaci%C3%B3n_ininterrumpida#SAI_en_l.C3.ADnea_.28on-line.29">online</a> muchísimo más avanzado y potente. Es un <a href="http://unitekpower.es/app/download/5781187990/ficha_epsilon-1000-2000-es.pdf">Unitek Epsilon 2000</a> (un viejo SAI ya descatalogado) en versión 19" montar en rack.</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_sai_unitek.jpg">
SAI Unitek Epsilon 2000</p>
<p>Éste es el que protege los servidores principales y alguno de los arrays de discos, y aunque por ahora he ido <em>tirando</em> con el, necesito conseguir otro mucho más potente porque ahora mismo no todos los servidores y arrays de discos estan protegidos ante un fallo de alimentación, ya que la potencia total que necesitaría para eso es muy superior a la que es capaz de ofrecer éste SAI.</p>
<p>Algunas veces no disponemos de red para poder acceder remotamente a los servidores, y necesitamos conectarnos a ellos físicamente con un teclado y un monitor (ya sea para acceder a la <a href="http://es.wikipedia.org/wiki/BIOS">BIOS</a>, para instalar el <a href="http://es.wikipedia.org/wiki/Sistema_operativo">sistema operativo</a> o simplemente porque la red no está configurada, o no lo está correctamente).</p>
<p>En éstos casos, lo que haríamos sería conectar un teclado y un monitor a la parte trasera del servidor al que queramos acceder... pero ¿qué sucede cuando tenemos decenas de servidores instalados en un rack, o cuando queremos conectarnos a varios de ellos cada poco tiempo? En lugar de andar moviendo el rack, enchufando y desenchufando monitores de un lado a otro, etc. <a href="http://en.wikipedia.org/wiki/Lords_of_Kobol">los Dioses</a> crearon los <a href="http://en.wikipedia.org/wiki/KVM_switch">switchs KVM</a>.</p>
<p>Con éstos switches, se pueden controlar varios ordenadores con un único monitor, teclado y ratón... de forma que solo tenemos que pulsar un botón para pasar de un servidor a otro.</p>
<p>Los hay de muchos tipos, siendo los más comunes y económicos los de <em>sobremesa</em>, que permiten controlar 2 o 4 dispositivos. Los hay también de 6, 8, 16, etc. y en formato 19" para montar en un rack.
En éste momento mi datacenter cuenta con 4 de ellos:</p>
<ul>
<li>Uno pequeño, en formato sobremesa, que permite conectar a 4 dispositivos.</li>
<li>Dos más grandes, en formato rack 19" (<a href="https://es.wikipedia.org/wiki/Unidad_rack">1 U</a>), que permiten conectar a 8 dispositivos cada uno.</li>
<li>Uno enorme, en formato rack 19" (<a href="https://es.wikipedia.org/wiki/Unidad_rack">2 U</a>) con el que se pueden gestionar hasta 16 servidores.</li>
</ul>
<p><img class="left" src="/images/posts/datacenter/datacenter_kvm_aten_masterview.gif"></p>
<p>El pequeño lo tengo desde hace muchísimos años, y hace varios que no lo uso debido a los pocos dispositivos que permite controlar.</p>
<p>Fué uno de los regalos de navidad que tuve cuando era pequeño que más me han gustado de toda mi vida... por aquel entonces me parecía <em>magia</em> poder controlar 4 ordenadores con solo 1 teclado y 1 monitor...</p>
<p>Los de 8 puertos son <a href="http://www.blackbox.com/Store/Results.aspx/KVM/n-4294964384">BlackBox ServSelect</a>. De éstos 2 únicamente utilizo 1 de ellos para alternar entre un viejo ordenador que uso para algunas cosas, las <a href="http://www.raspberrypi.org/">Raspberrys PI</a> con las que juego a veces, y los ordenadores que me traen familiares y amigos de vez en cuando para que les arregle algo (<a href="http://pringao.com/pringao-howto/">si, si... lo se, pero qué le voy a hacer</a>).</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_kvm_blackbox_01.jpg">
KVM Switch BlackBox ServSelect 8 puertos</p>
<p>Y por último (el grande) es un <a href="http://cache-www.belkin.com/support/dl/f1d116-osd-1.pdf">Omniview PRO 16-ports</a>, que valdría <em>un pastón</em> en su momento (entre 1.000 € y 2.000 € tranquilamente), pero lo conseguí de segunda mano gracias a <a href="http://www.ebay.com">eBay</a> a un precio increible hace ya varios años. Obviamente es el que tengo instalado en el rack, y es el que uso habitualmente.</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_kvm_omniview_01.jpg">
KVM Switch Omniview PRO 16-puertos</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_kvm_omniview_02.jpg"></p>
<p>Pero tanto servidor, tanto switch y tantos discos no solo consumen una increible cantidad de electricidad, sino que generan un calor absolutamente inaguantable. Para evitar ésto, y mantener las instalaciones refrigeradas para que rindan al máximo, los datacenters profesionales tienen sistemas de refrigeración por agua, aires acondicionados industriales, etc, etc. Obviamente yo no me puedo permitir algo así, por lo que para refrigerar todo utilizo métodos más <em>económicos</em> (y por supuesto, muchísimo menos eficaces xDDDD)</p>
<p>El dispositivo de refrigeración principal de mi rack es una bandeja de 4 ventiladores (que ocupa <a href="https://es.wikipedia.org/wiki/Unidad_rack">1 U</a>) cuya velocidad se regula automáticamente en función de la temperatura que registra su sensor. Dicho sensor (que en realidad es más bien una sonda) está colocado justo en la parte central trasera del rack.</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_fan_unit_01.jpg">
Unidad de refrigeración</p>
<p>El flujo de aire en un rack comienza por el aire que los servidores y unidades de disco aspiran por la parte delantera. Este aire (supuestamente frio) recorre el servidor de punta a punta, enfriando a su paso todos sus componentes gracias a las diferentes canalizaciones que tienen estos servidores en su interior. El aire, ya caliente, sale por la parte trasera del servidor, y gracias a ésta unidad de refrigeración, es aspirado hacia arriba para ser finalmente expulsado de nuevo al exterior (por el techo del rack).</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_fan_unit_02.jpg"></p>
<p>No obstante, teniendo todas estas máquinas en una habitación más bien pequeña, sin sistemas de refrigeración <em>decentes</em> (aire acondicionado permanente, etc) y sobre todo en pleno verano, ha habido algunos momentos en los que la temperatura de la habitación ha rozado límites absolutamente increibles... y para muestra, la siguiente imagen, sacada en agosto un dia cualquiera de éste último verano:</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_temperature.jpg">
Algunos dias en verano pensé que se iban a derretir hasta las paredes...</p>
<p>No aspiro a alojar grandes volúmenes de datos, ni visitadísimas páginas webs, ni nada parecido... solo soy un administrador de sistemas y programador al que le encanta la tecnología, y al que le encanta aún más saber que todos los servidores que necesita y que utiliza a diario se encuentran justo debajo de su dormitorio. xDDDDD</p>
<p>Eso si, ni siquiera señalizando el datacenter con carteles disuasorios consigo que Virginia, mi mujer, me deje tranquilo cuando estoy en esa habitación:</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_cartel.jpg"></p>
<p>Y es que por mucho ruido que haya, por mucho calor que produzca o por muchas luces que se enciendan y apaguen, a quien no le gusta vivir en un buen Datacenter??? xDD</p>
<p><img class="center" src="/images/posts/datacenter/datacenter_alvaro_01.jpg">
¿Quien dijo que enseñar Perl a un niño de 2 años sería dificil? xDD</p>
<p>Y creo que poco más me queda por enseñaros... el resto de dispositivos (impresoras de papel, impresoras de tarjetas identificativas, cámaras de vigilancia, etc) no tienen demasiada importancia, así que no necesitan demasiada presentación, por lo que parece que el <em>tour</em> a través de mi Datacenter casero ha llegado a su fin.</p>
<p>Espero que os haya resultado como mínimo interesante, y aunque obviamente hay millones de <a href="http://rm-rf.es/bunker-nuclear-transformado-en-un-datacenter/">datacenters muchísimo mejores</a> por ahí, éste está en mi casa, y los demás no.</p>
<p>Y a partir de ahora, cuando vuestra novia o madre os esté echando la bronca por dejar el ordenador encendido por la noche mientras se descarga algo, o por el ruido que hace el ventilador de vuestro portatil, o incluso por haberos dejado un monitor encendido sin estar usándolo, pasarle un enlace a éste artículo y os garantizo que no volverá a regañaros por eso jamás xDDD</p>
<p>Alaaaaaaaaaaaaaaaaaaaa!</p>Markdown, el lenguaje de marcado para texto plano2014-07-02T21:23:07+02:002014-07-02T21:23:07+02:00BhEaNtag:pornohardware.com,2014-07-02:/2014/07/02/markdown-el-lenguaje-de-marcado-para-texto-plano/<p>Cuando vosotros (<em>los humanos</em>) necesitais formatear un texto de forma rápida y sencilla, y además teneis que hacerlo en texto plano, la mayoría intentará hacerlo con <a href="http://es.wikipedia.org/wiki/HTML">HTML</a> (si va a ser interpretado por un navegador web) o incluso con <a href="http://es.wikipedia.org/wiki/Bbcode">BBCode</a> (si se trata de un post en un foro)... y ambas opciones no estan mal, pero existe otra opción especialmente diseñada para ese fin, que muy pocos conocen y aún menos utilizan: el lenguaje de marcado web <a href="https://es.wikipedia.org/wiki/Markdown">Markdown</a>.</p>
<p>Cuando vosotros (<em>los humanos</em>) necesitais formatear un texto de forma rápida y sencilla, y además teneis que hacerlo en texto plano, la mayoría intentará hacerlo con <a href="http://es.wikipedia.org/wiki/HTML">HTML</a> (si va a ser interpretado por un navegador web) o incluso con <a href="http://es.wikipedia.org/wiki/Bbcode">BBCode</a> (si se trata de un post en un foro)... y ambas opciones no estan mal, pero existe otra opción especialmente diseñada para ese fin, que muy pocos conocen y aún menos utilizan: el lenguaje de marcado web <a href="https://es.wikipedia.org/wiki/Markdown">Markdown</a>.</p>
<p>La <a href="https://es.wikipedia.org/">Wikipedia</a> lo describe de ésta forma:</p>
<blockquote>
<p>Markdown es un lenguaje de marcado ligero creado por John Gruber que trata de conseguir la máxima legibilidad y facilidad de publicación tanto en su forma de entrada como de salida, inspirándose en muchas convenciones existentes para marcar mensajes de correo electrónico usando texto plano. Se distribuye bajo licencia BSD y está disponible en diferentes sistemas de gestión de contenidos (CMS).</p>
</blockquote>
<p>Es decir, con Markdown podemos dar formato a un texto plano de forma rápida e intuitiva, de forma que al ser procesado por el correspondiente intérprete de Markdown, nuestro texto se convierta en texto <a href="http://es.wikipedia.org/wiki/XHTML">XHTML</a> con sus negritas, cursivas, títulos, etc.</p>
<p>Nuestro querido <a href="http://octopress.org/">Octopress</a> (el software sobre el que está escrito éste blog) utiliza éste lenguaje de marcado para formatear los textos, lo que significa que éste mismo artículo que estais leyendo ahora mismo (con sus cabeceras, negritas, etc) ha sido escrito utilizando Markdown).</p>
<p>Éstas son las opciones que tenemos con Markdown:</p>
<ol>
<li><a href="#bold">Texto en negrita, cursiva y tachado</a></li>
<li><a href="#paragraph">Párrafos y saltos de linea</a></li>
<li><a href="#codes">Códigos</a></li>
<li><a href="#headers">Títulos y cabeceras</a></li>
<li><a href="#lists">Listas</a></li>
<li><a href="#quotes">Citas</a></li>
<li><a href="#links">Enlaces</a></li>
<li><a href="#images">Imágenes</a></li>
<li><a href="#seps">Separadores</a></li>
<li><a href="#tables">Tablas</a></li>
<li><a href="#foodnotes">Notas a pié de página</a></li>
</ol>
<p>Vamos a empezar entonces, pero antes de seguir teneis que tener en cuenta que algunos de los ejemplos que os voy a enseñar en este artículo podrían verse de forma <em>diferente</em> en otra parte, ya que dependiendo de los <a href="https://es.wikipedia.org/wiki/Hoja_de_estilos_en_cascada">estilos CSS</a> que tengais en vuestra web, la presentación puede variar.</p>
<h2>Texto en negrita, cursiva y tachado<a name="bold"></a></h2>
<p>La forma de utilizarlo es muy simple: únicamente hay que colocar el texto que queremos formatear entre sus correspondientes <em>tags</em> de marcado (como si fuera HTML). Por ejemplo, si ponemos una frase entre <em>asteriscos</em> o entre <em>guiones bajos</em>, significa que queremos que dicha frase aparezca en letra cursiva.</p>
<p>Por tanto, con éste texto:</p>
<div class="highlight"><pre><span></span><code><span class="err">*Texto en cursiva* y _Texto en cursiva_</span>
</code></pre></div>
<p>Obtendremos éste resultado:</p>
<p><em>Texto en cursiva</em> y <em>Texto en cursiva</em></p>
<p>Del mismo modo, si encerramos el texto entre <em>dobles asteriscos</em> o <em>dobles guiones bajos</em>, significa que queremos que el texto se muestre en negrita.</p>
<p>Por tanto, éste texto:</p>
<div class="highlight"><pre><span></span><code><span class="err">**Texto en negrita** y __Texto en negrita__</span>
</code></pre></div>
<p>Obtendremos éste otro resultado:</p>
<p><strong>Texto en negrita</strong> y <strong>Texto en negrita</strong></p>
<p>Facil, no? Pues ahora vamos a ver todas las opciones de las que disponemos con éste lenguaje, o al menos, todas las opciones que permite la implementación de Markdown que hay en nuestro Octopress (que no son pocas).
Desconozco si hay alguna que no esté en Octopress, o si alguna de las que tiene no son <em>oficiales</em>, pero en éste artículo intentaré explicar el mayor número posible de ellas:</p>
<p>El texto tachado se consigue encerrando el texto entre <em>dobles virgulillas</em> <code>~</code>(tambien llamadas tildes de eñe), de forma que:</p>
<div class="highlight"><pre><span></span><code><span class="err">~~texto que aparecerá tachado~~</span>
</code></pre></div>
<p>nos mostrará:</p>
<p>~~texto que aparecerá tachado~~</p>
<h2>Párrafos y saltos de linea<a name="paragraph"></a></h2>
<p>Los párrafos se crean automáticamente cuando dejamos una linea en blanco entre medias de dos bloques de texto. Por ejemplo, este código:</p>
<div class="highlight"><pre><span></span><code><span class="n">Texto</span> <span class="n">del</span> <span class="n">párrafo</span> <span class="mi">1</span><span class="p">.</span>
<span class="n">Texto</span> <span class="n">del</span> <span class="n">párrafo</span> <span class="mi">2</span><span class="p">.</span>
</code></pre></div>
<p>Nos dará automáticamente la separación entre ambos bloques:</p>
<p>Texto del párrafo 1.</p>
<p>Texto del párrafo 2.</p>
<p>Sin embargo, si únicamente queremos hacer un salto de linea, basta con acabar la linea con 2 espacios en blanco (<em>sustituye el carácter _ por espacios en blanco</em>):</p>
<div class="highlight"><pre><span></span><code><span class="err">Linea 1__</span>
<span class="err">Linea 2</span>
</code></pre></div>
<p>Lo cual mostrará ésto:</p>
<p>Linea 1
Linea 2</p>
<h2>Códigos<a name="codes"></a></h2>
<p>Si lo que queremos mostrar es un código, el nombre de un archivo, un comando sencillo o algo similar, lo metemos entre acentos inversos:</p>
<div class="highlight"><pre><span></span><code><span class="ss">`codigo`</span>
</code></pre></div>
<p>Y obtendremos: <code>codigo</code></p>
<p>Si el código que queremos poner ocupa varias lineas, se pone entre 3 acentos inversos:</p>
<div class="highlight"><pre><span></span><code><span class="err">```</span>
<span class="err">Ejemplo de un trozo de</span>
<span class="err">codigo en varias lineas</span>
<span class="err">```</span>
</code></pre></div>
<p>Con lo que obtendremos:</p>
<div class="highlight"><pre><span></span><code><span class="err">Ejemplo de un trozo de</span>
<span class="err">codigo en varias lineas</span>
</code></pre></div>
<h2>Títulos y cabeceras<a name="headers"></a></h2>
<p>Para los títulos se utiliza el carácter #, pudiendo poner de 1 a 6 dependiendo del tamaño de título que queramos. Por ejemplo, éstos códigos:</p>
<div class="highlight"><pre><span></span><code><span class="err">######Titulo 6</span>
<span class="err">#####Titulo 5</span>
<span class="err">####Titulo 4</span>
<span class="err">###Titulo 3</span>
<span class="err">##Titulo 2</span>
<span class="err">#Titulo 1</span>
</code></pre></div>
<p>Darían como resultado:</p>
<h6>Titulo 6</h6>
<h5>Titulo 5</h5>
<h4>Titulo 4</h4>
<h3>Titulo 3</h3>
<h2>Titulo 2</h2>
<h1>Titulo 1</h1>
<h2>Listas<a name="lists"></a></h2>
<p>Para las listas, podemos poner cada elemento a continuación de un asterisco o un guión al principio de cada linea.
Si ponemos:</p>
<div class="highlight"><pre><span></span><code><span class="err">* Elemento 1</span>
<span class="err">* Elemento 2</span>
<span class="err">* Etc...</span>
</code></pre></div>
<p>Obtendremos:</p>
<ul>
<li>Elemento 1</li>
<li>Elemento 2</li>
<li>Etc...</li>
</ul>
<p>Y para listas de segundo nivel, basta con dejar un par de espacios en blanco delante. Por ejemplo, si ponemos:</p>
<div class="highlight"><pre><span></span><code><span class="err">* Elemento 1</span>
<span class="err">* Elemento 2</span>
<span class="err"> * Sub-elemento 2.1</span>
<span class="err"> * Sub-elemento 2.2</span>
<span class="err"> * Sub-elemento 2.3</span>
<span class="err"> * Sub-elemento 2.4</span>
<span class="err"> * Sub-elemento 2.4.1</span>
<span class="err">* Etc...</span>
</code></pre></div>
<p>Obtendremos:</p>
<ul>
<li>Elemento 1</li>
<li>Elemento 2</li>
<li>Sub-elemento 2.1</li>
<li>Sub-elemento 2.2</li>
<li>Sub-elemento 2.3</li>
<li>Sub-elemento 2.4<ul>
<li>Sub-elemento 2.4.1</li>
</ul>
</li>
<li>Etc...</li>
</ul>
<p>También se pueden hacer listas ordenadas (comenzando por numeros) e incluso mezclarlas:</p>
<div class="highlight"><pre><span></span><code><span class="err">1. Elemento 1</span>
<span class="err">2. Elemento 2</span>
<span class="err">3. Elemento 3</span>
<span class="err">4. Elemento 4</span>
<span class="err"> - Sub-elemento 4.1</span>
<span class="err"> - Sub-elemento 4.2</span>
<span class="err"> 1. Sub-elemento 4.2.1</span>
<span class="err"> 2. Sub-elemento 4.2.2</span>
<span class="err">5. Elemento 5</span>
</code></pre></div>
<p>Lo que nos mostraría:</p>
<ol>
<li>Elemento 1</li>
<li>Elemento 2</li>
<li>Elemento 3</li>
<li>Elemento 4</li>
<li>Sub-elemento 4.1</li>
<li>Sub-elemento 4.2<ol>
<li>Sub-elemento 4.2.1</li>
<li>Sub-elemento 4.2.2</li>
</ol>
</li>
<li>Elemento 5</li>
</ol>
<h2>Citas<a name="quotes"></a></h2>
<p>Para escribir citas, se pone el texto que queremos citar a continuación del carácter <code>></code>, por ejemplo, el código:</p>
<div class="highlight"><pre><span></span><code><span class="err">> No temo a los ordenadores; lo que temo es quedarme sin ellos - Isaac Asimov</span>
</code></pre></div>
<p>Daría como resultado:</p>
<blockquote>
<p>No temo a los ordenadores; lo que temo es quedarme sin ellos - Isaac Asimov</p>
</blockquote>
<p>Y para citas anidadas (citas dentro de otras citas) se van poniendo más carácteres <code>></code> (hasta el nivel que queramos: 2, 3, 4, ...). Por ejemplo:</p>
<div class="highlight"><pre><span></span><code><span class="err">> Cita primera</span>
<span class="err">>> Cita segunda</span>
<span class="err">>>> Cita tercera</span>
</code></pre></div>
<p>Generaría:</p>
<blockquote>
<p>Cita primera</p>
<blockquote>
<p>Cita segunda</p>
<blockquote>
<p>Cita tercera</p>
</blockquote>
</blockquote>
</blockquote>
<h2>Enlaces<a name="links"></a></h2>
<p>Para hacer enlaces, debemos poner la dirección a la que queremos que apunte entre paréntesis, precedida del texto del enlace entre corchetes, tal y como se ve aqui:</p>
<div class="highlight"><pre><span></span><code><span class="err">[Texto del enlace](https://pornohardware.com)</span>
</code></pre></div>
<p>Y eso nos mostraría ésto: <a href="https://pornohardware.com">Texto del enlace</a></p>
<h2>Imágenes<a name="images"></a></h2>
<p>Para añadir imágenes se puede usar éste código:</p>
<div class="highlight"><pre><span></span><code><span class="o">!</span><span class="p">[</span><span class="n">Texto</span> <span class="n">alternativo</span><span class="p">](</span><span class="o">/</span><span class="n">images</span><span class="o">/</span><span class="n">cylon</span><span class="p">.</span><span class="n">png</span> <span class="s">"Título de la imagen"</span><span class="p">)</span>
</code></pre></div>
<p>Que daría como resultado ésto:</p>
<p><img alt="Texto alternativo" src="/images/cylon.png" title="Título de la imagen"></p>
<h2>Separadores<a name="seps"></a></h2>
<p>Para mostrar un separador en el texto, podemos utilizar tres guiones:</p>
<div class="highlight"><pre><span></span><code><span class="err">---</span>
</code></pre></div>
<p>Que mostrará algo como ésto:</p>
<hr>
<h2>Tablas<a name="tables"></a></h2>
<p>Hay algunas opciones más avanzadas, como por ejemplo la creación de tablas simples utilizando las barras verticales (<em>pipes</em>) de ésta forma:</p>
<div class="highlight"><pre><span></span><code><span class="nv">Color</span> <span class="p">|</span> <span class="nv">Número</span> <span class="p">|</span> <span class="nv">Ciudad</span>
<span class="p">:-</span><span class="s s-Atom">--</span> <span class="p">|</span> <span class="p">:-</span><span class="s s-Atom">--:</span> <span class="p">|</span> <span class="s s-Atom">---:</span>
<span class="nv">Azul</span> <span class="p">|</span> <span class="nv">Uno</span> <span class="p">|</span> <span class="nv">Toledo</span>
<span class="nv">Rojo</span> <span class="p">|</span> <span class="nv">Dos</span> <span class="p">|</span> <span class="nv">Madrid</span>
<span class="nv">Negro</span> <span class="p">|</span> <span class="nv">Tres</span> <span class="p">|</span> <span class="nv">Asturias</span>
</code></pre></div>
<p>Lo cual generaría ésta tabla:</p>
<table>
<thead>
<tr>
<th align="left">Color</th>
<th align="center">Número</th>
<th align="right">Ciudad</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">Azul</td>
<td align="center">Uno</td>
<td align="right">Toledo</td>
</tr>
<tr>
<td align="left">Rojo</td>
<td align="center">Dos</td>
<td align="right">Madrid</td>
</tr>
<tr>
<td align="left">Negro</td>
<td align="center">Tres</td>
<td align="right">Asturias</td>
</tr>
</tbody>
</table>
<p>El lado en el que pongamos los 2 puntos <code>:</code> indica hacia donde estará alineado el contenido de cada celda:</p>
<ul>
<li>Centrado: <code>:--:</code></li>
<li>Alineado a la izquierda: <code>:---</code></li>
<li>Alineado a la derecha: <code>---:</code></li>
</ul>
<h2>Notas a pié de página<a name="foodnotes"></a></h2>
<p>Por último, se pueden poner <em>notas</em> a pié de página intercaladas en el texto, de forma que la explicación de cada anotación se situa en la parte de abajo del documento, por ejemplo así:</p>
<div class="highlight"><pre><span></span><code><span class="n">Esto</span> <span class="n">es</span> <span class="n">una</span> <span class="n">nota</span> <span class="n">a</span> <span class="n">pié</span> <span class="n">de</span> <span class="n">página</span><span class="p">[</span><span class="o">^</span><span class="n">nota1</span><span class="p">]</span> <span class="n">mezclada</span><span class="p">[</span><span class="o">^</span><span class="n">nota2</span><span class="p">]</span> <span class="n">con</span> <span class="n">el</span> <span class="n">texto</span><span class="p">[</span><span class="o">^</span><span class="n">nota3</span><span class="p">].</span>
<span class="p">[</span><span class="o">^</span><span class="n">nota1</span><span class="p">]:</span> <span class="n">Descripción</span> <span class="n">de</span> <span class="n">la</span> <span class="n">nota</span> <span class="mi">1</span>
<span class="p">[</span><span class="o">^</span><span class="n">nota2</span><span class="p">]:</span> <span class="n">Descripción</span> <span class="n">de</span> <span class="n">la</span> <span class="n">nota</span> <span class="mi">2</span>
<span class="p">[</span><span class="o">^</span><span class="n">nota3</span><span class="p">]:</span> <span class="n">Descripción</span> <span class="n">de</span> <span class="n">la</span> <span class="n">nota</span> <span class="mi">3</span>
</code></pre></div>
<p>Lo cual generaría algo como:</p>
<p>Esto es una nota a pié de página<sup id="fnref:nota1"><a class="footnote-ref" href="#fn:nota1">1</a></sup> mezclada<sup id="fnref:nota2"><a class="footnote-ref" href="#fn:nota2">2</a></sup> con el texto<sup id="fnref:nota3"><a class="footnote-ref" href="#fn:nota3">3</a></sup> <em>(Y como podrás ver al final de esta página, se ha añadido la "explicacion" a la nota que acabamos de poner)</em>.</p>
<p>Es importante resaltar que puesto que Markdown se usa para generar XHTML, hay 2 carácteres que hay ue tratar de forma especial cuando trabajemos con éste lenguaje de marcado. Éstos carácteres son <code><</code> y <code>&</code>.</p>
<p>El primero de ellos se utiliza para comenzar los <a href="https://es.wikipedia.org/wiki/Etiqueta_%28lenguaje_de_marcado%29">tags HTML</a>, y el último para especificar <a href="https://es.wikipedia.org/wiki/HTML#Entidades_HTML">entidades HTML</a>, por lo que a la hora de mostrar dichos carácteres con Markdown debemos <em>escaparlos</em> utilizando <code>&lt;</code> en lugar de <code><</code> y <code>&amp;</code> en lugar de <code>&</code>.</p>
<p>Y eso es todo por ahora! Prometo ir añadiendo todas las nuevas opciones de marcado que vaya descubriendo.</p>
<p>Y recordar, si el artículo os ha parecido útil, comentarlo, agradecerlo y/o compartirlo... que para eso está! xDD</p>
<p>Alaaaaaaaaaaaaaaaa</p>
<p><a name="refs"></a></p>
<h2>Referencias</h2>
<ul>
<li><a href="https://es.wikipedia.org/wiki/Aaron_Swartz">https://es.wikipedia.org/wiki/Aaron_Swartz</a></li>
<li><a href="http://daringfireball.net/projects/markdown/basics">http://daringfireball.net/projects/markdown/basics</a></li>
<li><a href="http://joedicastro.com/markdown-la-mejor-opcion-para-crear-contenidos-web.html">http://joedicastro.com/markdown-la-mejor-opcion-para-crear-contenidos-web.html</a></li>
</ul>
<div class="footnote">
<hr>
<ol>
<li id="fn:nota1">
<p>Descripción de la nota 1 <a class="footnote-backref" href="#fnref:nota1" title="Jump back to footnote 1 in the text">↩</a></p>
</li>
<li id="fn:nota2">
<p>Descripción de la nota 2 <a class="footnote-backref" href="#fnref:nota2" title="Jump back to footnote 2 in the text">↩</a></p>
</li>
<li id="fn:nota3">
<p>Descripción de la nota 3 <a class="footnote-backref" href="#fnref:nota3" title="Jump back to footnote 3 in the text">↩</a></p>
</li>
</ol>
</div>Mejorando un poco el SEO de Octopress (o de cualquier web en general)2014-06-26T22:22:01+02:002014-06-26T22:22:01+02:00BhEaNtag:pornohardware.com,2014-06-26:/2014/06/26/mejorando-el-seo-de-octopress/<p>Se entiende por <em>SEO</em> (<a href="http://es.wikipedia.org/wiki/Posicionamiento_en_motores_de_b%C3%BAsqueda">Search Engine Optimization</a>) el proceso de mejora de la visibilidad de un sitio web en los resultados de un buscador. Es decir, aquellos mecanismos que utilizamos para que nuestra web aparezca mejor posicionada que las demás en las páginas de resultados de los buscadores.</p>
<p>Hay todo un mundo detrás del SEO, donde la mayoría de las <em>pautas</em> son generales para todos los buscadores, pero donde también se pueden encontrar comportamientos y formas de hacer las cosas únicamente para favorecer los resultados en un buscador en concreto. En cualquier caso, en éste artículo solo nos vamos a centrar en 3 cosas muy concretas que nuestro querido <a href="http://www.octopress.org">Octopress</a> no hace del todo bien, pero que bastan unos sencillos cambios para solucionarlo.</p>
<p>Se entiende por <em>SEO</em> (<a href="http://es.wikipedia.org/wiki/Posicionamiento_en_motores_de_b%C3%BAsqueda">Search Engine Optimization</a>) el proceso de mejora de la visibilidad de un sitio web en los resultados de un buscador. Es decir, aquellos mecanismos que utilizamos para que nuestra web aparezca mejor posicionada que las demás en las páginas de resultados de los buscadores.</p>
<p>Hay todo un mundo detrás del SEO, donde la mayoría de las <em>pautas</em> son generales para todos los buscadores, pero donde también se pueden encontrar comportamientos y formas de hacer las cosas únicamente para favorecer los resultados en un buscador en concreto. En cualquier caso, en éste artículo solo nos vamos a centrar en 3 cosas muy concretas que nuestro querido <a href="http://www.octopress.org">Octopress</a> no hace del todo bien, pero que bastan unos sencillos cambios para solucionarlo.</p>
<p>Éste artículo se basa en un post de <em>Kornelije Sajler</em> titulado <a href="http://learnaholic.me/2012/10/15/octopress-seo-and-disabling-the-blog-route">Octopress SEO and Disabling the Blog Route</a>, pero para los que no sepais inglés o querais entender un poco más acerca de lo que estamos hablando, intentaré explicarlo un poco más en profundidad.</p>
<p>Las 3 cosas que vamos a modificar para mejorar el SEO de nuestros blogs con Octopress son:</p>
<ul>
<li>Meta tags</li>
<li>Duplicidad de contenido</li>
<li>Friendly URL's (o como se dice en español: las <a href="http://es.wikipedia.org/wiki/URL_sem%C3%A1ntica">URLs semánticas</a>)</li>
</ul>
<p>Vamos a ver cada una de ellas un poco más despacio...</p>
<h2>Meta tags</h2>
<p>Las Metatags son unas etiquetas de <code>HTML</code> que contienen información para el navegador que estemos utilizando (o el programa que esté accediendo al documento en cuestión), es decir, no muestran ningun tipo de información al usuario que visualiza la página (se dice por tanto que son <em>transparentes</em> para el usuario).</p>
<p>Suelen ir en el encabezado del documento (entre los tags <code><head></code> y <code></head></code>) y contienen información como por ejemplo la codificación o juego de caracteres del documento (<code>charset</code>), el nombre del programa que lo ha generado (<code>generator</code>), la descripción o pequeño resumen del contenido del mismo (<code>description</code>), etc.</p>
<p>La mayoría de los buscadores leen éstas <em>tags</em> cuando acceden a las páginas web para indexarlas, y tienen en cuenta lo que en ellas se especifica a la hora de clasificarlas en sus índices de búsqueda.</p>
<p>A pesar de que algunas de ellas se crean correctamente en Octopress, hay 2 en concreto que son muy importantes y que NO se tienen en cuenta a dia de hoy, aunque esperemos que en un futuro no muy lejano Octopress las incluya. De hecho, ahora que lo pienso, cuando tenga un rato haré un <em>fork</em> del proyecto de <a href="https://github.com/octopress/octopress">Octopress en Github</a> y enviaré un <a href="https://help.github.com/articles/using-pull-requests"><em>pull request</em></a> para que lo incluyan en el código si sus desarrolladores lo consideran de utilidad... <strong>bendito Open Source!!</strong>)</p>
<p>Éstas dos metatags que no se incluyen actualmente en Octopress son <code>keywords</code> y <code>description</code>.</p>
<h3>Metatag: keywords</h3>
<p>En ésta Metatag se suelen indicar aquellas palabras de búsqueda que estan relacionadas con el contenido de la página a la que estamos accediendo. Por ejemplo, en una página web que hable sobre <em>los hábitos reproductivos del calamar gigante</em> (un tema apasionante), podríamos indicar como <code>keyworks</code> las siguientes: <code>calamar</code>, <code>reproduccion</code>, <code>moluscos</code>, <code>costumbres sexuales</code>, etc.</p>
<p>Con esto le estamos diciendo al buscador que si alguien busca alguna de esas palabras, debería aparecer nuestra página entre los primeros resultados, ya que su contenido está muy relacionado con esa posible búsqueda.</p>
<p>Pero no os hagais ilusiones con éste tema y penseis que vuestra página aparecerá en el primer resultado de búsqueda cuando alguien busque esas palabras, sino únicamente que se tomarán dichas palabras como un argumento más a la hora de mostrar vuestra página, pero hay muchas más cosas que influyen en la posición. Y dar gracias a Dios (o a los <a href="http://en.wikipedia.org/wiki/Lords_of_Kobol">Dioses</a>, mejor dicho) que ésto sea así, porque sino, todo el mundo pondría todas las palabras que se les ocurrieran con la esperanza de que buscaras lo que buscaras, su página saldría entre los resultados (aún recuerdo cuando empezó éste tema hace ya muchos años, la gracia que me hacía ver que todo el mundo ponía <code>sexo</code>, <code>sex</code>, <code>games</code> y demás <em>Top Tens</em> de las palabrás más buscadas entre las <code>keywords</code> de sus páginas, ya fueran sobre recetas de cocina, sobre críticas de películas o incluso webs corporativas de empresas de todo tipo, con la esperanza de que aparecieran siempre en los primeros resultados de los buscadores, jejeje).</p>
<h3>Metatag: description</h3>
<p>Ésta otra metatag se utiliza a modo de pequeño resumen, sumario o descripción sobre el contenido de la página web.
En éste caso, no se suele utilizar para seleccionar en qué posición aparecerá nuestra página entre los resultados de una búsqueda, sino para que cuando finalmente aparezca nuestra página en ellos, sea éste texto que se muestre al usuario en lugar de cualquier otro texto irrelevante de cualquier parte de nuestra página (por ejemplo una trozo de la cabecera, del pié de página, del menu lateral o de cualquier otro contenido irrelevante para esa cuestión en este momento).</p>
<p>Es decir, si alguien ha buscado algo en un buscador, y éste va a mostrar nuestra página en los resultados de la búsqueda, éste podría ser el texto que le aparecería al usuario (junto con nuestra URL y demás), haciendo que sea mucho más legible y <em>configurable</em> para nosotros la forma en la que apareceremos en dicho buscador.</p>
<p>No obstante, aunque no sea tenido en cuenta el contenido de dicha metatag para mostrar nuestra web antes o después en la página de resultados, el mero hecho de que exista o no ésta metatag <strong>sí que será tenido en cuenta</strong> por la mayoría de los buscadores como un indicio de la <em>calidad</em> de nuestra web, y eso sí que afecta directamente a la posición en la que apareceremos en ellos.</p>
<p>Para solucionar éste tema de las metatags en nuestro blog de Octopress, necesitamos poder especificarlas cuando escribamos cada post, por lo que debemos modificar el código de Octopress para que el comando <code>rake new_post</code> nos genere el nuevo post con éstas 2 cabeceras para que nosotros podamos rellenarlas.</p>
<p>Editamos entonces el archivo <code>Rakefile</code>. En él, buscamos la tarea <code>:new_post</code>, y en la parte en la que se escriben las cabeceras de cada nuevo posts que escribimos añadimos 2 lineas con nuestras 2 cabeceras, quedando el código más o menos así:</p>
<div class="highlight"><pre><span></span><code><span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s1">'w'</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">post</span><span class="o">|</span>
<span class="n">post</span><span class="o">.</span><span class="n">puts</span> <span class="s2">"---"</span>
<span class="n">post</span><span class="o">.</span><span class="n">puts</span> <span class="s2">"layout: post"</span>
<span class="n">post</span><span class="o">.</span><span class="n">puts</span> <span class="s2">"title: </span><span class="se">\"</span><span class="si">#{</span><span class="n">title</span><span class="o">.</span><span class="n">gsub</span><span class="p">(</span><span class="sr">/&/</span><span class="p">,</span><span class="s1">'&amp;'</span><span class="p">)</span><span class="si">}</span><span class="se">\"</span><span class="s2">"</span>
<span class="n">post</span><span class="o">.</span><span class="n">puts</span> <span class="s2">"date: </span><span class="si">#{</span><span class="no">Time</span><span class="o">.</span><span class="n">now</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s1">'%Y-%m-%d %H:%M:%S %z'</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span>
<span class="n">post</span><span class="o">.</span><span class="n">puts</span> <span class="s2">"comments: true"</span>
<span class="n">post</span><span class="o">.</span><span class="n">puts</span> <span class="s2">"categories: "</span>
<span class="n">post</span><span class="o">.</span><span class="n">puts</span> <span class="s2">"keywords: "</span>
<span class="n">post</span><span class="o">.</span><span class="n">puts</span> <span class="s2">"description: "</span>
<span class="n">post</span><span class="o">.</span><span class="n">puts</span> <span class="s2">"---"</span>
<span class="k">end</span>
</code></pre></div>
<p>Ahora, cuando ejecutemos el comando de Octopress para crear un nuevo post (<code>rake new_post</code>), se nos creará en <code>source/_posts/</code> un archivo más o menos así (donde aparte de escribir el post como siempre, podremos tambien especificar los valores de nuestras 2 nuevas cabeceras):</p>
<div class="highlight"><pre><span></span><code><span class="err">---</span>
<span class="c">layout: post</span>
<span class="c">title: "Hábitos reproductivos del calamar gigante"</span>
<span class="c">date: 2014-06-24 23:02:38 +0200</span>
<span class="c">comments: true</span>
<span class="c">categories:</span>
<span class="c">keywords: calamar, reproduccion, moluscos, costumbres sexuales</span>
<span class="c">description: Descripción detallada de los rituales de apareamiento de éste singular animal cuando encuentra una bella dama calamar en las profundidades marinas</span>
<span class="err">---</span>
</code></pre></div>
<p>Ahora ya podemos especificar éstas metatags en nuestros posts... pero aunque podamos especificarlas, ahora tenemos que decirle a Octopress cómo y donde debe mostrarlas.</p>
<p>Para eso, editamos el archivo <code>header.html</code> del tema que estemos utilizando (por defecto se utiliza el theme <code>classic</code>) y justo después del código para añadir la metatag <code>author</code>, añadimos las nuestras (aprox. lineas 8 a 11) de forma que el archivo quede más o menos así:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><!DOCTYPE html></span>
<span class="c"><!--[if IEMobile 7 ]><html class="no-js iem7"><![endif]--></span>
<span class="c"><!--[if lt IE 9]><html class="no-js lte-ie8"><![endif]--></span>
<span class="c"><!--[if (gt IE 8)|(gt IEMobile 7)|!(IEMobile)|!(IE)]><!--></span><span class="p"><</span><span class="nt">html</span> <span class="na">class</span><span class="o">=</span><span class="s">"no-js"</span> <span class="na">lang</span><span class="o">=</span><span class="s">"en"</span><span class="p">></span><span class="c"><!--<![endif]--></span>
<span class="p"><</span><span class="nt">head</span><span class="p">></span>
<span class="p"><</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">"utf-8"</span><span class="p">></span>
<span class="p"><</span><span class="nt">title</span><span class="p">></span>{% if page.title %}{{ page.title }} - {% endif %}{{ site.title }}<span class="p"></</span><span class="nt">title</span><span class="p">></span>
<span class="p"><</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">"author"</span> <span class="na">content</span><span class="o">=</span><span class="s">"{{ site.author }}"</span><span class="p">></span>
{% capture description %}{% if page.description %}{{ page.description }}{% elsif site.description %}{{ site.description }}{%else%}{{ content | raw_content }}{% endif %}{% endcapture %}
<span class="p"><</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">"description"</span> <span class="na">content</span><span class="o">=</span><span class="s">"{{ description | strip_html | condense_spaces | truncate:150 }}"</span><span class="p">></span>
{% if page.keywords %}<span class="p"><</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">"keywords"</span> <span class="na">content</span><span class="o">=</span><span class="s">"{{ page.keywords }}"</span><span class="p">></span>{%else%}<span class="p"><</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">"keywords"</span> <span class="na">content</span><span class="o">=</span><span class="s">"{{ site.keywords }}"</span><span class="p">></span>{% endif %}
<span class="p"><</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">"HandheldFriendly"</span> <span class="na">content</span><span class="o">=</span><span class="s">"True"</span><span class="p">></span>
<span class="p"><</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">"MobileOptimized"</span> <span class="na">content</span><span class="o">=</span><span class="s">"320"</span><span class="p">></span>
<span class="p"><</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">"viewport"</span> <span class="na">content</span><span class="o">=</span><span class="s">"width=device-width, initial-scale=1"</span><span class="p">></span>
{% capture canonical %}{{ site.url }}{% if site.permalink contains '.html' %}{{ page.url }}{% else %}{{ page.url | remove:'index.html' }}{% endif %}{% endcapture %}
<span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"canonical"</span> <span class="na">href</span><span class="o">=</span><span class="s">"{{ canonical }}"</span><span class="p">></span>
<span class="p"><</span><span class="nt">link</span> <span class="na">href</span><span class="o">=</span><span class="s">"{{ root_url }}/favicon.ico"</span> <span class="na">rel</span><span class="o">=</span><span class="s">"icon"</span><span class="p">></span>
<span class="p"><</span><span class="nt">link</span> <span class="na">href</span><span class="o">=</span><span class="s">"{{ root_url }}/stylesheets/screen.css"</span> <span class="na">media</span><span class="o">=</span><span class="s">"screen, projection"</span> <span class="na">rel</span><span class="o">=</span><span class="s">"stylesheet"</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/css"</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"{{ root_url }}/javascripts/jquery-1.11.1.min.js"</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/javascript"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"{{ root_url }}/javascripts/modernizr-2.0.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"{{ root_url }}/javascripts/ender.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"{{ root_url }}/javascripts/octopress.js"</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/javascript"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">link</span> <span class="na">href</span><span class="o">=</span><span class="s">"{{ site.subscribe_rss }}"</span> <span class="na">rel</span><span class="o">=</span><span class="s">"alternate"</span> <span class="na">title</span><span class="o">=</span><span class="s">"{{site.title}}"</span> <span class="na">type</span><span class="o">=</span><span class="s">"application/atom+xml"</span><span class="p">></span>
{% include custom/head.html %}
{% include google_analytics.html %}
<span class="p"></</span><span class="nt">head</span><span class="p">></span>
</code></pre></div>
<p>Y listo, con eso ya tendremos nuestras nuevas metatags <code>description</code>y <code>keywords</code>, y a partir de ahora cada vez que escribamos un nuevo post en nuestro Octopress podremos especificarlas al igual que especificamos la fecha, título o cualquier otra configuración del post.</p>
<h2>Duplicidad de contenido</h2>
<p>La mayoría de los buscadores se lleva muy mal con aquellas webs que ponen el mismo contenido en diferentes páginas. Ésto es así en Octopress o en cualquier web del mundo, es algo universal...</p>
<p>Y cuando me refiero a <em>duplicar el mismo contenido en diferentes páginas</em> me refiero a que para un buscador, la web <a href="http://www.pornohardware.com">www.pornohardware.com</a> es diferente a la web <a href="https://pornohardware.com">pornohardware.com</a> (aunque realmente sean la misma, pero una con <code>www</code> delante y la otra no).</p>
<p>Por ese motivo hay que configurar nuestro servidor web para que únicamente se utilice un dominio (el que nosotros queramos, da igual uno u otro, pero hay que decidirse por uno de ellos).</p>
<p>Cómo elegir entre uno y otro depende del caso... aunque yo recomiendo <strong>SIN www</strong> delante (aparte de las preferencias personales, hace mucho tiempo leí un artículo sobre éste tema que me terminó de convencer de las ventajas de NO usar <code>www</code> en los dominios, pero por más que lo he intentado buscar ahora no lo encuentro, por lo tanto podéis creerme y tomar mi palabra como la verdad absoluta (cosa que deberíais, por cierto xDDD) o bien buscarlo vosotros mismos y ponerlo en los comentarios de éste artículo si lo encontrais).</p>
<p>Sea cual sea vuestra elección, debeis hacerla... y una vez hecha, configurar vuestro servidor web y vuestro entorno Octopress para que cuando se acceda al otro dominio se les redirija al que vosotros habeis elegido. De esa forma, los buscadores no verán 2 páginas iguales y os penalizarán por ello, sino que accedan a la que accedan, se les redirigirá siempre a la misma.</p>
<p>La forma de hacer ésto en Octopress es muy sencilla. Únicamente hemos de instalar la <em>gema</em> de Ruby llamada <code>rack-rewrite</code>:</p>
<div class="highlight"><pre><span></span><code>$ sudo gem install rack-rewrite
</code></pre></div>
<p><em>Lo instalo como <code>root</code> (con <code>sudo</code>) para que la gema esté disponible para todos los usuarios del servidor, no solo para el mio</em>.</p>
<p>Una vez instalada, editamos el archivo <code>Gemfile</code> de nuestro Octopress, y añadimos la <em>gema</em> que acabamos de instalar (<em>linea 19</em>):</p>
<div class="highlight"><pre><span></span><code><span class="n">source</span> <span class="s2">"https://rubygems.org "</span>
<span class="n">group</span> <span class="ss">:development</span> <span class="k">do</span>
<span class="n">gem</span> <span class="s1">'rake'</span><span class="p">,</span> <span class="s1">'~> 10.3.2'</span>
<span class="n">gem</span> <span class="s1">'jekyll'</span><span class="p">,</span> <span class="s1">'~> 0.12'</span>
<span class="n">gem</span> <span class="s1">'rdiscount'</span><span class="p">,</span> <span class="s1">'~> 2.0.7'</span>
<span class="n">gem</span> <span class="s1">'pygments.rb'</span><span class="p">,</span> <span class="s1">'~> 0.3.4'</span>
<span class="n">gem</span> <span class="s1">'RedCloth'</span><span class="p">,</span> <span class="s1">'~> 4.2.9'</span>
<span class="n">gem</span> <span class="s1">'haml'</span><span class="p">,</span> <span class="s1">'~> 3.1.7'</span>
<span class="n">gem</span> <span class="s1">'compass'</span><span class="p">,</span> <span class="s1">'~> 0.12.2'</span>
<span class="n">gem</span> <span class="s1">'sass'</span><span class="p">,</span> <span class="s1">'~> 3.2'</span>
<span class="n">gem</span> <span class="s1">'sass-globbing'</span><span class="p">,</span> <span class="s1">'~> 1.0.0'</span>
<span class="n">gem</span> <span class="s1">'rubypants'</span><span class="p">,</span> <span class="s1">'~> 0.2.0'</span>
<span class="n">gem</span> <span class="s1">'rb-fsevent'</span><span class="p">,</span> <span class="s1">'~> 0.9'</span>
<span class="n">gem</span> <span class="s1">'stringex'</span><span class="p">,</span> <span class="s1">'~> 1.4.0'</span>
<span class="n">gem</span> <span class="s1">'liquid'</span><span class="p">,</span> <span class="s1">'~> 2.3.0'</span>
<span class="n">gem</span> <span class="s1">'directory_watcher'</span><span class="p">,</span> <span class="s1">'1.4.1'</span>
<span class="n">gem</span> <span class="s1">'nokogiri'</span><span class="p">,</span> <span class="s1">'~> 1.6.2'</span>
<span class="n">gem</span> <span class="s1">'rack-rewrite'</span>
<span class="k">end</span>
<span class="n">gem</span> <span class="s1">'sinatra'</span><span class="p">,</span> <span class="s1">'~> 1.4.2'</span>
</code></pre></div>
<p>Cuando hacemos un <code>rake preview</code> y levantamos nuestro entorno de Octopress para probar los cambios antes de subirlos a <em>producción</em>, se levanta un servidor web (llamado <a href="http://www.sinatrarb.com/">Sinatra</a>) para que podamos acceder a dicha <em>previsualización</em> de nuestra web. Es en ese servidor web donde debemos especificar que se haga la redireccion al dominio que hayamos elegido, y la forma correcta de hacer eso es <strong>enviando la cabecera HTTP 301</strong>, que significa <a href="http://es.wikipedia.org/wiki/Anexo:C%C3%B3digos_de_estado_HTTP">contenido movido a otra dirección de forma permanente</a>.</p>
<p>Para hacer eso, editamos el archivo <code>config.ru</code> de nuestro Octopress y añadimos éstas lineas:</p>
<div class="highlight"><pre><span></span><code><span class="nb">require</span> <span class="s1">'bundler/setup'</span>
<span class="nb">require</span> <span class="s1">'sinatra/base'</span>
<span class="nb">require</span> <span class="s1">'rack-rewrite'</span>
<span class="c1"># The project root directory</span>
<span class="vg">$root</span> <span class="o">=</span> <span class="o">::</span><span class="no">File</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="bp">__FILE__</span><span class="p">)</span>
<span class="no">ENV</span><span class="o">[</span><span class="s1">'RACK_ENV'</span><span class="o">]</span> <span class="o">||=</span> <span class="s1">'development'</span>
<span class="no">ENV</span><span class="o">[</span><span class="s1">'SITE_URL'</span><span class="o">]</span> <span class="o">||=</span> <span class="s1">'pornohardware.com'</span>
<span class="n">use</span> <span class="no">Rack</span><span class="o">::</span><span class="no">Rewrite</span> <span class="k">do</span>
<span class="n">r301</span> <span class="sr">%r{.*}</span><span class="p">,</span> <span class="s2">"http://</span><span class="si">#{</span><span class="no">ENV</span><span class="o">[</span><span class="s1">'SITE_URL'</span><span class="o">]</span><span class="si">}</span><span class="s2">$&"</span><span class="p">,</span> <span class="ss">:if</span> <span class="o">=></span> <span class="no">Proc</span><span class="o">.</span><span class="n">new</span> <span class="p">{</span> <span class="o">|</span><span class="n">rack_env</span><span class="o">|</span>
<span class="no">ENV</span><span class="o">[</span><span class="s1">'RACK_ENV'</span><span class="o">]</span> <span class="o">==</span> <span class="s1">'production'</span> <span class="o">&&</span> <span class="n">rack_env</span><span class="o">[</span><span class="s1">'SERVER_NAME'</span><span class="o">]</span> <span class="o">!=</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">'SITE_URL'</span><span class="o">]</span>
<span class="p">}</span>
<span class="n">r301</span> <span class="sr">%r{^(.+)/$}</span><span class="p">,</span> <span class="s1">'$1'</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">SinatraStaticServer</span> <span class="o"><</span> <span class="no">Sinatra</span><span class="o">::</span><span class="no">Base</span>
<span class="n">get</span><span class="p">(</span><span class="sr">/.+/</span><span class="p">)</span> <span class="k">do</span>
<span class="n">send_sinatra_file</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">path</span><span class="p">)</span> <span class="p">{</span><span class="mi">404</span><span class="p">}</span>
<span class="k">end</span>
<span class="n">not_found</span> <span class="k">do</span>
<span class="n">send_file</span><span class="p">(</span><span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="no">File</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="bp">__FILE__</span><span class="p">),</span> <span class="s1">'public'</span><span class="p">,</span> <span class="s1">'404.html'</span><span class="p">),</span> <span class="p">{</span><span class="ss">:status</span> <span class="o">=></span> <span class="mi">404</span><span class="p">})</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">send_sinatra_file</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="o">&</span><span class="n">missing_file_block</span><span class="p">)</span>
<span class="n">file_path</span> <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="no">File</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="bp">__FILE__</span><span class="p">),</span> <span class="s1">'public'</span><span class="p">,</span> <span class="n">path</span><span class="p">)</span>
<span class="n">file_path</span> <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">file_path</span><span class="p">,</span> <span class="s1">'index.html'</span><span class="p">)</span> <span class="k">unless</span> <span class="n">file_path</span> <span class="o">=~</span> <span class="sr">/\.[a-z]+$/i</span>
<span class="no">File</span><span class="o">.</span><span class="n">exist?</span><span class="p">(</span><span class="n">file_path</span><span class="p">)</span> <span class="p">?</span> <span class="n">send_file</span><span class="p">(</span><span class="n">file_path</span><span class="p">)</span> <span class="p">:</span> <span class="n">missing_file_block</span><span class="o">.</span><span class="n">call</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">run</span> <span class="no">SinatraStaticServer</span>
</code></pre></div>
<p>Y con eso quedaría vuestro <em>Sinatra</em> configurado para la redirección, pero como lo más normal es que en producción utiliceis otro tipo de servidores web como por ejemplo <a href="http://www.apache.org/">Apache</a> o <a href="http://nginx.org/">Nginx</a>, ahora vamos a configurar dichos servidores para hacer también esa redirección.</p>
<h3>Apache</h3>
<p>En Apache la mejor forma de hacer ésta redirección es mediante el módulo <a href="http://httpd.apache.org/docs/current/mod/mod_rewrite.html">mod_rewrite</a>.</p>
<p>Debeis editar vuestro archivo de configuración del servidor web (su nombre y ubicación varía segun la distribución de Linux que esteis usando, pero normalmente está en <code>/etc/apache2</code> si usais <a href="http://www.debian.org">Debian</a> o derivados de ella, o en <code>/etc/httpd</code> si usais <a href="http://redhat.com">Redhat</a>/<a href="http://www.centos.org">CentOS</a> o derivados de ellas) y añadir éstas lineas:</p>
<div class="highlight"><pre><span></span><code><span class="nb">RewriteEngine</span> <span class="k">On</span>
<span class="nb">RewriteCond</span> %{HTTP_HOST} ^www\.pornohardware\.com$ [NC,OR]
<span class="nb">RewriteRule</span> ^\/(.*)$ https://pornohardware.com/$1 [R=301,L]
</code></pre></div>
<p>Recargais el servicio de Apache para que lea de nuevo dicha configuración, y listo. En Debian:</p>
<div class="highlight"><pre><span></span><code>$ sudo /etc/init.d/apache2 reload
</code></pre></div>
<p>Y en Redhat/CentOS:</p>
<div class="highlight"><pre><span></span><code>$ sudo /etc/init.d/httpd graceful
</code></pre></div>
<h3>Nginx</h3>
<p>En Nginx la redirección es muy parecida, únicamente editamos el archivo de configuración de Nxginx y añadimos éstas lineas:</p>
<div class="highlight"><pre><span></span><code><span class="k">server</span> <span class="p">{</span>
<span class="kn">server_name</span> <span class="s">www.pornohardware.com</span><span class="p">;</span>
<span class="kn">return</span> <span class="mi">301</span> <span class="nv">$scheme://pornohardware.com$request_uri</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>Recargamos Nginx, y listo... sea cual sea el servidor web que estemos utilizando, a partir de ese momento, cualquier petición que recibamos en nuestro servidor web y que vaya dirigida a la dirección <a href="http://www.pornohardware.com">http://www.pornohardware.com</a> será respondida con una cabecera HTTP 301 y redirigida a la URL <a href="https://pornohardware.com">https://pornohardware.com</a>.</p>
<h2>URLs semánticas (friendly URL's)</h2>
<p>Octopress ya incorpora éste tipo de URL's semánticas desde el principio, pero por defecto añade <code>/blog</code> a dicha URL... y eso no solo no es nada semántico sino que además es innecesario, por lo que parece buena idea quitarlo.</p>
<p>Por defecto, las direcciónes de los artículos de Octopress se crean utilizando la fecha de creación y el título del post. Es decir, algo como <code>http://dominio.com/blog/año/mes/dia/titulo-del-post</code>, y nosotros lo vamos a dejar en <code>http://dominio.com/año/mes/dia/titulo-del-post</code>.</p>
<p>Editamos el archivo <code>_config.yml</code> y cambiamos éstas 2 lineas:</p>
<div class="highlight"><pre><span></span><code><span class="nt">permalink</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">/blog/:year/:month/:day/:title/</span>
<span class="nt">category_dir</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">blog/categories</span>
</code></pre></div>
<p>por éstas otras:</p>
<div class="highlight"><pre><span></span><code><span class="nt">permalink</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">/:year/:month/:day/:title/</span>
<span class="nt">category_dir</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">categories</span>
</code></pre></div>
<p>Y regeneramos de nuevo la web con:</p>
<div class="highlight"><pre><span></span><code>$ rake generate
</code></pre></div>
<p>Ahora todas las URL's deberían aparecer correctamente sin <code>/blog</code> en ellas.</p>
<p>Hay muchísimas más cosas que podemos y debemos hacer para aumentar nuestra posición en los buscadores, así como muchas otras cosas que no debemos hacer por el mismo motivo. Ésto era solo un pequeño <em>tip</em> para mi recién estrenado Octopress, así que si quereis profundizar en el tema os recomiendo que busqueis un poco en Internet, ya que hay una cantidad brutal de literatura sobre éste tema.</p>
<p>El <em>mundo</em> del SEO es cada vez más grande, y siempre me ha dado la impresión de que se <em>autoalimenta</em>... como si fuera el propio SEO el que creara continuamente nuevas formas de <em>necesitarse</em> a si mismo, lo cual no me parece forzosamente malo excepto cuando se nos obliga a hacer determinadas cosas únicamente para cumplir con los designios de <a href="http://www.huyedelacorporacion.com">los <em>grandes</em> buscadores</a>, los cuales por mucho que digan que toman el SEO en cuenta, realmente hacen lo que les da la gana con quienes les da la gana para favorecer al que paga y perjudicar al que no... y ésto por desgracia lo tengo más que comprobado.</p>
<p>Hoy en dia todo mi afán por mejorar el SEO se centra únicamente en mejorar la posición de mis webs en <a href="http://www.bing.es">Bing</a>, <a href="http://www.duckduckgo.com">DuckDuckGo</a> e incluso en <a href="http://www.yahoo.es">Yahoo</a> (si es que aún hay alguien que lo usa, jejeje) porque a los CERDOS de <em>Google</em> hace ya tiempo que dejé de hacerles caso, harto de dedicar tiempo, esfuerzo y dinero para que de un dia para otro decidan banearte, retirarte 2 puntos de Pagerank o cancelar una cuenta de Adsense (que llevaba utilizando cerca de 8 años) por <em>publicar en una web un post hablando de un disco de Shakira donde aparecía la foto de la portada del disco, alegando que dicha portada contenía una foto de una chica con "posturas sugerentes"</em>, lo cual segun sus normas está prohibido, pero que sin embargo las webs de <em>Fnac</em>, <em>El Corte Ingles</em> o cualquier otra gran tienda de discos sí que pueden publicar y seguir <em>disfrutando</em> de su cuenta de Google aunque tengan ese mismo disco con esa misma portada en sus webs, y cien mil más).</p>
<p>Es más, puedes buscar <em>POLLAS</em> Y <em>CHOCHOS</em> en <em>Google</em> y obtendrás millones de resultados (con imágenes pornográficas absolutamente explícitas, e incluso alojadas físicamente en sus servidores), y al parecer eso no está en contra de sus normas, pero la portada del disco de Shakira en mi web si...</p>
<p>El tema de la censura y el doble/triple/etc rasero por el que se rige <em>Google</em> a la hora de aplicar sus normas mejor lo dejo para otro post... que solo de pensarlo me cabreo aún más con <a href="http://www.google.es">esa panda de dictadores y mentirosos</a>, y no es plan...</p>
<p>Que disfruten de su Octopress!</p>
<p>Alaaaaaaaaaaaaaaaaaaaaaaaaaa</p>
<h2>Referencias</h2>
<ul>
<li><a href="http://octopress.org/">http://octopress.org/</a></li>
<li><a href="http://learnaholic.me/2012/10/15/octopress-seo-and-disabling-the-blog-route">http://learnaholic.me/2012/10/15/octopress-seo-and-disabling-the-blog-route</a></li>
<li><a href="http://es.wikipedia.org/wiki/Metatag">http://es.wikipedia.org/wiki/Metatag</a></li>
<li><a href="http://httpd.apache.org/docs/current/mod/mod_rewrite.html">http://httpd.apache.org/docs/current/mod/mod_rewrite.html</a></li>
</ul>Replicación de bases de datos PostgreSQL con Slony en CentOS2014-06-24T23:02:38+02:002014-06-24T23:02:38+02:00BhEaNtag:pornohardware.com,2014-06-24:/2014/06/24/replicacion-de-bases-de-datos-postgresql-con-slony-en-linux-centos/<p><a href="http://www.slony.info">Slony1</a> es un software para la replicación de datos entre servidores <a href="http://www.postgresql.org">PostgreSQL</a>, creando clusters formados por un nodo maestro y uno o varios nodos esclavos.</p>
<p><img class="right" src="/images/logos/logo_slony.png"/>
Aunque soy <a href="http://www.debian.org">Debianita a muerte</a>, muchas veces me veo obligado a usar otras distribuciones de Linux (sobre todo en el curro), como por ejemplo <a href="http://www.centos.org">CentOS</a>. Y puesto que éste artículo lo escribí hace ya varios años como <em>chuleta personal</em> precisamente para el curro, está hecho sobre esa distribución... pero como casi siempre en éstos casos, debería ser perfectamente válido para cualquier otro Linux.</p>
<p>Partimos de la base de que ya tenemos instalados y configurados los servidores de base de datos PostgreSQL en los nodos que vamos a usar.</p>
<p>Es de vital importancia que todos los nodos que van a formar el cluster tengan la misma codificación. Es decir, si vamos a usar <code>UTF8</code>, TODOS los servidores y bases de datos deben estar en <code>UTF8</code>, y si vamos a usar <code>LATIN1</code>, TODOS deben estar en <code>LATIN1</code>. De lo contrario, al inicializar la replicación por primera vez, se comenzaran a copiar algunas tablas, y de repente el proceso parará y empezará de nuevo a copiar la primera tabla, y así sucesivamente en un bucle sin fin, sin que ningun log muestre ninguna pista al respecto, así que hay que tenerlo muy presente antes de empezar.</p>
<p><a href="http://www.slony.info">Slony1</a> es un software para la replicación de datos entre servidores <a href="http://www.postgresql.org">PostgreSQL</a>, creando clusters formados por un nodo maestro y uno o varios nodos esclavos.</p>
<p><img class="right" src="/images/logos/logo_slony.png">
Aunque soy <a href="http://www.debian.org">Debianita a muerte</a>, muchas veces me veo obligado a usar otras distribuciones de Linux (sobre todo en el curro), como por ejemplo <a href="http://www.centos.org">CentOS</a>. Y puesto que éste artículo lo escribí hace ya varios años como <em>chuleta personal</em> precisamente para el curro, está hecho sobre esa distribución... pero como casi siempre en éstos casos, debería ser perfectamente válido para cualquier otro Linux.</p>
<p>Partimos de la base de que ya tenemos instalados y configurados los servidores de base de datos PostgreSQL en los nodos que vamos a usar.</p>
<p>Es de vital importancia que todos los nodos que van a formar el cluster tengan la misma codificación. Es decir, si vamos a usar <code>UTF8</code>, TODOS los servidores y bases de datos deben estar en <code>UTF8</code>, y si vamos a usar <code>LATIN1</code>, TODOS deben estar en <code>LATIN1</code>. De lo contrario, al inicializar la replicación por primera vez, se comenzaran a copiar algunas tablas, y de repente el proceso parará y empezará de nuevo a copiar la primera tabla, y así sucesivamente en un bucle sin fin, sin que ningun log muestre ninguna pista al respecto, así que hay que tenerlo muy presente antes de empezar.</p>
<p>En este ejemplo vamos a configurar un cluster con 2 nodos: 1 maestro y 1 esclavo.</p>
<p>Slony funciona notificando a los esclavos mediante un demonio, que es llamado a su vez por medio de triggers en las tablas que se van a replicar. Solo las operaciones <code>INSERT</code>, <code>UPDATE</code> o <code>DELETE</code> pueden ser replicadas mediante Slony (y el valor de las secuencias, por supuesto). Esto significa que los cambios en el esquema de la base de datos NO son propagados a los nodos, ni ninguna otra operación tampoco (<code>TRUNCATE</code>, <code>DROP</code>, <code>CREATE</code>, etc....)</p>
<h2>Instalación</h2>
<p>Existen paquetes precompilados de Slony1 para ésta distribucion (CentOS), por lo tanto, lo instalamos mediante su gestor de paquetes YUM:</p>
<div class="highlight"><pre><span></span><code>$ sudo yum install slony1
</code></pre></div>
<p>Si no esstuviéramos utilizando los repositorios de yum necesarios o el paquete no estuviera disponible en ellos por cualquier motivo, deberemos bajar el paquete RPM manualmente desde la URL http://main.slony.info/downloads e instalarlo con:</p>
<div class="highlight"><pre><span></span><code>$ sudo rpm -i <nombrepaquete>
</code></pre></div>
<p>Una vez instalado, los archivos de configuración se guardan en <code>/etc/slon.conf</code> y <code>/etc/slon_tools.conf</code>.</p>
<p>Hay que crear primero el usuario que vamos a usar para la sincronización en todos los nodos del cluster. Dicho usuario debe tener permisos de <code>superuser</code> en el servidor de base de datos.
Tambien habrá que configurar los permisos de PostgreSQL para poder conectarse con este usuario desde el servidor maestro del cluster.</p>
<p>Para eso, creamos el usuario en el servidor PostgreSQL (en nuestro ejemplo, vamos a crear el usuario <code>slony</code>), por lo que iniciamos la consola de PostgreSQL y ejecutamos la query para crear el usuario:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$</span> sudo su postgres -
<span class="go">postgres@server:~$ psql</span>
<span class="go">psql (9.3.4)</span>
<span class="go">Type "help" for help.</span>
<span class="gp">postgres=#</span> <span class="k">CREATE</span> <span class="k">USER</span> <span class="n">slony</span> <span class="n">superuser</span> <span class="k">password</span> <span class="s1">'test'</span><span class="p">;</span>
<span class="go">CREATE ROLE</span>
<span class="gp">postgres=#</span> <span class="kp">\q</span>
</code></pre></div>
<p>Editamos ahora el archivo <code>pg_hba.conf</code> de PostgreSQL, que es donde se configura el acceso de los usuarios, habilitando el usuario que acabamos de crear (especificando todo el rango de IP's de nuestra red, y seleccionando <code>MD5</code> como tipo de password en dicha configuración):</p>
<div class="highlight"><pre><span></span><code><span class="c1"># "local" is for Unix domain socket connections only</span>
<span class="nb">local</span> all all ident sameuser
<span class="c1"># Slony</span>
host all slony <span class="m">172</span>.26.0.0/24 md5
<span class="c1"># IPv4 local connections:</span>
host all all <span class="m">127</span>.0.0.1/32 md5
<span class="c1"># IPv6 local connections:</span>
host all all ::1/128 ident sameuser
</code></pre></div>
<p>Probamos a conectarnos con dicho usuario desde la consola de PostgreSQL (comando <code>psql</code>), y una vez que hayamos comprobado que funciona, editamos el archivo <code>slon_tools.conf</code> para configurar los nodos, tablas y secuencias que formarán el cluster de replicación..</p>
<p>Definimos el nombre del cluster en la variable <code>$CLUSTER_NAME</code>:</p>
<div class="highlight"><pre><span></span><code><span class="nv">$CLUSTER_NAME</span> <span class="o">=</span> <span class="s">'test_replication'</span><span class="p">;</span>
</code></pre></div>
<p>Después, añadimos tantos nodos como servidores vayan a componer nuestro cluster. En el primer nodo definiremos el servidor MAESTRO, y en los sucesivos los esclavos:</p>
<div class="highlight"><pre><span></span><code><span class="n">add_node</span><span class="p">(</span><span class="n">node</span> <span class="o">=></span> <span class="mi">1</span><span class="p">,</span>
<span class="n">host</span> <span class="o">=></span> <span class="s">'borg01'</span><span class="p">,</span>
<span class="n">dbname</span> <span class="o">=></span> <span class="s">'testdb'</span><span class="p">,</span>
<span class="n">port</span> <span class="o">=></span> <span class="mi">5432</span><span class="p">,</span>
<span class="n">user</span> <span class="o">=></span> <span class="s">'slony'</span><span class="p">,</span>
<span class="n">password</span> <span class="o">=></span> <span class="s">'replicapass'</span>
<span class="p">);</span>
<span class="n">add_node</span><span class="p">(</span><span class="n">node</span> <span class="o">=></span> <span class="mi">2</span><span class="p">,</span>
<span class="n">host</span> <span class="o">=></span> <span class="s">'borg02'</span><span class="p">,</span>
<span class="n">dbname</span> <span class="o">=></span> <span class="s">'testdb'</span><span class="p">,</span>
<span class="n">port</span> <span class="o">=></span> <span class="mi">5432</span><span class="p">,</span>
<span class="n">user</span> <span class="o">=></span> <span class="s">'slony'</span><span class="p">,</span>
<span class="n">password</span> <span class="o">=></span> <span class="s">'replicapass'</span>
<span class="p">);</span>
</code></pre></div>
<p>Comentamos el resto de lineas de los nodos, ya que solo configuraremos estos 2 servidores, y luego especificamos las tablas (en nuestro caso lo haremos con la tabla de ejemplo <code>ads</code>) y secuencias (en nuestro caso <code>ads_id_seq</code>) que queremos sincronizar entre los servidores:</p>
<div class="highlight"><pre><span></span><code><span class="s">"pkeyedtables"</span> <span class="o">=></span> <span class="p">[</span>
<span class="s">'ads'</span><span class="p">,</span>
<span class="p">],</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="s">"sequences"</span> <span class="o">=></span> <span class="p">[</span>
<span class="s">'ads_id_seq'</span><span class="p">,</span>
<span class="p">],</span>
</code></pre></div>
<p>Es muy importante tener en cuenta que en pkeyedtables hay que especificar todas las tablas que vamos a replicar SIEMPRE Y CUANDO dichas tablas tengan definida una PRIMARY_KEY.
Si tenemos alguna tabla que NO tiene una clave primaria, pero tiene un índice único (y que no admita NULL) en lugar de especificarla en pkeyedtables lo haremos en keyedtables, indicando ademas el nombre del índice, de esta forma:</p>
<div class="highlight"><pre><span></span><code><span class="s">"keyedtables"</span> <span class="o">=></span> <span class="p">{</span>
<span class="s">'tablasinpk'</span> <span class="o">=></span> <span class="s">'nombre_indice'</span><span class="p">,</span>
<span class="p">},</span>
</code></pre></div>
<p>Después, copiamos éste archivo a ambos servidores (maestro y esclavo).</p>
<p><strong>Todas las tablas y secuencias que queramos sincronizar entre ambos servidores deben estar ya creadas en todos los nodos del cluster</strong>. Es decir, según nuestro ejemplo, la tabla <code>ads</code> y la secuencia <code>ads_id_seq</code> deben existir y ser iguales en ambos servidores (maestro y esclavo) antes de iniciar el proceso de replicación. Resumiendo: el modelo de datos debe estar creado en todos los servidores, ya que lo único que se replica con Slony son los datos, no el esquema.</p>
<h2>Inicialización del cluster</h2>
<p>Ahora que slony esta configurado correctamente en todos los servidores, y las bases de datos, usuarios y secuencias estan tambien creados en todos ellos, iniciamos el cluster <strong>desde el servidor maestro</strong> con el comando:</p>
<div class="highlight"><pre><span></span><code>$ slonik_init_cluster <span class="p">|</span> slonik
</code></pre></div>
<p>Después, iniciamos los demonios <code>slon</code> en cada servidor, primero con el comando <code>slon_start</code> y luego con el demonio del sistema <code>/etc/init.d/slony1</code>. En nuestro ejemplo, ejecutamos desde el servidor maestro (borg01) el nodo 1:</p>
<div class="highlight"><pre><span></span><code>$ sudo slon_start <span class="m">1</span>
$ sudo /etc/init.d/slony1 start
</code></pre></div>
<p>Y el nodo 2 <strong>desde el servidor esclave</strong> (borg02) con el comando:</p>
<div class="highlight"><pre><span></span><code>$ sudo slon_start <span class="m">2</span>
$ sudo /etc/init.d/slony1 start
</code></pre></div>
<p>Despues, iniciamos el proceso de replicacion, ejecutando el siguiente comando <strong>desde el servidor maestro</strong>:</p>
<div class="highlight"><pre><span></span><code>$ slonik_create_set <span class="m">1</span> <span class="p">|</span> slonik
</code></pre></div>
<p>Y por último, añadimos el esclavo al proceso de replicacion, con el comando:</p>
<div class="highlight"><pre><span></span><code>$ slonik_subscribe_set <span class="m">1</span> <span class="m">2</span> <span class="p">|</span> slonik
</code></pre></div>
<p>Si tuvieramos más servidores esclavos, habría que ejecutar ese comando en cada uno de ellos, especificando el nodo que estamos <em>suscribiendo</em> en ese momento, por ejemplo:</p>
<div class="highlight"><pre><span></span><code>$ slonik_subscribe_set <span class="m">1</span> <span class="m">3</span> <span class="p">|</span> slonik
$ slonik_subscribe_set <span class="m">1</span> <span class="m">4</span> <span class="p">|</span> slonik
</code></pre></div>
<p>Y así sucesivamente...</p>
<p>Ahora ya deberíamos tener nuestro cluster activo y funcionando. La primera vez, sobre todo si las tablas son grandes, suele tardar un buen rato en terminar la sincronización inicial, ya que lo primero que hará Slony será <code>TRUNCATE</code> de todas las tablas de los servidores esclavos, para irlas rellenando con los datos del maestro desde cero, por lo que a veces el proceso puede tardar un poco.</p>
<p>A partir de ese momento, todas las querys de inserción/modificación que ejecutemos en el servidor MAESTRO en la tabla que hemos configurado para la replicación, se transmitirán tambien a las tablas del servidor ESCLAVO.</p>
<h2>Monitorización de la replicación</h2>
<p>Slony crea un nuevo esquema en cada uno de los servidores, llamado <code>_$CLUSTER_NAME</code> (el nombre que especificamos en la variable <code>$CLUSTER_NAME</code>, con el guion-bajo delante). En dicho esquema se guarda la informacion que slony necesita para replicar los datos.</p>
<p>Además, en ese esquema tambien encontraremos un par de <em>vistas</em> que nos seran muy utiles para ver el estado del cluster y la replicacion, sobre todo una llamada <code>sl_status</code>, en la que se indican los nodos a los que se estan replicando, el <em>lag</em> de tiempo de replicación que existe entre cada uno de ellos y el maestro, etc...</p>
<p>Con esta query veremos toda esa informacion:</p>
<div class="highlight"><pre><span></span><code><span class="k">SELECT</span>
<span class="n">st_origin</span><span class="p">,</span>
<span class="n">st_received</span><span class="p">,</span>
<span class="n">st_last_event</span><span class="p">,</span>
<span class="n">st_last_received</span><span class="p">,</span>
<span class="n">st_last_event_ts</span><span class="p">,</span>
<span class="n">st_last_received_ts</span><span class="p">,</span>
<span class="n">st_lag_time</span>
<span class="k">FROM</span>
<span class="n">_replication</span><span class="mf">.</span><span class="n">sl_status</span>
<span class="k">ORDER</span> <span class="k">BY</span>
<span class="mf">2</span><span class="p">;</span>
</code></pre></div>
<p>Si tuvieramos que modificar la estructura de alguna tabla de nuestro cluster ya replicado, habría que utilizar los scripts de Slony que se encargan de transmitir dichos cambios al resto de los nodos, pero eso mejor lo dejamos para otro dia, jejejee...</p>
<p>No hace falta que os recuerde que en la <a href="http://www.slony.info">web oficial de Slony</a> hay mucha y muy detallada documentación sobre todos los comandos y funciones, así que es le primer sitio que debeis leer si estais montando una replicación de éste tipo.</p>
<p>Alaaaaaaaaaaaaaaaaaaaaaaa</p>
<h2>Referencias</h2>
<ul>
<li><a href="http://www.slony.info">http://www.slony.info</a></li>
<li><a href="http://www.nabble.com/altperl-scripts-td22710463.html">http://www.nabble.com/altperl-scripts-td22710463.html</a></li>
<li><a href="http://www.linuxjournal.com/article/7834">http://www.linuxjournal.com/article/7834</a></li>
</ul>Instalación y configuración de Octopress en Linux2014-06-20T20:33:02+02:002014-06-20T20:33:02+02:00BhEaNtag:pornohardware.com,2014-06-20:/2014/06/20/instalacion-y-configuracion-de-octopress-en-linux/<p><img class="right" src="/images/logos/logo_octopress.png"/>
Voy a intentar explicar de la forma más clara posible cómo instalar y configurar <a href="http://octopress.org/">Octopress</a>, un framework Open Source para construir blogs basados en el proyecto <a href="https://github.com/jekyll/jekyll]">Jekyll</a>.</p>
<p>Es un software muy potente que permite crear blogs totalmente estáticos, es decir, una vez configurado, basta con ejecutar un comando para que se nos genere en un directorio toda la escructura de archivos y directorios en texto plano (archivos HTML, JS y CSS) que necesitaremos para nuestro blog.</p>
<p>Estos archivos estáticos estarían listos para servir a través de un servidor web cualquiera, sin necesidad de bases de datos, scripts o lenguajes de programación en el lado del servidor, lo que permite ahorrar muchos recursos, tiempo y por supuesto hardware. De hecho, una vez configurado, bastaría con ejecutar otro comando para que Octopress subiera éstos archivos a nuestro servidor de forma totalmente automática (deploy).</p>
<p><img class="right" src="/images/logos/logo_octopress.png">
Voy a intentar explicar de la forma más clara posible cómo instalar y configurar <a href="http://octopress.org/">Octopress</a>, un framework Open Source para construir blogs basados en el proyecto <a href="https://github.com/jekyll/jekyll]">Jekyll</a>.</p>
<p>Es un software muy potente que permite crear blogs totalmente estáticos, es decir, una vez configurado, basta con ejecutar un comando para que se nos genere en un directorio toda la escructura de archivos y directorios en texto plano (archivos HTML, JS y CSS) que necesitaremos para nuestro blog.</p>
<p>Estos archivos estáticos estarían listos para servir a través de un servidor web cualquiera, sin necesidad de bases de datos, scripts o lenguajes de programación en el lado del servidor, lo que permite ahorrar muchos recursos, tiempo y por supuesto hardware. De hecho, una vez configurado, bastaría con ejecutar otro comando para que Octopress subiera éstos archivos a nuestro servidor de forma totalmente automática (deploy).</p>
<p>Además, se basa en el <em>todopoderoso</em> <a href="https://www.git-scm.com/">Git</a> (y más concretamente en <a href="http://pages.github.com/">GitHub Pages</a>) para gestionar los posts, las revisiones de los posts, etc.</p>
<p>Está hecho en <a href="http://www.ruby-lang.org">Ruby</a>, y utiliza la sintaxis de <a href="http://es.wikipedia.org/wiki/Markdown">Markdown</a> para formatear el texto de los posts, por lo que no estaría de más que le echaras un ojo a ésto último si no lo conocías ya (no tiene ningun misterio, y muchas de sus <em>expresiones</em> seguro que ya las habias usado antes en emails y cosas así).</p>
<p>Para ver ejemplos de blogs que utilicen éste framework no hace falta que vayais muy lejos, ya que tanto éste blog que estais leyendo ahora mismo como la propia web de <a href="http://octopress.org/">Octopress</a> estan hechas con él.</p>
<p>Pensé en escribir éste artículo fundamentalmente para que me sirviera a mi mismo como <em>chuleta</em> sobre la instalación y configuración del blog, pero si aparte de eso le resulta de utilidad a alguien, mejor que mejor...</p>
<p>Empecemos!</p>
<h2>Instalación</h2>
<p>Todos los pasos explicados en éste artículo estan probados en <a href="http://www.debian.org">Debian</a> (concretamente en Debian testing <em>Jessie</em>) pero deberían ser igualmente válidos (con alguna pequeña variación) en cualquier distribución de Linux...</p>
<p>Lo primero que necesitamos es tener instalado <a href="http://www.ruby-lang.org/">Ruby</a> en nuestra máquina local. <strong>NO en el servidor, sino en la máquina desde la que vayamos a trabajar</strong>, ya que recordemos que Octopress generará archivos HTML en texto plano que podrán ser visualizados a través de cualquier servidor web...</p>
<p>Para instalar Ruby, los que disfrutamos de Debian únicamente tenemos que hacer:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install ruby
</code></pre></div>
<p>La gente de Octopress recomienda utilizar la versión 1.9.3 o superior, por lo que si la versión de tu distribución es inferior, tendrás que instalarlo <em>manualmente</em> (y pensar en cambiar de distribución xDDD).
Para comprobar la versión de Ruby que tenemos instalada (en mi caso era <code>2.1.2p95</code>) basta con ejecutar:</p>
<div class="highlight"><pre><span></span><code>$ ruby --version
</code></pre></div>
<p>Con Ruby instalado, ya solo nos falta Git para tener todo lo necesario para empezar:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install git
</code></pre></div>
<p>Ahora, clonamos el repositorio de Octopress de Github en el directorio donde vayamos a trabajar:</p>
<div class="highlight"><pre><span></span><code>$ git clone git://github.com/imathis/octopress.git octopress-test
$ <span class="nb">cd</span> octopress-test
</code></pre></div>
<p>Ya tenemos el código de Octopress, pero para poder ejecutarlo necesitamos instalar algunas dependencias.
Lo primero que necesitamos es instalar <a href="http://bundler.io/">Bundler</a>, que por lo poco que he investigado (reconozco que de Ruby no tengo ni idea) es una herramienta fundamental para gestionar las dependencias en los proyectos de Ruby.</p>
<p>En esos proyectos, el archivo <code>Gemfile</code> es el que contiene el listado de dependencias y versiones necesarias, y <code>bundler</code>se encarga de instalar todo ésto de forma cómoda y muy rápida. Está disponible como una gema de Ruby, por lo que para instalarlo solo necesitamos ejecutar:</p>
<div class="highlight"><pre><span></span><code>$ sudo gem install bundler
</code></pre></div>
<p><strong>Nota:</strong>: Pese a que en muchos otros manuales que he visto se suele ejecutar éste paso como usuario normal (sin sudo), yo prefiero hacerlo así para que ésta gema esté disponible para todos los usuarios de la máquina, no solo para quien ejecuta la instalación. Pero si prefieres no hacerlo así, y que únicamente tu usuario pueda usar <code>bundler</code>, basta con ejecutar el comando <strong>sin</strong> sudo.</p>
<p>Finalmente, instalamos las dependencias especificadas en el <code>Gemfile</code> de Octopress:</p>
<div class="highlight"><pre><span></span><code>$ bundle install
</code></pre></div>
<p>Si hemos llegado aquí sin ningun susto, ya tenemos listo nuestro Octopress recién sacado del horno, por lo que ahora vamos a configurarlo un poco.</p>
<h2>Configuración</h2>
<p>La configuración inicial es muy sencilla. Aunque ya tenemos listo el código de Octopress para construir el blog por defecto, hay algunas cosas que <strike>podemos</strike> debemos configurar.</p>
<p>Todas las opciones de configuración se encuentran en el archivo <code>_config.yml</code>.
La mayoría de sus directivas son autoexplicativas, por lo que te será facil saber para qué son únicamente viendo su nombre. Nosotros para éste ejemplo vamos a modificar la URL del sitio que estamos contruyendo, el título, subtítulo, autor y poco más.</p>
<p>Editamos el archivo y especificamos las configuraciones que necesitemos:</p>
<div class="highlight"><pre><span></span><code><span class="n">url</span><span class="o">:</span> <span class="n">https</span><span class="o">://</span><span class="n">pornohardware</span><span class="o">.</span><span class="na">com</span>
<span class="n">title</span><span class="o">:</span> <span class="n">pornoHARDWARE</span><span class="o">.</span><span class="na">com</span>
<span class="n">subtitle</span><span class="o">:</span> <span class="n">La</span> <span class="n">culpa</span> <span class="n">es</span> <span class="n">de</span> <span class="n">los</span> <span class="n">padres</span><span class="o">,</span> <span class="n">que</span> <span class="n">las</span> <span class="n">visten</span> <span class="n">como</span> <span class="n">a</span> <span class="n">Cylons</span><span class="o">.</span>
<span class="n">author</span><span class="o">:</span> <span class="n">BhEaN</span>
<span class="n">simple_search</span><span class="o">:</span> <span class="n">http</span><span class="o">://</span><span class="n">www</span><span class="o">.</span><span class="na">bing</span><span class="o">.</span><span class="na">es</span>
<span class="n">description</span><span class="o">:</span> <span class="n">Blog</span> <span class="n">personal</span> <span class="n">sobre</span> <span class="n">programacion</span><span class="o">,</span> <span class="n">administracion</span> <span class="n">de</span> <span class="n">sistemas</span><span class="o">,</span> <span class="n">redes</span><span class="o">...</span>
<span class="n">date_format</span><span class="o">:</span> <span class="s2">"%A, %d de %B de %Y, a las %H:%M"</span>
</code></pre></div>
<p>Hay muchas otras cosas en el archivo <code>_config.yml</code> que seguramente quieras configurar. Es un archivo bastante autoexplicativo, por lo que échale un vistazo a las demás opciones de configuración y prácticamente por el nombre de cada una sabrás para qué se utilizan.</p>
<p>Ahora que ya hemos configurado las típicas opciones iniciales (título del sitio, autor, etc) ya podemos construir los archivos de nuestro blog.</p>
<p>Si vienes (como fué mi caso) de compilar con el comando <code>make</code>, de configurar dichas compilaciones con <code>makefiles</code> y todas esas cosas... seguro que nada de ésto te pillará por sorpresa, ya que que en Ruby es muy parecido, solo que se usa el comando <code>rake</code> compilar, y <code>rakefile's</code> para configurar dichas compilaciones.</p>
<p>Hay 4 <em>tareas</em> básicas en el <code>rakefile</code> de nuestro proyecto:</p>
<ol>
<li><code>rake install</code>: Éste comando instalará el tema por defecto de Octopress. Si en lugar de llamarlo directamente le pasamos el nombre de otro tema, lo instalará en lugar de instalar el tema por defecto (por ejemplo: <code>rake install['bhean_2014']</code> instalará el tema que se encuentre en el directorio <code>.themes/bhean_2014</code></li>
<li><code>rake generate</code>: Con éste comando se reconstruirán los archivos del blog, los artículos que escribamos, las paginas, etc. Es el comando que hay que ejecutar cada vez que modifiquemos algun artículo o escribamos un nuevo post para que dichos cambios se vean reflejados en nuestro blog.</li>
<li><code>rake preview</code>: Cuando ejecutamos éste comando, se levantará un servidor web en un puerto local (por defecto en el 4000) para que podamos probar cómo va a quedar el blog una vez generado. Cada vez que hagamos un cambio, deberemos ejecutarl para ver cómo va a quedar dicho cambio antes de subirlo a <em>produccion</em>.</li>
<li><code>rake deploy</code>: Una vez que todos los cambios que hayamos hechos esten a nuestro gusto, con éste comando podremos subir los archivos que del blog se nos han generado a nuestro servidor de <em>producción</em>. Para configurar ésto, debes editar el propio archivo <code>rakefile</code>.</li>
</ol>
<p>Por lo tanto, vamos ejecutamos los comandos necesarios para ver nuestro aún vacío blog:</p>
<div class="highlight"><pre><span></span><code>$ rake install<span class="o">[</span><span class="s1">'bhean_2014'</span><span class="o">]</span>
<span class="c1">## Copying classic theme into ./source and ./sass</span>
mkdir -p <span class="nb">source</span>
cp -r .themes/classic/source/. <span class="nb">source</span>
mkdir -p sass
cp -r .themes/classic/sass/. sass
mkdir -p source/_posts
mkdir -p public
$ rake generate
<span class="c1">## Generating Site with Jekyll</span>
unchanged sass/screen.scss
Configuration from /home/bhean/src/octopress/_config.yml
Notice: <span class="k">for</span> 10x faster LSI support, please install http://rb-gsl.rubyforge.org/
Building site: <span class="nb">source</span> -> public
Running the classifier... this could take a <span class="k">while</span>.
....
Successfully generated site: <span class="nb">source</span> -> public
$ rake preview
Starting to watch <span class="nb">source</span> with Jekyll and Compass. Starting Rack on port <span class="m">4000</span>
<span class="o">[</span><span class="m">2014</span>-06-24 <span class="m">00</span>:39:24<span class="o">]</span> INFO WEBrick <span class="m">1</span>.3.1
<span class="o">[</span><span class="m">2014</span>-06-24 <span class="m">00</span>:39:24<span class="o">]</span> INFO ruby <span class="m">2</span>.1.2 <span class="o">(</span><span class="m">2014</span>-05-08<span class="o">)</span> <span class="o">[</span>x86_64-linux-gnu<span class="o">]</span>
<span class="o">[</span><span class="m">2014</span>-06-24 <span class="m">00</span>:39:24<span class="o">]</span> INFO WEBrick::HTTPServer#start: <span class="nv">pid</span><span class="o">=</span><span class="m">12732</span> <span class="nv">port</span><span class="o">=</span><span class="m">4000</span>
Configuration from /home/bhean/src/octopress/_config.yml
Notice: <span class="k">for</span> 10x faster LSI support, please install http://rb-gsl.rubyforge.org/
Auto-regenerating enabled: <span class="nb">source</span> -> public
<span class="o">[</span><span class="m">2014</span>-06-24 <span class="m">00</span>:39:24<span class="o">]</span> regeneration: <span class="m">169</span> files changed
Running the classifier... this could take a <span class="k">while</span>.
.>>> Compass is polling <span class="k">for</span> changes. Press Ctrl-C to Stop.
..
</code></pre></div>
<p>Solo teneis que conectaros desde un navegador a la IP de la máquina donde hayais ejecutado el <code>rake preview</code> por el puerto 4000, y ya podreis ver vuestro nuevo blog:</p>
<p><img class="right" src="/images/posts/octopress_snapshot.jpg"></p>
<p>Espero que éste pequeño tutorial os haya servido de ayuda. En próximos artículos explicaré cómo personaliza aún más el blog y su contenido, cómo escribir y formatear correctamente los artículos del blog, cómo configurar una serie de plugins muy útiles que existen para su uso libre gracias a la comunidad del software libre, etc, etc.</p>
<p>Pero por ahora ya está bien, que menudo ladrillo me salido para ser el primer artículo <em>serio</em> del blog xDDD.</p>
<p>Saludos!</p>Instalación de Sphinx en Debian y su librería de acceso desde PHP2012-04-09T00:59:35+02:002012-04-09T00:59:35+02:00BhEaNtag:pornohardware.com,2012-04-09:/2012/04/09/instalacion-de-sphinx-en-debian-y-su-libreria-de-acceso-desde-php/<p><a href="http://sphinxsearch.com">Sphinx Search</a> es un genial motor de búsqueda Open Source especialmente útil cuando tenemos muchos datos a los que tenemos que acceder de forma rápida.</p>
<p><img class="left" src="/images/logos/logo_sphinx.png"/>
Su principal virtud es la de crear unos índices conteniendo la información que nosotros le hayamos configurado, que pueden ser accedidos desde nuestros programas (C, PHP, etc) para recuperar la información mucho más rápido que si lo hiciéramos directamente a una base de datos (normalmente se usa como complemento de éstas, cuando la cantidad de información que tenemos en dicha base de datos es demasiado grande y sus propios índices no son todo lo efectivos que nos gustaría).
<br/><br/>
<strike>A dia de hoy no existen paquetes precompilados para nuestra querida Debian, por lo que vamos a generarlos nosotros a partir de su código fuente.</strike> Ya existen paquetes precompilados para las distribuciones de Linux más importantes, los cuales se pueden descargar desde: <a href="http://sphinxsearch.com/downloads/release/">http://sphinxsearch.com/downloads/release/</a></p>
<p><a href="http://sphinxsearch.com">Sphinx Search</a> es un genial motor de búsqueda Open Source especialmente útil cuando tenemos muchos datos a los que tenemos que acceder de forma rápida.</p>
<p><img class="left" src="/images/logos/logo_sphinx.png">
Su principal virtud es la de crear unos índices conteniendo la información que nosotros le hayamos configurado, que pueden ser accedidos desde nuestros programas (C, PHP, etc) para recuperar la información mucho más rápido que si lo hiciéramos directamente a una base de datos (normalmente se usa como complemento de éstas, cuando la cantidad de información que tenemos en dicha base de datos es demasiado grande y sus propios índices no son todo lo efectivos que nos gustaría).
<br /><br />
<strike>A dia de hoy no existen paquetes precompilados para nuestra querida Debian, por lo que vamos a generarlos nosotros a partir de su código fuente.</strike> Ya existen paquetes precompilados para las distribuciones de Linux más importantes, los cuales se pueden descargar desde: <a href="http://sphinxsearch.com/downloads/release/">http://sphinxsearch.com/downloads/release/</a></p>
<p>Si vamos a utilizar éstos paquetes precompilados, únicamente tendremos que instalarlos con el gestor de paquetes de nuestra distribución (<code>dpkg</code>, <code>rpm</code> o lo que corresponda). Por lo tanto, si lo haceis de ésta forma, podeis saltaros la parte de <em>instalación</em> de éste artículo.</p>
<h2>Instalación</h2>
<p>En Debian, siempre es preferible generar paquetes .deb en lugar de instalar manualmente el código fuente compilado, ya que así podremos instalarlos y desinstalarlos limpiamente usando <code>apt</code> o <code>dpkg</code>.</p>
<p>Para generar éstos paquetes primero necesitamos el código fuente, y luego generaremos los paquetes con ese código ya compilado.
Po lo tanto, descargamos el tar.gz con la última versión del código fuente de la <a href="http://www.sphinxsearch.com/downloads.html">web oficial de descarga del proyecto</a>, que en este momento <strike>es la 0.9.8.1</strike>.
(<strong>Actualización</strong>: hoy en dia ésta versión está más que desactualizada, por lo que os recomiendo que bajeis la ultima versión estable)</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">cd</span> /tmp
$ wget http://www.sphinxsearch.com/downloads/sphinx-0.9.8.1.tar.gz
</code></pre></div>
<p>Descomprimimos el archivo en el directorio de fuentes de nuestro sistema (<code>/usr/src</code>)</p>
<div class="highlight"><pre><span></span><code>$ tar xvzf /tmp/sphinx-0.9.8.1.tar.gz
$ <span class="nb">cd</span> /usr/src
$ sudo mv /tmp/sphinx-0.9.8.1 /usr/src
</code></pre></div>
<p>Después, preparamos el paquete para la compilación, especificando si queremos SPHINX con soporte para MySQL, PostgreSQL o ambos, e indicando el directorio donde queremos instalarlo (en mi caso, en <code>/opt/sphinx</code>):</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">cd</span> /usr/src/sphinx-0.9.8.1
$ ./configure --with-pgsql --with-mysql --prefix<span class="o">=</span>/opt/sphinx/
</code></pre></div>
<p>Si ésto falla, normalmente será porque no tenemos instalados todos los paquetes necesarios (o sus correspondientes versiones de desarrollo, por lo que dependiendo del error que se muestre, instalaremos las dependencias necesarias).
En principio, debería bastar con éstos paquetes para compilar Sphinx con soporte para MySQL y PostgreSQL:</p>
<ul>
<li>build-essential</li>
<li>librerias de desarrollo de MySQL (libmysql++-dev)</li>
<li>librerías de desarrollo de PostgreSQL (postgresql-dev)</li>
</ul>
<p>Una vez preparado el paquete para la compilación, lo compilamos:</p>
<div class="highlight"><pre><span></span><code>$ make
</code></pre></div>
<p>Y una vez compilado, en lugar de instalarlo, generamos el paquete .deb con ayuda del programa checkinstall (si no lo tienes, instálalo! <code>apt-get</code> es tu amigo!), simplemente tecleando:</p>
<div class="highlight"><pre><span></span><code>$ checkinstall
</code></pre></div>
<p>Lo cual generará un archivo .deb, que podremos instalar fácilmente con dpkg:</p>
<div class="highlight"><pre><span></span><code>$ sudo dpkg -i sphinx_0.9.8.1-1_i386.deb
</code></pre></div>
<p>Este proceso hará, entre otras cosas, que tengamos 3 binarios de Sphinx instalados en nuestro sistema. Hay algunos mas, pero los que nos interesan son solo estos 3:</p>
<ul>
<li><strong>indexer</strong>: Este programa es el que generará los índices de búsqueda de nuestras bases de datos.</li>
<li><strong>search</strong>: El programa que realizará las búsquedas en los índices generados.</li>
<li><strong>searchd</strong>: Un demonio que permitirá consultas remotas desde la API o desde otras máquinas</li>
</ul>
<p>Ahora, crearemos el usuario que ejecutará el programa:</p>
<div class="highlight"><pre><span></span><code>$ sudo adduser --system --home /opt/sphinx --uid <span class="m">999</span> --disabled-password --disabled-login sphinx
</code></pre></div>
<p>Después, creamos algunos directorios más para los logs, el pid, etc:</p>
<div class="highlight"><pre><span></span><code>$ sudo mkdir /opt/sphinx/log
$ sudo mkdir /opt/sphinx/run
</code></pre></div>
<p>Descargamos el genial script de init.d de Sphinx, programado por <a href="http://www.klaus.gr/">Klaus</a>, para poder iniciar y para el servicio:</p>
<div class="highlight"><pre><span></span><code>$ wget http://www.klaus.gr/pub/sphinx
$ mv sphinx /etc/init.d/
$ chmod <span class="m">755</span> /etc/init.d/sphinx
</code></pre></div>
<p>Miramos cuál es nuestro runlevel actual, y hacemos enlaces al script desde el runlevel indicado:</p>
<div class="highlight"><pre><span></span><code>$ /sbin/runlevel <span class="p">|</span> cut -b <span class="m">3</span>
$ sudo ln -s /etc/init.d/sphinx /etc/rc2.d/S92sphinx
$ sudo chown -R sphinx:root /opt/sphinx
</code></pre></div>
<p>Copiamos el archivo de configuracion de ejemplo de Sphinx, y lo editamos:</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">cd</span> /opt/sphinx/etc
$ cp -p sphinx.conf.dist sphinx.conf
</code></pre></div>
<p>Hay información sobre la configuración en la web oficial de Sphinx, y aquí: http://www.compuglobalhipermega.net/mysql/ejemplo-rfc-sphinx/</p>
<h2>Configuración</h2>
<p>Una vez que hayamos configurado el archivo <code>/opt/sphinx/etc/sphinx.conf</code>, tenemos que crear los indices de búsqueda.
Para eso, hay que ejecutar el programa <code>indexer</code> de esta forma:</p>
<div class="highlight"><pre><span></span><code>$ /opt/sphinx/bin/indexer -config /opt/sphinx/etc/sphinx.conf --all
</code></pre></div>
<p>Cada vez que queramos actualizar el índice, debemos ejecutar de nuevo ese comando.
O mejor aún, vamos a modificar el script de <code>/etc/init.d/sphinx</code> para incluir un nuevo comando <code>rebuild-index</code> que nos facilitará el proceso de reconstruccion de los índices.</p>
<p>Para eso, modificamos <code>/etc/init.d/sphinx</code> e incluimos esta linea al principio, más o menos donde se define la variable <code>binpath</code>:</p>
<div class="highlight"><pre><span></span><code><span class="nv">indexerpath</span><span class="o">=</span>/opt/sphinx/bin/indexer
</code></pre></div>
<p>Y éstas lineas al final (donde corresponda, es facil verlo si observais el archivo):</p>
<div class="highlight"><pre><span></span><code><span class="err">rebuild-index)</span>
<span class="nf">echo "Rebuilding sphinx search index</span><span class="o">:</span> <span class="n">indexer</span>"
<span class="nv">$indexerpath</span> <span class="nv">$SPHINX</span> --all --rotate
<span class="nb">echo</span> <span class="s2">"."</span>
<span class="p">;;</span>
</code></pre></div>
<p>Y modificamos la linea:</p>
<div class="highlight"><pre><span></span><code><span class="nf">echo "Usage</span><span class="o">:</span> /<span class="n">etc</span>/<span class="n">init</span>.<span class="n">d</span>/<span class="n">shpinx</span> {<span class="n">start</span><span class="p">|</span><span class="n">stop</span><span class="p">|</span><span class="n">restart</span><span class="p">|</span><span class="n">force</span>-<span class="n">reload</span>}
</code></pre></div>
<p>Añadiendo rebuild-index, de tal forma que quede así:</p>
<div class="highlight"><pre><span></span><code><span class="nf">echo "Usage</span><span class="o">:</span> /<span class="n">etc</span>/<span class="n">init</span>.<span class="n">d</span>/<span class="n">shpinx</span> {<span class="n">start</span><span class="p">|</span><span class="n">stop</span><span class="p">|</span><span class="n">restart</span><span class="p">|</span><span class="n">force</span>-<span class="n">reload</span><span class="p">|</span><span class="n">rebuild</span>-<span class="n">index</span>}"
</code></pre></div>
<p>De forma que podremos reconstruir/actualizar los indices con el comando:</p>
<div class="highlight"><pre><span></span><code>$ sudo /etc/init.d/sphinx rebuild-index
</code></pre></div>
<p>Y ahora que ya tenemos los indices creados, lanzamos sphinx:</p>
<div class="highlight"><pre><span></span><code>$ sudo /etc/init.d/sphinx start
</code></pre></div>
<p>Y listo... ya tenemos nuestro demonio <code>searchd</code> corriendo...</p>
<h2>Instalación de la librería de acceso desde PHP</h2>
<p>Para acceder a Sphinx y poder realizar búsquedas en sus índices desde, por ejemplo PHP, necesitamos compilar la extensión de <a href="http://pecl.php.net/">PECL</a> de Sphinx.</p>
<p>Para compilar dicha extensión, necesitamos compilar previamente la librería <code>libsphinxclient</code>, que se encuentra en el subdirectorio <code>api/libsphinxclient</code> del codigo fuente de Sphinx.</p>
<p>Accedemos a dicho directorio, y compilamos la librería:</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">cd</span> /usr/src/sphinx-0.9.8.1/api/libsphinxclient
$ <span class="nv">CXXCPP</span><span class="o">=</span><span class="s2">"gcc -E"</span>
$ ./configure --prefix<span class="o">=</span>/opt/sphinx
$ make
$ sudo make install
</code></pre></div>
<p>Ya tenemos la librería lista... ahora, descargamos la librería PECL de Sphinx para PHP.
Podemos descargarla desde: http://pecl.php.net/package/sphinx/</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">cd</span> /tmp
$ wget http://pecl.php.net/get/sphinx-1.0.0.tgz
$ <span class="nb">cd</span> /usr/src
$ sudo tar xvzf /tmp/sphinx-1.0.0.tgz
$ sudo mv sphinx-1.0.0 sphinx-pecl-1.0.0
$ sudo <span class="nb">cd</span> sphinx-pecl-1.0.0
</code></pre></div>
<p>Si no tenemos phpize, lo instalamos:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install php5-dev
</code></pre></div>
<p>Usamos phpize y compilamos la librería:</p>
<div class="highlight"><pre><span></span><code>$ phpize5
$ ./configure --with-sphinx<span class="o">=</span>/opt/sphinx
$ make
</code></pre></div>
<p>Generamos de nuevo el paquete .deb con checkinstall, y lo instalamos con dpkg:</p>
<div class="highlight"><pre><span></span><code>$ checkinstall
$ dpkg -i sphinx-pecl_1.0.0-1_i386.deb
</code></pre></div>
<p>Y por último, añadimos añadir un archivo <code>sphinx.ini</code> en <code>/etc/php5/conf.d/</code> con estas lineas, para habilitar la librería:</p>
<div class="highlight"><pre><span></span><code><span class="p">[</span><span class="n">sphinx</span><span class="p">]</span>
<span class="n">extension</span><span class="o">=</span><span class="n">sphinx</span><span class="o">.</span><span class="n">so</span>
</code></pre></div>
<p>Reiniciamos el servidor web, y ya podremos trabajar con Sphinx desde PHP como se explica en <a href="http://php.net/sphinx">http://php.net/sphinx</a>.</p>
<p>Espero que os sirva de ayuda!</p>
<p>Alaaaaaaaaaaaaaaaaaaaaa</p>
<h2>Referencias</h2>
<ul>
<li><a href="http://www.compuglobalhipermega.net/mysql/instalacion-configuracion-sphinx/">http://www.compuglobalhipermega.net/mysql/instalacion-configuracion-sphinx/</a></li>
<li><a href="http://www.compuglobalhipermega.net/mysql/ejemplo-rfc-sphinx/">http://www.compuglobalhipermega.net/mysql/ejemplo-rfc-sphinx/</a></li>
<li><a href="http://www.sphinxsearch.com/forum/view.html?id=367">http://www.sphinxsearch.com/forum/view.html?id=367</a></li>
</ul>Instalacion y configuración de QNOTIFIER en Debian y CentOS2009-06-11T11:39:06+02:002009-06-11T11:39:06+02:00BhEaNtag:pornohardware.com,2009-06-11:/2009/06/11/instalacion-y-configuracion-de-qnotifier-en-debian-y-centos/<p>QNotifier es una aplicación desarrollada en Ruby para monitorizar servidores desde un iPhone / iPad (con avisos push).</p>
<p>Este manual explica la instalacion del servicio qnotifier en cada servidor que queramos monitorizar, por lo que partimos de la base de que ya tenemos la aplicación qnotifier instalada en el iPhone / Pad que vamos a utilizar (aplicación disponible en la App Store).</p>
<p>QNotifier es una aplicación desarrollada en Ruby para monitorizar servidores desde un iPhone / iPad (con avisos push).</p>
<p>Este manual explica la instalacion del servicio qnotifier en cada servidor que queramos monitorizar, por lo que partimos de la base de que ya tenemos la aplicación qnotifier instalada en el iPhone / Pad que vamos a utilizar (aplicación disponible en la App Store).</p>
<p>Una vez instalada la aplicación desde la App Store en el iPhone (como es nuestro caso), seleccionamos `Add server', lo que añadirá un nuevo registro para el servidor, y le asignará un código. Este código es el que usaremos más adelante para que el servicio de QNotifier de nuestro servidor <em>reporte</em> los datos de monitorización corresponientes.</p>
<p>No hay que confundir la aplicación QNotifier del iPhone (que es la que muestra los datos de cada servidor) con la aplicación QNotifier que instalaremos en cada servidor que queramos monitorizar (que es la que enviará los datos al QNotifier de nuestro iPhone).</p>
<p>La instalacion en el servidor es similar en cualquier sistema Linux, por lo que aunque el manual está orientado a la instalacion en Debian y en Centos, debería ser similar en cualquier otra distribución que queramos.</p>
<p>En primer lugar, debemos instalar el paquete ruby, obviamente... ;)
Para hacerlo de la forma más sencilla y manejable posible, lo haremos desde un repositorio para yum/apt, de forma que su instalacion, actualizacion o eliminacion en el futuro sean igualmente sencillas.</p>
<h2>Instalacion en Debian:</h2>
<p>Para añadir el repositorio que contiene los paquetes de Ruby necesarios para instalar QNotifier, editamos el archivo <code>/etc/apt/sources.list</code> y añadimos estas lineas al final:</p>
<div class="highlight"><pre><span></span><code><span class="c"># Ruby</span>
<span class="k">deb</span> <span class="s">http://debgem.com/apt</span> <span class="kp">debian-4.0</span> <span class="kp">rubyforge</span>
</code></pre></div>
<p>Importamos la firma GPG del servidor para la verificacion de los paquetes:</p>
<div class="highlight"><pre><span></span><code>$ wget -q http://debgem.com/apt/debgem.gpg -O- <span class="p">|</span> sudo apt-key add -
</code></pre></div>
<p>Después, actualizamos la lista de paquetes con los del nuevo repositorio:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get update
</code></pre></div>
<p>E instalamos los paquetes necesarios (es importante instalar todos estos paquetes, ya que sin ellos no podremos instalar Qnotifier correctamente):</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install ruby1.8 ruby1.8-dev rubygems libopenssl-ruby1.8
</code></pre></div>
<p>Una vez instalados, desde la aplicación gem de Ruby, instalamos la <em>gema</em> del QNotifier:</p>
<div class="highlight"><pre><span></span><code>$ sudo gem install qnotifier
</code></pre></div>
<p>Ya solo falta registrar el servicio (explicado más adelante en este manual, en la parte de <em>configuracion</em>)</p>
<h2>Instalacion en Centos:</h2>
<p>Añadimos el repositorio correspondiente, creando el archivo <code>/etc/yum.repos.d/rubyworks.repo</code>, y añadimos lo siguiente:</p>
<div class="highlight"><pre><span></span><code><span class="err">[rubyworks]</span>
<span class="na">name</span><span class="o">=</span><span class="s">RubyWorks</span>
<span class="na">baseurl</span><span class="o">=</span><span class="s">http://rubyworks.rubyforge.org/redhat/$releasever/RPMS/$basearch</span>
<span class="na">enabled</span><span class="o">=</span><span class="s">1</span>
<span class="na">gpgcheck</span><span class="o">=</span><span class="s">1</span>
<span class="na">gpgkey</span><span class="o">=</span><span class="s">http://rubyworks.rubyforge.org/RubyWorks.GPG.key</span>
<span class="na">priority</span><span class="o">=</span><span class="s">1</span>
</code></pre></div>
<p>Después, actualizamos la lista de paquetes con los del nuevo repositorio:</p>
<div class="highlight"><pre><span></span><code>$ sudo yum update
</code></pre></div>
<p>E instalamos los paquetes necesarios:</p>
<div class="highlight"><pre><span></span><code>$ sudo yum install ruby ruby-devel ruby-irb ruby-rdoc ruby-libs
</code></pre></div>
<p>Ahora instalamos rubygems para poder instalar la <em>gema</em> del QNotifier (desde <code>/usr/src</code>)</p>
<div class="highlight"><pre><span></span><code>$ wget http://rubyforge.org/frs/download.php/45905/rubygems-1.3.1.tgz
$ tar xvf rubygems-1.3.1.tgz
$ <span class="nb">cd</span> rubygems-1.3.1
$ ruby setup.rb
</code></pre></div>
<p>Y una vez instalado, desde la aplicación gem de Ruby, instalamos la <em>gema</em> del QNotifier:</p>
<div class="highlight"><pre><span></span><code>sudo gem install qnotifier
</code></pre></div>
<p>Si no ha habidfo ningún problema, la gema quedaría ya instalada ...</p>
<h2>Configuración y registro del servicio</h2>
<p>Ahora que ya tenemos la aplicación instalada en los servidores que queremos monitorizar, iniciamos el servicio:</p>
<div class="highlight"><pre><span></span><code>$ sudo qnotifier start
</code></pre></div>
<p>La aplicación nos pedirá el codigo de registro que nos ha dado el iPhone/iPad a la hora de añadir el servidor, y después preguntará si queremos que el servicio se inicie automaticamente al arrancar el servidor. Seleccionamos <code>YES</code> y listo, nuestro servidor empezará a enviar la informacioń de monitorización a nuestro <em>iDevice</em>.</p>
<p>Para configurar qué servicios queremos monitorizar, las opciones de cada <em>plugin</em>, etc... podemos editar el archivo <code>/var/lib/qnotifier/qnotifier_config.yml</code></p>
<p>Por ejemplo, podemos activar la comprobación de <strong>mysql</strong> para verificar el estado del servidor de base de datos. Para hacerlo, debemos instalar primero la <em>gema</em> de mysql:</p>
<div class="highlight"><pre><span></span><code>$ sudo gem install mysql
</code></pre></div>
<p>Editamos el archivo <code>/var/lib/qnotifier/qnotifier_config.yml</code> y rellenamos la parte del plugin <code>mysql</code> con los valores necesarios:</p>
<div class="highlight"><pre><span></span><code><span class="c1"># The MySQL built-in plugin</span>
<span class="nt">Mysql</span><span class="p">:</span>
<span class="c1"># Enabled, set to either true or false</span>
<span class="nt">enabled</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">true</span>
<span class="nt">username</span><span class="p">:</span> <span class="s">"username"</span>
<span class="nt">password</span><span class="p">:</span> <span class="s">"password"</span>
<span class="c1"># The name of the mysqladmin binary</span>
<span class="nt">mysqladmin</span><span class="p">:</span> <span class="s">"mysqladmin"</span>
<span class="c1"># Uncomment and edit to set a remote host</span>
<span class="nt">hostname</span><span class="p">:</span> <span class="s">"localhost"</span>
<span class="c1"># MySQL Port if not localhost, must be used with hostname above</span>
<span class="nt">port</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">3306</span>
</code></pre></div>
<p>Y listo...
Podemos ver qué informacion se enviará a nuestro <em>iDevice</em> con el comando:</p>
<div class="highlight"><pre><span></span><code>$ sudo qnotifier debug
</code></pre></div>
<p>Ahora ya deberíamos tener nuestro servidor informando a nuestro iPhone/iPad mediante push de la carga, memoria, uso de disco duro, base de datos, etc...</p>
<p>Que uds. lo disfruten!</p>
<p>Alaaaaaaaaaaaaaaaaaaaaaaaaaa</p>
<h2>Referencias</h2>
<ul>
<li><a href="http://qnotifier.com/">http://qnotifier.com/</a></li>
<li><a href="http://rubygems.org/gems/qnotifier">http://rubygems.org/gems/qnotifier</a></li>
<li><a href="http://www.pinguinosycia.com/instalar-ruby-on-rails-en-centos/">http://www.pinguinosycia.com/instalar-ruby-on-rails-en-centos/</a></li>
<li><a href="http://debgem.com/usage">http://debgem.com/usage</a></li>
</ul>