<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	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/"
	>

<channel>
	<title>ubuntu-ar &#8211; El Blog de Marcelo!</title>
	<atom:link href="http://blog.marcelofernandez.info/category/ubuntu-ar/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.marcelofernandez.info</link>
	<description>Blog Informático sobre Programación, Software Libre y/o Open Source, Linux, Python y alguna que otra cosa más...</description>
	<lastBuildDate>Wed, 04 Apr 2018 02:39:24 +0000</lastBuildDate>
	<language>es</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
		<item>
		<title>CORE Network Emulator</title>
		<link>http://blog.marcelofernandez.info/2018/01/core-network-emulator/</link>
					<comments>http://blog.marcelofernandez.info/2018/01/core-network-emulator/#comments</comments>
		
		<dc:creator><![CDATA[Marcelo]]></dc:creator>
		<pubDate>Wed, 31 Jan 2018 13:06:39 +0000</pubDate>
				<category><![CDATA[codear]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[ubuntu-ar]]></category>
		<guid isPermaLink="false">https://blog.marcelofernandez.info/?p=1523</guid>

					<description><![CDATA[Investigando herramientas de simulación/emulación de redes con fines educativos, un amigo pasó esta página, bastante nutrida por cierto, con un listado de simuladores/emuladores de red, recomendando probar CORE. C.O.R.E., acrónimo de Common Open Research Environment, fue un proyecto inicialmente de Boeing (sí, la de los aviones) y que ahora es sponsoreado por el Laboratorio de Investigación [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Investigando herramientas de simulación/emulación de redes con fines educativos, <a href="http://bitnegro.blogspot.com.ar/">un amigo</a> pasó <a href="http://www.brianlinkletter.com/open-source-network-simulators/">esta página</a>, bastante nutrida por cierto, con un listado de simuladores/emuladores de red, recomendando probar <a href="https://www.nrl.navy.mil/itd/ncs/products/core">CORE</a>.</p>
<p>C.O.R.E., acrónimo de <em>Common Open Research Environment</em>, fue un proyecto inicialmente de Boeing (sí, la de los aviones) y que ahora es sponsoreado por el <a href="https://www.nrl.navy.mil/">Laboratorio de Investigación Naval de los Estados Unidos</a>. Le dediqué un rato a revisar qué tal funcionaba, y aquí está lo que pude probar.</p>
<p>A priori, resulta que la última versión (4.8) está en los repos de Ubuntu 16.04, por lo que fue fácil la instalación [1]:</p>
<pre lang="sh">marcelo@marcelo-notebook:~$ apt-cache search core-network
 core-network - intuitive network emulator that interacts with real nets (metapackage)
 core-network-daemon - intuitive network emulator that interacts with real nets (daemon)
 core-network-gui - intuitive network emulator that interacts with real nets (GUI)
</pre>
<p>Se instalan esos paquetes y listo el pollo, las dependencias son básicas (TCL/TK y quagga):</p>
<pre lang="sh">marcelo@marcelo-notebook:~$ sudo apt install core-network core-network-gui
Leyendo lista de paquetes... Hecho
Creando árbol de dependencias 
Leyendo la información de estado... Hecho
Se instalarán los siguientes paquetes adicionales:
 core-network-daemon libev4 libtcl8.5 libtk-img libtk8.5 quagga tcl8.5 tk8.5
Paquetes sugeridos:
 libtk-img-doc snmpd tcl-tclreadline
Se instalarán los siguientes paquetes NUEVOS:
 core-network core-network-daemon core-network-gui libev4 libtcl8.5 libtk-img libtk8.5 quagga tcl8.5 tk8.5
0 actualizados, 10 nuevos se instalarán, 0 para eliminar y 2 no actualizados.
Se necesita descargar 3.905 kB de archivos.
Se utilizarán 16,4 MB de espacio de disco adicional después de esta operación.
¿Desea continuar? [S/n]
</pre>
<p>Usarlo es tanto como ejecutar «core-gui» y empezar a armar el mapa de la red tal como se ve en el video de la página que citó Mauro:</p>
<figure id="attachment_1524" aria-describedby="caption-attachment-1524" style="width: 600px" class="wp-caption aligncenter"><a href="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core1.png"><img fetchpriority="high" decoding="async" class="wp-image-1524" src="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core1.png" alt="Vista de Red - CORE" width="600" height="429" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core1.png 716w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core1-300x215.png 300w" sizes="(max-width: 600px) 100vw, 600px" /></a><figcaption id="caption-attachment-1524" class="wp-caption-text">Vista de Red &#8211; CORE</figcaption></figure>
<p>El direccionamiento lo hace automáticamente (aunque es configurable, haciéndole doble click a cada nodo):</p>
<p><a href="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core2.png"><img decoding="async" class="wp-image-1525 size-full aligncenter" src="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core2.png" alt="" width="391" height="362" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core2.png 391w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core2-300x278.png 300w" sizes="(max-width: 391px) 100vw, 391px" /></a></p>
<p><a href="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core3.png"><img decoding="async" class="wp-image-1526 size-full aligncenter" src="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core3.png" alt="" width="391" height="275" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core3.png 391w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core3-300x211.png 300w" sizes="(max-width: 391px) 100vw, 391px" /></a></p>
<p>&#8230; y la configuración del ruteo se hace sola (ver más abajo cómo), por lo que luego de armar esa red sencilla, ambos hosts («PC» y «Server») se ven automáticamente.</p>
<p>Luego de armar la red, se le da al botón de «Play» y se ejecuta todo. Todos los nodos son Linux (nada de emulación routers Cisco ni nada como sucede con <a href="https://www.gns3.com/">GNS3</a>), y acá viene lo interesante:</p>
<ul>
<li>Todos son containers (<a href="https://linuxcontainers.org/">LXC</a>) del mismo host de uno, pero <strong>sin estar en un chroot</strong> (?!?),</li>
<li>Es extremadamente rápido gracias a LXC, pero «raro» ya que todo corre en el mismo <em>filesystem</em> de la máquina de uno (puedo ir a mi home directamente desde cada nodo).</li>
<li>Dado que es un container, todos los kernels guest son los mismos del host.</li>
<li>¡El software que se ejecuta es el mismo del host! Es decir, si digo que este nodo va a tener Apache (servicio «HTTP»), hay que instalar el paquete apache2 en el host, no en el guest. No hay imagen de máquina virtual ni nada por el estilo como pasa con otros emuladores.</li>
<li>El directorio que te abre al entrar a cada guest es<code>/tmp/pycore.&lt;PID&gt;/&lt;nombredelhost&gt;.conf/</code></li>
<li>La configuración de los servicios/apps que va a usar en cada host la genera el entorno antes de darle «Play» en <code>/tmp/pycore.&lt;PID&gt;/&lt;nombredelhost&gt;.conf/</code>, por ejemplo:</li>
</ul>
<p><a href="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core4.png"><img loading="lazy" decoding="async" class="aligncenter wp-image-1527 size-full" src="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core4.png" alt="" width="507" height="265" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core4.png 507w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core4-300x157.png 300w" sizes="auto, (max-width: 507px) 100vw, 507px" /></a>Uno puede ir y editar los archivos en el directorio <code>etc.apache2/</code> que generó el sistema una vez que se le dio ejecución, o puede hacerlo antes, tocando en el botón «Services» de la configuración del host:<a href="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core5.png"><img loading="lazy" decoding="async" class="aligncenter wp-image-1528" src="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core5-300x159.png" alt="" width="601" height="318" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core5-300x159.png 300w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core5-768x406.png 768w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core5-1024x542.png 1024w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core5.png 1060w" sizes="auto, (max-width: 601px) 100vw, 601px" /></a></p>
<p>Y luego en el ícono de llave inglesa:<a href="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core6.png"><img loading="lazy" decoding="async" class="aligncenter wp-image-1529 size-full" src="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core6.png" alt="" width="591" height="604" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core6.png 591w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core6-294x300.png 294w" sizes="auto, (max-width: 591px) 100vw, 591px" /></a><br />
Este es un ps desde el guest Server:</p>
<pre lang="sh">root@Server:/tmp/pycore.34211/Server.conf# ps faxu
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 9676 1708 ? S 12:20 0:00 /usr/sbin/vnoded -v -c /tmp/pycore.34211/Server -l /tmp/pycore.34211/Server.log -p /tmp/pycore.34211/Server.pid -C /tmp/pycore.34211/Server.conf
root 46 0.0 0.0 65508 3096 ? Ss 12:20 0:00 /usr/sbin/sshd -f /etc/ssh/sshd_config
root 52 0.0 0.0 56680 3772 ? Ss 12:20 0:00 /usr/sbin/apache2 -k start
www-data 53 0.0 0.0 411412 3504 ? Sl 12:20 0:00 \_ /usr/sbin/apache2 -k start
www-data 54 0.0 0.0 411412 3504 ? Sl 12:20 0:00 \_ /usr/sbin/apache2 -k start
root 110 0.0 0.0 23848 3968 pts/19 Ss 12:20 0:00 /bin/bash
root 236 0.0 0.0 39932 3316 pts/19 R+ 12:22 0:00 \_ ps faxu
root@Server:/tmp/pycore.34211/Server.conf#</pre>
<p>Este es el <code>running-config</code> generado por core-network de un router (r1), entrando a Quagga con vtysh:<a href="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core7.png"><img loading="lazy" decoding="async" class="aligncenter wp-image-1530 size-full" src="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core7.png" alt="" width="484" height="660" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core7.png 484w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core7-220x300.png 220w" sizes="auto, (max-width: 484px) 100vw, 484px" /></a>Así que ahí vemos que define OSPF automáticamente:<br />
<a href="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core8.png"><img loading="lazy" decoding="async" class="aligncenter wp-image-1531" src="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core8-300x191.png" alt="" width="599" height="382" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core8-300x191.png 300w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core8-768x490.png 768w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core8-1024x653.png 1024w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core8.png 1448w" sizes="auto, (max-width: 599px) 100vw, 599px" /></a></p>
<p>Respecto a si se pueden guardar/cargar laboratorios completos, sí se puede, en el formato «imn» (ya que CORE es un fork de <a href="http://www.imunes.net/">Imunes</a>, y heredó su formato). Algo muy interesante es que se puede configurar el QoS de cada link, haciéndole doble click a cada línea (no lo probé):</p>
<p><a href="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core9.png"><img loading="lazy" decoding="async" class="aligncenter wp-image-1532 size-full" src="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core9.png" alt="" width="220" height="357" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core9.png 220w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core9-185x300.png 185w" sizes="auto, (max-width: 220px) 100vw, 220px" /></a></p>
<p>Y que te grafica el ancho de banda en tiempo real de la red:<a href="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core10.png"><img loading="lazy" decoding="async" class="aligncenter wp-image-1533" src="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core10-300x219.png" alt="" width="600" height="438" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core10-300x219.png 300w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core10-768x561.png 768w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core10.png 1011w" sizes="auto, (max-width: 600px) 100vw, 600px" /></a></p>
<p>Por último, para hacer capturas de tráfico es bastante sencillo, probé dos opciones:</p>
<ol>
<li>Se corre en cada nodo que se desea un <code>tcpdump</code> guardando el tráfico, queda en el «home» de cada container guest (<code>/tmp/pycore.&lt;PID&gt;/&lt;nombredelhost&gt;.conf/</code>), y uno desde el host directamente ejecuta <a href="https://www.wireshark.org/">Wireshark</a> y lo abre.</li>
<li>Pude guardar todo el tráfico de la red en una única captura (esto, con <a href="http://wiki.netkit.org/index.php/Main_Page">netkit</a>, no lo pudimos hacer de forma directa). Para ello, primero se arranca el entorno de simulación; esto hace que se creen dinámicamente los bridges a nivel de host y las interfaces virtuales de cada container, adjuntas a cada bridge (el virbr0 de la captura es de Virtualbox, ignórenlo):</li>
</ol>
<p><a href="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core11.png"><img loading="lazy" decoding="async" class="aligncenter wp-image-1534 size-full" src="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core11.png" alt="" width="600" height="161" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core11.png 600w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core11-300x81.png 300w" sizes="auto, (max-width: 600px) 100vw, 600px" /></a></p>
<p>Y bueno, para hacer la captura de toda la red al mismo tiempo, hay que decirle a Wireshark que capture en todos los bridges:<a href="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core12.png"><img loading="lazy" decoding="async" class="aligncenter wp-image-1535" src="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core12-300x148.png" alt="" width="601" height="296" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core12-300x148.png 300w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core12-768x378.png 768w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core12.png 950w" sizes="auto, (max-width: 601px) 100vw, 601px" /></a></p>
<p><a href="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core13.png"><img loading="lazy" decoding="async" class="aligncenter wp-image-1536" src="https://blog.marcelofernandez.info/wp-content/uploads/2018/01/core13-300x165.png" alt="" width="600" height="330" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core13-300x165.png 300w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core13-768x422.png 768w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core13-1024x563.png 1024w, http://blog.marcelofernandez.info/wp-content/uploads/2018/01/core13.png 1920w" sizes="auto, (max-width: 600px) 100vw, 600px" /></a></p>
<p>Filtré porque aparece tráfico OSPF todo el tiempo, lógicamente. Es cuestión de desactivarlo por defecto (configurando el servicio Quagga/Zebra). Un detalle de capturar así es que hay que ordenar por tiempo, porque el <em>packet number</em> queda desordenado. Pero ordenando por tiempo, lo seguí y aparentemente (hice un ping, nada más) el orden se mantiene (el «reloj» sería el host).</p>
<p>El manual está acá, parece que se pueden hacer muchísimas cosas más (entornos distribuidos, scripting automatizado en Python, etc.):<br />
<a href="https://downloads.pf.itd.nrl.navy.mil/docs/core/core-html/index.html">https://downloads.pf.itd.nrl.navy.mil/docs/core/core-html/index.html</a></p>
<p>Parece ser una muy buena herramienta para simular entornos de red, practicar y aprender sobre protocolos.</p>
<p>[1] Resulta que hace poco lo sacaron de Debian/Ubuntu, porque claro, el entorno gráfico se ejecuta como usuario normal, pero al abrir la consola de cualquier nodo que uno creó entra a la VM como root (y recuerden que no se está dentro de un chroot, con lo cual es root en el host con acceso al filesystem):</p>
<p><a href="https://github.com/coreemu/core/issues/117">https://github.com/coreemu/core/issues/117</a></p>
<p>No lo solucionaron, entonces Debian los sacó, por ende no está en Debian Stretch. Igual <a href="http://eriberto.pro.br/site/">maintainer del paquete</a> tiene un repositorio personal para Debian/Ubuntu:</p>
<p><a href="http://eriberto.pro.br/core/">http://eriberto.pro.br/core/</a></p>
<p>Saludos</p>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.marcelofernandez.info/2018/01/core-network-emulator/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title>Charlas: Introducción a AWS y a HTTP/2</title>
		<link>http://blog.marcelofernandez.info/2016/09/charlas-introduccion-a-aws-y-a-http2/</link>
					<comments>http://blog.marcelofernandez.info/2016/09/charlas-introduccion-a-aws-y-a-http2/#respond</comments>
		
		<dc:creator><![CDATA[Marcelo]]></dc:creator>
		<pubDate>Tue, 13 Sep 2016 18:30:45 +0000</pubDate>
				<category><![CDATA[codear]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[ubuntu-ar]]></category>
		<guid isPermaLink="false">https://blog.marcelofernandez.info/?p=1456</guid>

					<description><![CDATA[Hace unos días tuve el placer de dar una charla en el CIDETIC, perteneciente a la Universidad Nacional de Luján, respecto a los servicios de cloud computing en general y a los de Amazon Web Services en particular. Como siempre, preparar y hablar en público sobre un tema no es lo mismo que tener los conceptos algo [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Hace unos días tuve el placer de <a href="http://www.prensa.unlu.edu.ar/?q=node/3244" target="_blank">dar una charla</a> en el <a href="http://cidetic.unlu.edu.ar/" target="_blank">CIDETIC</a>, perteneciente a la <a href="http://www.unlu.edu.ar/" target="_blank">Universidad Nacional de Luján</a>, respecto a los servicios de cloud computing en general y a los de Amazon Web Services en particular.</p>
<p>Como siempre, preparar y hablar en público sobre un tema no es lo mismo que tener los conceptos algo desordenados, producto únicamente de la experiencia práctica; por lo que fue un desafío organizar tantas ideas algo deshilachadas&#8230; y acepté gustoso. De hecho, tengo un par de críticas que hacerme a mí mismo sobre cómo salió, como que por ejemplo, me quedaron cosas en el tintero y me llevó más tiempo de lo planificado.</p>
<p>De paso, subí también los slides que armé para la charla de HTTP/2, que vengo reeditando prácticamente todos los años en la cátedra de <a href="http://www.labredes.unlu.edu.ar/tyr" target="_blank">Teleinformática y Redes</a>. Esta vez pude ir con <a href="https://httpwg.github.io/specs/rfc7540.html" target="_blank">el protocolo estandarizado</a> para mostrarle a la gente. <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>En fin, los slides, para aquellos que les interesa, los dejé en la sección <a href="https://blog.marcelofernandez.info/charlas/">Charlas</a> del blog. Pueden usarlo sin problemas para lo que deseen.</p>
<p>PD: Si buscan los íconos de los servicios de AWS como recursos para uso personal en la generación de contenido, <a href="https://aws.amazon.com/architecture/icons/" target="_blank">acá están en múltiples formatos</a> (SVG/EPS, Visio, Powerpoint, etc.).</p>
<p>Saludos</p>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.marcelofernandez.info/2016/09/charlas-introduccion-a-aws-y-a-http2/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Migrando Host de VMs KVM de Ubuntu 12.04 a 14.04</title>
		<link>http://blog.marcelofernandez.info/2014/05/migrando-host-de-vms-kvm-12-04-14-04/</link>
					<comments>http://blog.marcelofernandez.info/2014/05/migrando-host-de-vms-kvm-12-04-14-04/#comments</comments>
		
		<dc:creator><![CDATA[Marcelo]]></dc:creator>
		<pubDate>Fri, 16 May 2014 22:07:05 +0000</pubDate>
				<category><![CDATA[codear]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[ubuntu-ar]]></category>
		<guid isPermaLink="false">https://blog.marcelofernandez.info/?p=1380</guid>

					<description><![CDATA[En estos días arranqué la tarea de migrar Máquinas Virtuales de Hosts Ubuntu 12.04 (entorno QEmu-KVM/Libvirt) a Ubuntu 14.04, para testear que esté funcionando todo ok, y me encontré con dos particularidades: 1) Por defecto, las interfaces de red no se llaman más «ethX» ni se guían como antes con el archivo en /etc/udev/rules.d/70-net-persistent.rules, sino [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>En estos días arranqué la tarea de migrar Máquinas Virtuales de Hosts Ubuntu 12.04 (entorno QEmu-KVM/Libvirt) a Ubuntu 14.04, para testear que esté funcionando todo ok, y me encontré con dos particularidades:</p>
<p>1) Por defecto, las interfaces de red no se llaman más «ethX» ni se guían como antes con el archivo en /etc/udev/rules.d/70-net-persistent.rules, sino que ahora son medio raras («p2p1», «p5p4», «eno1», «enp2s0», etc). <a title="Predictable Network Interface Names" href="http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/" target="_blank" rel="noopener">Acá está explicado el por qué del cambio</a> [1]. A priori no me gusta nada este cambio, por no respetar ninguna convención como sí lo hacía ethX, y encima por ser un cambio por defecto, pero como todo&#8230; supongo que me acostumbraré. Es adaptarse o morir; no es un capricho de Ubuntu, sino de udev.</p>
<p>2) ¡No hace falta más configurar un bridge en el host! Ahora se usa el driver de kernel <a title="Virtualized bridged networking with MacVTap" href="http://seravo.fi/2012/virtualized-bridged-networking-with-macvtap" target="_blank" rel="noopener">macvtap</a> [2][3][4][5], que uno <a title="Simple Bridged Networking with Virt-Manager using macvtap" href="http://www.linux-kvm.com/content/simple-bridged-networking-virt-manager-using-macvtap" target="_blank" rel="noopener">lo selecciona en el administrador virt-manager</a>. Así que para el host no habría que cambiar la configuración; para recordarlo, en un <strong>host</strong> Ubuntu 12.04 pasábamos de esto:</p>
<pre>auto eth0
 iface eth0 inet static
 address 192.168.1.18
 netmask 255.255.255.0
 gateway 192.168.1.1
 dns-nameservers 192.168.1.1 192.168.1.2</pre>
<p>a esto (cambia eth0 por br0, y las líneas de bridge):</p>
<pre>auto br0
 iface br0 inet static
 address 192.168.1.18
 netmask 255.255.255.0
 gateway 192.168.1.1
 dns-nameservers 192.168.1.10 192.168.1.15
 bridge_ports eth0
 bridge_stp off
 bridge_fd 0
 bridge_maxwait 0</pre>
<p>Ahora en Ubuntu 14.04 <strong>no hace falta </strong>tocar nada, ya que la interfaz principal sigue siendo la misma, aún cuando haya VMs que salgan directamente puenteadas por dicha interfaz. Lo que sí, por cada VM puenteada con el driver macvtap se va a crear una interfaz en el host, quedando así, digamos:</p>
<pre>macvtap0 Link encap:Ethernet HWaddr 52:54:00:1e:b5:29
 inet6 addr: fe80::5054:ff:fe1e:b529/64 Scope:Link
 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
 RX packets:437 errors:0 dropped:0 overruns:0 frame:0
 TX packets:71 errors:0 dropped:0 overruns:0 carrier:0
 collisions:0 txqueuelen:500
 RX bytes:36313 (36.3 KB) TX bytes:6617 (6.6 KB)

 p2p1 Link encap:Ethernet HWaddr 44:87:fc:ef:96:be
 inet addr:192.168.1.18 Bcast:192.168.1.255 Mask:255.255.255.0
 inet6 addr: fe80::4687:fcff:feef:96be/64 Scope:Link
 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
 RX packets:15346 errors:0 dropped:46 overruns:0 frame:0
 TX packets:16615 errors:0 dropped:0 overruns:0 carrier:0
 collisions:0 txqueuelen:1000
 RX bytes:2096838 (2.0 MB) TX bytes:4714920 (4.7 MB)</pre>
<p>Esto seguramente es más rápido que lo anterior, por diferentes motivos, pero tiene un lado feo, y es que de esta manera los guests <a title="Guest can reach outside network, but can't reach host" href="http://www.furorteutonicus.eu/2013/08/04/enabling-host-guest-networking-with-kvm-macvlan-and-macvtap/" target="_blank" rel="noopener">no pueden comunicarse con el host</a> [6]. Apliqué la «less painful solution» de esa wiki, y fue crear una red NAT aislada entre el host y sus guests, todo de manera gráfica desde virt-manager. Fue bastante simple, y aunque no me guste que tenga que haber una interfaz en el guest únicamente para comunicarse con el host, funciona bien y en mi caso esto es para necesidades muy puntuales (emergencia casi siempre).</p>
<p>En resumen, esto fue para darles un pantallazo de algunos de los cambios que vamos a tener que hacer cuando migremos a 14.04. Estos cambios también están en RHEL 7, ya que son todos cambios de proyectos <em>upstream</em>, así que no nos ahorramos este trabajo yendo para aquel lado tampoco.</p>
<p>[1] <a href="http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/" target="_blank" rel="noopener">http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/</a><br />
[2] <a href="http://seravo.fi/2012/virtualized-bridged-networking-with-macvtap" target="_blank" rel="noopener">http://seravo.fi/2012/virtualized-bridged-networking-with-macvtap</a><br />
[3] <a href="http://virt.kernelnewbies.org/MacVTap" target="_blank" rel="noopener">http://virt.kernelnewbies.org/MacVTap</a><br />
[4] <a href="http://libvirt.org/formatnetwork.html#examplesDirect" target="_blank" rel="noopener">http://libvirt.org/formatnetwork.html#examplesDirect</a><br />
[5] <a href="http://www.linux-kvm.com/content/simple-bridged-networking-virt-manager-using-macvtap" target="_blank" rel="noopener">http://www.linux-kvm.com/content/simple-bridged-networking-virt-manager-using-macvtap</a><br />
[6] <a title="Enabling host-guest networking with KVM, Macvlan and Macvtap" href="http://www.furorteutonicus.eu/2013/08/04/enabling-host-guest-networking-with-kvm-macvlan-and-macvtap/" target="_blank" rel="noopener">http://www.furorteutonicus.eu/2013/08/04/enabling-host-guest-networking-with-kvm-macvlan-and-macvtap/</a></p>
<p>Saludos!</p>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.marcelofernandez.info/2014/05/migrando-host-de-vms-kvm-12-04-14-04/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title>Estableciendo conexiones HTTPS «bien seguras» en Python</title>
		<link>http://blog.marcelofernandez.info/2011/02/estableciendo-conexiones-https-bien-seguras-en-python/</link>
					<comments>http://blog.marcelofernandez.info/2011/02/estableciendo-conexiones-https-bien-seguras-en-python/#comments</comments>
		
		<dc:creator><![CDATA[Marcelo]]></dc:creator>
		<pubDate>Sat, 19 Feb 2011 19:45:55 +0000</pubDate>
				<category><![CDATA[codear]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[ubuntu-ar]]></category>
		<guid isPermaLink="false">https://blog.marcelofernandez.info/?p=1112</guid>

					<description><![CDATA[Hace unos días que tenía pendiente colgar esto acá, ya que a alguien en PyAr le fue útil. HTTPS es la manera de establecer conexiones HTTP pero seguras, en el sentido de que previo al diálogo HTTP estándar pero luego de establecerse la conexión TCP contra el servidor, se negocia entre los participantes una conexión/sesión [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Hace unos días que tenía pendiente colgar esto acá, ya que a alguien en <a href="http://www.python.org.ar" target="_blank">PyAr</a> <a href="http://comments.gmane.org/gmane.org.user-groups.python.argentina/44953" target="_blank">le fue útil</a>.</p>
<p><a href="http://es.wikipedia.org/wiki/Https" target="_blank">HTTPS</a> es la manera de establecer conexiones HTTP pero <em>seguras</em>, en el sentido de que previo al diálogo HTTP estándar pero luego de establecerse la conexión TCP contra el servidor, se negocia entre los participantes una conexión/sesión «especial» entre ambos.  Allí se intercambian certificados con el fin de autenticar contra quién se «está hablando», para luego, si hubo éxito en la dicha comprobación, encriptar (o no) todo lo que va para el otro lado, tanto del Servidor al Cliente (generalmente un navegador), como del Cliente al Servidor.</p>
<p>Todo eso forma parte de SSL 3.0 (hoy <a href="http://es.wikipedia.org/wiki/Transport_Layer_Security" target="_blank">TLS 1.0</a>), y si bien se puede utilizar para cualquier conexión TCP (SMTP, IMAP, etc., lo pueden usar también), su uso más común se da cuando uno entra a su casilla de Webmail o su cuenta del Banco desde el navegador;  lo que sucede allí es que nuestro navegador autentica al Servidor, y si todo va bien nos muestra el famoso «candadito» e informa que la sesión «es segura». Ahora bien, en esos casos, el Banco o Webmail no nos autentica a nosotros como Cliente y deja que cualquiera se conecte a su página, ya que eso requiere varios pasos más (sería realmente engorroso que sea obligatorio).</p>
<p>Sin embargo, en nuestra vida de programadores nos solemos encontrar con necesidades del entorno que nos obliguen a esta situación un tanto extrema y bastante más segura: que tanto el Cliente que desarrollamos autentique al Servidor como que el Servidor autentique al Cliente, amén de que la conexión muy probablemente deberá estar encriptada. <strong>Esto nos permitirá asegurarnos que los Clientes (software) que se conecten a nuestro Servidor sean únicamente quienes queremos que sean</strong> (o casi).</p>
<p>Python, dentro del módulo <a href="http://docs.python.org/library/httplib.html" target="_blank">httplib</a> nos provee de la clase <strong>HTTPSConnection</strong>, que maneja y nos abstrae en varias de estas cuestiones de SSL/TLS y nos deja trabajar a nivel HTTP (una capa más arriba). Lo que hay que observar bien (y que recién en la versión 2.7 de la documentación apareció en rojo), es que esta clase aún cuando uno le puede pasar como parámetro los paths a certificados, <strong>en realidad no hace ninguna comprobación de validez del certificado que el Servidor exporta</strong>. Con lo cual, hay un potencial problema: que nuestro cliente mande los datos a cualquier lado menos a nuestro Servidor de confianza.</p>
<p>¿Y cómo se fuerza a que nuestro programa Cliente chequee el certificado del Servidor? Armé esta clase que extiende sólo lo necesario a HTTPSConnection, que funciona en Python 2.6.x y que me permite hacer eso.</p>
<p>Le agregué un ejemplo en la llamada a __main__ para mostrar cómo se usa:</p>
<pre lang="python">#!/usr/bin/env python
#-*- coding: utf-8 -*-

import socket
import ssl
import httplib

class HTTPSClientAuthConnection(httplib.HTTPSConnection):
    """ Class to make a HTTPS connection, with support for full client-based
        SSL Authentication.
    """

    def __init__(self, host, port, key_file, cert_file, ca_file, timeout=None):
        httplib.HTTPSConnection.__init__(self, host, key_file=key_file,
                                                   cert_file=cert_file)
        self.key_file = key_file
        self.cert_file = cert_file
        self.ca_file = ca_file
        self.timeout = timeout

    def connect(self):
        """ Connect to a host on a given (SSL) port.
            If ca_file is pointing somewhere, use it to check Server Certificate.

            Redefined/copied and extended from httplib.py:1105 (Python 2.6.x).
            This is needed to pass cert_reqs=ssl.CERT_REQUIRED as parameter
            to ssl.wrap_socket(), which forces SSL to check server certificate
            against our client certificate.
        """
        sock = socket.create_connection((self.host, self.port), self.timeout)
        if self._tunnel_host:
            self.sock = sock
            self._tunnel()
        # If there's no CA File, don't force Server Certificate Check
        if self.ca_file:
            self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
                        ca_certs=self.ca_file, cert_reqs=ssl.CERT_REQUIRED)
        else:
            self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
                                              cert_reqs=ssl.CERT_NONE)

if __name__ == '__main__':
    # Little test-case of our class
    import sys
    if len(sys.argv) != 6:
        print 'usage: ./https_auth_handler.py host port key_file cert_file ca_file'
        sys.exit(1)
    else:
        host, port, key_file, cert_file, ca_file = sys.argv[1:]
    conn = HTTPSClientAuthConnection(host, port, key_file=key_file,
                                           cert_file=cert_file, ca_file=ca_file)
    conn.request('GET', '/')
    response = conn.getresponse()
    print response.status, response.reason
    data = response.read()
    print data
    conn.close()</pre>
<p>En cuanto a la generación de las claves de Cliente, Servidor y CA <a href="http://www.google.com.ar/search?q=openssl+certificate+client+server+creation" target="_blank">hay unos cuantos artículos</a> y es relativamente sencillo una vez que se entiende qué se está haciendo. Por otra parte que en estos casos es muy común que el Servidor exija que el Cliente si o sí envíe su certificado o sino la conexión se deberá caer; esto en el caso del Servidor Apache está <a href="http://httpd.apache.org/docs/2.2/ssl/ssl_howto.html#allclients" target="_blank">bien documentado</a>.</p>
<p>Entiendo que en Python 3.2 esto está resuelto en la misma API standard de Python (en su momento abrí <a href="http://bugs.python.org/issue3466" target="_blank">un ticket similar</a> para usar esto con urllib2, que incluye cosas importantes como el manejo de cookies, por ejemplo), y comentaron eso.</p>
<p>Según me dijeron en PyAr, es casi seguro que este ejemplo no funcione en Python 2.7, así que en un futuro no muy lejano espero poder adaptar este código a dicha versión y seguramente lo estaré subiendo en esta página.</p>
<p>Saludos</p>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.marcelofernandez.info/2011/02/estableciendo-conexiones-https-bien-seguras-en-python/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>Virtualizando sólo una partición de una máquina física</title>
		<link>http://blog.marcelofernandez.info/2011/01/virtualizando-solo-una-particion-de-una-maquina-fisica/</link>
					<comments>http://blog.marcelofernandez.info/2011/01/virtualizando-solo-una-particion-de-una-maquina-fisica/#comments</comments>
		
		<dc:creator><![CDATA[Marcelo]]></dc:creator>
		<pubDate>Sat, 15 Jan 2011 00:26:20 +0000</pubDate>
				<category><![CDATA[codear]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[ubuntu-ar]]></category>
		<guid isPermaLink="false">https://blog.marcelofernandez.info/?p=1059</guid>

					<description><![CDATA[Hace poquito un amigo me contó que estuvo leyendo el post anterior de Consolidación y «Shrinking» de discos físicos para pasarlos a una máquina virtual, pero tenía un pequeño obstáculo relacionado con el espacio en disco necesario, que más o menos era así: Quería consolidar un disco real de 80 GB que tiene XP instalado [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Hace poquito un amigo me contó que estuvo leyendo <a href="https://blog.marcelofernandez.info/2010/08/achicando-imagenes-de-maquinas-virtuales-kvm-qcow2/" target="_blank">el post anterior</a> de Consolidación y «Shrinking» de discos físicos para pasarlos a una máquina virtual, pero tenía un pequeño obstáculo relacionado con el espacio en disco necesario, que más o menos era así:</p>
<blockquote><p>Quería consolidar un disco real de 80 GB que tiene XP instalado en su C:, pero en total el disco tiene 4 particiones (primarias). Sólo me interesaba el disco C:, con lo que ahorraba espacio en el proceso ya que la partición del C: sólo ocupa 25 GB.</p>
<p>Entonces hice la copia con «dd if=/dev/sdb1 of=imagen.raw». Como uso VirtualBox, con un comando lo convertí de .raw a .vdi. Pero no logré bootear.</p>
<p>Hice varias pruebas, siempre con VirtualBox y no lo logré. Supongo que es porque no se copió el MBR. En cambio, cuando copié el disco completo, booteó sin problemas.</p>
<p>La pregunta es: ¿Cómo debería haber hecho para trabajar solo con esa partición y de esa forma evitar trabajar con los 80GB?</p></blockquote>
<p>Bueno, el problema era que, efectivamente, al hacer el dd sobre /dev/sdb1 sólo se copian los bytes dentro de la partición y no el <a href="http://en.wikipedia.org/wiki/Master_boot_record" target="_blank">MBR</a>+Bootloader (la vieja «<a href="http://en.wikipedia.org/wiki/Track_0" target="_blank">pista 0</a>» del disco). <strong>Para resolver el problema habría que copiar los bytes de la pista 0 más los bytes de la partición en cuestión</strong>, siguiendo estos pasos:</p>
<p>Ejecutar el comando parted sobre /dev/sdb (en mi caso, voy a usar /dev/sda como ejemplo):</p>
<pre lang="bash">marcelo@jupiter:~$ sudo parted /dev/sda u s print
Modelo: ATA WDC WD3200BEVT-0 (scsi)
Disco /dev/sda: 625142448s
Tamaño de sector (lógico/físico): 512B/512B
Tabla de particiones. msdos

Numero  Inicio     Fin         Tamaño      Tipo      Sistema de ficheros  Banderas
 1      63s        32001479s   32001417s   primary   ext4                 arranque
 2      32001541s  94494329s   62492789s   extended
 5      32001543s  94494329s   62492787s   logical   ext4
 3      94494330s  98494514s   4000185s    primary   linux-swap(v1)
 4      98494515s  625137344s  526642830s  primary   ext4</pre>
<p>El parámetro «print» le dice a parted que me imprima la tabla de particiones, y «u s» que imprima los tamaños en sectores (que en los discos &lt;=1.0TB son siempre de 512 bytes, sino mismo parted lo dice en la salida, ver <a href="https://blog.marcelofernandez.info/2010/06/discos-rigidos-con-sectores-de-4kb-en-linux/" target="_blank">este post</a> para más detalles).</p>
<p>De esta manera se tienen todos los sectores a copiar de /dev/sda directamente; en mi caso, 63 sectores de la pista 0, que contiene al MBR, más los de la primera partición, 32001417, total: 32001480 sectores.</p>
<p>Luego el dd que sólo copia los bytes que nos interesan (Pista 0 + Partición «C:») es fácil:</p>
<pre lang="bash">sudo dd if=/dev/sda of=imagen.raw bs=512 count=32001480</pre>
<p>Y listo. Eso sí, luego hay que particionar la imagen con Parted, Fdisk, <a href="http://gparted.sourceforge.net/" target="_blank">GParted</a> o el software que se quiera utilizar a tal efecto. Es necesario hacerlo porque el MBR copiado va a reportar las 4 particiones que se tenían previamente en el disco y ahora sólo se va a disponer de una sola.</p>
<p>Asumo que este procedimiento también se puede aplicar para copiar una partición que no sea la primera, usando las opciones «skip» y «append» del comando dd; por ejemplo, si quisiera hacer un disco de sólo mi partición 5, tendría que:</p>
<ol>
<li>Copiar la pista 0 en un archivo con algo así como «dd if=/dev/sda of=imagen.raw bs=512 count=63».</li>
<li>Ejecutar otro dd con la partición a copiar, salteando («skipeando») N sectores con la opción «skip» y especificando la opción «append» para agregar al archivo anterior de salida: «dd if=/dev/sda of=imagen.raw bs=512 count=62492787 skip=32001543 append».</li>
</ol>
<p>Lógicamente esto último no lo probé, acepto comentarios de si funcionó o no <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Espero que a alguien le sirva&#8230;</p>
<p>¡Saludos!</p>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.marcelofernandez.info/2011/01/virtualizando-solo-una-particion-de-una-maquina-fisica/feed/</wfw:commentRss>
			<slash:comments>10</slash:comments>
		
		
			</item>
		<item>
		<title>Comparativas de Virtualización KVM</title>
		<link>http://blog.marcelofernandez.info/2011/01/comparativas-de-virtualizacion-kvm/</link>
					<comments>http://blog.marcelofernandez.info/2011/01/comparativas-de-virtualizacion-kvm/#comments</comments>
		
		<dc:creator><![CDATA[Marcelo]]></dc:creator>
		<pubDate>Wed, 05 Jan 2011 10:47:10 +0000</pubDate>
				<category><![CDATA[codear]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[ubuntu-ar]]></category>
		<guid isPermaLink="false">https://blog.marcelofernandez.info/?p=1037</guid>

					<description><![CDATA[Ultimamente por diferentes cuestiones personales estoy bastante desconectado de la lectura de noticias, blogs y demás. Sin embargo, me pareció útil dejar por acá dos comparativas sobre KVM de Phoronix.com, que si bien en algunos lados me encontré que se quejan de la «calidad» de su suite de benchmarks para software libre/abierto, por el otro, ¡hey! [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Ultimamente por diferentes cuestiones personales estoy bastante desconectado de la lectura de noticias, blogs y demás. Sin embargo, me pareció útil dejar por acá dos comparativas sobre KVM de <a href="http://www.phoronix.com/" target="_blank">Phoronix.com</a>, que si bien en algunos lados me encontré que se quejan de la «calidad» de su suite de <a href="http://www.phoronix-test-suite.com/" target="_blank">benchmarks</a> para software libre/abierto, por el otro, ¡hey! ¡al menos se preocupan en hacerlo! <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p><strong><a href="http://www.phoronix.com/scan.php?page=article&amp;item=linux_kvm_virtualbox4&amp;num=1" target="_blank">Linux KVM vs. VirtualBox 4.0 Virtualization Benchmarks</a></strong><br />
Este es un test de performance entre <a href="http://www.linux-kvm.com/" target="_blank">KVM</a> y <a href="http://www.virtualbox.org/" target="_blank">Virtualbox</a>. En resumen, y con los parámetros por defecto en cuanto a I/O, VBox gana, pero parece que es debido a que no hace los <a href="http://pubs.opengroup.org/onlinepubs/007908799/xsh/fsync.html" target="_blank">fsync</a> del guest en el host y termina utilizando su caché; muy probablemente este comportamiento es configurable (¿ver <a href="http://www.virtualbox.org/manual/ch05.html#iocaching" target="_blank">acá</a>?), pero así y todo ¡es bueno saberlo!. De todas maneras, de alguna manera es peligroso para un entorno de servidores ya que hay riesgo de pérdida de datos, pero por ejemplo, para mi notebook (<em>target </em>primario adonde Virtualbox siempre estuvo orientado) está bien.</p>
<p>Por el otro lado, cuando hay que usar la CPU, KVM «le pasa el trapo» a VBox. Hay un test de I/O de red (TCP) que a KVM le dio mal, tan mal, que seguro es debido a que los <span style="text-decoration: line-through;">salames</span> testers no habilitaron <a href="http://wiki.libvirt.org/page/Virtio#Network_driver" target="_blank">VirtIO</a> en los guests KVM.</p>
<p><a href="http://www.phoronix.com/scan.php?page=article&amp;item=linux_kvm_scaling&amp;num=1" target="_blank"><strong>Multi-Core Scaling In A KVM Virtualized Environment</strong></a><br />
Este test trata de dilucidar si es mito o no que el Hyperthreading (las VCPUs) de los microprocesadores <a href="http://en.wikipedia.org/wiki/Intel_Xeon#Nehalem_based_Xeon" target="_blank">Intel Xeon basados en Nehalem</a> hacen más lentas o más rápidas las VMs que corren sobre KVM. Esto es algo que pregunté personalmente en el IRC de KVM (#kvm en <a href="http://freenode.net/" target="_blank">Freenode</a>, dicho sea de paso), y me sugirieron lo mismo que dió en los tests: hay veces en donde las VMs aprovechan todas las CPUs virtuales (VCPUs) y otras en que no, con lo cual hay que probar en cada caso en particular y dejar la configuración que nos dé mejores resultados.</p>
<p>Interesante de leer y experimentar.</p>
<p>Saludos</p>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.marcelofernandez.info/2011/01/comparativas-de-virtualizacion-kvm/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Navegador simple con wxPython + Webkit/GTK</title>
		<link>http://blog.marcelofernandez.info/2010/10/navegador-simple-con-wxpython-webkitgtk/</link>
					<comments>http://blog.marcelofernandez.info/2010/10/navegador-simple-con-wxpython-webkitgtk/#comments</comments>
		
		<dc:creator><![CDATA[Marcelo]]></dc:creator>
		<pubDate>Sun, 10 Oct 2010 01:28:54 +0000</pubDate>
				<category><![CDATA[codear]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[ubuntu-ar]]></category>
		<guid isPermaLink="false">https://blog.marcelofernandez.info/?p=995</guid>

					<description><![CDATA[Hace algunos posts (¡casi un año ya!) escribí sobre una manera fácil y rápida de tener un componente «navegador web» en Python sobre Linux/BSD, gracias a PyGTK y WebkitGTK, llamado lógicamente, pyWebkitGTK. En pocas líneas de código uno puede disponer de un navegador potente y completo en un panel de su aplicación basada en PyGTK, [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Hace algunos posts (¡casi un año ya!) <a href="https://blog.marcelofernandez.info/2009/11/navegador-simple-con-pywebkitgtk/" target="_blank">escribí</a> sobre una manera fácil y rápida de tener un componente «navegador web» en Python sobre Linux/BSD, gracias a <a href="http://www.pygtk.org" target="_blank">PyGTK</a> y <a href="http://webkitgtk.org/" target="_blank">WebkitGTK</a>, llamado lógicamente, <a href="http://code.google.com/p/pywebkitgtk/" target="_blank">pyWebkitGTK</a>. En pocas líneas de código uno puede disponer de un navegador potente y completo en un panel de su aplicación basada en <a href="http://www.pygtk.org">PyGTK</a>, ideal para integrar aún más la cada omnipresente Web.</p>
<p>Las vueltas de la vida y las ganas de experimentar y aprender te llevan a probar otros frameworks/librerías, como lo es <a href="http://www.wxpython.org" target="_blank">wxPython</a>; tanto es así que de vez en cuando tengo el placer de dar <a href="/charlas/" target="_blank">alguna charla</a> al respecto <a href="#nota1">[1]</a>, y una de las debilidades que le usualmente le encontraba es la falta de un componente «browser web» nativo y soportado en todas las plataformas (wxPython sólo incluye IE embebible como ActiveX en Windows).</p>
<p>En búsqueda de alternativas existe <a href="http://wxwebkit.wxcommunity.com/" target="_blank">wxWebKit</a>, pero al proyecto le faltan terminar algunas cosas para tener lista su versión «1.0», y si bien <a href="http://www.kirix.com/labs/wxwebconnect/" target="_blank">wxWebConnect</a> funciona, no da soporte para wxPython, sólo wxWidgets desde C++. Eso nos deja con que en Linux/BSD no tenemos componente que nos dé esta posibildad, pero&#8230; si wxPython en estas plataformas utiliza GTK por debajo, ¿no podríamos usar pyWebkitGTK como componente para embeberlo en nuestra aplicación Python?</p>
<p>La respuesta por suerte es afirmativa, y en una rápida búsqueda en la <a href="http://wiki.wxpython.org" target="_blank">Wiki de wxPython</a> encontré <a href="http://wiki.wxpython.org/wxGTKWebKit" target="_blank">un ejemplo de cómo hacerlo</a>. Si bien podría copiar y pegar la receta, me gustaría «<em>aggiornarla</em>» un poquito, al menos traduciendo y explicando un poco más los comentarios.</p>
<p>Primero vamos a mostrar cómo se vería el módulo que incluye un widget HtmlPanel, wxwebkitgtk.py:</p>
<pre lang="python">#!/usr/bin/env python
# coding:utf-8

"""
    wxWebkitGTK - Componente wxPython que embebe un navegador
                   utiliza la biblioteca Webkit GTK desde Python (PyWebkitGTK).

    Marcelo Fidel Fernández - http://www.marcelofernandez.info
    Basado en: http://wiki.wxpython.org/wxGTKWebKit
"""
import os
import wx
import gobject
gobject.threads_init()
import gtk, gtk.gdk
import webkit

class HtmlPanel(wx.Panel):

    def __init__(self, *args, **kwargs):
        wx.Panel.__init__(self, *args, **kwargs)
        # Aquí es donde se hace la "magia" de embeber webkit en wxGTK.
        whdl = self.GetHandle()
        window = gtk.gdk.window_lookup(whdl)
        # Debemos mantener la referencia a "pizza", sino obtenemos un segfault.
        self.pizza = window.get_user_data()
        # Obtengo el padre de la clase GtkPizza, un gtk.ScrolledWindow
        self.scrolled_window = self.pizza.parent
        # Saco el objeto GtkPizza para poner un WebView en su lugar
        self.scrolled_window.remove(self.pizza)
        self.webview = webkit.WebView()
        self.scrolled_window.add(self.webview)
        self.scrolled_window.show_all()</pre>
<p>La «magia» consiste en que, sabiendo que pyWebkitGTK necesita un componente <a href="http://library.gnome.org/devel/pygtk/stable/class-gtkscrolledwindow.html" target="_blank">ScrolledWindow</a> GTK como padre para funcionar correctamente, se utiliza la biblioteca PyGTK para buscar el ScrolledWindow GTK donde está embebido el wx.Panel de la clase (su «abuelo»), y reemplazar el hijo GTKPizza (un componente inventado por wxWidgets para funcionar) por el WebView de Webkit.</p>
<p>Aquí hay un ejemplo de cómo se puede utilizar este panel como widget de wxPython completo e independiente, copiando la funcionalidad básica del <a href="https://blog.marcelofernandez.info/2009/11/navegador-simple-con-pywebkitgtk/">post de PyWebkitGTK</a>, el archivo wxwebkitgtk_demo.py:</p>
<pre lang="python">#!/usr/bin/env python
# coding: utf-8

"""
    wxSimpleBrowser - Navegador muy muy simple de internet, sólo de ejemplo,
                      que utiliza la biblioteca Webkit GTK desde wxPython.

    Marcelo Fidel Fernández - http://www.marcelofernandez.info
    Licencia: BSD. Disponible en: http://www.freebsd.org/copyright/license.html
"""

import sys
import wx
from wxwebkitgtk import HtmlPanel

DEFAULT_URL = 'http://www.python.org'

class wxSimpleBrowser(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, None)
        self.TxtUrl = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_PROCESS_ENTER)
        self.TxtUrl.Bind(wx.EVT_TEXT_ENTER, self.OnTxtURL)
        self.Box = wx.BoxSizer(wx.VERTICAL)
        self.Box.Add(self.TxtUrl, proportion=0, flag=wx.EXPAND)
        self.SetSizer(self.Box)
        self.SetSize((800,600))
        self.Show()
        # Necesitamos tener mostrado el componente padre del Panel para que funcione,
        # por eso mostramos primero el Frame y después creamos el HtmlPanel
        self.HtmlPanel = HtmlPanel(self)
        self.Box.Add(self.HtmlPanel, proportion=1, flag=wx.EXPAND)
        self.SendSizeEvent() # Para acomodar el panel al tamaño del frame

    def OnTxtURL(self, event):
        self.Open(self.TxtUrl.GetValue())

    def Open(self, url):
        # Podemos acceder a todos los métods del objeto WebView
        # http://webkitgtk.org/reference/webkitgtk-webkitwebview.html
        self.HtmlPanel.webview.load_uri(url)
        self.TxtUrl.SetValue(url)
        self.SetTitle('wxSimpleBrowser - %s' % url)

if __name__ == '__main__':
    if len(sys.argv) &gt; 1:
        url = sys.argv[1]
    else:
        url = DEFAULT_URL
    app = wx.App()
    browser = wxSimpleBrowser()
    browser.Open(url)
    app.MainLoop()</pre>
<p>Creo que para la enorme funcionalidad que nos brinda el proceso de ponerlo en práctica es bastante simple, y aunque depende de PyGTK, ésta biblioteca hoy está disponible «de fábrica» en cualquier distribución moderna de GNU/Linux. </p>
<p>De aquí en más es ser muy sencillo dejar al lector el armado de un widget para wxPython que en Windows muestre el componente navegador de IE y en Linux un navegador Webkit.</p>
<p><a name="nota1"></a>[1] ¡La semana que viene voy a estar en la <a href="http://ar.pycon.org/2010/about/" target="_blank">PyCon Argentina 2010</a> dando una charla de <a href="http://ar.pycon.org/2010/conference/schedule/event/55/" target="_blank">Introducción a wxPython</a>! <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>¡Saludos!</p>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.marcelofernandez.info/2010/10/navegador-simple-con-wxpython-webkitgtk/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
			</item>
		<item>
		<title>Achicando imágenes de Máquinas Virtuales (KVM-QCow2)</title>
		<link>http://blog.marcelofernandez.info/2010/08/achicando-imagenes-de-maquinas-virtuales-kvm-qcow2/</link>
					<comments>http://blog.marcelofernandez.info/2010/08/achicando-imagenes-de-maquinas-virtuales-kvm-qcow2/#comments</comments>
		
		<dc:creator><![CDATA[Marcelo]]></dc:creator>
		<pubDate>Sat, 14 Aug 2010 07:14:26 +0000</pubDate>
				<category><![CDATA[codear]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[ubuntu-ar]]></category>
		<guid isPermaLink="false">https://blog.marcelofernandez.info/?p=936</guid>

					<description><![CDATA[Consolidando Máquinas Físicas a Virtuales Dentro del mundo de la Virtualización, al momento de consolidar máquinas [1] lo más sencillo (o lo que primero se le puede ocurrir a uno [2]) es hacer una imagen bit a bit del disco donde éste se aloja a un archivo del Host, mediante alguna herramienta como dd en [&#8230;]]]></description>
										<content:encoded><![CDATA[<h2>Consolidando Máquinas Físicas a Virtuales</h2>
<p>Dentro del mundo de la Virtualización, al momento de consolidar máquinas <a href="#1">[1]</a> lo más sencillo (o lo que primero se le puede ocurrir a uno <a href="#2">[2]</a>) es hacer una imagen bit a bit del disco donde éste se aloja a un archivo del <em>Host</em>, mediante alguna herramienta como <a href="http://en.wikipedia.org/wiki/Dd_(Unix)" target="_blank">dd</a> en Linux:</p>
<pre lang="text">$ dd if=/dev/sdb of=/vms/images/imagen.raw</pre>
<p>Este mecanismo es generalmente infalible; luego de ésto, uno crea un perfil de una Máquina Virtual (típicamente un archivo XML donde se describen las características del <em>Guest</em>), se lo relaciona a esta imagen «cruda» de la ex-Máquina Física, y en un minutos la misma está corriendo como Máquina Virtual sin problemas.</p>
<p>Además, es más común utilizar un formato de imágenes más flexible que el Raw («crudo»), que soporte características como:</p>
<ul>
<li><a href="http://en.wikipedia.org/wiki/Virtual_disk_image#Dynamic_Storage_Growth" target="_blank">Almacenamiento/Crecimiento dinámico</a>.</li>
<li><em><a href="http://en.wikipedia.org/wiki/Qcow2" target="_blank">Copy-On-Write</a></em> (en este caso se trata de la posibilidad de tener una imagen «base» en modo sólo lectura y guardar las diferencias en otra imagen).</li>
<li>Gestionar <em><a href="http://en.wikipedia.org/wiki/Snapshot_(computer_storage)" target="_blank">snapshots</a> </em>del disco de cualquier momento dado.</li>
<li>Compresión al vuelo.</li>
<li>Encriptación.</li>
<li>etc.</li>
</ul>
<p>Es aquí donde cada solución de virtualización <a href="http://en.wikipedia.org/wiki/Virtual_disk_image" target="_blank">tiene su propio formato</a> para obtener todas o algunas de estas ventajas, según el caso:</p>
<ul>
<li><a href="http://www.virtualbox.org" target="_blank">VirtualBox</a> tiene al formato <a href="http://en.wikipedia.org/wiki/VirtualBox#Virtual_Desktop_Image" target="_blank">VDI</a>,</li>
<li><a href="http://www.vmware.com" target="_blank">VMWare</a> tiene el <a href="http://en.wikipedia.org/wiki/VMDK" target="_blank">VMDK</a>,</li>
<li><a href="http://www.linux-kvm.com/" target="_blank">KVM+QEmu</a> tiene el <a href="http://people.gnome.org/~markmc/qcow-image-format.html" target="_blank">QCow2</a>,</li>
<li>etc.</li>
</ul>
<p>El manejo del almacenamiento en forma dinámica de éstos nos permite que al momento de crear una imagen de un disco de por ejemplo, 80 GB, la imagen ocupe físicamente unos pocos cientos de bytes; a medida que se van guardando archivos en el disco de la VM, éstos son almacenados finalmente en el archivo de imagen, hasta llegar al tope estipulado al momento de crear la imagen de disco (los 80 GB, por ejemplo).</p>
<p>Pero volvamos al caso de la generación de una imagen de un disco físico de un equipo, ¿qué pasa si éste era de 160 GB y sólo tenía 20 GB de información guardada en uso efectivo? El archivo .raw es una copia bit a bit del disco de punta a punta, por lo tanto, su imagen Raw («cruda») en el Host ocupará 160 GB. Es decir, <strong>este mecanismo no discrimina el espacio ocupado por los archivos de datos del no utilizado y/o de archivos eliminados</strong>.</p>
<p>Bueno entonces, ¿para qué tenemos los formatos de imágenes nativos del <em>hypervisor </em>(KVM+QEmu en nuestro caso) que mencionamos anteriormente? ¿Es posible convertir una imagen Raw en una QCow2, para que su imagen ocupe los 20 GB de datos en vez de 160 GB? Sí es posible la conversión; para todas las operaciones con imágenes de disco KVM+QEmu tiene la herramienta <a href="http://wiki.qemu.org/download/qemu-doc.html#disk_005fimages" target="_blank">qemu-img</a>:</p>
<pre lang="bash">$ qemu-img convert -f raw imagen.raw -O qcow2 imagen.qcow2</pre>
<p>Con ese comando convertimos el archivo Raw al formato QCow2, buscando que la imagen a utilizar sea más pequeña , pero en su lugar la mejora de espacio es mucho menor a la esperada (aún si se llegara a dar). Es aquí donde nos encontraremos con un problema: <strong>¡qemu-img no sabe distinguir entre los archivos de datos y el espacio no utilizado/eliminado!</strong> Si la máquina física estuvo en uso por algún tiempo, es probable que no lleguemos ni cerca al archivo «ideal» de 20 GB. Si momentáneamente tuve en ese disco de esa máquina física 60 GB extras de música y fotos familiares, seguramente el archivo QCow2 convertido desde Raw no va a bajar de los 80GB, por ejemplo.</p>
<p>¿Y esto porqué sucede? <a href="http://en.wikipedia.org/wiki/Data_remanence" target="_blank">La teoría</a> dice que:</p>
<ul>
<li>Todo aquel espacio de disco, que viene de fábrica digamos, está compuesto de bytes en cero (0x00).</li>
<li>Todo aquel espacio de disco que es utilizado primero y luego borrado del disco, no es eliminado físicamente, es decir, no vuelve a cero, sino que queda con el contenido previo. El sistema de archivos en la enorme mayoría de los casos, para ganar velocidad (y mucha) al hacerlo, sólo quita la referencia en el índice del Sistema de Archivos al conjunto de clusters del disco que tiene el contenido real del archivo. Es por eso que uno «no ve» al archivo recientemente eliminado porque el índice de archivos existentes no lo tiene más, pero físicamente el archivo sigue estando.</li>
<li>QEmu-img reconoce como espacio vacío los bytes en cero.</li>
</ul>
<p>Sin embargo, tenemos opciones para hacer lo que queremos y no quedarnos sin espacio en el Host rápidamente, nada más que en KVM+QEmu <a href="http://qemu-forum.ipi.fi/viewtopic.php?t=2739" target="_blank">hay que hacerlo</a> <a href="http://itpro.haqida.uz/d/admin-notes/20-how-to-shrink-qcow-file.html" target="_blank">un poco</a> <a href="http://kerneltrap.org/mailarchive/linux-kvm/2009/3/22/5215854/thread" target="_blank">más a mano</a>; este proceso se llama en inglés «<em>Image Shrinking</em>» («achicar», «reducir», «contraer» la imagen). <a href="#3">[3]</a><a href="#4">[4]</a></p>
<h2>Achicando («Shrinkeando») imágenes de discos virtuales</h2>
<p>Según «la teoría» y los <a href="http://qemu-forum.ipi.fi/viewtopic.php?t=2739" target="_blank">links</a> <a href="http://itpro.haqida.uz/d/admin-notes/20-how-to-shrink-qcow-file.html" target="_blank">que se han citado</a><a href="http://kerneltrap.org/mailarchive/linux-kvm/2009/3/22/5215854/thread" target="_blank"> </a>, <strong>para poder recuperar espacio ocupado del disco hay que ponerlo en cero</strong>; ¿Y cómo se hace? Fácil, <strong>creando un archivo tan grande como el espacio remanente del disco lleno de ceros</strong>.</p>
<h3>Armando el Caso de Prueba</h3>
<p>Vamos a tratar de reproducir el problema y solucionarlo en forma representativa con una imagen Raw de 10 MB, como para que cualquiera pueda seguir estos pasos y entender de qué se trata todo esto.</p>
<p>1) Creamos una imagen Raw de prueba con 10 MB de bytes aleatorios:</p>
<pre lang="text">marcelo@marcelo-laptop:~$ dd if=/dev/urandom of=test.raw bs=1024 count=10000
10000+0 registros de entrada
10000+0 registros de salida
10240000 bytes (10 MB) copiados, 2,24907 s, 4,6 MB/s
marcelo@marcelo-laptop:~$</pre>
<p>2) Ya que todo disco tiene una tabla de particiones, se la creamos con parted:</p>
<pre lang="text">marcelo@marcelo-laptop:~$ parted test.raw print
AVISO: Usted no es el superusuario. Compruebe los permisos.
Error: /home/marcelo/test.raw: etiqueta de disco no reconocida
marcelo@marcelo-laptop:~$ parted test.raw mktable msdos
AVISO: Usted no es el superusuario. Compruebe los permisos.
marcelo@marcelo-laptop:~$ parted test.raw print
AVISO: Usted no es el superusuario. Compruebe los permisos.
Modelo:  (file)
Disco /home/marcelo/test.raw: 10,2MB
Tamaño de sector (lógico/físico): 512B/512B
Tabla de particiones. msdos

Numero  Inicio  Fin  Tamaño  Tipo  Sistema de ficheros  Banderas

marcelo@marcelo-laptop:~$</pre>
<p>El «parted test.raw print» muestra la tabla de particiones, y el «parted test.raw mktable msdos» crea una tabla de particiones de tipo MSDOS (hay otros tipos, como por ejemplo <a href="http://en.wikipedia.org/wiki/GUID_Partition_Table" target="_blank">GUID</a>). Primero vemos que el print da un error, luego creamos la tabla y por último vemos la tabla de particiones sin particiones definidas.</p>
<p>3) Ahora hay que crear una partición en esa tabla, nuevamente con parted:</p>
<pre lang="text">marcelo@marcelo-laptop:~$ parted test.raw mkpart primary 0 10
AVISO: Usted no es el superusuario. Compruebe los permisos.
Aviso: La partición resultante no está debidamente alineada para el mejor rendimiento.
Descartar/Ignore/Cancelar/Cancel? Ignore
marcelo@marcelo-laptop:~$ parted test.raw print
AVISO: Usted no es el superusuario. Compruebe los permisos.
Modelo:  (file)
Disco /home/marcelo/test.raw: 10,2MB
Tamaño de sector (lógico/físico): 512B/512B
Tabla de particiones. msdos

Numero  Inicio  Fin     Tamaño  Tipo     Sistema de ficheros  Banderas
 1      512B    10,2MB  10,2MB  primary

marcelo@marcelo-laptop:~$</pre>
<p>4) Ahora le damos formato a la partición en la imagen, por ejemplo, NTFS. El parámetro «&#8211;fast» es para que no llene de ceros la partición al momento de crearla (sólo para que siga con datos aleatorios) y el «&#8211;force» es para que se haga la operación a pesar de que el archivo no es un disco «de verdad».</p>
<pre lang="text">marcelo@marcelo-laptop:~$ mkfs.ntfs --fast --force test.raw
test.raw is not a block device.
mkntfs forced anyway.
The sector size was not specified for test.raw and it could not be obtained automatically.  It has been set to 512 bytes.
The partition start sector was not specified for test.raw and it could not be obtained automatically.  It has been set to 0.
The number of sectors per track was not specified for test.raw and it could not be obtained automatically.  It has been set to 0.
The number of heads was not specified for test.raw and it could not be obtained automatically.  It has been set to 0.
Cluster size has been automatically set to 4096 bytes.
To boot from a device, Windows needs the 'partition start sector', the 'sectors per track' and the 'number of heads' to be set.
Windows will not be able to boot from this device.
Creating NTFS volume structures.
mkntfs completed successfully. Have a nice day.
marcelo@marcelo-laptop:~$ parted test.raw print
AVISO: Usted no es el superusuario. Compruebe los permisos.
Modelo:  (file)
Disco /home/marcelo/test.raw: 10,2MB
Tamaño de sector (lógico/físico): 512B/512B
Tabla de particiones. loop

Numero  Inicio  Fin     Tamaño  Sistema de ficheros  Banderas
 1      0,00B   10,2MB  10,2MB  ntfs

marcelo@marcelo-laptop:~$</pre>
<p>6) Perfecto, ya tenemos nuestro «mini disco» NTFS para jugar. Ahora vamos a montarlo y ver qué tiene:</p>
<pre lang="text">marcelo@marcelo-laptop:~$ sudo mount -o loop test.raw /mnt
[sudo] password for marcelo:
marcelo@marcelo-laptop:~$ mount
/dev/sda1 on / type ext4 (rw,errors=remount-ro)
[...]
/dev/loop0 on /mnt type fuseblk (rw,nosuid,nodev,allow_other,blksize=4096)
marcelo@marcelo-laptop:~$ tail /var/log/syslog
[...]
Aug 14 02:28:57 marcelo-laptop ntfs-3g[19770]: Version 2010.3.6 external FUSE 28
Aug 14 02:28:57 marcelo-laptop ntfs-3g[19770]: Mounted /dev/loop0 (Read-Write, label "", NTFS 3.1)
Aug 14 02:28:57 marcelo-laptop ntfs-3g[19770]: Cmdline options: rw
Aug 14 02:28:57 marcelo-laptop ntfs-3g[19770]: Mount options: rw,silent,allow_other,nonempty,relatime,fsname=/dev/loop0,blkdev,blksize=4096
Aug 14 02:28:57 marcelo-laptop ntfs-3g[19770]: Ownership and permissions disabled, configuration type 1
marcelo@marcelo-laptop:~$  ls -l /mnt
total 0
marcelo@marcelo-laptop:~$</pre>
<p>7) Ahora estamos como si hubiéramos hecho el dd de un disco físico en nuestro Host con KVM+QEmu. Como se ha visto, la imagen no tiene nada en el sistema de archivos pero físicamente está lleno de bytes aleatorios y ocupa 10 MB, el tamaño completo. ¿Qué pasa si lo convertimos a QCow2? ¿Se cumple «la teoría»?</p>
<pre lang="text">marcelo@marcelo-laptop:~$ sudo umount /mnt
marcelo@marcelo-laptop:~$ qemu-img convert -f raw test.raw -O qcow2 test.qcow2
marcelo@marcelo-laptop:~$ ls -l
[...]
-rw-r--r--  1 marcelo marcelo 10420224 2010-08-14 02:37 test.qcow2
-rw-r--r--  1 marcelo marcelo 10240000 2010-08-14 02:28 test.raw
[...]
marcelo@marcelo-laptop:~$ qemu-img info test.raw
image: test.raw
file format: raw
virtual size: 9.8M (10240000 bytes)
disk size: 9.8M
marcelo@marcelo-laptop:~$ qemu-img info test.qcow2
image: test.qcow2
file format: qcow2
virtual size: 9.8M (10240000 bytes)
disk size: 9.8M
cluster_size: 65536
marcelo@marcelo-laptop:~$</pre>
<p>Sí, se cumple&#8230; es más, la imagen QCow2 ocupa más espacio que la Raw (por ahora). Hemos podido reproducir el problema.</p>
<h3>Llenando de Ceros el espacio vacío &#8211; Wiper.py</h3>
<p>Bien, ahora se me ocurrió armar un script en Python para que me ayude a automatizar el proceso de crear un archivo con ceros hasta que me quede sin espacio para luego borrarlo. Lo llamé «wiper.py». El código fuente es el siguiente:</p>
<pre lang="python">#!/usr/bin/env python
# coding: utf-8

# Wiper
# Copyleft 2010 - Licencia BSD
# Autor: Marcelo Fernández.
# Email: marcelo.fidel.fernandez@gmail.com

# This script creates a file which fills the available disk with zero bytes,
# and when the disk is full, the file is deleted.
# This allow to convert a raw partition to qcow2 'shrinking' the real image

import sys, os, errno

FILENAME = 'wiper.000'
STEP_SIZE = 4096

if __name__ == '__main__':
    if len(sys.argv) != 2:
        print 'usage: python wiper.py path_mounted_image'
        sys.exit(1)
    fat_file_path = os.path.join(sys.argv[1], FILENAME)
    try:
        fat_file = open(fat_file_path, 'wb', STEP_SIZE)
    except Exception, e:
        print 'There was an error opening the file in %s: %s' % (fat_file_path, str(e))
        sys.exit(2)
    print 'Temp file %s open for writing. Filling disk...' % fat_file_path
    try:
        while True:
            fat_file.write('\x00' * STEP_SIZE)
    except EnvironmentError, env_error:
        if env_error.errno == errno.ENOSPC:
            print 'No space left on device, good! Deleting temp file...'
        else:
            # There was another error different from 'No space available',
            # anyway we'll alway try to delete the fat_file
            print 'Abnormal error: ', oserror
    except Exception, e:
        # Rarely, but this could happend too
        print 'Exception: ' + repr(e)
    fat_file.close()
    try:
        os.unlink(fat_file_path)
    except Exception, e:
        print 'There was a problem deleting the temp file.'
    else:
        print 'Temp file erased ok.'</pre>
<p>Básicamente hace lo necesario, el STEP_SIZE es importante para que la operación sea bastante más rápida que escribiendo de a un byte. Vamos a ejecutar el script y convertir nuevamente el archivo Raw a QCow2 con qemu-img a ver qué sucede:</p>
<pre lang="text">marcelo@marcelo-laptop:~$ sudo mount -o loop test.raw /mnt
marcelo@marcelo-laptop:~$ python wiper.py /mnt/
Temp file /mnt/wiper.000 open for writing. Filling disk...
No space left on device, good! Deleting temp file...
Temp file erased ok.
marcelo@marcelo-laptop:~$ ls -l /mnt
total 0
marcelo@marcelo-laptop:~$ sudo umount /mnt
marcelo@marcelo-laptop:~$ qemu-img convert -f raw test.raw -O qcow2 test_shrinked.qcow2
marcelo@marcelo-laptop:~$ ls -l
[...]
-rw-r--r--  1 marcelo marcelo 10420224 2010-08-14 02:42 test.qcow2
-rw-r--r--  1 marcelo marcelo 10240000 2010-08-14 02:58 test.raw
-rw-r--r--  1 marcelo marcelo  3014656 2010-08-14 02:58 test_shrinked.qcow2
marcelo@marcelo-laptop:~$ sudo mount -o loop test.raw /mnt
marcelo@marcelo-laptop:~$ df -h
S.ficheros            Tamaño Usado  Disp Uso% Montado en
/dev/sda1              16G  6,7G  7,7G  47% /
[...]
/home/marcelo/test.raw
                      9,8M  2,5M  7,3M  26% /mnt
marcelo@marcelo-laptop:~$</pre>
<p>Bueno, ahora sí, el archivo QCow2 ocupa un cuarto del archivo Raw (2,5 MB). ¿En qué se gastan estos 2.5MB? Seguramente en los índices del sistema de archivos para poder gestionar el espacio libre. Es altamente probable que más que este espacio recuperado no podamos ganar, ya que si tocamos estos índices, corrompemos el sistema de archivos; recordemos que en test.raw puede haber un Sistema Operativo completo con todos sus archivos de datos.</p>
<p>De todas maneras, esto puede variar según el sistema de archivos de la imagen (NTFS en este caso) y los parámetros con los cuales se está manejando el mismo (el tamaño de bloque y de cluster incide mucho en el espacio que ocupan los índices de los Sistemas de Archivos en general).</p>
<h2>Conclusiones</h2>
<p>Es bueno saber que también se puede usar el comando dd para crear un archivo lleno de ceros en la partición ntfs de pruebas montada, con el comando «dd if=/dev/zero of=/mnt/borrame.000» y después borrar el archivo en cuestión, pero puede hacerse interminable el «llenado» si no pasamos como parámetro un block size relativamente grande, como de 4096 bytes:</p>
<pre lang="text">marcelo@marcelo-laptop:~$ time dd if=/dev/zero of=/mnt/borrame.000 bs=4096
dd: escribiendo «/mnt/borrame.000»: No hay espacio libre en el dispositivo
1863+0 registros de entrada
1862+0 registros de salida
7626752 bytes (7,6 MB) copiados, 0,144428 s, 52,8 MB/s

real	0m0.149s
user	0m0.000s
sys	0m0.030s
marcelo@marcelo-laptop:~$</pre>
<p>Prueben a pasarle bs=1, a ver cuánto tarda&#8230;. (lo pueden cortar con Ctrl+C). <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Una cuestión más que queda dando vueltas es que esta situación de espacio desperdiciado por la imagen se da también luego de un tiempo de usar la Máquina Virtual, si se da el caso de que se libere espacio en forma masiva; como caso, el ejemplo de un disco de 80 GB con 20 GB dedicados al Sistema Operativo más 60 GB de fotos y música eliminados recientemente.  Aquí también será útil correr wiper.py en la imagen montada y volver a ejecutar «qemu-img convert» para <em>shrinkear</em> la imagen.</p>
<p>En fin, espero que este post le sea de utilidad a aquellos que trabajamos con tan formidable <em>hypervisor</em> como lo es KVM y su gestor de I/O como lo es QEmu.</p>
<p>Saludos</p>
<p><a id="1">[1]</a> Si bien a un Linux se lo puede consolidar más fácilmente, sólo copiando todos los archivos con rsync, o «cp -a», con Windows este método no funciona, y hay que copiar el disco o al menos la partición completa. La idea al usar dd es abstraerse del SO.<br />
<a id="2">[2]</a> En vez de dd se puede usar una herramienta de clonación de discos/particiones que «entienda» o «interprete» el filesystem, como <a href="http://www.partimage.org/Main_Page" target="_blank">Partimage</a> para intentar generar directamente una imagen Raw con el espacio no utilizado en cero; pero nunca lo probé, ni me parece un método muy «limpio», ya que estamos insertando un software algo complejo en el medio de algo que de cualquier otra manera es conceptualmente simple y repetible. En el único caso que lo probaría es si estoy falto de espacio de disco en el Host. Si alguien lo prueba, me avisa. <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br />
<a id="3">[3]</a> Creo que «comprimir» no es la palabra apropiada porque da la idea al lector de que hay un proceso (que implementa un algoritmo) de <a href="http://en.wikipedia.org/wiki/Data_compression" target="_blank">compresión de datos</a> sin pérdida, como por ejemplo, <a href="http://en.wikipedia.org/wiki/Lempel-Ziv" target="_blank">LZ</a>. Sin embargo, aquí lo que se necesita es recuperar el espacio no utilizado de la imagen, para obtener un tamaño de imagen menor.<br />
<a id="4">[4]</a> Como nota al margen, VMWare tiene en sus VMWare Tools una opción para hacer «Shrink» de la imagen, pero ¿cómo se divierte un Sysadmin con ganas de aprender si sólo tiene que hacer click en un botón que diga «Shrink Image»? <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f61b.png" alt="😛" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.marcelofernandez.info/2010/08/achicando-imagenes-de-maquinas-virtuales-kvm-qcow2/feed/</wfw:commentRss>
			<slash:comments>10</slash:comments>
		
		
			</item>
		<item>
		<title>Free Pascal y Lazarus en Ubuntu</title>
		<link>http://blog.marcelofernandez.info/2010/06/free-pascal-y-lazarus-en-ubuntu/</link>
					<comments>http://blog.marcelofernandez.info/2010/06/free-pascal-y-lazarus-en-ubuntu/#comments</comments>
		
		<dc:creator><![CDATA[Marcelo]]></dc:creator>
		<pubDate>Sun, 20 Jun 2010 11:00:18 +0000</pubDate>
				<category><![CDATA[codear]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[ubuntu-ar]]></category>
		<guid isPermaLink="false">https://blog.marcelofernandez.info/?p=898</guid>

					<description><![CDATA[Creo que la gran mayoría de los programadores debemos recordar aquellos primeros momentos en que uno pasaba tardes y noches enteras escribiendo y escribiendo líneas de código en aquellas XT, AT, Commodores 64/128, etc., sólo por amor al arte y puro fanatismo. Supongo que diríamos lo mismo de los primeros años de facultad, cuando en [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Creo que la gran mayoría de los programadores debemos recordar aquellos primeros momentos en que uno pasaba tardes y noches enteras escribiendo y escribiendo líneas de código en aquellas XT, AT, Commodores 64/128, etc., sólo por amor al arte y puro fanatismo. Supongo que diríamos lo mismo de los primeros años de facultad, cuando en materias de título «Programación I» uno repasaba el paradigma de la <a href="http://es.wikipedia.org/wiki/Programaci%C3%B3n_estructurada" target="_blank">Programación Estructurada</a>, casi siempre en el lenguaje de aprendizaje facultativo por excelencia, al menos acá en Argentina: <strong><a href="http://es.wikipedia.org/wiki/Lenguaje_de_programaci%C3%B3n_Pascal" target="_blank">Pascal</a></strong>, usando <a href="http://en.wikipedia.org/wiki/Turbo_pascal" target="_blank">Turbo Pascal</a>, su versión más popular.</p>
<p>Viniendo más acá en el tiempo, y buscando alguna herramienta donde aprovechar mis conocimientos de este lenguaje pero para desarrollar sobre Linux, supe de la existencia de <a href="http://freepascal.org/" target="_blank">Free Pascal</a>, un compilador Pascal libre, multiplataforma y con soporte a diferentes arquitecturas, que genera ejecutables binarios con dependencias mínimas. También estaba disponible <a href="http://www.lazarus.freepascal.org/" target="_blank">Lazarus</a>, su inseparable IDE, no casualmente muy parecido a <a href="http://en.wikipedia.org/wiki/CodeGear_Delphi" target="_blank">Delphi</a>.</p>
<p>El problema era que hasta Ubuntu 9.04 y por una cuestión de madurez, las bibliotecas gráficas de Lazarus aún dependían de GTK 1.2 ( completamente en desuso desde hace «siglos» en las distribuciones Linux), y se veía así:</p>
<p style="text-align: center;"><a href="https://blog.marcelofernandez.info/wp-content/uploads/2010/06/Lazarus_IDE_GTK1_Linux.png"><img loading="lazy" decoding="async" class="aligncenter size-medium wp-image-899" title="Lazarus IDE sobre GTK1" src="https://blog.marcelofernandez.info/wp-content/uploads/2010/06/Lazarus_IDE_GTK1_Linux-300x225.png" alt="" width="300" height="225" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2010/06/Lazarus_IDE_GTK1_Linux-300x225.png 300w, http://blog.marcelofernandez.info/wp-content/uploads/2010/06/Lazarus_IDE_GTK1_Linux.png 1024w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></p>
<p>Se veía «duro», anticuado y lejos de toda amigabilidad con el usuario programador, carente de características básicas hoy en día tales como <a href="http://es.wikipedia.org/wiki/Unicode" target="_blank">Unicode</a>, <a href="http://es.wikipedia.org/wiki/Antialiasing" target="_blank">antialiasing</a> y mucho más&#8230; por lo tanto, concluí en ese momento que uno no podía encarar ningún desarrollo nuevo para Linux/Unix usando GTK 1.2 (y por ende Free Pascal+Lazarus), sucedido por la versión 2.0 allá por el año 2002.</p>
<p>En estos días leí un mail en la lista de <a href="http://ubuntu-ar.org/" target="_blank">Ubuntu-Ar</a> sobre Lazarus y Free Pascal, y decidí a instalarlo para echarle un vistazo otra vez. Por suerte la situación cambió bastante, me encontré con un bonito e importante cambio:</p>
<p style="text-align: center;"><a href="https://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo1.png"><img loading="lazy" decoding="async" class="aligncenter size-medium wp-image-900" title="Lazarus sobre GTK 2" src="https://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo1-300x187.png" alt="" width="300" height="187" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo1-300x187.png 300w, http://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo1-1024x640.png 1024w, http://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo1.png 1280w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></p>
<p>Ahora, con Lazarus sobre GTK 2, ¡sí que está mucho más decente! Junto a <a href="http://es.wikipedia.org/wiki/Gambas" target="_blank">Gambas</a> es lo más parecido a un entorno <a href="http://es.wikipedia.org/wiki/Desarrollo_r%C3%A1pido_de_aplicaciones" target="_blank">RAD</a> «estilo Visual Basic» que hay dando vueltas para Linux. Y es aún mejor que éstos dos:</p>
<ul>
<li>Libre: <a href="http://freepascal.org/faq.var#general-license" target="_blank">Licencia LGPL</a> (salvo el compilador que es GPL). Permite desarrollar software con cualquier licencia, incluso comercial.</li>
<li>Gratuito: Viene con los fuentes de sí mismo ¡y se <a href="http://en.wikipedia.org/wiki/Self-hosting">compila a sí mismo</a>!</li>
<li>Multiplataforma: DOS, Linux, Windows, Mac OSX, FreeBSD, Solaris, y <a href="http://freepascal.org/docs-html/user/userse2.html#x5-40001.2" target="_blank">más</a>.</li>
<li>Soporte de diferentes arquitecturas: Intel, AMD64, ARM, PowerPC, Sparc&#8230;</li>
<li>Diferentes Toolkits GUI: Win32/Win64, GTK1/2, QT3/4, Carbon, Cocoa, (aunque en diferentes estados de madurez).</li>
<li>Compatibilidad en <a href="http://wiki.lazarus.freepascal.org/Lazarus_For_Delphi_Users/es">un alto porcentaje</a> con Object Pascal y Delphi.</li>
</ul>
<p>Por último, me hice un «Hola Mundo» muy muy sencillo y lo compilé. Luego, ejecuté el comando <a href="http://linux.about.com/library/cmd/blcmdl1_ldd.htm" target="_blank">ldd</a>, para saber de qué bibliotecas dependía. El binario, que ocupaba 14 MB (ojo, era todo info de debug, luego de pasarle un <a href="http://www.computerhope.com/unix/strip.htm" target="_blank">strip</a> ocupó 5.1 MB) dependía de esto:</p>
<pre lang="bash">marcelo@marcelo-laptop:/tmp$ ldd project1
	linux-vdso.so.1 =>  (0x00007fff441ff000)
	libX11.so.6 => /usr/lib/libX11.so.6 (0x00007f6603e2f000)
	libgdk_pixbuf-2.0.so.0 =>; /usr/lib/libgdk_pixbuf-2.0.so.0 (0x00007f6603c13000)
	libgtk-x11-2.0.so.0 => /usr/lib/libgtk-x11-2.0.so.0 (0x00007f66035f0000)
	libgdk-x11-2.0.so.0 => /usr/lib/libgdk-x11-2.0.so.0 (0x00007f6603343000)
	libgobject-2.0.so.0 => /usr/lib/libgobject-2.0.so.0 (0x00007f66030fb000)
	libglib-2.0.so.0 => /lib/libglib-2.0.so.0 (0x00007f6602e1c000)
	libgthread-2.0.so.0 => /usr/lib/libgthread-2.0.so.0 (0x00007f6602c17000)
	libgmodule-2.0.so.0 => /usr/lib/libgmodule-2.0.so.0 (0x00007f6602a13000)
	libpango-1.0.so.0 => /usr/lib/libpango-1.0.so.0 (0x00007f66027c8000)
	libpthread.so.0 => /lib/libpthread.so.0 (0x00007f66025ab000)
	libatk-1.0.so.0 => /usr/lib/libatk-1.0.so.0 (0x00007f660238a000)
	libcairo.so.2 => /usr/lib/libcairo.so.2 (0x00007f6602106000)
	libdl.so.2 => /lib/libdl.so.2 (0x00007f6601f02000)
	libc.so.6 => /lib/libc.so.6 (0x00007f6601b80000)
	libxcb.so.1 => /usr/lib/libxcb.so.1 (0x00007f6601963000)
	libgio-2.0.so.0 => /usr/lib/libgio-2.0.so.0 (0x00007f66016b0000)
	librt.so.1 => /lib/librt.so.1 (0x00007f66014a8000)
	libm.so.6 => /lib/libm.so.6 (0x00007f6601224000)
	libXext.so.6 => /usr/lib/libXext.so.6 (0x00007f6601012000)
	libXrender.so.1 => /usr/lib/libXrender.so.1 (0x00007f6600e08000)
	libXinerama.so.1 => /usr/lib/libXinerama.so.1 (0x00007f6600c04000)
	libXi.so.6 => /usr/lib/libXi.so.6 (0x00007f66009f4000)
	libXrandr.so.2 => /usr/lib/libXrandr.so.2 (0x00007f66007eb000)
	libXcursor.so.1 => /usr/lib/libXcursor.so.1 (0x00007f66005e0000)
	libpangocairo-1.0.so.0 => /usr/lib/libpangocairo-1.0.so.0 (0x00007f66003d3000)
	libXcomposite.so.1 => /usr/lib/libXcomposite.so.1 (0x00007f66001d0000)
	libXdamage.so.1 => /usr/lib/libXdamage.so.1 (0x00007f65fffcc000)
	libXfixes.so.3 => /usr/lib/libXfixes.so.3 (0x00007f65ffdc6000)
	libpangoft2-1.0.so.0 => /usr/lib/libpangoft2-1.0.so.0 (0x00007f65ffb9c000)
	libfreetype.so.6 => /usr/lib/libfreetype.so.6 (0x00007f65ff915000)
	libz.so.1 => /lib/libz.so.1 (0x00007f65ff6fe000)
	libfontconfig.so.1 => /usr/lib/libfontconfig.so.1 (0x00007f65ff4c9000)
	libpcre.so.3 => /lib/libpcre.so.3 (0x00007f65ff29a000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f6604184000)
	libpixman-1.so.0 => /usr/lib/libpixman-1.so.0 (0x00007f65ff041000)
	libdirectfb-1.2.so.0 => /usr/lib/libdirectfb-1.2.so.0 (0x00007f65fedbd000)
	libfusion-1.2.so.0 => /usr/lib/libfusion-1.2.so.0 (0x00007f65febb3000)
	libdirect-1.2.so.0 => /usr/lib/libdirect-1.2.so.0 (0x00007f65fe99a000)
	libpng12.so.0 => /lib/libpng12.so.0 (0x00007f65fe772000)
	libxcb-render-util.so.0 => /usr/lib/libxcb-render-util.so.0 (0x00007f65fe56e000)
	libxcb-render.so.0 => /usr/lib/libxcb-render.so.0 (0x00007f65fe365000)
	libXau.so.6 => /usr/lib/libXau.so.6 (0x00007f65fe160000)
	libXdmcp.so.6 => /usr/lib/libXdmcp.so.6 (0x00007f65fdf5a000)
	libresolv.so.2 => /lib/libresolv.so.2 (0x00007f65fdd41000)
	libselinux.so.1 => /lib/libselinux.so.1 (0x00007f65fdb22000)
	libexpat.so.1 => /lib/libexpat.so.1 (0x00007f65fd8f9000)</pre>
<p>Si bien 5 MB sigue siendo un poco mucho (y no incluye GTK ni nada, aunque no jugué con las opciones del compilador) para un simple binario, a partir de ahora FreePascal + Lazarus en mi ranking personal entran en la categoría de «interesantes» <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Es bastante tarde, es cierto, más cuando gracias a <a href="http://www.python.org" target="_blank">Python</a> disfruto y me divierto al programar; tengo todo lo que necesito y más que lo que podría tener con FreePascal + Lazarus (siempre lo digo, Python no sería Python si no fuera por <a href="http://www.python.com.ar/" target="_blank">PyAr</a>), pero&#8230; bueno, rescato y festejo que haya otra herramienta de desarrollo libre, potente y al alcance de cualquiera. <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Saludos</p>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.marcelofernandez.info/2010/06/free-pascal-y-lazarus-en-ubuntu/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
			</item>
		<item>
		<title>Sincronizar carpetas a un Servidor Casero automáticamente</title>
		<link>http://blog.marcelofernandez.info/2010/06/sincronizar-carpetas-a-un-servidor-casero-automaticamente/</link>
					<comments>http://blog.marcelofernandez.info/2010/06/sincronizar-carpetas-a-un-servidor-casero-automaticamente/#comments</comments>
		
		<dc:creator><![CDATA[Marcelo]]></dc:creator>
		<pubDate>Fri, 18 Jun 2010 11:00:46 +0000</pubDate>
				<category><![CDATA[codear]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[ubuntu-ar]]></category>
		<guid isPermaLink="false">https://blog.marcelofernandez.info/?p=837</guid>

					<description><![CDATA[Introducción Supongamos que tengo un equipo donde usualmente estoy trabajando y otro equipo que está siempre encendido, ambos separados por Internet. En este último, el único puerto abierto sobre una IP Pública es el 22 para usar SSH, con lo cual me viene perfecta la capacidad de rsync de sincronizar carpetas y los últimos cambios mientras [&#8230;]]]></description>
										<content:encoded><![CDATA[<h2>Introducción</h2>
<p>Supongamos que tengo un equipo donde usualmente estoy trabajando y otro equipo que está siempre encendido, ambos separados por Internet. En este último, el único puerto abierto sobre una IP Pública es el 22 para usar <a href="http://www.openssh.com/" target="_blank">SSH</a>, con lo cual me viene perfecta la capacidad de <a href="http://samba.anu.edu.au/rsync/" target="_blank">rsync</a> de sincronizar carpetas y los últimos cambios mientras estoy trabajando, todo mediante un canal seguro.</p>
<h2>El Script de sincronización</h2>
<p>Lo único que necesito es este script en la carpeta personal de mi equipo «cliente», o sea, donde hago mis quehaceres diarios:</p>
<pre lang="bash">#!/bin/bash
# Script para sincronización a Servidor vía Casero rsync/ssh.
#
# Copyleft 2010 - Licencia BSD
# Autor: Marcelo Fernández.
# Email: marcelo.fidel.fernandez@gmail.com
#
# Características:
#  - Guarda la salida en un archivo de log (~/sync.log).
#  - Sincronización de una vía; pisa las modificaciones (y elimina) en el destino.
#  - Envía notificaciones al escritorio del usuario.
#  - Se sugiere ser llamado desde cron (gnome-schedule para el usuario final).
#  - Sincroniza (una sola vía) el directorio Documentos de mi Carpeta Personal y el Escritorio,
#    se pueden agregar más carpetas a gusto al momento de ejecutar el comando rsync.
#    También debe personalizarse el destino del backup, ahora en /media/Disco1/Backup
#
# Requerimientos:
#  - Rsync
#  - Paquete libnotify-bin (Debian/Ubuntu), que brinda el comando notify-send.
#
# Parámetros:
#  - Host destino. El script se lo llama "./sync.sh mi_host".
#    El login debe ser vía public keys, y la passphrase la maneja Gnome.

HOST=$1
LOG_FILE="sync.log"
export DISPLAY=:0.0 # Para el notify
export SSH_AUTH_SOCK="$(find /tmp/keyring*/ -perm 0755 -type s -user $LOGNAME -group $LOGNAME -name '*ssh' | head -n 1)"

notify-send -u normal --icon=gtk-refresh --category=transfer "Sincronizando a Casa..."
echo `date` &gt;&gt; $LOG_FILE
rsync -avz -e 'ssh' --delete ~/Documentos ~/Escritorio $HOST:/media/Disco1/Backup/ &amp;&gt;&gt; $LOG_FILE
RETVAL=$?
if [ $RETVAL -ne 0 ]; then
    notify-send -u critical --icon=gtk-dialog-error --category=transfer.error  "Error al Sincronizar";
else
    notify-send -u normal --icon=gtk-apply --category=transfer.complete "Sincronización Completa";
fi</pre>
<h2>Programando su ejecución automática</h2>
<p>Este script está pensado y preparado para ser llamado desde la aplicación «<a href="http://gnome-schedule.sourceforge.net/" target="_blank">Tareas Programadas</a>» de Gnome (disponible en el Centro de Software de Ubuntu o se instala haciendo click <a href="apt://gnome-schedule">aquí</a>):</p>
<p style="text-align: center;"><a href="https://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo.png"><img loading="lazy" decoding="async" class="size-medium wp-image-851 aligncenter" title="Programador de Tareas 1" src="https://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo-300x72.png" alt="" width="300" height="72" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo-300x72.png 300w, http://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo.png 704w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></p>
<p style="text-align: left;">Este es el detalle de la configuración de la tarea:</p>
<p><a href="https://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo-3.png"><img loading="lazy" decoding="async" class="size-medium wp-image-852 aligncenter" title="Programador de Tareas 2" src="https://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo-3-300x283.png" alt="" width="300" height="283" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo-3-300x283.png 300w, http://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo-3.png 576w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></p>
<p>Y además nos avisa de que está trabajando y si tuvo éxito o no al sincronizar:</p>
<p><a href="https://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo-2.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-861" title="Notificación 1" src="https://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo-2.png" alt="" width="340" height="80" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo-2.png 340w, http://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo-2-300x70.png 300w" sizes="auto, (max-width: 340px) 100vw, 340px" /></a></p>
<p><a href="https://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo-1.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-864" title="Notificacion OK" src="https://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo-1.png" alt="" width="340" height="80" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo-1.png 340w, http://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo-1-300x70.png 300w" sizes="auto, (max-width: 340px) 100vw, 340px" /></a><a href="https://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo-4.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-865" title="Notificación Error" src="https://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo-4.png" alt="" width="340" height="80" srcset="http://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo-4.png 340w, http://blog.marcelofernandez.info/wp-content/uploads/2010/06/Pantallazo-4-300x70.png 300w" sizes="auto, (max-width: 340px) 100vw, 340px" /></a></p>
<h2>Algunas cuestiones para destacar</h2>
<p>Como se aclara en los comentarios, cada vez que rsync copia las modificaciones al servidor, «pisa» lo que había anteriormente, lo que comúnmente se denomina sincronización de archivos «<a href="http://en.wikipedia.org/wiki/File_synchronization" target="_blank">de una vía</a>«.</p>
<p>Lo más interesante es que a pesar de ser ejecutado desde Cron, aprovecha las llaves SSH desbloqueadas por Gnome en la sesión de escritorio del usuario, es decir que la primera sincronización, si previamente no me había conectado al equipo remoto, me pide la frase de paso para desbloquear la clave privada; a partir de ese momento ésta queda compartida, gracias al <a href="http://es.wikipedia.org/wiki/SSH-Agent" target="_blank">ssh-agent</a> que utiliza Gnome en <em>background</em>. Luego, mientras siga la sesión de escritorio establecida, va a aprovechar la llave desbloqueada por el usuario y hacer la sincronización sin mayor problema. <strong>Esto es mucho mejor en cuanto a seguridad que usar una clave privada sin frase de paso contra el servidor, y me permite desbloquearla sólo la primera vez y no cada vez que se hace la sincronización, siendo un perfecto balance (al menos para mí) entre seguridad, automatización y comodidad</strong>. Lógicamente esto sirve para utilizar en cualquier conexión SSH que se quiera establecer, y la solución, después de dar muchas vueltas y probar muchas alternativas (¡el ssh del cron no «veía» al agente!), la encontré en <a href="http://www.codealpha.net/163/cron-ssh-and-rsync-and-key-with-passphrase-ubuntu/" target="_blank">este post</a>.</p>
<h2>Conclusión</h2>
<p>Este script fue creciendo desde algo muy simple, totalmente manual y que ejecutaba «cada vez que me acordaba» a mejorarlo un poco en cuanto a la automatización y hacerlo más «lindo» como está hoy. Si bien hay muchísimos mecanismos más robustos o con más facilidades (usando los <em>snapshots</em> de rsync por ejemplo y/o sincronizando ida y vuelta), <strong>éste es el que funciona para mí</strong>. Es bien claro lo que hace y no hay ninguna «magia» en el medio; trabaja sin que me moleste en mi actividad diaria y me despreocupo totalmente de que <em>tenía</em> que hacer backup. <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Espero que les sirva como a mí. <a href="http://www.vicente-navarro.com/blog/2008/01/13/backups-con-rsync/" target="_blank">Acá hay mucha más información</a> sobre rsync y una explicación más profunda de las diferentes opciones y alternativas, que por supuesto se pueden utilizar con esto como base.</p>
<p>¡Saludos!</p>
<h2>Actualización &#8211; Ubuntu 11.10</h2>
<p>En Ubuntu 11.10 hay que tocar levemente la línea donde define la variable SSH_AUTH_SOCK, cambia esto:</p>
<pre lang="bash">
export SSH_AUTH_SOCK="$(find /tmp/keyring*/ -perm 0755 -type s -user $LOGNAME -group $LOGNAME -name '*ssh' | head -n 1)"
</pre>
<p>por esto, reemplazar $USER por el nombre de usuario («marcelo» en mi caso):</p>
<pre lang="bash">
export SSH_AUTH_SOCK="$(find /tmp/keyring*/ -type s -user $USER -group $USER -name '*ssh' | head -n 1)"
</pre>
<h2>Actualización &#8211; Ubuntu 12.10</h2>
<p>En Ubuntu 12.10 hay que tocar levemente la línea donde define la variable SSH_AUTH_SOCK, cambia esto:</p>
<pre lang="bash">
export SSH_AUTH_SOCK="$(find /tmp/keyring*/ -perm 0755 -type s -user $LOGNAME -group $LOGNAME -name '*ssh' | head -n 1)"
</pre>
<p>por esto, reemplazar $USER por el nombre de usuario («marcelo» en mi caso):</p>
<pre lang="bash">
export SSH_AUTH_SOCK="$(find /run/user/$USER/keyring*/ -type s -user $USER -group $USER -name '*ssh' | head -n 1)"
</pre>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.marcelofernandez.info/2010/06/sincronizar-carpetas-a-un-servidor-casero-automaticamente/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>
