It is sometimes convenient to be able to throw a whole pile of reports into
the import process through the regular upload process. This is more useful
for testing than uploading old reports, given the parallel import process.
Usage is:
rake reports:repost REPORT_DIR=/path/to/spool CONCURRENCY=16 \
# REPORT_URL=http://dashboard:3000/reports/upload
Concurrently controls the maximum number of concurrent threads POSTing at one
time, and is used to implement the client-side concurrency control.
---
lib/tasks/import_reports.rake | 84 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 84 insertions(+), 0 deletions(-)
diff --git a/lib/tasks/import_reports.rake b/lib/tasks/import_reports.rake
index 46b6db7..b629b3b 100644
--- a/lib/tasks/import_reports.rake
+++ b/lib/tasks/import_reports.rake
@@ -1,6 +1,7 @@
require "#{RAILS_ROOT}/lib/progress_bar"
namespace :reports do
DEFAULT_DIR = '/var/lib/puppet/reports/'
+ DEFAULT_URL = 'http://localhost:3000/reports/upload'
desc "Import stored YAML reports from your puppet report directory (or
$REPORT_DIR)"
task :import => :environment do
@@ -30,4 +31,87 @@ namespace :reports do
STDOUT.puts "#{successes} of #{reports.size} #{plural['report',
successes]} queued"
STDOUT.puts "#{skipped} #{plural['report', skipped]} skipped" if skipped > 0
end
+
+
+ desc "Import by POSTing reports to dashboard in parallel"
+ task :repost => :environment do
+ require 'thread'
+ require 'shellwords'
+
+ report_dir = ENV['REPORT_DIR'] || DEFAULT_DIR
+ url = ENV['REPORT_URL'] || DEFAULT_URL
+ concurrent = ENV['CONCURRENCY'].to_i
+ concurrent = 4 unless concurrent and concurrent > 0
+
+ plural = lambda{|str, count| str + (count != 1 ? 's' : '')}
+ reports = FileList[File.join(report_dir, '**', '*.yaml')]
+
+ STDOUT.puts "Importing #{reports.size} #{plural['report', reports.size]}
from #{report_dir} (#{concurrent} at once)"
+
+ skipped = 0
+ pbar = ProgressBar.new("Importing:", reports.size, STDOUT)
+
+ # Fill up our queue of things to do.
+ work = Queue.new
+ reports.each {|report| work.push report }
+
+ # Put in place our queue of results.
+ results = Queue.new
+
+ # ...and spawn our workers to submit the request.
+ workers = (1..concurrent).map do |n|
+ Thread.new do
+ loop do
+ begin
+ while item = work.pop(true) do
+ cmd = "curl -sSF report=" +
+ Shellwords::shellescape(item) + " " +
+ Shellwords::shellescape(url)
+ output = ''
+ IO.popen(cmd) {|fd| output = fd.read }
+ if $?.success? then
+ results.push true
+ else
+ puts "Failed to submit #{item}: #{output}"
+ results.push false
+ end
+ pbar.inc
+ end
+ rescue ThreadError => e
+ # Seriously, Ruby, *this* is how you expect me to deal with
+ # discovering that the queue is empty? Am I supposed to use a racy
+ # check on size, or prefer to only use a queue when I know exactly
+ # how many items are going to be pushed on ahead of time?
+ raise unless e.message == "queue empty"
+ Thread.exit # ...otherwise, a good exit. :)
+ rescue Exception => e
+ puts e
+ results.push false
+ end
+ end
+ end
+ end
+
+ # Finally, wait for all those workers to exit.
+ workers.each &:join
+ pbar.finish
+
+ # Count the failed results. This is safe because we have joined all
+ # worker threads, so there should be nothing left to do.
+ if work.size > 0
+ raise "ERROR: still had #{work.size} items of work after threads died"
+ end
+ if reports.size != results.size
+ raise "ERROR: missing #{reports.size - results.size} results (expected
#{reports.size}, got #{results.size})"
+ end
+
+ while results.size > 0
+ skipped += 1 unless results.pop(true)
+ end
+
+ successes = reports.size - skipped
+
+ STDOUT.puts "#{successes} of #{reports.size} #{plural['report',
successes]} imported"
+ STDOUT.puts "#{skipped} #{plural['report', skipped]} skipped" if skipped > 0
+ end
end
--
1.7.5.4
--
You received this message because you are subscribed to the Google Groups
"Puppet Developers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/puppet-dev?hl=en.