I recently open-sourced Cartoque, the CMDB tool we use at $work. I want to make it suitable for any medium-sized datacenter in the next few months, but with a bit more than 1 year of specific development for my platform, a significant part of the app isn’t that generic and won’t fit other people needs. Moreover, most of this specific code is poorly tested or not tested at all, because I knew from the beginning that I didn’t want to stick with it. I have to improve that.
The problems with SQL and ActiveRecord
Let’s say it from the beginning, ActiveRecord and AREL are fan-tas-tic tools. I really love them. But it turns out they didn’t fit my needs really well this time.
1- I need first-class citizen custom fields : in Cartoque, users should be able to define structured custom fields (with type, constraints, optionally defining relations to other “tables”) ; these fields should be accessible with the API the same way normal fields are (not with cf.{custom_field_47} (yes I’m looking at you Request Tracker). Redmine has a pretty robust solution for this, but the code is far too complex for my little brain, and it doesn’t provide arbitrary relations to other tables.
2- I need first-class citizen custom “tables” : you may have 2 SaaS products in your company. They each have different properties, hence different custom fields. I need a mechanism for storing and retrieving different attributes for different object types. But maybe you have 3 products, and 2 of them have some common attributes. Same goes for some DCI patterns I’d like to implement (for instance switches, routers, servers and virtual machines all have a processor). If you have some experience with SQL databases, you already imagine the nightmare it would be to implement something in generic tables. Basically it consists in putting denormalized, unstructured data in a structured engine, just for the sake of intellectual pleasure. Not a good idea.
3- I don’t want to deal with secondary joins, callbacks to update a reference table, etc. : today in Cartoque I maintain a secondary model called ConfigurationItem. Each CI has a configuration item, and common relations (such as contact relations) are linked to this model. It means I need to update it with a complicated callback chain, and I add some extra joins everywhere as soon as I want to retrieve those informations. It will become very complicated when I have to expose a dozen CIs in a single page. This is dirty and painful.
4- I need double polymorphic associations, with constraints defined by the user : in a CMDB, nearly every CI could be linked with every other CI. I didn’t find any good solution to provide this kind of link easily, and if possible let the user parameterize it.
5 – SQL databases don’t know how to store complex objects : as I’m writing this, SQL databases don’t support complex column types like JSON. They don’t know how to store Hash, nested Hashes, or Arrays. As soon as you have complex objects to store, modelling them in relational databases becomes a problem, and leads to unnecesay pain.
Enters MongoDB
MongoDB has all this and more.
Kristóf Kovács wrote a fair comparison of so-called “NoSQL” tools. Cartoque is typically the kind of use-case he quotes as an example for MongoDB : “For most things that you would do with MySQL or PostgreSQL, but having predefined columns really holds you back.” I also tried CouchDB (very complicated…), and Riak (which I really love but doesn’t fit this particular use case).
John Nunemaker also wrote an excellent article about ‘Why he thinks Mongo is to databases what Rails was to frameworks’. It’s two years old, a bit old, but still relevant, and I strongly encourage you to check it out. Back in these days MongoDB had some durability problems, and a very tiny ecosystem. But it has resolved its problems and it has gained some popularity in the Rails community. Today there are tons of great gems for the basic functionalities I need in the application (for instance friendly ids, pagination, trees, etc.).
So here I am, now : I’m trying MongoDB with the Mongoid ORM for 3 weeks now, and I’m very happy with it. I might write other posts to cover more technical aspects later, but the best aspect so far is that it forced me to re-think the way I see my data in this application, it put me a bit out of my comfort zone (e.g. SQL databases + ActiveRecord), and it opened a whole new world of great ideas for the future of Cartoque.
Conclusion
Choose the right tool for the job. That’s all ;)
These days I’m discovering Graphite more in depth. To be honest, I saw this slide from Zach Holman and immediately thought I needed the same kind of dashboard.
This future dashboard will be served from a different host than the one hosting Graphite. I want to load data from Graphite into the page through Javascript. Hence standard AJAX calls are impossible because of Same Origin Policy, yet another security rule everyone suffer and no one (at least not me :)) understand.
Before I declare this measure totally stupid and finally take the time to launch lolsecurity.org, let’s have a look at JSONP. The principle is well described on the Wikipedia page. Instead of getting {"a json": "object"} through XMLHttpRequest and AJAX-y friends, this technique inserts a new <script> tag in the DOM and evaluate its content. The client waits for something like callbackFunction({"a json": "object"}) and the resulting JSON object is processed client-side with the callbackFunction() function. This function name should be supplied by the client as a parameter to the URL, though it’s not normalized. As it doesn’t make use of XMLHttpRequest to retrieve the content, it’s not subject to the Same Origin Policy Hell ©.
If you look at jQuery, the $.ajax functions galaxy allow you to use JSONP by setting dataType: "jsonp" in the request configuration. The callback name is often passed through ?callback=blah or jsoncallback=blah in the URL. For Graphite, it should be passed as jsonp=blah though it’s not really well documented^W^W^W^W not documented at all (it took me nearly 2 hours to make it work, the time to be fed up enough to look at the Python source code :/). The final result looks like this :
//graphite host var url = "http://graphite-server/render/"; //add target and everything needed by graphite URL API... url = url + "?target=<graph-data-etc.>"; //set "json" as the response format url = url + "&format=json"; //set "jsonp" parameter to set the callback name //the "?" will automagically be replaced by jQuery url = url + "&jsonp=?"; //finally go! $.getJSON(url, function(data){ //do whatever you want with the result console.log(data); });
It should work out of the box, though a look at your favorite browser’s inspector won’t hurt.
Since Graphite URL generation can be hard, I recommend you use the graphitejs plugin if you use jQuery.
This post is an updated, working and complete version of an older one I published mistakenly.
I suppose you have a functional ruby env for installing Vagrant, and that you have VirtualBox v4.1 already installed.
Let’s go!
mkdir ~/cloudfoundry cd ~/cloudfoundry #(optional) rvm 1.9.2@vagrant --create gem install vagrant vagrant box add ubuntu-lucid-64 http://s3.lds.li/vagrant/lucid64.box vagrant init ubuntu-lucid-64 vagrant up
NB: if you’re getting a general protection fault: 0000 [#3] SMP error, it might be the sign you’re running an other virtualization system on this host (see this post about VirtualBox + kvm errors)
Then connect to your VM with vagrant ssh.
I used to install RVM manually and then install CloudFoundry step by step, manually too. But now the community provided a good install script, so let’s use it directly.
Before that, we should just fix a problem in our Vagrant image, the /home/vagrant/.gem is owned by root:root:
sudo chown vagrant:vagrant /home/vagrant/.gem -R
Then we follow the standard installation steps mentionned in the README:
sudo apt-get install curl -y bash < <(curl -s -k -B https://raw.github.com/cloudfoundry/vcap/master/setup/install)
When it’s finished (it lasted more than 1.5 hour on my old desktop computer!), log out and vagrant ssh again (so that your groups / env get reloaded).
Before starting cloud foundry, I strongly encourage you to adapt the memory and CPU of your VM if you didn’t before (min 1G RAM and 4 cores for my setup).
Then I logged in again to the VM and prepared to start the whole thing:
rvm rvmrc trust ~/cloudfoundry/vcap cd ~/cloudfoundry/vcap bin/vcap start #=>BOOM :/
But I had problems at this point. I think I hit that bug. You should run this commands before starting everything, it won’t hurt if you’re not in my case, because our instance is just a test instance so we don’t need to change default configuration choices:
sed -i 's#.*db:migrate.*#Dir.chdir("\#{File.dirname(__FILE__)}/../cloud_controller") { `bundle exec rake db:migrate` }#' bin/vcapThen you can finally start everything:
cd ~/cloudfoundry/vcap bin/vcap start
You should see:
router : RUNNING cloud_controller : RUNNING dea : RUNNING health_manager : RUNNING stager : RUNNING redis_gateway : RUNNING redis_node : RUNNING mysql_gateway : RUNNING mysql_node : RUNNING mongodb_gateway : RUNNING mongodb_node : RUNNING neo4j_gateway : RUNNING neo4j_node : RUNNING
Some components may appear as “STOPPED” if your VM is too slow (cloud_controller in my case). So maybe it’s a good idea to issue a bin/vcap status afterwards to see if everything has booted properly. If not, you can restart a specific service like that: bin/vcap start cloud_controller. It’s probably a good idea to watch the log ‘live’ too: bin/vcap tail to detect any problem. Be careful, it’s really verbose.
One other step, you need to make a local SSL tunnel so that commands sent to api.vcap.me (a conventional domain in cloud foundry ecosystem, which resolves to 127.0.0.1) are forwarded to the VM. If you find a solution to forward your local 80 port to the VM one, go ahead. But communicating to your vagrant VM directly didn’t seem to be that easy for me, so I uncommented the config.vm.forward_port (forward local 8080 to VM’s 80) in the Vagrantfile, restarted the VM (vagrant halt; vagrant up), and started CF services as described above.
When everything’s ok, log out and, from the host:
gem install vmc vmc target api.vcap.me:8080 vmc info
You should see something like:
VMware's Cloud Application Platform For support visit http://support.cloudfoundry.com Target: http://api.vcap.me:8080 (v0.999) Client: v0.3.14
Now we can (finally!) play with your new toy. First register and login:
vmc register --email foo@bar.com --passwd password vmc login --email foo@bar.com --passwd password
And build our first app (adapted from the README):
mkdir env && cd env
echo -e "require 'rubygems'\nrequire 'sinatra'\nget('/'){ host = ENV['VMC_APP_HOST']; port = ENV['VMC_APP_PORT']; %(<h1>XXXXX Hello from the Cloud! via: #{host}:#{port}</h1>) }" > env.rbThen deploy it, as easy as:
vmc push env --instances 4 --mem 64M --url env.vcap.me -n
In case it doesn’t work, and you want to consult logs manually, apps are stored in /var/vcap.local/dea/apps/ in the VM. Note that you can see an Error on startup even if the application starts correctly, don’t know why.
Anyway, the result in http://env.vcap.me:8080/ should be OK, you’ll see your four instances answer alternatively like a charm.
Run vmc help if you want to scale the app because of an excessive load!
Conclusion: the product seems great, but it’s not really well-documented and it can be hard to find informations or people with the same problems. Community seems to be super-reactive tho. In the past I tried to play with more complex app (rails+mysql) and had other problems, so I let you test and see if you’re happy with CloudFoundry.
EDIT: I confirm it’s fixed in 3.1.0-stable, and this patch is not compatible with the stable version.
This night I upgraded my main app of the moment to Rails 3.1.rc6. I followed this awesome post and everything went fine. I had to fix one or two tests, and now I have to think about what goes to the asset pipeline or not, but everything works fine!
One little gotcha with this version though, Sprockets outputs a lot (and I mean a LOT) of deprecation warnings because of this: https://github.com/rails/rails/issues/2598
The interesting part of this patch can easily be backported in an initializer until 3.1-stable is released. Let’s put it in config/initializers/sprockets_warnings_silencer.rb :
require 'sprockets/helpers/rails_helper' module Sprockets module Helpers module RailsHelper class AssetPaths def digest_for(logical_path) if asset = asset_environment[logical_path] return asset.digest_path end logical_path end def rewrite_asset_path(source, dir) if source[0] == ?/ source else source = digest_for(source) if performing_caching? source = File.join(dir, source) source = "/#{url}" unless source =~ /^\// source end end end end end end
Now let’s explore all the awesome features of Rails 3.1 ! (and first split my bloated CSS and Javascript files)
The choice is not easy in this case…
EDIT: just a quick note, it’s not an other SVG vs Canvas comparison. My “Canvas” version uses pure HTML+jQuery things so there’s a bias I’m totally aware of.
Recently I blogged about an experiment I was making for building logical maps of an application architecture, e.g. servers, components, arrows to represent relations between servers, etc. It was built with HTML’s Canvas and dirty Javascript code, but I was pretty sure I would switch to CoffeeScript and SVG (with RaphaelJS library).
After a day of work, I have started the switch to CoffeeScript and Jasmine. It’s not finished yet, but it’s moving fast, no problem on that side. All the code is now pure client code, I’ve migrated the few functions I had in Ruby/ERB to Javascript. I even started to tweak and read a Cakefile (doc) to ease build actions and organize my code. I’m really impressed with CoffeeScript so far, it’s amazingly concise and has some high-level concepts to make Javascript easier. Feels good !
On the SVG side, I’m not that happy. I managed to have the basic things working :
- draw boxes
- position boxes automatically
- put text in each box
- make boxes draggable
- draw links dynamically between related boxes
Here’s a screenshot of the result :

But I miss a lot of things :
- collision detection ? seems I have to write my own
- grouping management ? same, SVG doesn’t support it, so I had to write some basic stuff to make pieces of text move with their box
- text flow ? nothing, so I have to fix height manually on boxes
- styling elements : SVG doesn’t rely on CSS (I can retrieve properties and translate them, but it’ll be tiresome)
- can’t style rectangle borders under 2px (it’s ugly)
On the other hand, it comes with good things that I won’t have with Canvas :
- drag/drop work on iPhone/iPad
- vectors : you keep high-quality rendering when zooming
- animations : not useful now, but maybe later
- everything is an object, so I won’t have to re-draw the whole map when there’s a change
The repo is finally on github and you can watch a live demo here where both methods are displayed side by side : Canvas on the left, SVG on the right.
Now I don’t really know what to do. Everything would be easier if you could embed HTML trees in an SVG element, but it’s not possible by default. I started to play with a Raphael plugin called Infobox so I keep HTML for representing servers. The idea would be to manage a grid and the boxes only with SVG, and have HTML embedded in it so it solves styling/flow problems. It works with some effort, but it starts to become pretty complicated, and there are still a lot of problems to solve.
It seems there’s no magical solution in the SVG/Canvas world (for now). Any suggestion would be welcome.
Today I’m tired of server-side programming.. And yes, I’m looking at you, SQL ! It’s a pain to persist objects naturally when you have complex data structures. And switching to smarter alternatives such as Riak is not an option since I’m coding for $WORK. So I decided to work on something else.
There are a lot of things to explore in my sysadmin world : high availability, security, monitoring, capacity planning, logs correlation, performance tuning, databases, automated deployments, networking, backups, storage, messaging, virtualization, config management, versionning, etc. There are also many subjects on the management or client relations sides : basically it’s everything that is treated under ITIL, including configuration database (CMDB), provisioning, treating support requests/incidents/problems/changes, building reporting/dashboards, contracts, etc.
I don’t love them all the same way. I even hate a few of them because of the stupid way they’re treated. Anyway, I can’t explore all of the remaining ones. These days I’m really passionate about CMDB and config management, and how I can integrate it with the gazillions of tools we use every day. It’s a hard thing, and I think visualizing things is one of the major lack in today tools. There are some cool things in Service-Now though, but I’m not that rich (and the “diagrams” part is not worth the price).
This night, I started to work on a visual output for the CMDB I build these days. I want to be able to build diagrams for the applications I host, at least semi-automatically. They should represent servers, arrows for network traffic, active/passive clustering, and basic components on each server. Later, I plan to make it dynamic so we can display either components, network parameters, physical machine, location, and maybe even integrate it with the monitoring system so that it eases problems resolution. But enough for the dreams.
I started with a basic canvas and some jQuery to make elements “draggable”, with collision detection. I already had boxes, with some piece of code for dynamically drawing arrows between the boxes. Then with ruby and erb, I made it a bit more dynamic (data are in nested hashes/arrays for now, but it could well have been data extracted from a database). I added some intelligence (on the ruby side, maybe I’ll need to port it to javascript) to position elements automatically, depending on the number of elements on the line, and the elements type. Then I added signs to represent active/passive clusters (hearts for heartbeat and “R” for redhat clusters).
Here’s the result for now :

Boxes are auto-positionned, draggable, they cannot collide, and they’re re-drawn with each drag event. Cluster signs don’t follow their boxes though, because boxes in a same cluster are not linked together for now.
But now I have a problem : I’d like to be able to click on links between servers, to group elements, to provide animations… and it seems it’s not that easy with canvas. Tomorrow I’ll try to explore SVG with the awesome raphaeljs library, and see where it leads.
The second problem I have is my (very) limited skills in Javascript. My code is ugly and not so organized, not even tested. It’s mainly because I always find javascript syntax itself ugly. I’ll try to use CoffeeScript as a therapy to build a smarter component, and if it looks good, I’ll put it on Github.
It’s been a while since I wanted to integrate Redmine with my CAS server at $WORK. Unfortunately, Redmine only supports its integrated login/password, LDAP auth and OpenID. There are existing demands on this topic (#2965 for instance) but Redmine developers always refused to implement such specific authentications in the core itself. I approve this choice, I think they should even drop OpenID, and maybe LDAP support (hard to maintain so many things, the core should be leaner).
Existing solutions
I’m only aware of two existing solutions if you want to authenticate your Redmine users against CAS :
- a blog post titled ‘CASify Redmine’ : it explains how to modify the core to use rubycas-client, definitely not a long-term solution
- a plugin called redmine_cas : it works, but it doesn’t exactly fit my needs :
- it replaces Redmine standard authentication completely : I just want CAS authentication as a comfort option, as some of my users are not registered on the CAS server
- it cannot be configured in the interface : as a datacenter which offers a SaaS product for dozens of users, I want them to be able to configure the CAS server themselves (we have multiple addresses depending on wether your users are on the intranet, extranet or internet)
- there’s an annoying but when clicking on “logout” :
undefined method `destroy' for {}:Hash, though it may be easy to fix
To be honest, I also wanted to try to the OmniAuth authentication framework and see if it could help integrating Redmine with external authentication sources (not only CAS).
OmniAuth
OmniAuth (blog post) is an awesome authentication framework built as a Rack middleware.
It has a pretty simple workflow for external authentication sources. If we take the example of CAS :
- call
/auth/casand you will be redirected to the CAS server (with the needed back url) - after you logged in to your CAS server, you’re redirected to
/auth/cas/callbackand free to do whatever you want with the params returned, stored inrequest.env["omniauth.auth"]; this hash stores at least the “provider” (“cas”) and the “uid” (“jeanbaptiste.barth” for instance)
OmniAuth is covered in 3 railscasts, but the one that has been really helpful is #241 Simple OmniAuth.
The “redmine_omniauth_cas” plugin
I spent some hours last week-end to build the “redmine_omniauth_cas” plugin. The code is on github. It relies on OmniAuth for (optionally) authenticating your users against a CAS server. The CAS server has to be configured in the plugin configuration section. It’s only compatible with Redmine 1.2.0 since latest versions of OmniAuth are not compatible with Rack 1.0.1.
There are currently some limitations I plan to improve in the next versions :
- implement ticket validation when first opening your browser (for now you’ll be considered as logged out if your session has expired on Redmine but your ticket is still valid on the CAS server)
- add a plugin option to hide ‘normal’ login/password form
- authorize on-the-fly registration
I also plan to contribute to OmniAuth and especially the CAS provider. The current implementation is functional but not so flexible, since it doesn’t support OmniAuth’s mechanisms to setup the CAS options at runtime.
Conclusion
This plugin is a first try at using OmniAuth with Redmine, but I could easily imagine building plugins to authenticate against other sources. I hope it will be useful for some of you. I think it could even be a viable option to throw OpenID support out of the core, and let it live its life in a clean plugin. Stay tuned !
Note to myself :
Recently I upgraded my desktop to Ubuntu Natty at $WORK. Some file associations broke, ok. It wasn’t a problem til the moment I tried to open a shared samba device in gnome menu’s shortcuts, and chose the wrong binary to open that. From now, every time I tried to open a shortcut in this menu, LibreOffice was launched, argl :(
The place where this setting was saved has been pretty hard to find, but I finally identified it in $HOME/.local/share/xfce4/helpers/custom-FileManager.desktop. Just removed this file and everything’s ok now.
OK, you’re convinced that Riak is a great database, now you want to use it in your Rails 3 app. You should really have a look at the advices from Basho, and especially the Riak with Rails slides from Sean Cribbs.
So first, let’s install the rich ruby client for Riak, ripple, built on top of riak-client. Simply add the following lines to your Gemfile:
gem 'ripple' #=> riak orm ; installs "riak-client" as a dependency gem 'excon' #=> faster http gem 'yajl-ruby' #=> faster json
…and of course run bundle command.
Then generate your ripple config with:
rails generate ripple
Optionnaly you can configure the config/ripple.yml file. With the environment I used in my previous article, I had to change the riak server’s port (default is 8098, I had to change it to 8091, 92 or 93 for my development cluster).
Then generate a first model:
rails generate ripple:model Article title:string content:text
The generated app/models/article.rb looks like this:
class Article include Ripple::Document property :title, String property :content, String end
You can optionnaly add timestamps! if you want to have created_at/updated_at fields updated automatically by ripple.
You can now test everything runs fine in a rails console session:
>> Article.all => [] >> Article.create(:title => "A shiny title", :content => "Lorem ipsum blah bleh") => <Article:Fp1RZWPRDcDLLjDv8aJ0t3p0C5i created_at=2011-04-23 16:25:13 UTC title="A shiny title" content="Lorem ipsum blah bleh" updated_at=2011-04-23 16:25:13 UTC>
Looks ok, but the key isn’t so pretty. After a quick search on google, it appears that this key is auto-generated by Riak if not provided by the client, and it’s pretty easy to define your own key format. I personnaly wanted the creation date and the title in the key:
def key @key ||= "#{created_at.strftime("%Y%m%d%H%M%S")}-#{title.parameterize}" end
Now it looks better:
>> reload! Reloading... => true >> Article.create(:title => "A shiny title", :content => "Lorem ipsum blah bleh") => <Article:20110423182948-a-shiny-title created_at=2011-04-23 16:29:48 UTC title="A shiny title" content="Lorem ipsum blah bleh" updated_at=2011-04-23 16:29:48 UTC>
It seems there’s a tiny problem with Article.all, since it doesn’t contain the newly created item. I’ll ask about that on the riak mailing list, but it seems Riak client does a bit of caching. If you really need it, reset the cache by hand, it’s ugly but it works:
>> Article.all => [] >> Ripple.client.instance_variable_set(:@bucket_cache,nil) => nil >> Article.all => [<Article:20110423183635-a-shiny-title created_at=2011-04-23 16:36:35 UTC title="A shiny title" content="Lorem ipsum blah bleh" updated_at=2011-04-23 16:36:35 UTC>]
Now, what about the controller side ? This is where Rails 3 has become a powerful solution, it’s database agnostic. I generated a scaffold with the 7 standard crud actions:
rails generate scaffold Article title:string content:text
It works for 6 of the 7 elementary actions, but I must admit I had a tiny problem with the destroy action, because of a bug in ActiveModel. It’s described here with a workaround, so I added those 2 lines in my Article model:
def validation_context=(value); end def initialize(*args); errors; super(*args); end
I’m not really sure which impact it will have on my validations, but validations and links between objects are for the next article. That’s all for today, hope this article will be useful for some of you!
edit: replaced ‘curb’ gem by ‘excon’
It’s been a long time since I wanted to test RIAK, a “NoSQL” (what a fucking stupid word) database from the Basho team. It’s Dynamo-inspired, you can process data through “MapReduce” jobs on server side, and it’s content-agnostic. It can scale easily on numerous nodes and it aims at being strongly fault tolerant, so no node is particular in a riak cluster.
Have you ever heard about the CAP theorem ? In brief, it says that “In a distributed system, you can’t get a perfect Consistency, Availability and Partition tolerance at the same time”. It’s like that, it’s been proved, now you’ll have to live with that. Riak focuses on the A and P sides, which means a Riak cluster is not always perfectly Consistent (it’s not boolean, your consistency needs can be tuned). A first node can have some data, and you might have to wait a certain amount of time before this data is coherent with the node you query. Which is perfectly fine in most cases.
Install Riak
What’s fun with Riak is the scalability thing. If you want to test it, the wiki has a great tutorial about Building a Development Environment. Erlang was a bit too old on my Ubuntu 10.10 (R13B03 instead of required R13B04), so I had to get a fresh version from sources:
#!/bin/sh sudo aptitude install build-essential libncurses5-dev openssl libssl-dev [ -f otp_src_R13B04.tar.gz ] || wget http://erlang.org/download/otp_src_R13B04.tar.gz tar zxvf otp_src_R13B04.tar.gz cd otp_src_R13B04 ./configure && make && sudo make install
Then I installed Riak latest stable release (0.14.1). I could have taken current master branch too, but I wanted something stable for my first steps into :
#!/bin/sh [ -f riak-0.14.1.tar.gz ] || curl -O http://downloads.basho.com/riak/riak-0.14/riak-0.14.1.tar.gz tar zxvf riak-0.14.1.tar.gz mv riak-0.14.1 riak cd riak make all make devrel
It built me 3 nodes as expected, located in ./riak/dev folder. So let’s start the 3 nodes and cluster-ize them :
% cd riak/dev % ./dev1/bin/riak start % ./dev2/bin/riak start % ./dev3/bin/riak start % ./dev2/bin/riak-admin join dev1@127.0.0.1 % ./dev3/bin/riak-admin join dev1@127.0.0.1
Command line
We have 2 binaries :
% dev1/bin/riak
Usage: riak {start|stop|restart|reboot|ping|console|attach}
% dev1/bin/riak-admin
Usage: riak-admin { join | leave | backup | restore | test | status |
reip | js_reload | wait-for-service | ringready |
transfers | remove }riak-admin allows us to see the parameters of a running instance through the status command, and especially the state of our ring (= cluster of riak nodes) :
% dev1/bin/riak-admin status |grep ring_
ring_members : ['dev1@127.0.0.1','dev2@127.0.0.1','dev3@127.0.0.1']
ring_num_partitions : 64
ring_ownership : <<"[{'dev3@127.0.0.1',21},{'dev2@127.0.0.1',21},{'dev1@127.0.0.1',22}]">>
ring_creation_size : 64And we can see if the ring is ready to serve requests :
% dev1/bin/riak-admin ringready
TRUE All nodes agree on the ring ['dev1@127.0.0.1','dev2@127.0.0.1',
'dev3@127.0.0.1']We can even test if a node is able to read/write data :
% dev1/bin/riak-admin test =INFO REPORT==== 21-Dec-2010::18:35:06 === Successfully completed 1 read/write cycle to 'dev1@127.0.0.1'
NB: I didn’t manage to make this test fail, I don’t really know what it tests. Restricting read/write permissions on dev*/data/ doesn’t seem to affect it, but I presume Riak buffers things in memory in such cases, so it would need some more tests…
HTTP Exploration
Riak has a full HTTP API, so it’s dead simple to dialog with your ring (from any of its nodes). It returns JSON, so it’s easy to parse (formatting is mine in the following examples).
You can organize data into buckets, which are containers for storing elements of the same type. You can get informations on a bucket (existing or not) with :
% curl http://localhost:8091/riak/MyBucket
{
"props": {
"name": "MyBucket",
"n_val": 3,
"allow_mult": false,
"last_write_wins": false,
"precommit": [],
"postcommit": [],
"chash_keyfun": {
"mod": "riak_core_util",
"fun": "chash_std_keyfun"
},
"linkfun": {
"mod": "riak_kv_wm_link_walker",
"fun": "mapreduce_linkfun"
},
"old_vclock": 86400,
"young_vclock": 20,
"big_vclock": 50,
"small_vclock": 10,
"r": "quorum",
"w": "quorum",
"dw": "quorum",
"rw": "quorum"
}
}If the bucket doesn’t exist, it will be created as soon as you insert an element in it.
You can get the list of all existing buckets with :
% curl http://localhost:8091/riak?buckets=true
{"buckets":["articles","rekon"]}And get some general stats on the node you query (the result is quite similar to stats on a particular bucket) :
% curl http://localhost:8091/riak/stats
{
"props": {
"name": "stats",
"n_val": 3,
"allow_mult": false,
"last_write_wins": false,
"precommit": [],
"postcommit": [],
"chash_keyfun": {
"mod": "riak_core_util",
"fun": "chash_std_keyfun"
},
"linkfun": {
"mod": "riak_kv_wm_link_walker",
"fun": "mapreduce_linkfun"
},
"old_vclock": 86400,
"young_vclock": 20,
"big_vclock": 50,
"small_vclock": 10,
"r": "quorum",
"w": "quorum",
"dw": "quorum",
"rw": "quorum"
}
}But I wanna haz some GUI !
Not happy with the command line ? Adam Hunter built Rekon, a data browser for your riak node, built as a riak app (only riak objects and javascript, yeah). Installation is pretty simple, in our case for our “dev1” node :
curl -s get.rekonapp.com | node=127.0.0.1:8091 sh
Then navigate to http://localhost:8091/riak/rekon/go, and tadam :

I let you play with it, it’s intuitive enough.
Conclusion
Riak is an amazing piece of software. In future posts, I’ll try to discuss how you can query it from a Rails app with the Ripple client library, and some other exciting things such as deployment and system administration things.