<?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>Tomatohater</title>
	<atom:link href="http://tomatohater.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://tomatohater.com</link>
	<description>Drew Engelson hates tomatoes.</description>
	<lastBuildDate>Mon, 23 Jan 2012 01:56:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Migrating a Django app to Heroku</title>
		<link>http://tomatohater.com/2012/01/23/migrating-a-django-app-to-heroku/</link>
		<comments>http://tomatohater.com/2012/01/23/migrating-a-django-app-to-heroku/#comments</comments>
		<pubDate>Mon, 23 Jan 2012 01:48:16 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[heroku]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://tomatohater.com/?p=132</guid>
		<description><![CDATA[Heroku supports Python! What are we waiting for?]]></description>
			<content:encoded><![CDATA[<p>As a Python and Django kind of guy, I had always been jealous of the Ruby on Rails folks. This has nothing at all to do with the framework itself. No, no, no&#8230;. Django all the way. It was the <a href="http://www.heroku.com">Heroku</a> cloud application platform that had me longing.</p>
<p>Yes, I could run my Django application on Google App Engine, but that requires all sorts of hackery and my app ended up an abomination of the original&#8230; too unnatural for my tastes.</p>
<p>I sensed a small shift in the Earth&#8217;s rotation on Sept 28, 2011. This is when Heroku added <a href="http://blog.heroku.com/archives/2011/9/28/python_and_django/">support for Python/Django</a> on their platform. I needed to give it a test drive and I was amazed how simple it was. The following is an account of what I did to port one of my existing Django sites to Heroku&#8230;</p>
<h2>Initial setup</h2>
<p>Heroku already provides a decent <a href="http://devcenter.heroku.com/articles/python">quick start guide for Python</a>. That&#8217;s a great place to begin. Check out the <strong>Prerequisites</strong> and <strong>Local Workstation Setup</strong> which will get you up and running quickly. It helps if you&#8217;re already familiar with <a href="http://git-scm.com/">Git</a>, <a href="http://pypi.python.org/pypi/virtualenv">virtualenv</a> and <a href="http://pypi.python.org/pypi/pip">pip</a>. If you&#8217;re not, then now is an excellent time to learn!</p>
<p>First things first. Assuming your Django project is already in Git, change directory to the project root. Then&#8230;</p>
<pre class="prettyprint lang-sh">$ heroku login
... output omitted ...
$ heroku create --stack cedar
... output omitted ...</pre>
<p>Believe it or not, we&#8217;re almost there!</p>
<h2>Database config</h2>
<p>Now, my existing app is running a MySQL database. I&#8217;m going to use the built-in Postgres DB on Heroku. So I need to update my Django settings&#8230;</p>
<pre class="prettyprint lang-python"># Database config
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
    }
}</pre>
<p>Note, that I didn&#8217;t supply any database info or credentials. Heroku auromatically injects this info into your settings.py file. I also need to dump out my current database which I can later import into my new app (this could also be done with fixtures).</p>
<pre class="prettyprint lang-sh">$ python myapp/manage.py dumpdata &gt; db.sql</pre>
<p>I&#8217;m already storing my Python dependencies in a <a href="http://www.pip-installer.org/en/latest/requirements.html">requirements.txt</a> file. If you&#8217;re not, you&#8217;ll need to create this file at the project root.</p>
<pre class="prettyprint">$ pip freeze &gt; requirements.txt
$ cat requirements.txt
Django==1.3
feedparser==5.1
gunicorn==0.12.2
lxml==2.3.3
psycopg2==2.4.2
python-dateutil==1.5
python-sunlightapi==1.1.0
</pre>
<p>Don&#8217;t forget to commit your changes! Then push to Heroku.</p>
<pre class="prettyprint">$ git commit -a -m 'Mods to run on Heroku.'
$ git push heroku master</pre>
<p>That second line above is really something to be admired. Not only does it push the code to Heroku&#8217;s repository, but then it triggers a real deployment. Heroku automatically copies the files to the stack, installs all the dependencies (via requirements.txt), detects that this is a Django application, and runs the application with &#8220;runserver&#8221;. Poof! Done.</p>
<p>Well, not quite done. But really that&#8217;s bulk of the it and my app is in fact running. You can confirm this by using the &#8220;heroku ps&#8221; command.</p>
<h2>Running your app</h2>
<p>Now I need to do all the normal Django setup stuff, like syncdb and loaddata&#8230;</p>
<pre class="prettyprint">$ heroku run python myapp/manage.py syncdb
$ heroku run python myapp/manage.py loaddata &lt; db.sql</pre>
<p>If all goes well, I should be able to hit my site with a web browser at the wacky hostname provided by Heroku when I created the stack. Herou provides a shortcut&#8230;</p>
<pre class="prettyprint">$ heroku open</pre>
<h2>Final thoughts</h2>
<p>We&#8217;ll that was pretty darn easy. A few other things to note if you&#8217;re trying this yourself.</p>
<ul>
<li>You&#8217;ll need to serve static media from somewhere. I used <a href="https://docs.djangoproject.com/en/dev/howto/static-files/#using-django-contrib-staticfiles">django.contrib.staticfiles</a> in this example, but that&#8217;s probably not idea for production. Though the output does get cached&#8230; so it&#8217;s also not too bad.</li>
<li>You don&#8217;t want to use the built-in Django runserver. I prefer <a href="http://gunicorn.org/">gunicorn</a> and it&#8217;s easy to configure that!</li>
<li>Enjoy yourself. This is cool stuff!</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2012/01/23/migrating-a-django-app-to-heroku/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dear Congress&#8230;</title>
		<link>http://tomatohater.com/2012/01/19/dear-congress/</link>
		<comments>http://tomatohater.com/2012/01/19/dear-congress/#comments</comments>
		<pubDate>Thu, 19 Jan 2012 02:20:02 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[congress]]></category>
		<category><![CDATA[opengov]]></category>
		<category><![CDATA[pipa]]></category>
		<category><![CDATA[sopa]]></category>

		<guid isPermaLink="false">http://tomatohater.com/?p=158</guid>
		<description><![CDATA[A note to Congress regarding SOPA and PIPA]]></description>
			<content:encoded><![CDATA[<p>Dear Representative Van Hollen, Senator Cardin, and Senator Mikulski:</p>
<p>The “Stop Online Piracy Act” (H.R. 3261) and the “Preventing Real Online Threats to Economic Creativity and Theft of Intellectual Property Act of 2011″ (S.968) are intended to solve a worthy problem, yet the methods recommended by these bills I find to be completely offensive.</p>
<p>I greatly value the protection of intellectual property, yet I place the values of freedom and free speech even higher. We must not enact a bill with power to dismantle these very freedoms.</p>
<p>Please find another way. Punish the offender, not the messenger. I have confidence that you will find an acceptable alternative.</p>
<p>Please undertand very clearly that your vote for these bills in their current forms will be countered with a vote against you in your next election.</p>
<p>Sincerely,</p>
<p>Drew Engelson<br />
Cabin John, MD</p>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2012/01/19/dear-congress/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Custom Django management commands on Heroku</title>
		<link>http://tomatohater.com/2012/01/17/custom-django-management-commands-on-heroku/</link>
		<comments>http://tomatohater.com/2012/01/17/custom-django-management-commands-on-heroku/#comments</comments>
		<pubDate>Tue, 17 Jan 2012 02:51:31 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[heroku]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://tomatohater.com/?p=137</guid>
		<description><![CDATA[Quick solution to a common Django/Heroku problem.]]></description>
			<content:encoded><![CDATA[<h1>Running custom management commands</h2>
<p>Running Django management commands is easy on <a href="http://heroku.com">Heroku</a>. For example, to <strong>syncdb</strong> you simply execute:</p>
<pre class="prettyprint">$ heroku run python your_app/manage.py syncdb</pre>
<p>Easy enough. But you may find that running a <a href="https://docs.djangoproject.com/en/dev/howto/custom-management-commands/">custom management command</a> to be a little trickier. You might run into something like this:</p>
<pre class="prettyprint">$ heroku run python your_app/manage.py your_custom_command
Running python your_app/manage.py your_custom_command attached to terminal... up, run.2
Unknown command: 'your_custom_command'
Type 'manage.py help' for usage.</pre>
<p>Ouch! And you wouldn&#8217;t be alone here:</p>
<ul>
<li><a href="http://stackoverflow.com/questions/8294363/django-custom-commands-not-showing-up-on-heroku">Django custom commands not showing up on Heroku</a></li>
<li><a href="http://stackoverflow.com/questions/8380733/running-django-custom-manage-py-task-on-heroku-importing-issues">Running Django custom manage.py task on Heroku &#8211; Importing Issues</a></li>
<li><a href="https://convore.com/django-community/custom-management-command-discovery-fail/">Custom management command discovery fail <img src='http://tomatohater.com/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' /> </a></li>
</ul>
<p></p>
<h1>The solution</h2>
<p>This really just comes down to Python not finding your app. You just need to adjust your Python path to include your home directory.</p>
<p>On Heroku, your home directory is generally &#8220;/app&#8221;. You should confirm this by running:</p>
<pre class="prettyprint">$ heroku run env | grep HOME
HOME=/app
</pre>
<p>A simple way to adjust your Python path within your Heroku environment (and not mucking with your app) is by setting the PYTHONPATH env variable as follows:</p>
<pre class="prettyprint">$ heroku config:add PYTHONPATH=/app
</pre>
<p>To confirm it is set correctly, run:</p>
<pre class="prettyprint">$ heroku run env | grep PYTHONPATH
PYTHONPATH=/app
</pre>
<p>Now you can run your custom management command. This also allows you to run these as cron (scheduled) tasks:</p>
<pre class="prettyprint">$ heroku run python your_app/manage.py your_custom_command
Success!</pre>
<p>I hope this post will save you some headbanging. Unless, of course, it&#8217;s to the Melvins.</p>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2012/01/17/custom-django-management-commands-on-heroku/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Why Django?</title>
		<link>http://tomatohater.com/2011/11/21/why-django/</link>
		<comments>http://tomatohater.com/2011/11/21/why-django/#comments</comments>
		<pubDate>Mon, 21 Nov 2011 16:06:27 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://tomatohater.com/?p=123</guid>
		<description><![CDATA[In 5 words or less... Why do you use Django?]]></description>
			<content:encoded><![CDATA[<p>I have been a heavy Django developer, architect, and evangelist since about 2006 when <a href="http://nowell.strite.org/" title="Nowell Strite">Nowell Strite</a> and I first saw a presentation by <a href="http://conferences.oreillynet.com/cs/os2006/view/e_sess/9153" title="Django: Web Development with Journalists' Deadlines with Jacob Kaplan-Moss and Adrian Holovaty">Adrian and Jacob at OSCON</a>. We brought Django back to <a href="http://www.pbs.org/">PBS</a> where it quickly became our standard development platform.</p>
<h1>I know why I use Django&#8230;</h1>
<p>I&#8217;m conducting some informal research for a project and I want to hear from you. <strong>Why you do use Django?</strong> Please leave a comment here or tweet me <a href="http://twitter.com/handofdoom">@handofdoom</a>.</p>
<p>Try to limit your responses to 5 words or less.</p>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2011/11/21/why-django/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Concatenating strings in Django templates</title>
		<link>http://tomatohater.com/2011/09/22/concatenating-strings-django-templates/</link>
		<comments>http://tomatohater.com/2011/09/22/concatenating-strings-django-templates/#comments</comments>
		<pubDate>Thu, 22 Sep 2011 15:43:22 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[templates]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=109</guid>
		<description><![CDATA[Cheap ass hack to append a string within Django templates.]]></description>
			<content:encoded><![CDATA[<p>You might think that joining two strings in a Django template would have been simple and straightforward. In modern versions of Django, we can achieve it using the <strong>add</strong> filter.</p>
<pre class="prettyprint lang-html">
{{ "Mary had a little"|add:" lamb." }}
</pre>
<p>However, in earlier versions of Django [TODO: identify specific version], the add filter only works with numbers. Using it on a string has no effect.</p>
<h3>So how to do it?</h3>
<p>It looks like we&#8217;re left with the <strong>stringformat</strong> filter. This feels quite dirty to me, but it works.</p>
<pre class="prettyprint lang-html">
{{ "Mary had a little"|stringformat:"s lamb." }}
</pre>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2011/09/22/concatenating-strings-django-templates/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>DCPython: Architecture at PBS</title>
		<link>http://tomatohater.com/2011/06/08/dcpython-architecture-pbs/</link>
		<comments>http://tomatohater.com/2011/06/08/dcpython-architecture-pbs/#comments</comments>
		<pubDate>Wed, 08 Jun 2011 15:42:16 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[celery]]></category>
		<category><![CDATA[dcpython]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[solr]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=106</guid>
		<description><![CDATA[Slides from DCPython meetup on Jun 7, 2011]]></description>
			<content:encoded><![CDATA[<p><a href="http://open.pbs.org/edgarroman/">Edgar</a> and I had the pleasure of presenting at the <a href="http://meetup.dcpython.org/events/15037316/">DCPython meetup</a> last night about how PBS uses Python, Django, Celery, Solr and Amazon Web Services (autoscaling EC2, RDS) to power many of our sites and services. We focused primarily on the COVE (video) and Merlin (content) APIs since those probably have the most interesting architectures.</p>
<p>We had a blast and received many smart questions from the crowd about Solr, Amazon Web Services, Celery and the recent Tupac incident in about that order. Thanks for having us DCPython!</p>
<p>Check out DCPython at <a href="http://dcpython.org">http://dcpython.org</a> or follow <a href="http://twitter.com/DCPython">@DCPython</a>.</p>
<div style="width:425px" id="__ss_8247826"><strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/tomatohater/dcpython-architecture-at-pbs-jun-7-2011" title="DCPython: Architecture at PBS (Jun 7, 2011)">DCPython: Architecture at PBS (Jun 7, 2011)</a></strong><object id="__sse8247826" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=dcpython-pbs-20110607-110608103249-phpapp02&#038;stripped_title=dcpython-architecture-at-pbs-jun-7-2011&#038;userName=tomatohater" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse8247826" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=dcpython-pbs-20110607-110608103249-phpapp02&#038;stripped_title=dcpython-architecture-at-pbs-jun-7-2011&#038;userName=tomatohater" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<div style="padding:5px 0 12px">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/tomatohater">Drew Engelson</a>.</div>
</div>
<div style="background-color: #DDDDDD; font-size: smaller; padding: 6px; margin-bottom: 8px; border: 1px solid #999999;"><strong>Note:</strong> This is a repost from the <a href="http://bit.ly/lUxni9" title="DCPython: Architecture at PBS (Jun 7, 2011) slides">OpenPBS blog</a>.</div>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2011/06/08/dcpython-architecture-pbs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Recovering from Amazon cloud outage</title>
		<link>http://tomatohater.com/2011/04/21/recovering-amazon-cloud-outage/</link>
		<comments>http://tomatohater.com/2011/04/21/recovering-amazon-cloud-outage/#comments</comments>
		<pubDate>Thu, 21 Apr 2011 15:41:03 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[amazon-web-services]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[ebs]]></category>
		<category><![CDATA[ec2]]></category>
		<category><![CDATA[pbs]]></category>
		<category><![CDATA[rds]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=103</guid>
		<description><![CDATA[What happens when the AWS cloud has a very, very bad day?]]></description>
			<content:encoded><![CDATA[<p><a href="http://aws.amazon.com/">Amazon Web Services</a> (AWS) have been integral to the successes of nearly all recent project launches at <a href="http://www.pbs.org/">PBS</a>. All of our core applications are deployed out on AWS EC2 servers and RDS database instances. While we have  experienced an occasional component failure, these have been infrequent. When failures have occurred, we have typically been able to leverage the agility of the cloud to quickly and easily work through them.</p>
<h3>AWS East is down</h3>
<p>April 21st was quite another story! Early that morning, AWS began experiencing connectivity issues affecting Elastic Block Store (EBS) volumes in the Northern Virginia region (us-east-1), and hence any EC2 or RDS instances that depend on EBS. Oy vey!</p>
<p>
The outage was heavily covered in the press:</p>
<ul>
<li><a href="http://technorati.com/technology/it/article/amazon-ec2-outlook-cloudy-with-a/" title="Amazon EC2 Outlook: Cloudy With A Chance of Downtime">Technorati</a></li>
<li><a href="http://www.informationweek.com/news/cloud-computing/infrastructure/229402054" title="Amazon EC2 Outage Hobbles Websites">Information Week</a></li>
<li><a href="http://www.marketwatch.com/video/asset/digits-amazons-cloud-crashes-2011-04-21/C8BA6424-08D4-450A-8855-DF67A2397C8A#!C8BA6424-08D4-450A-8855-DF67A2397C8A" title="digits: Amazon's Cloud Crashes">MarketWatch [video]</a></li>
<li><a href="http://www.reuters.com/article/2011/04/21/amazon-cloud-idUSN2128319020110421" title="Amazon cloud disruption hits some social websites">Reuters</a></li>
</ul>
<p>What did this mean for PBS? Well it took out our main portal site (<a href="http://www.pbs.oprg/">PBS.org</a>) and many core services (Merlin API, COVE video API, TV Schedules API, mobile apps for iPad and iPhone, and more) for a while. Ouch! While we try to leverage multiple availability zones where possible, we are entirely in Amazon&#8217;s East Coast data centers.</p>
<h3>Recovering from AWS outage</h3>
<p>Since the outage affected only EBS-based EC2 and RDS services in the East region, a path to workaround the outage seems obvious:</p>
<ol>
<li>Avoid EBS (at least for now)</li>
<li>Go West, young man!</li>
</ol>
<p>This is exactly what we did this morning. We relaunched some applications from backups on temporarily EBS-less servers. And we migrated some RDS database servers to the West coast region (us-west-1). Once this was accomplished, our public facing systems were back online.</p>
<h3>Looking forward</h3>
<p>Now what? How can we depend on AWS in the future? Should we migrate our services elsewhere? There is a universal truth that applies here: <strong>sh*t happens</strong></p>
<p>In practicality, being in the cloud has provided such an improvement in our overall stability and ability to manage our infrastructure with minimal resources that I can no longer imagine life without it.</p>
<p>So the real question is, &#8220;How can we reduce our exposure to this in the future?&#8221;</p>
<p>Any ideas?</p>
<h3>Links</h3>
<ul>
<li><a href="http://status.aws.amazon.com/" title="AWS Service Health Dashboard">AWS Service Health Dashboard</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2011/04/21/recovering-amazon-cloud-outage/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>mod_wsgi and the HTTP Authorization header</title>
		<link>http://tomatohater.com/2011/04/07/mod_wsgi-and-http-authorization-header/</link>
		<comments>http://tomatohater.com/2011/04/07/mod_wsgi-and-http-authorization-header/#comments</comments>
		<pubDate>Thu, 07 Apr 2011 15:39:29 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[mod_wsgi]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=100</guid>
		<description><![CDATA[A friendly reminder for myself to RTFD!]]></description>
			<content:encoded><![CDATA[<p>If one is building a WSGI application on mod_wsgi and one wants this WSGI application to handle HTTP authentication, it is likely that one will need access to the &#8220;Authorization&#8221; HTTP header at some point. Had one read the documentation, one would have already understood that mod_wsgi does not pass this header to your WSGI application by default. This is probably a very good thing.</p>
<p>To tell mod_wsgi to pass the Authorization header through to your application, just set the mod_wsgi configuration directive <a href="http://code.google.com/p/modwsgi/wiki/ConfigurationDirectives#WSGIPassAuthorization">WSGIPassAuthorization</a>  to &#8220;On&#8221;.</p>
<pre class="prettyprint lang-sh"># enable authorization headers
WSGIPassAuthorization On

# set up wsgi app
WSGIApplicationGroup myapp-1
WSGIImportScript /projects/myapp/myapp.wsgi application-group=myapp-1 process-group=myapp-1
WSGIScriptAlias /myapp /projects/myapp/myapp.wsgi</pre>
<p>Note to self (and others who may have wasted time on such things):<br />
<a href="http://code.google.com/p/modwsgi/wiki/ConfigurationDirectives">Read The Docs!</a></p>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2011/04/07/mod_wsgi-and-http-authorization-header/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AWS Identity and Access Management (IAM) with Python</title>
		<link>http://tomatohater.com/2011/01/22/aws-identity-and-access-management-iam-python/</link>
		<comments>http://tomatohater.com/2011/01/22/aws-identity-and-access-management-iam-python/#comments</comments>
		<pubDate>Sat, 22 Jan 2011 15:37:50 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[amazon-web-services]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[boto]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[iam]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=97</guid>
		<description><![CDATA[Flexible access control to AWS cloud services using Amazon IAM, Python, and boto]]></description>
			<content:encoded><![CDATA[<p>With <a href="http://aws.amazon.com/">all the AWS services</a> that are now available, our opportunities in the cloud are virtually unlimited. But using any of these services requires access to your AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY and unfortunately, these keys provides complete access to the kingdom. This may not be a problem for some, but for large enterprises, granular access control is a necessity.</p>
<p>Up until recently, we would have been out of luck. But fortunately Amazon released <a href="http://aws.amazon.com/iam/">Identity and Access Management (IAM)</a> which makes flexible access control possible. And <a href="http://code.google.com/p/boto/" title="boto - Python interface to Amazon Web Services">boto</a> makes it easy in <a href="http://www.python.org" title="Python Programming Language – Official Website">Python</a>.</p>
<h3>Take this example</h3>
<p>Say your company uses Amazon S3 store your company&#8217;s image assets in a variety of S3 buckets. If you needed to grant a third party the ability to upload new images to your S3 account, they will need a set of keys. You wouldn&#8217;t want to give them your main keys since not only would they gain access to <strong>all</strong> of your S3 buckets, but also your EC2 instances, RDS databases, etc. Not a good situation.</p>
<p>Here&#8217;s where IAM comes in. With IAM, you can create a user for this specific purpose which would have it&#8217;s own unique AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY key pair. Additionally, you can apply an IAM policy to restrict what this user can do&#8230; a specific S3 bucket, in this case.</p>
<h3>Let&#8217;s give it a try</h3>
<p>In this example, we&#8217;ll create a user called <em>melvins</em> and grant it access to an S3 bucket called <em>houdini</em>.</p>
<pre class="prettyprint lang-py">import boto

# Connect to IAM with boto
iam = boto.connect_iam(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)

# Create user
user_response = iam.create_user('melvins')

# Limit access with IAM policy
policy_json = '''{
    "Statement":[{
        "Sid":"RandomStringIdentifier",
        "Action":"s3:*",
        "Effect":"Allow",
        "Resource":"arn:aws:s3:::houdini/*"
    }]
}'''
iam.put_user_policy('melvins', 'allow_access_houdini', policy_json)

# Generate new access key pair for 'melvins'
key_response = iam.create_access_key('melvins')
</pre>
<p>We now have a new set of AWS keys with access limited to a single S3 bucket. We could have just as easily further limited it to specific action (i.e. S3:PutObject), or to other services (i.e. EC2:*).</p>
<p>The objects we created with boto provide us with all sorts of nifty info.</p>
<pre class="prettyprint lang-py">
>>> import simplejson as json
>>>
>>> user = user_response.create_user_response.create_user_result.user
>>> print json.dumps(user, indent=4)
{
    "path": "/",
    "create_date": "2011-01-22T20:02:27.900Z",
    "user_id": "AIDAXXXXXXXXXXXXXKXBW",
    "arn": "arn:aws:iam::46XXXXXXXX90:user/melvins",
    "user_name": "melvins"
}
>>>
>>> key = key_response.create_access_key_response.create_access_key_result.access_key
>>> print json.dumps(key, indent=4)
{
    "status": "Active",
    "user_name": "melvins",
    "create_date": "2011-01-22T20:16:17.189Z",
    "secret_access_key": "vDskXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX2cob",
    "access_key_id": "AKIAXXXXXXXXXXXXQ5DA"
}
>>>
>>> # Provide new keys to user
>>> print 'AWS_ACCESS_KEY_ID', key.access_key_id
AWS_ACCESS_KEY_ID AKIAXXXXXXXXXXXXQ5DA
>>>
>>> print 'AWS_SECRET_ACCESS_KEY', key.secret_access_key
AWS_SECRET_ACCESS_KEY vDskXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX2cob
</pre>
<h3>Using IAM groups</h3>
<p>Suppose your have three trusted employees (<em>Buzzo</em>, <em>Lorax</em> and <em>Dale</em>) who require full access to your AWS account. You could give them the master key pair. But what if <em>Lorax</em> decides to leave the company? You would have to change your master key pair, redistribute to the remaining employees, and hope there was nothing depending on the old ones. I would grow tired of this very quickly.</p>
<p>A better solution is to grant each employee his own key pair (as described above). But rather than managing their policies individually, you could add them to a group and apply a group policy.</p>
<pre class="prettyprint lang-py">import boto

# Connect to IAM with boto
iam = boto.connect_iam(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)

# Create group
iam.create_group('admins')

# Apply full access IAM policy
policy_json = '''{
   "Statement":[{
      "Effect":"Allow",
      "Action":"*",
      "Resource":"*"
      }
   ]
}
'''
iam.put_group_policy('admins', 'allow_all', policy_json)

# Create users
iam.create_user('buzzo')
iam.create_user('lorax')
iam.create_user('dale')

# Generate access keys
iam.create_access_key('buzzo')
iam.create_access_key('lorax')
iam.create_access_key('dale')

# Add users to group
iam.add_user_to_group('admins', 'buzzo')
iam.add_user_to_group('admins', 'lorax')
iam.add_user_to_group('admins', 'dale')
</pre>
<p>So when <em>Lorax</em> takes off, it&#8217;s just a simple matter.</p>
<pre class="prettyprint lang-py">
iam.remove_user_from_group('admins', 'lorax')
iam.delete_user('lorax')
</pre>
<p>The moral of the story is: Quit distributing your master access keys. Use IAM. I doubt you want to learn this lesson the hard way!</p>
<p style="font-size: smaller">Version note: boto added IAM support in 2.0b3.</p>
<h3>Links</h3>
<ul>
<li><a href="http://aws.amazon.com/iam/" title="AWS Identity and Access Management (IAM)">AWS Identity and Access Management (IAM)</a></li>
<li><a href="http://boto.cloudhackers.com/ref/iam.html" title="boto v2.0 &gt; API Reference &gt; IAM">boto v2.0 &gt; API Reference &gt; IAM</a></li>
<li><a href="http://www.last.fm/music/Melvins">Melvins</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2011/01/22/aws-identity-and-access-management-iam-python/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>pyawschart &#8211; v0.2 released</title>
		<link>http://tomatohater.com/2011/01/10/pyawschart-v02-released/</link>
		<comments>http://tomatohater.com/2011/01/10/pyawschart-v02-released/#comments</comments>
		<pubDate>Mon, 10 Jan 2011 15:35:37 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[amazon-web-services]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[boto]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[cloudwatch]]></category>
		<category><![CDATA[ebs]]></category>
		<category><![CDATA[ec2]]></category>
		<category><![CDATA[elb]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[rds]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=94</guid>
		<description><![CDATA[Amazon CloudWatch data visualization]]></description>
			<content:encoded><![CDATA[<p>I have just pushed the source code for <a href="/pyawschart/" title="pyawschart: Python library for generating charts for Amazon Web Services based on Amazon CloudWatch data.">pyawschart &#8211; v0.2</a> out to <a href="http://github.com/tomatohater/pyawschart" title="tomatohater/pyawschart - GitHub">GitHub</a>. This project was created a few months back and I have been using it for personal (<a href="http://probosc.is/">Proboscis</a>) and professional (<a href="http://www.pbs.org/">PBS</a>) projects since then. I&#8217;ve just decided to open source it for the betterment of the AWS and Python communities.</p>
<p>The goal was quite simple&#8230; Use <a href="http://boto.cloudhackers.com/" title="boto: A Python interface to Amazon Web Services">boto</a> to pipe <a href="http://aws.amazon.com/cloudwatch/" title="Amazon CloudWatch">Amazon CloudWatch</a> data into <a href="http://pygooglechart.slowchop.com/" title="pygooglechart is a complete Python wrapper for the Google Chart API. ">Python Google Chart</a> and hope for some really cool data visualizations.</p>
<p>
The results are pretty neat:<br />
<a href="http://www.flickr.com/photos/drewengelson/5343110179/" title="pyawschart-rds-writeops-example-1 by tomatohater, on Flickr"><img src="http://farm6.static.flickr.com/5165/5343110179_ed864e7b7f.jpg" width="400" height="166" alt="pyawschart-rds-writeops-example-1"   style="padding: 20px;" /></a>
</p>
<h3>Features</h3>
<p><a href="/pyawschart/" title="pyawschart: Python library for generating charts for Amazon Web Services based on Amazon CloudWatch data.">pyawschart &#8211; v0.2</a> supports all of the metrics that Amazon makes available for Elastic Compute Cloud (EC2), Relation Database Service (RDS), Elastic Block Store (EBS), and Elastic Load Balancer (ELB).</p>
<h3>Example code</h3>
<p>Get EC2 cpu utilization chart for the past hour.</p>
<pre class="prettyprint lang-py">import boto
from pyawschart import RANGES
from pyawschart.ec2 import CPUUtilizationChart

# Connect with boto
conn = boto.connect_cloudwatch(AWS_ACCESS_KEY AWS_SECRET_ACCCES_KEY)
chart = CPUUtilizationChart(conn, 'i-6d3efXXX', RANGES['hour'])

# Display chart url
print chart.get_url()

# Download chart image
chart.download('/tmp/i-6d3efXXX-cpu-hour.png')
</pre>
<p>Get RDS database connections chart for the past day.</p>
<pre class="prettyprint lang-py">import boto
from pyawschart import RANGES
from pyawschart.rds import DatabaseConnectionsChart

# Connect with boto
conn = boto.connect_cloudwatch(AWS_ACCESS_KEY AWS_SECRET_ACCCES_KEY)
chart = DatabaseConnectionsChart(conn, 'my-rds-instance', RANGES['day'])

# Display chart url
print chart.get_url()

# Download chart image
chart.download('/tmp/my-ec2-instance-connections-day.png')
</pre>
<h3>Feedback</h3>
<p>While the library works well for most of the use cases I require, I would welcome feedback on your use cases. Use it&#8230; Abuse it.. then submit comments on this entry, or post issues/requests on <a href="https://github.com/tomatohater/pyawschart/issues" title="Issues - tomatohater/pyawschart - GitHub">GitHub</a>.</p>
<h3>URLs</h3>
<ul>
<li>Project page: <a href="http://tomatohater.com/pyawschart/">http://tomatohater.com/pyawschart/</a></li>
<li>Source code: <a href="http://github.com/tomatohater/pyawschart">http://github.com/tomatohater/pyawschart</a></li>
<li>Issue tracker: <a href="http://github.com/tomatohater/pyawschart/issues">http://github.com/tomatohater/pyawschart/issues</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2011/01/10/pyawschart-v02-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Lunar eclipse photos</title>
		<link>http://tomatohater.com/2010/12/21/lunar-eclipse-photos/</link>
		<comments>http://tomatohater.com/2010/12/21/lunar-eclipse-photos/#comments</comments>
		<pubDate>Tue, 21 Dec 2010 15:33:21 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Astronomy]]></category>
		<category><![CDATA[astronomy]]></category>
		<category><![CDATA[lunar-eclipse]]></category>
		<category><![CDATA[moon]]></category>
		<category><![CDATA[photography]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=91</guid>
		<description><![CDATA[From an extremely amateur photographer]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m no photographer, but since I was staying up late to watch this morning&#8217;s <a href="http://eclipse.gsfc.nasa.gov/OH/OH2010.html#LE2010Dec21T" title="NASA - Eclipses During 2010 (December 21)">total lunar eclipse</a> anyway (what is it, almost 6am now?), I decided to break out my camera, point the lens skyward, and see what happens. Of course, I had absolutely no idea what I was doing and I messed with all sorts of settings (ISO, f-stop, shutter speed, white balance), but I eventually came up with some interesting results</p>
<p><a href="http://www.flickr.com/photos/drewengelson/5279423037/" title="eclipse-mosaic by tomatohater, on Flickr"><img src="http://farm6.static.flickr.com/5210/5279423037_34e141cdf1.jpg" width="500" height="103" alt="eclipse-mosaic" /></a></p>
<p>About mid way through the event, the sky over Washington, DC become overcast, putting a damper on the re-emergence phase. But at one point I caught a glimpse just as the moon peeked through a hole in the cloud cover.</p>
<p><a href="http://www.flickr.com/photos/drewengelson/5280026792/" title="Eclipse through cloud by tomatohater, on Flickr"><img src="http://farm6.static.flickr.com/5250/5280026792_0b785508d7.jpg" width="500" height="332" alt="Eclipse through cloud" /></a></p>
<p>As I was tinkering with various exposures just before the eclipse, I accidentally took the following photo which I think came out pretty cool. Check out Orion and Taurus! Note to self: I need to try out more night sky photography.</p>
<p><a href="http://www.flickr.com/photos/drewengelson/5280026642/" title="Pre-eclipse sky by tomatohater, on Flickr"><img src="http://farm6.static.flickr.com/5288/5280026642_5c4d31de5b.jpg" width="500" height="332" alt="Pre-eclipse sky" /></a></p>
<p>By the way, as the eclipse reached totality, it was gorgeous through my telescope. Now if only I could figure out how to hook my camera up to that!</p>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2010/12/21/lunar-eclipse-photos/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New PBS.org launched!</title>
		<link>http://tomatohater.com/2010/10/25/new-pbsorg-launched/</link>
		<comments>http://tomatohater.com/2010/10/25/new-pbsorg-launched/#comments</comments>
		<pubDate>Mon, 25 Oct 2010 15:32:13 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[amazon-web-services]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[ec2]]></category>
		<category><![CDATA[pbs]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[rds]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=88</guid>
		<description><![CDATA[New Django-based PBS.org site and APIs]]></description>
			<content:encoded><![CDATA[<p>Today is a big day. Just after midnight we pulled the trigger and launched the new re-envisioned <a href="http://www.pbs.org/">PBS.org website</a>. This is a huge step for PBS on a number of fronts; mostly having to do bringing PBS to the <a href="http://www.hollywoodreporter.com/news/pbs-making-digital-push-new-32272 title="PBS Making Digital Push With New Website, iPad Application">forefront of new media</a>.
<p><a href="http://www.flickr.com/photos/drewengelson/5114959088/" title="New PBS.org launched today (cropped) by tomatohater, on Flickr"><img src="http://farm2.static.flickr.com/1249/5114959088_18aaf94e94.jpg" width="500" height="359" alt="New PBS.org launched today (cropped)" /></a></p>
<p>But for me, as you might imagine, the most interesting aspect is the technology architecture underlying it all.</p>
<h3>A win for Django and Python</h3>
<p>There is no doubt that the new PBS.org site probably ranks as one of the most highly trafficked Django sites in existence today. I think there is a lot to be said about how Django may be scaled if an application is properly designed. The tools are all there for the taking. I will write a future post that details the full architecture, but here is a short list of technologies involved in the stack: <a href="http://python.org/" title="Python Programming Language">Python</a>, <a href="http://www.djangoproject.com/" title="Django | The Web framework for perfectionists with deadlines">Django</a>, <a href="http://www.mysql.com/">MySQL</a>, <a href="http://httpd.apache.org/" title="The Apache HTTP Server Project">Apache</a>, <a href="http://memcached.org/" title="memcached - a distributed memory object caching system">Memcached</a>, <a href="http://celeryproject.org/" title="Celery - The Distributed Task Queue">Celery</a>, <a href="http://bitbucket.org/jespern/django-piston/wiki/Home" title="Piston is a Django mini-framework creating APIs.">Piston</a>, <a href="http://aws.amazon.com/" title="Amazon Web Services">Amazon Web Services</a></p>
<h3>And thanks for cloud computing&#8230;</h3>
<p>You may have noticed Amazon Web Services mentioned above. I slipped it in at the end of the list, but in reality, it is truly the enabling technology that makes all else possible. The new PBS.org site sits on a cluster of Amazon EC2 instances and is powered by a few Relational Database Service (RDS) instances. In my opinion, RDS is already very cool, and getting much cooler.</p>
<p>Putting the applications in the cloud lets us be very agile on the infrastructure side. In fact, just prior to launch, we decided to put the cache on a bigger machine and that took all of 10 minutes. This kind of stuff is just not possible on a traditional infrastructure. Thank you, Amazon.</p>
<p>And big thanks to the entire team of smart and hardworking individuals that made this site launch a success. Hats off to you all!</p>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2010/10/25/new-pbsorg-launched/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CloudFront object invalidation in Python</title>
		<link>http://tomatohater.com/2010/10/22/cloudfront-object-invalidation-python/</link>
		<comments>http://tomatohater.com/2010/10/22/cloudfront-object-invalidation-python/#comments</comments>
		<pubDate>Fri, 22 Oct 2010 15:31:04 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[amazon-web-services]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[boto]]></category>
		<category><![CDATA[cdn]]></category>
		<category><![CDATA[cloudfront]]></category>
		<category><![CDATA[expiration]]></category>
		<category><![CDATA[invalidation]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[rest]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=85</guid>
		<description><![CDATA[Pythonically purge objects from CloudFront via RESTful API]]></description>
			<content:encoded><![CDATA[<p><a href="http://aws.amazon.com" title="Amazon Web Services">Amazon Web Services</a> enables the management of all AWS services through some pretty powerful REST APIs. <a href="http://aws.amazon.com/cloudfront/">CloudFront</a> is Amazon&#8217;s content delivery network offering which allows you to serve files out of S3 buckets with much better performance. S3 files are cached at edge servers so that users may download them more quickly. The service plays nice with cache-control and expiration headers, but what happens when you need to delete or update some cached files from the edge immediately?</p>
<p>CloudFront <a href="http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/index.html?CreateInvalidation.html" title="POST object invalidation for AWS CloudFrront">object invalidation</a> is a recent addition&#8230; here&#8217;s how to do it in Python.</p>
<h3>AWS REST authentication</h3>
<p>One of the first things you&#8217;ll need to do for each request is <a href="http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/RESTAuthentication.html" title="Authenticating REST Requests">generate an authentication signature</a> based on your AWS credentials. So let&#8217;s define a function for that.</p>
<pre class="prettyprint lang-py">>>> import base64
>>> import datetime
>>> import hmac
>>> import hashlib
>>>
>>>
>>> def get_aws_auth():
>>>     date = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
>>>     auth = 'AWS %s:%s' % (
>>>         AWS_ACCESS_KEY,
>>>         base64.b64encode(
>>>             hmac.new(
>>>                 AWS_SECRET_ACCESS_KEY.encode('utf-8'),
>>>                 date.encode('utf-8'),
>>>                 hashlib.sha1
>>>             ).digest()
>>>         )
>>>     )
>>>     return date, auth
>>>
>>>
>>> print get_aws_auth()
('Thu, 22 Oct 2010 06:08:48 GMT', 'AWS 0PN5J17HBGZHT7JJ3X82:4cP0hCJsdCxTJ1jPXo7+e/YSu0g=')
</pre>
<p>We can now use <i>get_aws_auth()</i> to sign the following REST requests. Next, we&#8217;ll create an invalidation request.</p>
<h3>Invalidating CloudFront objects</h3>
<p>The invalidation handler expects a POST request with an xml payload containing a list of file paths to be expired.</p>
<pre class="prettyprint lang-py">>>> import urllib2
>>>
>>>
>>> host = 'cloudfront.amazonaws.com'
>>> path = '/2010-08-01/distribution/%s/invalidation' % AWS_CF_DISTRIBUTION_ID
>>>
>>> # create authentication signature
>>> date, auth = get_aws_auth()
>>>
>>> files = ['/file-01.mp4', '/file-02.mp4', '/file-03.mp4']
>>>
>>> # create xml data to post
>>> data = ['&lt;?xml version="1.0" encoding="UTF-8"?&gt;']
>>> data.append('&lt;InvalidationBatch&gt;')
>>> data.append('%s' % ''.join(['&lt;Path&gt;/%s&lt;/Path&gt;' % f for f in files]))
>>> data.append('&lt;CallerReference&gt;%s&lt;/CallerReference&gt;' % date)
>>> data.append('&lt;/InvalidationBatch&gt;')
>>> data = ''.join(data)
>>>
>>> # define required http headers
>>> headers = {
...     'Host': host,
...     'Authorization' : auth,
...     'Date': date,
...     'Content-Type': 'text/xml',
...     'Content-Length': len(data),
... }
>>>
>>> # make REST request, capture 201 (success) response
>>> request_url = 'https://%s%s' % (host, path)
>>> req = urllib2.Request(request_url, data, headers=headers)
>>> try:
>>>     response = urllib2.urlopen(req)
>>> except urllib2.HTTPError, e:
>>>     print e
HTTP Error 201: Created
</pre>
<p>Of course, you probably also want to check the status of your invalidation request</p>
<h3>Retrieving invalidation request status</h3>
<p>Invalidation requests can take up to 15 minutes. Hit the GET invalidation API to check on the status of your recent requests.</p>
<pre class="prettyprint lang-py">>>> import urllib2
>>> from xml.dom import minidom
>>>
>>>
>>> host = 'cloudfront.amazonaws.com'
>>> path = '/2010-08-01/distribution/%s/invalidation?MaxItems=2' % AWS_CF_DISTRIBUTION_ID
>>>
>>> # create authentication signature
>>> date, auth = get_aws_auth()
>>>
>>> # define required http headers
>>> headers = {
...     'Host': host,
...     'Authorization' : auth,
...     'Date': date,
... }
>>>
>>> # send REST request and print results
>>> request_url = 'https://%s%s' % (host, path)
>>> req = urllib2.Request(request_url, headers=headers)
>>> response = urllib2.urlopen(req)
>>> xml = response.read()
>>> print minidom.parseString(xml).toprettyxml(indent=' '*4)
&lt;?xml version="1.0" ?&gt;
&lt;InvalidationList xmlns="http://cloudfront.amazonaws.com/doc/2010-08-01/"&gt;
    &lt;Marker/&gt;
    &lt;NextMarker&gt;
        I1Z3T4GFYRIAZU
    &lt;/NextMarker&gt;
    &lt;MaxItems&gt;
        2
    &lt;/MaxItems&gt;
    &lt;IsTruncated&gt;
        true
    &lt;/IsTruncated&gt;
    &lt;InvalidationSummary&gt;
        &lt;Id&gt;
            I2HD8ADHMH7R
        &lt;/Id&gt;
        &lt;Status&gt;
            InProgress
        &lt;/Status&gt;
    &lt;/InvalidationSummary&gt;
    &lt;InvalidationSummary&gt;
        &lt;Id&gt;
            IEFHBD78AAQN
        &lt;/Id&gt;
        &lt;Status&gt;
            Completed
        &lt;/Status&gt;
    &lt;/InvalidationSummary&gt;
&lt;/InvalidationList&gt;
</pre>
<h3>The easy way: Use boto</h3>
<p>As of version 2.0b3, the kick-ass <a href="http://code.google.com/p/boto/" title="boto - Python interface to Amazon Web Services">boto</a> library (Python interface to Amazon Web Services) has added support for invalidating CloudFront objects.</p>
<pre class="prettyprint lang-py">>>> import datetime
>>> from boto.cloudfront import CloudFrontConnection
>>>
>>> files = ['/file-01.mp4', '/file-02.mp4', '/file-03.mp4']
>>>
>>> conn = CloudFrontConnection(AWS_ACCESS_KEY, AWS_SECRET_ACCESS_KEY)
>>> print conn.create_invalidation_request(AWS_CF_DISTRIBUTION_ID, files)
&lt;boto.cloudfront.invalidation.InvalidationBatch object at 0x1012b6390&gt;
</pre>
<p>So short and sweet.</p>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2010/10/22/cloudfront-object-invalidation-python/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pretty print xml (and json) in Python</title>
		<link>http://tomatohater.com/2010/10/20/pretty-print-xml-python/</link>
		<comments>http://tomatohater.com/2010/10/20/pretty-print-xml-python/#comments</comments>
		<pubDate>Wed, 20 Oct 2010 15:29:30 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[prettify]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=82</guid>
		<description><![CDATA[Quick Python one-liner to prettify xml (and json too)]]></description>
			<content:encoded><![CDATA[<p>So that I don&#8217;t forget&#8230; again.</p>
<pre class="prettyprint lang-py">>>> from xml.dom import minidom
>>>
>>> # from a string
>>> minidom.parseString(xml_string).toprettyxml(indent=' '*4)
>>>
>>> # or from a file
>>> minidom.parse(open(xml_file)).toprettyxml(indent=' '*4)
</pre>
<p>And for the record&#8230;</p>
<pre class="prettyprint lang-py">>>> import simplejson as json
>>>
>>> json.dumps(json_obj, indent=4)
</pre>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2010/10/20/pretty-print-xml-python/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The NPR Radio by Livio</title>
		<link>http://tomatohater.com/2010/10/07/npr-radio-livio/</link>
		<comments>http://tomatohater.com/2010/10/07/npr-radio-livio/#comments</comments>
		<pubDate>Thu, 07 Oct 2010 15:28:05 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[internet-radio]]></category>
		<category><![CDATA[npr]]></category>
		<category><![CDATA[pbs]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=79</guid>
		<description><![CDATA[What's the verdict?]]></description>
			<content:encoded><![CDATA[<p>I was at Micro Center today and came across this neat looking device called <a href="http://shop.npr.org/products/The_NPR_Radio_by_Livio-906-0.html" title="The NPR Radio by Livio">The NPR Radio</a> by <a href="http://www.livioradio.com/npr_radio/" title="The NPR Radio by Livio">Livio</a>. My first reaction was, &#8220;Wow! This is so cool. You can listen to NPR anytime, anywhere! Why aren&#8217;t we selling The PBS Television yet?&#8221; or something along those lines.</p>
<p>But upon thinking about this for a few moments, it occurred to me that my regular radio already gets NPR, costs less than $199, and it doesn&#8217;t even require an internet connection.</p>
<p><a href="http://www.flickr.com/photos/drewengelson/5061379700/" title="The NPR Radio by tomatohater, on Flickr"><img src="http://farm5.static.flickr.com/4124/5061379700_1e50919590.jpg" width="500" height="374" alt="The NPR Radio" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2010/10/07/npr-radio-livio/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Private repos on BitBucket</title>
		<link>http://tomatohater.com/2010/10/02/private-repos-bitbucket/</link>
		<comments>http://tomatohater.com/2010/10/02/private-repos-bitbucket/#comments</comments>
		<pubDate>Sat, 02 Oct 2010 15:27:00 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[bitbucket]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[hg]]></category>
		<category><![CDATA[version-control]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=76</guid>
		<description><![CDATA[Mercury rising?]]></description>
			<content:encoded><![CDATA[<p>Well now they&#8217;ve done it&#8230; With the <a href="http://blogs.atlassian.com/news/2010/09/weve_gone_into_the_code_hosting_business.html">acquisition of BitBucket</a> by <a href="http://www.atlassian.com/">Atlassian</a>, we can expect <a href="http://www.bitbucket.org/">BitBucket</a> to see tremendous gains in usability and developer support. They now offer unlimited public and private repositories for up to 5 users for free.</p>
<p>Will users flock to Mercurial leaving Git behind? I say, &#8220;Hello hg!&#8221;</p>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2010/10/02/private-repos-bitbucket/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ken Burns: Baseball, continued</title>
		<link>http://tomatohater.com/2010/09/27/ken-burns-baseball-continued/</link>
		<comments>http://tomatohater.com/2010/09/27/ken-burns-baseball-continued/#comments</comments>
		<pubDate>Mon, 27 Sep 2010 15:25:38 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[baseball]]></category>
		<category><![CDATA[ken-burns]]></category>
		<category><![CDATA[pbs]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=73</guid>
		<description><![CDATA[New site launched on <a href="http://www.pbs.org/">PBS.org</a>.]]></description>
			<content:encoded><![CDATA[<table>
<tr>
<td><img style="visibility:hidden;width:0px;height:0px;" border=0 width=0 height=0 src="http://counters.gigya.com/wildfire/IMP/CXNID=2000002.0NXC/bT*xJmx*PTEyODU1OTU5NTg3MDEmcHQ9MTI4NTU5NTk2NzMzOSZwPTEzNzAwNDEmZD*mZz*xJm89Yzc3ZGYzYjc3MDJhNDZjNWI5/ZDMwYjVhNTY2MTA5ZTAmb2Y9MA==.gif" /><a href="http://www.pbs.org/baseball-the-tenth-inning"><img src="http://www-tc.pbs.org/baseball-the-tenth-inning/media/images/widgets/ball.jpg" width="160" height="300" alt="THE TENTH INNING" /></a></td>
<td><img style="visibility:hidden;width:0px;height:0px;" border=0 width=0 height=0 src="http://counters.gigya.com/wildfire/IMP/CXNID=2000002.0NXC/bT*xJmx*PTEyODU1OTYyNTczNjMmcHQ9MTI4NTU5NjI1OTk5NiZwPTEzNzAwNDEmZD*mZz*xJm89Yzc3ZGYzYjc3MDJhNDZjNWI5/ZDMwYjVhNTY2MTA5ZTAmb2Y9MA==.gif" /><a href="http://www.pbs.org/baseball-the-tenth-inning"><img src="http://www-tc.pbs.org/baseball-the-tenth-inning/media/images/widgets/bat.jpg" width="160" height="300" alt="THE TENTH INNING" /></a></td>
<td><img style="visibility:hidden;width:0px;height:0px;" border=0 width=0 height=0 src="http://counters.gigya.com/wildfire/IMP/CXNID=2000002.0NXC/bT*xJmx*PTEyODU1OTYyNjg*MTAmcHQ9MTI4NTU5NjI3MDQ2MiZwPTEzNzAwNDEmZD*mZz*xJm89Yzc3ZGYzYjc3MDJhNDZjNWI5/ZDMwYjVhNTY2MTA5ZTAmb2Y9MA==.gif" /><a href="http://www.pbs.org/baseball-the-tenth-inning/share-your-story/"><img src="http://www-tc.pbs.org/baseball-the-tenth-inning/media/images/widgets/crowd.jpg" width="160" height="300" alt="THE TENTH INNING" /></a></td>
</tr>
</table>
<p>Just launched new site for &#8220;Baseball: The Tenth Inning&#8221; by Ken Burns. Watch it this week on <a href="http://www.pbs.org/">PBS</a>!</p>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2010/09/27/ken-burns-baseball-continued/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Private clouds for developers</title>
		<link>http://tomatohater.com/2010/09/23/private-clouds-developers/</link>
		<comments>http://tomatohater.com/2010/09/23/private-clouds-developers/#comments</comments>
		<pubDate>Thu, 23 Sep 2010 15:24:31 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[amazon-web-services]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[ec2]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=70</guid>
		<description><![CDATA[A viable option?]]></description>
			<content:encoded><![CDATA[<p>At PBS we have been launching most new applications up in <a href="http://aws.amazon.com/ec2/" title="Amazon Elastic Compute Cloud (Amazon EC2)">Amazon&#8217;s cloud platform</a> utilizing EC2 instances, EBS and S3 storage, etc. The flexibility and agility that this Infrastructure as a Service (IaaS) is truly game changing, if not frightening (to IT departments).</p>
<p>The ease with which I am able spin up a server or 30 still gives me the chills even though I&#8217;ve been doing this for years by now. In fact, it is so easy that in addition to launching production applications in the cloud, we&#8217;ve been providing developers each their own dedicated EC2 servers for the applications they are building, modifying, or testing. The benefits of doing so are easy to see:</p>
<ul>
<li>Development environment is <strong>identical in all aspects</strong> to production environment.</li>
<li>Deployment systems (such as Fabric) can be used to push to QA, staging and production servers as easily as to the developers instance.</li>
<li>Instances can be easily cloned if something goes wrong. Made a mistake on configuring the environment? Who cares? Blow it away and start over.</li>
</ul>
<h4>But is it too easy?</h4>
<p>For each active application, we may have a dozen or so developers, each with their own EC2 instance. As more applications and developers come on board, you can foresee how we might end up with multiplicative growth in the number of development servers. Let&#8217;s take 10 developers each working on 3 projects&#8230; that&#8217;s 30 development instances for 3 projects. And that&#8217;s not counting QA, staging or production instances. Since a throw-away development instance costs just as much as a mission critical production instance&#8230; the cost balance feels out of whack to me.</p>
<p>Is there a way to bring down the cost of development instances while maintaining the above-mentioned benefits? What about hosting development servers in a private AWS compatible cloud, such as those fronted by <a href="http://www.eucalyptus.com/" title="Eucalyptus">Eucalyptus</a>? There may be potential here and we are prototyping this out. But I suspect the underlying hardware required to run such a private cloud would be as costly (and less flexible) than using dedicated AWS EC2 instances.</p>
<p>Amazon&#8217;s new <a href="http://aws.amazon.com/about-aws/whats-new/2010/09/09/announcing-micro-instances-for-amazon-ec2/" title="Announcing Micro Instances for Amazon EC2">micro instances</a> should provide some relief. Any other ideas?</p>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2010/09/23/private-clouds-developers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Future of Faetus&#8230;</title>
		<link>http://tomatohater.com/2010/07/21/future-faetus/</link>
		<comments>http://tomatohater.com/2010/07/21/future-faetus/#comments</comments>
		<pubDate>Wed, 21 Jul 2010 15:21:41 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[amazon-web-services]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[faetus]]></category>
		<category><![CDATA[ftp]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[s3]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=67</guid>
		<description><![CDATA[Should my FTP-to-S3 project evolve?]]></description>
			<content:encoded><![CDATA[<p>In my recent post entitled, <a href="http://tomatohater.com/2010/07/15/faetus-v05-released/" title="Faetus v0.5 released!: An FTP interface to Amazon S3 file storage.">Faetus v0.5 released!</a>, I described how and why I built a Python-based FTP server that reads and writes to Amazon S3. This project was born out of necessity because I am using a 3rd-party file management application (which didn&#8217;t understand the S3 API) but needed the files to end up on S3. The system did talk FTP, so I wrote an FTP server that does just that.</p>
<p>As it turns out, the file manager DOES now support the S3 API. Therefore my immediate need for an intermediary FTP interface is gone. While I think it is still a very cool idea, I no longer have an urgent need for it. I will continue to fix some of the major bugs with it, but most of my tinkering will cease. Please let me know if you are interested in using <a href="http://tomatohater.com/faetus/" title="An FTP interface to Amazon S3 file storage.">Faetus</a> and I&#8217;m happy to help you out if I can.</p>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2010/07/21/future-faetus/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Faetus v0.5 released!</title>
		<link>http://tomatohater.com/2010/07/15/faetus-v05-released/</link>
		<comments>http://tomatohater.com/2010/07/15/faetus-v05-released/#comments</comments>
		<pubDate>Thu, 15 Jul 2010 15:20:29 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[amazon-web-services]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[faetus]]></category>
		<category><![CDATA[ftp]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[s3]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=64</guid>
		<description><![CDATA[An FTP interface to Amazon S3 file storage.]]></description>
			<content:encoded><![CDATA[<p><a href="/faetus/">Faetus</a> is an FTP server that translates FTP commands into Amazon S3 API calls providing an FTP interface on top of Amazon S3 storage.</p>
<p>This project came out of a specific need I have at PBS. I need to put files on Amazon S3 storage, but the 3rd-party file management system doesn&#8217;t know how to speak to S3&#8242;s APIs. What the system does understand is FTP. So I decided to write an FTP server that utilizes S3 storage as opposed to local filesystems.</p>
<p>The server is based on <a href="http://code.google.com/p/pyftpdlib/" title="Python FTP server library">pyftpdlib</a>, a Python library that implements most, if not the full RFC spec for. Especially nice is the fact that the the library implements the filesystem layer in an abstract fashion. I basically needed to replace all the filesystem calls with S3 API calls. I used <a href="http://code.google.com/p/boto/" title="Python interface to Amazon Web Services">boto</a> to handle all the S3 API calls and I quickly had a working prototype.</p>
<p>After playing with my prototype for a few hours, I stumbled upon Chmouel&#8217;s <a href="http://blog.chmouel.com/2009/10/29/ftp-server-for-cloud-files/" title="FTP server for Cloud Files">ftp-cloudfs</a>&#8230; who basically did the exact thing I had just done, but for Rackspace CloudFiles. For consistency&#8217;s sake, I rolled my code back, forked ftp-cloudfs, gave the project a questionable new name, and added my S3 code back in. La voila!</p>
<ul>
<li><a href="/faetus/">Faetus</a> project page</li>
<li><a href="http://github.com/tomatohater/faetus">Source code</a> on GitHub</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2010/07/15/faetus-v05-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>GoogleCL is serious life automation</title>
		<link>http://tomatohater.com/2010/06/21/googlecl-serious-life-automation/</link>
		<comments>http://tomatohater.com/2010/06/21/googlecl-serious-life-automation/#comments</comments>
		<pubDate>Mon, 21 Jun 2010 15:19:02 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[command-line]]></category>
		<category><![CDATA[google]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=61</guid>
		<description><![CDATA[Command line tools for the Google Data APIs]]></description>
			<content:encoded><![CDATA[<p>Google released <a href="http://code.google.com/p/googlecl/">GoogleCL</a> last Friday they describe as &#8220;Command line tools for the Google Data APIs&#8221;. I took a few minutes to play with it today and an awed by the possibilities it opens up. Yes, APIs have existed for all these services, so in theory, it&#8217;s nothing new&#8230; But really, who wants to write command-line wrappers for the APIs, or manage all the different 3rd party packages for doing so.</p>
<p>It&#8217;s basically a bunch of Python scripts that are all imported into one executable file called &#8220;google&#8221;. All the API calls are full abstracted allowing you do run commands like:</p>
<pre>
$ google contact list
$ google calendar add "Get up at 5:30am Thursday"
</pre>
</p>
<p>GoogleCL currently supports Blogger, Calendar, Contacts, Docs, Picasa, YouTube&#8230; though I&#8217;m sure others will be added shortly.</p>
<p>Installing is pretty much a piece of cake. All you really need is a modern version of the gdata library (mine was outdated) and the googlecl package itself.</p>
<pre>
$ pip install gdata googlecl
$ pip install
</pre>
</p>
<p>I see some serious life automation happening in the near future.</p>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2010/06/21/googlecl-serious-life-automation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>django-openlike v0.1</title>
		<link>http://tomatohater.com/2010/05/20/django-openlike-v01/</link>
		<comments>http://tomatohater.com/2010/05/20/django-openlike-v01/#comments</comments>
		<pubDate>Thu, 20 May 2010 15:17:26 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[bookmarking]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[open-source]]></category>
		<category><![CDATA[openlike]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[social-networking]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=58</guid>
		<description><![CDATA[A Django template tag for easily implementing and extending <a href="http://www.openlike.org" title="OpenLike is a protocol for sharing the things you like on the web.">OpenLike</a> protocol.]]></description>
			<content:encoded><![CDATA[<p>
    Source code available at GitHub:<br />
    <a href="http://github.com/tomatohater/django-openlike">http://github.com/tomatohater/django-openlike</a>
</p>
<h3>Release notes (v0.1):</h3>
<pre>
# django-openlike

Django template tag for easily implementing and extending OpenLike protocol.
See http://www.openlike.org/ for more info.

FEATURES:
- Templatetags for displaying OpenLike widget

USAGE:
- Basic: {% openlike %}
- Less basic: {% openlike "http://domain.com/&quot; "Page title" %}

TODO:
- Documentation.
- Add support for extended sources.
- Configuration via Django admin

AUTHOR'S NOTE:
This app is most definitely overkill given the simplicy of OpenLike and the
ease of pure JavaScript implementation. But it was a fun project to fully
support a third-party service in Django.
</pre>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2010/05/20/django-openlike-v01/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>My slides from RightScale MeetUp 2010</title>
		<link>http://tomatohater.com/2010/05/19/my-slides-rightscale-meetup-2010/</link>
		<comments>http://tomatohater.com/2010/05/19/my-slides-rightscale-meetup-2010/#comments</comments>
		<pubDate>Wed, 19 May 2010 15:15:21 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[amazon-web-services]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[pbs]]></category>
		<category><![CDATA[rightscale]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=55</guid>
		<description><![CDATA[Last month, I presented on how PBS utilizes RightScale to manage our servers in the Amazon Cloud.]]></description>
			<content:encoded><![CDATA[<p><object id="__sse4085796" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=rightscale-meetup-2010-pbs-final-100513110258-phpapp01&#038;stripped_title=pbs-rightscale-user-meetup-2010" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse4085796" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=rightscale-meetup-2010-pbs-final-100513110258-phpapp01&#038;stripped_title=pbs-rightscale-user-meetup-2010" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object></p>
<p>This is my deck from <a href="http://www.rightscale.com/lp/user-meetup.php" title="RightScale User Meetup 2010">RightScale MeetUp 2010</a> before it was incorporated into RightScale&#8217;s template. The <a href="http://www.rightscale.com/lp/downloads/RightScale-User-Meetup-2010.pdf" title="RightScale User Meetup 2010">full MeetUp presentation</a> is up on RightScale&#8217;s website.</p>
<p>At the MeetUp, I met a ton of really smart people with interesting problems to solve&#8230; many with the same problems I&#8217;m working on as well.</p>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2010/05/19/my-slides-rightscale-meetup-2010/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Talking points: Django v. Drupal</title>
		<link>http://tomatohater.com/2010/05/13/talking-points-django-v-drupal/</link>
		<comments>http://tomatohater.com/2010/05/13/talking-points-django-v-drupal/#comments</comments>
		<pubDate>Thu, 13 May 2010 15:13:20 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[drupal]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=52</guid>
		<description><![CDATA[Why you should use Django instead of Drupal.]]></description>
			<content:encoded><![CDATA[<p>At <a href="http://www.pbs.org/">PBS</a>, I frequently find myself with a proposal to build a web application with Drupal. We&#8217;re primarily a <a href="http://www.djangoproject.com/">Django</a> shop, so you can imagine my bias against Drupal. Yet these proposals continue and I routinely find myself pushing Django instead.</p>
<p>To date, we have attempted exactly four Drupal sites at PBS. Three of them eventually made it to production. All three experienced significant delivery, quality assurance and/or scalability problems. These apps were built by experienced development shops, even some who had proven track records and delivered exceptional (non-Drupal) applications in the past.</p>
<p>I am sure that it is possible to build a solid, highly scalable Drupal application. There are many examples out in the world. So what&#8217;s the deal?</p>
<p>In a recent post, <a href="http://nicksergeant.com/2010/drupal-v-django/">Drupal v. Django</a>, Nick Sergeant provides some excellent talking points on the matter. I agree with every one of his points. Some of my favorites are echoed below:</p>
<blockquote>
<ul>
<li>Django is a lower level development framework (than Drupal) that encourages rapid development and cleanly written &#038; organized code.</li>
<li>With Django, we’re able to construct custom functionality at a more rapid pace than Drupal.</li>
<li>Drupal funnels data into chunks of content referred to as “nodes”, which developers must often force their content into. The content should define the data structure, not the other way around.</li>
<li>Because Drupal stores so much configuration and definitions of functionality in the database, it becomes incredibly difficult to version control the software.</li>
<li>Drupal’s default admin interface is riddled with UI and workflow problems (one of the primary focuses of the upcoming Drupal 7 release).</li>
<li>Django’s default admin interface is designed to encourage quick and easy content management, and allows developers to quickly design custom admin interfaces and workflows.</li>
</ul>
</blockquote>
<p>I don&#8217;t mean to add fuel the Django versus Drupal fires, so let&#8217;s just rename this post to &#8220;Why you shouldn&#8217;t introduce Drupal into a Django-centric environment.&#8221; I&#8217;m just looking to add some sanity to my life.</p>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2010/05/13/talking-points-django-v-drupal/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tomatohater.com is Mingus-ified!</title>
		<link>http://tomatohater.com/2010/05/11/tomatohater-mingus-ified/</link>
		<comments>http://tomatohater.com/2010/05/11/tomatohater-mingus-ified/#comments</comments>
		<pubDate>Tue, 11 May 2010 15:12:01 +0000</pubDate>
		<dc:creator>tomatohater</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[blogware]]></category>
		<category><![CDATA[django django-mingus]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://localhost/~drewengelson/tomatohater/?p=49</guid>
		<description><![CDATA[I just finished migrating this blog from vanilla <a href="http://nathanborror.com/posts/2007/dec/2/django-basic-apps/">django-basic-blog</a> to <a href="http://github.com/montylounge/django-mingus">django-mingus</a>.]]></description>
			<content:encoded><![CDATA[<p>While django-basic-blog is perfectly sufficient to power this site, I was interested in testing how <a href="http://blog.montylounge.com/2010/02/7/mingus-09-released/">Monty Lounge</a> extended it. You see, django-mingus isn&#8217;t really an application itself; there&#8217;s really not much code involved. It is more like a recipe for combining a number of existing reusable Django applications that make up a solid blogging platform. The article <a href="http://blog.montylounge.com/2009/sep/24/apps-that-power-django-mingus/">The apps that power Django-Mingus</a> describes the 28 apps that have been nicely imaplemented into a single project.</p>
<p>My experience setting my Django-mingus blog was ridiculously simple. My only issues were related to the pip install script&#8230;</p>
<ol>
<li>BitBucket was down tonight&#8230;</li>
<li>One updated dependency had had trouble finding the version specified &#8230;</li>
<li>One dependency was broken</li>
<li>I had to change it to use git+http:// since my web host blocked traffic on the git:// port</li>
</ol>
<p>Other than that, I didn&#8217;t have to do much customization. I treated my site design just like a new Mingus theme and attempted to make all my changes in CSS. I did have to rearrange some of the HTML to support my layout. I then did a bunch of clean-up in the Django templates to get consistent page titles and page themes.</p>
<p>I&#8217;m only using a few of the apps included with Mingus&#8230; I&#8217;ll be digging into the rest to see whether I&#8217;m missing out.</p>
]]></content:encoded>
			<wfw:commentRss>http://tomatohater.com/2010/05/11/tomatohater-mingus-ified/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

