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