joe di castrohttp://joedicastro.com2011-07-13T20:21:00+02:00Fabric & Rsync para realizar Backups2011-07-13T20:21:00+02:00joe di castrohttp://joedicastro.com/fabric-rsync-para-realizar-backups.html<p>En el <a href="http://joedicastro.com/sincronizar-dos-directorios-con-fabric-y-rsync.html">anterior articulo</a> empleaba <a href="http://fabfile.org/">fabric</a> y <a href="http://es.wikipedia.org/wiki/Rsync">rsync</a> para sincronizar
un directorio local y uno remoto en ambas direcciones. Además le añadía las
funcionalidades de <a href="http://joedicastro.com/logger-informes-legibles-para-tus-scripts-python.html">logger</a> y <a href="http://joedicastro.com/notificaciones-de-escritorio-en-ubuntu-desde-python.html">notify</a> para proporcionar información sobre
el proceso durante y después de su ejecución. Y comenzaba el articulo recordando
a <a href="http://joedicastro.com/sincronizar-una-carpeta-local-y-una-remota-a-traves-de-ftp-lftp-mirror.html">lftp-mirror</a>, el script que había creado para realizar la sincronización a
través de FTP. Pero <strong>lftp-mirror</strong> realiza algo más que la sincronización, pues
también permite realizar el archivado del directorio local en ficheros
comprimidos y lanzar varias tareas en una sola ejecución.</p>
<p>Ahora he añadido esta funcionalidad al fichero <strong>fabric</strong> creado anteriormente.
Así empleando este fichero podemos realizar el Backup periódico de varios
servidores en una sola operación y de forma completamente automática (basta con
programar su ejecución). Se sincronizan los dos directorios y se crea un archivo
comprimido del directorio local por cada día de la semana. De este modo siempre
tenemos una copia del estado del directorio remoto de los últimos siete días. Y
al final del proceso en nuestro correo, un email con el informe del resultado por
cada una de las tareas ejecutadas.</p>
<p>En este fichero, <strong>rsync_fabric.py</strong>, disponemos de tres posibles tareas:</p>
<div class="codehilite"><pre><span class="gp">$</span> fab -l
<span class="go"> A Fabric file for sync two directories (remote ⇄ local) with rsync.</span>
<span class="go">Available commands:</span>
<span class="go"> backup Sync from remote to local & archive the local directory.</span>
<span class="go"> down Sync from remote to local.</span>
<span class="go"> up Sync from local to remote.</span>
</pre></div>
<p>Con la primera realizamos el backup (sincronización + archivado) y
con las siguientes solo la sincronización desde o hacia el servidor. Una de las
ventajas de fabric es que nos permite concatenar tareas fácilmente desde la
línea de comandos, así podemos lanzar varias sincronizaciones de forma
simultanea. Para poder realizar esto, creo una configuración de sincronización
por defecto y después creo una función para cada una las tareas adicionales que
simplemente redefinen los valores de estas variables globales. Por ejemplo:</p>
<div class="codehilite"><pre><span class="c"># Variables globales de sincronización predefenidas</span>
<span class="n">env</span><span class="o">.</span><span class="n">host_string</span> <span class="o">=</span> <span class="s">"username@example.com"</span>
<span class="n">env</span><span class="o">.</span><span class="n">remote</span> <span class="o">=</span> <span class="s">"/my_directory"</span>
<span class="n">env</span><span class="o">.</span><span class="n">local</span> <span class="o">=</span> <span class="s">"/home/my_user/backups/my_directory"</span>
<span class="c"># Redefinimos estas variables para otra configuración de sincronización. Por </span>
<span class="c"># supuesto, pueden tratarse de servidores distintos.</span>
<span class="k">def</span> <span class="nf">_databases</span><span class="p">():</span>
<span class="k">global</span> <span class="n">env</span>
<span class="n">env</span><span class="o">.</span><span class="n">host_string</span> <span class="o">=</span> <span class="s">"username@example.com"</span>
<span class="n">env</span><span class="o">.</span><span class="n">remote</span> <span class="o">=</span> <span class="s">"/databases"</span>
<span class="n">env</span><span class="o">.</span><span class="n">local</span> <span class="o">=</span> <span class="s">"/home/my_user/backups/databases"</span>
</pre></div>
<p>Veamos ejemplos de como podemos utilizar estas tareas:</p>
<div class="codehilite"><pre><span class="gp">#</span> <span class="s2">"Si queremos sincronizar el contenido local hacia el remoto, por ejemplo </span>
<span class="gp">#</span><span class="s2"> para subir los ficheros al servidor por primera vez. Empleando los valores </span>
<span class="gp">#</span><span class="s2"> por defecto. El modificador -w lo empleo para que no se detenga en los </span>
<span class="gp">#</span><span class="s2"> errores, que de ocurrir, los veremos luego en el informe final."</span>
<span class="gp">$</span> fab -w up
<span class="go">[localhost] local: rsync -pthrvz --delete /home/my_user/backups/my_directory/ </span>
<span class="go"> username@example.com:my_directory</span>
<span class="go">Done.</span>
<span class="gp">#</span> <span class="s2">"Pero también podemos especificar una tarea distinta a la por defecto de </span>
<span class="gp">#</span><span class="s2"> este modo. Sincronizando desde el servidor a nuestro directorio local las </span>
<span class="gp">#</span><span class="s2"> bases de datos."</span>
<span class="gp">$</span> fab -w down:databases
<span class="go">[localhost] local: rsync -pthrvz --delete username@example.com:databases/ </span>
<span class="go">/home/my_user/backups/databases</span>
<span class="go">Done.</span>
<span class="gp">#</span> <span class="s2">"Y por supuesto, podemos realizar varias tareas a la vez."</span>
<span class="gp">$</span> fab -w down backup:databases
<span class="go">[localhost] local: rsync -pthrvz --delete username@example.com:my_directory/ </span>
<span class="go">/home/my_user/backups/my_directory</span>
<span class="go">[localhost] local: rsync -pthrvz --delete username@example.com:databases/ </span>
<span class="go">/home/my_user/backups/databases</span>
<span class="go">Done.</span>
</pre></div>
<p>No empleo contraseña alguna, ni en el fichero ni en la línea de comandos, podría
hacerse perfectamente, pero prefiero emplear una clave <a href="http://es.wikipedia.org/wiki/RSA">RSA</a> <a href="http://es.wikipedia.org/wiki/Criptograf%C3%ADa_asim%C3%A9trica">pública</a>
autorizada para las sesiones SSH en el servidor. Es bastante más seguro y cómodo.
En los ejemplos no se ve la salida de <em>rsync</em>, pues es capturada (así como los
erores) para ser mostrada a posteriori en los informes. </p>
<p>Un ejemplo de informe sería el siguiente:</p>
<div class="codehilite"><pre>START TIME =====================================================================
miércoles 13/07/11, 19:48:55
================================================================================
SCRIPT =========================================================================
fab (ver. Unknown)
Fabric Rsync
http://joedicastro.com
Syncing username@example.com:databases to /home/my_user/backups/databases
================================================================================
RSYNC OUTPUT ___________________________________________________________________
receiving file list ... done
sent 20 bytes received 825 bytes 153.64 bytes/sec
total size is 827.76M speedup is 979595.42
ROTATE COMPRESSED COPIES _______________________________________________________
Created file:
/home/my_user/backups/databases_13jul2011_19:49_mié.tar.gz
Deleted old file:
databases_13jul2011_19:37_mié.tar.gz
DISK SPACE USED ================================================================
1.60 GiB
================================================================================
END TIME =======================================================================
miércoles 13/07/11, 19:50:02
================================================================================
</pre></div>
<p>Que como podemos ver, ha tardado poco más de un minuto en sincronizar 827.56
Megabytes y el total de espacio ocupado por el directorio y los siete archivos
comprimidos es de 1.60 Gibibytes (1,72 Gigabytes). </p>
<h2 id="ventajas">Ventajas</h2>
<p>Las ventajas de sincronizarlo con <strong>rsync + ssh</strong> vs <strong>ftp</strong>, como ya comenté en el
anterior articulo son enormes. Se ahorra muchísimo tiempo y ancho de banda, lo
que ayuda a no saturar la red y no tener que planificar con tanto cuidado las
ventanas de backup. Por ejemplo he realizado unas pruebas y para las mismas
condiciones: <strong>mismo servidor, mismo directorio, mismo horario y condiciones de
red; la sincronización remoto → local a través de FTP emplea entre 35 y 45
minutos y cuando lo hacemos a través de rsync emplea entre 2 y 4 minutos</strong>. Ahí
es nada, estamos hablando de un proceso ~13 veces más rápido. </p>
<h2 id="c+digo">Código</h2>
<p>El código del fichero fabric es el siguiente:</p>
<div class="codehilite"><pre><span class="c">#!/usr/bin/env python</span>
<span class="c"># -*- coding: utf8 -*-</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">glob</span>
<span class="kn">import</span> <span class="nn">tarfile</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="kn">from</span> <span class="nn">get_size</span> <span class="kn">import</span> <span class="n">get_size</span> <span class="k">as</span> <span class="n">_get_size</span>
<span class="kn">from</span> <span class="nn">get_size</span> <span class="kn">import</span> <span class="n">best_unit_size</span> <span class="k">as</span> <span class="n">_best_unit_size</span>
<span class="kn">from</span> <span class="nn">logger</span> <span class="kn">import</span> <span class="n">Logger</span> <span class="k">as</span> <span class="n">_logger</span>
<span class="kn">from</span> <span class="nn">notify</span> <span class="kn">import</span> <span class="n">notify</span> <span class="k">as</span> <span class="n">_notify</span>
<span class="kn">from</span> <span class="nn">fabric.api</span> <span class="kn">import</span> <span class="n">env</span><span class="p">,</span> <span class="n">local</span>
<span class="n">LOG</span> <span class="o">=</span> <span class="n">_logger</span><span class="p">()</span>
<span class="c">#===============================================================================</span>
<span class="c"># RSYNC HOSTS</span>
<span class="c">#===============================================================================</span>
<span class="c"># Your default host. No need any more if only wants a host.</span>
<span class="n">env</span><span class="o">.</span><span class="n">host_string</span> <span class="o">=</span> <span class="s">"username@host"</span>
<span class="n">env</span><span class="o">.</span><span class="n">remote</span> <span class="o">=</span> <span class="s">"/your/remote/path"</span>
<span class="n">env</span><span class="o">.</span><span class="n">local</span> <span class="o">=</span> <span class="s">"/your/local/path"</span>
<span class="c"># If wants to use various hosts, then define the previous variables like this, </span>
<span class="c"># one function per host. </span>
<span class="k">def</span> <span class="nf">_host_1</span><span class="p">():</span>
<span class="sd">"""Host variables for host_1."""</span>
<span class="k">global</span> <span class="n">env</span>
<span class="n">env</span><span class="o">.</span><span class="n">host_string</span> <span class="o">=</span> <span class="s">"username@host_1"</span>
<span class="n">env</span><span class="o">.</span><span class="n">remote</span> <span class="o">=</span> <span class="s">"/your/remote/path/in/host_1"</span>
<span class="n">env</span><span class="o">.</span><span class="n">local</span> <span class="o">=</span> <span class="s">"/your/local/path/for/host_1"</span>
<span class="k">def</span> <span class="nf">_host_2</span><span class="p">():</span>
<span class="sd">"""Host variables for host_2."""</span>
<span class="k">global</span> <span class="n">env</span>
<span class="n">env</span><span class="o">.</span><span class="n">host_string</span> <span class="o">=</span> <span class="s">"username@host_2"</span>
<span class="n">env</span><span class="o">.</span><span class="n">remote</span> <span class="o">=</span> <span class="s">"/your/remote/path/in/host_2"</span>
<span class="n">env</span><span class="o">.</span><span class="n">local</span> <span class="o">=</span> <span class="s">"/your/local/path/for/host_2"</span>
<span class="c"># ...</span>
<span class="c">#</span>
<span class="c"># def _host_n():</span>
<span class="c"># """Host variables for host_n."""</span>
<span class="c"># global env</span>
<span class="c"># env.host_string = "username@host_n"</span>
<span class="c"># env.remote = "/your/remote/path/in/host_n"</span>
<span class="c"># env.local = "/your/local/path/for/host_n"</span>
<span class="c">#===============================================================================</span>
<span class="c"># END RSYNC HOSTS</span>
<span class="c">#===============================================================================</span>
<span class="k">def</span> <span class="nf">_log_start</span><span class="p">():</span>
<span class="sd">"""Create the Start time info block for the log."""</span>
<span class="c"># Init the log for multiple hosts. Do not repeat the previous logs.</span>
<span class="k">if</span> <span class="n">LOG</span><span class="o">.</span><span class="n">get</span><span class="p">():</span>
<span class="n">LOG</span><span class="o">.</span><span class="n">__init__</span><span class="p">()</span>
<span class="n">LOG</span><span class="o">.</span><span class="n">time</span><span class="p">(</span><span class="s">"Start time"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_log_end</span><span class="p">(</span><span class="n">task</span><span class="p">):</span>
<span class="sd">"""Create the End time info block and send & write the log."""</span>
<span class="n">_notify</span><span class="p">(</span><span class="s">"Rsync"</span><span class="p">,</span> <span class="s">"Ended"</span> <span class="p">,</span> <span class="s">"ok"</span><span class="p">)</span>
<span class="n">LOG</span><span class="o">.</span><span class="n">time</span><span class="p">(</span><span class="s">"End time"</span><span class="p">)</span>
<span class="n">LOG</span><span class="o">.</span><span class="n">free</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">linesep</span> <span class="o">*</span> <span class="mi">2</span><span class="p">)</span>
<span class="n">LOG</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span>
<span class="n">LOG</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="s">"Fabric Rsync ({0})"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">task</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">_check_local</span><span class="p">():</span>
<span class="sd">"""Create local directory if no exists."""</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">env</span><span class="o">.</span><span class="n">local</span><span class="p">):</span>
<span class="n">os</span><span class="o">.</span><span class="n">mkdir</span><span class="p">(</span><span class="n">env</span><span class="o">.</span><span class="n">local</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_rsync</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">target</span><span class="p">,</span> <span class="n">delete</span><span class="p">):</span>
<span class="sd">"""Process the _rsync command."""</span>
<span class="n">_log_start</span><span class="p">()</span>
<span class="n">LOG</span><span class="o">.</span><span class="n">header</span><span class="p">(</span><span class="s">"Fabric Rsync</span><span class="se">\n</span><span class="s">http://joedicastro.com"</span><span class="p">,</span>
<span class="s">"Syncing {0} to {1}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">target</span><span class="p">))</span>
<span class="n">_notify</span><span class="p">(</span><span class="s">"Rsync"</span><span class="p">,</span> <span class="s">"Start syncing {0} to {1}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">target</span><span class="p">),</span> <span class="s">"info"</span><span class="p">)</span>
<span class="n">out</span> <span class="o">=</span> <span class="n">local</span><span class="p">(</span><span class="s">"rsync -pthrvz {2} {0}/ {1}"</span><span class="o">.</span>
<span class="n">format</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">target</span><span class="p">,</span> <span class="s">"--delete"</span> <span class="k">if</span> <span class="n">delete</span> <span class="o">==</span> <span class="s">"yes"</span> <span class="k">else</span> <span class="s">""</span><span class="p">),</span>
<span class="n">capture</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">_notify</span><span class="p">(</span><span class="s">"Rsync"</span><span class="p">,</span> <span class="s">"Finished synchronization"</span><span class="p">,</span> <span class="s">"ok"</span><span class="p">)</span>
<span class="n">LOG</span><span class="o">.</span><span class="n">list</span><span class="p">(</span><span class="s">"Rsync Output"</span><span class="p">,</span> <span class="n">out</span><span class="p">)</span>
<span class="k">if</span> <span class="n">out</span><span class="o">.</span><span class="n">failed</span><span class="p">:</span>
<span class="n">LOG</span><span class="o">.</span><span class="n">list</span><span class="p">(</span><span class="s">"Rsync Errors"</span><span class="p">,</span> <span class="n">out</span><span class="o">.</span><span class="n">stderr</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_compress</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
<span class="sd">"""Compress a local directory into a gz file.</span>
<span class="sd"> Creates a file for each weekday, an removes the old files if exists"""</span>
<span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">os</span><span class="o">.</span><span class="n">pardir</span><span class="p">))</span>
<span class="n">dir2gz</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
<span class="n">old_gzs</span> <span class="o">=</span> <span class="n">glob</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s">'{0}*{1}.tar.gz'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">dir2gz</span><span class="p">,</span> <span class="n">time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s">'%a'</span><span class="p">)))</span>
<span class="n">gz_name</span> <span class="o">=</span> <span class="s">"{0}_{1}.tar.gz"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">dir2gz</span><span class="p">,</span> <span class="n">time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s">'</span><span class="si">%d</span><span class="s">%b%Y_%H:%M_%a'</span><span class="p">))</span>
<span class="n">gz_file</span> <span class="o">=</span> <span class="n">tarfile</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">gz_name</span><span class="p">,</span> <span class="s">"w:gz"</span><span class="p">)</span>
<span class="n">gz_file</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">arcname</span><span class="o">=</span><span class="n">dir2gz</span><span class="p">)</span>
<span class="n">gz_file</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">output</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">linesep</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="s">'Created file:'</span><span class="p">,</span> <span class="s">''</span><span class="p">,</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">(),</span>
<span class="n">gz_name</span><span class="p">)])</span>
<span class="k">for</span> <span class="n">old_gz</span> <span class="ow">in</span> <span class="n">old_gzs</span><span class="p">:</span>
<span class="n">os</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">old_gz</span><span class="p">)</span>
<span class="n">output</span> <span class="o">+=</span> <span class="n">os</span><span class="o">.</span><span class="n">linesep</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">os</span><span class="o">.</span><span class="n">linesep</span><span class="p">,</span> <span class="s">'Deleted old file:'</span><span class="p">,</span> <span class="s">''</span><span class="p">,</span> <span class="n">old_gz</span><span class="p">])</span>
<span class="k">return</span> <span class="n">output</span>
<span class="k">def</span> <span class="nf">_archive</span><span class="p">():</span>
<span class="sd">"""Archive the local directory in a gz file for each weekday."""</span>
<span class="n">_notify</span><span class="p">(</span><span class="s">'Rsync'</span><span class="p">,</span> <span class="s">'Compressing folder...'</span><span class="p">,</span> <span class="s">'info'</span><span class="p">)</span>
<span class="n">LOG</span><span class="o">.</span><span class="n">list</span><span class="p">(</span><span class="s">'Rotate compressed copies'</span><span class="p">,</span> <span class="n">_compress</span><span class="p">(</span><span class="n">env</span><span class="o">.</span><span class="n">local</span><span class="p">))</span>
<span class="n">_notify</span><span class="p">(</span><span class="s">"Rsync"</span><span class="p">,</span> <span class="s">"Finished compression"</span><span class="p">,</span> <span class="s">"ok"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_get_diskspace</span><span class="p">():</span>
<span class="sd">"""Get the disk space used by the local directory and archives."""</span>
<span class="n">gz_size</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">([</span><span class="n">_get_size</span><span class="p">(</span><span class="n">gz</span><span class="p">)</span> <span class="k">for</span> <span class="n">gz</span> <span class="ow">in</span> <span class="n">glob</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s">'{0}*.gz'</span><span class="o">.</span>
<span class="n">format</span><span class="p">(</span><span class="n">env</span><span class="o">.</span><span class="n">local</span><span class="p">))])</span>
<span class="n">log_size</span> <span class="o">=</span> <span class="n">_get_size</span><span class="p">(</span><span class="n">LOG</span><span class="o">.</span><span class="n">filename</span><span class="p">)</span> <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">LOG</span><span class="o">.</span><span class="n">filename</span><span class="p">)</span> <span class="k">else</span> <span class="mi">0</span>
<span class="n">local_size</span> <span class="o">=</span> <span class="n">_get_size</span><span class="p">(</span><span class="n">env</span><span class="o">.</span><span class="n">local</span><span class="p">)</span>
<span class="n">size</span> <span class="o">=</span> <span class="n">_best_unit_size</span><span class="p">(</span><span class="n">local_size</span> <span class="o">+</span> <span class="n">gz_size</span> <span class="o">+</span> <span class="n">log_size</span><span class="p">)</span>
<span class="n">LOG</span><span class="o">.</span><span class="n">block</span><span class="p">(</span><span class="s">'Disk space used'</span><span class="p">,</span> <span class="s">'{0:>76.2f} {1}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">size</span><span class="p">[</span><span class="s">'s'</span><span class="p">],</span> <span class="n">size</span><span class="p">[</span><span class="s">'u'</span><span class="p">]))</span>
<span class="k">def</span> <span class="nf">up</span><span class="p">(</span><span class="n">server</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">dlt</span><span class="o">=</span><span class="s">'yes'</span><span class="p">):</span>
<span class="sd">"""Sync from local to remote."""</span>
<span class="nb">globals</span><span class="p">()[</span><span class="s">"_"</span> <span class="o">+</span> <span class="n">server</span><span class="p">]()</span> <span class="k">if</span> <span class="n">server</span> <span class="k">else</span> <span class="bp">None</span>
<span class="n">_rsync</span><span class="p">(</span><span class="n">env</span><span class="o">.</span><span class="n">local</span><span class="p">,</span> <span class="s">":"</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">env</span><span class="o">.</span><span class="n">host_string</span><span class="p">,</span> <span class="n">env</span><span class="o">.</span><span class="n">remote</span><span class="p">]),</span> <span class="n">dlt</span><span class="p">)</span>
<span class="n">_log_end</span><span class="p">(</span><span class="n">server</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">down</span><span class="p">(</span><span class="n">server</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">dlt</span><span class="o">=</span><span class="s">'yes'</span><span class="p">,</span> <span class="n">archive</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
<span class="sd">"""Sync from remote to local."""</span>
<span class="nb">globals</span><span class="p">()[</span><span class="s">"_"</span> <span class="o">+</span> <span class="n">server</span><span class="p">]()</span> <span class="k">if</span> <span class="n">server</span> <span class="k">else</span> <span class="bp">None</span>
<span class="n">_check_local</span><span class="p">()</span>
<span class="n">_rsync</span><span class="p">(</span><span class="s">":"</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">env</span><span class="o">.</span><span class="n">host_string</span><span class="p">,</span> <span class="n">env</span><span class="o">.</span><span class="n">remote</span><span class="p">]),</span> <span class="n">env</span><span class="o">.</span><span class="n">local</span><span class="p">,</span> <span class="n">dlt</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">archive</span><span class="p">:</span>
<span class="n">_log_end</span><span class="p">(</span><span class="n">server</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">backup</span><span class="p">(</span><span class="n">server</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
<span class="sd">"""Sync from remote to local & archive the local directory."""</span>
<span class="n">down</span><span class="p">(</span><span class="n">server</span><span class="p">,</span> <span class="n">archive</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">_archive</span><span class="p">()</span>
<span class="n">_get_diskspace</span><span class="p">()</span>
<span class="n">_log_end</span><span class="p">(</span><span class="n">server</span><span class="p">)</span>
</pre></div>
<p>El fichero siempre actualizado puede ser encontrado en el repositorio <em>Python Recipes</em> que está alojado en <a href="http://github.com/joedicastro/python-recipes">github</a> con el nombre <code>rsync_fabfile.py</code> </p>