blog.notmyidea.org/working-directly-on-your-server-how-to-backup-and-sync-your-dev-environment-with-unison.html

214 lines
No EOL
17 KiB
HTML

<!DOCTYPE html>
<html lang="fr">
<head>
<title>
Working directly on your server? How to backup and sync your dev environment with&nbsp;unison - Alexis Métaireau </title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet"
href="https://blog.notmyidea.org/theme/css/main.css?v2"
type="text/css" />
<link href="https://blog.notmyidea.org/feeds/all.atom.xml"
type="application/atom+xml"
rel="alternate"
title="Alexis Métaireau ATOM Feed" />
</head>
<body>
<div id="content">
<section id="links">
<ul>
<li>
<a class="main" href="/">Alexis Métaireau</a>
</li>
<li>
<a class=""
href="https://blog.notmyidea.org/journal/index.html">Journal</a>
</li>
<li>
<a class="selected"
href="https://blog.notmyidea.org/code/">Code, etc.</a>
</li>
<li>
<a class=""
href="https://blog.notmyidea.org/weeknotes/">Notes hebdo</a>
</li>
<li>
<a class=""
href="https://blog.notmyidea.org/lectures/">Lectures</a>
</li>
<li>
<a class=""
href="https://blog.notmyidea.org/projets.html">Projets</a>
</li>
</ul>
</section>
<header>
<h1 class="post-title">Working directly on your server? How to backup and sync your dev environment with&nbsp;unison</h1>
<time datetime="2011-03-16T00:00:00+01:00">16 mars 2011</time>
</header>
<article>
<p>I have a server running freebsd since some time now, and was wondering
about the possibility to directly have a development environment ready
to use when I get a internet connexion, even if I&#8217;m not on my&nbsp;computer.</p>
<p>Since I use vim to code, and spend most of my time in a console while
developing, it&#8217;s possible to work via ssh, from&nbsp;everywhere.</p>
<p>The only problem is the synchronisation of the source code, config files
etc. from my machine to the&nbsp;server.</p>
<p>Unison provides an interesting way to synchronise two folders, even over
a network. So let&#8217;s do it&nbsp;!</p>
<h2 id="creating-the-jail">Creating the&nbsp;jail</h2>
<p>In case you don&#8217;t use FreeBSD, you can skip this&nbsp;section.</p>
<div class="highlight"><pre><span></span><code># I have a flavour jail named default
$ ezjail-admin -f default workspace.notmyidea.org 172.19.1.6
$ ezjail-admin start workspace.notmyidea.org
</code></pre></div>
<p>In my case, because the &#8220;default&#8221; flavour contains already a lot of
interesting things, my jail come already setup with ssh, bash and vim
for instance, but maybe you&#8217;ll need it in your&nbsp;case.</p>
<p>I want to be redirected to the ssh of the jail when I connect to the
host with the 20006 port. Add lines in <code>/etc/pf.conf</code>:</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nv">workspace_jail</span><span class="o">=</span><span class="s2">&quot;172.19.1.6&quot;</span>
<span class="w"> </span>rdr<span class="w"> </span>on<span class="w"> </span><span class="nv">$ext_if</span><span class="w"> </span>proto<span class="w"> </span>tcp<span class="w"> </span>from<span class="w"> </span>any<span class="w"> </span>to<span class="w"> </span><span class="nv">$ext_ip</span><span class="w"> </span>port<span class="w"> </span><span class="m">20006</span><span class="w"> </span>-&gt;<span class="w"> </span><span class="nv">$workspace_jail</span><span class="w"> </span>port<span class="w"> </span><span class="m">22</span>
</code></pre></div>
<p>Reload packet filter&nbsp;rules</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>/etc/rc.d/pf<span class="w"> </span>reload
</code></pre></div>
<h2 id="working-with-unison">Working with&nbsp;unison</h2>
<p>Now that we&#8217;ve set up the jail. Set up unison on the server and on your
client. Unison is available on the freebsd ports so just install&nbsp;it</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>ssh<span class="w"> </span>notmyidea.org<span class="w"> </span>-p<span class="w"> </span><span class="m">20006</span>
$<span class="w"> </span>make<span class="w"> </span>-C<span class="w"> </span>/usr/ports/net/unison-nox11<span class="w"> </span>config-recursive
$<span class="w"> </span>make<span class="w"> </span>-C<span class="w"> </span>/usr/ports/net/unison-nox11<span class="w"> </span>package-recursive
</code></pre></div>
<p>Install as well unison on your local machine. Double check to install
the same version on the client and on the server. Ubuntu contains the
2.27.57 as well as the&nbsp;2.32.52.</p>
<p>Check that unison is installed and reachable via ssh from your&nbsp;machine</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>ssh<span class="w"> </span>notmyidea.org<span class="w"> </span>-p<span class="w"> </span><span class="m">20006</span><span class="w"> </span>unison<span class="w"> </span>-version
unison<span class="w"> </span>version<span class="w"> </span><span class="m">2</span>.27.157
$<span class="w"> </span>unison<span class="w"> </span>-version
unison<span class="w"> </span>version<span class="w"> </span><span class="m">2</span>.27.57
</code></pre></div>
<h2 id="let-sync-our-folders">Let sync our&nbsp;folders</h2>
<p>The first thing I want to sync is my vim configuration. Well, it&#8217;s
already <a href="http://github.com/ametaireau/dotfiles/">in a git repository</a>
but let&#8217;s try to use unison for it right&nbsp;now.</p>
<p>I have two machines then: workspace, the jail, and ecureuil my&nbsp;laptop.</p>
<div class="highlight"><pre><span></span><code>unison<span class="w"> </span>.vim<span class="w"> </span>ssh://notmyidea.org:20006/.vim
unison<span class="w"> </span>.vimrc<span class="w"> </span>ssh://notmyidea.org:20006/.vimrc
</code></pre></div>
<p>It is also possible to put all the informations in a config file, and
then to only run unison. (fire up vim&nbsp;\~/.unison/default.prf.</p>
<p>Here is my&nbsp;config:</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="na">root</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">/home/alexis</span>
<span class="w"> </span><span class="na">root</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">ssh://notmyidea.org:20006</span>
<span class="w"> </span><span class="na">path</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">.vimrc</span>
<span class="w"> </span><span class="na">path</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">dotfiles</span>
<span class="w"> </span><span class="na">path</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">dev</span>
<span class="w"> </span><span class="na">follow</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">Name *</span>
</code></pre></div>
<p>My vimrc is in fact a symbolic link on my laptop, but I don&#8217;t want to
specify each of the links to unison. That&#8217;s why the follow = Name * is&nbsp;for.</p>
<p>The folders you want to synchronize are maybe a bit large. If so,
considering others options such as rsync for the first import may be a
good idea (I enjoyed my university huge upload bandwith to upload <span class="caps">2GB</span> in
20mn&nbsp;;)</p>
<h2 id="run-the-script-frequently">Run the script&nbsp;frequently</h2>
<p>Once that done, you just need to run the unison command line some times
when you want to sync your two machines. I&#8217;ve wrote a tiny script to get
some feedback from the&nbsp;sync:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
<span class="n">DEFAULT_LOGFILE</span> <span class="o">=</span> <span class="s2">&quot;~/unison.log&quot;</span>
<span class="n">PROGRAM_NAME</span> <span class="o">=</span> <span class="s2">&quot;Unison syncer&quot;</span>
<span class="k">def</span> <span class="nf">sync</span><span class="p">(</span><span class="n">logfile</span><span class="o">=</span><span class="n">DEFAULT_LOGFILE</span><span class="p">,</span> <span class="n">program_name</span><span class="o">=</span><span class="n">PROGRAM_NAME</span><span class="p">):</span>
<span class="c1"># init</span>
<span class="n">display_message</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">error</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">before</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span>
<span class="c1"># call unison to make the sync</span>
<span class="n">os</span><span class="o">.</span><span class="n">system</span><span class="p">(</span><span class="s1">&#39;unison -batch &gt; </span><span class="si">{0}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">logfile</span><span class="p">))</span>
<span class="c1"># get the duration of the operation</span>
<span class="n">td</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">-</span> <span class="n">before</span>
<span class="n">delta</span> <span class="o">=</span> <span class="p">(</span><span class="n">td</span><span class="o">.</span><span class="n">microseconds</span> <span class="o">+</span> <span class="p">(</span><span class="n">td</span><span class="o">.</span><span class="n">seconds</span> <span class="o">+</span> <span class="n">td</span><span class="o">.</span><span class="n">days</span> <span class="o">*</span> <span class="mi">24</span> <span class="o">*</span> <span class="mi">3600</span><span class="p">)</span> <span class="o">*</span> <span class="mi">10</span><span class="o">**</span><span class="mi">6</span><span class="p">)</span> <span class="o">/</span> <span class="mi">10</span><span class="o">**</span><span class="mi">6</span>
<span class="c1"># check what was the last entry in the log</span>
<span class="n">log</span> <span class="o">=</span> <span class="nb">open</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">expanduser</span><span class="p">(</span><span class="n">logfile</span><span class="p">))</span>
<span class="n">lines</span> <span class="o">=</span> <span class="n">log</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
<span class="k">if</span> <span class="s1">&#39;No updates to propagate&#39;</span> <span class="ow">in</span> <span class="n">lines</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span>
<span class="n">display_message</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">output</span> <span class="o">=</span> <span class="p">[</span><span class="n">l</span> <span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="n">lines</span> <span class="k">if</span> <span class="s2">&quot;Synchronization&quot;</span> <span class="ow">in</span> <span class="n">l</span><span class="p">]</span>
<span class="n">message</span> <span class="o">=</span> <span class="n">output</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">message</span> <span class="o">+=</span> <span class="s2">&quot; It took </span><span class="si">{0}</span><span class="s2">s.&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">delta</span><span class="p">)</span>
<span class="k">if</span> <span class="n">display_message</span><span class="p">:</span>
<span class="n">os</span><span class="o">.</span><span class="n">system</span><span class="p">(</span><span class="s1">&#39;notify-send -i </span><span class="si">{2}</span><span class="s1"> &quot;</span><span class="si">{0}</span><span class="s1">&quot; &quot;</span><span class="si">{1}</span><span class="s1">&quot;&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">program_name</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span>
<span class="s1">&#39;error&#39;</span> <span class="k">if</span> <span class="n">error</span> <span class="k">else</span> <span class="s1">&#39;info&#39;</span><span class="p">))</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&quot;__main__&quot;</span><span class="p">:</span>
<span class="n">sync</span><span class="p">()</span>
</code></pre></div>
<p>This is probably perfectible, but that does the&nbsp;job.</p>
<p>Last step is to tell you machine to run that frequently. That&#8217;s what
crontab is made for, so let&#8217;s <code>crontab -e</code>:</p>
<div class="highlight"><pre><span></span><code> $ <span class="gs">* *</span>/3 <span class="gs">* *</span> * . ~/.Xdbus; /usr/bin/python /home/alexis/dev/python/unison-syncer/sync.py
</code></pre></div>
<p>The \~/.Xdbus allows cron to communicate with your X11 session. Here is
its&nbsp;content.</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/bash</span>
<span class="c1"># Get the pid of nautilus</span>
<span class="nv">nautilus_pid</span><span class="o">=</span><span class="k">$(</span>pgrep<span class="w"> </span>-u<span class="w"> </span><span class="nv">$LOGNAME</span><span class="w"> </span>-n<span class="w"> </span>nautilus<span class="k">)</span>
<span class="c1"># If nautilus isn&#39;t running, just exit silently</span>
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>-z<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$nautilus_pid</span><span class="s2">&quot;</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="nb">exit</span><span class="w"> </span><span class="m">0</span>
<span class="k">fi</span>
<span class="c1"># Grab the DBUS_SESSION_BUS_ADDRESS variable from nautilus&#39;s environment</span>
<span class="nb">eval</span><span class="w"> </span><span class="k">$(</span>tr<span class="w"> </span><span class="s1">&#39;\0&#39;</span><span class="w"> </span><span class="s1">&#39;\n&#39;</span><span class="w"> </span>&lt;<span class="w"> </span>/proc/<span class="nv">$nautilus_pid</span>/environ<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span><span class="s1">&#39;^DBUS_SESSION_BUS_ADDRESS=&#39;</span><span class="k">)</span>
<span class="c1"># Check that we actually found it</span>
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>-z<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$DBUS_SESSION_BUS_ADDRESS</span><span class="s2">&quot;</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;Failed to find bus address&quot;</span><span class="w"> </span>&gt;<span class="p">&amp;</span><span class="m">2</span>
<span class="nb">exit</span><span class="w"> </span><span class="m">1</span>
<span class="k">fi</span>
<span class="c1"># export it so that child processes will inherit it</span>
<span class="nb">export</span><span class="w"> </span>DBUS_SESSION_BUS_ADDRESS
</code></pre></div>
<p>And it comes from
<a href="http://ubuntuforums.org/showthread.php?p=10148738#post10148738">here</a>.</p>
<p>A sync takes about 20s + the upload time on my machine, which stay
acceptable for all of my&nbsp;developments.</p>
</article>
<footer>
<a id="feed" href="/feeds/all.atom.xml">
<img alt="RSS Logo" src="/theme/rss.svg" />
</a>
</footer>
</div>
</body>
</html>