Class MCollective::Application::Inventory
In: plugins/mcollective/application/inventory.rb
Parent: MCollective::Application

Methods

Public Instance methods

[Source]

     # File plugins/mcollective/application/inventory.rb, line 227
227:     def agents
228:         @node[:agents]
229:     end

[Source]

     # File plugins/mcollective/application/inventory.rb, line 223
223:     def classes
224:         @node[:classes]
225:     end

Writes a crude DOT graph to a file

[Source]

     # File plugins/mcollective/application/inventory.rb, line 86
 86:     def collectives_map(file)
 87:         File.open(file, "w") do |graph|
 88:             puts "Retrieving collective info...."
 89:             collectives = get_collectives
 90: 
 91:             graph.puts 'graph {'
 92: 
 93:             collectives[:collectives].keys.sort.each do |collective|
 94:                 graph.puts '   subgraph "%s" {' % [ collective ]
 95: 
 96:                 collectives[:collectives][collective].each do |member|
 97:                     graph.puts '      "%s" -- "%s"' % [ member, collective ]
 98:                 end
 99: 
100:                 graph.puts '   }'
101:             end
102: 
103:             graph.puts '}'
104: 
105:             puts "Graph of #{collectives[:total_nodes]} nodes has been written to #{file}"
106:         end
107:     end

Prints a report of all known sub collectives

[Source]

     # File plugins/mcollective/application/inventory.rb, line 110
110:     def collectives_report
111:         collectives = get_collectives
112: 
113:         puts "   %-30s %s" % [ "Collective", "Nodes" ]
114:         puts "   %-30s %s" % [ "==========", "=====" ]
115: 
116:         collectives[:collectives].sort_by {|key,count| count.size}.each do |collective|
117:             puts "   %-30s %d" % [ collective[0], collective[1].size ]
118:         end
119: 
120:         puts
121:         puts "   %30s %d" % [ "Total nodes:", collectives[:nodes] ]
122:         puts
123:     end

[Source]

     # File plugins/mcollective/application/inventory.rb, line 219
219:     def facts
220:         @node[:facts]
221:     end

[Source]

     # File plugins/mcollective/application/inventory.rb, line 211
211:     def fields(&blk)
212:         @flds = blk
213:     end

Helpers to create a simple DSL for scriptlets

[Source]

     # File plugins/mcollective/application/inventory.rb, line 207
207:     def format(fmt)
208:         @fmt = fmt
209:     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

[Source]

     # File plugins/mcollective/application/inventory.rb, line 299
299:     def formatted_inventory(&blk)
300:         require 'formatr'
301: 
302:         raise "Need to give a block to formatted_inventory" unless block_given?
303: 
304:         blk.call if block_given?
305: 
306:         raise "Need to define page body format" if @page_body.nil?
307: 
308:         body_fmt = FormatR::Format.new(@page_heading, @page_body)
309:         body_fmt.setPageLength(@page_length)
310:         time = Time.now
311: 
312:         util = rpcclient("rpcutil")
313:         util.progress = false
314: 
315:         util.inventory do |t, resp|
316:             @node = {:identity => resp[:sender],
317:                      :facts    => resp[:data][:facts],
318:                      :classes  => resp[:data][:classes],
319:                      :agents   => resp[:data][:agents]}
320: 
321:             body_fmt.printFormat(binding)
322:         end
323:     rescue Exception => e
324:         STDERR.puts "Could not create report: #{e.class}: #{e}"
325:         exit 1
326:     end

Get all the known collectives and nodes that belong to them

[Source]

    # File plugins/mcollective/application/inventory.rb, line 60
60:     def get_collectives
61:         util = rpcclient("rpcutil")
62:         util.progress = false
63: 
64:         collectives = {}
65:         nodes = 0
66:         total = 0
67: 
68:         util.collective_info do |r, cinfo|
69:             begin
70:                 if cinfo[:data] && cinfo[:data][:collectives]
71:                     cinfo[:data][:collectives].each do |collective|
72:                         collectives[collective] ||= []
73:                         collectives[collective]  << cinfo[:sender]
74:                     end
75: 
76:                     nodes += 1
77:                     total += 1
78:                 end
79:             end
80:         end
81: 
82:         {:collectives => collectives, :nodes => nodes, :total_nodes => total}
83:     end

[Source]

     # File plugins/mcollective/application/inventory.rb, line 215
215:     def identity
216:         @node[:identity]
217:     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

[Source]

     # File plugins/mcollective/application/inventory.rb, line 251
251:     def inventory(&blk)
252:         raise "Need to give a block to inventory" unless block_given?
253: 
254:         blk.call if block_given?
255: 
256:         raise "Need to define a format" if @fmt.nil?
257:         raise "Need to define inventory fields" if @flds.nil?
258: 
259:         util = rpcclient("rpcutil")
260:         util.progress = false
261: 
262:         util.inventory do |t, resp|
263:             @node = {:identity => resp[:sender],
264:                      :facts    => resp[:data][:facts],
265:                      :classes  => resp[:data][:classes],
266:                      :agents   => resp[:data][:agents]}
267: 
268:             puts @fmt % @flds.call
269:         end
270:     end

