Mind Passthrough

Nicolas Ochem's mumblings on virtualization and network policy

Archipel + Vagrant + Puppet

Archipel is a lightweight cloud management platform built on top of libvirt. While it does not match the feature set of more popular orchestrators, Archipel’s Cappuccino-based UI is way better than every other cloud management platform out there.

I spent some time last year trying to maintain an environment where I could hack on ArchipelAgent, Archipel’s Python backend, and test it in a box.

To test Archipel, I need one virtual machine acting as ejabberd server and central agent, and one or more nested hypervisors. I wrote some scripts to manage the lifecycle of this setup. The features were :

  • ability to start and stop all Archipel daemons
  • deploy the Archipel working tree in all VMs by NFS
  • send commands to the VMs shell by script

I ended up writing mostly unmaintainable code.

Then a few months ago I stumbled upon the Technical Blog of James. James has made puppet-gluster-vagrant, an awesome self-contained hacking environment for glusterfs which turned out very handy to test a gluster setup I am using at work. The interesting part is that it is running in Vagrant with Vagrant-Libvirt plugin. Since Archipel is a pure Libvirt shop, it sounds like a plan, now, does it not ?

Setup

Vagrant is a deployment and prototyping environment perfectly adapted for the use case described above, but it was designed around Virtualbox. Only a few months ago, feature parity with Libvirt was achieved. Still, based on James’ blog post, Libvirt felt like a second-class citizen, at least on Fedora 20. So I decided to give it a try on Ubuntu 14.04 LTS.

First things first, I installed vagrant and the necessary plugin :

1
2
3
4
5
# This will install Vagrant 1.4.1.
# Good, because vagrant-libvirt is currently broken with Vagrant 1.5.
apt-get install vagrant

vagrant plugin install vagrant-libvirt

I added this line to my .bashrc to make Vagrant use libvirt by default :

1
export VAGRANT_DEFAULT_PROVIDER=libvirt # libvirt as default vagrant provider

I then downloaded a centos6.5 box in libvirt format :

1
vagrant box add centos-6 https://download.gluster.org/pub/gluster/purpleidea/vagrant/centos-6.box --provider=libvirt

Then I created a Vagrantfile using vagrant init and created 3 VMs :

1
2
3
4
5
6
7
8
9
10
11
# -*- mode: ruby -*-
# vi: set ft=ruby :

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "centos-6"
  config.vm.define :central_server, :primary => true
  config.vm.define :agent_1
  config.vm.define :agent_2
end

Then issuing vagrant up brought my 3 VMs up. I was able to login to them using i.e. vagrant ssh central_server. vagrant destroy sent them into oblivion.

Nested virtualization works out-of-the-box on Ubuntu, provided that you set up the correct options in your VM XML definition. Vagrant-libvirt has a configuration option that will do that for you :

1
2
3
4
5
6
7
Vagrant.configure("2") do |config|
  config.vm.define "agent_1" do |agent|
    agent.vm.provider :libvirt do |domain|
      domain.nested = true
    end
  end
end

The rest of the Vagrantfile is fairly standard Ruby code. The default comments make it really easy to incrementally create the setup you want. Check out the final Vagrantfile.

There were a few hurdles before I reached that state though :

  • for some reason my Ubuntu laptop will not allow NFS exports anything under my home directory. Maybe because it is encrypted ? Anyways, I ended up working as root and using /root/workspace/archipel-puppet-vagrant as working directory. I had to make it world-readable.
  • Ubuntu’s firewall, ufw, does not let me export NFS folders. I had to deactivate it completely by issuing sudo ufw disable. Just shutting it down does not do the trick as it keeps coming back up.

It looks like libvirt is still not a first-class citizen in the Vagrant world, but hopefully the situation will improve.

You can check more advice on how to run vagrant with libvirt on this blog post.

Provisioning

I have 3 empty boxes, and I want to turn them into a running Archipel setup, with one central server and 2 agents running VMs. How do I do that in 2014 ? I use a provisioning solution, like Puppet.

That should be easy because Vagrant supports Puppet out of the box. The vagrant provision command will execute puppet manifests on all nodes. The manifests will also be executed by default if they are present when you do vagrant up.

