Permalink
Fetching contributors…
Cannot retrieve contributors at this time
executable file 251 lines (200 sloc) 6.33 KB
#!/usr/bin/env ruby
require 'mcollective'
include MCollective::RPC
script = nil
node = nil
@options = rpcoptions do |parser, options|
parser.define_head "Shows an inventory for a given node"
parser.banner = "Usage: mc-inventory [options] node"
parser.on('--script SCRIPT', 'Script to run') do |v|
script = v
end
end
if ARGV.length > 0
node = ARGV.shift
end
unless script || node
STDERR.puts("Please specify a node or script to run")
exit 1
end
# Monkey patching array with a in_groups_of method
# that walks an array in groups, pass a block to
# call the block on each sub array
class Array
def in_groups_of(chunk_size, padded_with=nil)
arr = self.clone
# how many to add
padding = chunk_size - (arr.size % chunk_size)
# pad at the end
arr.concat([padded_with] * padding)
# how many chunks we'll make
count = arr.size / chunk_size
# make that many arrays
result = []
count.times {|s| result << arr[s * chunk_size, chunk_size]}
if block_given?
result.each{|a| yield(a)}
else
result
end
end
end
def node_inventory(node, options)
begin
util = rpcclient("rpcutil", :options => @options)
util.identity_filter node
util.progress = false
nodestats = util.custom_request("daemon_stats", {}, node, {"identity" => node})
util.custom_request("inventory", {}, node, {"identity" => node}).each do |resp|
puts "Inventory for #{resp[:sender]}:"
puts
if nodestats.is_a?(Array)
nodestats = nodestats.first[:data]
puts " Server Statistics:"
puts " Version: #{nodestats[:version]}"
puts " Start Time: #{Time.at(nodestats[:starttime])}"
puts " Config File: #{nodestats[:configfile]}"
puts " Process ID: #{nodestats[:pid]}"
puts " Total Messages: #{nodestats[:total]}"
puts " Messages Passed Filters: #{nodestats[:passed]}"
puts " Messages Filtered: #{nodestats[:filtered]}"
puts " Replies Sent: #{nodestats[:replies]}"
puts " Total Processor Time: #{nodestats[:times][:utime]} seconds"
puts " System Time: #{nodestats[:times][:stime]} seconds"
puts
end
puts " Agents:"
resp[:data][:agents].sort.in_groups_of(3, "") do |agents|
puts " %-15s %-15s %-15s" % agents
end
puts
puts " Configuration Management Classes:"
resp[:data][:classes].sort.in_groups_of(2, "") do |klasses|
puts " %-30s %-30s" % klasses
end
puts
puts " Facts:"
resp[:data][:facts].sort_by{|f| f[0]}.each do |f|
puts " #{f[0]} => #{f[1]}"
end
break
end
rescue Exception => e
puts "Could not show inventory for node #{node}: #{e}"
end
end
# Helpers to create a simple DSL for scriptlets
def format(fmt)
@fmt = fmt
end
def fields(&blk)
@flds = blk
end
def identity
@node[:identity]
end
def facts
@node[:facts]
end
def classes
@node[:classes]
end
def agents
@node[:agents]
end
def page_length(len)
@page_length = len
end
def page_heading(fmt)
@page_heading = fmt
end
def page_body(fmt)
@page_body = fmt
end
# Expects a simple printf style format and apply it to
# each node:
#
# inventory do
# format "%s:\t\t%s\t\t%s"
#
# fields { [ identity, facts["serialnumber"], facts["productname"] ] }
# end
def inventory(&blk)
raise "Need to give a block to inventory" unless block_given?
blk.call if block_given?
raise "Need to define a format" if @fmt.nil?
raise "Need to define inventory fields" if @flds.nil?
util = rpcclient("rpcutil", :options => @options)
util.progress = false
util.inventory.each do |resp|
@node = {:identity => resp[:sender],
:facts => resp[:data][:facts],
:classes => resp[:data][:classes],
:agents => resp[:data][:agents]}
puts @fmt % @flds.call
end
end
# Use the ruby formatr gem to build reports using Perls formats
#
# It is kind of ugly but brings a lot of flexibility in report
# writing without building an entire reporting language.
#
# You need to have formatr installed to enable reports like:
#
# formatted_inventory do
# page_length 20
#
# page_heading <<TOP
#
# Node Report @<<<<<<<<<<<<<<<<<<<<<<<<<
# time
#
# Hostname: Customer: Distribution:
# -------------------------------------------------------------------------
# TOP
#
# page_body <<BODY
#
# @<<<<<<<<<<<<<<<< @<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
# identity, facts["customer"], facts["lsbdistdescription"]
# @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
# facts["processor0"]
# BODY
# end
def formatted_inventory(&blk)
require 'formatr'
include FormatR
raise "Need to give a block to formatted_inventory" unless block_given?
blk.call if block_given?
raise "Need to define page body format" if @page_body.nil?
body_fmt = Format.new(@page_heading, @page_body)
body_fmt.setPageLength(@page_length)
time = Time.now
util = rpcclient("rpcutil", :options => @options)
util.progress = false
util.inventory.each do |resp|
@node = {:identity => resp[:sender],
:facts => resp[:data][:facts],
:classes => resp[:data][:classes],
:agents => resp[:data][:agents]}
body_fmt.printFormat(binding)
end
rescue Exception => e
puts "Could not create report: #{e.class}: #{e}"
end
@fmt = nil
@flds = nil
@page_heading = nil
@page_body = nil
@page_length = 40
if script
if File.exist?(script)
load(script)
else
puts "Could not find script to run: #{script}"
exit 1
end
else
node_inventory(node, @options)
end
# vi:tabstop=4:expandtab:ai