class MCollective::Application::Inventory - mcollective version 2.12.5

# class MCollective::Application::Inventory

### Public Instance Methods

agents() click to toggle source

        # File lib/mcollective/application/inventory.rb
    219 def agents
    220   @node[:agents]
    221 end

classes() click to toggle source

        # File lib/mcollective/application/inventory.rb
    215 def classes
    216   @node[:classes]
    217 end

collectives_map(file) click to toggle source

Writes a crude DOT graph to a file

       # File lib/mcollective/application/inventory.rb
    55 def collectives_map(file)
    56   File.open(file, "w") do |graph|
    57     puts "Retrieving collective info...."
    58     collectives = get_collectives
    59
    60     graph.puts 'graph {'
    61
    62     collectives[:collectives].keys.sort.each do |collective|
    63       graph.puts '   subgraph "%s" {' % [ collective ]
    64
    65       collectives[:collectives][collective].each do |member|
    66         graph.puts '      "%s" -- "%s"' % [ member, collective ]
    67       end
    68
    69       graph.puts '   }'
    70     end
    71
    72     graph.puts '}'
    73
    74     puts "Graph of #{collectives[:total_nodes]} nodes has been written to #{file}"
    75   end
    76 end

collectives_report() click to toggle source

Prints a report of all known sub collectives

       # File lib/mcollective/application/inventory.rb
    79 def collectives_report
    80   collectives = get_collectives
    81
    82   puts "   %-30s %s" % [ "Collective", "Nodes" ]
    83   puts "   %-30s %s" % [ "==========", "=====" ]
    84
    85   collectives[:collectives].sort_by {|key,count| count.size}.each do |collective|
    86     puts "   %-30s %d" % [ collective[0], collective[1].size ]
    87   end
    88
    89   puts
    90   puts "   %30s %d" % [ "Total nodes:", collectives[:nodes] ]
    91   puts
    92 end

facts() click to toggle source

        # File lib/mcollective/application/inventory.rb
    211 def facts
    212   @node[:facts]
    213 end

fields(&blk) click to toggle source

        # File lib/mcollective/application/inventory.rb
    203 def fields(&blk)
    204   @flds = blk
    205 end

format(fmt) click to toggle source

Helpers to create a simple DSL for scriptlets

        # File lib/mcollective/application/inventory.rb
    199 def format(fmt)
    200   @fmt = fmt
    201 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 lib/mcollective/application/inventory.rb
    291 def formatted_inventory(&blk)
    292   require 'formatr'
    293
    294   raise "Need to give a block to formatted_inventory" unless block_given?
    295
    296   blk.call if block_given?
    297
    298   raise "Need to define page body format" if @page_body.nil?
    299
    300   body_fmt = FormatR::Format.new(@page_heading, @page_body)
    301   body_fmt.setPageLength(@page_length)
    302   time = Time.now
    303
    304   util = rpcclient("rpcutil")
    305   util.progress = false
    306
    307   util.inventory do |t, resp|
    308     @node = {:identity => resp[:sender],
    309       :facts    => resp[:data][:facts],
    310       :classes  => resp[:data][:classes],
    311       :agents   => resp[:data][:agents]}
    312
    313     body_fmt.printFormat(binding)
    314   end
    315 rescue Exception => e
    316   STDERR.puts "Could not create report: #{e.class}: #{e}"
    317   exit 1
    318 end

get_collectives() click to toggle source

Get all the known collectives and nodes that belong to them

       # File lib/mcollective/application/inventory.rb
    29 def get_collectives
    30   util = rpcclient("rpcutil")
    31   util.progress = false
    32
    33   collectives = {}
    34   nodes = 0
    35   total = 0
    36
    37   util.collective_info do |r, cinfo|
    38     begin
    39       if cinfo[:data] && cinfo[:data][:collectives]
    40         cinfo[:data][:collectives].each do |collective|
    41           collectives[collective] ||= []
    42           collectives[collective]  << cinfo[:sender]
    43         end
    44
    45         nodes += 1
    46         total += 1
    47       end
    48     end
    49   end
    50
    51   {:collectives => collectives, :nodes => nodes, :total_nodes => total}
    52 end

identity() click to toggle source

        # File lib/mcollective/application/inventory.rb
    207 def identity
    208   @node[:identity]
    209 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 lib/mcollective/application/inventory.rb
    243 def inventory(&blk)
    244   raise "Need to give a block to inventory" unless block_given?
    245
    246   blk.call if block_given?
    247
    248   raise "Need to define a format" if @fmt.nil?
    249   raise "Need to define inventory fields" if @flds.nil?
    250
    251   util = rpcclient("rpcutil")
    252   util.progress = false
    253
    254   util.inventory do |t, resp|
    255     @node = {:identity => resp[:sender],
    256       :facts    => resp[:data][:facts],
    257       :classes  => resp[:data][:classes],
    258       :agents   => resp[:data][:agents]}
    259
    260     puts @fmt % @flds.call
    261   end
    262 end

