require 'json' require 'open3' require 'stringio' require 'logger' # Optionally can specify the command to continue from # Exit on first failure # def time_diff_milli(start, finish) (finish - start) * 1000.0 end def handleIO(stillOpen, ioArray, io, log) if ioArray.include?(io) begin log.write(io.readpartial(4096)) rescue EOFError stillOpen.delete_if{|s| s == io} end end end class Audit def start (id, cmd) self.log( id, cmd, "start", "", 0, "") end def complete (id, cmd, status, msecs, result) self.log( id, cmd, "complete", status, msecs, result) end def status (id, cmd, status, msecs, result) data = { "message" => { "id" => id, "cmd" => cmd, "task" => "status", "status" => status, "elapsed" => msecs, "result" => result } } puts data.to_json File.open(Canzea::config[:logging_root] + '/audit.log', 'a') { |file| file.puts(data.to_json) } end def log (id, cmd, task, status, msecs, result) data = { "message" => { "id" => id, "cmd" => cmd, "task" => task, "status" => status, "elapsed" => msecs, "result" => result } } summary = { "message" => { "id" => id, "cmd" => cmd, "task" => task, "status" => status, "elapsed" => msecs } } puts summary.to_json File.open(Canzea::config[:logging_root] + '/audit.log', 'a') { |file| file.puts(data.to_json) } end end class ManagedError < StandardError end class Worker @test = false def test (t) @test = t end def run(command, start, lines, statusIndicator = false ) audit = Audit.new log = Logger.new(Canzea::config[:logging_root] + '/plans.log') log.info("HANDLING: " + command) File.foreach(command) { |l| if ( l.start_with?('## ') ) log.info "#{lines + 1} Label: " + l elsif ( l.start_with?('#') ) elsif ( /\S/ !~ l ) elsif ( l.chomp.end_with?(".sh") && !l.chomp.end_with?(".atomic.sh") && !l.include?("cp ") && !l.include?("chmod") ) log.info("#{lines + 1} RECURSE: " + l) lines = run l.chomp, start, lines else if ( (lines + 1) < start ) log.info("Skipping : #{lines + 1} #{l}") lines += 1 next end audit.start( "#{lines + 1 }", l.chomp) log.info("#{lines + 1} FOUND: " + l) if @test == false t1 = Time.now begin puts "-- Executing: #{l}" Open3.popen3(l) {|stdin, stdout, stderr, wait_thr| pid = wait_thr.pid # pid of the started process. log_w = StringIO.new stillOpen = [stdout, stderr] while !stillOpen.empty? fhs = select(stillOpen, nil, nil, nil) handleIO(stillOpen, fhs[0], stdout, log_w) handleIO(stillOpen, fhs[0], stderr, log_w) end exit_status = wait_thr.value # wait for it to finish log_w.close_write output = log_w.string output.split(/\n/).each do | line | puts "-- #{line}" end puts "-- Exit Status = #{exit_status}" log.info("STDOUT #{output}") log.info("Exit Status = #{exit_status}") # if exit status is failure then exit right away t2 = Time.now msecs = time_diff_milli t1, t2 audit.complete("#{lines + 1}", l.chomp, exit_status.exitstatus, msecs, output) if (statusIndicator) audit.status("#{lines + 1}", l.chomp, exit_status.exitstatus, msecs, output) end if exit_status.exitstatus != 0 abort() end } rescue => exception msecs = time_diff_milli t1, Time.now audit.complete("#{lines + 1}", l.chomp, "-1", msecs, exception.to_s) raise end else puts "-- TEST -- [#{lines + 1}] FOUND: " + l end end lines += 1 } return lines end end