diff --git a/lib/puppet/agent.rb b/lib/puppet/agent.rb index f07305559..84bda6756 100644 --- a/lib/puppet/agent.rb +++ b/lib/puppet/agent.rb @@ -1,110 +1,108 @@ require 'sync' require 'puppet/external/event-loop' require 'puppet/application' # A general class for triggering a run of another # class. class Puppet::Agent require 'puppet/agent/locker' include Puppet::Agent::Locker - require 'puppet/agent/runner' - attr_reader :client_class, :client, :splayed # Just so we can specify that we are "the" instance. def initialize(client_class) @splayed = false @client_class = client_class end def lockfile_path client_class.lockfile_path end def needing_restart? Puppet::Application.restart_requested? end # Perform a run with our client. def run(*args) if running? Puppet.notice "Run of %s already in progress; skipping" % client_class return end result = nil block_run = Puppet::Application.controlled_run do splay with_client do |client| begin sync.synchronize { lock { result = client.run(*args) } } rescue => detail puts detail.backtrace if Puppet[:trace] Puppet.err "Could not run %s: %s" % [client_class, detail] end end true end Puppet.notice "Shutdown/restart in progress; skipping run" unless block_run result end def stopping? Puppet::Application.stop_requested? end # Have we splayed already? def splayed? splayed end # Sleep when splay is enabled; else just return. def splay return unless Puppet[:splay] return if splayed? time = rand(Integer(Puppet[:splaylimit]) + 1) Puppet.info "Sleeping for %s seconds (splay is enabled)" % time sleep(time) @splayed = true end # Start listening for events. We're pretty much just listening for # timer events here. def start # Create our timer. Puppet will handle observing it and such. timer = EventLoop::Timer.new(:interval => Puppet[:runinterval], :tolerance => 1, :start? => true) do run() end # Run once before we start following the timer timer.sound_alarm end def sync unless defined?(@sync) and @sync @sync = Sync.new end @sync end private # Create and yield a client instance, keeping a reference # to it during the yield. def with_client begin @client = client_class.new rescue SystemExit,NoMemoryError raise rescue Exception => detail puts detail.backtrace if Puppet[:trace] Puppet.err "Could not create instance of %s: %s" % [client_class, detail] return end yield @client ensure @client = nil end end diff --git a/lib/puppet/indirector/run/rest.rb b/lib/puppet/indirector/run/rest.rb new file mode 100644 index 000000000..7cf6411f1 --- /dev/null +++ b/lib/puppet/indirector/run/rest.rb @@ -0,0 +1,6 @@ +require 'puppet/run' +require 'puppet/indirector/rest' + +class Puppet::Run::Rest < Puppet::Indirector::REST + desc "Trigger Agent runs via REST." +end diff --git a/lib/puppet/indirector/runner/rest.rb b/lib/puppet/indirector/runner/rest.rb deleted file mode 100644 index 25d3def3f..000000000 --- a/lib/puppet/indirector/runner/rest.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'puppet/agent' -require 'puppet/agent/runner' -require 'puppet/indirector/rest' - -class Puppet::Agent::Runner::Rest < Puppet::Indirector::REST - desc "Trigger Agent runs via REST." -end diff --git a/lib/puppet/network/handler/runner.rb b/lib/puppet/network/handler/runner.rb index 070cae114..4f8247214 100755 --- a/lib/puppet/network/handler/runner.rb +++ b/lib/puppet/network/handler/runner.rb @@ -1,31 +1,31 @@ -require 'puppet/agent/runner' +require 'puppet/run' class Puppet::Network::Handler class MissingMasterError < RuntimeError; end # Cannot find the master client # A simple server for triggering a new run on a Puppet client. class Runner < Handler desc "An interface for triggering client configuration runs." @interface = XMLRPC::Service::Interface.new("puppetrunner") { |iface| iface.add_method("string run(string, string)") } side :client # Run the client configuration right now, optionally specifying # tags and whether to ignore schedules def run(tags = nil, ignoreschedules = false, fg = true, client = nil, clientip = nil) options = {} options[:tags] = tags if tags options[:ignoreschedules] = ignoreschedules if ignoreschedules options[:background] = !fg - runner = Puppet::Agent::Runner.new(options) + runner = Puppet::Run.new(options) runner.run return runner.status end end end diff --git a/lib/puppet/agent/runner.rb b/lib/puppet/run.rb similarity index 98% rename from lib/puppet/agent/runner.rb rename to lib/puppet/run.rb index 705b6c269..1503f5d7f 100644 --- a/lib/puppet/agent/runner.rb +++ b/lib/puppet/run.rb @@ -1,65 +1,65 @@ require 'puppet/agent' require 'puppet/configurer' require 'puppet/indirector' # A basic class for running the agent. Used by # puppetrun to kick off agents remotely. -class Puppet::Agent::Runner +class Puppet::Run extend Puppet::Indirector indirects :runner, :terminus_class => :rest attr_reader :status, :background, :options def agent Puppet::Agent.new(Puppet::Configurer) end def background? background end def initialize(options = {}) if options.include?(:background) @background = options[:background] options.delete(:background) end valid_options = [:tags, :ignoreschedules] options.each do |key, value| raise ArgumentError, "Runner does not accept %s" % key unless valid_options.include?(key) end @options = options end def log_run msg = "" msg += "triggered run" % if options[:tags] msg += " with tags %s" % options[:tags] end if options[:ignoreschedules] msg += " ignoring schedules" end Puppet.notice msg end def run if agent.running? @status = "running" return end log_run() if background? Thread.new { agent.run(options) } else agent.run(options) end @status = "success" end end diff --git a/spec/unit/indirector/runner/rest.rb b/spec/unit/indirector/run/rest.rb similarity index 60% rename from spec/unit/indirector/runner/rest.rb rename to spec/unit/indirector/run/rest.rb index 61457175d..e07fe7fc2 100755 --- a/spec/unit/indirector/runner/rest.rb +++ b/spec/unit/indirector/run/rest.rb @@ -1,11 +1,11 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../../spec_helper' require 'puppet/indirector/runner/rest' -describe Puppet::Agent::Runner::Rest do +describe Puppet::Run::Rest do it "should be a sublcass of Puppet::Indirector::REST" do - Puppet::Agent::Runner::Rest.superclass.should equal(Puppet::Indirector::REST) + Puppet::Run::Rest.superclass.should equal(Puppet::Indirector::REST) end end diff --git a/spec/unit/agent/runner.rb b/spec/unit/run.rb similarity index 76% rename from spec/unit/agent/runner.rb rename to spec/unit/run.rb index dfd267a5f..57eff0f98 100755 --- a/spec/unit/agent/runner.rb +++ b/spec/unit/run.rb @@ -1,118 +1,118 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/agent' -require 'puppet/agent/runner' +require 'puppet/run' -describe Puppet::Agent::Runner do +describe Puppet::Run do before do - @runner = Puppet::Agent::Runner.new + @runner = Puppet::Run.new end it "should indirect :runner" do - Puppet::Agent::Runner.indirection.name.should == :runner + Puppet::Run.indirection.name.should == :runner end it "should use a configurer agent as its agent" do agent = mock 'agent' Puppet::Agent.expects(:new).with(Puppet::Configurer).returns agent @runner.agent.should equal(agent) end it "should accept options at initialization" do - lambda { Puppet::Agent::Runner.new :background => true }.should_not raise_error + lambda { Puppet::Run.new :background => true }.should_not raise_error end it "should default to running in the foreground" do - Puppet::Agent::Runner.new.should_not be_background + Puppet::Run.new.should_not be_background end it "should default to its options being an empty hash" do - Puppet::Agent::Runner.new.options.should == {} + Puppet::Run.new.options.should == {} end it "should accept :tags for the agent" do - Puppet::Agent::Runner.new(:tags => "foo").options[:tags].should == "foo" + Puppet::Run.new(:tags => "foo").options[:tags].should == "foo" end it "should accept :ignoreschedules for the agent" do - Puppet::Agent::Runner.new(:ignoreschedules => true).options[:ignoreschedules].should be_true + Puppet::Run.new(:ignoreschedules => true).options[:ignoreschedules].should be_true end it "should accept an option to configure it to run in the background" do - Puppet::Agent::Runner.new(:background => true).should be_background + Puppet::Run.new(:background => true).should be_background end it "should retain the background option" do - Puppet::Agent::Runner.new(:background => true).options[:background].should be_nil + Puppet::Run.new(:background => true).options[:background].should be_nil end it "should not accept arbitrary options" do - lambda { Puppet::Agent::Runner.new(:foo => true) }.should raise_error(ArgumentError) + lambda { Puppet::Run.new(:foo => true) }.should raise_error(ArgumentError) end describe "when asked to run" do before do @agent = stub 'agent', :run => nil, :running? => false @runner.stubs(:agent).returns @agent end it "should run its agent" do agent = stub 'agent2', :running? => false @runner.stubs(:agent).returns agent agent.expects(:run) @runner.run end it "should pass any of its options on to the agent" do @runner.stubs(:options).returns(:foo => :bar) @agent.expects(:run).with(:foo => :bar) @runner.run end it "should log its run using the provided options" do @runner.expects(:log_run) @runner.run end it "should set its status to 'already_running' if the agent is already running" do @agent.expects(:running?).returns true @runner.run @runner.status.should == "running" end it "should set its status to 'success' if the agent is run" do @agent.expects(:running?).returns false @runner.run @runner.status.should == "success" end it "should run the agent in a thread if asked to run it in the background" do Thread.expects(:new) @runner.expects(:background?).returns true @agent.expects(:run).never # because our thread didn't yield @runner.run end it "should run the agent directly if asked to run it in the foreground" do Thread.expects(:new).never @runner.expects(:background?).returns false @agent.expects(:run) @runner.run end end end diff --git a/test/network/handler/runner.rb b/test/network/handler/runner.rb index 23cff83ff..6bf783b6f 100755 --- a/test/network/handler/runner.rb +++ b/test/network/handler/runner.rb @@ -1,20 +1,20 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../lib/puppettest' require 'puppettest' require 'puppet/network/handler/runner' class TestHandlerRunner < Test::Unit::TestCase include PuppetTest def test_it_calls_agent_runner runner = mock 'runner' - Puppet::Agent::Runner.expects(:new).with(:tags => "mytags", :ignoreschedules => true, :background => false).returns runner + Puppet::Run.expects(:new).with(:tags => "mytags", :ignoreschedules => true, :background => false).returns runner runner.expects(:run) runner.expects(:status).returns "yay" assert_equal("yay", Puppet::Network::Handler.runner.new.run("mytags", true, true)) end end