Select Page

London DevOps

Since DevOps Days last year a number of us have been meeting monthly, it was all a bit under the radar and not announced to the wider public.

The thinking was that we wanted to be sure we will do the meetings roughly monthly rather than start something with a lot of noise and then fizzle out.

We’ve met 4 months in a row and we figured it’s about time to throw open the doors. We are therefore meeting on the 24th of February 2010 at The Priory Bar, we’ll aim to be there from 6 or 7pm on wards.

We’re trying to create a community of like minded people in London – Sysadmins, Ops People, Developers, Puppet Users, Chef Users we do not discriminate. As long as your interested in Agile Infrastructures or in bridging the gap between the Dev and Ops Silos or just want to hang out with a bunch of Systems guys who aren’t stuck in the 1980s you’re welcome to join us. The basic format we’re aiming for is to meet in a pub/restaurant for Lunch or Dinner one month and every second month to try and arrange some meeting with talks.

Our first actual meeting with talks will be in March at a venue provided by Thought Works so the meeting on the 24th is to discuss what we’ll be up to there. We’ll also be very glad to hear from any companies who would like to offer us some space on a bi-monthly basis for our talks.

While on the subject I should mention an event that is coming up. In March London hosts Q-Con with a track specifically for DevOps and I will be there doing a talk as well as some of our other regular members.

Please help spread the word by tweeting with the #ldndevops hashtag. We’ve created a site at http://londondevops.org/ that aggregates some of the blogs of people who we already know about in London who are operating in this space. Please contact me here in comments or on Twitter @ripienaar to get yourself added.

Adding methods to a ruby class

I’m just blogging this because it took me ages to figure out, it seems so simple now but I guess that’s how it usually goes.

The problem I have is I want a plugin to be able to either make a method using the normal Ruby def foo or via some DSL’ish helpers.

class Foo<Base
   register_action(:name => "do_something", :description => "foo")
 
   def do_something_action
   end
 
   register_action(:name => "do_something_else", :description => "foo") do
      # body of the action here
   end
end

The above code should make me two methods – do_something_action and do_something_else_action – they should be identical to viewers from the outside. Here’s the base class that makes this happen correctly:

class Base
   def self.register_input(input, &block)
      name = input[:name]
 
      self.module_eval { define_method("#{name}_action", &block) } if block_given?
   end
end

It’s pretty simple, we’re just using define_method in the scope of the module and that does the rest.

MCollective Agent Introspection

With the new SimpleRPC system in MCollective we have a simple interface to creating agents. The way to call an agent would be:

$ mc-rpc service status service=httpd

This is all fine and well and easy enough, however it requires you to know a lot. You need to know there’s a status action and you need to know it expects a service argument, not great.

I’m busy adding the ability for an agent to register its metadata and interface so that 3rd party tools can dynamically generate useful interfaces.

A sample registration for service agent is:

register_meta(:name        => "SimpleRPC Service Agent",
              :description => "Agent to manage services using the Puppet service provider",
              :author      => "R.I.Pienaar",
              :license     => "GPLv2",
              :version     => 1.1,
              :url         => "http://mcollective-plugins.googlecode.com/",
              :timeout     => 60)
 
["start", "stop", "restart", "status"].each do |action|
    register_input(:action      => action,
                   :name        => "service",
                   :prompt      => "Service Name",
                   :description => "The service to #{action}",
                   :type        => :string,
                   :validation  => '^[a-zA-Z\-_\d]+$',
                   :maxlength   => 30):

This includes all the meta data, versions, timeouts, validation of inputs, prompts and help text for every input argument.

Using this we can now generate dynamic UI’s, and do something like JavaDoc generated documentation. I’ve recorded a little video demonstrating a proof of concept Text UI that uses this data to generate a UI dynamically. This is ripe for integration into tools like Foreman and Puppet Dashboard.

Please watch the video here, best viewed full screen.

MCollective 0.4.3 Auditing

I just released version 0.4.3 of mcollective which brings a new auditing capability to SimpleRPC. Using the auditing system you can log to a file on each host every request or build a centralized auditing system for all requests on all nodes.

We ship a simple plugin that logs to the local harddrive but there is also a community plugin that creates a centralized logging system running over MCollective as a transport.

This is the kind of log the centralized logger will produce:

01/24/10 18:24:20 dev1.my.net> d53a8306f20e9b3a0f7946adccd6eb5e: 01/24/10 18:24:20 caller=uid=500@ids1.my.net agent=iptables action=block
01/24/10 18:24:20 dev1.my.net> d53a8306f20e9b3a0f7946adccd6eb5e: {:ipaddr=>"114.255.136.120"}
01/24/10 18:24:20 dev2.my.net> d53a8306f20e9b3a0f7946adccd6eb5e: 01/24/10 18:24:20 caller=uid=500@ids1.my.net agent=iptables action=block
01/24/10 18:24:20 dev2.my.net> d53a8306f20e9b3a0f7946adccd6eb5e: {:ipaddr=>"114.255.136.120"}
01/24/10 18:24:20 dev3.my.net> d53a8306f20e9b3a0f7946adccd6eb5e: 01/24/10 18:24:20 caller=uid=500@ids1.my.net agent=iptables action=block
01/24/10 18:24:20 dev3.my.net> d53a8306f20e9b3a0f7946adccd6eb5e: {:ipaddr=>"114.255.136.120"}

Here we see 3 nodes that got a request to add 114.255.136.120 to their local firewall. The request was sent by UID 500 on the machine ids1.my.net. The request is of course the same everywhere so the request id is the same on every node, the log shows agent and all parameters passed.

Better way to query facts

Facter has some annoying bug where it won’t always print all facts when called like facter fact, ones that require dynamic lookups etc just won’t print.

This is a long standing bug that doesn’t seem to get any love, so I hacked up a little wrapper that works better.

#!/usr/bin/ruby
 
require 'facter'
require 'puppet'
 
Puppet.parse_config
unless $LOAD_PATH.include?(Puppet[:libdir])
    $LOAD_PATH << Puppet[:libdir]
end
 
facts = Facter.to_hash
 
if ARGV.size > 0
    ARGV.each do |f|
        puts "#{f} => #{facts[f]}" if facts.include?(f)
    end
else
    facts.each_pair do |k,v|
        puts("#{k} => #{v}")
    end
end

It behaves by default as if you ran facter -p but you can supply as many fact names as you want on the command line to print just the ones requested.

$ fctr uptime puppetversion processorcount
uptime => 8 days
puppetversion => 0.25.2
processorcount => 1