Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
1049 lines (725 sloc) 105 KB
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Tomaz Muraus' personal blog</title>
<subtitle>computers, programming, startups and life.</subtitle>
<link href="https://www.tomaz.me" rel="self" />
<link href="https://www.tomaz.me" />
<id>https://www.tomaz.me</id>
<updated>2015-09-05T15:57:52+02:00</updated>
<author>
<name>Tomaz Muraus</name>
<email>tomaz@tomaz.me</email>
</author>
<entry>
<title>Libcloud now supports OpenStack Identity (Keystone) API v3</title>
<link href="https://www.tomaz.me/2014/08/23/libcloud-now-supports-openstack-identity-keystone-api-v3.html" />
<id>https://www.tomaz.me/2014/08/23/libcloud-now-supports-openstack-identity-keystone-api-v3.html</id>
<updated>2014-08-23T00:00:00+02:00</updated>
<author>
<name>Tomaz Muraus</name>
</author>
<content type="html">&lt;h2 id=&quot;libcloud_now_supports_openstack_identity_keystone_api_v3&quot;&gt;&lt;a href=&quot;/2014/08/23/libcloud-now-supports-openstack-identity-keystone-api-v3.html&quot;&gt;Libcloud now supports OpenStack Identity (Keystone) API v3&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have recently pushed support for &lt;a href=&quot;http://developer.openstack.org/api-ref-identity-v3.html&quot;&gt;OpenStack Identity API v3&lt;/a&gt; to Libcloud trunk. In this blog post I’m going to have a look at the motivation for that, changes which were involved and show some examples of how you can utilize those changes and newly available features.&lt;/p&gt;
&lt;h3 id=&quot;what_is_openstack_keystone__identity_service&quot;&gt;What is OpenStack Keystone / Identity service?&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://docs.openstack.org/developer/keystone/&quot;&gt;OpenStack Keystone&lt;/a&gt; is an OpenStack project that provides identity and authentication related features to OpenStack projects such as Nova.&lt;/p&gt;
&lt;p&gt;The project started as a simple service which only provided basic authentication features, but it has since grown into a fully fledged and powerful identity management service.&lt;/p&gt;
&lt;p&gt;The latest version supports advanced user management, multiple projects, complex ACLs and more.&lt;/p&gt;
&lt;p&gt;Future release will also include a &lt;a href=&quot;https://github.com/openstack/keystone-specs/blob/master/specs/juno/keystone-to-keystone-federation.rst&quot;&gt;Keystone to Keystone federation&lt;/a&gt; feature which will makes things such as a seamless cross-cloud authorizations possible.&lt;/p&gt;
&lt;h3 id=&quot;motivation&quot;&gt;Motivation&lt;/h3&gt;
&lt;p&gt;Support for OpenStack Nova was first added to Libcloud back in 2011. First version only included support for a simple token based authentication.&lt;/p&gt;
&lt;p&gt;Since then a lot has changed and new (and more flexible) OpenStack Keystone versions have been released. We have been pretty good at following those changes and support for authenticating against Keystone API v2.0 has been available in Libcloud for a long time.&lt;/p&gt;
&lt;p&gt;Those changes worked fine, but the problem was that not much thinking went into them and support for multiple Keystone versions was added after the fact. This means that the code was hacky, inflexible, hard to re-use and extend.&lt;/p&gt;
&lt;p&gt;Luckily, those things were (mostly) hidden from the end user who just wanted to connect to the OpenStack installation. They only became apparent if you wanted to talk directly to the Keystone service or do anything more complex with it.&lt;/p&gt;
&lt;p&gt;For one of the features we are working on at &lt;a href=&quot;http://www.divvycloud.com/&quot;&gt;DivvyCloud&lt;/a&gt;, we needed support authenticating and talking to OpenStack Keystone API v3. Since Libcloud didn’t include support for this version yet, I decide to go ahead and add it.&lt;/p&gt;
&lt;p&gt;All of the “hackiness” of the existing code also became very apparent when I wanted to add support for API v3. Because of that, I have decided to spend more time on it, do it “the right way” and refactor the existing code to make it more re-usable, extensible and maintainable.&lt;/p&gt;
&lt;h3 id=&quot;refactoring_the_existing_code&quot;&gt;Refactoring the existing code&lt;/h3&gt;
&lt;p&gt;Before my changes, all of the logic for talking to Keystone, handling of the token expiration, re-authentication, etc. was contained in a single class (&lt;code&gt;OpenStackAuthConnection&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;To authenticate, there was one method per Keystone API version (&lt;code&gt;authenticate_1_0&lt;/code&gt;, &lt;code&gt;authenticate_1_1&lt;/code&gt;, &lt;code&gt;authenticate_2_0_with_apikey&lt;/code&gt;, &lt;code&gt;authenticate_2_0_with_password&lt;/code&gt;). This means there was a lot of duplicated code, the code was hard to extend, etc.&lt;/p&gt;
&lt;p&gt;I went ahead and moved to a “base class with common functionality” + “one class per Keystone API version” model. This approach has multiple advantages over the old one:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the code is easier to re-use, maintain and extend&lt;/li&gt;
&lt;li&gt;version specific functionality is available via methods on the version specific class&lt;/li&gt;
&lt;li&gt;less coupling&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some other notable changes are described bellow.&lt;/p&gt;
&lt;h3 id=&quot;identity_related_code_has_been_moved_to_a_separate_independent_module&quot;&gt;Identity related code has been moved to a separate (independent) module&lt;/h3&gt;
&lt;p&gt;All of the identity related code has been moved from &lt;code&gt;libcloud.common.openstack&lt;/code&gt; to a new &lt;code&gt;libcloud.common.openstack_identity&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;This module reduces coupling between general OpenStack and Identity related code and makes code re-use and other things easier.&lt;/p&gt;
&lt;h3 id=&quot;improvements_in_the_service_catalog_related_code&quot;&gt;Improvements in the service catalog related code&lt;/h3&gt;
&lt;p&gt;Before my changes, parsed service catalog entries were stored in an unstructured dictionary on the &lt;code&gt;OpenStackServiceCatalog&lt;/code&gt; class. To make things even worse, the structure and the contents of the dictionary differed based on the Keystone API version.&lt;/p&gt;
&lt;p&gt;Dynamic nature of Python can be a huge asset and can make development and prototyping faster and easier. The problem is that when it’s abused / overused it makes code hard to use, maintain and reason about. Sadly, that’s pretty common in the Python world and many times, people tend to over-use dictionaries and base their APIs around passing around unstructured dictionaries.&lt;/p&gt;
&lt;p&gt;I refactored the code to store service catalog entries in a structured format (a list of &lt;code&gt;OpenStackServiceCatalogEntry&lt;/code&gt; and &lt;code&gt;OpenStackServiceCatalogEntryEndpoint&lt;/code&gt; objects).&lt;/p&gt;
&lt;p&gt;Now only the code which parses service catalog responses needs to know about the response structure. The user itself doesn’t need to know anything about the internal structure and the code for retrieving entries from the service catalog is API version agnostic.&lt;/p&gt;
&lt;h3 id=&quot;addition_of_the_administrative_related_functionality&quot;&gt;Addition of the administrative related functionality&lt;/h3&gt;
&lt;p&gt;In addition to the changes mentioned above, &lt;code&gt;OpenStackIdentity_3_0_Connection&lt;/code&gt; class now also contains methods for performing different administrative related tasks such as user, role, domain and project management.&lt;/p&gt;
&lt;h3 id=&quot;examples&quot;&gt;Examples&lt;/h3&gt;
&lt;p&gt;This section includes some examples which show how to use the newly available functionality. For more information, please refer to the docstrings in the &lt;a href=&quot;https://github.com/apache/libcloud/blob/trunk/libcloud/common/openstack_identity.py&quot;&gt;openstack_identity&lt;/a&gt; module.&lt;/p&gt;
&lt;h3 id=&quot;authenticating_against_keystone_api_v3_using_the_openstack_compute_driver&quot;&gt;Authenticating against Keystone API v3 using the OpenStack compute driver&lt;/h3&gt;
&lt;p&gt;This example shows how to authenticate against Keystone API v3 using the OpenStack compute driver (for the time being, default auth version used by the compute driver is 2.0).&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;pprint&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;pprint&lt;/span&gt;
&lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;libcloud.compute.types&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;Provider&lt;/span&gt;
&lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;libcloud.compute.providers&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;get_driver&lt;/span&gt;
&lt;span class='n'&gt;cls&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;get_driver&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;Provider&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;OPENSTACK&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;driver&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;cls&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;&amp;lt;username&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;&amp;lt;password&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
&lt;span class='n'&gt;ex_force_auth_version&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;3.x_password&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
&lt;span class='n'&gt;ex_force_auth_url&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;http://192.168.1.100:5000&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
&lt;span class='n'&gt;ex_force_service_type&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;compute&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
&lt;span class='n'&gt;ex_force_service_region&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;regionOne&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
&lt;span class='n'&gt;ex_tenant_name&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;&amp;lt;my tenant&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;pprint&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;driver&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_nodes&lt;/span&gt;&lt;span class='p'&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;obtaining_auth_token_scoped_to_the_domain&quot;&gt;Obtaining auth token scoped to the domain&lt;/h3&gt;
&lt;p&gt;This example show how to obtain a token which is scoped to a domain and not to a project / tenant which is a default.&lt;/p&gt;
&lt;p&gt;Keep in mind that most of the OpenStack services don’t yet support tokens which are scoped to a domain, so such tokens are of a limited use right now.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;pprint&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;pprint&lt;/span&gt;
&lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;libcloud.common.openstack_identity&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;OpenStackIdentity_3_0_Connection&lt;/span&gt;
&lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;libcloud.common.openstack_identity&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;OpenStackIdentityTokenScope&lt;/span&gt;
&lt;span class='n'&gt;driver&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;OpenStackIdentity_3_0_Connection&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;auth_url&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;http://&amp;lt;host&amp;gt;:&amp;lt;port&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
&lt;span class='n'&gt;user_id&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
&lt;span class='n'&gt;key&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;&amp;lt;key&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
&lt;span class='n'&gt;token_scope&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='n'&gt;OpenStackIdentityTokenScope&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;DOMAIN&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
&lt;span class='n'&gt;domain_name&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;Default&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
&lt;span class='n'&gt;tenant_name&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;driver&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;authenticate&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;span class='n'&gt;pprint&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;driver&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;auth_token&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;talking_directly_to_the_openstack_keystone_api_v3&quot;&gt;Talking directly to the OpenStack Keystone API v3&lt;/h3&gt;
&lt;p&gt;This example shows how to talk directly to OpenStack Keystone API v3 and perform administrative tasks such as listing users and roles.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;pprint&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;pprint&lt;/span&gt;
&lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;libcloud.common.openstack_identity&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;OpenStackIdentity_3_0_Connection&lt;/span&gt;
&lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;libcloud.common.openstack_identity&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;OpenStackIdentityTokenScope&lt;/span&gt;
&lt;span class='n'&gt;driver&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;OpenStackIdentity_3_0_Connection&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;auth_url&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;http://&amp;lt;host&amp;gt;:&amp;lt;port&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
&lt;span class='n'&gt;user_id&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
&lt;span class='n'&gt;key&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;&amp;lt;key&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
&lt;span class='n'&gt;token_scope&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='n'&gt;OpenStackIdentityTokenScope&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;PROJECT&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
&lt;span class='n'&gt;tenant_name&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='c'&gt;# This call doesn&amp;#39;t require authentication&lt;/span&gt;
&lt;span class='n'&gt;pprint&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;driver&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_supported_versions&lt;/span&gt;&lt;span class='p'&gt;())&lt;/span&gt;
&lt;span class='c'&gt;# The calls bellow require authentication and admin access&lt;/span&gt;
&lt;span class='c'&gt;# (depends on the ACL configuration)&lt;/span&gt;
&lt;span class='n'&gt;driver&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;authenticate&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;span class='n'&gt;users&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;driver&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_users&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;span class='n'&gt;roles&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;driver&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_roles&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;span class='n'&gt;pprint&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;users&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;pprint&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;roles&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;a_quick_note_on_backward_compatibility&quot;&gt;A quick note on backward compatibility&lt;/h3&gt;
&lt;p&gt;If you only use OpenStack compute driver, those changes are fully backward compatible and you aren’t affected.&lt;/p&gt;
&lt;p&gt;If you use &lt;code&gt;OpenStackAuthConnection&lt;/code&gt; class to talk directly to the Keystone installation, you need to update your code to either use the new &lt;code&gt;OpenStackIdentityConnection&lt;/code&gt; class or a version specific class since &lt;code&gt;OpenStackAuthConnection&lt;/code&gt; class has been removed.&lt;/p&gt;</content>
</entry>
<entry>
<title>Libcloud at ApacheCon NA, 2014 in Denver, Colorado</title>
<link href="https://www.tomaz.me/2014/03/07/libcloud-at-apachecon-na-2014.html" />
<id>https://www.tomaz.me/2014/03/07/libcloud-at-apachecon-na-2014.html</id>
<updated>2014-03-07T00:00:00+01:00</updated>
<author>
<name>Tomaz Muraus</name>
</author>
<content type="html">&lt;h2 id=&quot;libcloud_at_apachecon_na_2014_in_denver_colorado&quot;&gt;&lt;a href=&quot;/2014/03/07/libcloud-at-apachecon-na-2014.html&quot;&gt;Libcloud at ApacheCon NA, 2014 in Denver, Colorado&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is just a quick heads up that I will be attending &lt;a href=&quot;http://events.linuxfoundation.org/events/apachecon-north-america&quot;&gt;ApacheCon North America, 2014&lt;/a&gt; in Denver, Colorado next month.&lt;/p&gt;
&lt;p&gt;I will be giving two talks. First one is titled &lt;a href=&quot;http://events.linuxfoundation.org/events/apachecon-north-america&quot;&gt;5 years of Libcloud&lt;/a&gt;. This is retrospective talk where I will tell a story of how Libcloud grew from a small project originally developed for the needs of &lt;a href=&quot;https://en.wikipedia.org/wiki/Cloudkick&quot;&gt;Cloudkick&lt;/a&gt; product into a fully fledged and relatively popular Apache project.&lt;/p&gt;
&lt;div class='imginline'&gt;
&lt;a href='http://events.linuxfoundation.org/events/apachecon-north-america' target='_blank'&gt;
&lt;img class='inline' src='/images/apachecon_denver_2014.png' /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;I will go into details on some of the challenges we faced, what we learned from them and how we grew the community and the project.&lt;/p&gt;
&lt;p&gt;Second one is titled &lt;a href=&quot;http://apacheconnorthamerica2014.sched.org/event/3dd818c4a382e5c32aee514f024b2e4e&quot;&gt;Reducing barriers to contribution to an Apache project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To give you some context, I first need to say that I’m a person who loves to move fast and loves lean and efficient approaches and teams. On top of that, I also have zero tolerance for unnecessary / useless processes and deep and mostly useless hierarchies.&lt;/p&gt;
&lt;p&gt;All of that means I don’t see myself a big company person, where having useless processes, which among many other things, slow innovation down is usually the norm.&lt;/p&gt;
&lt;p&gt;Apache is a relatively big organization which means it has it’s own fair share of (useless) proceses. A lot of “new era” developers who grew up with Github also consider Apache as slow, inflexible and place where projects go to die&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;In this talk I will go into details why this is not totally true and how Apache is (slowly) becoming more flexible and changing to adopt those new work-flows.&lt;/p&gt;
&lt;p&gt;On top of that, I will also give some examples on how you can adopt those new work-flows, iterate fast and still receive all the benefits from being an Apache project. Those examples will be taken directly from the things we have learned at the &lt;a href=&quot;https://libcloud.apache.org/&quot;&gt;Apache Libcloud&lt;/a&gt; project.&lt;/p&gt;
&lt;p&gt;Depending on how many people will attend the talk, I think it would also be very interesting to turn this into a panel where other people can contribute their ideas and we can discuss how to reduce barriers even further and make Apache more attractive for “new-era projects”.&lt;/p&gt;
&lt;p&gt;Besides my talks, &lt;a href=&quot;https://twitter.com/sebgoa&quot;&gt;Sebastien Goasguen&lt;/a&gt;, a long time contributor to the project who has &lt;a href=&quot;https://libcloud.apache.org/blog/2014/02/17/sebastien-goasguen-joins-our-team.html&quot;&gt;recently joined the PMC&lt;/a&gt; is also giving a talk titled &lt;a href=&quot;http://apacheconnorthamerica2014.sched.org/event/d6f5edb63d65ca64923450993cb6c223&quot;&gt;Apache Libcloud&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you are around, you should stop by to listen to those talks and contribute your ideas to my second talk.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;&lt;hr /&gt;&lt;ol&gt;&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;Citation needed. I’m kinda lazy and tired atm, but you can Google it up. &lt;a href=&quot;#fnref:1&quot; rev=&quot;footnote&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</content>
</entry>
<entry>
<title>Libcloud Google Summer of Code 2014 Call for Participation</title>
<link href="https://www.tomaz.me/2014/02/11/libcloud-gsoc-cfp.html" />
<id>https://www.tomaz.me/2014/02/11/libcloud-gsoc-cfp.html</id>
<updated>2014-02-11T00:00:00+01:00</updated>
<author>
<name>Tomaz Muraus</name>
</author>
<content type="html">&lt;h2 id=&quot;libcloud_google_summer_of_code_2014_call_for_participation&quot;&gt;&lt;a href=&quot;/2014/02/11/libcloud-gsoc-cfp.html&quot;&gt;Libcloud Google Summer of Code 2014 Call for Participation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is call for participation / proposals for all the students who are interested in working on &lt;a href=&quot;https://libcloud.apache.org&quot;&gt;Apache Libcloud&lt;/a&gt; project during the &lt;a href=&quot;http://google-melange.appspot.com/gsoc/homepage/google/gsoc2014&quot;&gt;Google Summer of Code 2014 program&lt;/a&gt;.&lt;/p&gt;
&lt;div class='imginline'&gt;
&lt;a href='http://libcloud.apache.org' target='_blank'&gt;
&lt;img class='inline' src='/images/2013-12-11-libcloud-update-key-pair-management-methods-are-now-part-of-the-base-api/libcloud.png' /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;Before diving further, I just want to give a short disclaimer. We (Apache Software Foundation and Libcloud as a project) haven’t been accepted into Google Summer of Code 2014 yet, but we will apply, cross our fingers and hope we get a spot.&lt;/p&gt;
&lt;p&gt;We will know if we have been accepted on February 24th when Google publishes a list of the accepted mentoring organizations.&lt;/p&gt;
&lt;h3 id=&quot;what_is_google_summer_of_code&quot;&gt;What is Google Summer of Code?&lt;/h3&gt;
&lt;div class='imginline'&gt;
&lt;a href='http://google-melange.appspot.com/gsoc/homepage/google/gsoc2014' target='_blank'&gt;
&lt;img class='inline' src='/images/2014-02-11-libcloud-gsoc-cfp/gsoc2014.jpg' /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;http://google-melange.appspot.com/gsoc/homepage/google/gsoc2014&quot;&gt;Google Summer of Code&lt;/a&gt; is a program where Google sponsors students from around the world to spend their summer working on open-source projects. Student is paid 5500$ if they successfully complete all of their evaluations. More information about the program can be found on the &lt;a href=&quot;http://google-melange.appspot.com/gsoc/homepage/google/gsoc2014&quot;&gt;project website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This year is also special, because it’s a tenth anniversary of the program. To celebrate the anniversary, Google is, among other things, giving out 5500$ for successfully completed projects instead of the usual 5000$.&lt;/p&gt;
&lt;h3 id=&quot;google_summer_of_code_and_libcloud&quot;&gt;Google Summer of Code and Libcloud&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.apache.org/&quot;&gt;Apache Software Foundation&lt;/a&gt; is not a stranger to Google Summer of Code since it has already participated in this program &lt;a href=&quot;https://community.apache.org/mentoring/mentoring/experiences.html&quot;&gt;multiple times over the past years&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We (as in Libcloud project) have also participated in GSoC 2014 with one project. I have mentored a student Ilgiz Islamgulov from Russia who has worked and successfully completed (yeah, software is never really done, but in this case completed refers to him passing all the GSoC evaluations) a project called &lt;a href=&quot;https://github.com/islamgulov/libcloud.rest&quot;&gt;Libcloud REST interface&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to know more about his project and our GSoC 2012 participation, you should check the following links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://libcloud.apache.org/gsoc-2012.html&quot;&gt;Libcloud GSoC 2013 page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/islamgulov/libcloud.rest&quot;&gt;Github repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/document/d/1P9fIxILn-WdgpkXDPydHB_dghGs-BYuoSmkFwh0Y36w&quot;&gt;Strategic plan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://islamgulov.blogspot.com/2012/08/gsoc-experience.html&quot;&gt;Ilgiz’s post about his GSoC experience&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;why_should_i_participate__what_do_i_get_out_of_participating_in_gsoc&quot;&gt;Why should I participate / What do I get out of participating in GSoC?&lt;/h3&gt;
&lt;p&gt;Before looking at our call for proposals, let’s have a look at why you might want to participate in Google Summer of Code program.&lt;/p&gt;
&lt;p&gt;For a moment, lets forget about the money and have a look at a couple of other reasons why participating in GSoC is great for you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Instead of spending your summer flipping burgers (or similar) you can spend summer flipping bits (fun!)&lt;/li&gt;
&lt;li&gt;You will learn how open source projects and communities work&lt;/li&gt;
&lt;li&gt;You will get experience with working in distributed / remote teams&lt;/li&gt;
&lt;li&gt;You will get experience with working across different timezones&lt;/li&gt;
&lt;li&gt;You will make new friends in the open source community&lt;/li&gt;
&lt;li&gt;It’s a great thing for your C.V. You will be able to show potential employers some concrete things you have worked on.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;libcloud_google_summer_of_code_2014_call_for_proposals&quot;&gt;Libcloud Google Summer of Code 2014 Call For Proposals&lt;/h3&gt;
&lt;p&gt;This is the part where you, dear students come in. We would like to invite all the students who are interested in participating to start thinking about the things they could work on and start reaching out to the community.&lt;/p&gt;
&lt;p&gt;It doesn’t matter if you are already using or contributing to the project or not, everyone is welcome (people who have or are already contributing to the project have a slight advantage though since we already know what they are capable of)!&lt;/p&gt;
&lt;p&gt;Only pre-requisite is a good knowledge of Python, HTTP, REST APIs and a basic familiarity with different cloud services such as Amazon EC2 and others.&lt;/p&gt;
&lt;p&gt;As noted in the opening paragraph, we haven’t been accepted yet and the student applications will open in about a month. The reason I’m already posting this is because we want to give potential candidates plenty of time to get familiar with the project and the community.&lt;/p&gt;
&lt;p&gt;If you would like to participate, now is the right time to start &lt;a href=&quot;http://s.apache.org/lcgsoc2014&quot;&gt;exploring the existing ideas&lt;/a&gt; (you are also more than welcome to propose your own ideas), start thinking about the things you could work, getting familiar with the code base and start reaching out to the community.&lt;/p&gt;
&lt;p&gt;Other links you might find useful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://google-melange.appspot.com/gsoc/homepage/google/gsoc2014&quot;&gt;Official GSoC 2014 page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://en.flossmanuals.net/GSoCStudentGuide/&quot;&gt;GSoC student guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://libcloud.apache.org/gsoc-2012.html&quot;&gt;Libcloud GSoC 2012 page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://libcloud.apache.org/gsoc-2014.html&quot;&gt;Libcloud GSoC 2014 page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://s.apache.org/lcgsoc2014&quot;&gt;Libcloud GSoC project ideas&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
</entry>
<entry>
<title>New Libcloud website is now live</title>
<link href="https://www.tomaz.me/2014/01/26/new-libcloud-website-is-now-live.html" />
<id>https://www.tomaz.me/2014/01/26/new-libcloud-website-is-now-live.html</id>
<updated>2014-01-26T00:00:00+01:00</updated>
<author>
<name>Tomaz Muraus</name>
</author>
<content type="html">&lt;h2 id=&quot;new_libcloud_website_is_now_live&quot;&gt;&lt;a href=&quot;/2014/01/26/new-libcloud-website-is-now-live.html&quot;&gt;New Libcloud website is now live&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’m happy to announce that a new Libcloud website is now live at &lt;a href=&quot;https://libcloud.apache.org&quot;&gt;libcloud.apache.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Design and layout wise, previous website hasn’t really changed since 2009 so a makeover was long overdue.&lt;/p&gt;
&lt;div class='imginline'&gt;
&lt;a href='https://libcloud.apache.org' target='_blank'&gt;
&lt;img class='inline' src='/images/2014-01-26-new-libcloud-website-is-now-live/libcloud_website.png' /&gt;
&lt;/a&gt;
&lt;span class='image-caption'&gt;New website.&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;The new website includes many new features and improvements. One of the more important ones is a new and fully responsive design which means that the content can now also more easily be consumed on devices with smaller resolutions such as mobile phones and tablets.&lt;/p&gt;
&lt;p&gt;On top of that the new website is now powered by Jekyll (same as my blog) which makes adding content and many other things easier.&lt;/p&gt;
&lt;p&gt;Without further ado, I encourage you to go &lt;a href=&quot;https://libcloud.apache.org&quot;&gt;check out the new website&lt;/a&gt; and read the &lt;a href=&quot;https://libcloud.apache.org/blog/2014/01/23/welcome-to-the-new-website.html&quot;&gt;announcement blog post&lt;/a&gt;.&lt;/p&gt;</content>
</entry>
<entry>
<title>Say hello to Živa</title>
<link href="https://www.tomaz.me/2014/01/24/say-hello-to-ziva.html" />
<id>https://www.tomaz.me/2014/01/24/say-hello-to-ziva.html</id>
<updated>2014-01-24T00:00:00+01:00</updated>
<author>
<name>Tomaz Muraus</name>
</author>
<content type="html">&lt;h2 id=&quot;say_hello_to_iva&quot;&gt;&lt;a href=&quot;/2014/01/24/say-hello-to-ziva.html&quot;&gt;Say hello to Živa&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This week I made a big decision. I finally decided to get a dog. In this blog post I’m going to introduce you to my new 24kg / 52 lbs heavy fluffy meatball friend called Živa.&lt;/p&gt;
&lt;div class='imginline'&gt;
&lt;a class='fancybox' href='/images/2014-01-24-say-hello-to-ziva/IMG_20140120_125424.jpg' rel='dog'&gt;
&lt;img class='inline' src='/images/2014-01-24-say-hello-to-ziva/IMG_20140120_125424_thumb.jpg' /&gt;
&lt;/a&gt;
&lt;span class='image-caption'&gt;Živa on the way to her new home.&lt;/span&gt;
&lt;/div&gt;
&lt;h3 id=&quot;why_get_a_dog_in_the_first_place&quot;&gt;Why get a dog in the first place?&lt;/h3&gt;
&lt;p&gt;First I need to say that I do like cats, but I was always more of a dog person. I always wanted my own dog, but haven’t really had a chance before.&lt;/p&gt;
&lt;p&gt;When I still lived at my parents place, I couldn’t do it because we lived in an apartment and my parents didn’t allow it.&lt;/p&gt;
&lt;p&gt;Later on when I moved to the US I was thinking of getting a dog again, but after some more thought I decided it would be irresponsible for me to do it. I did have a nice apartment with a patio, but the problem is that dogs need a lot of attention and I wasn’t really planning in staying in the US for the long term. I was working a lot and leaving the dog at home by itself for a half day or more just seems irresponsible to me.&lt;/p&gt;
&lt;p&gt;On top of that, finding an apartment and landlord in San Francisco which allows larger dogs is quite hard and makes moving very painful.&lt;/p&gt;
&lt;p&gt;Another opportunity showed itself again recently when I moved back to Slovenia. I decided that I want to stay in Europe for the foreseeable future and work from home. On top of that, my landlord here in Ljubljana has no problem with me having a dog inside the apartment.&lt;/p&gt;
&lt;p&gt;Working from home means I can dedicate enough attention and love to the dog and that is also one of the main reasons why I decided to get it.&lt;/p&gt;
&lt;h3 id=&quot;adopting_a_dog_from_a_shelter&quot;&gt;Adopting a dog from a shelter&lt;/h3&gt;
&lt;p&gt;A lot of people today buy puppies from local dog breeders. The problem is that all puppies are cute and a lot of people don’t realize that dogs are a big responsibility, especially when they grow up. Usually this leads to a lot of dogs being dumped once they grow up.&lt;/p&gt;
&lt;p&gt;I’m not like that so I decided to adopt a slightly older dog. In top of that, I believe that dogs living in the shelters need more help so I decided to adopt one from a &lt;a href=&quot;/2014/01/24/say-hello-to-ziva.html&quot;&gt;local shelter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before visiting the shelter in person, I have visited the website and immediately fell in love with a lovely young female called &lt;a href=&quot;http://zavetisce-ljubljana.si/ziva-1301032106122013/default.aspx&quot;&gt;Živa&lt;/a&gt;. I know that dogs are very similar to people and outside look is not everything so I didn’t keep my hopes too high.&lt;/p&gt;
&lt;p&gt;Luckily, when I visited the shelter in person it turned out that she’s one of the friendliest dogs there. Unlike other dogs, she was very friendly, didn’t bark and simply stuck her nose through the fence to greet me.&lt;/p&gt;
&lt;p&gt;After getting to know her a little better, I came back on Monday and decided to adopt her.&lt;/p&gt;
&lt;h3 id=&quot;iva&quot;&gt;Živa&lt;/h3&gt;
&lt;p&gt;Without further ado, lets get to know this lovely (not so) little creature.&lt;/p&gt;
&lt;p&gt;Živa is a mixed breed (looks very much like a German shepherd) ~10 months old female which weighs around 24 kg / 52 lbs. She was found on the street and arrived in the shelter about two months ago. Her name is in Slovenian and stands for lively / playful / cheery. She got this name at the shelter and I decided to keep it since it describes her temperament really well.&lt;/p&gt;
&lt;div class='imginline'&gt;
&lt;a class='fancybox' href='/images/2014-01-24-say-hello-to-ziva/IMG_20140121_112244.jpg' rel='dog'&gt;
&lt;img class='inline' src='/images/2014-01-24-say-hello-to-ziva/IMG_20140121_112244_thumb.jpg' /&gt;
&lt;/a&gt;
&lt;span class='image-caption'&gt;Resting.&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;She is a very friendly, quiet and a kind dog, but she also has almost unlimited energy and needs a tons of play time.&lt;/p&gt;
&lt;div class='imginline'&gt;
&lt;a class='fancybox' href='/images/2014-01-24-say-hello-to-ziva/IMG_20140121_115810.jpg' rel='dog'&gt;
&lt;img class='inline' src='/images/2014-01-24-say-hello-to-ziva/IMG_20140121_115810_thumb.jpg' /&gt;
&lt;/a&gt;
&lt;span class='image-caption'&gt;Tummy rub time.&lt;/span&gt;
&lt;/div&gt;&lt;div class='imginline'&gt;
&lt;a class='fancybox' href='/images/2014-01-24-say-hello-to-ziva/IMG_20140121_120532.jpg' rel='dog'&gt;
&lt;img class='inline' src='/images/2014-01-24-say-hello-to-ziva/IMG_20140121_120532_thumb.jpg' /&gt;
&lt;/a&gt;
&lt;span class='image-caption'&gt;Tummy rub time.&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;Even though she is very friendly she is currently still afraid of a lot of things including moving vehicles, bridges, stairs and so on. Interesting enough, she is not afraid of other people and dogs. She loves to jump on and kiss people :-)&lt;/p&gt;
&lt;div class='imginline'&gt;
&lt;a class='fancybox' href='/images/2014-01-24-say-hello-to-ziva/vlcsnap-2014-01-22-20h28m23s241.png' rel='dog'&gt;
&lt;img class='inline' src='/images/2014-01-24-say-hello-to-ziva/vlcsnap-2014-01-22-20h28m23s241_thumb.png' /&gt;
&lt;/a&gt;
&lt;span class='image-caption'&gt;Dat look.&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;I don’t know her history, but being afraid of so many thing probably means that her previous owner didn’t socialize her much / enough.&lt;/p&gt;
&lt;h3 id=&quot;first_day_with_a_dog&quot;&gt;First day with a dog&lt;/h3&gt;
&lt;p&gt;First day was very happy, but also very stressful for both of us. We both didn’t get a lot of sleep (she was constantly checking on me and I was checking on her) and there were some potty accidents. Potty accidents were mostly my fault because I didn’t recognize that she needs to go to the toilet (I thought she just wants to play).&lt;/p&gt;
&lt;div class='imginline'&gt;
&lt;a class='fancybox' href='/images/2014-01-24-say-hello-to-ziva/IMG_20140122_093219.jpg' rel='dog'&gt;
&lt;img class='inline' src='/images/2014-01-24-say-hello-to-ziva/IMG_20140122_093219_thumb.jpg' /&gt;
&lt;/a&gt;
&lt;span class='image-caption'&gt;Deer antler is nom nom.&lt;/span&gt;
&lt;/div&gt;&lt;div class='imginline'&gt;
&lt;a class='fancybox' href='/images/2014-01-24-say-hello-to-ziva/IMG_20140122_093227.jpg' rel='dog'&gt;
&lt;img class='inline' src='/images/2014-01-24-say-hello-to-ziva/IMG_20140122_093227_thumb.jpg' /&gt;
&lt;/a&gt;
&lt;span class='image-caption'&gt;Mmm, bone marrow...&lt;/span&gt;
&lt;/div&gt;
&lt;h3 id=&quot;plans_for_the_future&quot;&gt;Plans for the future&lt;/h3&gt;
&lt;p&gt;First couple of days were great, but there is still a tons of things to do in the future. She needs more socializing, I need to train her not to pull and she needs to be trained to not be so afraid of many things.&lt;/p&gt;
&lt;p&gt;As far as the pulling goes, I tried some manual approaches without much success. I’ve ordered an anti pull harness which goes around her front legs and doesn’t hurt her. Hopefully that will help.&lt;/p&gt;
&lt;p&gt;On top of that, I also plan to take her to the dog school. The dog school is actually more for me than her (this is my first dog).&lt;/p&gt;</content>
</entry>
<entry>
<title>Migrating from Zerigo to Rackspace Cloud DNS using Libcloud</title>
<link href="https://www.tomaz.me/2014/01/18/migrating-from-zerigo-to-rackspace-cloud-dns-using-libcloud.html" />
<id>https://www.tomaz.me/2014/01/18/migrating-from-zerigo-to-rackspace-cloud-dns-using-libcloud.html</id>
<updated>2014-01-18T00:00:00+01:00</updated>
<author>
<name>Tomaz Muraus</name>
</author>
<content type="html">&lt;h2 id=&quot;migrating_from_zerigo_to_rackspace_cloud_dns_using_libcloud&quot;&gt;&lt;a href=&quot;/2014/01/18/migrating-from-zerigo-to-rackspace-cloud-dns-using-libcloud.html&quot;&gt;Migrating from Zerigo to Rackspace Cloud DNS using Libcloud&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this blog post I’m going to describe how to migrate from &lt;a href=&quot;http://www.zerigo.com/managed-dns&quot;&gt;Zerigo DNS&lt;/a&gt; to &lt;a href=&quot;http://www.rackspace.com/cloud/dns/&quot;&gt;Rackspace Cloud DNS&lt;/a&gt; using a ~80 lines long Python script which utilizes &lt;a href=&quot;https://libcloud.apache.org/&quot;&gt;Libcloud&lt;/a&gt;.&lt;/p&gt;
&lt;div class='imginline'&gt;
&lt;a href='http://libcloud.apache.org' target='_blank'&gt;
&lt;img class='inline' src='/images/2013-12-11-libcloud-update-key-pair-management-methods-are-now-part-of-the-base-api/libcloud.png' /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;h3 id=&quot;background_and_motivation&quot;&gt;Background and Motivation&lt;/h3&gt;
&lt;p&gt;In September of the last year, I wrote how to &lt;a href=&quot;/2013/09/07/exporting-libcloud-dns-zone-to-bind-zone-file-format-and-migrating-between-dns-providers.html&quot;&gt;export a Libcloud zone to the BIND zone format&lt;/a&gt; and use the BIND zone file to migrate between DNS providers.&lt;/p&gt;
&lt;p&gt;At that time, my motivation for migrating away from Zerigo was mostly fueled by a very unreliable service which was a consequence of DDoS attacks and less than ideal service architecture.&lt;/p&gt;
&lt;p&gt;I have a paid Zerigo plan, so back then, I only migrated the most important domains to a different provider. Not long after I have done this, Zerigo announced that they have &lt;a href=&quot;http://www.zerigo.com/article/akamai-dns-partnership&quot;&gt;partnered with Akamai&lt;/a&gt; and that going forward, they will outsource running of the DNS infrastructure to Akami and as such, the service should be way more stable and reliable.&lt;/p&gt;
&lt;p&gt;I thought great, I won’t need to migrate rest of the domains away, but an unplesant surprise came earlier this month, when Zerigo announced pricing changes (see &lt;a href=&quot;http://www.zerigo.com/news/notice-zerigo-dns-change-of-plans&quot;&gt;1&lt;/a&gt;, &lt;a href=&quot;http://www.zerigo.com/news/zerigo-price-increase-facts&quot;&gt;2&lt;/a&gt;, &lt;a href=&quot;http://www.zerigo.com/news/on-grandfathering-pre-paid-dns-accounts&quot;&gt;3&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://gist.github.com/Kami/5199908f006383dbfdcc&quot;&gt;4&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Previously, I have paid &lt;strong&gt;19$ years per year&lt;/strong&gt;, but with a new plan which matches my current one, I would need to pay &lt;strong&gt;25$ per month&lt;/strong&gt;. That’s with an existing customer loyalty discount. New customers will need to pay &lt;strong&gt;38$ per month&lt;/strong&gt; (what a great deal, instead of paying 24 times more, now I need to pay &lt;strong&gt;just&lt;/strong&gt; 15 times more!). Yes, you have read this correctly, that’s more than one order of magniture per year more than I used to pay before.&lt;/p&gt;
&lt;p&gt;I honestly don’t mind paying for a great software and services and I wouldn’t mind paying a little more if the service improved, but that kind or price increase is simply too much. That is especially true, because all of the ~15 domains that I still have at Zerigo are used to host non-profit and community websites and paying 25$ per month is simply too much.&lt;/p&gt;
&lt;h3 id=&quot;why_rackspace_cloud_dns&quot;&gt;Why Rackspace Cloud DNS?&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Disclamer: I used to work at Rackspace, but I don’t work there anymore and I’m not affiliated with them in any way.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Before I dive further, lets have a look at why you might want to use Rackspace Cloud DNS.&lt;/p&gt;
&lt;p&gt;The main reason for me to migrate to Rackspace is that they have a decent API, they are supported in Libcloud and best of all, the service is totally free for the existing cloud servers customers. On top of that, the service is supposed to use Anycast.&lt;/p&gt;
&lt;p&gt;All of that made it a good fit for hosting my non-profit domains there.&lt;/p&gt;
&lt;p&gt;I also need to add that I haven’t used the service a lot before, so I can’t really talk much about the service relablitity at this point. Only time and monitoring will tell how reliable the service really is.&lt;/p&gt;
&lt;h3 id=&quot;migrating_from_zerigo_dns_to_rackspace_cloud_dns_using_libcloud&quot;&gt;Migrating from Zerigo DNS to Rackspace Cloud DNS using Libcloud&lt;/h3&gt;
&lt;p&gt;Instead of using Libcloud’s export to BIND zone file functionality, this script works by talking directly to both of the provider APIs.&lt;/p&gt;
&lt;p&gt;The reason for that is that this approach is more robust and makes performing partial migrations and synchronizations easier. On top of that it also works with other providers which don’t support importing a BIND zone file.&lt;/p&gt;
&lt;p&gt;It’s also important to note that the script relies on some Libcloud fixes which are currently only available in trunk. As such, you should use &lt;code&gt;pip&lt;/code&gt; to install latest version from Git inside a virtual environment:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;pip install -e git+https://github.com/apache/libcloud.git@trunk#egg&lt;span class='o'&gt;=&lt;/span&gt;libcloud
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After you have done this, you can use the script bellow to migrate all of your zones from Zerigo to Rackspace:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='nn'&gt;hashlib&lt;/span&gt;
&lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;libcloud.dns.types&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;Provider&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;RecordType&lt;/span&gt;
&lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;libcloud.dns.providers&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;get_driver&lt;/span&gt;
&lt;span class='n'&gt;ZERIGO_USERNAME&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class='n'&gt;ZERIGO_API_KEY&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class='n'&gt;RACKSPACE_USERNAME&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class='n'&gt;RACKSPACE_API_KEY&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class='n'&gt;CONTACT_EMAIL&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class='c'&gt;# Rackspace requires a valid email for every domain&lt;/span&gt;
&lt;span class='n'&gt;ZONE_TTL&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='mi'&gt;30&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt; &lt;span class='mi'&gt;60&lt;/span&gt; &lt;span class='c'&gt;# Default zone TTL (in seconds) which should be used&lt;/span&gt;
&lt;span class='n'&gt;MIN_TTL&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='mi'&gt;300&lt;/span&gt; &lt;span class='c'&gt;# Minim TTL supported by the target provider&lt;/span&gt;
&lt;span class='n'&gt;IGNORED_RECORD_TYPES&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='n'&gt;RecordType&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;NS&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;RecordType&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;PTR&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt;
&lt;span class='n'&gt;source_cls&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;get_driver&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;Provider&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;ZERIGO&lt;/span&gt;&lt;span class='p'&gt;)(&lt;/span&gt;&lt;span class='n'&gt;ZERIGO_USERNAME&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;ZERIGO_API_KEY&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;destination_cls&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;get_driver&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;Provider&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;RACKSPACE&lt;/span&gt;&lt;span class='p'&gt;)(&lt;/span&gt;&lt;span class='n'&gt;RACKSPACE_USERNAME&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
&lt;span class='n'&gt;RACKSPACE_API_KEY&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;get_record_hash&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;record&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
&lt;span class='sd'&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class='sd'&gt; Return a hash for the provided record. This is used to determine if the&lt;/span&gt;
&lt;span class='sd'&gt; record already exists.&lt;/span&gt;
&lt;span class='sd'&gt; &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class='n'&gt;record_hash&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;hashlib&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;md5&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;&lt;/span&gt;&lt;span class='si'&gt;%s&lt;/span&gt;&lt;span class='s'&gt;-&lt;/span&gt;&lt;span class='si'&gt;%s&lt;/span&gt;&lt;span class='s'&gt;-&lt;/span&gt;&lt;span class='si'&gt;%s&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;%&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;record&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;record&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;type&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
&lt;span class='n'&gt;record&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;data&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;hexdigest&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;record_hash&lt;/span&gt;
&lt;span class='n'&gt;source_zones&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;source_cls&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_zones&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;span class='n'&gt;destination_zones&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;destination_cls&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_zones&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;span class='n'&gt;destination_domains&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='n'&gt;zone&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;domain&lt;/span&gt; &lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;zone&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;destination_zones&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt;
&lt;span class='c'&gt;# 1. Create zones&lt;/span&gt;
&lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;zone&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;source_zones&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;
&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;zone&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;domain&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;destination_domains&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;
&lt;span class='k'&gt;print&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;Zone &amp;quot;&lt;/span&gt;&lt;span class='si'&gt;%s&lt;/span&gt;&lt;span class='s'&gt;&amp;quot; already exists, skipping...&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;%&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;zone&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;domain&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;span class='k'&gt;continue&lt;/span&gt;
&lt;span class='n'&gt;extra&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;email&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='n'&gt;CONTACT_EMAIL&lt;/span&gt;&lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='k'&gt;print&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;Creating zone: &lt;/span&gt;&lt;span class='si'&gt;%s&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;%&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;zone&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;domain&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;span class='n'&gt;destination_cls&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;create_zone&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;domain&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='n'&gt;zone&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;domain&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;ttl&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='n'&gt;ZONE_TTL&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
&lt;span class='n'&gt;extra&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='n'&gt;extra&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;destination_zones&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;destination_cls&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_zones&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;span class='n'&gt;supported_record_type&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;destination_cls&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_record_types&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;span class='c'&gt;# 2. Create records&lt;/span&gt;
&lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;source_zone&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;source_zones&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;
&lt;span class='n'&gt;destination_zone&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='n'&gt;zone&lt;/span&gt; &lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;zone&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;destination_zones&lt;/span&gt;
&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;zone&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;domain&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='n'&gt;source_zone&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;domain&lt;/span&gt;&lt;span class='p'&gt;][&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt;
&lt;span class='n'&gt;source_records&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;source_zone&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_records&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;span class='n'&gt;destination_records&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;destination_zone&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_records&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;source_record&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;source_records&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;
&lt;span class='c'&gt;# Rackspace doesn&amp;#39;t have a special SPF record type&lt;/span&gt;
&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;source_record&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;type&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='n'&gt;RecordType&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;SPF&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;
&lt;span class='n'&gt;source_record&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;type&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;RecordType&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;TXT&lt;/span&gt;
&lt;span class='n'&gt;record_hash&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;get_record_hash&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;source_record&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;destination_record_hashes&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='n'&gt;get_record_hash&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;record&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;record&lt;/span&gt;
&lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;destination_records&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt;
&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;source_record&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;
&lt;span class='n'&gt;fqdn&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;&lt;/span&gt;&lt;span class='si'&gt;%s&lt;/span&gt;&lt;span class='s'&gt;.&lt;/span&gt;&lt;span class='si'&gt;%s&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;%&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;source_record&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;source_zone&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;domain&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='k'&gt;else&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;
&lt;span class='n'&gt;fqdn&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;source_zone&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;domain&lt;/span&gt;
&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;record_hash&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;destination_record_hashes&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;
&lt;span class='k'&gt;print&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;Record &amp;quot;&lt;/span&gt;&lt;span class='si'&gt;%s&lt;/span&gt;&lt;span class='s'&gt;&amp;quot; already exists, skipping...&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;%&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fqdn&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;span class='k'&gt;continue&lt;/span&gt;
&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;source_record&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;type&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;IGNORED_RECORD_TYPES&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;
&lt;span class='k'&gt;print&lt;/span&gt;&lt;span class='p'&gt;((&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;Encountered ignored record type (type=&lt;/span&gt;&lt;span class='si'&gt;%s&lt;/span&gt;&lt;span class='s'&gt;,name=&lt;/span&gt;&lt;span class='si'&gt;%s&lt;/span&gt;&lt;span class='s'&gt;) &amp;#39;&lt;/span&gt;
&lt;span class='s'&gt;&amp;#39;skipping...&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;%&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;source_record&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;type&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;fqdn&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;span class='k'&gt;continue&lt;/span&gt;
&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='nb'&gt;type&lt;/span&gt; &lt;span class='ow'&gt;not&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;supported_record_type&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;
&lt;span class='k'&gt;print&lt;/span&gt;&lt;span class='p'&gt;((&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;Encountered unsupported record type (type=&lt;/span&gt;&lt;span class='si'&gt;%s&lt;/span&gt;&lt;span class='s'&gt;,name=&lt;/span&gt;&lt;span class='si'&gt;%s&lt;/span&gt;&lt;span class='s'&gt;)&amp;#39;&lt;/span&gt;
&lt;span class='s'&gt;&amp;#39;, skipping...&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;%&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;source_record&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;type&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;fqdn&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;span class='k'&gt;continue&lt;/span&gt;
&lt;span class='n'&gt;extra&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;{}&lt;/span&gt;
&lt;span class='n'&gt;ttl&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;source_record&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;extra&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;ttl&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='bp'&gt;None&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;priority&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;source_record&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;extra&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;priority&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='bp'&gt;None&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;ttl&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;
&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;ttl&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='n'&gt;MIN_TTL&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;
&lt;span class='n'&gt;ttl&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;MIN_TTL&lt;/span&gt;
&lt;span class='n'&gt;extra&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;ttl&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;ttl&lt;/span&gt;
&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;priority&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;
&lt;span class='n'&gt;extra&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;priority&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;priority&lt;/span&gt;
&lt;span class='n'&gt;name&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;source_record&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;
&lt;span class='nb'&gt;type&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;source_record&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;type&lt;/span&gt;
&lt;span class='n'&gt;data&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;source_record&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;data&lt;/span&gt;
&lt;span class='k'&gt;print&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;Creating a record: &lt;/span&gt;&lt;span class='si'&gt;%s&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;%&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fqdn&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;span class='n'&gt;destination_zone&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;create_record&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nb'&gt;type&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='nb'&gt;type&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;data&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='n'&gt;data&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
&lt;span class='n'&gt;extra&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='n'&gt;extra&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Before proceeeding it’s worth knowing that there are some differences between the providers and some limitations you should be aware of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Zerigo supports more record types. If you use more advanced record types which are not supported by Rackspace, then Rackspace might not be a good fit for you.&lt;/li&gt;
&lt;li&gt;Rackspace only allows you to create &lt;code&gt;PTR&lt;/code&gt; records for resources (cloud servers &amp;amp; load balancers) which are hosted in their data centers.&lt;/li&gt;
&lt;li&gt;Rackspace doesn’t support &lt;code&gt;SPF&lt;/code&gt; record type. This is not a big deal since this record type has been deprecated anyway and &lt;code&gt;TXT&lt;/code&gt; can be used instead. This script transparently handled remapping of &lt;code&gt;SPF&lt;/code&gt; to &lt;code&gt;TXT&lt;/code&gt; for you.&lt;/li&gt;
&lt;li&gt;Minimum supported TTL by Zerigo is &lt;code&gt;180&lt;/code&gt; seconds and the minimum supported TTL by Rackspace is &lt;code&gt;300&lt;/code&gt; seconds. If during the migration the script encounteres a TTL smaller than 300 seconds, it simply uses the smallest possible TTL which is 300 seconds.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To use it, simply plug in your API credentials and run it:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;python migrate_dns_providers.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class='imginline'&gt;
&lt;a class='fancybox' href='/images/2014-01-18-migrating-from-zerigo-to-rackspace-cloud-dns-using-libcloud/zerigo.png'&gt;&lt;img class='inline' src='/images/2014-01-18-migrating-from-zerigo-to-rackspace-cloud-dns-using-libcloud/zerigo.png' /&gt;&lt;/a&gt;
&lt;span class='image-caption'&gt;Zerigo control panel.&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;If the script for some reason fails half-way through (bad connectivity, API issues, etc.), it’s safe to run it again since all the operations are idempotent.&lt;/p&gt;
&lt;div class='imginline'&gt;
&lt;a class='fancybox' href='/images/2014-01-18-migrating-from-zerigo-to-rackspace-cloud-dns-using-libcloud/rax.png'&gt;&lt;img class='inline' src='/images/2014-01-18-migrating-from-zerigo-to-rackspace-cloud-dns-using-libcloud/rax.png' /&gt;&lt;/a&gt;
&lt;span class='image-caption'&gt;Rackspace Cloud DNS control panel after the migration.&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;After you have run the script, you should check if everything looks OK and if it does, you can go ahead and change the DNS records for your domains to point to the Rackspace Cloud DNS servers (&lt;code&gt;dns1.stabletransit.com&lt;/code&gt; &amp;amp; &lt;code&gt;dns2.stabletransit.com&lt;/code&gt;).&lt;/p&gt;</content>
</entry>
<entry>
<title>Programatically detecting type / platform of the Amazon Machine Images</title>
<link href="https://www.tomaz.me/2014/01/12/programatically-detecting-type-platform-of-the-amazon-machine-images.html" />
<id>https://www.tomaz.me/2014/01/12/programatically-detecting-type-platform-of-the-amazon-machine-images.html</id>
<updated>2014-01-12T00:00:00+01:00</updated>
<author>
<name>Tomaz Muraus</name>
</author>
<content type="html">&lt;h2 id=&quot;programatically_detecting_type__platform_of_the_amazon_machine_images&quot;&gt;&lt;a href=&quot;/2014/01/12/programatically-detecting-type-platform-of-the-amazon-machine-images.html&quot;&gt;Programatically detecting type / platform of the Amazon Machine Images&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Yesterday I was talking with one of the Libcloud users on our IRC channel. The user was trying to figure out if there is a programmatic way to detect type of the image used (also called a platform) by an EC2 instance (e.g. Linux, RHEL, Windows, Windows with SQL server, etc.).&lt;/p&gt;
&lt;p&gt;This information is important because the EC2 instance pricing depends on the type of the image used (more on that bellow).&lt;/p&gt;
&lt;p&gt;I was already looking into this in the past while trying to extend pricing information which is available in Libcloud. I didn’t have much luck back then, but I decided to look into it again and dig deeper this time.&lt;/p&gt;
&lt;p&gt;After a lot of research and poking with the API, it turned out that there still seems to be no programmatic and reliable way to determine that (if I missed something out, please let me know).&lt;/p&gt;
&lt;p&gt;In this post I’m going to have a quick look at how EC2 instance pricing works and at some of the less than ideal approaches which can be used to determine the image type.&lt;/p&gt;
&lt;h3 id=&quot;how_ec2_instance_pricing_works&quot;&gt;How EC2 instance pricing works&lt;/h3&gt;
&lt;p&gt;First lets have a quick look at how the whole EC2 instance pricing works.&lt;/p&gt;
&lt;p&gt;Compared to a lot of other cloud providers, EC2 pricing is very complex and depends on multiple factors:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Region (us-east-1 us-west-1, eu-west-1, …)&lt;/li&gt;
&lt;li&gt;Instance type (t1.micro, m1.small, m1.xlarge, …)&lt;/li&gt;
&lt;li&gt;Image type (Linux, RHEL, SLES, Windows, Windows with SQL Server standard, …)&lt;/li&gt;
&lt;li&gt;Is the instance EBS optimized&lt;/li&gt;
&lt;li&gt;Is the instance on-demand, reserved or spot&lt;/li&gt;
&lt;li&gt;Volume discounts&lt;/li&gt;
&lt;li&gt;Data transfer&lt;/li&gt;
&lt;li&gt;Other resources associated with this instance (e.g. EBS volumes)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you want to calculate an accurate instance pricing information, you need to take into account all the factors mentioned above.&lt;/p&gt;
&lt;h3 id=&quot;amazon_ec2_pricing_information&quot;&gt;Amazon EC2 pricing information&lt;/h3&gt;
&lt;p&gt;Amazon offers all the pricing information in a human readable format on their &lt;a href=&quot;http://aws.amazon.com/ec2/pricing/&quot;&gt;pricing page&lt;/a&gt;, but they don’t offer a documented API which could be used to consume this information programatically.&lt;/p&gt;
&lt;p&gt;Luckily, the pricing page reads JSON files (e.g. http://aws.amazon.com/ec2/pricing/json/linux-od.json) which can also be consumed programatically.&lt;/p&gt;
&lt;div class='imginline'&gt;
&lt;img class='inline' src='/images/2014-01-12-programatically-detecting-type-platform-of-the-amazon-machine-images/bad_time.jpg' /&gt;
&lt;/div&gt;
&lt;p&gt;Those JSON files are undocumented and the bad thing with any undocumented feature is that it could be changed or removed at any time without any prior notice.&lt;/p&gt;
&lt;p&gt;Sadly that’s the best we’ve get so far so we need to stick with it for now.&lt;/p&gt;
&lt;h3 id=&quot;programatically_detecting_the_image_type__platform&quot;&gt;Programatically detecting the image type / platform&lt;/h3&gt;
&lt;p&gt;I’ve spent a bunch of time researching and poking with the API and the web interface, but I had no luck with finding an API method which would return that information.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeImages.html&quot;&gt;DescribeImages&lt;/a&gt; API method does return &lt;code&gt;platform&lt;/code&gt; attribute, but only for Windows based images. This means you still need to use a different approach to detect RHEL, SLES and other type of Windows images.&lt;/p&gt;
&lt;p&gt;EC2 api has some undocumented features like the undocumented &lt;code&gt;max-instances&lt;/code&gt;, &lt;code&gt;max-elastic-ips&lt;/code&gt; and &lt;code&gt;vpc-max-elastic-ips&lt;/code&gt; value for the &lt;code&gt;AttributeName&lt;/code&gt; filter used by the &lt;a href=&quot;http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeAccountAttributes.html&quot;&gt;DescribeAccountAttributes&lt;/a&gt; API method. Because of that, I also tried a bunch of undocumented things and filter values, but I had no luck with retrieving a &lt;code&gt;platform&lt;/code&gt; attribute for all the images or retrieving only RHEL based images.&lt;/p&gt;
&lt;p&gt;The interesting thing is that the web interface does show an image type / platform, but it seems to use a private method to obtain this information.&lt;/p&gt;
&lt;div class='imginline'&gt;
&lt;a class='fancybox' href='/images/2014-01-12-programatically-detecting-type-platform-of-the-amazon-machine-images/web_interface_platform.png'&gt;
&lt;img class='inline' src='/images/2014-01-12-programatically-detecting-type-platform-of-the-amazon-machine-images/web_interface_platform_thumb.png' /&gt;
&lt;/a&gt;
&lt;span class='image-caption'&gt;Image platform as displayed in the web
interface.&lt;/span&gt;
&lt;/div&gt;&lt;div class='imginline'&gt;
&lt;a class='fancybox' href='/images/2014-01-12-programatically-detecting-type-platform-of-the-amazon-machine-images/inspector_network_request.png'&gt;
&lt;img class='inline' src='/images/2014-01-12-programatically-detecting-type-platform-of-the-amazon-machine-images/inspector_network_request_thumb.png' /&gt;
&lt;/a&gt;
&lt;span class='image-caption'&gt;Web interface calls a private API method which
returns information which is not available via the public one.&lt;/span&gt;
&lt;/div&gt;
&lt;h3 id=&quot;1_inferring_platform_from_the_image_details&quot;&gt;1. Inferring platform from the image details&lt;/h3&gt;
&lt;p&gt;Each image has name a name, description and a bunch of other attributes associated with it.&lt;/p&gt;
&lt;p&gt;This information can be used to infer the platform from it or to build a static list which maps image id to a platform.&lt;/p&gt;
&lt;p&gt;Inferring platform from the name and description should work reasonably well for the standard images, but it breaks down for private or copied images with custom names and descriptions.&lt;/p&gt;
&lt;p&gt;On the other hand, the problem with a static list approach is that it doesn’t scale and it’s time consuming and error prone to keep it up to date.&lt;/p&gt;
&lt;h3 id=&quot;2_scrapping_the_cloud_market_website&quot;&gt;2. Scrapping The Cloud Market website&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://thecloudmarket.com/&quot;&gt;The Cloud Market&lt;/a&gt; website provides details (including platform / image type) for every publicly available Amazon Machine Image.&lt;/p&gt;
&lt;p&gt;This approach basically just builds on the static list approach, but instead of putting the burden of keeping this list up to date on you, it puts it on the Cloud Market team.&lt;/p&gt;
&lt;p&gt;The Cloud Market website provides an API, but you can only retrieve details for the images which you are owner of. This means that to retrieve a platform for a particular image, you need to scrape the website which again is very hacky and far from ideal.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;As you can see, all of the approaches I have describes are hacky and far from ideal, but sadly that’s the best we have so far.&lt;/p&gt;
&lt;p&gt;Let’s just hope Amazon will pick their stuff together and finally provide an official API for this in the near future.&lt;/p&gt;</content>
</entry>
<entry>
<title>Detecting which process is creating a file using LD_PRELOAD trick</title>
<link href="https://www.tomaz.me/2014/01/08/detecting-which-process-is-creating-a-file-using-ld-preload-trick.html" />
<id>https://www.tomaz.me/2014/01/08/detecting-which-process-is-creating-a-file-using-ld-preload-trick.html</id>
<updated>2014-01-08T00:00:00+01:00</updated>
<author>
<name>Tomaz Muraus</name>
</author>
<content type="html">&lt;h2 id=&quot;detecting_which_process_is_creating_a_file_using_ld_preload_trick&quot;&gt;&lt;a href=&quot;/2014/01/08/detecting-which-process-is-creating-a-file-using-ld-preload-trick.html&quot;&gt;Detecting which process is creating a file using LD_PRELOAD trick&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The other day I was debugging an issue, basically I was trying to figure out which process is creating and writing to a file on Linux.&lt;/p&gt;
&lt;p&gt;There are multiple ways to detect this (some are better and more efficient than others). In this post I’m going to explain have I have done this using &lt;code&gt;LD_PRELOAD&lt;/code&gt; trick.&lt;/p&gt;
&lt;p&gt;This approach might not be the best and most efficient, but it’s a fun one and it can come handy in many other situations as well.&lt;/p&gt;
&lt;h3 id=&quot;alternative_solutions&quot;&gt;Alternative solutions&lt;/h3&gt;
&lt;p&gt;Before diving into how to use &lt;code&gt;LD_PRELOAD&lt;/code&gt; to solve this problem, lets have a look at a couple of other (more efficient) solutions which could also work.&lt;/p&gt;
&lt;h3 id=&quot;1_using_auditd&quot;&gt;1. Using auditd&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://people.redhat.com/sgrubb/audit/&quot;&gt;auditd&lt;/a&gt; is a subsystem for monitoring and accounting for Linux. Other *nix and BSD based systems also include a similar subsystems (e.g. standard installation of FreeBSD includes &lt;a href=&quot;http://www.freebsd.org/doc/handbook/audit-config.html&quot;&gt;audit&lt;/a&gt; and so on).&lt;/p&gt;
&lt;p&gt;Among other things, auditd allows you to monitor file accesses and writes and that’s exactly what we are looking for.&lt;/p&gt;
&lt;p&gt;To use it, you first create a watch file rule using &lt;code&gt;auditctl&lt;/code&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;sudo auditctl -w &amp;lt;file path&amp;gt; -p w
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I’ve used &lt;code&gt;w&lt;/code&gt; flag because we want to monitor file writes and creates.&lt;/p&gt;
&lt;p&gt;And then you can use &lt;code&gt;aureport&lt;/code&gt; to view audit reports:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;sudo aureport -f
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;2_using_strace_dtrace_or_a_similar_tool_for_tracking_syscalls&quot;&gt;2. Using strace, dtrace or a similar tool for tracking syscalls&lt;/h3&gt;
&lt;p&gt;Another approach is using a tool like &lt;a href=&quot;http://en.wikipedia.org/wiki/Strace&quot;&gt;strace&lt;/a&gt; or &lt;a href=&quot;http://linux.die.net/man/1/inotifywait&quot;&gt;dtrace&lt;/a&gt; which allows you to monitor all the system calls used by a running process.&lt;/p&gt;
&lt;p&gt;Those tools are very powerful (especially dtrace which offers a very flexible scripting language), but the problem with &lt;code&gt;dtrace&lt;/code&gt; is that it’s not available on all the Linux distributions yet and &lt;code&gt;strace&lt;/code&gt; needs to be attached to an existing running process.&lt;/p&gt;
&lt;p&gt;In my case I was trying to find the offending process so this approach doesn’t really work here.&lt;/p&gt;
&lt;h3 id=&quot;3_using_inotify&quot;&gt;3. Using inotify&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Inotify&quot;&gt;Inotify&lt;/a&gt; is a kernel subsystem which allows you to monitor and subscribe to file system changes.&lt;/p&gt;
&lt;p&gt;The are two problems with this approach which don’t make it ideal for solving this problem:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;inotify is used through system calls which means you need to use some other higher-level tool which uses inotify underneath or write some code yourself.&lt;/li&gt;
&lt;li&gt;inotify only tells you that a file has been modified, but it doesn’t tell you who modified it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;First problem can be solved pretty easily. You can use an existing tool such as &lt;a href=&quot;http://linux.die.net/man/1/inotifywait&quot;&gt;inotifywait&lt;/a&gt; or write a couple of lines of code yourself. The good thing is that you can find inotify bindings for most of the popular higher level languages (e.g. there is &lt;a href=&quot;https://github.com/seb-m/pyinotify&quot;&gt;pyinotify&lt;/a&gt; for Python) and some frameworks like Node.js already provide support for it in the standard library (see &lt;a href=&quot;http://nodejs.org/docs/latest/api/fs.html#fs_fs_watch_filename_options_listener&quot;&gt;fs.watch&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id=&quot;4_using_fuser&quot;&gt;4. Using fuser&lt;/h3&gt;
&lt;p&gt;My friend &lt;a href=&quot;https://twitter.com/lnktweets&quot;&gt;Lakshmi&lt;/a&gt; asked if the &lt;code&gt;fuser&lt;/code&gt; command didn’t help me. The answer is no.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Fuser_(Unix)&quot;&gt;fuser&lt;/a&gt; is a useful command line tool which lists all the processes which are currently using a file or a directory (underneath is just uses &lt;code&gt;procfs&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The problem is that it doesn’t work well for my use case. It only lists processes which are currently using an existing file. There are two problems with that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It doesn’t support polling and it only works on an existing file.&lt;/li&gt;
&lt;li&gt;It only lists processes which are currently using a file - this means processes which are currently holding a file or socket open.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Both of those problems can be worked around by writing a simple loop which calls &lt;code&gt;fuser&lt;/code&gt; indefinitely, but the problem with that is that it will most likely miss processes which only open a file for a short amount of time (e.g. fast open, write, close sequence).&lt;/p&gt;
&lt;p&gt;On top of that, this polling approach is very inefficient and there are better and way more efficient approaches for this, like the aforementioned inotify subsystem.&lt;/p&gt;
&lt;p&gt;Similar arguments also apply to the &lt;code&gt;lsof&lt;/code&gt; approach.&lt;/p&gt;
&lt;h3 id=&quot;ld_preload_approach&quot;&gt;LD_PRELOAD approach&lt;/h3&gt;
&lt;p&gt;OK, now back to the &lt;code&gt;LD_PRELOAD&lt;/code&gt; approach I have decided to use.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;LD_PRELOAD&lt;/code&gt; allows you to specify a list of of ELF shared libraries to load before other libraries, including libc.&lt;/p&gt;
&lt;p&gt;To use it, you simply set &lt;code&gt;LD_PRELOAD&lt;/code&gt; environment variable to point to your shared library or libraries.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='nv'&gt;LD_PRELOAD&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;/home/me/mylibrary.so ./myprogram
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This approach is very powerful and you can, among many other things, use it to mask functions provided by libc and other libraries. This comes very handy in many cases, including this one.&lt;/p&gt;
&lt;p&gt;As other approaches described above, this one also has some limitations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LD_PRELOAD approach doesn’t work with binaries which have &lt;a href=&quot;http://en.wikipedia.org/wiki/Setuid&quot;&gt;suid permissions bit&lt;/a&gt; set (see &lt;a href=&quot;http://man7.org/linux/man-pages/man2/setuid.2.html&quot;&gt;setuid&lt;/a&gt; and &lt;a href=&quot;http://man7.org/linux/man-pages/man2/setgid.2.html&quot;&gt;setgid&lt;/a&gt; for more info)&lt;/li&gt;
&lt;li&gt;If you use SELinux, it will, by default, automatically set &lt;code&gt;AT_SECURE&lt;/code&gt; glibc flag on a domain transition (e.g. when you use fork / execve) which means child processes won’t inherit environment variables from the parent process.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’ve used this approach to solve my problem by masking / wrapping &lt;code&gt;fopen&lt;/code&gt; and &lt;code&gt;open&lt;/code&gt; function provided by libc.&lt;/p&gt;
&lt;p&gt;Wrapped functions behave almost the same as the original ones, the only difference is that they log file access information to a file before calling the original function.&lt;/p&gt;
&lt;p&gt;In my case, I’ve logged the timestamp and the pid and name of the process which has called the function.&lt;/p&gt;
&lt;p&gt;Some code which shows how you can do that is shown bellow.&lt;/p&gt;
&lt;p&gt;log_file_access.c&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='c'&gt;&lt;span class='cp'&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/span&gt;
&lt;span class='cp'&gt;#include &amp;lt;unistd.h&amp;gt;&lt;/span&gt;
&lt;span class='cp'&gt;#include &amp;lt;errno.h&amp;gt;&lt;/span&gt;
&lt;span class='cp'&gt;#include &amp;lt;string.h&amp;gt;&lt;/span&gt;
&lt;span class='cp'&gt;#include &amp;lt;dlfcn.h&amp;gt;&lt;/span&gt;
&lt;span class='cp'&gt;#define FILE_NAME &amp;quot;/var/myfile&amp;quot;&lt;/span&gt;
&lt;span class='k'&gt;typedef&lt;/span&gt; &lt;span class='kt'&gt;FILE&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;orig_fopen_func_type&lt;/span&gt;&lt;span class='p'&gt;)(&lt;/span&gt;&lt;span class='k'&gt;const&lt;/span&gt; &lt;span class='kt'&gt;char&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;path&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='k'&gt;const&lt;/span&gt; &lt;span class='kt'&gt;char&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;mode&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='k'&gt;typedef&lt;/span&gt; &lt;span class='nf'&gt;int&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;orig_open_func_type&lt;/span&gt;&lt;span class='p'&gt;)(&lt;/span&gt;&lt;span class='k'&gt;const&lt;/span&gt; &lt;span class='kt'&gt;char&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;pathname&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='kt'&gt;int&lt;/span&gt; &lt;span class='n'&gt;flags&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='kt'&gt;int&lt;/span&gt; &lt;span class='nf'&gt;log_file_access&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;const&lt;/span&gt; &lt;span class='kt'&gt;char&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;path&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;strcmp&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;path&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;FILE_NAME&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;!=&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
&lt;span class='c1'&gt;// Not a file we are interested in&lt;/span&gt;
&lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='c1'&gt;// Log file access to a file. Need to use flock or a similar locking&lt;/span&gt;
&lt;span class='c1'&gt;// approach if all the accesses are written to the same file.&lt;/span&gt;
&lt;span class='c1'&gt;// ...&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='kt'&gt;FILE&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt; &lt;span class='nf'&gt;fopen&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;const&lt;/span&gt; &lt;span class='kt'&gt;char&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;path&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='k'&gt;const&lt;/span&gt; &lt;span class='kt'&gt;char&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;mode&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='p'&gt;{&lt;/span&gt;
&lt;span class='n'&gt;log_file_access&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;path&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='n'&gt;orig_fopen_func_type&lt;/span&gt; &lt;span class='n'&gt;orig_func&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='n'&gt;orig_func&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;orig_fopen_func_type&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='n'&gt;dlsym&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;RTLD_NEXT&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;fopen&amp;quot;&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;orig_func&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;path&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;mode&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='kt'&gt;int&lt;/span&gt; &lt;span class='nf'&gt;open&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;const&lt;/span&gt; &lt;span class='kt'&gt;char&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;pathname&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='kt'&gt;int&lt;/span&gt; &lt;span class='n'&gt;flags&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='p'&gt;{&lt;/span&gt;
&lt;span class='n'&gt;log_file_access&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;pathname&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='n'&gt;orig_open_func_type&lt;/span&gt; &lt;span class='n'&gt;orig_func&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='n'&gt;orig_func&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;orig_open_func_type&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='n'&gt;dlsym&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;RTLD_NEXT&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;open&amp;quot;&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;orig_func&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;pathname&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;flags&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Makefile:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='makefile'&gt;&lt;span class='nf'&gt;log_file_accesses.s&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt;
gcc -shared -fPIC log_file_access.c -o log_file_access.so -ldl
&lt;span class='nf'&gt;clean&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt;
rm *.so
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Using it:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='nv'&gt;LD_PRELOAD&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;/home/myuser/mypath/log_file_access.so ./myapp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To make it work for all the started processes, I have modified upstart scripts and &lt;code&gt;/etc/profile&lt;/code&gt;file to set the &lt;code&gt;LD_PRELOAD&lt;/code&gt; environment variable.&lt;/p&gt;
&lt;h3 id=&quot;other_use_cases_for_ld_preload&quot;&gt;Other use cases for LD_PRELOAD&lt;/h3&gt;
&lt;p&gt;As noted above, &lt;code&gt;LD_PRELOAD&lt;/code&gt; can come handy in many different scenarios. One of the cases worth mentioning is mocking library functions for tests.&lt;/p&gt;
&lt;p&gt;A while back when I was still at Rackspace we were discussing how to mock and test MySQL check used by our monitoring agent. MySQL check fetches a bunch of metrics from a MySQL server using a MySQL client library (libmysql).&lt;/p&gt;
&lt;p&gt;One of the approaches I have suggested was to use &lt;code&gt;LD_PRELOAD&lt;/code&gt; to wrap functions from the MySQL client library and make them return mock data. I thought this was pretty clever, but soon afterwards, &lt;a href=&quot;http://paul.querna.org/&quot;&gt;Paul&lt;/a&gt; came up with even &lt;a href=&quot;https://github.com/virgo-agent-toolkit/virgo/blob/master/tests/check/mysql_mock.lua&quot;&gt;more clever approach&lt;/a&gt; using &lt;a href=&quot;http://en.wikipedia.org/wiki/Foreign_function_interface&quot;&gt;ffi&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It turned out that ffi approach was even simpler and better, but this was mostly because unlike most other languages, Lua includes a really nice &lt;a href=&quot;http://luajit.org/ext_ffi.html&quot;&gt;ffi library&lt;/a&gt; in the core. Okay &lt;a href=&quot;http://cffi.readthedocs.org/en/release-0.8/&quot;&gt;cffi&lt;/a&gt; for Python is not bad either, but that’s mostly because it’s modeled after the Lua one :-)&lt;/p&gt;
&lt;p&gt;If you are not or can’t use ffi, using &lt;code&gt;LD_PRELOAD&lt;/code&gt; is a good and valid alternative.&lt;/p&gt;
&lt;p&gt;Remember that this is just the tip of the iceberg. Other cool use cases include wrapping a &lt;code&gt;ptrace&lt;/code&gt; function to prevent debugger detection and anti-debugging techniques in the application and so on.&lt;/p&gt;
&lt;p&gt;Edit 1 (January 11th, 2014) - Added a section about &lt;code&gt;fuser&lt;/code&gt;.&lt;/p&gt;</content>
</entry>
<entry>
<title>The cocktail experiment &amp;#35;7 - Damn Fine in Blue</title>
<link href="https://www.tomaz.me/2014/01/04/cocktail-experiment-7-damn-fine-in-blue.html" />
<id>https://www.tomaz.me/2014/01/04/cocktail-experiment-7-damn-fine-in-blue.html</id>
<updated>2014-01-04T00:00:00+01:00</updated>
<author>
<name>Tomaz Muraus</name>
</author>
<content type="html">&lt;h2 id=&quot;the_cocktail_experiment_7__damn_fine_in_blue&quot;&gt;&lt;a href=&quot;/2014/01/04/cocktail-experiment-7-damn-fine-in-blue.html&quot;&gt;The cocktail experiment #7 - Damn Fine in Blue&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;This is a seventh post in the ”&lt;a href=&quot;/tags/cocktail%20experiment.html&quot;&gt;Cocktail Experiment&lt;/a&gt;” post series. In this series I write about my experience with learning to mix cocktails. Every post contains instructions on how to prepare a cocktail, cocktail’s nutritional values (calories) and a good 80’s song which goes along well with that particular cocktail.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As I have promised in &lt;a href=&quot;/2014/01/03/cocktail-experiment-6-kamikaze.html&quot;&gt;my previous post&lt;/a&gt;, here is a second cocktail we have mixed at the New Year’s Eve Party - Damn Fine in Blue.&lt;/p&gt;
&lt;h3 id=&quot;ingredients&quot;&gt;Ingredients&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;1.5 oz (45 ml) of blue curacao&lt;/li&gt;
&lt;li&gt;0.5 oz (15 ml) of white rum&lt;/li&gt;
&lt;li&gt;0.5 oz (15 ml) of malibu coconut rum&lt;/li&gt;
&lt;li&gt;0.5 oz (15 ml) of triple sec&lt;/li&gt;
&lt;li&gt;ice cubes&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;nutritional_values_calories&quot;&gt;Nutritional Values (calories)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;1.5 oz of blue curacao - 108 calories (12.7 grams of alcohol)&lt;/li&gt;
&lt;li&gt;0.5 oz of white rum - 32 calories (5.3 grams of alcohol)&lt;/li&gt;
&lt;li&gt;0.5 oz of malibu coconut rum - 25 calories (3.4 grams of alcohol)&lt;/li&gt;
&lt;li&gt;0.5 oz of triple sec - 36 calories (3.4 grams alcohol)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Total: 201 calories (21.7 grams alcohol - equivalent to 1.5 standard drinks)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;1 standard drink = regular beer, glass of table wine or a shot of 80-proof (40%) spirit (around 14 grams of pure alcohol)&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;preparation&quot;&gt;Preparation&lt;/h3&gt;
&lt;p&gt;I’m more of a ”&lt;a href=&quot;http://en.wikipedia.org/wiki/Shaken,_not_stirred#Purpose_of_shaking&quot;&gt;shaken, not stirred&lt;/a&gt;” guy myself, but for a change, I decided to stir this cocktail and serve it &lt;a href=&quot;http://en.wikipedia.org/wiki/Straight_up_(bartending)#Definitions_and_usage&quot;&gt;on the rocks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To prepare it, put ice in a cocktail glass, add all the ingredients in the shaker, mix it very gently, pour mixture into the cocktail class and use the bar spoon to stir it.&lt;/p&gt;
&lt;p&gt;As a garnish, we have used a maraschino cherry. We didn’t have the decoration umbrella thing so we have put cherry directly on the side of the glass.&lt;/p&gt;
&lt;div class='imginline'&gt;
&lt;img class='inline' src='/images/2014-01-04-cocktail-experiment-7-damn-fine-in-blue/DSC_0089.JPG' /&gt;
&lt;span class='image-caption'&gt;They see me pourin' they hatin'&lt;/span&gt;
&lt;/div&gt;
&lt;h3 id=&quot;the_outcome&quot;&gt;The outcome&lt;/h3&gt;
&lt;p&gt;The cocktail was pretty good, but not shaking it made it slightly too sweet for my taste. Next time I’m going to try to shake it and see how it goes.&lt;/p&gt;
&lt;div class='imginline'&gt;
&lt;img class='inline' src='/images/2014-01-04-cocktail-experiment-7-damn-fine-in-blue/DSC_0112.JPG' /&gt;
&lt;span class='image-caption'&gt;Cocktail is ready.&lt;/span&gt;
&lt;/div&gt;&lt;div class='imginline'&gt;
&lt;img class='inline' src='/images/2014-01-04-cocktail-experiment-7-damn-fine-in-blue/DSC_0119.JPG' /&gt;
&lt;span class='image-caption'&gt;Cheers! And yes, we are using a beer glass. Deal with it.&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;As you can see on the pictures, blue curacaco adds a nice blue color to the cocktail, hence the name.&lt;/p&gt;
&lt;h3 id=&quot;eiffel_65__blue_da_ba_dee&quot;&gt;Eiffel 65 - Blue (Da Ba Dee)&lt;/h3&gt;
&lt;p&gt;Today I’m presenting you &lt;a href=&quot;http://en.wikipedia.org/wiki/Blue_(Da_Ba_Dee)&quot;&gt;Eiffel 65 - Blue&lt;/a&gt;. As you might recognize, this song is not from the 80’s, but the music video is ridiculous enough to earn an exception.&lt;/p&gt;
&lt;div class='imginline'&gt;
&lt;object height='415' width='520'&gt;
&lt;param name='movie' value='//www.youtube-nocookie.com/v/68ugkg9RePc?hl=en_US&amp;amp;version=3' /&gt;
&lt;param name='allowFullScreen' value='true' /&gt;
&lt;param name='allowscriptaccess' value='always' /&gt;
&lt;embed allowfullscreen='true' allowscriptaccess='always' height='415' src='//www.youtube-nocookie.com/v/68ugkg9RePc?hl=en_US&amp;amp;version=3' type='application/x-shockwave-flash' width='520' /&gt;
&lt;/object&gt;
&lt;/div&gt;</content>
</entry>
<entry>
<title>The cocktail experiment &amp;#35;6 - Kamikaze</title>
<link href="https://www.tomaz.me/2014/01/03/cocktail-experiment-6-kamikaze.html" />
<id>https://www.tomaz.me/2014/01/03/cocktail-experiment-6-kamikaze.html</id>
<updated>2014-01-03T00:00:00+01:00</updated>
<author>
<name>Tomaz Muraus</name>
</author>
<content type="html">&lt;h2 id=&quot;the_cocktail_experiment_6__kamikaze&quot;&gt;&lt;a href=&quot;/2014/01/03/cocktail-experiment-6-kamikaze.html&quot;&gt;The cocktail experiment #6 - Kamikaze&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;This is a sixth post in the ”&lt;a href=&quot;/tags/cocktail%20experiment.html&quot;&gt;Cocktail Experiment&lt;/a&gt;” post series. In this series I write about my experience with learning to mix cocktails. Every post contains instructions on how to prepare a cocktail, cocktail’s nutritional values (calories) and a good 80’s song which goes along well with that particular cocktail.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It has been a while since my last cocktail experiment. To make up for it, I plan to adds more posts in the upcoming days. All of those posts will be based on the cocktails we’ve mixed at a recent New Year’s Eve party.&lt;/p&gt;
&lt;p&gt;During the party, we’ve mixed most cocktail for 4-8 people, but in this post, I’m going to normalize the ingredients and serving sizes for a single person / serving.&lt;/p&gt;
&lt;p&gt;If you are wondering why pictures in this and upcoming posts look better than usual, that’s because they were taken by my friend &lt;a href=&quot;http://simplified.me/&quot;&gt;Ivan&lt;/a&gt; who has better equipment and photography skills than I do.&lt;/p&gt;
&lt;p&gt;I’m going to start with a very simple cocktail, the one with which we and a lot of other people usually start a party with. Everyone, say hello to &lt;a href=&quot;http://en.wikipedia.org/wiki/Kamikaze_(cocktail)&quot;&gt;Kamikaze&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;ingredients&quot;&gt;Ingredients&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;1 oz (30 ml) of vodka&lt;/li&gt;
&lt;li&gt;1 oz (30 ml) of triple sec&lt;/li&gt;
&lt;li&gt;1 oz (30 ml) of lime juice&lt;/li&gt;
&lt;li&gt;ice cubes&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;nutritional_values_calories&quot;&gt;Nutritional Values (calories)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;1 oz of vodka - 64 calories (9.3 grams alcohol)&lt;/li&gt;
&lt;li&gt;1 oz of triple sec - 72 calories (6.8 grams alcohol)&lt;/li&gt;
&lt;li&gt;1 oz lime juice - 6 calories&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Total: 144 calories (16.1 grams alcohol - equivalent to 1.1 standard drinks)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;1 standard drink = regular beer, glass of table wine or a shot of 80-proof (40%) spirit (around 14 grams of pure alcohol)&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;preparation&quot;&gt;Preparation&lt;/h3&gt;
&lt;p&gt;This is another cocktail which is very easy to prepare. Simply put ice and all the ingredients in the shaker and mix it well (~10 seconds or so). In our case, we didn’t have limes so we have used a lime juice concentrate instead.&lt;/p&gt;
&lt;div class='imginline'&gt;
&lt;img class='inline' src='/images/2014-01-03-cocktail-experiment-6-kamikaze/DSC_0075.JPG' /&gt;
&lt;span class='image-caption'&gt;Pouring #1&lt;/span&gt;
&lt;/div&gt;&lt;div class='imginline'&gt;
&lt;img class='inline' src='/images/2014-01-03-cocktail-experiment-6-kamikaze/DSC_0136.JPG' /&gt;
&lt;span class='image-caption'&gt;Pouring #2&lt;/span&gt;
&lt;/div&gt;&lt;div class='imginline'&gt;
&lt;img class='inline' src='/images/2014-01-03-cocktail-experiment-6-kamikaze/DSC_0140.JPG' /&gt;
&lt;span class='image-caption'&gt;Pouring #3&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;As you can notice it on the pictures, we have used shot glasses.&lt;/p&gt;
&lt;h3 id=&quot;the_outcome&quot;&gt;The outcome&lt;/h3&gt;
&lt;p&gt;This is the 5th time in the past two months or so that I have mixed this cocktail at the party and the outcome was again very tasty and refreshing (other people who have tasted the cocktail can confirm that).&lt;/p&gt;
&lt;p&gt;I have drank kamikaze on multiple occasions at different bars before, but that is by far the best kamikaze I had so far. I think the “secret ingredient” which helps make it so good and refreshing is the lime juice concentrate I use. This juice has a tiny bit of sugar in it which makes up for a perfect taste which is not too bitter or too sweet.&lt;/p&gt;
&lt;h3 id=&quot;earth_wind_and_fire__september&quot;&gt;Earth, Wind And Fire - September&lt;/h3&gt;
&lt;div class='imginline'&gt;
&lt;object height='415' width='520'&gt;
&lt;param name='movie' value='//www.youtube-nocookie.com/v/M1Nxo6ypsB8?hl=en_US&amp;amp;version=3' /&gt;
&lt;param name='allowFullScreen' value='true' /&gt;
&lt;param name='allowscriptaccess' value='always' /&gt;
&lt;embed allowfullscreen='true' allowscriptaccess='always' height='415' src='//www.youtube-nocookie.com/v/M1Nxo6ypsB8?hl=en_US&amp;amp;version=3' type='application/x-shockwave-flash' width='520' /&gt;
&lt;/object&gt;
&lt;/div&gt;
&lt;p&gt;I couldn’t think of any particular 80’s song which goes well with this cocktail so I’m just posting a random all around good song from late 1970’s - &lt;a href=&quot;http://en.wikipedia.org/wiki/September_(Earth,_Wind_%26_Fire_song)&quot;&gt;Earth, Wind And Fire - September&lt;/a&gt;.&lt;/p&gt;</content>
</entry>
</feed>