James’s puppet-gluster-vagrant setup has a standalone puppet server box defined in his Vagrantfile. All the other VMs are using it as puppetmaster. This mimics a production environment in the best possible way, but it is overkill for me. I am only going to write Puppet manifests on my workspace and load them in the VMs using headless Puppet.

I followed the installation instructions for Archipel Agent, Archipel Server and Archipel Central Agent. I turned these instructions into a Puppet module for Archipel. The Vagrantfile is in a subdirectory of this module.

A few caveats apply :

  • the setup is very slow over ssh because of DNS timeouts. Bringing up the setup from scratch takes more time than it should. I have found a lot of suggestions but none seemed to help.
  • there is no DNS support so I had to add commands in the Vagrantfile to set the hostnames of every node manually in /etc/hosts of every node. There is a Vagrant plugin named Landrush that does just that for Virtualbox. Hopefully libvirt support will be coming soon.

Hacking

Archipel repository is checked out as a submodule inside puppet-archipel. This way, it gets NFS-mounted to every node.

ArchipelAgent already has a “developer mode” built in. Running buildAgent -d will set up redirects from the python library folder to the development environment. So I added this step in the Puppet manifest.

It means that editing the source code in my laptop deploys it instantly to all nodes. Testing changes is trivial.

Probably the best part of this setup is the portability of the configuration. In theory, anyone can check out the code, perform vagrant up and deploy the same environment in minutes. The barrier of entry for a potential developer is pushed to the lowest limit, no matter how distributed the setup is. That is a huge asset for cloud management systems.

To start using archipel-vagrant-puppet, check out the README. Enjoy !

Branch-aware Git Submodules

Large software projects often build their release from many repositories. It it tempting to set up a super-repository referencing all your shipping code through git submodules. Since each commit of your superproject contains an unambiguous reference to a particular commit of every submodule, you can tag your superproject to define a release or nightly build.

All it takes is a single command to retrieve all the source code for a particular release.

1
2
# checking out all source code for 3.11 release
git clone --recursive superproject -b 3.11

It is very useful for archival purposes or code escrow. In this post, we explore how to set that up.

Setting up submodules

There used to be no straightforward way to update your submodules. You would have to extract the SHA checksum of the desired commit of every submodule, and point your superproject to each one of them. git submodule update would check out the submodule code. Add branching logic to the mix, and you ended up with fairly complex code.

Since git 1.8.2, it has become much easier. When defining a submodule, you can now specify which branch it is supposed to track.

Say you are building your superproject from components A and B. Your development builds are built from branch master of component A and branch dev of component B. The following commands will set up the superproject:

1
2
3
git init
git submodule --branch dev add <git repo of component A>
git submodule --branch master add <git repo of component B>

Git will store the relationship with the sumbodules in the .gitmodule file.

1
2
3
4
5
6
7
8
9
# content of .gitmodules files on master branch
[submodule "component_A"]
    path = component_A
    url = <git repo of component A>
    branch = dev
[submodule "component_B"]
    path = component_B
    url = <git repo of component B>
    branch = master

Then all it takes to fetch the last commits from the components is:

1
git submodule update --remote

You can issue git submodule status to verify that the commit SHA1 hashes match the latest commits of your component repositories:

1
2
3
nochem@bonk:/tmp/submodules/superproject$ git submodule status
 9665f1cd09faa63c6e3211712a805c49bf99c7c5 component_A (heads/dev)
 323db44f229e794850fec8afb5e8964d813d9a30 component_B (heads/master)

Then your automated build system may just automatically tag nightlies for all your components every night:

1
2
3
4
5
git checkout master
git submodule update --remote
# do the build.
git commit -a -m "Nightly build 345"
git tag master-nightly-345

Of course, this does not dispense you from tagging your component repositories individually.

Adding a branch

If your release branch is named “3.11” on both components, you may create a branch 3.11 on your superproject, delete the submodules (with the git submodule deinit command available since release 1.8.3 of git), then recreate them again giving the correct --branch option.

Or you may just edit your .gitmodules file and check it in to the repo.

