summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuke Kanies <luke@madstop.com>2009-01-19 16:29:17 -0600
committerLuke Kanies <luke@madstop.com>2009-02-06 18:08:39 -0600
commit8f5cbc349daa868020b009851ee97ea3f29fcfbf (patch)
tree5cfc7826cb90d7daf8aa1014b83ee1877255ebee
parent25b28c58c22bae718794dc679f10c61665af0b15 (diff)
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-xbin/puppetd13
-rw-r--r--lib/puppet/agent.rb429
-rw-r--r--lib/puppet/agent/downloader.rb24
-rw-r--r--lib/puppet/agent/splayer.rb29
-rwxr-xr-xspec/unit/agent.rb219
-rwxr-xr-xspec/unit/agent/downloader.rb19
-rwxr-xr-xspec/unit/agent/splayer.rb42
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