Ulzurrun de Asanza i Sàez

Month: May 2014

Naming your partitions

I’ve been playing with different names for partitions on Mac OS X and I’ve found two interesting things:

Spaces in the name

Avoid spaces in the name. At all costs. Some make script are not properly written and don’t work when the partition where the file is located contains a space. Usually the output is something like: HD/Users/sumolari/script.c  not found. OS X uses as default name for system’s partition Macintosh HD. You can easily scape the space using: Macintosh\ HD when writing paths in shell, but some developers don’t worry about that and their scripts just don’t compile. I’ve found this with npm modules that use native code (for instance, ZMQ), as well as Ruby gems (Berkshelf was one of them).

Time Machine

Some months ago I added a solid state disk to my MacBook. I use the typical setup for SSD+HD: I installed OS X in my SSD and moved my user folder to the HD. I enabled Time Machine and I didn’t receive any complain from it, so I kept using it as before.

A few days ago I replaced my HD and when I reinstalled OS X I tried to restore my Time Machine backup. It couldn’t restore my user’s home folder because it was located on a different partition than the system. I was worried but as soon as I logged in my not-restored account (which I moved again to the HD) I run Time Machine and it allowed me to restore all the documents that where there.

Not as clean as a checkbox during OS X installation, but definitively more convenient than losing the files or having to backing them up in other disk before formatting the partition.

Target disk mode

I’ve an iMac and a MacBook. Both of them had only two partitions: SSD and HD. SSD had only OS X and some applications installed and HD had my user account. I started my MacBook in target disk mode and then booted the iMac using MacBook’s SSD partition as boot partition. OS X loaded my user account from iMac’s HD partition, so I had the home folder of my user in the iMac but the applications that were installed on my MacBook. Pretty weird. I finally renamed the partitions to be different on each computer.


Provisioning your Vagrant machine

This is just a very short introduction to Vagrant, if you already know a little bit about Chef and Berkshelf you’ll find it disappointing.

We previously saw how to install and use Vagrant but we didn’t talk about how to install applications to that machine. You can use the traditional way and install everything manually compiling it or through a package manager but if you wonder if there is a better way to do this, you’re lucky: there is.

Vagrant supports multiple provisioners. A provisioner is a utility that allows you to automatically install software and change configuration. Although Vagrant supports a bunch of provisioners this post is focused only on Chef.

If you take a look at your Vagrantfile you’ll see this fragment of code near line 90.

[ruby]
config.vm.provision “chef_solo” do |chef|
chef.cookbooks_path = “../my-recipes/cookbooks”
chef.roles_path = “../my-recipes/roles”
chef.data_bags_path = “../my-recipes/data_bags”
chef.add_recipe “mysql”
chef.add_role “web”

# You may also specify custom JSON attributes:
chef.json = { :mysql_password => “foo” }
end
[/ruby]

This is the block telling Chef provisioner  what to install and giving some settings to the installer. You can see three different parts in this chunk of code:

[ruby]
chef.cookbooks_path = “../my-recipes/cookbooks”
chef.roles_path = “../my-recipes/roles”
chef.data_bags_path = “../my-recipes/data_bags”
[/ruby]

Tells Chef where cookbooks, roles and data bags are located (don’t worry, we’ll talk about it later).

[ruby]
chef.add_recipe “mysql”
chef.add_role “web”
[/ruby]

Tells Chef what do you want to install, in this example MySQL and role web (wait for it…).

[ruby]
chef.json = { :mysql_password => “foo” }
[/ruby]

Gives Chef some settings it will use when installing the applications, in this example you ask Chef yo use “foo” as password for MySQL.

Cookbooks, roles and data bags

You’ll probably wondering what are those things. Cookbooks are scripts defining the requirements and steps to install to set up some software. A cookbook can be as simple as adding a file to your .bash_profile or as complex and installing NodeJS by installing gcc, git, cloning NodeJS source’s git repository, compiling and then installing it. But again, don’t worry, most of the times you will use a third-party cookbook. A cookbook may contain more than one installation script (usually referred as recipe).

Roles are a way to set up some common settings for different machines. A simple example:  imagine you are developing a platform where there are nodes serving content to users and nodes performing maintenance tasks, but all of them use Ruby. You would create a role “myplatform-node” which tells Chef to install Ruby, RVM and set up the default Ruby version to the version you want to use. If you decide to upgrade to a new Ruby version you just update your role and reprovision the machines. That is much easier and faster than the alternative: manually adding Ruby, RVM and Ruby’s version setting to Vagrantfile of each one of your nodes (note that there are lots of solutions to this situation).

Data bags are global variables that are can be loaded by a recipe.

Recipes

So we know the basic concepts of Chef and we want to install something in our Vagrant machines, what do we have to do know? Search a cookbook containing the recipe to install the software we want, download it, put it in the cookbooks folder and then provision the machine.

When everything is in its place, you just run:

[bash]
vagrant up
vagrant provision
[/bash]

And Vagrant will start the machine and install everything. Note that the first time you run vagrant up Vagrant will provision the machine, but after that first start you’ll have to manually ask Vagrant to provision it.

Sounds pretty easy, right? Well, think about it. If you have, let’s say, 2 different computers, you’ll have to copy the cookbooks in the right folder in both machines. That’s not a big issue. But what if we talk about our workplace. Distributing those files to each mate’s computer is not the best idea.

But this is just the initial deployment. What if we want to use an updated version of a recipe? We would have to redistribute again the cookbooks. The chance of not being properly distributed is so high that some people have developed a better way to do this: Berkshelf.

Berkshelf

Berkshelf solves this distribution problem with a very simple approach: in a config file named Berksfile you define the URL of the repository where cookbooks will be searched and a list of cookbooks to search and download (optionally you can indicate the version and even a custom path to where the cookbook is located). Berkshelf will process the config file and download (or update) the cookbooks specified in it. When you provision your Vagrant machine Berkshelf will be hooked so instead of provisioning using the paths specified in Vagrantfile, Berkshelf will handle the location of the cookbooks.

Berkfile looks like this:

[ruby]
source “https://api.berkshelf.com”

cookbook “mysql”
cookbook “nginx”, “~> 2.6”
[/ruby]

First line tells Berkshelf where should it look for cookbooks. The other lines tell Berkshelf which cookbooks should download and which version.

And so, by just distributing the Vagrantfile and Bersfile, anybody will be able to provision the machine with the desired version of desired applications.

Setting up Berkshelf

Assuming you’ve installed Vagrant, you’ll have to install Berkshelf and Vagrant Berkshelf plugin. Then you’ll have to add this line to your Vagrantfile to enable Berkshelf:

[ruby]
config.berkshelf.enabled = true
[/ruby]