<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="text">g.raphaelli's weblog</title>
  <id>http://g.raphaelli.com/2009/01/feed.atom</id>
  <updated>2009-08-07T23:48:13Z</updated>
  <link href="http://g.raphaelli.com/" />
  <link href="http://g.raphaelli.com/2009/01/feed.atom" rel="self" />
  <generator uri="http://zine.pocoo.org/" version="0.1.2">Zine</generator>
  <entry xml:base="http://g.raphaelli.com/2009/01/feed.atom">
    <title type="text">Circumventing security policy with gearman</title>
    <id>tag:g.raphaelli.com,2009-01-09/entry:2009/1/9/defeating-firewalls-with-gearmand</id>
    <updated>2009-01-12T10:45:44Z</updated>
    <published>2009-01-12T10:42:00Z</published>
    <link href="http://g.raphaelli.com/2009/1/9/circumventing-security-policy-with-gearman" />
    <author>
      <name>g</name>
    </author>
    <content type="html">&lt;p&gt;Gearman can be handy for defeating security in situations like the one pictured:

&lt;/p&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://static.g.raphaelli.com/images/2009/01/12/host-setup.png"&gt;&lt;/div&gt;

Here, Host A can initiate connections to Host B but Host B is blocked by a firewall/router ACL/etc from initiating communications with Host A.&lt;p&gt;&lt;/p&gt;

&lt;p&gt;With gearman, you can call a service on Host A from Host B with a setup like this:

&lt;/p&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://static.g.raphaelli.com/images/2009/01/12/gearman-rpc.png"&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Run a gearmand job server on host B (or any host that A and B can both reach).&lt;/li&gt;
&lt;li&gt;Register a gearman worker running on Host A with that job server.&lt;/li&gt;
&lt;li&gt;Submit work from a client running on Host B to that job server.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;/p&gt;

&lt;p&gt;This idea can be taken another step by chaining workers together such that calling abc() as depicted above creates a job that Host C, which can't reach or be reached by Host B at all, can ultimately execute.  That kind of setup makes it increasingly difficult to track an individual task's real status but it can be handy in a pinch.&lt;/p&gt;</content>
  </entry>
  <entry xml:base="http://g.raphaelli.com/2009/01/feed.atom">
    <title type="text">Gearmand Rewrite Released</title>
    <id>tag:g.raphaelli.com,2009-01-09/entry:2009/1/9/gearmand</id>
    <updated>2009-01-11T01:57:53Z</updated>
    <published>2009-01-09T07:43:00Z</published>
    <link href="http://g.raphaelli.com/2009/1/9/gearmand-rewrite-released" />
    <author>
      <name>g</name>
    </author>
    <content type="html">&lt;p&gt;There is some big news for &lt;a href="http://www.gearmanproject.org/"&gt;Gearman&lt;/a&gt; fans out today - the first release of the C-rewrite of the gearmand job server has been &lt;a href="http://www.oddments.org/?p=30"&gt;announced&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Gearman is an excellent framework for farming out tasks to pools of machines, parallelizing tasks, and making calls between programming languages that speak gearman.  Like memcached, it's extremely easy to get started using it.  Once you do start using it, you'll never understand how you lived without it.&lt;/p&gt;

&lt;p&gt;The new release does not provide python bindings but the code in &lt;a href="http://code.sixapart.com/svn/gearman/trunk/api/python/"&gt;sixapart's svn&lt;/a&gt; should be compatible with the new server*.  The sample code provided with the both the perl and C versions is pretty trivial as they simply echo or reverse some strings.  To pass interesting data between client and worker you'll need to create your own convention.  YAML or simply JSON is very handy for this.&lt;/p&gt;

&lt;p&gt;Let's take a contrived example.  Of course, error handling will be omitted for clarity.&lt;/p&gt;

&lt;p&gt;This is a gearman worker that expects a list of urls and will do something to each of them.&lt;/p&gt;

&lt;div class="syntax"&gt;&lt;pre&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot; A Sample Gearman Worker &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;logging&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wraps&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;simplejson&lt;/span&gt; &lt;span class="kn"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;urllib&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;gearman&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;GearmanWorker&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;job_in&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot; Decorates worker functions by calling them with a job&amp;#39;s arguments &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c"&gt;# do something with the job object&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;json_in&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot; Decorates a function that may be called with a&lt;/span&gt;
&lt;span class="sd"&gt;        JSON-formatted string but expects a python object &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c"&gt;# convert the args in JSON to a python object&lt;/span&gt;
        &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;

&lt;span class="nd"&gt;@job_in&lt;/span&gt;
&lt;span class="nd"&gt;@json_in&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fetching &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;# do something with the url&lt;/span&gt;
        &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;fetched&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="n"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GearmanWorker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jobservers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fetch&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;work&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;
A client for this worker can look like:

&lt;/p&gt;&lt;div class="syntax"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;simplejson&lt;/span&gt; &lt;span class="kn"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;gearman&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;GearmanClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;

&lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;http://www.flickr.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;http://www.yahoo.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GearmanClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jobservers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;do_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fetch&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%i&lt;/span&gt;&lt;span class="s"&gt; urls fetched successfully&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;fetched&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;While this example is still quite simple, it does illustrate the idea of the convention necessary for passing real information between clients and workers.  The python libraries for gearman also support tasksets which are a set of tasks submitted at once to a job server for parallel execution.  This is a simple yet powerful way to speed up work and make the most of hardware investments.&lt;/p&gt;

&lt;p&gt;I hope that this rewrite of gearmand renews interest in the python community to enhance the current bindings.  I'd be very interested in a gearman protocol implementation for twisted (and might just start working on it soon).&lt;/p&gt;

&lt;p&gt;* on Mac OSX 10.4.11 I'm getting a bus error from gearmand after successfully running a job.  I haven't tracked it down or submitted a bug yet. &lt;b&gt;update:&lt;/b&gt; &lt;a href="https://bugs.launchpad.net/gearmand/+bug/315652"&gt;bug&lt;/a&gt; reported via IRC (yes, I'm gilad on freenode) and fixed with a two line patch.  A new release should be announced shortly.&lt;/p&gt;</content>
  </entry>
  <entry xml:base="http://g.raphaelli.com/2009/01/feed.atom">
    <title type="text">Dr. Dog, Gomez, The Black Keys at The Arena, Brisbane</title>
    <id>tag:g.raphaelli.com,2009-01-06/entry:2009/1/6/dr-dog-gomez-the-black-keys-at-the-arena-brisbane</id>
    <updated>2009-01-07T03:42:20Z</updated>
    <published>2009-01-06T10:17:00Z</published>
    <link href="http://g.raphaelli.com/2009/1/6/dr-dog-gomez-the-black-keys-at-the-arena-brisbane" />
    <author>
      <name>g</name>
    </author>
    <content type="html">&lt;p&gt;Dr. Dog, Gomez, and The Black Keys played &lt;a href="http://www.arenaonline.com.au"&gt;The Arena&lt;/a&gt; last night.  It was the best rock show I've been to in a long time.&lt;/p&gt;

&lt;div style="text-align: center;"&gt;&lt;a href="http://flickr.com/photos/graph/3170085517/"&gt;&lt;img src="http://farm4.static.flickr.com/3087/3170085517_531bd4f186.jpg" alt="Dr. Dog Photo at The Arena, Brisbane" title="Dr. Dog on stage"&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="http://www.drdogmusic.com/"&gt;Dr. Dog&lt;/a&gt; opened and I'm pretty sure they played Worst Trip, The Ark, The Beach, The Old Days, and a few others.  They were easily my favorite new-to-me band of 2008.  I first heard them on &lt;a href="http://www.xpn.org/yrock-on-xpn/home"&gt;yrock on xpn&lt;/a&gt; and soon after bought their new album, &lt;a href="http://www.amazon.com/Fate-Dr-Dog/dp/B0018TAFW0/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=music&amp;amp;qid=1231207997&amp;amp;sr=8-1"&gt;Fate&lt;/a&gt;.  They rocked.&lt;/p&gt;

&lt;div style="text-align: center;"&gt;&lt;a href="http://flickr.com/photos/graph/3170090719/"&gt;&lt;img src="http://farm4.static.flickr.com/3091/3170090719_1ea4a4b5a2_m.jpg" alt="Gomez Photo at The Arena, Brisbane" title="Gomez"&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;While I went to the show to see the opening act, the second opener &lt;a href="http://www.gomeztheband.com"&gt;Gomez&lt;/a&gt; turned out to be awesome.  I'm definitely going to need to check out some more of their work.&lt;/p&gt;

&lt;div style="text-align: center;"&gt;&lt;a href="http://flickr.com/photos/graph/3170105327/"&gt;&lt;img src="http://farm2.static.flickr.com/1146/3170105327_1f46b54d12_m.jpg" alt="The Black Keys Photo at The Arena, Brisbane" title="The Black Keys"&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="http://www.theblackkeys.com/"&gt;The Black Keys&lt;/a&gt; headlined and were incredible - those two guys had so much energy.  They're touring a bit more in Australia and then heading back to my hometown area.  They'll be at the Electric Factory in Philly in Feb - word is they sold out the TLA so quickly the show got moved.&lt;/p&gt;</content>
  </entry>
  <entry xml:base="http://g.raphaelli.com/2009/01/feed.atom">
    <title type="text">Ganglia for MySQL Metrics</title>
    <id>tag:g.raphaelli.com,2009-01-05/entry:2009/1/5/mysql-metrics-in-ganglia</id>
    <updated>2009-08-07T23:46:46Z</updated>
    <published>2009-01-05T02:43:00Z</published>
    <link href="http://g.raphaelli.com/2009/1/5/ganglia-mysql-metrics" />
    <author>
      <name>g</name>
    </author>
    <content type="html">&lt;p&gt;I just made some minor updates to the metric collection module I use for monitoring MySQL with Ganglia.  It collects over 100 metrics and includes a basic report like:

&lt;/p&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://static.g.raphaelli.com/images/2009/01/05/ganglia_mysql_report_sample.png" alt="MySQL selects, inserts, updates, deletes on one graph" title="Sample Ganglia MySQL Report"&gt;&lt;/div&gt;

This blog is the only thing using this MySQL server and I don't generate much traffic (hi mom!)
&lt;p&gt;&lt;/p&gt;

&lt;p&gt;It works either as a ganglia 3.1-style &lt;a href="http://ganglia.wiki.sourceforge.net/ganglia_gmond_python_modules"&gt;gmond python module&lt;/a&gt; or as a gmetric script, for use with any decent version of ganglia.  These are the relevant files:

&lt;/p&gt;&lt;ul&gt;
        &lt;li&gt;the module: &lt;a href="http://static.g.raphaelli.com/contrib/code/ganglia/mysql.py"&gt;mysql.py&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;sample module configuration file: &lt;a href="http://static.g.raphaelli.com/contrib/code/ganglia/mysql.pyconf"&gt;mysql.pyconf&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;ganglia frontend report: &lt;a href="http://static.g.raphaelli.com/contrib/code/ganglia/mysql_query_report.php"&gt;mysql_query_report.php&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;dependency module, for parsing InnoDB Status: &lt;a href="http://static.g.raphaelli.com/contrib/code/ganglia/DBUtil.py"&gt;DBUtil.py&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;/p&gt;

Comments and improvements are welcome.</content>
  </entry>
  <entry xml:base="http://g.raphaelli.com/2009/01/feed.atom">
    <title type="text">Packaging Python Modules</title>
    <id>tag:g.raphaelli.com,2009-01-01/entry:2009/1/1/packaging-python-modules</id>
    <updated>2009-08-07T23:48:13Z</updated>
    <published>2009-01-01T06:05:00Z</published>
    <link href="http://g.raphaelli.com/2009/1/1/packaging-python-modules" />
    <author>
      <name>g</name>
    </author>
    <content type="html">&lt;p&gt;Tools like &lt;a href="http://peak.telecommunity.com/DevCenter/EasyInstall"&gt;EasyInstall&lt;/a&gt; and &lt;a href="http://pypi.python.org/pypi/pip/"&gt;PIP&lt;/a&gt; are excellent for frequently changing environments.  I use virtualenv extensively in my development environments where I can easy_install or pip -E install away.  These tools, however, are not appropriate for production environments.  In production, repeatability and minimal dependency on development tools are essential.  When rolling out hundreds of servers, installing MySQL-python bindings with easy_install would require setting up a build environment on each host.  The operating system's package manager is sufficient for managing the installation of these modules.&lt;/p&gt;

&lt;p&gt;What if you need different versions of the same package on a particular host?  Assuming there are two applications running on a host that require different versions of the same package: move one of the applications to a separate host or VM.  If one application needs two versions of a particular package: fix the application.  In an emergency, running an application out of a temporary virtualenv can do the job at the expense of operational headaches.&lt;/p&gt;

&lt;p&gt;I run Redhat based systems so RPMs are the way to go for me.  python setup.py bdist_rpm is handy but there are a number of things I don't like about it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Packages are not python-versioned.  pyOpenSSL-0.8-1.i386.rpm does not indicate which python it is built against.  Also, what if you want that package for both python2.4 and python2.5?&lt;/li&gt;
&lt;li&gt;Similarly, I prefer that python library packages be clearly identified in the list of installed packages. A 'python-' prefix is effective.  rrdtool-1.2.27-5.i386.rpm is the application package, python25-rrdtool.i386.rpm are the python2.5 bindings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since those things are not easy to override in the stock bdist_rpm, I use a lightly modified distutils/command/bdist_rpm.py arbitrarily named bdist_rpm_ver.py.  Building production packages is usually as easy as:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;easy_install --build-directory ~/rpm/BUILD/ --editable &amp;lt;pkg&amp;gt;&lt;/li&gt;
&lt;li&gt;cd ~/rpm/BUILD/&amp;lt;pkg&amp;gt;&lt;/li&gt;
&lt;li&gt;pythonXX setup.py bdist_rpm_ver --fix-python --binary-only&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This certainly is not perfect yet - sometimes I have to break down and do a --spec-only and tweak things by hand.  Fortunately, this happens once and only takes a few minutes to fix and then I have a stable package ready for deployment.  Also, I handle dependencies separately from the rpms currently but they can be added in step 3 with --requires, --conflicts, etc.&lt;/p&gt;

&lt;p&gt;I'm interested in hearing more about:
&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;I’ve been meaning to write a post on why I think using system packaging for libraries is counter-productive, but that’ll wait for another time.
&lt;br&gt;&lt;br&gt;Ian Bicking - &lt;a href="http://blog.ianbicking.org/2008/12/14/a-few-corrections-to-on-packaging/"&gt;A Few Corrections To “On Packaging”&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;/p&gt;

&lt;p&gt;In my experience, system packaging is the way to go for simple, repeatable installations to a single host or 1000s of hosts.&lt;/p&gt;</content>
  </entry>
</feed>