main() click to toggle source

        # File lib/mcollective/application/inventory.rb
    326 def main
    327   if configuration[:script]
    328     if File.exist?(configuration[:script])
    329       eval(File.read(configuration[:script]))
    330     else
    331       raise "Could not find script to run: #{configuration[:script]}"
    332     end
    333
    334   elsif configuration[:collectivemap]
    335     collectives_map(configuration[:collectivemap])
    336
    337   elsif configuration[:collectives]
    338     collectives_report
    339
    340   else
    341     node_inventory
    342   end
    343 end

node_inventory() click to toggle source

        # File lib/mcollective/application/inventory.rb
     94 def node_inventory
     95   node = configuration[:node]
     96
     97   util = rpcclient("rpcutil")
     98   util.identity_filter node
     99   util.progress = false
    100
    101   nodestats = util.custom_request("daemon_stats", {}, node, {"identity" => node}).first
    102
    103   unless nodestats
    104     STDERR.puts "Did not receive any results from node #{node}"
    105     exit 1
    106   end
    107
    108   unless nodestats[:statuscode] == 0
    109     STDERR.puts "Failed to retrieve daemon_stats from #{node}: #{nodestats[:statusmsg]}"
    110   else
    111     util.custom_request("inventory", {}, node, {"identity" => node}).each do |resp|
    112       unless resp[:statuscode] == 0
    113         STDERR.puts "Failed to retrieve inventory for #{node}: #{resp[:statusmsg]}"
    114         next
    115       end
    116
    117       data = resp[:data]
    118
    119       begin
    120         puts "Inventory for #{resp[:sender]}:"
    121         puts
    122
    123         nodestats = nodestats[:data]
    124
    125         puts "   Server Statistics:"
    126         puts "                      Version: #{nodestats[:version]}"
    127         puts "                   Start Time: #{Time.at(nodestats[:starttime])}"
    128         puts "                  Config File: #{nodestats[:configfile]}"
    129         puts "                  Collectives: #{data[:collectives].join(', ')}" if data.include?(:collectives)
    130         puts "              Main Collective: #{data[:main_collective]}" if data.include?(:main_collective)
    131         puts "                   Process ID: #{nodestats[:pid]}"
    132         puts "               Total Messages: #{nodestats[:total]}"
    133         puts "      Messages Passed Filters: #{nodestats[:passed]}"
    134         puts "            Messages Filtered: #{nodestats[:filtered]}"
    135         puts "             Expired Messages: #{nodestats[:ttlexpired]}"
    136         puts "                 Replies Sent: #{nodestats[:replies]}"
    137         puts "         Total Processor Time: #{nodestats[:times][:utime]} seconds"
    138         puts "                  System Time: #{nodestats[:times][:stime]} seconds"
    139
    140         puts
    141
    142         puts "   Agents:"
    143         if data[:agents].size > 0
    144           data[:agents].sort.in_groups_of(3, "") do |agents|
    145             puts "      %-15s %-15s %-15s" % agents
    146           end
    147         else
    148           puts "      No agents installed"
    149         end
    150
    151         puts
    152
    153         puts "   Data Plugins:"
    154         if data[:data_plugins].size > 0
    155           data[:data_plugins].sort.in_groups_of(3, "") do |plugins|
    156             puts "      %-15s %-15s %-15s" % plugins.map{|p| p.gsub("_data", "")}
    157           end
    158         else
    159           puts "      No data plugins installed"
    160         end
    161
    162         puts
    163
    164         puts "   Configuration Management Classes:"
    165         if data[:classes].size > 0
    166           field_size = MCollective::Util.field_size(data[:classes], 30)
    167           fields_num = MCollective::Util.field_number(field_size)
    168           format = "   " + (" %-#{field_size}s" * fields_num)
    169
    170           data[:classes].sort.in_groups_of(fields_num, "") do |klasses|
    171             puts format % klasses
    172           end
    173         else
    174           puts "      No classes applied"
    175         end
    176
    177         puts
    178
    179         puts "   Facts:"
    180         if data[:facts].size > 0
    181           data[:facts].sort_by{|f| f[0]}.each do |f|
    182             puts "      #{f[0]} => #{f[1]}"
    183           end
    184         else
    185           puts "      No facts known"
    186         end
    187
    188         break
    189       rescue Exception => e
    190         STDERR.puts "Failed to display node inventory: #{e.class}: #{e}"
    191       end
    192     end
    193   end
    194
    195   halt util.stats
    196 end

page_body(fmt) click to toggle source

        # File lib/mcollective/application/inventory.rb
    231 def page_body(fmt)
    232   @page_body = fmt
    233 end

page_heading(fmt) click to toggle source

        # File lib/mcollective/application/inventory.rb
    227 def page_heading(fmt)
    228   @page_heading = fmt
    229 end

page_length(len) click to toggle source

        # File lib/mcollective/application/inventory.rb
    223 def page_length(len)
    224   @page_length = len
    225 end

post_option_parser(configuration) click to toggle source

       # File lib/mcollective/application/inventory.rb
    18 def post_option_parser(configuration)
    19   configuration[:node] = ARGV.shift if ARGV.size > 0
    20 end

validate_configuration(configuration) click to toggle source

       # File lib/mcollective/application/inventory.rb
    22 def validate_configuration(configuration)
    23   unless configuration[:node] || configuration[:script] || configuration[:collectives] || configuration[:collectivemap]
    24     raise "Need to specify either a node name, script to run or other options"
    25   end
    26 end