by R.I. Pienaar | Feb 11, 2010 | Front Page
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.
by R.I. Pienaar | Feb 5, 2010 | Uncategorized
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 |
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 |
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.
by R.I. Pienaar | Feb 3, 2010 | Uncategorized
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 |
$ 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): |
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.
by R.I. Pienaar | Jan 24, 2010 | Code
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"} |
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.
by R.I. Pienaar | Jan 14, 2010 | Code
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 |
#!/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 |
$ fctr uptime puppetversion processorcount
uptime => 8 days
puppetversion => 0.25.2
processorcount => 1