<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" version="2.0">

<channel>
	<title>tail -f | sysadmintail -f | sysadmin</title>
	
	<link>http://www.tail-f.com.ar</link>
	<description>Noticias y recursos para sysadmins Unix</description>
	<lastBuildDate>Mon, 28 Nov 2011 21:44:41 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/Tail-fSysadmin" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="tail-fsysadmin" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Resolver problema con la resolución de un monitor ViewSonic con nVidia en Linux</title>
		<link>http://www.tail-f.com.ar/sistemas-operativos/gnu-linux/resolver-problema-con-la-resolucion-de-un-monitor-viewsonic-con-nvidia-en-linux.html</link>
		<comments>http://www.tail-f.com.ar/sistemas-operativos/gnu-linux/resolver-problema-con-la-resolucion-de-un-monitor-viewsonic-con-nvidia-en-linux.html#comments</comments>
		<pubDate>Mon, 28 Nov 2011 21:26:01 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[GNU/Linux]]></category>
		<category><![CDATA[Placa de video]]></category>
		<category><![CDATA[EDID]]></category>
		<category><![CDATA[HorizSync]]></category>
		<category><![CDATA[LCD]]></category>
		<category><![CDATA[nVidia]]></category>
		<category><![CDATA[VertRefresh]]></category>
		<category><![CDATA[ViewSonic]]></category>
		<category><![CDATA[Xorg]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=464</guid>
		<description><![CDATA[Resumen Un monitor ViewSonic VG2021wm y una placa de video nVidia GeForce 6500 dejan de entenderse espontáneamente en Linux Mint y el Xorg pasa a funcionar sólo en modo 640&#215;480. ¿La solución? Deshabilitar el uso de EDID y configurar manualmente &#8230;<p class="read-more"><a href="http://www.tail-f.com.ar/sistemas-operativos/gnu-linux/resolver-problema-con-la-resolucion-de-un-monitor-viewsonic-con-nvidia-en-linux.html">Read more &#187;</a></p>]]></description>
				<content:encoded><![CDATA[<div id="attachment_472" class="wp-caption alignright" style="width: 210px"><a href="http://www.tail-f.com.ar/wp-content/uploads/xorg.jpg"><img class="size-full wp-image-472" title="X.Org" src="http://www.tail-f.com.ar/wp-content/uploads/xorg.jpg" alt="X.Org" width="200" height="131" /></a><p class="wp-caption-text">X.Org</p></div>
<p><strong>Resumen</strong></p>
<p>Un monitor ViewSonic VG2021wm y una placa de video nVidia GeForce 6500 dejan de entenderse espontáneamente en Linux Mint y el Xorg pasa a funcionar sólo en modo 640&#215;480. ¿La solución? Deshabilitar el uso de EDID y configurar manualmente los datos del monitor en el xorg.conf.</p>
<p><strong>Desarrollo</strong></p>
<p>Ayer me sucedió algo muy raro. Hace varios meses vengo usando <a href="http://www.linuxmint.com/">Linux Mint</a> sin mayores inconvenientes en mi máqunia. Cuando ayer fui a encender la máquina (sin que mediara ningún cambio extraño, ningún update de los drivers de la placa de video ni ninguna instalación de software), el X iniciaba sesión solamente en resolución 640&#215;480. Teniendo un monitor de 20&#8243;, cuya resolución óptima es de 1680&#215;1050, se darán cuenta que la imagen era espantosa: no entraba nada en la pantalla.</p>
<p>Después de varias horas sin entender bien cuál era el problema, postear en el foro de Linux Mint sin respuesta, y buscar en Internet, me puse a revisar los logs del X y encontré que mencionaba errores para leer el EDID. Por ejemplo:</p>
<pre>Unable to get display device CRT-0's EDID; cannot compute DPI</pre>
<p>¿Qué es el EDID? <a href="http://en.wikipedia.org/wiki/Extended_display_identification_data">Extended display identification data</a>, es una estructura de datos que ofrecen los dispositivos de visualización (ej.: los monitores) y que permiten, por ejemplo, a una placa de video conocer sus cualidades. De esta manera, la operatoria normal habría sido que mi placa de video obtuviera los datos del monitor de su EDID y conforme a ello me diera las opciones adecuadas para configurar mi pantalla. Más concretamente, el Xorg lo que hace es obtener a través de la placa de video, entre otros datos, la frecuencia horizontal (HorizSync) y la tasa de refresco vertical (VertRefresh) (para más información sobre qué es cada una de estas variables, pueden consultar <a href="http://en.tldp.org/HOWTO/XFree86-Video-Timings-HOWTO/basic.html">esta página</a>).</p>
<p>La cuestión es que de buenas a primeras, el Xorg dejó de poder leer el EDID de mi monitor y por eso levantaba con los datos default para un monitor CRT (por cierto, entre las cosas que aprendí ayer, el driver de nVidia le pone de nombre &#8220;CRT&#8221; a cualquier dispositivo que se conecte al puerto VGA, no tiene nada que ver con lo que efectivamente esté conectado). Eso quiere decir que tomaba un HorizSync y un VertRefresh que solamente eran compatibles con una resolución de 640&#215;480@50 Hz.</p>
<p>¿Por qué pasa esto? La verdad, no lo sé a ciencia cierta. Encontré a <a href="http://ubuntuforums.org/archive/index.php/t-1213003.html">este usuario</a> que le pasó lo mismo, y levantando de un Live CD se dio cuenta que no era un problema de configuración, entonces lo resolvió cambiando su cable DVI por un cable VGA con un adaptador. Yo comprobé lo mismo, el problema no estaba en la configuración de mi Xorg, pero como yo sólo tenía cable VGA, probé cambiandolo por otro cable VGA, pero no hizo diferencia. Entonces seguí buscando y llegué a <a href="http://ubuntuforums.org/archive/index.php/t-1470168.html">este otro post</a> donde alguien lo resolvió sencillamente cambiando los HorizSync y VertRefresh en el xorg.conf.</p>
<p>Me bajé el manual de mi monitor (ViewSonic VG2021wm) y busqué los datos correspondientes (HorizSync y VertRefresh), y los puse en el xorg.conf. Este tipo de configuración manual del Xorg es lo que viene a evitar el EDID. El tema es que al reinicar el X, el Xorg seguía intentando leer el EDID y como no podía, seguía dando el mismo problema.</p>
<p>Finalmente, y casi por casualidad, me di cuenta que el nvidia-xconfig tenía unos parámetros para que configurara el xorg.conf indicándole al Xorg ignorar el EDID. Entonces ejecuté el siguiente comando:</p>
<pre>sudo nvidia-xconfig --no-use-edid --no-use-edid-dpi --no-use-edid-freqs --mode=1680x1050</pre>
<p>Y con eso me quedó generado el siguiente xorg.conf</p>
<pre># nvidia-xconfig: X configuration file generated by nvidia-xconfig
# nvidia-xconfig:  version 280.13  (pbuilder@cake)  Mon Aug  8 15:37:15 UTC 2011

Section "ServerLayout"
    Identifier     "Layout0"
    Screen      0  "Screen0" 0 0
    InputDevice    "Keyboard0" "CoreKeyboard"
    InputDevice    "Mouse0" "CorePointer"
EndSection

Section "Files"
EndSection

Section "InputDevice"

    # generated from default
    Identifier     "Mouse0"
    Driver         "mouse"
    Option         "Protocol" "auto"
    Option         "Device" "/dev/psaux"
    Option         "Emulate3Buttons" "no"
    Option         "ZAxisMapping" "4 5"
EndSection

Section "InputDevice"

    # generated from default
    Identifier     "Keyboard0"
    Driver         "kbd"
EndSection

Section "Monitor"

    Identifier     "Monitor0"
    VendorName     "Unknown"
    ModelName      "LCD-1"
    <strong>HorizSync 24.0 - 82.0</strong>
    <strong>VertRefresh 50.0 - 85.0</strong>
    Option         "DPMS"
EndSection

Section "Device"
    Identifier     "Device0"
    Driver         "nvidia"
    VendorName     "NVIDIA Corporation"
EndSection
Section "Screen"
    Identifier     "Screen0"
    Device         "Device0"
    Monitor        "Monitor0"
    DefaultDepth    24
    <strong>Option "UseEdidFreqs" "False"</strong>
    <strong>Option "UseEdid" "False"</strong>
    <strong>Option "UseEdidDpi" "False"</strong>
    SubSection     "Display"
        Depth       24
        Modes      "1680x1050" "1680x1050_60.00"
    EndSubSection
EndSection</pre>
<p>Si ven los parámetros resaltados, en la sección Monitor defino el HorizSync y el VertRefresh. Y luego en la sección Screen, los parámetros que evitan que se use el EDID (anteriormente existía una opción IgnoreEDID que fue deprecada, ver los comentarios de <a href="http://baudizm.blogsome.com/2005/09/27/ignoring-edid-to-impose-higher-resolution/">este artículo</a>).</p>
<p>Una vez modificado el xorg.conf solamente tuve que reiniciar el X y volvió a la normalidad. Después tuve que pelearme un rato con GDM para volver a configurar la resolución adecuada (1680&#215;1050@60 Hz) utilizando nvidia-settings. Pero esto puede tener que ver con todas las vueltas que dí antes de encontrar la solución.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/sistemas-operativos/gnu-linux/resolver-problema-con-la-resolucion-de-un-monitor-viewsonic-con-nvidia-en-linux.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Sencillo parser para Apache mod_status en Python</title>
		<link>http://www.tail-f.com.ar/servicios/httpd/apache-httpd-servicios/sencillo-parser-para-apache-mod_status-en-python.html</link>
		<comments>http://www.tail-f.com.ar/servicios/httpd/apache-httpd-servicios/sencillo-parser-para-apache-mod_status-en-python.html#comments</comments>
		<pubDate>Sun, 31 Jul 2011 01:01:46 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[Apache]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[mod_status]]></category>
		<category><![CDATA[parser]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=455</guid>
		<description><![CDATA[Cuánto hace que no actualizo este blog!! Hoy estuve jugando un poco con Python y me puse a hacer un pequeño script que supongo que a otros les podrá servir como base para hacer algo más interesante. Precisamente, tengo planes &#8230;<p class="read-more"><a href="http://www.tail-f.com.ar/servicios/httpd/apache-httpd-servicios/sencillo-parser-para-apache-mod_status-en-python.html">Read more &#187;</a></p>]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.tail-f.com.ar/wp-content/uploads/apache1.gif"><img class="size-full wp-image-37 alignright" title="apache1" src="http://www.tail-f.com.ar/wp-content/uploads/apache1.gif" alt="" width="210" height="210" /></a></p>
<p>Cuánto hace que no actualizo este blog!! Hoy estuve jugando un poco con Python y me puse a hacer un pequeño script que supongo que a otros les podrá servir como base para hacer algo más interesante. Precisamente, tengo planes para hacer algo más interesante, pero como recién están en veremos, les voy pasando esta pequeña base a ver si alguien me gana de mano <img src='http://www.tail-f.com.ar/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Como muchos sabrán, Apache (y otros web servers) tiene un módulo llamado <a href="http://httpd.apache.org/docs/2.2/mod/mod_status.html">mod_status</a> que nos permite ver en tiempo real el estado del servidor (los requests que se están procesando, el uso del CPU, el estado de las conexiones, etc.). Esta información puede ser muy útil para hacer diagnósticos cuando está habiendo algún tipo de problema, para hacer monitoreo, etc. El módulo nos muestra una página web con la información y tiene dos interfaces: una está pensada para ser vista por seres humanos y otra para ser consultada por scripts (para ver esta segunda sólo hace falta pasarle el parámetro &#8220;?auto&#8221; en la URL). El problema es que esta segunda interfaz no nos muestra a qué dominios (virtual hosts) están dirigidos los requests que se están procesando (o si hay forma de que lo muestre yo no la encontré). Entonces me puse a hacer un sencillo script en Python para parsear la página &#8220;para seres humanos&#8221;.</p>
<p>Por suerte Python nos ofrece muchas herramientas muy útiles para este tipo de cosas, así que no me tuve que esforzar demasiado. En este caso utilicé <a href="http://docs.python.org/library/urllib2.html">urllib2</a> para acceder a la página de mod_status y <a href="http://www.crummy.com/software/BeautifulSoup/">BeautifulSoup</a> para parsear el HTML. Por si no lo conocen, BeautifulSoup es un muy poderoso parser para XML/HTML hecho en Python. No viene con el código fuente sino que hay que instalarlo, pero hacerlo es muy fácil:</p>
<p>En Debian/Ubuntu:</p>
<pre>apt-get install python-beautifulsoup</pre>
<p>En CentOS/RedHat:</p>
<pre>yum install python-BeautifulSoup</pre>
<p>Con easy_install:</p>
<pre>easy_install BeautifulSoup</pre>
<p>El código tiene una clase Status que es la que hace la magia y una función main() que utiliza la clase para parsear una URL e imprimir algunos datos a modo de ejemplo.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">import</span> <span class="kw3">sys</span><br />
<span class="kw1">import</span> <span class="kw3">urllib2</span><br />
<span class="kw1">from</span> <span class="kw3">operator</span> <span class="kw1">import</span> itemgetter<br />
<span class="kw1">from</span> BeautifulSoup <span class="kw1">import</span> BeautifulSoup</p>
<p><span class="kw1">class</span> Status <span class="br0">&#40;</span><span class="kw2">object</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; _url = <span class="kw2">None</span></p>
<p>&nbsp; &nbsp; <span class="kw1">def</span> <span class="kw4">__init__</span> <span class="br0">&#40;</span><span class="kw2">self</span>, url<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">self</span>._url = url</p>
<p>&nbsp; &nbsp; <span class="kw1">def</span> fetch <span class="br0">&#40;</span><span class="kw2">self</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw3">urllib2</span>.<span class="me1">urlopen</span><span class="br0">&#40;</span><span class="kw2">self</span>._url<span class="br0">&#41;</span>.<span class="me1">read</span><span class="br0">&#40;</span><span class="br0">&#41;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">def</span> parse <span class="br0">&#40;</span><span class="kw2">self</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; html = <span class="kw2">self</span>.<span class="me1">fetch</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; soup = BeautifulSoup<span class="br0">&#40;</span>html<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; status = <span class="br0">&#123;</span><span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; status<span class="br0">&#91;</span><span class="st0">&#8216;server_info&#8217;</span><span class="br0">&#93;</span> = <span class="br0">&#91;</span>i.<span class="kw3">string</span>.<span class="me1">strip</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="kw1">for</span> i <span class="kw1">in</span> soup.<span class="me1">findAll</span><span class="br0">&#40;</span><span class="st0">&#8216;dt&#8217;</span><span class="br0">&#41;</span><span class="br0">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; status<span class="br0">&#91;</span><span class="st0">&#8216;requests&#8217;</span><span class="br0">&#93;</span> = <span class="br0">&#91;</span><span class="br0">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; requests = soup.<span class="me1">find</span><span class="br0">&#40;</span><span class="st0">&#8216;table&#8217;</span><span class="br0">&#41;</span>.<span class="me1">findAll</span><span class="br0">&#40;</span><span class="st0">&#8216;tr&#8217;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; keys = <span class="br0">&#91;</span>i.<span class="kw3">string</span> <span class="kw1">for</span> i <span class="kw1">in</span> requests.<span class="me1">pop</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span><span class="br0">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> tr <span class="kw1">in</span> requests:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; req = <span class="br0">&#123;</span><span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> n, td <span class="kw1">in</span> <span class="kw2">enumerate</span><span class="br0">&#40;</span>tr<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; req<span class="br0">&#91;</span>keys<span class="br0">&#91;</span>n<span class="br0">&#93;</span><span class="br0">&#93;</span> = td.<span class="kw3">string</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; status<span class="br0">&#91;</span><span class="st0">&#8216;requests&#8217;</span><span class="br0">&#93;</span>.<span class="me1">append</span><span class="br0">&#40;</span>req<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> status</p>
<p><span class="kw1">def</span> main <span class="br0">&#40;</span>argv<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="kw2">len</span><span class="br0">&#40;</span>argv<span class="br0">&#41;</span> &lt; <span class="nu0">2</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;Usage %s &quot;</span>%argv<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">1</span></p>
<p>&nbsp; &nbsp; status = Status<span class="br0">&#40;</span>argv<span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; data = status.<span class="me1">parse</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;SERVER INFORMATION&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;==================&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">for</span> v <span class="kw1">in</span> data<span class="br0">&#91;</span><span class="st0">&#8216;server_info&#8217;</span><span class="br0">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">print</span> v</p>
<p>&nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;REQUESTS BY VHOST&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;=================&quot;</span><br />
&nbsp; &nbsp; entries = <span class="br0">&#91;</span>i<span class="br0">&#91;</span><span class="st0">&#8216;VHost&#8217;</span><span class="br0">&#93;</span> <span class="kw1">for</span> i <span class="kw1">in</span> data<span class="br0">&#91;</span><span class="st0">&#8216;requests&#8217;</span><span class="br0">&#93;</span><span class="br0">&#93;</span><br />
&nbsp; &nbsp; requests = <span class="kw2">sorted</span><span class="br0">&#40;</span><span class="br0">&#91;</span><span class="br0">&#40;</span>entries.<span class="me1">count</span><span class="br0">&#40;</span>i<span class="br0">&#41;</span>, i<span class="br0">&#41;</span> <span class="kw1">for</span> i <span class="kw1">in</span> <span class="kw2">list</span><span class="br0">&#40;</span><span class="kw2">set</span><span class="br0">&#40;</span>entries<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#93;</span>, reverse=<span class="kw2">True</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;<span class="es0">\n</span>&quot;</span>.<span class="me1">join</span><span class="br0">&#40;</span><span class="br0">&#91;</span><span class="st0">&quot;%d: %s&quot;</span>%<span class="br0">&#40;</span>a,b<span class="br0">&#41;</span> <span class="kw1">for</span> a,b <span class="kw1">in</span> requests<span class="br0">&#93;</span><span class="br0">&#41;</span></p>
<p><span class="kw1">if</span> __name__ == <span class="st0">&quot;__main__&quot;</span>:<br />
&nbsp; &nbsp; <span class="kw3">sys</span>.<span class="me1">exit</span><span class="br0">&#40;</span>main<span class="br0">&#40;</span><span class="kw3">sys</span>.<span class="me1">argv</span><span class="br0">&#41;</span><span class="br0">&#41;</span></div>
<p>La forma de uso es:</p>
<pre>python status.py "http://localhost/server-status"</pre>
<p>Y en este caso la salida del script es algo así:</p>
<pre>SERVER INFORMATION
==================
Server Version: Apache/2.2.19 (Unix) mod_ssl/2.2.19 OpenSSL/0.9.8e-fips-rhel5 DAV/2
Server Built: May 26 2011 15:14:47
Current Time: Sunday, 31-Jul-2011 00:53:59 ART
Restart Time: Saturday, 30-Jul-2011 12:07:12 ART
Parent Server Generation: 0
Server uptime:  12 hours 46 minutes 47 seconds
Total accesses: 407813 - Total Traffic: 3.7 GB
CPU Usage: u2.05 s3.23 cu52 cs0 - .125% CPU load
8.86 requests/sec - 85.0 kB/second - 9.6 kB/request
10 requests currently being processed, 8 idle workers
REQUESTS BY VHOST
=================
9: www.tail-f.com.ar
5: www.otro-dominio.com.ar
4: www.not-a-domain.com.ar
3: www.algunlado.com.ar
2: subdominio.dominio.com.ar
1: www.pepe.com.ar
1: www.no-votes-a-macri.com.ar
1: www.asd.com.ar
1: localhost</pre>
<p>Obviamente esto no es una aplicación funcional, sino un ejemplo que espero que les sirva para hacer algo más copado. Yo seguiré jugando y si hago algo un poco más interesante, ya se los mostraré.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/servicios/httpd/apache-httpd-servicios/sencillo-parser-para-apache-mod_status-en-python.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>FLISOL 2011</title>
		<link>http://www.tail-f.com.ar/noticias/flisol-2011.html</link>
		<comments>http://www.tail-f.com.ar/noticias/flisol-2011.html#comments</comments>
		<pubDate>Wed, 06 Apr 2011 21:13:20 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[Noticias]]></category>
		<category><![CDATA[Eventos]]></category>
		<category><![CDATA[FLiSoL]]></category>
		<category><![CDATA[Software Libre]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=446</guid>
		<description><![CDATA[Este sábado 9 de abril es el Festival Latinoamericano de Instalación de Software Libre (FLISoL), el evento de difusión de Software Libre más grande de Latinoamérica. Como indica su sitio web, su principal objetivo es promover el uso del software &#8230;<p class="read-more"><a href="http://www.tail-f.com.ar/noticias/flisol-2011.html">Read more &#187;</a></p>]]></description>
				<content:encoded><![CDATA[<p>Este sábado 9 de abril es el <a href="http://www.installfest.info/"><strong>Festival Latinoamericano de Instalación de Software Libre</strong> (<strong>FLISoL</strong>)</a>, el evento de difusión de <a href="http://es.wikipedia.org/wiki/Software_libre">Software Libre</a> más grande de Latinoamérica.</p>
<div id="attachment_449" class="wp-caption aligncenter" style="width: 610px"><a href="http://www.tail-f.com.ar/wp-content/uploads/headbox2011.png"><img class="size-full wp-image-449" title="FLiSoL - Festival Latinoamericano de Software Libre" src="http://www.tail-f.com.ar/wp-content/uploads/headbox2011.png" alt="FLiSoL - Festival Latinoamericano de Software Libre" width="600" height="300" /></a><p class="wp-caption-text">Festival Latinoamericano de Software Libre</p></div>
<p>Como indica su sitio web, su principal objetivo es promover el uso del software libre, dando a conocer al público en general su filosofía, alcances, avances y desarrollo. A tal fin, las diversas comunidades locales de software libre (en cada país/ciudad/localidad), organizan simultáneamente eventos en los que se instala, de manera gratuita y totalmente legal, software libre en las computadoras que llevan los asistentes. Además, en forma paralela, se ofrecen charlas, ponencias y talleres, sobre temáticas locales, nacionales y latinoamericanas en torno al Software Libre, en toda su gama de expresiones: artística, académica, empresarial y social.</p>
<p>Particularmente, nuestro amigo <a href="http://blog.exodica.com.ar/">Exos</a> estará participando en el evento a realizarse en Lanús, organizado por <a href="http://www.lanux.org.ar/">LANUX</a> (Grupo de Usuarios de Linux de Lanús). Allí el evento será este sábado 9 de abril de 2011 de 10 a 16:30 horas en la Universidad Argentina “John. F. Kennedy” Av. Hipólito Yrigoyen 4651 -Partido de Lanús.</p>
<p>Este tipo de encuentros son una excelente oportunidad tanto para usuarios avanzados de Linux que quieran encontrarse con otros entusiastas, como para usuarios básicos de computadoras que no conozcan nada sobre Software Libre y quieran conocer de qué se trata de la mano de usuarios experimentados, con buena onda y dispuestos a ayudar.</p>
<p>Mapa, registración y más información en el sitio de <a href="http://www.lanux.org.ar/flisol-2011/">FLiSoL en LANUX</a>.</p>
<p><strong>Links</strong></p>
<ul>
<li><a href="http://www.installfest.info/">Sitio web de FLiSoL 2011</a></li>
<li><a href="http://www.lanux.org.ar/flisol-2011/">Sitio web de FLiSoL 2011 en LANUX</a></li>
<li><a href="http://www.lanux.org.ar/">Sitio oficial de LANUX</a></li>
<li><a href="http://www.periodicotribuna.com.ar/8669-flisol-instalando-software-libre-en-tu-computadora.html">Nota sobre FLiSoL en Periódico Tribuna</a> por <a href="http://blog.exodica.com.ar/">Exos</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/noticias/flisol-2011.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Nginx como Proxy Reverso en servidor Directadmin</title>
		<link>http://www.tail-f.com.ar/servicios/httpd/nginx/nginx-como-proxy-reverso-en-servidor-directadmin.html</link>
		<comments>http://www.tail-f.com.ar/servicios/httpd/nginx/nginx-como-proxy-reverso-en-servidor-directadmin.html#comments</comments>
		<pubDate>Sat, 18 Sep 2010 04:04:05 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[nginx]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[Nginx]]></category>
		<category><![CDATA[proxy reverso]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=434</guid>
		<description><![CDATA[En esta oportunidad voy a explicar cómo instalar Nginx como proxy reverso en un servidor de hosting con Directadmin. ¿Qué es un proxy reverso? Un proxy reverso en este caso es, básicamente, un servidor web que se interpone como una &#8230;<p class="read-more"><a href="http://www.tail-f.com.ar/servicios/httpd/nginx/nginx-como-proxy-reverso-en-servidor-directadmin.html">Read more &#187;</a></p>]]></description>
				<content:encoded><![CDATA[<div id="attachment_37" class="wp-caption alignright" style="width: 310px"><strong><a href="../wp-content/uploads/apache1.gif"><img class="size-medium wp-image-37  " title="Apache" src="/wp-content/uploads/apache1-300x300.gif" alt="Apache" width="300" height="300" /></a></strong><p class="wp-caption-text">Apache</p></div>
<p>En esta oportunidad voy a explicar cómo instalar Nginx como proxy reverso en un servidor de hosting con Directadmin.</p>
<p><strong>¿Qué es un proxy reverso?</strong></p>
<p>Un proxy reverso en este caso es, básicamente, un servidor web que se interpone como una capa entre el cliente y un backend, de manera de optimizar la conexión. Típicamente el proxy es un servidor muy liviano que funciona de frontend, atiende las peticiones de los clientes HTTP y deriva el procesamiento en un backend que podría ser un servidor Apache. Según la configuración que apliquemos, un proxy nos permite introducir mayor seguridad en nuestra red, hacer balanceo de carga, hacer cache, etc.</p>
<p>También optimiza el manejo de memoria. Pensemos que Apache lanza un thread o proceso por cada nuevo cliente, el cual se cierra recién cuando termina la transferencia de datos. Si el cliente tiene una conexión lenta, por más que Apache funcione rápido, el proceso queda corriendo hasta que se terminen de enviar los datos. Un frontend liviano como Nginx nos permite que el proceso que espere al cliente sea mucho más liviano que uno de Apache.</p>
<p>Por último, como indican en <a href="http://systemadmin.es/2009/08/slowloris-ataque-de-denegacion-de-servicio-para-apache-1x-y-2x">sysadmin.es</a>, un proxy Nginx nos sirve para prevenir ataques de denegación de servicio utilizando <a href="http://ha.ckers.org/slowloris/">slowloris</a>.</p>
<p><strong>Un proxy reverso en un servidor de hosting</strong></p>
<div id="attachment_437" class="wp-caption alignleft" style="width: 131px"><a href="../wp-content/uploads/nginx.gif"><img class="size-full wp-image-437  " title="nginx" src="/wp-content/uploads/nginx.gif" alt="Nginx" width="121" height="32" /></a><br />
<p class="wp-caption-text">Nginx</p></div>
<p>Los proxies se suelen utilizar en arquitecturas para servir sitios de alta demanda. En esos casos es común, por ejemplo, hacer que Apache sirva el contenido dinámico y un servidor más liviano (lighttpd o nginx) sirva contenido estático. Pero en un servidor de hosting esto no es tan sencillo, pues al alojarse varios sitios en un mismo equipo nuestra configuración debe ser lo más genérica posible para que sirva a la mayor parte de nuestros clientes. Como veremos, podemos definir algún tipo de cache, pero también tiene que ser bastante genérico para no causar problemas. Además tenemos que pensar en la integración con el panel de control que estemos usando. Yo uso Directadmin y este panel no tiene (aún) una integración nativa con otro web server que no sea Apache.</p>
<p><strong>Nginx + Apache + Directadmin</strong></p>
<p>La opción que les presento es para utilizar Nginx como proxy reverso, manejando las conexiones de los clientes y haciendo un muy básico cache del contenido estático. La guía está pensada para CentOS, pero en otros sistemas operativos no debería ser muy distinto.</p>
<p>Primero instalamos Nginx. El proceso es muy sencillo.</p>
<pre># cd /usr/src
# wget http://nginx.org/download/nginx-0.7.67.tar.gz
# tar zxvf nginx-0.7.67.tar.gz
# cd nginx-0.7.67
# ./configure --prefix=/usr \
              --conf-path=/etc/nginx/nginx.conf \
              --error-log-path=/var/log/nginx/error.log \
              --http-log-path=/var/log/nginx/access.log \
              --pid-path=/var/run/nginx/nginx.pid \
              --lock-path=/var/run/nginx/nginx.lock \
              --with-http_stub_status_module \
              --with-openssl=/usr/lib/openssl
# make &amp;&amp; make install</pre>
<p>Creamos el directorio para guardar el cache de contenido estático:</p>
<pre># mkdir -p /var/tmp/nginx
# chown apache:apache /var/tmp/nginx</pre>
<p>Lo más importante es configurar Nginx. Para ello modificaremos /etc/nginx/nginx.conf para que quede algo similar a esto:</p>
<p><strong>Importante:</strong> reemplazar __SERVER_IP__ por la IP del servidor y __SERVER_HOSTNAME__ por el nombre del servidor.</p>
<pre>user  apache;
worker_processes  1;

events {
    worker_connections  8192;
}

http {
    server_tokens off;

    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    tcp_nopush     on;

    keepalive_timeout  75 20;

    gzip  on;

    server_names_hash_bucket_size 64;
    reset_timedout_connection on;

    client_max_body_size 100m;

    # Main cache data
    proxy_cache_path  /var/tmp/nginx/cache  levels=1:2   keys_zone=staticfilecache:180m  max_size=500m;
    proxy_temp_path /var/tmp/nginx/proxy;
    proxy_connect_timeout 30;
    proxy_read_timeout 120;
    proxy_send_timeout 120;
    proxy_cache_key "$scheme$host$request_uri";

    server {
        listen       __SERVER_IP__:81;
        server_name  __SERVER_HOSTNAME__ _;

        #charset koi8-r;
        charset off;

        access_log off;
        #access_log  /var/log/nginx/access.log  main;

        # Main reverse proxy for most requests
        location / {
                    proxy_set_header Host $host;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

                    proxy_pass              http://__SERVER_IP__;    # apache here

                    client_max_body_size       16m;
                    client_body_buffer_size    128k;

                    #proxy_buffering     off;
                    proxy_buffering     on;  

                    proxy_connect_timeout      90;
                    proxy_send_timeout         90;
                    proxy_read_timeout         120;
                    proxy_buffer_size          8k;
                    proxy_buffers              32 32k;
                    proxy_busy_buffers_size    64k;
                    proxy_temp_file_write_size 64k;

                    error_page              502 503 /50x.html;
        }

        # Proxy cache for static files
        location ~* \.(jpg|png|gif|jpeg|css|js|mp3|wav|swf|mov|doc|pdf|xls|ppt|docx|pptx|xlsx)$ {
                    proxy_set_header Host $host;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

                    proxy_pass              http://__SERVER_IP__;    # apache here

                    client_max_body_size       16m;
                    client_body_buffer_size    128k;

                    #proxy_buffering     off;
                    proxy_buffering     on;  

                    proxy_connect_timeout      90;
                    proxy_send_timeout         90;
                    proxy_read_timeout         120;
                    proxy_buffer_size          8k;
                    proxy_buffers              32 32k;
                    proxy_busy_buffers_size    64k;
                    proxy_temp_file_write_size 64k;

                    # Proxy cache data
                    proxy_cache_valid 200 120m;
                    expires 864000;
                    proxy_cache staticfilecache;

                    error_page              502 503 /50x.html;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /var/www/html;
        }

    }

}</pre>
<p>Por supuesto esta es una configuración básica que debería adaptarse al caso específico. Es importante notar lo siguiente:</p>
<ul>
<li>Nginx escucha en el puerto 81 y Apache en el 80. Esto es importante para no tener que hacer cambios en la configuración de Directadmin.</li>
<li>Se definen 3 Locations. Las primeras dos son proxies que le pasan requests al Apache esuchando en el puerto 80. La segunda aplica solamente a los requests de archivos estáticos y hace un cache en /var/tmp/nginx. Este cache es manejado siguiendo los headers HTTP correspondientes.</li>
</ul>
<p>Ahora necesitamos instalar un módulo de Apache, mod_rpaf, para poder usar el header X-Real-IP.</p>
<pre># cd /usr/src
# wget http://stderr.net/apache/rpaf/download/mod_rpaf-0.6.tar.gz
# tar zxvf mod_rpaf-0.6.tar.gz
# cd mod_rpaf-0.6
# apxs -i -c -n mod_rpaf-2.0.so mod_rpaf-2.0.c</pre>
<p>Y luego agregamos esto al httpd.conf</p>
<pre>
LoadModule rpaf_module /usr/lib/apache/mod_rpaf-2.0.so
RPAFenable On
RPAFsethostname On
RPAFproxy_ips 127.0.0.1 __SERVER_IP__
RPAFheader X-Forwarded-For</pre>
<p>Reemplazando __SERVER_IP__ por la IP del servidor.</p>
<p>También vamos a necesitar un script para el init del Nginx. Como no encontré uno hecho, hice este:</p>
<pre>#!/bin/bash
#
# Name: NginX, tsj5j
#
# Function:     Start up NginX
#
# chkconfig: - 85 15
# description: NginX starter

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

prog="nginx"
nginx=/usr/sbin/nginx

start () {
        echo -n $"Starting $prog: "
        $nginx
        RETVAL=$?
        return $RETVAL
}

stop () {
        echo -n $"Stopping $prog: "
        killproc $nginx
        RETVAL=$?
        return $RETVAL
}

reload () {
        echo -n $"Reloading $prog: "
        killproc $nginx -HUP
        RETVAL=$?
        return $RETVAL
}

case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  restart)
        stop
        sleep 1
        start
        ;;
  reload)
        reload
        ;;
  graceful)
        reload
        ;;
esac

exit $RETVAL;</pre>
<p>Una vez ubicado ese contenido en un archivo /etc/init.d/nginx lo habilitamos</p>
<pre># chkconfig --add nginx
# chkconfig nginx on
# service nginx start</pre>
<p>Y nos falta una única cosa. Tenemos Apache corriendo en el puerto 80 y Nginx en el 81. ¿Cómo hacemos que Nginx atienda las peticiones de nuestros clientes? Creamos una ruta en iptables para que redirija el tráfico del puerto 81 al 80:</p>
<pre># iptables -t nat -A PREROUTING -p tcp -s ! __SERVER_IP__ --dport 80 -j REDIRECT --to-ports 81
# service iptables save</pre>
<p>Reemplazando __SERVER_IP__ por la IP del servidor.</p>
<p>Y listo, ahora nuestro Nginx va a recibir todo el tráfico HTTP y negociar con el Apache para devolverlo a los clientes.</p>
<p><strong>Verificar que atienda Nginx</strong></p>
<p>Comprobar que Nginx esté atendiendo las peticiones en el puerto 80 es muy sencillo de hacer con curl. Por ejemplo, probándolo contra la URL de este blog.</p>
<pre># curl -I http://www.tail-f.com.ar
HTTP/1.1 200 OK
<strong>Server: nginx</strong>
Date: Sat, 18 Sep 2010 04:09:23 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Keep-Alive: timeout=20
Vary: Cookie,Accept-Encoding,User-Agent
X-Pingback: http://www.tail-f.com.ar/xmlrpc.php
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Pragma: no-cache</pre>
<p>Como vemos el servidor que atiende es Nginx.</p>
<p><strong>Referencias:</strong></p>
<ul>
<li><a href="http://nginx.org">Sitio de Nginx</a></li>
<li><a href="http://stderr.net/apache/rpaf/">Sitio de mod_rpaf</a></li>
<li><a href="http://directadmin.com/forum/showthread.php?t=27344">HOWTO: Using Nginx &#8211; best practices!</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/servicios/httpd/nginx/nginx-como-proxy-reverso-en-servidor-directadmin.html/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Ya salió PET: English Translation!</title>
		<link>http://www.tail-f.com.ar/programacion/python/ya-salio-pet-english-translation.html</link>
		<comments>http://www.tail-f.com.ar/programacion/python/ya-salio-pet-english-translation.html#comments</comments>
		<pubDate>Fri, 10 Sep 2010 12:12:39 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[PET]]></category>
		<category><![CDATA[traducciones]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=431</guid>
		<description><![CDATA[Hace unos días comenté la salida del primer número de la revista PET: Python Entre Todos. Como también adelanté en esa oportunidad, se descubrió que se trataba de la única revista de Python en el mundo (activa por lo menos). &#8230;<p class="read-more"><a href="http://www.tail-f.com.ar/programacion/python/ya-salio-pet-english-translation.html">Read more &#187;</a></p>]]></description>
				<content:encoded><![CDATA[<p>Hace unos días comenté la salida del primer número de la revista <a href="http://www.tail-f.com.ar/programacion/python/pet-python-entre-todos-primera-revista-de-python.html">PET: Python Entre Todos</a>. Como también adelanté en esa oportunidad, se descubrió que se trataba de la única revista de Python en el mundo (activa por lo menos). Así que luego de varios días de esfuerzo se tradujo el primer número y salió <a href="http://revista.python.org.ar/1/html-en/">PET: English Translation</a>.</p>
<div>
<div id="attachment_432" class="wp-caption alignnone" style="width: 310px"><a href="http://www.tail-f.com.ar/wp-content/uploads/tapa-nro11.jpg"><img class="size-medium wp-image-432" title="tapa-nro1" src="http://www.tail-f.com.ar/wp-content/uploads/tapa-nro11-300x212.jpg" alt="PET: English Translation" width="300" height="212" /></a><p class="wp-caption-text">PET: English Translation</p></div>
</div>
<p>Los artículos de este número son:</p>
<ul>
<li><a href="http://revista.python.org.ar/1/html-en/pet_first_shot.html">PET First Shot</a></li>
<li><a href="http://revista.python.org.ar/1/html-en/help.html">How you can help PET</a></li>
<li><a href="http://revista.python.org.ar/1/html-en/pyar.html">PyAr, The History</a></li>
<li><a href="http://revista.python.org.ar/1/html-en/hacking_python_s1.html">from gc import commonsense &#8211; Finish Him!</a></li>
<li><a href="http://revista.python.org.ar/1/html-en/processing.html">Painless Concurrency: The multiprocessing Module</a></li>
<li><a href="http://revista.python.org.ar/1/html-en/unittest.html">Introduction to Unit Testing with Python</a></li>
<li><a href="http://revista.python.org.ar/1/html-en/taint.html">Taint Mode in Python</a></li>
<li><a href="http://revista.python.org.ar/1/html-en/dinamismo.html">Applied Dynamism</a></li>
<li><a href="http://revista.python.org.ar/1/html-en/decorators.html">Decorating code (Part 1)</a></li>
<li><a href="http://revista.python.org.ar/1/html-en/web2py.html">Web2Py for Everybody</a></li>
<li><a href="http://revista.python.org.ar/1/html-en/howto.html">How is this magazine made?</a></li>
<li><a href="http://revista.python.org.ar/1/html-en/desafio.html">PET Challenge</a></li>
<li><a href="http://revista.python.org.ar/1/html-en/xkcd.html">A Bit of xkcd</a></li>
</ul>
<p>Como también ya les había adelantado, en este número tuve oportunidad de participar traduciendo dos artículos. <a href="http://revista.python.org.ar/1/html-en/pyar.html">PyAr, The History</a> de <a href="http://www.taniquetil.com.ar/plog/">Facundo Batista</a> y <a href="http://revista.python.org.ar/1/html-en/howto.html">How is this magazine made?</a> de <a href="http://lateral.netmanagers.com.ar/">Roberto Alsina</a>.</p>
<p>Además, aprovechando la ampliación del público de la revista, se ha agregado la posibilidad de hacer <a href="http://python.org.ar/pyar/Donations">donaciones</a> para la comunidad PyAr, de manera de solventar futuras actividades como impresiones del <a href="http://tutorial.python.org.ar/">tutorial de Python</a>, compra de materiales, charlas, etc.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/programacion/python/ya-salio-pet-english-translation.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Notificaciones de mails Prioritarios de Gmail en nuestro escritorio</title>
		<link>http://www.tail-f.com.ar/programacion/python/notificaciones-de-mails-prioritarios-de-gmail-en-nuestro-escritorio.html</link>
		<comments>http://www.tail-f.com.ar/programacion/python/notificaciones-de-mails-prioritarios-de-gmail-en-nuestro-escritorio.html#comments</comments>
		<pubDate>Sat, 04 Sep 2010 18:21:46 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Gmail]]></category>
		<category><![CDATA[IMAP]]></category>
		<category><![CDATA[imaplib]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=423</guid>
		<description><![CDATA[En estos días GMail empezó a implementar la Priority Inbox, o Prioritarios en su versión en castellano. No es nada demasiado novedoso, en realidad es una etiqueta que define a un mensaje como prioritario. Lo más interesante es que Gmail &#8230;<p class="read-more"><a href="http://www.tail-f.com.ar/programacion/python/notificaciones-de-mails-prioritarios-de-gmail-en-nuestro-escritorio.html">Read more &#187;</a></p>]]></description>
				<content:encoded><![CDATA[<div id="attachment_424" class="wp-caption alignright" style="width: 310px"><a href="http://www.tail-f.com.ar/wp-content/uploads/gmail-logo.jpg"><img class="size-medium wp-image-424" title="gmail-logo" src="http://www.tail-f.com.ar/wp-content/uploads/gmail-logo-300x224.jpg" alt="GMail" width="300" height="224" /></a><p class="wp-caption-text">GMail</p></div>
<p>En estos días <a href="http://www.gmail.com">GMail</a> empezó a implementar la <a href="http://mail.google.com/support/bin/answer.py?hl=en&amp;answer=186531">Priority Inbox</a>, o <a href="http://mail.google.com/support/bin/answer.py?hl=es&amp;answer=186531">Prioritarios</a> en su versión en castellano. No es nada demasiado novedoso, en realidad es una etiqueta que define a un mensaje como prioritario. Lo más interesante es que Gmail no solamente te puede mostrar por separado los mails con prioridad de los otros, sino que nos promete ir &#8220;aprendiendo&#8221; a determinar cuáles son prioritarios y cuáles no.</p>
<p>En estos días estuve probando el feature y me viene bien. Yo recibo muchos mails por día, la mayoría de distintas listas de correo. Y como soy muy obsesivo, cada vez que tengo un mensaje nuevo voy a ver de qué se trata y &#8220;marcarlo como leído&#8221;. Este feature me permite perocuparme solamente por los prioritarios y dejar los menos importantes (como los de las listas) para más tarde.</p>
<p>Hoy pensé: &#8220;qué bueno estaría tener una aplicación que me notifique solamente de los mails importantes&#8221;. Ya existen varios <a href="http://www.google.com/search?&amp;q=gmail+notifier&amp;ie=utf-8&amp;oe=utf-8">notifiers para Gmail</a>, tanto de Google o de terceros, para Firefox o para el Desktop. Pero supongo que todavía no habrán implementado esta posibilidad de solamente avisarte de los mensajes prioritarios. Así que lo que hice fue hacerlo en Python que es muuuy fácil.</p>
<p>En su versión simplificada, ver si hay mails &#8220;Importantes&#8221; y notificarlo es tan sencillo como esto:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="co1">#!/usr/bin/env python</span><br />
<span class="co1"># -*- coding: utf-8 -*-</span><br />
<span class="kw1">import</span> <span class="kw3">sys</span><br />
<span class="kw1">import</span> <span class="kw3">imaplib</span><br />
<span class="kw1">import</span> pynotify<br />
<span class="kw1">from</span> <span class="kw3">email</span>.<span class="me1">header</span> <span class="kw1">import</span> decode_header<br />
<span class="kw1">from</span> <span class="kw3">email</span>.<span class="kw3">parser</span> <span class="kw1">import</span> Parser</p>
<p>host = <span class="st0">&#8216;imap.gmail.com&#8217;</span><br />
port = <span class="nu0">993</span><br />
username = <span class="st0">&#8216;usuario@gmail.com&#8217;</span><br />
password = <span class="st0">&#8216;passwordsupersecreto&#8217;</span></p>
<p><span class="kw1">def</span> get_header <span class="br0">&#40;</span>msg, header<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Gets a header from a message&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; header = decode_header<span class="br0">&#40;</span>msg.<span class="me1">get</span><span class="br0">&#40;</span>header<span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>header<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">unicode</span><span class="br0">&#40;</span>header<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>, header<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span>.<span class="me1">encode</span><span class="br0">&#40;</span><span class="st0">&#8216;utf8&#8242;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> header<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span></p>
<p><span class="kw1">if</span> <span class="kw1">not</span> pynotify.<span class="me1">init</span><span class="br0">&#40;</span><span class="st0">&quot;GMail Important Messages&quot;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;Failed to initialize pynotify&quot;</span><br />
&nbsp; &nbsp; <span class="kw3">sys</span>.<span class="me1">exit</span><span class="br0">&#40;</span><span class="nu0">1</span><span class="br0">&#41;</span></p>
<p>client = &nbsp;<span class="kw3">imaplib</span>.<span class="me1">IMAP4_SSL</span><span class="br0">&#40;</span>host, port<span class="br0">&#41;</span><br />
<span class="kw1">if</span> <span class="kw1">not</span> client.<span class="me1">login</span><span class="br0">&#40;</span>username, password<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;Failed to login&quot;</span><br />
&nbsp; &nbsp; <span class="kw3">sys</span>.<span class="me1">exit</span><span class="br0">&#40;</span><span class="nu0">1</span><span class="br0">&#41;</span></p>
<p>status, data = client.<span class="kw3">select</span><span class="br0">&#40;</span><span class="st0">&#8216;[Gmail]/Important&#8217;</span><span class="br0">&#41;</span><br />
<span class="kw1">if</span> status != <span class="st0">&#8216;OK&#8217;</span>:<br />
&nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;Failed to select Important label&quot;</span><br />
&nbsp; &nbsp; <span class="kw3">sys</span>.<span class="me1">exit</span><span class="br0">&#40;</span><span class="nu0">1</span><span class="br0">&#41;</span></p>
<p>status, data = client.<span class="me1">search</span><span class="br0">&#40;</span><span class="kw2">None</span>, <span class="st0">&#8216;(UNSEEN)&#8217;</span><span class="br0">&#41;</span><br />
<span class="kw1">if</span> status == <span class="st0">&#8216;OK&#8217;</span> <span class="kw1">and</span> data<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> != <span class="st0">&#8221;</span>:<br />
&nbsp; &nbsp; <span class="kw1">for</span> msg_id <span class="kw1">in</span> <span class="kw2">sorted</span><span class="br0">&#40;</span>data<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>.<span class="me1">split</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> msg_id != <span class="st0">&#8221;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; status, data = client.<span class="me1">fetch</span><span class="br0">&#40;</span>msg_id, <span class="st0">&#8216;(RFC822)&#8217;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> status == <span class="st0">&#8216;OK&#8217;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; msg = Parser<span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">parsestr</span><span class="br0">&#40;</span>data<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pynotify.<span class="me1">Notification</span><span class="br0">&#40;</span>get_header<span class="br0">&#40;</span>msg, <span class="st0">&#8216;From&#8217;</span><span class="br0">&#41;</span>, \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;get_header<span class="br0">&#40;</span>msg, <span class="st0">&#8216;Subject&#8217;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>.<span class="me1">show</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;Failed to fetch message #%s&quot;</span> % <span class="kw2">str</span><span class="br0">&#40;</span>msg_id<span class="br0">&#41;</span></div>
<p>Ese código lo que hace es inicializar pynotify, conectarse al servidor IMAP de GMail usando <a href="http://docs.python.org/library/imaplib.html">imaplib</a>, autenticarse con el user y password provisto, seleccionar la etiqueta &#8220;[Gmail]/Important&#8221; y ver si hay mensajes sin leer. En caso de que haya itera sobre ellos, obtiene su contenido (para sacar el remitente y el asunto) y lanza un mensaje de notificación.</p>
<p>Para convertir eso en una aplicación básicamente hace falta meterlo en un while y corregir un detalle que es que el fetch del mensaje lo marca como leído (y eso no es algo que queramos en un simple notificador), así que hay que volver a marcarlo como no leído. Eso y algunos toques cosméticos es lo que hice en <a href="http://pastebin.com/9SqPTLJS">el script completo</a>.</p>
<p>Por supuesto se trata solo de una prueba de concepto y a una aplicación completamente funcional deberían hacersele algunas correcciones más. Pero creo que es una idea divertida como para que otros puedan hacer algo mejor.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/programacion/python/notificaciones-de-mails-prioritarios-de-gmail-en-nuestro-escritorio.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Backups con tar + rsync + rotación</title>
		<link>http://www.tail-f.com.ar/programacion/bash/backups-con-tar-rsync-rotacion.html</link>
		<comments>http://www.tail-f.com.ar/programacion/bash/backups-con-tar-rsync-rotacion.html#comments</comments>
		<pubDate>Thu, 02 Sep 2010 14:29:02 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[BASH]]></category>
		<category><![CDATA[backup]]></category>
		<category><![CDATA[rsync]]></category>
		<category><![CDATA[tar]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=416</guid>
		<description><![CDATA[En estos días tuve que configurar unos backups para un cliente. Algo bastante sencillo. Tenía dos servidores y necesitaba hacer backups de distintas cosas en cada equipo y copiarlos al otro. Por supuesto, la herramienta clave para esto es rsync. &#8230;<p class="read-more"><a href="http://www.tail-f.com.ar/programacion/bash/backups-con-tar-rsync-rotacion.html">Read more &#187;</a></p>]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.tail-f.com.ar/wp-content/uploads/Backup.jpg"><img class="alignright size-medium wp-image-417" title="Backup" src="http://www.tail-f.com.ar/wp-content/uploads/Backup-300x225.jpg" alt="" width="300" height="225" /></a>En estos días tuve que configurar unos backups para un cliente. Algo bastante sencillo. Tenía dos servidores y necesitaba hacer backups de distintas cosas en cada equipo y copiarlos al otro. Por supuesto, la herramienta clave para esto es <a href="http://www.samba.org/rsync/">rsync</a>. Googleando un poco vi que existe <a href="http://www.mikerubel.org/computers/rsync_snapshots/">esta página</a> donde se puede ver cómo generar snapshots incrementales automáticos usando hard links y rsync. Realmente es una solución muy interesante, pero a mí no me terminaba de convencer porque yo quería tener archivos comprimidos que fueran rotando.</p>
<p>Por lo tanto lo que hice fue, seguramente, reinventar la rueda una vez más. Hice una pequeña librería en BASH que luego reutilicé en los distintos scripts de backup que hice. La clave aquí es la función &#8220;create_archive&#8221; que toma un path, un nombre de archivo base y una lista de archivos, y se ocupa de ir al path, ver todos los archivos que haya con ese patrón de nombre básico, rotarlos y generar un nuevo tar.gz. Después agregué un par de funciones más que me venían bien, &#8220;log&#8221; para registrar todo lo que pasaba en un archivo, &#8220;mail_notification&#8221; para mandarme mails y &#8220;sync_backup_servers&#8221; para ejecutar rsync.</p>
<p>El código:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="re3">#!/bin/bash</span><br />
<span class="re2">CONF_FILE=</span><span class="st0">&quot;/home/sysbackup/scripts/backup.conf&quot;</span><br />
<span class="kw1">if</span> <span class="br0">&#91;</span> -f <span class="re1">$CONF_FILE</span> <span class="br0">&#93;</span>; <span class="kw1">then</span><br />
&nbsp; &nbsp; . <span class="re1">$CONF_FILE</span><br />
<span class="kw1">else</span><br />
&nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;Configuration file $CONF_FILE not found&quot;</span><br />
&nbsp; &nbsp; <span class="kw3">exit</span> <span class="nu0">1</span><br />
<span class="kw1">fi</span></p>
<p><span class="re2">RM_BIN=</span><span class="st0">&quot;/bin/rm&quot;</span><br />
<span class="re2">TAR_BIN=</span><span class="st0">&quot;/bin/tar&quot;</span><br />
<span class="re2">MAIL_BIN=</span><span class="st0">&quot;/bin/mail&quot;</span><br />
<span class="re2">RSYNC_BIN=</span><span class="st0">&quot;/usr/bin/rsync&quot;</span></p>
<p><span class="kw1">function</span> log<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;`date`: $*&quot;</span> &gt;&gt; <span class="re1">$LOG_FILE</span><br />
<span class="br0">&#125;</span></p>
<p><span class="kw1">function</span> mail_notification<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="re2">subject=</span><span class="st0">&quot;$1&quot;</span><br />
&nbsp; &nbsp; <span class="re2">message=</span><span class="st0">&quot;$2&quot;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> -z <span class="st0">&quot;$subject&quot;</span> <span class="br0">&#93;</span>; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re2">subject=</span><span class="st0">&quot;Backup Notification&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">fi</span></p>
<p>&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> -z <span class="st0">&quot;$NOTIFICATIONS_MAILS&quot;</span> <span class="br0">&#93;</span>; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; log <span class="st0">&quot;mail_notification: empty recipients list&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">return</span> <span class="nu0">1</span><br />
&nbsp; &nbsp; <span class="kw1">fi</span></p>
<p>&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> -z <span class="st0">&quot;$message&quot;</span> <span class="br0">&#93;</span>; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; log <span class="st0">&quot;mail_notification: empty message&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">return</span> <span class="nu0">1</span><br />
&nbsp; &nbsp; <span class="kw1">fi</span></p>
<p>&nbsp; &nbsp; <span class="re2">sysdata=</span><span class="st0">&quot;Date: `date`<span class="es0">\n</span>Host: `hostname`&quot;</span></p>
<p>&nbsp; &nbsp; <span class="kw3">echo</span> -e <span class="st0">&quot;$message<span class="es0">\n</span><span class="es0">\n</span>$sysdata&quot;</span> | <span class="re1">$MAIL_BIN</span> -s <span class="st0">&quot;$subject&quot;</span> <span class="st0">&quot;$NOTIFICATIONS_MAILS&quot;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="kw1">function</span> sync_backup_servers<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; log <span class="st0">&quot;Running rsync from $LOCAL_DIR to $REMOTE_DIR as $RSYNC_USER&quot;</span><br />
&nbsp; &nbsp; <span class="kw2">su</span> -c <span class="st0">&quot;$RSYNC_BIN -aq &#8211;delete -e ssh $LOCAL_DIR/ $REMOTE_DIR/ 2&gt;&gt; $LOG_FILE&quot;</span> <span class="re1">$RSYNC_USER</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> $? -eq <span class="nu0">0</span> <span class="br0">&#93;</span>; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; log <span class="st0">&quot;Syncronization complete successfuly&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; log <span class="st0">&quot;Syncronization finished with errors&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">fi</span><br />
<span class="br0">&#125;</span></p>
<p><span class="kw1">function</span> create_archive<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="re2">file_path=</span><span class="st0">&quot;$1&quot;</span><br />
&nbsp; &nbsp; <span class="re2">file_name=</span><span class="st0">&quot;$2&quot;</span><br />
&nbsp; &nbsp; <span class="re2">files=</span><span class="st0">&quot;${*:3}&quot;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> -z <span class="re1">$file_path</span> <span class="br0">&#93;</span>; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;Missing file path&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">return</span> <span class="nu0">1</span><br />
&nbsp; &nbsp; <span class="kw1">fi</span></p>
<p>&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> -z <span class="re1">$file_name</span> <span class="br0">&#93;</span>; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;Missing file name&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">return</span> <span class="nu0">1</span><br />
&nbsp; &nbsp; <span class="kw1">fi</span></p>
<p>&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> -z <span class="re1">$files</span> <span class="br0">&#93;</span>; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;Missing file list&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">return</span> <span class="nu0">1</span><br />
&nbsp; &nbsp; <span class="kw1">fi</span></p>
<p>&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> -z <span class="re1">$MAX_BKP_FILES</span> <span class="br0">&#93;</span>; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re2">MAX_BKP_FILES=</span><span class="nu0">4</span><br />
&nbsp; &nbsp; <span class="kw1">fi</span></p>
<p>&nbsp; &nbsp; <span class="re2">archive_name=</span><span class="st0">&quot;${file_name}_`date +%Y%m%d`.tar.gz&quot;</span><br />
&nbsp; &nbsp; log <span class="st0">&quot;Preparing to create $archive_name archive&quot;</span></p>
<p>&nbsp; &nbsp; <span class="re3"># Begin to Rotate files</span><br />
&nbsp; &nbsp; <span class="re3"># Sort files by <span class="kw2">date</span> and keep the latest ones</span><br />
&nbsp; &nbsp; <span class="re3"># MAX_BKP_FILES will determine how many to store</span><br />
&nbsp; &nbsp; <span class="re2">dir=</span>`<span class="kw2">ls</span> -t <span class="re1">$file_path</span>/<span class="re0">$<span class="br0">&#123;</span>file_name<span class="br0">&#125;</span></span>_*.<span class="kw2">tar</span>.gz <span class="nu0">2</span>&gt; /dev/null`<br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> $? -eq <span class="nu0">0</span> <span class="br0">&#93;</span>; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re2">N=</span><span class="nu0">0</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="kw2">file</span> <span class="kw1">in</span> <span class="re1">$dir</span>; <span class="kw1">do</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="re1">$N</span> -lt <span class="re1">$MAX_BKP_FILES</span> <span class="br0">&#93;</span>; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">let</span> N++<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log <span class="st0">&quot;Removing old file $file&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re1">$RM_BIN</span> -f <span class="re1">$file</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fi</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">done</span><br />
&nbsp; &nbsp; <span class="kw1">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; log <span class="st0">&quot;No other archive found on $file_path&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">fi</span></p>
<p>&nbsp; &nbsp; log <span class="st0">&quot;Creating tar archive $file_path/$archive_name&quot;</span><br />
&nbsp; &nbsp; <span class="re1">$TAR_BIN</span> zcf <span class="st0">&quot;$file_path/$archive_name&quot;</span> <span class="re1">$files</span> <span class="nu0">2</span>&gt;&gt; <span class="re1">$LOG_FILE</span><br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p>Algunas consideraciones importantes.</p>
<p><strong>Configuración</strong></p>
<p>Al principio del script lo que hago es incluir un archivo de configuración con algunas variables básicas que voy a utilizar. Este archivo debería ser algo similar a esto:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="re3">#!/bin/bash</span><br />
<span class="re2">LOCAL_DIR=</span><span class="st0">&quot;/home/sysbackup/backup/server1.domain.com&quot;</span><br />
<span class="re2">REMOTE_DIR=</span><span class="st0">&quot;sysbackup@server1.domain.com:/home/sysbackup/backup/server1.domain.com&quot;</span><br />
<span class="re2">LOG_FILE=</span><span class="st0">&quot;/var/log/sysbackup.log&quot;</span><br />
<span class="re2">MAX_BKP_FILES=</span><span class="nu0">4</span><br />
<span class="re2">NOTIFICATIONS_MAILS=</span><span class="st0">&quot;admin@email.com&quot;</span><br />
<span class="re2">RSYNC_USER=</span><span class="st0">&quot;sysbackup&quot;</span><br />
&nbsp;</div>
<p>LOCAL_DIR es el directorio local base donde van a estar mis backups. REMOTE_DIR es el directorio equivalente en el otro servidor. Lo que hice fue crear un usuario &#8220;sysbackup&#8221; (un poco menos obvio que &#8220;backup&#8221;, pero también self-explanatory) en los dos servidores y generar llaves para que se puedan conectar por SSH entre los dos servidores. Luego en la /home de cada usuario creé una carpeta &#8220;backup&#8221; y adentro de ella una carpeta para cada host que iba a ser backupeado &#8220;server1.domain.com&#8221; y &#8220;server2.domain.com&#8221;.</p>
<p>LOG_FILE indica el archivo donde se van a guardar los logs del backup y MAX_BKP_FILES determina la cantidad máxima de archivos de backup que va a haber por cada elemento.</p>
<p><strong>Rotación</strong></p>
<p>Como dije, la función más importante es create_archive. La pensé para logs que se crean una vez por día (o cada más tiempo), por lo que si la quieren usar para rotar logs generados en intervalos de tiempo más cortos van a tener que modificarla. Lo que hace es generar un nombre de archivo con una raiz elegida por nosotros (digamos &#8220;db&#8221;) y la fecha actual (la función pone la fecha, pero si necesitan intervalos más cortos van a tener que poner fecha y hora). Luego hace un `ls -t` del directorio donde hay que generar el backup para ver si hay otros archivos que coincidan con el patrón del nombre correspondiente (por ejemplo, &#8216;db_*.tar.gz&#8217;). Si hay archivos, va a conservar los últimos 4 (en realidad la cantidad la determina MAX_BKP_FILES) y va a borrar los más viejos. Por último, va a generar el tar.gz con la lista de archivos que le hayamos pasado.</p>
<p>Ejemplo:</p>
<div class="dean_ch" style="white-space: wrap;">create_archive <span class="st0">&quot;$LOCAL_DIR/web&quot;</span> <span class="st0">&quot;web&quot;</span> <span class="st0">&quot;/var/www/html&quot;</span><br />
&nbsp;</div>
<p>Va a generar con un archivo de nombre como &#8220;web_20100902.tar.gz&#8221; en la carpeta $LOCAL_DIR/web con todos los contenidos de /var/www/html.</p>
<p><strong>Rsync</strong></p>
<p>La función sync_backup_servers hace la sincronización entre los dos servidores usando rsync por SSH. Una cosa a tener en cuenta es que en mi caso, yo necesitaba que el script de backup corriera como root (para poder acceder a todos los archivos que había que backupear) pero quería que el rsync se ejecutara con el usuario sysbackup (para mayor seguridad). Por lo tanto la función usa &#8220;su -c  sysbackup&#8221;. Si a uds. este enfoque no les sirve pueden poner en la función directamente:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="re1">$RSYNC_BIN</span> -aq &#8211;delete -e <span class="kw2">ssh</span> <span class="re1">$LOCAL_DIR</span>/ <span class="re1">$REMOTE_DIR</span>/ <span class="nu0">2</span>&gt;&gt; <span class="re1">$LOG_FILE</span><br />
&nbsp;</div>
<p><strong>Notificaciones por mail</strong></p>
<p>Es muy útil poder tener notificaciones por mail, sobre todo cuando las cosas andan mal. El comando &#8220;mail&#8221; de Linux/Unix es muy útil para esto. La funcion mail_notification usa ese comando para mandar un mail con el mensaje que queramos y le agrega dos datos útiles: la fecha y el hostname desde el que se manda. En realidad son datos que siempre viajan en los headers del mail, pero a mí me parecía útil que estuvieran en el body.</p>
<p>Espero que les sirvan estos recursos. No son una solución completa y cerrada, sino herramientas que quizás les sirvan para implementar o al menos pensar cómo hacer sus propios sistemas de backup. Les recomiendo enfáticamente que lean este artículo sobre <a href="http://www.mikerubel.org/computers/rsync_snapshots/">cómo generar backups con rsync</a> porque explica muchas cosas fundamentales.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/programacion/bash/backups-con-tar-rsync-rotacion.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>PET: Python Entre Todos, primera revista de Python</title>
		<link>http://www.tail-f.com.ar/programacion/python/pet-python-entre-todos-primera-revista-de-python.html</link>
		<comments>http://www.tail-f.com.ar/programacion/python/pet-python-entre-todos-primera-revista-de-python.html#comments</comments>
		<pubDate>Sun, 22 Aug 2010 14:41:03 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[PET]]></category>
		<category><![CDATA[revista]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=412</guid>
		<description><![CDATA[A esta altura ya es una noticia vieja, pero quizás alguno no se haya enterado de que la semana pasada salió publicada la revista PET: Python Entre Todos. La revista es una producción colaborativa de la Comunidad PyAr, con artículos &#8230;<p class="read-more"><a href="http://www.tail-f.com.ar/programacion/python/pet-python-entre-todos-primera-revista-de-python.html">Read more &#187;</a></p>]]></description>
				<content:encoded><![CDATA[<p>A esta altura ya es una noticia vieja, pero quizás alguno no se haya enterado de que la semana pasada salió publicada la revista <a href="http://revista.python.org.ar/">PET: Python Entre Todos</a>.</p>
<p>La revista es una producción colaborativa de la <a href="http://python.org.ar/">Comunidad PyAr</a>, con artículos de muy alto nivel de distintos participantes de la lista y el esfuerzo especial de sus dos editores, Roberto Alsina y Emiliano Dalla Verde Marcozzi.</p>
<div id="attachment_413" class="wp-caption alignright" style="width: 310px"><a href="http://www.tail-f.com.ar/wp-content/uploads/tapa-nro1.jpg"><img class="size-medium wp-image-413 " title="PET: Python Entre Todos Num. 1" src="http://www.tail-f.com.ar/wp-content/uploads/tapa-nro1-300x212.jpg" alt="PET: Python Entre Todos Num. 1" width="300" height="212" /></a><p class="wp-caption-text">PET: Python Entre Todos Num. 1</p></div>
<p>Los artículos incluidos en la revista son:</p>
<ul>
<li>PET First Shot</li>
<li>Cómo contribuir a PET</li>
<li> PyAr, la historia</li>
<li> from gc import commonsense &#8211; Finish Him!</li>
<li> Concurrencia Indolora: el módulo processing</li>
<li> Introducción a Unit Testing con Python</li>
<li> Taint Mode en Python</li>
<li> Dinamismo Aplicado</li>
<li> Decorando Código (Parte 1)</li>
<li> Web2Py Para Todos</li>
<li> ¿Cómo Está Hecha Esta Revista?</li>
<li> Desafío PET</li>
<li> Un poco de xkcd</li>
</ul>
<p>La publicación fue todo un éxito porque se dinfundió rápidamente por Internet con la ayuda de diversos medios: blogs, twitter, barrapunto, etc. En mi opinión esta buena recepción se debió dos factores clave: la calidad del contenido que es realmente muy alta y que gracias a las tecnologías de software libre utilizadas para la edición de la revista, la misma pudo ser publicada en múltiples formatos: HTML online, PDF en distintos layouts y para e-book readers en ePub y Mobi. A todos ellos se puede acceder en la página del <a href="http://revista.python.org.ar/1/html/">primer número de la revista</a>.</p>
<p>Además, al poco tiempo de publicada la revista, Roberto descubrió que <a href="http://revista.python.org.ar/">PET</a> es la primera revista de Python&#8230; en el mundo!. Esto animó a la comunidad a crear una versión en inglés para poder difundirla a un mayor público. Personalmente tuve la opotunidad de colaborar traduciendo dos artículos, &#8220;<a href="http://revista.python.org.ar/1/html/genesispyar.html">PyAr, la historia</a>&#8221; de <a href="http://www.taniquetil.com.ar/plog/">Facundo Batista</a> y &#8220;<a href="http://revista.python.org.ar/1/html/comohacer.html">¿Cómo Está Hecha Esta Revista?</a>&#8221; de <a href="http://lateral.netmanagers.com.ar/">Roberto Alsina</a>. De esta manera, si no puedo aportar con un artículo interesante, por lo menos puedo colaborar para que las cosas interesantes que escriben otros puedan llegar a un público más amplio.</p>
<p>Así que seguramente pronto estemos anunciando la versión en inglés del número 1 de PET. Y en el futuro, según entiendo, la idea es poder incorporar artículos de colaboradores internacionales en ambas versiones de la revista.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/programacion/python/pet-python-entre-todos-primera-revista-de-python.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Una vueltita por las Charlas Abiertas de Python en La Tribu</title>
		<link>http://www.tail-f.com.ar/programacion/python/una-vueltita-por-las-charlas-abiertas-de-python-en-la-tribu.html</link>
		<comments>http://www.tail-f.com.ar/programacion/python/una-vueltita-por-las-charlas-abiertas-de-python-en-la-tribu.html#comments</comments>
		<pubDate>Sat, 21 Aug 2010 18:21:00 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Charlas]]></category>
		<category><![CDATA[Desarrollo web]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=409</guid>
		<description><![CDATA[Hoy pude darme una vuelta, por primera vez, por las Charlas Abiertas de Python en La Tribu. Le robé un tiempo al estudio y me dirigí a Lambaré 873 junto a un amigo, a ver qué tal estaban esas charlas. &#8230;<p class="read-more"><a href="http://www.tail-f.com.ar/programacion/python/una-vueltita-por-las-charlas-abiertas-de-python-en-la-tribu.html">Read more &#187;</a></p>]]></description>
				<content:encoded><![CDATA[<div id="attachment_391" class="wp-caption alignright" style="width: 310px"><a href="http://www.tail-f.com.ar/wp-content/uploads/charlasabiertaspytribu.png"><img class="size-medium wp-image-391" title="charlasabiertaspytribu" src="http://www.tail-f.com.ar/wp-content/uploads/charlasabiertaspytribu-300x136.png" alt="" width="300" height="136" /></a><p class="wp-caption-text">Charlas Abiertas de Python en La Tribu</p></div>
<p>Hoy pude darme una vuelta, por primera vez, por las <a href="http://www.tail-f.com.ar/programacion/python/ciclo-de-charlas-abiertas-de-python-argentina-en-la-tribu.html">Charlas Abiertas de Python en La Tribu</a>. Le robé un tiempo al estudio y me dirigí a Lambaré 873 junto a un amigo, a ver qué tal estaban esas charlas.</p>
<p>No esperaba encontrar grandes revelaciones porque la charla a la que iba era la de Introducción al Desarrollo Web I, a cargo de Alejandro Cura, y yo ya trabajo en el rubro hace algunos años. Sin embargo me interesaba verle las caras a algunos miembros de la <a href="http://python.org.ar/">comunidad</a> por quienes tengo un gran respeto.</p>
<p>Me encontré con un ámbito muy amigable, lleno de gente deseosa de aprender. Me alegró mucho encontrar algunas personas &#8220;mayores&#8221; (por lo menos mayores al tipo de gente que uno suele conocer en este acotado segmento del mercado laboral), muy interesadas y participativas. La charla estuvo muy bien, era una introducción para quienes no tienen idea de en qué consiste hacer un sitio web (y preparatoria para la próxima charla que dará algunos conceptos básicos de <a href="http://www.web2py.com/">Web2Py</a>). Me pareció muy copado que se le diera un poco de bola al protocolo HTTP y cómo funciona, porque en mi experiencia laboral me he encontrado con desarrolladores que pueden manejar muy bien algunos lenguajes como PHP, Javascript o HTML pero no tienen idea de cómo llegan esas cosas &#8220;a la mesa&#8221; del browser.</p>
<p>Incluso me encontré aprendiendo una cosita de CSS que no sabía y era la posibilidad de incluir tipografías externas (que quisiera ver qué tan compatible es con la bosta de IE, pero que me resultó muy útil).</p>
<p>Me hubiera gustado quedarme a la charla siguiente del eminente <a href="http://lateral.netmanagers.com.ar/">Roberto Alsina</a>, pero lamentablemente tenía que volver a la cueva a estudiar.</p>
<p>Felicito desde este humilde lugar el enorme trabajo que está realizando la comunidad <a href="http://python.org.ar/">PyAr</a> organizando estas charlas que permiten acercar herramientas a la sociedad para conocer y apropiarse de las nuevas tecnologías asociadas a la informática e Internet.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/programacion/python/una-vueltita-por-las-charlas-abiertas-de-python-en-la-tribu.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Recalcular quota en Directadmin</title>
		<link>http://www.tail-f.com.ar/paneles-de-control/directadmin/recalcular-quota-en-directadmin.html</link>
		<comments>http://www.tail-f.com.ar/paneles-de-control/directadmin/recalcular-quota-en-directadmin.html#comments</comments>
		<pubDate>Mon, 16 Aug 2010 16:19:17 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[Directadmin]]></category>
		<category><![CDATA[quota]]></category>
		<category><![CDATA[tally]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=406</guid>
		<description><![CDATA[Directadmin utiliza el sistema de quotas del sistema operativo para calcular el espacio que está siendo utilizado por cada usuario. A veces, por diversas circunstancias, puede ser que necesitemos recalcular estos datos. Particularmente, en estos días tuvimos un problema con &#8230;<p class="read-more"><a href="http://www.tail-f.com.ar/paneles-de-control/directadmin/recalcular-quota-en-directadmin.html">Read more &#187;</a></p>]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.tail-f.com.ar/category/paneles-de-control/directadmin"><a href="http://www.tail-f.com.ar/wp-content/uploads/direct_admin.gif"><img class="size-full wp-image-22 alignright" title="DirectAdmin" src="http://www.tail-f.com.ar/wp-content/uploads/direct_admin.gif" alt="" width="281" height="162" /></a></p>
<p>Directadmin</a> utiliza el sistema de quotas del sistema operativo para calcular el espacio que está siendo utilizado por cada usuario. A veces, por diversas circunstancias, puede ser que necesitemos recalcular estos datos. Particularmente, en estos días tuvimos un problema con el acceso a un dispositivo que generó problemas en la ejecución del comando repquota y cuando solucioné el problema, tuve que recalcular la quota de todos los usuarios del sistema. Me pareció que sería útil explicar cómo hacerlo, porque si bien es algo que está explicado en la <a href="http://help.directadmin.com/item.php?id=42">Knowledge Base de Directadmin</a>, allí está en inglés.</p>
<p>Para que el sistema recalcule las quotas, es decir, analice todo el filesystem verificando el uso del disco y cree, confirme o repare los archivos de quotas, necesitamos correr el comando quotacheck. Para ello necesitamos deshabilitar las quotas, chequear y volver a habilitarlas.</p>
<pre># /sbin/quotaoff -a
# /sbin/quotacheck -avugm
# /sbin/quotaon -a
</pre>
<p>Esto tomará algunos minutos (particularmente el proceso quotacheck). Luego de lo cual podemos esperar que Directadmin corra el tally y recalcule los valores para cada usuario, o podemos indicarle explícitamente que lo haga en este momento. Para ello debemos agregar la tarea del tally a la cola:</p>
<pre># echo "action=tally&amp;value=all" &gt;&gt; /usr/local/directadmin/data/task.queue
</pre>
<p>El tally se ejecutará cuando corra el proceso dataskq de Directadmin (que se ejecuta cada minuto). Podemos ver los logs de este proceso en /var/log/directadmin/system.log.</p>
<p>Pero si somos demasiado impacientes o queremos ver información de debug, podemos correr explícitamente el dataskq.</p>
<pre># /usr/local/directadmin/dataskq d10
</pre>
<p>Listo. Una vez que Directadmin re-procese todos los usuarios, los datos de consumo de disco de cada uno se habrá sincronizado con la información actual del sistema.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/paneles-de-control/directadmin/recalcular-quota-en-directadmin.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss><!-- Dynamic page generated in 0.549 seconds. --><!-- Cached page generated by WP-Super-Cache on 2013-04-08 13:19:51 --><!-- Compression = gzip -->
