diff options
author | Luke Kanies <luke@madstop.com> | 2009-01-19 16:29:17 -0600 |
---|---|---|
committer | Luke Kanies <luke@madstop.com> | 2009-02-06 18:08:39 -0600 |
commit | 8f5cbc349daa868020b009851ee97ea3f29fcfbf (patch) | |
tree | 5cfc7826cb90d7daf8aa1014b83ee1877255ebee | |
parent | 25b28c58c22bae718794dc679f10c61665af0b15 (diff) | |
download | puppet-8f5cbc349daa868020b009851ee97ea3f29fcfbf.tar.gz puppet-8f5cbc349daa868020b009851ee97ea3f29fcfbf.tar.xz puppet-8f5cbc349daa868020b009851ee97ea3f29fcfbf.zip |
This is work that I've decided not to keep
so I'm just applying it here so it continues to show
up in the history in case I ever want to look at it again.
Signed-off-by: Luke Kanies <luke@madstop.com>
-rwxr-xr-x | bin/puppetd | 13 | ||||
-rw-r--r-- | lib/puppet/agent.rb | 429 | ||||
-rw-r--r-- | lib/puppet/agent/downloader.rb | 24 | ||||
-rw-r--r-- | lib/puppet/agent/splayer.rb | 29 | ||||
-rwxr-xr-x | spec/unit/agent.rb | 219 | ||||
-rwxr-xr-x | spec/unit/agent/downloader.rb | 19 | ||||
-rwxr-xr-x | spec/unit/agent/splayer.rb | 42 |
7 files changed, 669 insertions, 106 deletions
diff --git a/bin/puppetd b/bin/puppetd index ecea2d894..cc60d8cdc 100755 --- a/bin/puppetd +++ b/bin/puppetd @@ -328,20 +328,23 @@ end Puppet::SSL::Host.ca_location = :remote Puppet::Transaction::Report.terminus_class = :rest +Puppet::Node::Facts.terminus_class = :facter +Puppet::Node::Facts.cache_class = :rest -# We need tomake the client either way, we just don't start it -# if --no-client is set. -client = Puppet::Network::Client.master.new(args) if options[:enable] - client.enable + Puppet::Agent.enable elsif options[:disable] - client.disable + Puppet::Agent.disable end if options[:enable] or options[:disable] exit(0) end +# We need tomake the client either way, we just don't start it +# if --no-client is set. +client = Puppet::Network::Client.master.new(args) + server = nil # It'd be nice to daemonize later, but we have to daemonize before the diff --git a/lib/puppet/agent.rb b/lib/puppet/agent.rb index 095a2942b..e94835959 100644 --- a/lib/puppet/agent.rb +++ b/lib/puppet/agent.rb @@ -1,23 +1,87 @@ +# The class that functions as our client agent. It has all +# of the logic for downloading and applying catalogs, and anything +# else needed by puppetd to do its job. class Puppet::Agent - # enable/disable + # The 'require' is inside the class so the Agent constant already exists. + require 'puppet/agent/downloader' - # storage + # Disable all agent activity. This would be used by someone to + # temporarily stop puppetd without killing the daemon. + def self.disable + lockfile.lock :anonymous => true + end + + # Enable activity again. + def self.enable + lockfile.unlock :anonymous => true + end + + def self.enabled? + ! lockfile.locked? + end + + # The lockfile we're using. + def self.lockfile + unless defined?(@lockfile) and @lockfile + @lockfile = Puppet::Util::Pidlock.new(Puppet[:puppetdlockfile]) + end - # locking + @lockfile + end + + # Determine the timeout value to use. + def self.timeout + timeout = Puppet[:configtimeout] + case timeout + when String: + if timeout =~ /^\d+$/ + timeout = Integer(timeout) + else + raise ArgumentError, "Configuration timeout must be an integer" + end + when Integer: # nothing + else + raise ArgumentError, "Configuration timeout must be an integer" + end + + return timeout + end + + # storage # config timeout # setclasses # Retrieve our catalog, possibly from the cache. - def catalog - unless c = Puppet::Node::Catalog.find(name, :use_cache => (!Puppet[:ignorecache])) + def download_catalog + unless c = Puppet::Resource::Catalog.find(name, :use_cache => (!Puppet[:ignorecache])) raise "Could not retrieve catalog" end c.host_config = true c end + # Should we be downloading plugins? + def download_plugins? + Puppet[:pluginsync] + end + + # Download, and load if necessary, central plugins. + def download_plugins + Puppet::Agent::Downloader.new("plugin", Puppet[:pluginsource], Puppet[:plugindest], Puppet[:pluginsignore]).evaluate + end + + # Should we be downloading facts? + def download_facts? + Puppet[:factsync] + end + + # Download, and load if necessary, central facts. + def download_facts + Puppet::Agent::Downloader.new("fact", Puppet[:factsource], Puppet[:factdest], Puppet[:factsignore]).evaluate + end + def initialize(options = {}) options.each do |param, value| if respond_to?(param.to_s + "=") @@ -39,9 +103,11 @@ class Puppet::Agent end def run - splay() + splay() if splay? + + download_plugins() if download_plugins? - download_plugins() + download_facts() if download_facts? upload_facts() @@ -50,58 +116,343 @@ class Puppet::Agent apply(catalog) end + # Should we splay? + def splay? + Puppet[:splay] + end + # Sleep for a random but consistent period of time if configured to # do so. def splay return unless Puppet[:splay] + return if splayed? - time = splay_time() - + time = rand(Integer(Puppet[:splaylimit]) + 1) Puppet.info "Sleeping for %s seconds (splay is enabled)" % time sleep(time) + @splayed = true + end + + # Have we already splayed? + def splayed? + defined?(@splayed) and @splayed end def start -# # Create our timer. Puppet will handle observing it and such. -# timer = Puppet.newtimer( -# :interval => Puppet[:runinterval], -# :tolerance => 1, -# :start? => true -# ) do -# begin -# self.runnow if self.scheduled? -# rescue => detail -# puts detail.backtrace if Puppet[:trace] -# Puppet.err "Could not run client; got otherwise uncaught exception: %s" % detail -# end -# end -# -# # Run once before we start following the timer -# self.runnow end - def download_catalog - # LAK:NOTE This needs to handle skipping cached configs - # if configured to do so. - Puppet::Node::Catalog.find name + # This works because puppetd configures Facts to use 'facter' for + # finding facts and the 'rest' terminus for caching them. Thus, we'll + # compile them and then "cache" them on the server. + def upload_facts + Puppet::Node::Facts.find(Puppet[:certname]) end +end - def download_plugins - raise "Plugin downloads not implemented" +class OldMaster + attr_accessor :catalog + attr_reader :compile_time + + class << self + # Puppetd should only have one instance running, and we need a way + # to retrieve it. + attr_accessor :instance + include Puppet::Util end - def upload_facts + def self.facts + + down = Puppet[:downcasefacts] + + Facter.clear + + # Reload everything. + if Facter.respond_to? :loadfacts + Facter.loadfacts + elsif Facter.respond_to? :load + Facter.load + else + Puppet.warning "You should upgrade your version of Facter to at least 1.3.8" + end + + # This loads all existing facts and any new ones. We have to remove and + # reload because there's no way to unload specific facts. + loadfacts() + facts = Facter.to_hash.inject({}) do |newhash, array| + name, fact = array + if down + newhash[name] = fact.to_s.downcase + else + newhash[name] = fact.to_s + end + newhash + end + + facts + end + + # Retrieve the config from a remote server. If this fails, then + # use the cached copy. + def getconfig + dostorage() + + facts = nil + Puppet::Util.benchmark(:debug, "Retrieved facts") do + facts = self.class.facts + end + + raise Puppet::Network::ClientError.new("Could not retrieve any facts") unless facts.length > 0 + + Puppet.debug("Retrieving catalog") + + # If we can't retrieve the catalog, just return, which will either + # fail, or use the in-memory catalog. + unless marshalled_objects = get_actual_config(facts) + use_cached_config(true) + return + end + + begin + case Puppet[:catalog_format] + when "marshal": objects = Marshal.load(marshalled_objects) + when "yaml": objects = YAML.load(marshalled_objects) + else + raise "Invalid catalog format '%s'" % Puppet[:catalog_format] + end + rescue => detail + msg = "Configuration could not be translated from %s" % Puppet[:catalog_format] + msg += "; using cached catalog" if use_cached_config(true) + Puppet.warning msg + return + end + + self.setclasses(objects.classes) + + # Clear all existing objects, so we can recreate our stack. + clear() if self.catalog + + # Now convert the objects to a puppet catalog graph. + begin + @catalog = objects.to_catalog + rescue => detail + clear() + puts detail.backtrace if Puppet[:trace] + msg = "Configuration could not be instantiated: %s" % detail + msg += "; using cached catalog" if use_cached_config(true) + Puppet.warning msg + return + end + + # Keep the state database up to date. + @catalog.host_config = true + end + + # Just so we can specify that we are "the" instance. + def initialize(*args) + Puppet.settings.use(:main, :ssl, :puppetd) + super + + self.class.instance = self + @running = false + @splayed = false + end + + # Mark that we should restart. The Puppet module checks whether we're running, + # so this only gets called if we're in the middle of a run. + def restart + # If we're currently running, then just mark for later + Puppet.notice "Received signal to restart; waiting until run is complete" + @restart = true + end + + # Should we restart? + def restart? + if defined? @restart + @restart + else + false + end + end + + # Retrieve the cached config + def retrievecache + if FileTest.exists?(self.cachefile) + return ::File.read(self.cachefile) + else + return nil + end + end + + # The code that actually runs the catalog. + # This just passes any options on to the catalog, + # which accepts :tags and :ignoreschedules. + def run(options = {}) + got_lock = false + splay + Puppet::Util.sync(:puppetrun).synchronize(Sync::EX) do + if !lockfile.lock + Puppet.notice "Lock file %s exists; skipping catalog run" % + lockfile.lockfile + else + got_lock = true + begin + duration = thinmark do + self.getconfig + end + rescue => detail + puts detail.backtrace if Puppet[:trace] + Puppet.err "Could not retrieve catalog: %s" % detail + end + + if self.catalog + @catalog.retrieval_duration = duration + Puppet.notice "Starting catalog run" unless @local + benchmark(:notice, "Finished catalog run") do + @catalog.apply(options) + end + end + + # Now close all of our existing http connections, since there's no + # reason to leave them lying open. + Puppet::Network::HttpPool.clear_http_instances + end + + lockfile.unlock + + # Did we get HUPped during the run? If so, then restart now that we're + # done with the run. + if self.restart? + Process.kill(:HUP, $$) + end + end + ensure + # Just make sure we remove the lock file if we set it. + lockfile.unlock if got_lock and lockfile.locked? + clear() + end + + def running? + lockfile.locked? + end + + # Store the classes in the classfile, but only if we're not local. + def setclasses(ary) + if @local + return + end + unless ary and ary.length > 0 + Puppet.info "No classes to store" + return + end + begin + ::File.open(Puppet[:classfile], "w") { |f| + f.puts ary.join("\n") + } + rescue => detail + Puppet.err "Could not create class file %s: %s" % + [Puppet[:classfile], detail] + end end - def splay_time - limit = Integer(Puppet[:splaylimit]) + private + + def self.loaddir(dir, type) + return unless FileTest.directory?(dir) + + Dir.entries(dir).find_all { |e| e =~ /\.rb$/ }.each do |file| + fqfile = ::File.join(dir, file) + begin + Puppet.info "Loading %s %s" % + [type, ::File.basename(file.sub(".rb",''))] + Timeout::timeout(self.timeout) do + load fqfile + end + rescue => detail + Puppet.warning "Could not load %s %s: %s" % [type, fqfile, detail] + end + end + end - # Pick a splay time and then cache it. - unless time = Puppet::Util::Storage.cache(:configuration)[:splay_time] - time = rand(limit) - Puppet::Util::Storage.cache(:configuration)[:splay_time] = time + def self.loadfacts + # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com] + x = Puppet[:factpath].split(":").each do |dir| + loaddir(dir, "fact") end + end + + def self.timeout + timeout = Puppet[:configtimeout] + case timeout + when String: + if timeout =~ /^\d+$/ + timeout = Integer(timeout) + else + raise ArgumentError, "Configuration timeout must be an integer" + end + when Integer: # nothing + else + raise ArgumentError, "Configuration timeout must be an integer" + end + + return timeout + end + + loadfacts() + + # Retrieve a config from a remote master. + def get_remote_config(facts) + textobjects = "" + + textfacts = CGI.escape(YAML.dump(facts)) - time + benchmark(:debug, "Retrieved catalog") do + # error handling for this is done in the network client + begin + textobjects = @driver.getconfig(textfacts, Puppet[:catalog_format]) + begin + textobjects = CGI.unescape(textobjects) + rescue => detail + raise Puppet::Error, "Could not CGI.unescape catalog" + end + + rescue => detail + Puppet.err "Could not retrieve catalog: %s" % detail + return nil + end + end + + return nil if textobjects == "" + + @compile_time = Time.now + + return textobjects + end + + private + + # Use our cached config, optionally specifying whether this is + # necessary because of a failure. + def use_cached_config(because_of_failure = false) + return true if self.catalog + + if because_of_failure and ! Puppet[:usecacheonfailure] + @catalog = nil + Puppet.warning "Not using cache on failed catalog" + return false + end + + return false unless oldtext = self.retrievecache + + begin + @catalog = YAML.load(oldtext).to_catalog + @catalog.from_cache = true + @catalog.host_config = true + rescue => detail + puts detail.backtrace if Puppet[:trace] + Puppet.warning "Could not load cached catalog: %s" % detail + clear + return false + end + return true end end diff --git a/lib/puppet/agent/downloader.rb b/lib/puppet/agent/downloader.rb index 46a64d52d..e838d4d79 100644 --- a/lib/puppet/agent/downloader.rb +++ b/lib/puppet/agent/downloader.rb @@ -1,36 +1,20 @@ require 'puppet/agent' +# A simple class that abstracts downloading files +# fromthe server. class Puppet::Agent::Downloader attr_reader :name, :path, :source, :ignore - # Determine the timeout value to use. - def self.timeout - timeout = Puppet[:configtimeout] - case timeout - when String: - if timeout =~ /^\d+$/ - timeout = Integer(timeout) - else - raise ArgumentError, "Configuration timeout must be an integer" - end - when Integer: # nothing - else - raise ArgumentError, "Configuration timeout must be an integer" - end - - return timeout - end - # Evaluate our download, returning the list of changed values. def evaluate Puppet.info "Retrieving #{name}" files = [] begin - Timeout.timeout(self.class.timeout) do + Timeout.timeout(Puppet::Agent.timeout) do catalog.apply do |trans| trans.changed?.find_all do |resource| - yield resource if block_given? + yield resource[:path] if block_given? files << resource[:path] end end diff --git a/lib/puppet/agent/splayer.rb b/lib/puppet/agent/splayer.rb new file mode 100644 index 000000000..6c2b1ba51 --- /dev/null +++ b/lib/puppet/agent/splayer.rb @@ -0,0 +1,29 @@ +require 'puppet/agent' + +# The class that handles sleeping for the appropriate splay +# time, if at all. +class Puppet::Agent::Splayer + attr_reader :splayed + + # Should we splay? + def splay? + Puppet[:splay] + end + + # Sleep for a random but consistent period of time if configured to + # do so. + 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 + + # Have we already splayed? + def splayed? + defined?(@splayed) and @splayed + end +end diff --git a/spec/unit/agent.rb b/spec/unit/agent.rb index 63914c3a3..a564308be 100755 --- a/spec/unit/agent.rb +++ b/spec/unit/agent.rb @@ -5,6 +5,66 @@ require File.dirname(__FILE__) + '/../spec_helper' require 'puppet/agent' describe Puppet::Agent do + it "should be able to provide a timeout value" do + Puppet::Agent.should respond_to(:timeout) + end + + it "should use the configtimeout, converted to an integer, as its timeout" do + Puppet.settings.expects(:value).with(:configtimeout).returns "50" + Puppet::Agent.timeout.should == 50 + end + + describe "when managing the lockfile" do + after do + Puppet::Agent.instance_variable_set("@lockfile", nil) + end + + it "should use Pidlock to manage the lock file itself" do + Puppet::Agent.instance_variable_set("@lockfile", nil) + + Puppet.settings.expects(:value).with(:puppetdlockfile).returns "/lock/file" + Puppet::Util::Pidlock.expects(:new).with("/lock/file").returns "mylock" + + Puppet::Agent.lockfile.should == "mylock" + end + + it "should always reuse the same lock file instance" do + Puppet::Agent.lockfile.should equal(Puppet::Agent.lockfile) + end + + it "should have a class method for disabling the agent" do + Puppet::Agent.should respond_to(:disable) + end + + it "should have a class method for enabling the agent" do + Puppet::Agent.should respond_to(:enable) + end + + it "should use the lockfile to disable the agent anonymously" do + Puppet::Agent.lockfile.expects(:lock).with(:anonymous => true) + Puppet::Agent.disable + end + + it "should use the lockfile to enable the agent anonymously" do + Puppet::Agent.lockfile.expects(:unlock).with(:anonymous => true) + Puppet::Agent.enable + end + + it "should have a class method for determining whether the agent is enabled" do + Puppet::Agent.should respond_to(:enabled?) + end + + it "should consider the agent enabled if the lockfile is not locked" do + Puppet::Agent.lockfile.expects(:locked?).returns false + Puppet::Agent.should be_enabled + end + + it "should consider the agent disabled if the lockfile is locked" do + Puppet::Agent.lockfile.expects(:locked?).returns true + Puppet::Agent.should_not be_enabled + end + end + it "should have a start method" do Puppet::Agent.new.should respond_to(:start) end @@ -32,22 +92,22 @@ describe Puppet::Agent do @agent.stubs(:name).returns "foo" Puppet.settings.stubs(:value).with(:splaylimit).returns "1800" - Puppet.settings.stubs(:value).with(:splaylimit).returns "1800" + Puppet.settings.stubs(:value).with(:splay).returns true end - it "should do nothing if splay is disabled" do - Puppet.settings.expects(:value).with(:splay).returns false - @agent.expects(:sleep).never - @agent.splay - end - - it "should sleep if splay is enabled" do + it "should sleep if it has not previously splayed" do Puppet.settings.expects(:value).with(:splay).returns true @agent.expects(:sleep) @agent.splay end + + it "should do nothing if it has already splayed" do + @agent.expects(:sleep).once + @agent.splay + @agent.splay + end - it "should log when splay is enabled" do + it "should log if it is sleeping" do Puppet.settings.expects(:value).with(:splay).returns true @agent.stubs(:sleep) @@ -57,22 +117,125 @@ describe Puppet::Agent do end end - it "should default to using splay time" + describe "when running" do + before do + @agent = Puppet::Agent.new + [:upload_facts, :download_catalog, :apply].each { |m| @agent.stubs(m) } + end - it "should be able to ignore splay time" + it "should splay if splay is enabled" do + @agent.expects(:splay?).returns true + @agent.expects(:splay) + @agent.run + end - it "should be able to retrieve facts" + it "should not splay if splay is disabled" do + @agent.expects(:splay?).returns false + @agent.expects(:splay).never + @agent.run + end - describe "when running" do - it "should download plugins" + it "should download plugins if plugin downloading is enabled" do + @agent.expects(:download_plugins?).returns true + @agent.expects(:download_plugins) + @agent.run + end + + it "should not download plugins if plugin downloading is disabled" do + @agent.expects(:download_plugins?).returns false + @agent.expects(:download_plugins).never + @agent.run + end + + it "should download facts if fact downloading is enabled" do + @agent.expects(:download_facts?).returns true + @agent.expects(:download_facts) + @agent.run + end + + it "should not download facts if fact downloading is disabled" do + @agent.expects(:download_facts?).returns false + @agent.expects(:download_facts).never + @agent.run + end + + it "should retrieve the facts and save them to the server" do + @agent.expects(:upload_facts) + @agent.run + end + + it "should retrieve the catalog" do + @agent.expects(:download_catalog) + @agent.run + end + + it "should apply the catalog" do + catalog = mock("catalog") + @agent.expects(:download_catalog).returns catalog + @agent.expects(:apply).with(catalog) + @agent.run + end + end + + describe "when downloading plugins" do + before do + @agent = Puppet::Agent.new + @downloader = stub 'downloader', :evaluate + end - it "should download facts" + it "should download plugins if the :pluginsync setting is true" do + Puppet.settings.expects(:value).with(:pluginsync).returns true + @agent.should be_download_plugins + end - it "should retrieve the facts and save them to the server" + it "should not download plugins if the :pluginsync setting is false" do + Puppet.settings.expects(:value).with(:pluginsync).returns false + @agent.should_not be_download_plugins + end + + it "should use a Downloader instance with its name set to 'plugin' and the pluginsource, plugindest, and pluginsignore settings" do + Puppet.settings.expects(:value).with(:pluginsource).returns "plugsource" + Puppet.settings.expects(:value).with(:plugindest).returns "plugdest" + Puppet.settings.expects(:value).with(:pluginsignore).returns "plugig" + Puppet::Agent::Downloader.expects(:new).with("plugin", "plugsource", "plugdest", "plugig").returns @downloader + @downloader.expects(:evaluate) + @agent.download_plugins + end + end - it "should retrieve the catalog" + describe "when downloading facts" do + before do + @agent = Puppet::Agent.new + @downloader = stub 'downloader', :evaluate + end - it "should apply the catalog" + it "should download facts if the :factsync setting is true" do + Puppet.settings.expects(:value).with(:factsync).returns true + @agent.should be_download_facts + end + + it "should not download facts if the :factsync setting is false" do + Puppet.settings.expects(:value).with(:factsync).returns false + @agent.should_not be_download_facts + end + + it "should use a Downloader instance with its name set to 'facts' and the factssource, factsdest, and factsignore settings" do + Puppet.settings.expects(:value).with(:factsource).returns "factsource" + Puppet.settings.expects(:value).with(:factdest).returns "factdest" + Puppet.settings.expects(:value).with(:factsignore).returns "factig" + Puppet::Agent::Downloader.expects(:new).with("fact", "factsource", "factdest", "factig").returns @downloader + @downloader.expects(:evaluate) + @agent.download_facts + end + end + + describe "when uploading facts" do + it "should just retrieve the facts for the current host" do + @agent = Puppet::Agent.new + + Puppet::Node::Facts.expects(:find).with(Puppet[:certname]) + @agent.upload_facts + end end describe "when retrieving the catalog" do @@ -84,34 +247,34 @@ describe Puppet::Agent do end it "should use the Catalog class to find the catalog" do - Puppet::Node::Catalog.expects(:find).with { |name, options| name == "me" }.returns @catalog + Puppet::Resource::Catalog.expects(:find).with { |name, options| name == "me" }.returns @catalog - @agent.catalog.should equal(@catalog) + @agent.download_catalog.should equal(@catalog) end it "should default to allowing use of the cache" do - Puppet::Node::Catalog.expects(:find).with { |name, options| options[:use_cache] == true }.returns @catalog + Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:use_cache] == true }.returns @catalog - @agent.catalog + @agent.download_catalog end it "should ignore a cached catalog if configured to do so" do Puppet.settings.expects(:value).with(:ignorecache).returns true - Puppet::Node::Catalog.expects(:find).with { |name, options| options[:use_cache] == false }.returns @catalog + Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:use_cache] == false }.returns @catalog - @agent.catalog + @agent.download_catalog end it "should mark the catalog as a host catalog" do @catalog.expects(:host_config=).with true - Puppet::Node::Catalog.expects(:find).returns @catalog + Puppet::Resource::Catalog.expects(:find).returns @catalog - @agent.catalog + @agent.download_catalog end it "should fail if a catalog can not be retrieved" do - Puppet::Node::Catalog.expects(:find).returns nil - lambda { @agent.catalog }.should raise_error(RuntimeError) + Puppet::Resource::Catalog.expects(:find).returns nil + lambda { @agent.download_catalog }.should raise_error(RuntimeError) end end end diff --git a/spec/unit/agent/downloader.rb b/spec/unit/agent/downloader.rb index 6b07e5bb4..5c53de824 100755 --- a/spec/unit/agent/downloader.rb +++ b/spec/unit/agent/downloader.rb @@ -20,15 +20,6 @@ describe Puppet::Agent::Downloader do dler.source.should == "source" end - it "should be able to provide a timeout value" do - Puppet::Agent::Downloader.should respond_to(:timeout) - end - - it "should use the configtimeout, converted to an integer, as its timeout" do - Puppet.settings.expects(:value).with(:configtimeout).returns "50" - Puppet::Agent::Downloader.timeout.should == 50 - end - describe "when creating the file that does the downloading" do before do @dler = Puppet::Agent::Downloader.new("foo", "path", "source") @@ -118,8 +109,8 @@ describe Puppet::Agent::Downloader do @dler.evaluate end - it "should set a timeout for the download" do - Puppet::Agent::Downloader.expects(:timeout).returns 50 + it "should use the agent timeout for the download" do + Puppet::Agent.expects(:timeout).returns 50 Timeout.expects(:timeout).with(50) @dler.evaluate @@ -153,7 +144,7 @@ describe Puppet::Agent::Downloader do @dler.evaluate.should == %w{/changed/file} end - it "should yield the resources if a block is given" do + it "should yield the downloaded file's path if a block is given" do trans = mock 'transaction' catalog = mock 'catalog' @@ -163,13 +154,13 @@ describe Puppet::Agent::Downloader do Timeout.expects(:timeout).yields resource = mock 'resource' - resource.expects(:[]).with(:path).returns "/changed/file" + resource.stubs(:[]).with(:path).returns "/changed/file" trans.expects(:changed?).returns([resource]) yielded = nil @dler.evaluate { |r| yielded = r } - yielded.should == resource + yielded.should == "/changed/file" end it "should catch and log exceptions" do diff --git a/spec/unit/agent/splayer.rb b/spec/unit/agent/splayer.rb new file mode 100755 index 000000000..e097cc98b --- /dev/null +++ b/spec/unit/agent/splayer.rb @@ -0,0 +1,42 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet/agent/splayer' + +describe Puppet::Agent::Splayer do + it "should be able to splay" do + Puppet::Agent::Splayer.new.should respond_to(:splay) + end + + describe "when splaying" do + before do + @agent = Puppet::Agent::Splayer.new + @agent.stubs(:name).returns "foo" + + Puppet.settings.stubs(:value).with(:splaylimit).returns "1800" + Puppet.settings.stubs(:value).with(:splay).returns true + end + + it "should sleep if it has not previously splayed" do + Puppet.settings.expects(:value).with(:splay).returns true + @agent.expects(:sleep) + @agent.splay + end + + it "should do nothing if it has already splayed" do + @agent.expects(:sleep).once + @agent.splay + @agent.splay + end + + it "should log if it is sleeping" do + Puppet.settings.expects(:value).with(:splay).returns true + @agent.stubs(:sleep) + + Puppet.expects(:info) + + @agent.splay + end + end +end |