class MCollective::Application::Inventory

Public Instance Methods

agents() click to toggle source
# File plugins/mcollective/application/inventory.rb, line 227
def agents
    @node[:agents]
end
classes() click to toggle source
# File plugins/mcollective/application/inventory.rb, line 223
def classes
    @node[:classes]
end
collectives_map(file) click to toggle source

Writes a crude DOT graph to a file

# File plugins/mcollective/application/inventory.rb, line 86
def collectives_map(file)
    File.open(file, "w") do |graph|
        puts "Retrieving collective info...."
        collectives = get_collectives

        graph.puts 'graph {'

        collectives[:collectives].keys.sort.each do |collective|
            graph.puts '   subgraph "%s" {' % [ collective ]

            collectives[:collectives][collective].each do |member|
                graph.puts '      "%s" -- "%s"' % [ member, collective ]
            end

            graph.puts '   }'
        end

        graph.puts '}'

        puts "Graph of #{collectives[:total_nodes]} nodes has been written to #{file}"
    end
end
collectives_report() click to toggle source

Prints a report of all known sub collectives

# File plugins/mcollective/application/inventory.rb, line 110
def collectives_report
    collectives = get_collectives

    puts "   %-30s %s" % [ "Collective", "Nodes" ]
    puts "   %-30s %s" % [ "==========", "=====" ]

    collectives[:collectives].sort_by {|key,count| count.size}.each do |collective|
        puts "   %-30s %d" % [ collective[0], collective[1].size ]
    end

    puts
    puts "   %30s %d" % [ "Total nodes:", collectives[:nodes] ]
    puts
end
facts() click to toggle source
# File plugins/mcollective/application/inventory.rb, line 219
def facts
    @node[:facts]
end
fields(&blk) click to toggle source
# File plugins/mcollective/application/inventory.rb, line 211
def fields(&blk)
    @flds = blk
end
format(fmt) click to toggle source

Helpers to create a simple DSL for scriptlets

# File plugins/mcollective/application/inventory.rb, line 207
def format(fmt)
    @fmt = fmt
end
formatted_inventory(&blk) click to toggle source

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
# File plugins/mcollective/application/inventory.rb, line 299
def formatted_inventory(&blk)
    require '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 = FormatR::Format.new(@page_heading, @page_body)
    body_fmt.setPageLength(@page_length)
    time = Time.now

    util = rpcclient("rpcutil")
    util.progress = false

    util.inventory do |t, 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
    STDERR.puts "Could not create report: #{e.class}: #{e}"
    exit 1
end
get_collectives() click to toggle source

Get all the known collectives and nodes that belong to them

# File plugins/mcollective/application/inventory.rb, line 60
def get_collectives
    util = rpcclient("rpcutil")
    util.progress = false

    collectives = {}
    nodes = 0
    total = 0

    util.collective_info do |r, cinfo|
        begin
            if cinfo[:data] && cinfo[:data][:collectives]
                cinfo[:data][:collectives].each do |collective|
                    collectives[collective] ||= []
                    collectives[collective]  << cinfo[:sender]
                end

                nodes += 1
                total += 1
            end
        end
    end

    {:collectives => collectives, :nodes => nodes, :total_nodes => total}
end
identity() click to toggle source
# File plugins/mcollective/application/inventory.rb, line 215
def identity
    @node[:identity]
end
inventory(&blk) click to toggle source

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
# File plugins/mcollective/application/inventory.rb, line 251
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")
    util.progress = false

    util.inventory do |t, resp|
        @node = {:identity => resp[:sender],
                 :facts    => resp[:data][:facts],
                 :classes  => resp[:data][:classes],
                 :agents   => resp[:data][:agents]}

        puts @fmt % @flds.call
    end
end
main() click to toggle source
# File plugins/mcollective/application/inventory.rb, line 334
def main
    if configuration[:script]
        if File.exist?(configuration[:script])
            eval(File.read(configuration[:script]))
        else
            raise "Could not find script to run: #{configuration[:script]}"
        end

    elsif configuration[:collectivemap]
        collectives_map(configuration[:collectivemap])

    elsif configuration[:collectives]
        collectives_report

    else
        node_inventory
    end
end
node_inventory() click to toggle source
# File plugins/mcollective/application/inventory.rb, line 125
def node_inventory
    node = configuration[:node]

    util = rpcclient("rpcutil")
    util.identity_filter node
    util.progress = false

    nodestats = util.custom_request("daemon_stats", {}, node, {"identity" => node}).first

    unless nodestats[:statuscode] == 0
        STDERR.puts "Failed to retrieve daemon_stats from #{node}: #{nodestats[:statusmsg]}"
    else
        util.custom_request("inventory", {}, node, {"identity" => node}).each do |resp|
            unless resp[:statuscode] == 0
                STDERR.puts "Failed to retrieve inventory for #{node}: #{resp[:statusmsg]}"
                next
            end

            data = resp[:data]

            begin
                puts "Inventory for #{resp[:sender]}:"
                puts

                nodestats = nodestats[:data]

                puts "   Server Statistics:"
                puts "                      Version: #{nodestats[:version]}"
                puts "                   Start Time: #{Time.at(nodestats[:starttime])}"
                puts "                  Config File: #{nodestats[:configfile]}"
                puts "                  Collectives: #{data[:collectives].join(', ')}" if data.include?(:collectives)
                puts "              Main Collective: #{data[:main_collective]}" if data.include?(:main_collective)
                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

                puts "   Agents:"
                if data[:agents].size > 0
                    data[:agents].sort.in_groups_of(3, "") do |agents|
                        puts "      %-15s %-15s %-15s" % agents
                    end
                else
                    puts "      No agents installed"
                end

                puts

                puts "   Configuration Management Classes:"
                if data[:classes].size > 0
                    data[:classes].sort.in_groups_of(2, "") do |klasses|
                        puts "      %-30s %-30s" % klasses
                    end
                else
                    puts "      No classes applied"
                end

                puts

                puts "   Facts:"
                if data[:facts].size > 0
                    data[:facts].sort_by{|f| f[0]}.each do |f|
                        puts "      #{f[0]} => #{f[1]}"
                    end
                else
                    puts "      No facts known"
                end

                break
            rescue Exception => e
                STDERR.puts "Failed to display node inventory: #{e.class}: #{e}"
            end
        end
    end
end
page_body(fmt) click to toggle source
# File plugins/mcollective/application/inventory.rb, line 239
def page_body(fmt)
    @page_body = fmt
end
page_heading(fmt) click to toggle source
# File plugins/mcollective/application/inventory.rb, line 235
def page_heading(fmt)
    @page_heading = fmt
end
page_length(len) click to toggle source
# File plugins/mcollective/application/inventory.rb, line 231
def page_length(len)
    @page_length = len
end
post_option_parser(configuration) click to toggle source
# File plugins/mcollective/application/inventory.rb, line 49
def post_option_parser(configuration)
    configuration[:node] = ARGV.shift if ARGV.size > 0
end
validate_configuration(configuration) click to toggle source
# File plugins/mcollective/application/inventory.rb, line 53
def validate_configuration(configuration)
    unless configuration[:node] || configuration[:script] || configuration[:collectives] || configuration[:collectivemap]
        raise "Need to specify either a node name, script to run or other options"
    end
end