1
2
3
4
5
6
7
8
9
# content of manually edited .gitmodules files on 3.11 release branch
[submodule "component_A"]
    path = component_A
    url = <git repo of component A>
    branch = 3.11
[submodule "component_B"]
    path = component_B
    url = <git repo of component B>
    branch = 3.11

Then, when on branch 3.11 of your superproject, git submodule update --remote will fetch the latest release branch content from all submodules.

1
2
3
4
5
6
nochem@bonk:/tmp/submodules/superproject$ git submodule update --remote
Submodule path 'component_A': checked out '56d62717ac6f5fb4e67daa331c5ef566588cec4e'
Submodule path 'component_B': checked out '312df465c70cb81ffaf6dd6f2d505df44c8db45f'
nochem@bonk:/tmp/submodules/superproject$ git submodule status
 56d62717ac6f5fb4e67daa331c5ef566588cec4e component_A (heads/3.11)
 312df465c70cb81ffaf6dd6f2d505df44c8db45f component_B (heads/3.11)

You may now tag and commit again:

1
2
git commit -a -m "release 3.11 nightly build 5"
git tag "3.11-nightly-5"

You have now set a multi-branch superproject tracking all branches of all your components. Isn’t it nice ?

Thus said, a word of warning is necessary. Git submodules are recently receiving a lot of improvements, but they are no panacea. If your component repositories are very dependent on one another, and developers are likely to commit to several repositories, then you may be better off having one big repository. This model works well when your different components are worked on by different teams, and you are looking for an easy way to check out or tag all the code.

All the code used in this post is also available as a gist.

2 Measures to Take Back the Internet

They are at it again. Verizon is trying to turn the Internet into cable TV. The Europen Commission is pushing carrier-controlled prioritization of traffic in the Telecom package.

Ten years ago the Internet was a thriving, neutral environment with a low barrier of entry to newcomers. But arguably, today’s Internet is much more important to civil society. People from various backgrounds have stepped in the debate, and have told us that it is not just a bunch of engineer’s issues anymore.

It does not have to be this way. As Bruce Schneier said, engineers need to take bake the Internet from 10 years of mishandling by lawyers, telcos, spooks and Big Media.

Not that we could bring the network 10 years back. New usages, new traffic patterns have emerged. Quality of Service is necessary to ensure quality audio and video calls. Caching is necessary to deal with the deluge of video traffic. QoS and caching need to be included in the network neutrality equation.

  • Quality of Service should be end-user controlled. Every provider should let a fraction of the subscriber’s bandwidth be prioritized. Such priority marking should be honored by the provider regardless of the originating application. Of course, the end-user does not have to care about that. Her favourite app to make free calls would do that for her. But this measure guarantees fairness and low barrier of entry for the next-generation of conferencing protocols, websites and apps.

  • Big data caches hidden in every part of the Internet should open up, at least partially. Just like modern web application hosting providers move their data around to bring it close to the service that needs it, the most popular content on the web should be cached in a neutral manner, close to the subscribers, i.e. in the provider’s premises. Protocols should be developed to ensure fairness, and all datacenters serving Internet video should propagate the most popular content regardless of origin, be it a buzzing home-made video or the latest episode of your favourite TV blockbuster.

Nested Virtualization : A Generic CPU Config for Intel and AMD

Nested virtualization with Libvirt is not straightforward. Your mileage may vary depending on your CPU and operating system.

Often, you need to pass the virtualization feature to the guest so that it behaves like a virtualization host. But on Intel, this feature is named “vmx” and on AMD, it is named “svm”.

If like me you have a heterogeneous pool of hypervisors, some Intel and some AMD, and you do not wish to write a different VM definition, here is the CPU node XML I am using to ensure the virtualization extensions will be available in my VM, no matter if running on Intel or AMD :

1
2
3
4
5
6
7
8
<cpu mode='custom' match='exact'>
  <model fallback='allow'>cpu64-rhel5</model>
  <feature policy='optional' name='vmx'/>
  <feature policy='optional' name='svm'/>
  <feature policy='optional' name='fxsr_opt'/>
  <feature policy='optional' name='monitor'/>
  <feature policy='optional' name='mmxext'/>
</cpu>