[Source]

     # File plugins/mcollective/application/inventory.rb, line 334
334:     def main
335:         if configuration[:script]
336:             if File.exist?(configuration[:script])
337:                 eval(File.read(configuration[:script]))
338:             else
339:                 raise "Could not find script to run: #{configuration[:script]}"
340:             end
341: 
342:         elsif configuration[:collectivemap]
343:             collectives_map(configuration[:collectivemap])
344: 
345:         elsif configuration[:collectives]
346:             collectives_report
347: 
348:         else
349:             node_inventory
350:         end
351:     end

[Source]

     # File plugins/mcollective/application/inventory.rb, line 125
125:     def node_inventory
126:         node = configuration[:node]
127: 
128:         util = rpcclient("rpcutil")
129:         util.identity_filter node
130:         util.progress = false
131: 
132:         nodestats = util.custom_request("daemon_stats", {}, node, {"identity" => node}).first
133: 
134:         unless nodestats[:statuscode] == 0
135:             STDERR.puts "Failed to retrieve daemon_stats from #{node}: #{nodestats[:statusmsg]}"
136:         else
137:             util.custom_request("inventory", {}, node, {"identity" => node}).each do |resp|
138:                 unless resp[:statuscode] == 0
139:                     STDERR.puts "Failed to retrieve inventory for #{node}: #{resp[:statusmsg]}"
140:                     next
141:                 end
142: 
143:                 data = resp[:data]
144: 
145:                 begin
146:                     puts "Inventory for #{resp[:sender]}:"
147:                     puts
148: 
149:                     nodestats = nodestats[:data]
150: 
151:                     puts "   Server Statistics:"
152:                     puts "                      Version: #{nodestats[:version]}"
153:                     puts "                   Start Time: #{Time.at(nodestats[:starttime])}"
154:                     puts "                  Config File: #{nodestats[:configfile]}"
155:                     puts "                  Collectives: #{data[:collectives].join(', ')}" if data.include?(:collectives)
156:                     puts "              Main Collective: #{data[:main_collective]}" if data.include?(:main_collective)
157:                     puts "                   Process ID: #{nodestats[:pid]}"
158:                     puts "               Total Messages: #{nodestats[:total]}"
159:                     puts "      Messages Passed Filters: #{nodestats[:passed]}"
160:                     puts "            Messages Filtered: #{nodestats[:filtered]}"
161:                     puts "                 Replies Sent: #{nodestats[:replies]}"
162:                     puts "         Total Processor Time: #{nodestats[:times][:utime]} seconds"
163:                     puts "                  System Time: #{nodestats[:times][:stime]} seconds"
164: 
165:                     puts
166: 
167:                     puts "   Agents:"
168:                     if data[:agents].size > 0
169:                         data[:agents].sort.in_groups_of(3, "") do |agents|
170:                             puts "      %-15s %-15s %-15s" % agents
171:                         end
172:                     else
173:                         puts "      No agents installed"
174:                     end
175: 
176:                     puts
177: 
178:                     puts "   Configuration Management Classes:"
179:                     if data[:classes].size > 0
180:                         data[:classes].sort.in_groups_of(2, "") do |klasses|
181:                             puts "      %-30s %-30s" % klasses
182:                         end
183:                     else
184:                         puts "      No classes applied"
185:                     end
186: 
187:                     puts
188: 
189:                     puts "   Facts:"
190:                     if data[:facts].size > 0
191:                         data[:facts].sort_by{|f| f[0]}.each do |f|
192:                             puts "      #{f[0]} => #{f[1]}"
193:                         end
194:                     else
195:                         puts "      No facts known"
196:                     end
197: 
198:                     break
199:                 rescue Exception => e
200:                     STDERR.puts "Failed to display node inventory: #{e.class}: #{e}"
201:                 end
202:             end
203:         end
204:     end

[Source]

     # File plugins/mcollective/application/inventory.rb, line 239
239:     def page_body(fmt)
240:         @page_body = fmt
241:     end

[Source]

     # File plugins/mcollective/application/inventory.rb, line 235
235:     def page_heading(fmt)
236:         @page_heading = fmt
237:     end

[Source]

     # File plugins/mcollective/application/inventory.rb, line 231
231:     def page_length(len)
232:         @page_length = len
233:     end

[Source]

    # File plugins/mcollective/application/inventory.rb, line 49
49:     def post_option_parser(configuration)
50:         configuration[:node] = ARGV.shift if ARGV.size > 0
51:     end

[Source]

    # File plugins/mcollective/application/inventory.rb, line 53
53:     def validate_configuration(configuration)
54:         unless configuration[:node] || configuration[:script] || configuration[:collectives] || configuration[:collectivemap]
55:             raise "Need to specify either a node name, script to run or other options"
56:         end
57:     end

[Validate]