diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/dsh/application/dsh.rb mcollective-plugins-0.0.0~git20120507.df2fa81/agent/dsh/application/dsh.rb --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/dsh/application/dsh.rb 1970-01-01 01:00:00.000000000 +0100 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/dsh/application/dsh.rb 2012-04-25 15:00:16.000000000 +0100 @@ -0,0 +1,16 @@ +# Dancers Shell Application +class MCollective::Application::Dsh "File to manage", - :arguments => ["--file FILE", "-f FILE"], - :required => true + :description => "File to manage", + :arguments => ["--file FILE", "-f FILE"], + :required => true option :details, - :description => "Show full file details", - :arguments => ["--details", "-d"], - :type => :bool + :description => "Show full file details", + :arguments => ["--details", "-d"], + :type => :bool def post_option_parser(configuration) configuration[:command] = ARGV.shift if ARGV.size > 0 diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/nettest/agent/nettest.ddl mcollective-plugins-0.0.0~git20120507.df2fa81/agent/nettest/agent/nettest.ddl --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/nettest/agent/nettest.ddl 2011-12-14 16:18:41.000000000 +0000 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/nettest/agent/nettest.ddl 2012-04-25 15:00:16.000000000 +0100 @@ -2,7 +2,7 @@ :description => "Agent to do network tests from a mcollective host", :author => "Dean Smith ", :license => "BSD", - :version => "1.0", + :version => "2.1", :url => "http://github.com/deasmi", :timeout => 60 @@ -10,39 +10,40 @@ display :always input :fqdn, - :prompt => "FQDN", - :description => "The fully qualified domain name to ping", - :type => :string, - :validation => '^.+$', - :optional => false, - :maxlength => 80 - + :prompt => "FQDN", + :description => "The fully qualified domain name to ping", + :type => :string, + :validation => '^.+$', + :optional => false, + :maxlength => 80 + output :rtt, - :description => "The round trip time in ms", - :display_as=>"RTT" + :description => "The round trip time in ms", + :display_as=>"RTT" end - + action "connect", :description => "Check connectivity of remote server on port" do - display :always + display :always input :fqdn, - :prompt => "FQDN", - :description => "The fully qualified domain name to ping", - :validation => '^.+$', - :type => :string, - :optional => false, - :maxlength => 80 + :prompt => "FQDN", + :description => "The fully qualified domain name to ping", + :validation => '^.+$', + :type => :string, + :optional => false, + :maxlength => 80 input :port, - :prompt => "Port", - :description => "The port to connect on", - :validation => '^[0-9]+$', - :type => :string, - :optional => false - + :prompt => "Port", + :description => "The port to connect on", + :validation => '^[0-9]+$', + :type => :string, + :maxlength => 4, + :optional => false + output :connect, - :description => "Can we connect", - :display_as=>"connected" + :description => "Can we connect", + :display_as=>"connected" -end \ No newline at end of file +end diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/nettest/agent/nettest.rb mcollective-plugins-0.0.0~git20120507.df2fa81/agent/nettest/agent/nettest.rb --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/nettest/agent/nettest.rb 2011-12-14 16:18:41.000000000 +0000 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/nettest/agent/nettest.rb 2012-04-25 15:00:16.000000000 +0100 @@ -10,46 +10,44 @@ :description => "Agent to do network tests from a mcollective host", :author => "Dean Smith", :license => "BSD", - :version => "2.0", + :version => "2.1", :url => "http://github.com/deasmi", :timeout => 60 action "ping" do - validate :fqdn,String + validate :fqdn, String fqdn = request[:fqdn] icmp = Net::Ping::ICMP.new(fqdn) if icmp.ping? then - reply[:rtt] = (icmp.duration*1000).to_s + reply[:rtt] = (icmp.duration * 1000).to_s else - reply[:rtt]="Host did not respond" + reply[:rtt] = "Host did not respond" end end action "connect" do - - validate :fqdn,String - validate :port,String + validate :fqdn, String + validate :port, String fqdn = request[:fqdn] - port = request[:port] + port = Integer(request[:port]) begin Timeout::timeout(2) do begin - t=TCPSocket.new(fqdn,port) - rescue - reply[:connect]="Connection Refused" - else - reply[:connect] = "Connected" + t = TCPSocket.new(fqdn, port) t.close + reply[:connect] = "Connected" + rescue + reply[:connect] = "Connection Refused" end end rescue Timeout::Error - reply[:connect]="Connection timeout" + reply[:connect] = "Connection timeout" end end end diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/nettest/application/nettest.rb mcollective-plugins-0.0.0~git20120507.df2fa81/agent/nettest/application/nettest.rb --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/nettest/application/nettest.rb 2011-12-14 16:18:41.000000000 +0000 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/nettest/application/nettest.rb 2012-04-25 15:00:16.000000000 +0100 @@ -11,45 +11,12 @@ connect - check connectivity of remote host on specific port END_OF_USAGE - def print_statistics(statistics, action_statistics, type) - print "\n---- nettest summary ----\n" - puts " Nodes: #{statistics[:responses] + - statistics[:noresponsefrom].size} / #{statistics[:responses]}" - print " Results: " - - if action_statistics.size > 0 - case type - when /^ping$/ - times = action_statistics[:ping] - - sum = times.inject(0) { |v, i| v + i } - average = sum / times.size.to_f - - printf("replies=%d, maximum=%.3f ms, " + - "minimum=%.3f ms, average=%.3f ms", times.size, - times.max, times.min, average) - - when /^connect$/ - printf("connected=%d, connection refused=%d, " + - "timed out=%d", action_statistics[:connect][0], - action_statistics[:connect][1], - action_statistics[:connect][2]) - end - else - print "No responses received" - end - - printf("\n Elapsed Time: %.2f s\n\n", statistics[:blocktime]) - end - def post_option_parser(configuration) if ARGV.size < 2 raise "Please specify an action and optional arguments" else - # # We trust that validation will be handled correctly # as per accompanying DDL file ... - # action = ARGV.shift host_name = ARGV.shift @@ -60,11 +27,11 @@ end case action - when /^ping$/ - arguments = { :fqdn => host_name } - when /^connect$/ - arguments = { :fqdn => host_name, - :port => remote_port } + when /^ping$/ + arguments = {:fqdn => host_name} + when /^connect$/ + arguments = {:fqdn => host_name, + :port => remote_port} end configuration[:action] = action @@ -73,17 +40,14 @@ end def validate_configuration(configuration) - # # We have to ask this question because you do NOT want # your entire network of bazillion machines to simply # go and hammer some poor remote host ... You may get # your network blocked or whatnot, and that would be # quite an unpleasant thing to have place so better to # be sorry and safe ... - # if MCollective::Util.empty_filter?(options[:filter]) - print "Do you really want to perform network " + - "tests unfiltered? (y/n): " + print "Do you really want to perform network tests unfiltered? (y/n): " STDOUT.flush @@ -92,27 +56,85 @@ end end + def print_statistics(statistics, action_statistics, type) + puts "\n---- nettest summary ----" + puts " Nodes: %d / %d" % [statistics[:responses] + statistics[:noresponsefrom].size, statistics[:responses]] + + if action_statistics.size > 0 + case type + when "ping" + times = action_statistics[:ping] + + sum = times.inject(0) { |v, i| v + i } + average = sum / times.size.to_f + + puts " Results: replies=%d, maximum=%.3f ms, minimum=%.3f ms, average=%.3f ms" % [times.size, times.max, times.min, average] + + when "connect" + puts " Results: connected=%d, connection refused=%d, timed out=%d" % [action_statistics[:connect][0], action_statistics[:connect][1], action_statistics[:connect][2]] + end + else + puts " Results: No responses received" + end + + puts " Elapsed Time: %.2f s\n" % [ statistics[:blocktime] ] + end + + def process_connect_result(result, node, action_statistics, verbose) + action_statistics[:connect] ||= [ 0, 0, 0 ] + + # This is to be in line with the usual format of output ... + result = result.tr("A-Z", "a-z") + + case result + when "connected" + action_statistics[:connect][0] += 1 + + when "refused" + action_statistics[:connect][1] += 1 + + when "timeout" + action_statistics[:connect][2] += 1 + end + + if verbose + puts "%-40s status=%s\n\t\t%s" % [node[:sender], result, node[:statusmsg]] + else + puts "%-40s status=%s" % [node[:sender], result] + end + end + + def process_ping_result(result, node, action_statistics, verbose) + action_statistics[:ping] ||= [] + + result = Float(result) rescue 0.0 + + if verbose + puts "%-40s time=%.3f\n\t\t%s" % [node[:sender], result, node[:statusmsg]] + else + puts "%-40s time=%.3f" % [node[:sender], result] + end + + action_statistics[:ping] << result + end + def main action_statistics = {} - action = configuration[:action] + action = configuration[:action] arguments = configuration[:arguments] - rpc_nettest = rpcclient("nettest", { :options => options }) + rpc_nettest = rpcclient("nettest", {:options => options}) rpc_nettest.send(action, arguments).each do |node| - # We want new line here ... puts if action_statistics.size.zero? and not rpc_nettest.progress - sender = node[:sender] - data = node[:data] + data = node[:data] - # # If the status code is non-zero and data is empty then we # assume that something out of an ordinary had place and # therefore assume that there was some sort of error ... - # unless node[:statuscode].zero? and data result = "error" else @@ -120,52 +142,15 @@ end case action - when /^ping$/ - action_statistics[:ping] ||= [] + when "ping" + process_ping_result(result, node, action_statistics, rpc_nettest.verbose) - if result.match(/^[0-9\.]+$/) - action_statistics[:ping] << result.to_f - result = sprintf("%.3f", result) - else - action_statistics[:ping] << 0.0 - end - - if rpc_nettest.verbose - printf("%-40s time=%s\n", sender, result) - puts "\t\t#{node[:statusmsg]}" - else - printf("%-40s time=%s\n", sender, result) - end - - when /^connect$/ - action_statistics[:connect] ||= [ 0, 0, 0 ] - - # This is to be in line with the usual format of output ... - result = result.tr("A-Z", "a-z") - - case result - when /^connected$/ - action_statistics[:connect][0] += 1 - when /refused$/ - action_statistics[:connect][1] += 1 - when /timeout$/ - action_statistics[:connect][2] += 1 - end - - if rpc_nettest.verbose - printf("%-40s status=%s\n", sender, result) - puts "\t\t#{node[:statusmsg]}" - else - printf("%-40s status=%s\n", sender, result) - end + when "connect" + process_connect_result(result, node, action_statistics, rpc_nettest.verbose) end end - rpc_nettest.disconnect - print_statistics(rpc_nettest.stats, action_statistics, action) end end end - -# vim: set ts=4 sw=4 et : diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/nettest/spec/nettest_agent_spec.rb mcollective-plugins-0.0.0~git20120507.df2fa81/agent/nettest/spec/nettest_agent_spec.rb --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/nettest/spec/nettest_agent_spec.rb 1970-01-01 01:00:00.000000000 +0100 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/nettest/spec/nettest_agent_spec.rb 2012-04-25 15:00:16.000000000 +0100 @@ -0,0 +1,82 @@ +#!/usr/bin/env rspec +require 'spec_helper' + +describe "nettest agent" do + before do + agent_file = File.join([File.dirname(__FILE__), "../agent/nettest.rb"]) + @agent = MCollective::Test::LocalAgentTest.new("nettest", :agent_file => agent_file).plugin + @agent.instance_variable_set("@lockfile", "spec_test_lock_file") + @agent.instance_variable_set("@pidfile", "spec_test_pid_file") + end + + describe "#meta" do + it "should have valid metadata" do + @agent.should have_valid_metadata + end + end + + describe "#ping" do + it "should fail for non string fqdns" do + result = @agent.call(:ping, :fqdn => nil) + result.should be_invalid_data_error + + result = @agent.call(:ping) + result.should be_missing_data_error + end + + it "should set correct rtt if it can ping the host" do + icmp = mock + icmp.expects("ping?").returns(true) + icmp.expects(:duration).returns(0.001) + + Net::Ping::ICMP.expects(:new).with("rspec").returns(icmp) + + result = @agent.call(:ping, :fqdn => "rspec") + result.should be_successful + result.should have_data_items(:rtt => "1.0") + end + + it "should return failure when it cannot ping" do + icmp = mock + icmp.expects("ping?").returns(false) + + Net::Ping::ICMP.expects(:new).with("rspec").returns(icmp) + + result = @agent.call(:ping, :fqdn => "rspec") + result.should be_successful + result.should have_data_items(:rtt => "Host did not respond") + end + end + + describe "#connect" do + it "should fail for invalid fqdn and port" do + @agent.call(:connect).should be_missing_data_error + @agent.call(:connect, :fqdn => "rspec").should be_missing_data_error + @agent.call(:connect, :port => "rspec").should be_missing_data_error + end + + it "should handle timeout errors on connection" do + TCPSocket.expects(:new).raises(Timeout::Error) + result = @agent.call(:connect, :fqdn => "rspec", :port => "80") + result.should be_successful + result.should have_data_items(:connect => "Connection timeout") + end + + it "should report connection refused errors" do + TCPSocket.expects(:new).raises(Errno::ECONNREFUSED) + result = @agent.call(:connect, :fqdn => "rspec", :port => "80") + result.should be_successful + result.should have_data_items(:connect => "Connection Refused") + end + + it "should report connected status correctly" do + socket = mock + socket.expects(:close) + + TCPSocket.expects(:new).with("rspec", 80).returns(socket) + result = @agent.call(:connect, :fqdn => "rspec", :port => "80") + result.should be_successful + result.should have_data_items(:connect => "Connected") + end + end +end diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/nettest/spec/nettest_application_spec.rb mcollective-plugins-0.0.0~git20120507.df2fa81/agent/nettest/spec/nettest_application_spec.rb --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/nettest/spec/nettest_application_spec.rb 1970-01-01 01:00:00.000000000 +0100 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/nettest/spec/nettest_application_spec.rb 2012-04-25 15:00:16.000000000 +0100 @@ -0,0 +1,174 @@ +#!/usr/bin/env rspec +require 'spec_helper' + +module Mcollective + describe "nettest application" do + before do + application_file = File.join([File.dirname(__FILE__), "../application/nettest.rb"]) + @util = MCollective::Test::ApplicationTest.new("nettest", :application_file => application_file) + @app = @util.plugin + end + + describe "#application_description" do + it "should have a description" do + @app.should have_a_description + end + end + + describe "#post_option_parser" do + it "should raise an exception for no arguments" do + expect { + @app.post_option_parser({}) + }.to raise_error("Please specify an action and optional arguments") + end + + it "should raise an exception for unknown actions" do + ARGV << "action" + ARGV << "rspec" + + expect { + @app.post_option_parser({}) + }.to raise_error("Action can only to be ping or connect") + end + + it "should set fqdn and port correctly in the configuration" do + ARGV << "ping" + ARGV << "rspec" + + configuration = {} + @app.post_option_parser(configuration) + + configuration.should == {:action=>"ping", :arguments=>{:fqdn=>"rspec"}} + + ARGV << "connect" + ARGV << "rspec" + ARGV << "80" + + configuration = {} + @app.post_option_parser(configuration) + + configuration.should == {:action=>"connect", :arguments=>{:port=>"80", :fqdn=>"rspec"}} + end + end + + describe "#validate_configuration" do + it "should check if no filter is supplied and ask confirmation expecting y or yes" do + MCollective::Util.expects("empty_filter?").returns(true).twice + + @app.expects(:print).with("Do you really want to perform network tests unfiltered? (y/n): ").twice + @app.expects(:options).returns({}).twice + STDIN.expects(:gets).returns("y") + @app.expects("exit!").never + @app.validate_configuration({}) + + STDIN.expects(:gets).returns("yes") + @app.validate_configuration({}) + end + + it "should exit unless y or yes is supplied" do + MCollective::Util.expects("empty_filter?").returns(true) + + @app.expects(:print).with("Do you really want to perform network tests unfiltered? (y/n): ") + @app.expects(:options).returns({}) + + @app.expects("exit!") + STDIN.expects(:gets).returns("n") + @app.validate_configuration({}) + end + end + + describe "#process_connect_result" do + it "should correctly handle connected results" do + @app.expects(:puts).with(regexp_matches(/rspec.+status=connected/)) + @app.process_connect_result("connected", {:sender => "rspec", :statusmsg => "OK"}, (stats = {}), false) + stats.should == {:connect => [1, 0, 0]} + end + + it "should correctly handle refused results" do + @app.expects(:puts).with(regexp_matches(/rspec.+status=refused/)) + @app.process_connect_result("refused", {:sender => "rspec", :statusmsg => "OK"}, (stats = {}), false) + stats.should == {:connect => [0, 1, 0]} + end + + it "should correctly handle timeout results" do + @app.expects(:puts).with(regexp_matches(/rspec.+status=timeout/)) + @app.process_connect_result("timeout", {:sender => "rspec", :statusmsg => "OK"}, (stats = {}), false) + stats.should == {:connect => [0, 0, 1]} + end + + it "should support verbose output" do + @app.expects(:puts).with(regexp_matches(/rspec.+status=timeout.+OK/m)) + @app.process_connect_result("timeout", {:sender => "rspec", :statusmsg => "OK"}, (stats = {}), true) + stats.should == {:connect => [0, 0, 1]} + end + end + + describe "#process_ping_result" do + it "should track ping stats correctly" do + @app.expects(:puts).with(regexp_matches(/rspec.+time=1.100/)) + @app.expects(:puts).with(regexp_matches(/rspec.+time=1.200/)) + @app.process_ping_result("1.1", {:sender => "rspec", :statusmsg => "OK"}, (stats = {}), false) + @app.process_ping_result("1.2", {:sender => "rspec", :statusmsg => "OK"}, stats, false) + stats.should == {:ping => [1.1, 1.2]} + end + + it "should support verbose output" do + @app.expects(:puts).with(regexp_matches(/rspec.+time=1.100.+OK/m)) + @app.process_ping_result("1.1", {:sender => "rspec", :statusmsg => "OK"}, {}, true) + end + end + + describe "#print_statistics" do + it "should support ping statistics" do + @app.expects(:puts).with(regexp_matches(/Nodes: 2 \/ 2/)) + @app.expects(:puts).with(regexp_matches(/Results: replies=2, maximum=2.000 ms, minimum=1.000 ms, average=1.500 ms/)) + @app.expects(:puts).with(regexp_matches(/Elapsed.+2.00 s/)) + @app.print_statistics({:responses => 2, :noresponsefrom => [], :blocktime => 2}, {:ping => [1.0, 2.0]}, "ping") + end + + it "should support connect statistics" do + @app.expects(:puts).with(regexp_matches(/Nodes: 2 \/ 2/)) + @app.expects(:puts).with(regexp_matches(/Results: connected=1, connection refused=0, timed out=1/)) + @app.expects(:puts).with(regexp_matches(/Elapsed.+2.00 s/)) + @app.print_statistics({:responses => 2, :noresponsefrom => [], :blocktime => 2}, {:connect => [1, 0, 1]}, "connect") + end + + it "should support empty results" do + @app.expects(:puts).with(regexp_matches(/Results: No responses received/)) + @app.print_statistics({:responses => 2, :noresponsefrom => [], :blocktime => 2}, {}, "ping") + end + end + + describe "#main" do + before do + @rpc_client = mock + @rpc_client.expects(:stats).returns(:stats) + @rpc_client.expects(:progress).returns(false) + @rpc_client.expects(:verbose).returns(false) + @app.expects(:rpcclient).returns(@rpc_client) + end + + it "should handle errors from nodes" do + @app.expects(:configuration).returns({:action => "ping", :arguments => {:fqdn => "rspec"}}).twice + @rpc_client.expects(:send).with("ping", {:fqdn => "rspec"}).returns([{:statuscode => 1}]) + @app.expects(:process_ping_result).with("error", {:statuscode => 1}, {}, false) + @app.expects(:print_statistics).with(:stats, {}, "ping") + @app.main + end + + it "should handle ping actions correctly" do + @app.expects(:configuration).returns({:action => "ping", :arguments => {:fqdn => "rspec"}}).twice + @rpc_client.expects(:send).with("ping", {:fqdn => "rspec"}).returns([{:statuscode => 0, :data => {}}]) + @app.expects(:print_statistics).with(:stats, {:ping => [0.0]}, "ping") + @app.main + end + + it "should handle connect actions correctly" do + @app.expects(:configuration).returns({:action => "connect", :arguments => {:fqdn => "rspec", :port => 80}}).twice + @rpc_client.expects(:send).with("connect", {:fqdn => "rspec", :port => 80}).returns([{:statuscode => 0, :data => {:connect => "rspec"}}]) + @app.expects(:print_statistics).with(:stats, {:connect => [0, 0, 0]}, "connect") + @app.main + end + end + end +end diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/nrpe/sbin/check-mc-nrpe mcollective-plugins-0.0.0~git20120507.df2fa81/agent/nrpe/sbin/check-mc-nrpe --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/nrpe/sbin/check-mc-nrpe 2011-12-14 16:18:41.000000000 +0000 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/nrpe/sbin/check-mc-nrpe 2012-04-25 15:00:16.000000000 +0100 @@ -13,10 +13,10 @@ nrpe.progress = false if ARGV.length > 0 - command = ARGV.shift + command = ARGV.shift else - puts("UNKNOWN: NRPE command not specified") - exit 3 + puts("UNKNOWN: NRPE command not specified") + exit 3 end @@ -25,24 +25,29 @@ statuscodes = [0] if nrpe.discover.size == 0 - puts("#{command}: UNKNOWN: did not discovery any nodes") - exit 3 + puts("#{command}: UNKNOWN: did not discovery any nodes") + exit 3 end nrpe_results = nrpe.runcommand(:command => command) nrpe_results.each do |result| + begin exitcode = result[:data][:exitcode].to_i - statuscodes << exitcode - stats[exitcode] << result[:sender] + rescue + exitcode = 3 + end + + statuscodes << exitcode + stats[exitcode] << result[:sender] end # Nodes that don't respond are UNKNOWNs if nrpe.stats[:noresponsefrom].size > 0 - stats[3] << nrpe.stats[:noresponsefrom] - statuscodes << 3 + stats[3] << nrpe.stats[:noresponsefrom] + statuscodes << 3 - stats[3].flatten! + stats[3].flatten! end # If we didn't discover any then thats an unknown @@ -51,20 +56,21 @@ puts("#{command}: OK: %d WARNING: %d CRITICAL: %d UNKNOWN: %d|total=%d ok=%d warn=%d crit=%d unknown=%d checktime=%f" % [stats[0].size, stats[1].size, stats[2].size, stats[3].size, nrpe_results.size, stats[0].size, stats[1].size, stats[2].size, stats[3].size, nrpe.stats.blocktime]) [2,1,3].each do |e| - if stats[e].size > 0 - puts "#{labels[e]}:" - puts " " + stats[e].join(" ") - end + if stats[e].size > 0 + puts "#{labels[e]}:" + puts " " + stats[e].join(" ") + end end +nrpe.disconnet + # if there's any critical checks, exit critical # else just take the highest. UNKNOWN is 3 while # critical is 2, just exiting with max would hide # the fact that there are criticals. if statuscodes.include?(2) - exit 2 + exit 2 else - exit statuscodes.max + exit statuscodes.max end -# vi:tabstop=4:expandtab:ai diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/package/agent/package.ddl mcollective-plugins-0.0.0~git20120507.df2fa81/agent/package/agent/package.ddl --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/package/agent/package.ddl 2011-12-14 16:18:41.000000000 +0000 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/package/agent/package.ddl 2012-04-25 15:00:16.000000000 +0100 @@ -2,7 +2,7 @@ :description => "Install and uninstall software packages", :author => "R.I.Pienaar", :license => "ASL2", - :version => "1.3", + :version => "2.2", :url => "https://github.com/puppetlabs/mcollective-plugins", :timeout => 180 @@ -47,6 +47,13 @@ end action "yum_clean", :description => "Clean the YUM cache" do + input :mode, + :prompt => "Yum clean mode", + :description => "One of the various supported clean modes", + :type => :list, + :optional => true, + :list => ["all", "headers", "packages", "metadata", "dbcache", "plugins", "expire-cache"] + output :output, :description => "Output from YUM", :display_as => "Output" diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/package/agent/puppet-package.rb mcollective-plugins-0.0.0~git20120507.df2fa81/agent/package/agent/puppet-package.rb --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/package/agent/puppet-package.rb 2011-12-14 16:18:41.000000000 +0000 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/package/agent/puppet-package.rb 2012-04-25 15:00:16.000000000 +0100 @@ -14,7 +14,7 @@ :description => "Install and uninstall software packages", :author => "R.I.Pienaar", :license => "ASL2", - :version => "2.0", + :version => "2.2", :url => "http://projects.puppetlabs.com/projects/mcollective-plugins/wiki", :timeout => 180 @@ -27,7 +27,18 @@ action "yum_clean" do reply.fail! "Cannot find yum at /usr/bin/yum" unless File.exist?("/usr/bin/yum") - reply[:exitcode] = run("/usr/bin/yum clean all", :stdout => :output, :chomp => true) + + if request[:mode] + clean_mode = request[:mode] + else + clean_mode = @config.pluginconf["package.yum_clean_mode"] || "all" + end + + if ["all", "headers", "packages", "metadata", "dbcache", "plugins", "expire-cache"].include?(clean_mode) + reply[:exitcode] = run("/usr/bin/yum clean #{clean_mode}", :stdout => :output, :chomp => true) + else + reply.fail! "Unsupported yum clean mode: #{clean_mode}" + end reply.fail! "Yum clean failed, exit code was #{reply[:exitcode]}" unless reply[:exitcode] == 0 end @@ -101,13 +112,13 @@ case action when :install - reply[:output] = pkg.install if pkg.properties[:ensure] == :absent + reply[:output] = pkg.install if [:absent, :purged].include?(pkg.properties[:ensure]) when :update - reply[:output] = pkg.update unless pkg.properties[:ensure] == :absent + reply[:output] = pkg.update unless [:absent, :purged].include?(pkg.properties[:ensure]) when :uninstall - reply[:output] = pkg.uninstall unless pkg.properties[:ensure] == :absent + reply[:output] = pkg.uninstall unless [:absent, :purged].include?(pkg.properties[:ensure]) when :status pkg.flush diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/package/spec/package_agent_spec.rb mcollective-plugins-0.0.0~git20120507.df2fa81/agent/package/spec/package_agent_spec.rb --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/package/spec/package_agent_spec.rb 2011-12-14 16:18:41.000000000 +0000 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/package/spec/package_agent_spec.rb 2012-04-25 15:00:16.000000000 +0100 @@ -18,20 +18,55 @@ result[:statusmsg].should == "Cannot find yum at /usr/bin/yum" end - it "should succeed if the agent responds to 'run' and the run method returns 0" do + it "should succeed if run method returns 0" do File.expects(:exist?).with("/usr/bin/yum").returns(true) + @agent.config.expects(:pluginconf).returns({"package.yum_clean_mode" => "all"}) @agent.expects(:run).with("/usr/bin/yum clean all", :stdout => :output, :chomp => true).returns(0) + result = @agent.call(:yum_clean) - result.should have_data_items(:exitcode => 0) result.should be_successful + result.should have_data_items(:exitcode => 0) end - it "should fail if the agent responds to 'run' and the run method doesn't return 0" do + it "should fail if the run method doesn't return 0" do File.expects(:exist?).with("/usr/bin/yum").returns(true) @agent.expects(:run).with("/usr/bin/yum clean all", :stdout => :output, :chomp => true).returns(1) + @agent.config.expects(:pluginconf).returns({"package.yum_clean_mode" => "all"}) result = @agent.call(:yum_clean) - result.should have_data_items(:exitcode => 1) result.should be_aborted_error + result.should have_data_items(:exitcode => 1) + end + + it "should default to 'all' mode" do + File.expects(:exist?).with("/usr/bin/yum").returns(true) + @agent.config.expects(:pluginconf).returns({}) + @agent.expects(:run).with("/usr/bin/yum clean all", :stdout => :output, :chomp => true).returns(0) + + result = @agent.call(:yum_clean) + result.should be_successful + result.should have_data_items(:exitcode => 0) + end + + it "should support a configured mode" do + File.expects(:exist?).with("/usr/bin/yum").returns(true) + @agent.config.expects(:pluginconf).returns({"package.yum_clean_mode" => "headers"}) + @agent.expects(:run).with("/usr/bin/yum clean headers", :stdout => :output, :chomp => true).returns(0) + + result = @agent.call(:yum_clean) + result.should be_successful + result.should have_data_items(:exitcode => 0) + end + + it "should support configured modes" do + ["all", "headers", "packages", "metadata", "dbcache", "plugins", "expire-cache"].each do |mode| + File.expects(:exist?).with("/usr/bin/yum").returns(true) + @agent.config.expects(:pluginconf).returns({"package.yum_clean_mode" => "all"}) + @agent.expects(:run).with("/usr/bin/yum clean #{mode}", :stdout => :output, :chomp => true).returns(0) + + result = @agent.call(:yum_clean, :mode => mode) + result.should be_successful + result.should have_data_items(:exitcode => 0) + end end end @@ -192,40 +227,42 @@ end describe "#install" do - it "should install if ensure is set to absent" do - Puppet.expects(:version).returns("0.24") - Puppet::Type.expects(:type).with(:package).twice.returns(@puppet_type) - - @puppet_type.expects(:clear) - @puppet_type.expects(:create).with(:name => "package").returns(@puppet_package) - @puppet_package.expects(:provider).returns(@puppet_package) - @puppet_package.expects(:install).returns(0) - @puppet_package.expects(:properties).twice.returns({:ensure => :absent}) - @puppet_package.expects(:flush) - - result = @agent.call(:install, :package => "package") - result.should be_successful - result.should have_data_items(:properties=>{:ensure=>:absent}, :output=>0) + it "should install if the package is absent" do + [:absent, :purged].each do |status| + Puppet.expects(:version).returns("0.24") + Puppet::Type.expects(:type).with(:package).twice.returns(@puppet_type) + + @puppet_type.expects(:clear) + @puppet_type.expects(:create).with(:name => "package").returns(@puppet_package) + @puppet_package.expects(:provider).returns(@puppet_package) + @puppet_package.expects(:install).returns(0) + @puppet_package.expects(:properties).twice.returns({:ensure => status}) + @puppet_package.expects(:flush) + + result = @agent.call(:install, :package => "package") + result.should be_successful + result.should have_data_items(:properties=>{:ensure=>status}, :output=>0) + end end - it "should not install if ensure is not set to absent" do + it "should not install if the package is present" do Puppet.expects(:version).returns("0.24") Puppet::Type.expects(:type).with(:package).twice.returns(@puppet_type) @puppet_type.expects(:clear) @puppet_type.expects(:create).with(:name => "package").returns(@puppet_package) @puppet_package.expects(:provider).returns(@puppet_package) - @puppet_package.expects(:properties).twice.returns({:ensure => :not_absent}) + @puppet_package.expects(:properties).twice.returns({:ensure => "123"}) @puppet_package.expects(:flush) result = @agent.call(:install, :package => "package") result.should be_successful - result.should have_data_items(:properties=>{:ensure=>:not_absent}, :output=>"") + result.should have_data_items(:properties=>{:ensure=>"123"}, :output=>"") end end describe "#update" do - it "should update unless ensure is set to absent" do + it "should update unless the package is absent" do Puppet.expects(:version).returns("0.24") Puppet::Type.expects(:type).with(:package).twice.returns(@puppet_type) @@ -241,24 +278,26 @@ result.should have_data_items(:properties=>{:ensure=>:not_absent}, :output=>0) end - it "should not update if ensure is set to absent" do - Puppet.expects(:version).returns("0.24") - Puppet::Type.expects(:type).with(:package).twice.returns(@puppet_type) - - @puppet_type.expects(:clear) - @puppet_type.expects(:create).with(:name => "package").returns(@puppet_package) - @puppet_package.expects(:provider).returns(@puppet_package) - @puppet_package.expects(:properties).twice.returns({:ensure => :absent}) - @puppet_package.expects(:flush) - - result = @agent.call(:update, :package => "package") - result.should be_successful - result.should have_data_items(:properties=>{:ensure=>:absent}, :output=>"") + it "should not update if the package is not installed" do + [:absent, :purged].each do |status| + Puppet.expects(:version).returns("0.24") + Puppet::Type.expects(:type).with(:package).twice.returns(@puppet_type) + + @puppet_type.expects(:clear) + @puppet_type.expects(:create).with(:name => "package").returns(@puppet_package) + @puppet_package.expects(:provider).returns(@puppet_package) + @puppet_package.expects(:properties).twice.returns({:ensure => status}) + @puppet_package.expects(:flush) + + result = @agent.call(:update, :package => "package") + result.should be_successful + result.should have_data_items(:properties => {:ensure => status}, :output=>"") + end end end describe "#uninstall" do - it "should uninstall unless ensure is set to absent" do + it "should uninstall if the package is present" do Puppet.expects(:version).returns("0.24") Puppet::Type.expects(:type).with(:package).twice.returns(@puppet_type) @@ -274,19 +313,21 @@ result.should have_data_items(:properties=>{:ensure=>:not_absent}, :output=>0) end - it "should not uninstall if ensure is set to absent" do - Puppet.expects(:version).returns("0.24") - Puppet::Type.expects(:type).with(:package).twice.returns(@puppet_type) - - @puppet_type.expects(:clear) - @puppet_type.expects(:create).with(:name => "package").returns(@puppet_package) - @puppet_package.expects(:provider).returns(@puppet_package) - @puppet_package.expects(:properties).twice.returns({:ensure => :absent}) - @puppet_package.expects(:flush) - - result = @agent.call(:uninstall, :package => "package") - result.should be_successful - result.should have_data_items(:properties=>{:ensure=>:absent}, :output=>"") + it "should not uninstall if the package is absent" do + [:absent, :purged].each do |status| + Puppet.expects(:version).returns("0.24") + Puppet::Type.expects(:type).with(:package).twice.returns(@puppet_type) + + @puppet_type.expects(:clear) + @puppet_type.expects(:create).with(:name => "package").returns(@puppet_package) + @puppet_package.expects(:provider).returns(@puppet_package) + @puppet_package.expects(:properties).twice.returns({:ensure => status}) + @puppet_package.expects(:flush) + + result = @agent.call(:uninstall, :package => "package") + result.should be_successful + result.should have_data_items(:properties => {:ensure => status}, :output => "") + end end end diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/process/agent/process.ddl mcollective-plugins-0.0.0~git20120507.df2fa81/agent/process/agent/process.ddl --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/process/agent/process.ddl 2011-12-14 16:18:41.000000000 +0000 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/process/agent/process.ddl 2012-04-25 15:00:16.000000000 +0100 @@ -2,24 +2,24 @@ :description => "Agent To Manage Processes", :author => "R.I.Pienaar", :license => "Apache 2.0", - :version => "1.1", + :version => "1.2", :url => "http://projects.puppetlabs.com/projects/mcollective-plugins/wiki", :timeout => 10 action "list", :description => "List Processes" do input :pattern, - :prompt => "Pattern to match", - :description => "List only processes matching this patten", - :type => :string, - :validation => '^.+$', - :optional => true, - :maxlength => 50 + :prompt => "Pattern to match", + :description => "List only processes matching this patten", + :type => :string, + :validation => '^.+$', + :optional => true, + :maxlength => 50 input :just_zombies, - :prompt => "Zombies Only", - :description => "Restrict the process list to Zombie Processes only", - :type => :boolean, - :optional => true + :prompt => "Zombies Only", + :description => "Restrict the process list to Zombie Processes only", + :type => :boolean, + :optional => true output :pslist, :description => "Process List", @@ -28,20 +28,20 @@ action "kill", :description => "Kills a process" do input :pid, - :prompt => "PID", - :description => "The PID to kill", - :type => :string, - :validation => '^\d+$', - :optional => false, - :maxlength => 6 + :prompt => "PID", + :description => "The PID to kill", + :type => :string, + :validation => '^\d+$', + :optional => false, + :maxlength => 6 input :signal, - :prompt => "Signal", - :description => "The signal to send", - :type => :string, - :validation => '^.+$', - :optional => false, - :maxlength => 6 + :prompt => "Signal", + :description => "The signal to send", + :type => :string, + :validation => '^.+$', + :optional => false, + :maxlength => 6 output :killed, :description => "Indicates if the process was signalled", @@ -50,20 +50,20 @@ action "pkill", :description => "Kill all processes matching filter" do input :pattern, - :prompt => "Pattern to match", - :description => "List only processes matching this patten", - :type => :string, - :validation => '^.+$', - :optional => true, - :maxlength => 50 + :prompt => "Pattern to match", + :description => "List only processes matching this patten", + :type => :string, + :validation => '^.+$', + :optional => true, + :maxlength => 50 input :signal, - :prompt => "Signal", - :description => "The signal to send", - :type => :string, - :validation => '^.+$', - :optional => false, - :maxlength => 6 + :prompt => "Signal", + :description => "The signal to send", + :type => :string, + :validation => '^.+$', + :optional => false, + :maxlength => 6 output :killed, :description => "Number of processes signalled", diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/process/agent/process.rb mcollective-plugins-0.0.0~git20120507.df2fa81/agent/process/agent/process.rb --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/process/agent/process.rb 2011-12-14 16:18:41.000000000 +0000 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/process/agent/process.rb 2012-04-25 15:00:16.000000000 +0100 @@ -5,9 +5,9 @@ :description => "Agent To Manage Processes", :author => "R.I.Pienaar", :license => "Apache 2.0", - :version => "1.1", + :version => "1.2", :url => "http://projects.puppetlabs.com/projects/mcollective-plugins/wiki", - :timeout => 3 + :timeout => 10 # List all processes, accepts an optional pattern action "list" do diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/process/application/pgrep.rb mcollective-plugins-0.0.0~git20120507.df2fa81/agent/process/application/pgrep.rb --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/process/application/pgrep.rb 1970-01-01 01:00:00.000000000 +0100 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/process/application/pgrep.rb 2012-04-25 15:00:16.000000000 +0100 @@ -0,0 +1,76 @@ +class MCollective::Application::Pgrep [-z]" + + option :just_zombies, + :description => "Only list defunct processes", + :arguments => ["-z", "--zombies"], + :type => :bool + + class ::Numeric + def bytes_to_human + if self > 0 + units = %w{B KB MB GB TB} + e = (Math.log(self)/Math.log(1024)).floor + s = "%.3f " % (to_f / 1024**e) + s.sub(/\.?0*$/, units[e]) + else + "0 B" + end + end + end + + def post_option_parser(configuration) + if ARGV.length == 1 + configuration[:pattern] = ARGV.shift + else + abort "Please provide a pattern to search for" + end + end + + def validate_configuration(configuration) + abort "Please provide a pattern to search for" unless configuration.include?(:pattern) + end + + def main + ps = rpcclient("process") + + stats = {:count => 0, + :hosts => 0, + :vsize => 0, + :rss => 0} + + ps.list(configuration).each_with_index do |result, i| + begin + if result[:data][:pslist].size > 0 + stats[:hosts] += 1 + + puts result[:sender] + + result[:data][:pslist].each_with_index do |process, idx| + puts " %5s %-10s %-15s %s" % ["PID", "USER", "VSZ", "COMMAND"] if idx == 0 + process[:state] == "Z" ? cmdline = "[#{process[:cmdline]}]" : cmdline = process[:cmdline] + + puts " %5d %-10s %-15s %s" % [process[:pid], process[:username][0,10], process[:vsize].bytes_to_human, cmdline[0,60] ] if process[:cmdline].match configuration[:pattern] + + stats[:count] += 1 + stats[:vsize] += process[:vsize] + stats[:rss] += process[:rss] * 1024 + end + + puts + end + rescue => e + STDERR.puts "Failed to get results from #{result[:sender]}: #{e.class}: #{e}" + end + end + + puts " ---- process list stats ----" + puts " Matched hosts: #{stats[:hosts]}" + puts " Matched processes: #{stats[:count]}" + puts " Resident Size: #{stats[:rss].bytes_to_human}" + puts " Virtual Size: #{stats[:vsize].bytes_to_human}" + + printrpcstats + end +end diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/process/sbin/mc-pgrep mcollective-plugins-0.0.0~git20120507.df2fa81/agent/process/sbin/mc-pgrep --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/process/sbin/mc-pgrep 2011-12-14 16:18:41.000000000 +0000 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/process/sbin/mc-pgrep 1970-01-01 01:00:00.000000000 +0100 @@ -1,77 +0,0 @@ -#!/usr/bin/env ruby - -require 'mcollective' - -include MCollective::RPC - -limits = {:pattern => ".", - :just_zombies => false} - -options = rpcoptions do |parser, options| - parser.define_head "Search for processes matching criteria" - parser.banner = "Usage: mc-pgrep [options] " - parser.separator "" - parser.separator "Process List Limiters:" - - parser.on('-z', '--zombie', 'Find only zombie processes') do |v| - limits[:just_zombies] = v - end -end - -$0 = "mc-pgrep" - -ps = rpcclient("process", :options => options) - -if ARGV.length > 0 - limits[:pattern] = ARGV.shift -end - -class Numeric - def bytes_to_human - if self > 0 - units = %w{B KB MB GB TB} - e = (Math.log(self)/Math.log(1024)).floor - s = "%.3f" % (to_f / 1024**e) - s.sub(/\.?0*$/, units[e]) - else - "0B" - end - end -end - -stats = {:count => 0, - :hosts => 0, - :vsize => 0, - :rss => 0} - -ps.list(limits).each_with_index do |result, i| - begin - if result[:data][:pslist].size > 0 - puts result[:sender] - stats[:hosts] += 1 - - result[:data][:pslist].each do |proc| - proc[:state] == "Z" ? cmdline = "[#{proc[:cmdline]}]" : cmdline = proc[:cmdline] - - puts "%5d %-10s %s %s" % [proc[:pid], proc[:username][0,10], proc[:vsize].bytes_to_human, cmdline[0,60] ] if proc[:cmdline].match limits[:pattern] - - stats[:count] += 1 - stats[:vsize] += proc[:vsize] - stats[:rss] += proc[:rss] * 1024 - end - - puts - end - rescue - STDERR.puts "Failed to get results from #{result[:sender]}" - end -end - -puts " ---- process list stats ----" -puts " Matched hosts: #{stats[:hosts]}" -puts " Matched processes: #{stats[:count]}" -puts " Resident Size: #{stats[:rss].bytes_to_human}" -puts " Virtual Size: #{stats[:vsize].bytes_to_human}" - -# vi:tabstop=4:expandtab:ai - diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/puppetd/agent/puppetd.ddl mcollective-plugins-0.0.0~git20120507.df2fa81/agent/puppetd/agent/puppetd.ddl --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/puppetd/agent/puppetd.ddl 2011-12-14 16:18:41.000000000 +0000 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/puppetd/agent/puppetd.ddl 2012-04-25 15:00:16.000000000 +0100 @@ -2,7 +2,7 @@ :description => "Run puppet agent, get its status, and enable/disable it", :author => "R.I.Pienaar", :license => "Apache License 2.0", - :version => "1.4", + :version => "1.5", :url => "https://github.com/puppetlabs/mcollective-plugins", :timeout => 20 @@ -54,6 +54,10 @@ action "status", :description => "Get puppet agent's status" do display :always + output :status, + :description => "The status of the puppet agent: disabled, running, idling or stopped", + :display_as => "Status" + output :enabled, :description => "Whether puppet agent is enabled", :display_as => "Enabled" @@ -62,6 +66,14 @@ :description => "Whether puppet agent is running", :display_as => "Running" + output :idling, + :description => "Whether puppet agent is idling", + :display_as => "Idling" + + output :stopped, + :description => "Whether puppet agent is stopped", + :display_as => "Stopped" + output :lastrun, :description => "When puppet agent last ran", :display_as => "Last Run" diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/puppetd/agent/puppetd.rb mcollective-plugins-0.0.0~git20120507.df2fa81/agent/puppetd/agent/puppetd.rb --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/puppetd/agent/puppetd.rb 2011-12-14 16:18:41.000000000 +0000 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/puppetd/agent/puppetd.rb 2012-04-25 15:00:16.000000000 +0100 @@ -21,7 +21,7 @@ :description => "Run puppet agent, get its status, and enable/disable it", :author => "R.I.Pienaar", :license => "Apache License 2.0", - :version => "1.4", + :version => "1.5", :url => "http://projects.puppetlabs.com/projects/mcollective-plugins/wiki/AgentPuppetd", :timeout => 30 @@ -51,7 +51,7 @@ end action "status" do - status + set_status end private @@ -65,48 +65,38 @@ end end - def status - reply[:enabled] = 0 - reply[:running] = 0 + def set_status + reply[:status] = puppet_daemon_status + reply[:running] = reply[:status] == 'running' ? 1 : 0 + reply[:enabled] = reply[:status] == 'disabled' ? 0 : 1 + reply[:idling] = reply[:status] == 'idling' ? 1 : 0 + reply[:stopped] = reply[:status] == 'stopped' ? 1 : 0 reply[:lastrun] = 0 - - if File.exists?(@lockfile) - if File::Stat.new(@lockfile).zero? - reply[:output] = "Disabled, not running" - else - reply[:output] = "Enabled, running" - reply[:enabled] = 1 - reply[:running] = 1 - end - else - reply[:output] = "Enabled, not running" - reply[:enabled] = 1 - end - reply[:lastrun] = File.stat(@statefile).mtime.to_i if File.exists?(@statefile) - reply[:output] += ", last run #{Time.now.to_i - reply[:lastrun]} seconds ago" + reply[:output] = "Currently #{reply[:status]}; last completed run #{Time.now.to_i - reply[:lastrun]} seconds ago" end - - # We would like to merge this method with the above status method some day def puppet_daemon_status locked = File.exists?(@lockfile) + disabled = locked && File::Stat.new(@lockfile).zero? has_pid = File.exists?(@pidfile) - return :running if locked && has_pid - return :disabled if locked && ! has_pid - return :idling if ! locked && has_pid - return :stopped if ! locked && ! has_pid + + return 'disabled' if disabled + return 'running' if locked && has_pid + return 'idling' if ! locked && has_pid + return 'stopped' if ! has_pid end def runonce - case (state = puppet_daemon_status) - when :disabled then # can't run - reply.fail "Lock file exists, but no PID file; puppet agent looks disabled." + set_status + case (reply[:status]) + when 'disabled' then # can't run + reply.fail "Empty Lock file exists; puppet agent is disabled." - when :running then # can't run two simultaniously - reply.fail "Lock file and PID file exist; puppet agent appears to be running." + when 'running' then # can't run two simultaniously + reply.fail "Lock file and PID file exist; puppet agent is running." - when :idling then # signal daemon + when 'idling' then # signal daemon pid = File.read(@pidfile) if pid !~ /^\d+$/ reply.fail "PID file does not contain a PID; got #{pid.inspect}" @@ -119,7 +109,7 @@ # theoretically signal arbitrary processes with this... begin ::Process.kill("USR1", Integer(pid)) - reply[:output] = "Signalled daemonized puppet agent to run (process #{Integer(pid)})" + reply[:output] = "Signalled daemonized puppet agent to run (process #{Integer(pid)}); " + (reply[:output] || '') rescue Exception => e reply.fail "Failed to signal the puppet agent daemon (process #{pid}): #{e}" end @@ -129,11 +119,11 @@ end end - when :stopped then # just run + when 'stopped' then # just run runonce_background else - reply.fail "Unknown puppet agent state: #{state}" + reply.fail "Unknown puppet agent status: #{reply[:status]}" end end @@ -148,7 +138,9 @@ cmd = cmd.join(" ") + output = reply[:output] || '' run(cmd, :stdout => :output, :chomp => true) + reply[:output] = "Called #{cmd}, " + output + (reply[:output] || '') end def enable @@ -162,7 +154,7 @@ reply[:output] = "Currently running; can't remove lock" end else - reply.fail "Already unlocked" + reply.fail "Already enabled" end end @@ -173,8 +165,7 @@ stat.zero? ? reply.fail("Already disabled") : reply.fail("Currently running; can't remove lock") else begin - File.open(@lockfile, "w") do |file| - end + File.open(@lockfile, "w") { |file| } reply[:output] = "Lock created" rescue Exception => e diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/puppetd/application/puppetd.rb mcollective-plugins-0.0.0~git20120507.df2fa81/agent/puppetd/application/puppetd.rb --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/puppetd/application/puppetd.rb 2011-12-14 16:18:41.000000000 +0000 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/puppetd/application/puppetd.rb 2012-04-25 15:00:16.000000000 +0100 @@ -104,7 +104,11 @@ when "status" mc.send(configuration[:command]).each do |node| - node[:statuscode] == 0 ? msg = node[:data][:output] : msg = node[:statusmsg] + if node[:statuscode] == 0 + msg = node[:data][:output] + else + msg = node[:statusmsg] + end puts "%-40s %s" % [ node[:sender], msg ] end @@ -113,13 +117,15 @@ printrpc mc.last_run_summary when "count" - running = enabled = total = 0 + running = enabled = total = stopped = idling = 0 mc.progress = false mc.status do |resp| begin running += resp[:body][:data][:running].to_i enabled += resp[:body][:data][:enabled].to_i + idling += resp[:body][:data][:idling].to_i + stopped += resp[:body][:data][:stopped].to_i total += 1 rescue Exception => e log("Failed to get node status for #{e}; continuing") @@ -129,9 +135,11 @@ disabled = total - enabled puts - puts "Nodes currently doing puppet runs: #{running}" puts " Nodes currently enabled: #{enabled}" puts " Nodes currently disabled: #{disabled}" + puts "Nodes currently doing puppet runs: #{running}" + puts " Nodes currently stopped: #{stopped}" + puts " Nodes currently idling: #{idling}" puts else diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/puppetd/spec/puppetd_agent_spec.rb mcollective-plugins-0.0.0~git20120507.df2fa81/agent/puppetd/spec/puppetd_agent_spec.rb --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/puppetd/spec/puppetd_agent_spec.rb 2011-12-14 16:18:41.000000000 +0000 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/puppetd/spec/puppetd_agent_spec.rb 2012-04-25 15:00:16.000000000 +0100 @@ -38,7 +38,7 @@ File.expects(:exists?).returns(false) result = @agent.call(:enable) result.should be_aborted_error - result[:statusmsg].should == "Already unlocked" + result[:statusmsg].should == "Already enabled" end it "should attempt to remove zero byte lockfiles" do @@ -112,25 +112,26 @@ end describe "#runonce" do + before do + @agent.instance_variable_set("@statefile", "spec_test_state_file") + end + it "with puppet agent disabled" do - File.expects(:exists?).with("spec_test_lock_file").returns(true) - File.expects(:exists?).with("spec_test_pid_file").returns(false) + @agent.expects(:puppet_daemon_status).returns('disabled') result = @agent.call(:runonce) result.should be_aborted_error - result[:statusmsg].should == "Lock file exists, but no PID file; puppet agent looks disabled." + result[:statusmsg].should == "Empty Lock file exists; puppet agent is disabled." end it "with puppet agent actively running" do - File.expects(:exists?).with("spec_test_lock_file").returns(true) - File.expects(:exists?).with("spec_test_pid_file").returns(true) + @agent.expects(:puppet_daemon_status).returns('running') result = @agent.call(:runonce) - result[:statusmsg].should == "Lock file and PID file exist; puppet agent appears to be running." + result[:statusmsg].should == "Lock file and PID file exist; puppet agent is running." result.should be_aborted_error end it "with puppet agent stopped" do - File.expects(:exists?).with("spec_test_lock_file").returns(false) - File.expects(:exists?).with("spec_test_pid_file").returns(false) + @agent.expects(:puppet_daemon_status).returns('stopped') @agent.instance_variable_set("@puppetd", "spec_test_puppetd") @agent.expects(:run).with("spec_test_puppetd --onetime", :stdout => :output, :chomp => true) result = @agent.call(:runonce) @@ -139,20 +140,18 @@ end it "with puppet agent idling as a daemon" do - File.expects(:exists?).with("spec_test_lock_file").returns(false) - File.expects(:exists?).with("spec_test_pid_file").returns(true) + @agent.expects(:puppet_daemon_status).returns('idling') File.expects(:read).with("spec_test_pid_file").returns("99999999\n") ::Process.expects(:kill).with(0, 99999999).returns(1) ::Process.expects(:kill).with("USR1", 99999999).once result = @agent.call(:runonce) result[:statusmsg].should == "OK" - result[:data][:output].should == "Signalled daemonized puppet agent to run (process 99999999)" + result[:data][:output].should =~ /Signalled daemonized puppet agent to run \(process 99999999\); Currently idling; last completed run/ result.should be_successful end - it "with puppet agent stopped but PID file present" do - File.expects(:exists?).with("spec_test_lock_file").returns(false) - File.expects(:exists?).with("spec_test_pid_file").returns(true) + it "with puppet agent stale pid file" do + @agent.expects(:puppet_daemon_status).returns('idling') File.expects(:read).with("spec_test_pid_file").returns("99999999\n") ::Process.expects(:kill).with(0, 99999999).raises(Errno::ESRCH) ::Process.expects(:kill).with("USR1", 99999999).never @@ -164,8 +163,7 @@ end it "with PID file containing rubbish" do - File.expects(:exists?).with("spec_test_lock_file").returns(false) - File.expects(:exists?).with("spec_test_pid_file").returns(true) + @agent.expects(:puppet_daemon_status).returns('idling') File.expects(:read).with("spec_test_pid_file").returns("fred\nwilma\nbarney\n") result = @agent.call(:runonce) result[:statusmsg].should == "PID file does not contain a PID; got \"fred\\nwilma\\nbarney\\n\"" @@ -199,48 +197,88 @@ stat = mock stat.stubs(:zero?).returns(true) @agent.instance_variable_set("@statefile", "spec_test_state_file") + @agent.instance_variable_set("@pidfile", "spec_test_pid_file") File.expects(:exists?).with("spec_test_lock_file").returns(true) File::Stat.expects(:new).with("spec_test_lock_file").returns(stat) File.expects(:exists?).with("spec_test_state_file").returns(false) + File.expects(:exists?).with("spec_test_pid_file").returns(false) result = @agent.call(:status) result.should be_successful - result.should have_data_items({:running => 0, - :enabled => 0, - :lastrun => 0, - :output => /Disabled, not running, last run/}) - + result.should have_data_items({ + :status => 'disabled', + :running => 0, + :enabled => 0, + :idling => 0, + :stopped => 0, + :lastrun => 0, + :output => /Currently disabled; last completed run \d+ seconds ago/ + }) end - it "is enabled and running when the lockfile exists and its size is not 0" do + it "is enabled and running when the pidfile exists and the lockfile exists and its size is not 0" do stat = mock stat.stubs(:zero?).returns(false) @agent.instance_variable_set("@statefile", "spec_test_state_file") + @agent.instance_variable_set("@pidfile", "spec_test_pid_file") File.expects(:exists?).with("spec_test_lock_file").returns(true) File::Stat.expects(:new).with("spec_test_lock_file").returns(stat) File.expects(:exists?).with("spec_test_state_file").returns(false) + File.expects(:exists?).with("spec_test_pid_file").returns(true) result = @agent.call(:status) result.should be_successful - result.should have_data_items({:running => 1, - :enabled => 1, - :lastrun => 0, - :output => /Enabled, running, last run/}) + result.should have_data_items({ + :status => 'running', + :running => 1, + :enabled => 1, + :idling => 0, + :stopped => 0, + :lastrun => 0, + :output => /Currently running; last completed run \d+ seconds ago/ + }) end - it "is enabled and not running if the lockfile does not exist" do + it "is enabled and idling if the pidfile exists but the lockfile does not exist" do File.expects(:exists?).with("spec_test_lock_file").returns(false) File.expects(:exists?).with("spec_test_state_file").returns(false) + File.expects(:exists?).with("spec_test_pid_file").returns(true) + + @agent.instance_variable_set("@statefile", "spec_test_state_file") + + result = @agent.call(:status) + result.should be_successful + result.should have_data_items({ + :status => 'idling', + :running => 0, + :enabled => 1, + :idling => 1, + :stopped => 0, + :lastrun => 0, + :output => /Currently idling; last completed run \d+ seconds ago/ + }) + end + + it "is enabled and stopped if the pidfile does not exist and the lockfile does not exist" do + File.expects(:exists?).with("spec_test_lock_file").returns(false) + File.expects(:exists?).with("spec_test_state_file").returns(false) + File.expects(:exists?).with("spec_test_pid_file").returns(false) + @agent.instance_variable_set("@statefile", "spec_test_state_file") result = @agent.call(:status) result.should be_successful - result.should have_data_items({:running => 0, - :enabled => 1, - :lastrun => 0, - :output => /Enabled, not running, last run/}) + result.should have_data_items({ + :status => 'stopped', + :running => 0, + :enabled => 1, + :idling => 0, + :stopped => 1, + :lastrun => 0, + :output => /Currently stopped; last completed run \d+ seconds ago/ + }) end end end diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/puppetd/spec/puppetd_application_spec.rb mcollective-plugins-0.0.0~git20120507.df2fa81/agent/puppetd/spec/puppetd_application_spec.rb --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/puppetd/spec/puppetd_application_spec.rb 2011-12-14 16:18:41.000000000 +0000 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/puppetd/spec/puppetd_application_spec.rb 2012-04-25 15:00:16.000000000 +0100 @@ -120,8 +120,19 @@ @app.stubs(:configuration).returns({:command => "status"}) @app.expects(:rpcclient).with("puppetd", :options => nil).returns(rpcclient_mock) - rpcclient_mock.expects(:send).returns([{:sender => "node1", :statuscode => 0, :data => {:output => "success"}},{:sender => "node2", :statuscode => 1, :statusmsg => "failure"}]) - @app.expects(:puts).with("node1 success") + rpcclient_mock.expects(:send).returns([ + { + :sender => "node1", + :statuscode => 0, + :data => {:output => "Currently idling; success"} + }, + { + :sender => "node2", + :statuscode => 1, + :statusmsg => "failure" + } + ]) + @app.expects(:puts).with("node1 Currently idling; success") @app.expects(:puts).with("node2 failure") @util.config.stubs(:color) rpcclient_mock.expects(:disconnect) @@ -160,10 +171,17 @@ @app.stubs(:configuration).returns({:command => "count"}) @app.expects(:rpcclient).with("puppetd", :options => nil).returns(rpcclient_mock) rpcclient_mock.expects(:progress=).with(false) - rpcclient_mock.expects(:status).yields(:body => {:data => {:running => "1", :enabled => "1"}}) - @app.expects(:puts).with("Nodes currently doing puppet runs: 1") + rpcclient_mock.expects(:status).yields(:body => {:data => { + :running => "1", + :enabled => "1", + :stopped => "0", + :idling => "0" + }}) @app.expects(:puts).with(" Nodes currently enabled: 1") @app.expects(:puts).with(" Nodes currently disabled: 0") + @app.expects(:puts).with("Nodes currently doing puppet runs: 1") + @app.expects(:puts).with(" Nodes currently stopped: 0") + @app.expects(:puts).with(" Nodes currently idling: 0") rpcclient_mock.expects(:disconnect) @app.main diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/registration-mongodb/registration.rb mcollective-plugins-0.0.0~git20120507.df2fa81/agent/registration-mongodb/registration.rb --- mcollective-plugins-0.0.0~git20120105.9b90c2b/agent/registration-mongodb/registration.rb 2011-12-14 16:18:41.000000000 +0000 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/agent/registration-mongodb/registration.rb 2012-04-25 15:00:16.000000000 +0100 @@ -13,7 +13,10 @@ # - plugin.registration.mongohost where the mongodb is default: localhost # - plugin.registration.mongodb the db name default: puppet # - plugin.registration.collection the collection name default: nodes - # + # - plugin.registration.extra_yaml_dir the presense of this key indicates a directory + # containing additional yaml files to push into an 'extra' key in the registration data. All files + # in the directory are pushed into a hash with keys being the file name (with the + # path and .yml extension stripped) and the value being the contents. default: false # Each document will have the following data: # - fqdn - the fqdn of the sender # - lastseen - last time we got data from it @@ -43,6 +46,7 @@ @mongohost = @config.pluginconf["registration.mongohost"] || "localhost" @mongodb = @config.pluginconf["registration.mongodb"] || "puppet" @collection = @config.pluginconf["registration.collection"] || "nodes" + @yaml_dir = @config.pluginconf["registration.extra_yaml_dir"] || false Log.instance.debug("Connecting to mongodb @ #{@mongohost} db #{@mongodb} collection #{@collection}") @@ -55,9 +59,22 @@ def handlemsg(msg, connection) req = msg[:body] + if (req.kind_of?(Array)) + Log.instance.warn("Got no facts - did you forget to add 'registration = Meta' to your server.cfg?"); + return nill + end + req[:fqdn] = req[:facts]["fqdn"] req[:lastseen] = Time.now.to_i + # Optionally send a list of extra yaml files + if (@yaml_dir != false) + req[:extra] = {} + Dir[@yaml_dir + "/*.yaml"].each do | f | + req[:extra][File.basename(f).split('.')[0]] = YAML.load_file(f) + end + end + # Sometimes facter doesnt send a fqdn?! if req[:fqdn].nil? Log.instance.debug("Got stats without a FQDN in facts") diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/debian/changelog mcollective-plugins-0.0.0~git20120507.df2fa81/debian/changelog --- mcollective-plugins-0.0.0~git20120105.9b90c2b/debian/changelog 2012-03-10 00:34:35.000000000 +0000 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/debian/changelog 2012-05-07 19:13:29.000000000 +0100 @@ -1,3 +1,10 @@ +mcollective-plugins (0.0.0~git20120507.df2fa81-0ubuntu1) quantal; urgency=low + + * Updated from upstream for Quantal + * Fix for mcollective-plugins-facter postrm script error (LP: #994357) + + -- Marc Cluet Mon, 07 May 2012 18:47:02 +0100 + mcollective-plugins (0.0.0~git20120105.9b90c2b-0ubuntu2) precise; urgency=low * Removed facts ohai package (LP: #948437) diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/debian/control mcollective-plugins-0.0.0~git20120507.df2fa81/debian/control --- mcollective-plugins-0.0.0~git20120105.9b90c2b/debian/control 2012-03-10 00:34:35.000000000 +0000 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/debian/control 2012-05-07 18:52:11.000000000 +0100 @@ -2,7 +2,7 @@ Section: admin Priority: extra Build-Depends: debhelper (>= 7.0.50) -Standards-Version: 3.9.2 +Standards-Version: 3.9.3 Homepage: http://projects.puppetlabs.com/projects/mcollective-plugins/wiki Maintainer: Ubuntu Developers diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/debian/mcollective-plugins-facts-facter.postrm mcollective-plugins-0.0.0~git20120507.df2fa81/debian/mcollective-plugins-facts-facter.postrm --- mcollective-plugins-0.0.0~git20120105.9b90c2b/debian/mcollective-plugins-facts-facter.postrm 2011-06-23 18:37:17.000000000 +0100 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/debian/mcollective-plugins-facts-facter.postrm 2012-05-07 18:44:17.000000000 +0100 @@ -5,7 +5,7 @@ ucfr -pf mcollective /etc/mcollective/server.cfg if [ $(grep "facter" /etc/mcollective/server.cfg | wc -l) = "1" ] then - sed -i -e "s/^factsource.*/factsource = yaml\nplugin.yaml = /etc/mcollective/facts.yaml/" /etc/mcollective/server.cfg + sed -i -e "s#^factsource.*#factsource = yaml\nplugin.yaml = /etc/mcollective/facts.yaml#" /etc/mcollective/server.cfg fi if [ $(grep "fact_cache_time" /etc/mcollective/server.cfg | wc -l) = "1" ] then diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/debian/mcollective-plugins-process.install mcollective-plugins-0.0.0~git20120507.df2fa81/debian/mcollective-plugins-process.install --- mcollective-plugins-0.0.0~git20120105.9b90c2b/debian/mcollective-plugins-process.install 2012-01-06 14:53:35.000000000 +0000 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/debian/mcollective-plugins-process.install 2012-05-07 19:28:35.000000000 +0100 @@ -1,3 +1,3 @@ agent/process/agent/*.ddl usr/share/mcollective/plugins/mcollective/agent agent/process/agent/*.rb usr/share/mcollective/plugins/mcollective/agent -agent/process/sbin/mc-pgrep usr/sbin +agent/process/application/pgrep.rb usr/share/mcollective/plugins/mcollective/application diff -Nru mcollective-plugins-0.0.0~git20120105.9b90c2b/debian/mcollective-plugins-process.manpages mcollective-plugins-0.0.0~git20120507.df2fa81/debian/mcollective-plugins-process.manpages --- mcollective-plugins-0.0.0~git20120105.9b90c2b/debian/mcollective-plugins-process.manpages 2011-06-21 21:44:24.000000000 +0100 +++ mcollective-plugins-0.0.0~git20120507.df2fa81/debian/mcollective-plugins-process.manpages 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -man/mc-pgrep.1