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)
downloadpuppet-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-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