From 37692e5851dd3f7b15bde1caf785fb7801c97a25 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Mon, 19 Jan 2009 17:25:50 -0600 Subject: Renmaing Puppet::Network::Client::Master to Puppet::Agent Made minor changes, including removing the parent class. The functionality hasn't changed yet -- that comes in later patches -- but all but a couple of the older tests pass. Signed-off-by: Luke Kanies --- lib/puppet/agent.rb | 526 ++++++++++++++++++++++++++++++++++++ lib/puppet/network/client/master.rb | 523 ----------------------------------- spec/unit/agent.rb | 436 ++++++++++++++++++++++++++++++ spec/unit/network/client/master.rb | 442 ------------------------------ test/agent.rb | 419 ++++++++++++++++++++++++++++ test/network/client/master.rb | 472 -------------------------------- 6 files changed, 1381 insertions(+), 1437 deletions(-) create mode 100644 lib/puppet/agent.rb delete mode 100644 lib/puppet/network/client/master.rb create mode 100755 spec/unit/agent.rb delete mode 100755 spec/unit/network/client/master.rb create mode 100755 test/agent.rb delete mode 100755 test/network/client/master.rb diff --git a/lib/puppet/agent.rb b/lib/puppet/agent.rb new file mode 100644 index 000000000..f6d96acc2 --- /dev/null +++ b/lib/puppet/agent.rb @@ -0,0 +1,526 @@ +# The client for interacting with the puppetmaster config server. +require 'sync' +require 'timeout' +require 'puppet/network/http_pool' +require 'puppet/util' + +class Puppet::Agent + # For benchmarking + include Puppet::Util + + unless defined? @@sync + @@sync = Sync.new + end + + 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 self.facts + # Retrieve the facts from the central server. + if Puppet[:factsync] + self.getfacts() + end + + 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 + + # Add our client version to the list of facts, so people can use it + # in their manifests + facts["clientversion"] = Puppet.version.to_s + + # And add our environment as a fact. + unless facts.include?("environment") + facts["environment"] = Puppet[:environment] + end + + facts + end + + # Return the list of dynamic facts as an array of symbols + # NOTE:LAK(2008/04/10): This code is currently unused, since we now always + # recompile. + def self.dynamic_facts + # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com] + x = Puppet.settings[:dynamicfacts].split(/\s*,\s*/).collect { |fact| fact.downcase } + end + + # Cache the config + def cache(text) + Puppet.info "Caching catalog at %s" % self.cachefile + confdir = ::File.dirname(Puppet[:localconfig]) + ::File.open(self.cachefile + ".tmp", "w", 0660) { |f| + f.print text + } + ::File.rename(self.cachefile + ".tmp", self.cachefile) + end + + def cachefile + unless defined? @cachefile + @cachefile = Puppet[:localconfig] + ".yaml" + end + @cachefile + end + + def clear + @catalog.clear(true) if @catalog + @catalog = nil + end + + # Initialize and load storage + def dostorage + begin + Puppet::Util::Storage.load + @compile_time ||= Puppet::Util::Storage.cache(:configuration)[:compile_time] + rescue => detail + if Puppet[:trace] + puts detail.backtrace + end + Puppet.err "Corrupt state file %s: %s" % [Puppet[:statefile], detail] + begin + ::File.unlink(Puppet[:statefile]) + retry + rescue => detail + raise Puppet::Error.new("Cannot remove %s: %s" % + [Puppet[:statefile], detail]) + end + end + end + + # Let the daemon run again, freely in the filesystem. Frolick, little + # daemon! + def enable + lockfile.unlock(:anonymous => true) + end + + # Stop the daemon from making any catalog runs. + def disable + lockfile.lock(:anonymous => true) + end + + # Retrieve the config from a remote server. If this fails, then + # use the cached copy. + def getconfig + dostorage() + + # Retrieve the plugins. + getplugins() if Puppet[:pluginsync] + + facts = nil + Puppet::Util.benchmark(:debug, "Retrieved facts") do + facts = self.class.facts + end + + raise Puppet::Error.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 + + if ! @catalog.from_cache + self.cache(marshalled_objects) + end + + # Keep the state database up to date. + @catalog.host_config = true + end + + # A simple proxy method, so it's easy to test. + def getplugins + self.class.getplugins + end + + # Just so we can specify that we are "the" instance. + def initialize + Puppet.settings.use(:main, :ssl, :puppetd) + + 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 + + private + + # Download files from the remote server, returning a list of all + # changed files. + def self.download(args) + hash = { + :path => args[:dest], + :recurse => true, + :source => args[:source], + :tag => "#{args[:name]}s", + :owner => Process.uid, + :group => Process.gid, + :purge => true, + :force => true, + :backup => false, + :noop => false + } + + if args[:ignore] + hash[:ignore] = args[:ignore].split(/\s+/) + end + downconfig = Puppet::Resource::Catalog.new("downloading") + downconfig.add_resource Puppet::Type.type(:file).new(hash) + + Puppet.info "Retrieving #{args[:name]}s" + + files = [] + begin + Timeout::timeout(self.timeout) do + downconfig.apply do |trans| + trans.changed?.find_all do |resource| + yield resource if block_given? + files << resource[:path] + end + end + end + rescue Puppet::Error, Timeout::Error => detail + if Puppet[:debug] + puts detail.backtrace + end + Puppet.err "Could not retrieve %ss: %s" % [args[:name], detail] + end + + # Now clean up after ourselves + downconfig.clear + + return files + end + + # Retrieve facts from the central server. + def self.getfacts + # Download the new facts + path = Puppet[:factpath].split(":") + files = [] + download(:dest => Puppet[:factdest], :source => Puppet[:factsource], + :ignore => Puppet[:factsignore], :name => "fact") do |resource| + + next unless path.include?(::File.dirname(resource[:path])) + + files << resource[:path] + end + end + + # Retrieve the plugins from the central server. We only have to load the + # changed plugins, because Puppet::Type loads plugins on demand. + def self.getplugins + download(:dest => Puppet[:plugindest], :source => Puppet[:pluginsource], + :ignore => Puppet[:pluginsignore], :name => "plugin") do |resource| + + next if FileTest.directory?(resource[:path]) + path = resource[:path].sub(Puppet[:plugindest], '').sub(/^\/+/, '') + unless Puppet::Util::Autoload.loaded?(path) + next + end + + begin + Puppet.info "Reloading downloaded file %s" % path + load resource[:path] + rescue => detail + Puppet.warning "Could not reload downloaded file %s: %s" % + [resource[:path], detail] + end + end + end + + 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 + + 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() + + # Actually retrieve the catalog, either from the server or from a + # local master. + def get_actual_config(facts) + begin + Timeout::timeout(self.class.timeout) do + return get_remote_config(facts) + end + rescue Timeout::Error + Puppet.err "Configuration retrieval timed out" + return nil + end + end + + # Retrieve a config from a remote master. + def get_remote_config(facts) + textobjects = "" + + textfacts = CGI.escape(YAML.dump(facts)) + + 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 + Puppet::Util::Storage.cache(:configuration)[:facts] = facts + Puppet::Util::Storage.cache(:configuration)[:compile_time] = @compile_time + + return textobjects + end + + def lockfile + unless defined?(@lockfile) + @lockfile = Puppet::Util::Pidlock.new(Puppet[:puppetdlockfile]) + end + + @lockfile + end + + 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 + + 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/network/client/master.rb b/lib/puppet/network/client/master.rb deleted file mode 100644 index 047f2b82a..000000000 --- a/lib/puppet/network/client/master.rb +++ /dev/null @@ -1,523 +0,0 @@ -# The client for interacting with the puppetmaster config server. -require 'sync' -require 'timeout' -require 'puppet/network/http_pool' - -class Puppet::Network::Client::Master < Puppet::Network::Client - unless defined? @@sync - @@sync = Sync.new - end - - 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 self.facts - # Retrieve the facts from the central server. - if Puppet[:factsync] - self.getfacts() - end - - 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 - - # Add our client version to the list of facts, so people can use it - # in their manifests - facts["clientversion"] = Puppet.version.to_s - - # And add our environment as a fact. - unless facts.include?("environment") - facts["environment"] = Puppet[:environment] - end - - facts - end - - # Return the list of dynamic facts as an array of symbols - # NOTE:LAK(2008/04/10): This code is currently unused, since we now always - # recompile. - def self.dynamic_facts - # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com] - x = Puppet.settings[:dynamicfacts].split(/\s*,\s*/).collect { |fact| fact.downcase } - end - - # Cache the config - def cache(text) - Puppet.info "Caching catalog at %s" % self.cachefile - confdir = ::File.dirname(Puppet[:localconfig]) - ::File.open(self.cachefile + ".tmp", "w", 0660) { |f| - f.print text - } - ::File.rename(self.cachefile + ".tmp", self.cachefile) - end - - def cachefile - unless defined? @cachefile - @cachefile = Puppet[:localconfig] + ".yaml" - end - @cachefile - end - - def clear - @catalog.clear(true) if @catalog - @catalog = nil - end - - # Initialize and load storage - def dostorage - begin - Puppet::Util::Storage.load - @compile_time ||= Puppet::Util::Storage.cache(:configuration)[:compile_time] - rescue => detail - if Puppet[:trace] - puts detail.backtrace - end - Puppet.err "Corrupt state file %s: %s" % [Puppet[:statefile], detail] - begin - ::File.unlink(Puppet[:statefile]) - retry - rescue => detail - raise Puppet::Error.new("Cannot remove %s: %s" % - [Puppet[:statefile], detail]) - end - end - end - - # Let the daemon run again, freely in the filesystem. Frolick, little - # daemon! - def enable - lockfile.unlock(:anonymous => true) - end - - # Stop the daemon from making any catalog runs. - def disable - lockfile.lock(:anonymous => true) - end - - # Retrieve the config from a remote server. If this fails, then - # use the cached copy. - def getconfig - dostorage() - - # Retrieve the plugins. - getplugins() if Puppet[:pluginsync] - - 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 - - if ! @catalog.from_cache - self.cache(marshalled_objects) - end - - # Keep the state database up to date. - @catalog.host_config = true - end - - # A simple proxy method, so it's easy to test. - def getplugins - self.class.getplugins - 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 - - private - - # Download files from the remote server, returning a list of all - # changed files. - def self.download(args) - hash = { - :path => args[:dest], - :recurse => true, - :source => args[:source], - :tag => "#{args[:name]}s", - :owner => Process.uid, - :group => Process.gid, - :purge => true, - :force => true, - :backup => false, - :noop => false - } - - if args[:ignore] - hash[:ignore] = args[:ignore].split(/\s+/) - end - downconfig = Puppet::Resource::Catalog.new("downloading") - downconfig.add_resource Puppet::Type.type(:file).new(hash) - - Puppet.info "Retrieving #{args[:name]}s" - - files = [] - begin - Timeout::timeout(self.timeout) do - downconfig.apply do |trans| - trans.changed?.find_all do |resource| - yield resource if block_given? - files << resource[:path] - end - end - end - rescue Puppet::Error, Timeout::Error => detail - if Puppet[:debug] - puts detail.backtrace - end - Puppet.err "Could not retrieve %ss: %s" % [args[:name], detail] - end - - # Now clean up after ourselves - downconfig.clear - - return files - end - - # Retrieve facts from the central server. - def self.getfacts - # Download the new facts - path = Puppet[:factpath].split(":") - files = [] - download(:dest => Puppet[:factdest], :source => Puppet[:factsource], - :ignore => Puppet[:factsignore], :name => "fact") do |resource| - - next unless path.include?(::File.dirname(resource[:path])) - - files << resource[:path] - end - end - - # Retrieve the plugins from the central server. We only have to load the - # changed plugins, because Puppet::Type loads plugins on demand. - def self.getplugins - download(:dest => Puppet[:plugindest], :source => Puppet[:pluginsource], - :ignore => Puppet[:pluginsignore], :name => "plugin") do |resource| - - next if FileTest.directory?(resource[:path]) - path = resource[:path].sub(Puppet[:plugindest], '').sub(/^\/+/, '') - unless Puppet::Util::Autoload.loaded?(path) - next - end - - begin - Puppet.info "Reloading downloaded file %s" % path - load resource[:path] - rescue => detail - Puppet.warning "Could not reload downloaded file %s: %s" % - [resource[:path], detail] - end - end - end - - 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 - - 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() - - # Actually retrieve the catalog, either from the server or from a - # local master. - def get_actual_config(facts) - begin - Timeout::timeout(self.class.timeout) do - return get_remote_config(facts) - end - rescue Timeout::Error - Puppet.err "Configuration retrieval timed out" - return nil - end - end - - # Retrieve a config from a remote master. - def get_remote_config(facts) - textobjects = "" - - textfacts = CGI.escape(YAML.dump(facts)) - - 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 - Puppet::Util::Storage.cache(:configuration)[:facts] = facts - Puppet::Util::Storage.cache(:configuration)[:compile_time] = @compile_time - - return textobjects - end - - def lockfile - unless defined?(@lockfile) - @lockfile = Puppet::Util::Pidlock.new(Puppet[:puppetdlockfile]) - end - - @lockfile - end - - 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 - - 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/spec/unit/agent.rb b/spec/unit/agent.rb new file mode 100755 index 000000000..dc2fc9034 --- /dev/null +++ b/spec/unit/agent.rb @@ -0,0 +1,436 @@ +#!/usr/bin/env ruby +# +# Created by Luke Kanies on 2007-11-12. +# Copyright (c) 2007. All rights reserved. + +require File.dirname(__FILE__) + '/../spec_helper' +require 'puppet/agent' + +describe Puppet::Agent, " when retrieving the catalog" do + before do + Puppet.settings.stubs(:use).returns(true) + @client = Puppet::Agent.new + @facts = {"one" => "two", "three" => "four"} + end + + it "should initialize the metadata store" do + @client.class.stubs(:facts).returns(@facts) + @client.expects(:dostorage) + @master.stubs(:getconfig).returns(nil) + @client.getconfig + end + + it "should collect facts to use for catalog retrieval" do + @client.stubs(:dostorage) + @client.class.expects(:facts).returns(@facts) + @master.stubs(:getconfig).returns(nil) + @client.getconfig + end + + it "should fail if no facts could be collected" do + @client.stubs(:dostorage) + @client.class.expects(:facts).returns({}) + @master.stubs(:getconfig).returns(nil) + proc { @client.getconfig }.should raise_error(Puppet::Error) + end + + it "should retrieve plugins if :pluginsync is enabled" do + file = "/path/to/cachefile" + @client.stubs(:cachefile).returns(file) + @client.stubs(:dostorage) + @client.class.stubs(:facts).returns(@facts) + Puppet.settings.expects(:value).with(:pluginsync).returns(true) + @client.expects(:getplugins) + @client.stubs(:get_actual_config).returns(nil) + FileTest.stubs(:exist?).with(file).returns(true) + @client.stubs(:use_cached_config).returns(true) + @client.class.stubs(:facts).returns(@facts) + @client.getconfig + end + + it "should use the cached catalog if no catalog could be retrieved" do + @client.stubs(:dostorage) + @client.class.stubs(:facts).returns(@facts) + @master.stubs(:getconfig).raises(ArgumentError.new("whev")) + @client.expects(:use_cached_config).with(true) + @client.getconfig + end + + describe "when the catalog format is set to yaml" do + before do + Puppet.settings.stubs(:value).returns "foo" + Puppet.settings.stubs(:value).with(:pluginsync).returns false + Puppet.settings.stubs(:value).with(:configtimeout).returns 10 + Puppet.settings.stubs(:value).with(:factsync).returns false + Puppet.settings.stubs(:value).with(:catalog_format).returns "yaml" + end + + it "should request a yaml-encoded catalog" do + @client.stubs(:dostorage) + @client.class.stubs(:facts).returns(@facts) + @master.expects(:getconfig).with { |*args| args[1] == "yaml" } + + @client.getconfig + end + + it "should load the retrieved catalog using YAML" do + @client.stubs(:dostorage) + @client.class.stubs(:facts).returns(@facts) + @master.stubs(:getconfig).returns("myconfig") + + config = mock 'config' + YAML.expects(:load).with("myconfig").returns(config) + + @client.stubs(:setclasses) + + config.stubs(:classes) + config.stubs(:to_catalog).returns(config) + config.stubs(:host_config=) + config.stubs(:from_cache).returns(true) + + @client.getconfig + end + + it "should use the cached catalog if the retrieved catalog cannot be converted from YAML" do + @client.stubs(:dostorage) + @client.class.stubs(:facts).returns(@facts) + @master.stubs(:getconfig).returns("myconfig") + + YAML.expects(:load).with("myconfig").raises(ArgumentError) + + @client.expects(:use_cached_config).with(true) + + @client.getconfig + end + end + + describe "from Marshal" do + before do + Puppet.settings.stubs(:value).returns "foo" + Puppet.settings.stubs(:value).with(:pluginsync).returns false + Puppet.settings.stubs(:value).with(:configtimeout).returns 10 + Puppet.settings.stubs(:value).with(:factsync).returns false + Puppet.settings.stubs(:value).with(:catalog_format).returns "marshal" + end + + it "should load the retrieved catalog using Marshal" do + @client.stubs(:dostorage) + @client.class.stubs(:facts).returns(@facts) + @master.stubs(:getconfig).returns("myconfig") + + config = mock 'config' + Marshal.expects(:load).with("myconfig").returns(config) + + @client.stubs(:setclasses) + + config.stubs(:classes) + config.stubs(:to_catalog).returns(config) + config.stubs(:host_config=) + config.stubs(:from_cache).returns(true) + + @client.getconfig + end + + it "should use the cached catalog if the retrieved catalog cannot be converted from Marshal" do + @client.stubs(:dostorage) + @client.class.stubs(:facts).returns(@facts) + @master.stubs(:getconfig).returns("myconfig") + + Marshal.expects(:load).with("myconfig").raises(ArgumentError) + + @client.expects(:use_cached_config).with(true) + + @client.getconfig + end + end + + it "should set the classes.txt file with the classes listed in the retrieved catalog" do + @client.stubs(:dostorage) + @client.class.stubs(:facts).returns(@facts) + @master.stubs(:getconfig).returns("myconfig") + + config = mock 'config' + YAML.expects(:load).with("myconfig").returns(config) + + config.expects(:classes).returns(:myclasses) + @client.expects(:setclasses).with(:myclasses) + + config.stubs(:to_catalog).returns(config) + config.stubs(:host_config=) + config.stubs(:from_cache).returns(true) + + @client.getconfig + end + + it "should convert the retrieved catalog to a RAL catalog" do + @client.stubs(:dostorage) + @client.class.stubs(:facts).returns(@facts) + @master.stubs(:getconfig).returns("myconfig") + + yamlconfig = mock 'yaml config' + YAML.stubs(:load).returns(yamlconfig) + + @client.stubs(:setclasses) + + config = mock 'config' + + yamlconfig.stubs(:classes) + yamlconfig.expects(:to_catalog).returns(config) + + config.stubs(:host_config=) + config.stubs(:from_cache).returns(true) + + @client.getconfig + end + + it "should use the cached catalog if the retrieved catalog cannot be converted to a RAL catalog" do + @client.stubs(:dostorage) + @client.class.stubs(:facts).returns(@facts) + @master.stubs(:getconfig).returns("myconfig") + + yamlconfig = mock 'yaml config' + YAML.stubs(:load).returns(yamlconfig) + + @client.stubs(:setclasses) + + config = mock 'config' + + yamlconfig.stubs(:classes) + yamlconfig.expects(:to_catalog).raises(ArgumentError) + + @client.expects(:use_cached_config).with(true) + + @client.getconfig + end + + it "should clear the failed catalog if using the cached catalog after failing to instantiate the retrieved catalog" do + @client.stubs(:dostorage) + @client.class.stubs(:facts).returns(@facts) + @master.stubs(:getconfig).returns("myconfig") + + yamlconfig = mock 'yaml config' + YAML.stubs(:load).returns(yamlconfig) + + @client.stubs(:setclasses) + + config = mock 'config' + + yamlconfig.stubs(:classes) + yamlconfig.stubs(:to_catalog).raises(ArgumentError) + + @client.stubs(:use_cached_config).with(true) + + @client.expects(:clear) + + @client.getconfig + end + + it "should cache the retrieved yaml catalog if it is not from the cache and is valid" do + @client.stubs(:dostorage) + @client.class.stubs(:facts).returns(@facts) + @master.stubs(:getconfig).returns("myconfig") + + yamlconfig = mock 'yaml config' + YAML.stubs(:load).returns(yamlconfig) + + @client.stubs(:setclasses) + + config = mock 'config' + + yamlconfig.stubs(:classes) + yamlconfig.expects(:to_catalog).returns(config) + + config.stubs(:host_config=) + + config.expects(:from_cache).returns(false) + + @client.expects(:cache).with("myconfig") + + @client.getconfig + end + + it "should mark the catalog as a host catalog" do + @client.stubs(:dostorage) + @client.class.stubs(:facts).returns(@facts) + @master.stubs(:getconfig).returns("myconfig") + + yamlconfig = mock 'yaml config' + YAML.stubs(:load).returns(yamlconfig) + + @client.stubs(:setclasses) + + config = mock 'config' + + yamlconfig.stubs(:classes) + yamlconfig.expects(:to_catalog).returns(config) + + config.stubs(:from_cache).returns(true) + + config.expects(:host_config=).with(true) + + @client.getconfig + end +end + +describe Puppet::Agent, " when using the cached catalog" do + before do + Puppet.settings.stubs(:use).returns(true) + @client = Puppet::Agent.new + @facts = {"one" => "two", "three" => "four"} + end + + it "should return do nothing and true if there is already an in-memory catalog" do + @client.catalog = :whatever + Puppet::Agent.publicize_methods :use_cached_config do + @client.use_cached_config.should be_true + end + end + + it "should return do nothing and false if it has been told there is a failure and :nocacheonfailure is enabled" do + Puppet.settings.expects(:value).with(:usecacheonfailure).returns(false) + Puppet::Agent.publicize_methods :use_cached_config do + @client.use_cached_config(true).should be_false + end + end + + it "should return false if no cached catalog can be found" do + @client.expects(:retrievecache).returns(nil) + Puppet::Agent.publicize_methods :use_cached_config do + @client.use_cached_config().should be_false + end + end + + it "should return false if the cached catalog cannot be instantiated" do + YAML.expects(:load).raises(ArgumentError) + @client.expects(:retrievecache).returns("whatever") + Puppet::Agent.publicize_methods :use_cached_config do + @client.use_cached_config().should be_false + end + end + + it "should warn if the cached catalog cannot be instantiated" do + YAML.stubs(:load).raises(ArgumentError) + @client.stubs(:retrievecache).returns("whatever") + Puppet.expects(:warning).with { |m| m.include?("Could not load cache") } + Puppet::Agent.publicize_methods :use_cached_config do + @client.use_cached_config().should be_false + end + end + + it "should clear the client if the cached catalog cannot be instantiated" do + YAML.stubs(:load).raises(ArgumentError) + @client.stubs(:retrievecache).returns("whatever") + @client.expects(:clear) + Puppet::Agent.publicize_methods :use_cached_config do + @client.use_cached_config().should be_false + end + end + + it "should return true if the cached catalog can be instantiated" do + config = mock 'config' + YAML.stubs(:load).returns(config) + + ral_config = mock 'ral config' + ral_config.stubs(:from_cache=) + ral_config.stubs(:host_config=) + config.expects(:to_catalog).returns(ral_config) + + @client.stubs(:retrievecache).returns("whatever") + Puppet::Agent.publicize_methods :use_cached_config do + @client.use_cached_config().should be_true + end + end + + it "should set the catalog instance variable if the cached catalog can be instantiated" do + config = mock 'config' + YAML.stubs(:load).returns(config) + + ral_config = mock 'ral config' + ral_config.stubs(:from_cache=) + ral_config.stubs(:host_config=) + config.expects(:to_catalog).returns(ral_config) + + @client.stubs(:retrievecache).returns("whatever") + Puppet::Agent.publicize_methods :use_cached_config do + @client.use_cached_config() + end + + @client.catalog.should equal(ral_config) + end + + it "should mark the catalog as a host_config if valid" do + config = mock 'config' + YAML.stubs(:load).returns(config) + + ral_config = mock 'ral config' + ral_config.stubs(:from_cache=) + ral_config.expects(:host_config=).with(true) + config.expects(:to_catalog).returns(ral_config) + + @client.stubs(:retrievecache).returns("whatever") + Puppet::Agent.publicize_methods :use_cached_config do + @client.use_cached_config() + end + + @client.catalog.should equal(ral_config) + end + + it "should mark the catalog as from the cache if valid" do + config = mock 'config' + YAML.stubs(:load).returns(config) + + ral_config = mock 'ral config' + ral_config.expects(:from_cache=).with(true) + ral_config.stubs(:host_config=) + config.expects(:to_catalog).returns(ral_config) + + @client.stubs(:retrievecache).returns("whatever") + Puppet::Agent.publicize_methods :use_cached_config do + @client.use_cached_config() + end + + @client.catalog.should equal(ral_config) + end + + describe "when calling splay" do + it "should do nothing if splay is not enabled" do + Puppet.stubs(:[]).with(:splay).returns(false) + @client.expects(:rand).never + @client.send(:splay) + end + + describe "when splay is enabled" do + before do + Puppet.stubs(:[]).with(:splay).returns(true) + Puppet.stubs(:[]).with(:splaylimit).returns(42) + end + + it "should sleep for a random time plus 1" do + @client.expects(:rand).with(43).returns(43) + @client.expects(:sleep).with(43) + @client.send(:splay) + end + + it "should inform that it is splayed" do + @client.stubs(:rand).with(43).returns(43) + @client.stubs(:sleep).with(43) + Puppet.expects(:info) + @client.send(:splay) + end + + it "should set splay = true" do + @client.stubs(:rand).returns(43) + @client.stubs(:sleep) + @client.send(:splay) + @client.send(:splayed?).should == true + end + + it "should do nothing if already splayed" do + @client.stubs(:rand).returns(43).at_most_once + @client.stubs(:sleep).at_most_once + @client.send(:splay) + @client.send(:splay) + end + end + end +end diff --git a/spec/unit/network/client/master.rb b/spec/unit/network/client/master.rb deleted file mode 100755 index 050088707..000000000 --- a/spec/unit/network/client/master.rb +++ /dev/null @@ -1,442 +0,0 @@ -#!/usr/bin/env ruby -# -# Created by Luke Kanies on 2007-11-12. -# Copyright (c) 2007. All rights reserved. - -require File.dirname(__FILE__) + '/../../../spec_helper' -require 'puppet/network/client/master' - -describe Puppet::Network::Client::Master, " when retrieving the catalog" do - before do - Puppet.settings.stubs(:use).returns(true) - @master = mock 'master' - @client = Puppet::Network::Client.master.new( - :Master => @master - ) - @facts = {"one" => "two", "three" => "four"} - end - - it "should initialize the metadata store" do - @client.class.stubs(:facts).returns(@facts) - @client.expects(:dostorage) - @master.stubs(:getconfig).returns(nil) - @client.getconfig - end - - it "should collect facts to use for catalog retrieval" do - @client.stubs(:dostorage) - @client.class.expects(:facts).returns(@facts) - @master.stubs(:getconfig).returns(nil) - @client.getconfig - end - - it "should fail if no facts could be collected" do - @client.stubs(:dostorage) - @client.class.expects(:facts).returns({}) - @master.stubs(:getconfig).returns(nil) - proc { @client.getconfig }.should raise_error(Puppet::Network::ClientError) - end - - it "should retrieve plugins if :pluginsync is enabled" do - file = "/path/to/cachefile" - @client.stubs(:cachefile).returns(file) - @client.stubs(:dostorage) - @client.class.stubs(:facts).returns(@facts) - Puppet.settings.expects(:value).with(:pluginsync).returns(true) - @client.expects(:getplugins) - @client.stubs(:get_actual_config).returns(nil) - FileTest.stubs(:exist?).with(file).returns(true) - @client.stubs(:use_cached_config).returns(true) - @client.class.stubs(:facts).returns(@facts) - @client.getconfig - end - - it "should use the cached catalog if no catalog could be retrieved" do - @client.stubs(:dostorage) - @client.class.stubs(:facts).returns(@facts) - @master.stubs(:getconfig).raises(ArgumentError.new("whev")) - @client.expects(:use_cached_config).with(true) - @client.getconfig - end - - describe "when the catalog format is set to yaml" do - before do - Puppet.settings.stubs(:value).returns "foo" - Puppet.settings.stubs(:value).with(:pluginsync).returns false - Puppet.settings.stubs(:value).with(:configtimeout).returns 10 - Puppet.settings.stubs(:value).with(:factsync).returns false - Puppet.settings.stubs(:value).with(:catalog_format).returns "yaml" - end - - it "should request a yaml-encoded catalog" do - @client.stubs(:dostorage) - @client.class.stubs(:facts).returns(@facts) - @master.expects(:getconfig).with { |*args| args[1] == "yaml" } - - @client.getconfig - end - - it "should load the retrieved catalog using YAML" do - @client.stubs(:dostorage) - @client.class.stubs(:facts).returns(@facts) - @master.stubs(:getconfig).returns("myconfig") - - config = mock 'config' - YAML.expects(:load).with("myconfig").returns(config) - - @client.stubs(:setclasses) - - config.stubs(:classes) - config.stubs(:to_catalog).returns(config) - config.stubs(:host_config=) - config.stubs(:from_cache).returns(true) - - @client.getconfig - end - - it "should use the cached catalog if the retrieved catalog cannot be converted from YAML" do - @client.stubs(:dostorage) - @client.class.stubs(:facts).returns(@facts) - @master.stubs(:getconfig).returns("myconfig") - - YAML.expects(:load).with("myconfig").raises(ArgumentError) - - @client.expects(:use_cached_config).with(true) - - @client.getconfig - end - end - - describe "from Marshal" do - before do - Puppet.settings.stubs(:value).returns "foo" - Puppet.settings.stubs(:value).with(:pluginsync).returns false - Puppet.settings.stubs(:value).with(:configtimeout).returns 10 - Puppet.settings.stubs(:value).with(:factsync).returns false - Puppet.settings.stubs(:value).with(:catalog_format).returns "marshal" - end - - it "should load the retrieved catalog using Marshal" do - @client.stubs(:dostorage) - @client.class.stubs(:facts).returns(@facts) - @master.stubs(:getconfig).returns("myconfig") - - config = mock 'config' - Marshal.expects(:load).with("myconfig").returns(config) - - @client.stubs(:setclasses) - - config.stubs(:classes) - config.stubs(:to_catalog).returns(config) - config.stubs(:host_config=) - config.stubs(:from_cache).returns(true) - - @client.getconfig - end - - it "should use the cached catalog if the retrieved catalog cannot be converted from Marshal" do - @client.stubs(:dostorage) - @client.class.stubs(:facts).returns(@facts) - @master.stubs(:getconfig).returns("myconfig") - - Marshal.expects(:load).with("myconfig").raises(ArgumentError) - - @client.expects(:use_cached_config).with(true) - - @client.getconfig - end - end - - it "should set the classes.txt file with the classes listed in the retrieved catalog" do - @client.stubs(:dostorage) - @client.class.stubs(:facts).returns(@facts) - @master.stubs(:getconfig).returns("myconfig") - - config = mock 'config' - YAML.expects(:load).with("myconfig").returns(config) - - config.expects(:classes).returns(:myclasses) - @client.expects(:setclasses).with(:myclasses) - - config.stubs(:to_catalog).returns(config) - config.stubs(:host_config=) - config.stubs(:from_cache).returns(true) - - @client.getconfig - end - - it "should convert the retrieved catalog to a RAL catalog" do - @client.stubs(:dostorage) - @client.class.stubs(:facts).returns(@facts) - @master.stubs(:getconfig).returns("myconfig") - - yamlconfig = mock 'yaml config' - YAML.stubs(:load).returns(yamlconfig) - - @client.stubs(:setclasses) - - config = mock 'config' - - yamlconfig.stubs(:classes) - yamlconfig.expects(:to_catalog).returns(config) - - config.stubs(:host_config=) - config.stubs(:from_cache).returns(true) - - @client.getconfig - end - - it "should use the cached catalog if the retrieved catalog cannot be converted to a RAL catalog" do - @client.stubs(:dostorage) - @client.class.stubs(:facts).returns(@facts) - @master.stubs(:getconfig).returns("myconfig") - - yamlconfig = mock 'yaml config' - YAML.stubs(:load).returns(yamlconfig) - - @client.stubs(:setclasses) - - config = mock 'config' - - yamlconfig.stubs(:classes) - yamlconfig.expects(:to_catalog).raises(ArgumentError) - - @client.expects(:use_cached_config).with(true) - - @client.getconfig - end - - it "should clear the failed catalog if using the cached catalog after failing to instantiate the retrieved catalog" do - @client.stubs(:dostorage) - @client.class.stubs(:facts).returns(@facts) - @master.stubs(:getconfig).returns("myconfig") - - yamlconfig = mock 'yaml config' - YAML.stubs(:load).returns(yamlconfig) - - @client.stubs(:setclasses) - - config = mock 'config' - - yamlconfig.stubs(:classes) - yamlconfig.stubs(:to_catalog).raises(ArgumentError) - - @client.stubs(:use_cached_config).with(true) - - @client.expects(:clear) - - @client.getconfig - end - - it "should cache the retrieved yaml catalog if it is not from the cache and is valid" do - @client.stubs(:dostorage) - @client.class.stubs(:facts).returns(@facts) - @master.stubs(:getconfig).returns("myconfig") - - yamlconfig = mock 'yaml config' - YAML.stubs(:load).returns(yamlconfig) - - @client.stubs(:setclasses) - - config = mock 'config' - - yamlconfig.stubs(:classes) - yamlconfig.expects(:to_catalog).returns(config) - - config.stubs(:host_config=) - - config.expects(:from_cache).returns(false) - - @client.expects(:cache).with("myconfig") - - @client.getconfig - end - - it "should mark the catalog as a host catalog" do - @client.stubs(:dostorage) - @client.class.stubs(:facts).returns(@facts) - @master.stubs(:getconfig).returns("myconfig") - - yamlconfig = mock 'yaml config' - YAML.stubs(:load).returns(yamlconfig) - - @client.stubs(:setclasses) - - config = mock 'config' - - yamlconfig.stubs(:classes) - yamlconfig.expects(:to_catalog).returns(config) - - config.stubs(:from_cache).returns(true) - - config.expects(:host_config=).with(true) - - @client.getconfig - end -end - -describe Puppet::Network::Client::Master, " when using the cached catalog" do - before do - Puppet.settings.stubs(:use).returns(true) - @master = mock 'master' - @client = Puppet::Network::Client.master.new( - :Master => @master - ) - @facts = {"one" => "two", "three" => "four"} - end - - it "should return do nothing and true if there is already an in-memory catalog" do - @client.catalog = :whatever - Puppet::Network::Client::Master.publicize_methods :use_cached_config do - @client.use_cached_config.should be_true - end - end - - it "should return do nothing and false if it has been told there is a failure and :nocacheonfailure is enabled" do - Puppet.settings.expects(:value).with(:usecacheonfailure).returns(false) - Puppet::Network::Client::Master.publicize_methods :use_cached_config do - @client.use_cached_config(true).should be_false - end - end - - it "should return false if no cached catalog can be found" do - @client.expects(:retrievecache).returns(nil) - Puppet::Network::Client::Master.publicize_methods :use_cached_config do - @client.use_cached_config().should be_false - end - end - - it "should return false if the cached catalog cannot be instantiated" do - YAML.expects(:load).raises(ArgumentError) - @client.expects(:retrievecache).returns("whatever") - Puppet::Network::Client::Master.publicize_methods :use_cached_config do - @client.use_cached_config().should be_false - end - end - - it "should warn if the cached catalog cannot be instantiated" do - YAML.stubs(:load).raises(ArgumentError) - @client.stubs(:retrievecache).returns("whatever") - Puppet.expects(:warning).with { |m| m.include?("Could not load cache") } - Puppet::Network::Client::Master.publicize_methods :use_cached_config do - @client.use_cached_config().should be_false - end - end - - it "should clear the client if the cached catalog cannot be instantiated" do - YAML.stubs(:load).raises(ArgumentError) - @client.stubs(:retrievecache).returns("whatever") - @client.expects(:clear) - Puppet::Network::Client::Master.publicize_methods :use_cached_config do - @client.use_cached_config().should be_false - end - end - - it "should return true if the cached catalog can be instantiated" do - config = mock 'config' - YAML.stubs(:load).returns(config) - - ral_config = mock 'ral config' - ral_config.stubs(:from_cache=) - ral_config.stubs(:host_config=) - config.expects(:to_catalog).returns(ral_config) - - @client.stubs(:retrievecache).returns("whatever") - Puppet::Network::Client::Master.publicize_methods :use_cached_config do - @client.use_cached_config().should be_true - end - end - - it "should set the catalog instance variable if the cached catalog can be instantiated" do - config = mock 'config' - YAML.stubs(:load).returns(config) - - ral_config = mock 'ral config' - ral_config.stubs(:from_cache=) - ral_config.stubs(:host_config=) - config.expects(:to_catalog).returns(ral_config) - - @client.stubs(:retrievecache).returns("whatever") - Puppet::Network::Client::Master.publicize_methods :use_cached_config do - @client.use_cached_config() - end - - @client.catalog.should equal(ral_config) - end - - it "should mark the catalog as a host_config if valid" do - config = mock 'config' - YAML.stubs(:load).returns(config) - - ral_config = mock 'ral config' - ral_config.stubs(:from_cache=) - ral_config.expects(:host_config=).with(true) - config.expects(:to_catalog).returns(ral_config) - - @client.stubs(:retrievecache).returns("whatever") - Puppet::Network::Client::Master.publicize_methods :use_cached_config do - @client.use_cached_config() - end - - @client.catalog.should equal(ral_config) - end - - it "should mark the catalog as from the cache if valid" do - config = mock 'config' - YAML.stubs(:load).returns(config) - - ral_config = mock 'ral config' - ral_config.expects(:from_cache=).with(true) - ral_config.stubs(:host_config=) - config.expects(:to_catalog).returns(ral_config) - - @client.stubs(:retrievecache).returns("whatever") - Puppet::Network::Client::Master.publicize_methods :use_cached_config do - @client.use_cached_config() - end - - @client.catalog.should equal(ral_config) - end - - describe "when calling splay" do - it "should do nothing if splay is not enabled" do - Puppet.stubs(:[]).with(:splay).returns(false) - @client.expects(:rand).never - @client.send(:splay) - end - - describe "when splay is enabled" do - before do - Puppet.stubs(:[]).with(:splay).returns(true) - Puppet.stubs(:[]).with(:splaylimit).returns(42) - end - - it "should sleep for a random time plus 1" do - @client.expects(:rand).with(43).returns(43) - @client.expects(:sleep).with(43) - @client.send(:splay) - end - - it "should inform that it is splayed" do - @client.stubs(:rand).with(43).returns(43) - @client.stubs(:sleep).with(43) - Puppet.expects(:info) - @client.send(:splay) - end - - it "should set splay = true" do - @client.stubs(:rand).returns(43) - @client.stubs(:sleep) - @client.send(:splay) - @client.send(:splayed?).should == true - end - - it "should do nothing if already splayed" do - @client.stubs(:rand).returns(43).at_most_once - @client.stubs(:sleep).at_most_once - @client.send(:splay) - @client.send(:splay) - end - end - end -end diff --git a/test/agent.rb b/test/agent.rb new file mode 100755 index 000000000..775e16d02 --- /dev/null +++ b/test/agent.rb @@ -0,0 +1,419 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/lib/puppettest' + +require 'puppettest' +require 'puppet/agent' +require 'mocha' + +class TestAgent < Test::Unit::TestCase + include PuppetTest::ServerTest + + def setup + super + @agent_class = Puppet::Agent + end + + def test_disable + FileUtils.mkdir_p(Puppet[:statedir]) + + client = Puppet::Agent.new + + assert_nothing_raised("Could not disable client") { + client.disable + } + + client.expects(:getconfig).never + + client.run + + client = Puppet::Agent.new + + client.expects(:getconfig) + + assert_nothing_raised("Could not enable client") { + client.enable + } + client.run + end + + # Make sure we're getting the client version in our list of facts + def test_clientversionfact + facts = nil + assert_nothing_raised { + facts = Puppet::Agent.facts + } + + assert_equal(Puppet.version.to_s, facts["clientversion"]) + + end + + # Make sure non-string facts don't make things go kablooie + def test_nonstring_facts + FileUtils.mkdir_p(Puppet[:statedir]) + # Add a nonstring fact + Facter.add("nonstring") do + setcode { 1 } + end + + # so we don't lose our fact setting + Facter.stubs(:clear) + Puppet::Agent.stubs(:loadfacts) + + assert_equal("1", Puppet::Agent.facts["nonstring"], "Did not convert all facts to strings") + end + + # This method downloads files, and yields each file object if a block is given. + def test_download + source = tempfile() + dest = tempfile() + sfile = File.join(source, "file") + dfile = File.join(dest, "file") + Dir.mkdir(source) + File.open(sfile, "w") {|f| f.puts "yay"} + + files = [] + assert_nothing_raised do + files = Puppet::Agent.download(:dest => dest, :source => source, :name => "testing") + end + + assert(FileTest.directory?(dest), "dest dir was not created") + assert(FileTest.file?(dfile), "dest file was not created") + assert_equal(File.read(sfile), File.read(dfile), "Dest file had incorrect contents") + assert_equal([dest, dfile].sort, files.sort, "Changed files were not returned correctly") + end + + def test_getplugins + Puppet[:filetimeout] = -1 + Puppet[:pluginsource] = tempfile() + Dir.mkdir(Puppet[:pluginsource]) + Dir.mkdir(File.join(Puppet[:pluginsource], "testing")) + + $loaded = [] + loader = Puppet::Util::Autoload.new(self, "testing") + + myplugin = File.join(Puppet[:pluginsource], "testing", "myplugin.rb") + File.open(myplugin, "w") do |f| + f.puts %{$loaded << :myplugin} + end + + assert_nothing_raised("Could not get plugins") { + Puppet::Agent.getplugins + } + + destfile = File.join(Puppet[:plugindest], "testing", "myplugin.rb") + + assert(File.exists?(destfile), "Did not get plugin") + + assert(loader.load(:myplugin), "Did not load downloaded plugin") + + assert($loaded.include?(:myplugin), "Downloaded code was not evaluated") + + # Now modify the file and make sure the type is replaced + File.open(myplugin, "w") do |f| + f.puts %{$loaded << :changed} + end + + assert_nothing_raised("Could not get plugin changes") { + Puppet::Agent.getplugins + } + + assert($loaded.include?(:changed), "Changed code was not evaluated") + + # Now try it again, to make sure we don't have any objects lying around + assert_nothing_raised { + Puppet::Agent.getplugins + } + end + + def test_getfacts + Puppet[:filetimeout] = -1 + Puppet[:factsource] = tempfile() + Dir.mkdir(Puppet[:factsource]) + hostname = Facter.value(:hostname) + + myfact = File.join(Puppet[:factsource], "myfact.rb") + File.open(myfact, "w") do |f| + f.puts %{Facter.add("myfact") do + setcode { "yayness" } +end +} + end + + assert_nothing_raised { + Puppet::Agent.getfacts + } + + destfile = File.join(Puppet[:factdest], "myfact.rb") + + assert(File.exists?(destfile), "Did not get fact") + + facts = Puppet::Agent.facts + + assert_equal(hostname, facts["hostname"], + "Lost value to hostname") + + assert_equal("yayness", facts["myfact"], + "Did not get correct fact value") + + # Now modify the file and make sure the type is replaced + File.open(myfact, "w") do |f| + f.puts %{Facter.add("myfact") do + setcode { "funtest" } +end +} + end + + assert_nothing_raised { + Puppet::Agent.getfacts + } + facts = Puppet::Agent.facts + + assert_equal("funtest", facts["myfact"], + "Did not reload fact") + assert_equal(hostname, facts["hostname"], + "Lost value to hostname") + + # Now run it again and make sure the fact still loads + assert_nothing_raised { + Puppet::Agent.getfacts + } + facts = Puppet::Agent.facts + + assert_equal("funtest", facts["myfact"], + "Did not reload fact") + assert_equal(hostname, facts["hostname"], + "Lost value to hostname") + end + + # Make sure that setting environment by fact takes precedence to configuration + def test_setenvironmentwithfact + name = "environment" + value = "test_environment" + + Facter.stubs(:to_hash).returns(name => value) + + assert_equal(value, Puppet::Agent.facts[name]) + end + + # Make sure we load all facts on startup. + def test_loadfacts + dirs = [tempfile(), tempfile()] + count = 0 + names = [] + dirs.each do |dir| + Dir.mkdir(dir) + name = "fact%s" % count + names << name + file = File.join(dir, "%s.rb" % name) + + # Write out a plugin file + File.open(file, "w") do |f| + f.puts %{Facter.add("#{name}") do setcode { "#{name}" } end } + end + count += 1 + end + + Puppet[:factpath] = dirs.join(":") + + names.each do |name| + assert_nil(Facter.value(name), "Somehow retrieved invalid fact") + end + + assert_nothing_raised { + Puppet::Agent.loadfacts + } + + names.each do |name| + assert_equal(name, Facter.value(name), + "Did not retrieve facts") + end + end + + if Process.uid == 0 + # Testing #283. Make sure plugins et al are downloaded as the running user. + def test_download_ownership + dir = tstdir() + dest = tstdir() + file = File.join(dir, "file") + File.open(file, "w") { |f| f.puts "funtest" } + + user = nonrootuser() + group = nonrootgroup() + chowner = Puppet::Type.type(:file).new :path => dir, + :owner => user.name, :group => group.name, :recurse => true + assert_apply(chowner) + chowner.remove + + assert_equal(user.uid, File.stat(file).uid) + assert_equal(group.gid, File.stat(file).gid) + + + assert_nothing_raised { + Puppet::Agent.download(:dest => dest, :source => dir, + :name => "testing" + ) {} + } + + destfile = File.join(dest, "file") + + assert(FileTest.exists?(destfile), "Did not create destfile") + + assert_equal(Process.uid, File.stat(destfile).uid) + end + end + + # Test retrieving all of the facts. + def test_facts + facts = nil + assert_nothing_raised do + facts = Puppet::Agent.facts + end + Facter.to_hash.each do |fact, value| + assert_equal(facts[fact.downcase], value.to_s, "%s is not equal" % fact.inspect) + end + + # Make sure the puppet version got added + assert_equal(Puppet::PUPPETVERSION, facts["clientversion"], "client version did not get added") + + # And make sure the ruby version is in there + assert_equal(RUBY_VERSION, facts["rubyversion"], "ruby version did not get added") + end + + # #540 - make sure downloads aren't affected by noop + def test_download_in_noop + source = tempfile + File.open(source, "w") { |f| f.puts "something" } + dest = tempfile + Puppet[:noop] = true + node = stub 'node', :environment => "development" + Puppet::Node.stubs(:find).returns node + assert_nothing_raised("Could not download in noop") do + @agent_class.download(:dest => dest, :source => source, :tag => "yay") + end + + assert(FileTest.exists?(dest), "did not download in noop mode") + + assert(Puppet[:noop], "noop got disabled in run") + end + + # #491 - make sure a missing config doesn't kill us + def test_missing_localconfig + master = Puppet::Agent.new + Puppet::Node::Facts.indirection.stubs(:save) + # Retrieve the configuration + + master.getconfig + + # Now the config is up to date, so get rid of the @objects var and + # the cached config + master.clear + File.unlink(master.cachefile) + + assert_nothing_raised("Missing cache file threw error") do + master.getconfig + end + + assert(! @logs.detect { |l| l.message =~ /Could not load/}, + "Tried to load cache when it is non-existent") + end + + def test_locking + master = Puppet::Agent.new + + class << master + def getconfig + raise ArgumentError, "Just testing" + end + end + + master.run + + assert(! master.send(:lockfile).locked?, + "Master is still locked after failure") + end + + # Make sure we get a value for timeout + def test_config_timeout + master = Puppet::Agent + time = Integer(Puppet[:configtimeout]) + assert_equal(time, master.timeout, "Did not get default value for timeout") + assert_equal(time, master.timeout, "Did not get default value for timeout on second run") + + # Reset it + Puppet[:configtimeout] = "50" + assert_equal(50, master.timeout, "Did not get changed default value for timeout") + assert_equal(50, master.timeout, "Did not get changed default value for timeout on second run") + + # Now try an integer + Puppet[:configtimeout] = 100 + assert_equal(100, master.timeout, "Did not get changed integer default value for timeout") + assert_equal(100, master.timeout, "Did not get changed integer default value for timeout on second run") + end + + def test_splay + client = Puppet::Agent.new + + # Make sure we default to no splay + client.expects(:sleep).never + + assert_nothing_raised("Failed to call splay") do + client.send(:splay) + end + + # Now set it to true and make sure we get the right value + client = Puppet::Agent.new + client.expects(:sleep) + + Puppet[:splay] = true + assert_nothing_raised("Failed to call sleep when splay is true") do + client.send(:splay) + end + + # Now try it again + client = Puppet::Agent.new + client.expects(:sleep) + + assert_nothing_raised("Failed to call sleep when splay is true with a cached value") do + client.send(:splay) + end + end + + def test_environment_is_added_to_facts + facts = Puppet::Agent.facts + assert_equal(facts["environment"], Puppet[:environment], "Did not add environment to client facts") + + # Now set it to a real value + Puppet[:environment] = "something" + facts = Puppet::Agent.facts + assert_equal(facts["environment"], Puppet[:environment], "Did not add environment to client facts") + end + + # #685 + def test_http_failures_do_not_kill_puppetd + client = Puppet::Agent.new + + client.meta_def(:getconfig) { raise "A failure" } + + assert_nothing_raised("Failure in getconfig threw an error") do + client.run + end + end + + def test_classfile + Puppet[:code] = "class yaytest {}\n class bootest {}\n include yaytest, bootest" + + Puppet::Node::Facts.indirection.stubs(:save) + + client = Puppet::Agent.new + + # We can't guarantee class ordering + client.expects(:setclasses).with do |array| + array.length == 2 and array.include?("yaytest") and array.include?("bootest") + end + + assert_nothing_raised { + client.getconfig + } + end +end diff --git a/test/network/client/master.rb b/test/network/client/master.rb deleted file mode 100755 index ee6a2c6ab..000000000 --- a/test/network/client/master.rb +++ /dev/null @@ -1,472 +0,0 @@ -#!/usr/bin/env ruby - -require File.dirname(__FILE__) + '/../../lib/puppettest' - -require 'puppettest' -require 'mocha' - -class TestMasterClient < Test::Unit::TestCase - include PuppetTest::ServerTest - - def setup - super - @master = Puppet::Network::Client.master - end - - def mkmaster(options = {}) - options[:UseNodes] = false - options[:Local] = true - if code = options[:Code] - Puppet[:code] = code - else - Puppet[:manifest] = options[:Manifest] || mktestmanifest - end - # create our master - # this is the default server setup - master = Puppet::Network::Handler.master.new(options) - return master - end - - def mkclient(master = nil) - master ||= mkmaster() - client = Puppet::Network::Client.master.new( - :Master => master - ) - - return client - end - - def test_disable - FileUtils.mkdir_p(Puppet[:statedir]) - manifest = mktestmanifest - - master = mkmaster(:Manifest => manifest) - - client = mkclient(master) - - assert_nothing_raised("Could not disable client") { - client.disable - } - - client.expects(:getconfig).never - - client.run - - client = mkclient(master) - - client.expects(:getconfig) - - assert_nothing_raised("Could not enable client") { - client.enable - } - client.run - end - - # Make sure we're getting the client version in our list of facts - def test_clientversionfact - facts = nil - assert_nothing_raised { - facts = Puppet::Network::Client.master.facts - } - - assert_equal(Puppet.version.to_s, facts["clientversion"]) - - end - - # Make sure non-string facts don't make things go kablooie - def test_nonstring_facts - FileUtils.mkdir_p(Puppet[:statedir]) - # Add a nonstring fact - Facter.add("nonstring") do - setcode { 1 } - end - - assert_equal(1, Facter.nonstring, "Fact was a string from facter") - - client = mkclient() - - assert(! FileTest.exists?(@createdfile)) - - assert_nothing_raised { - client.run - } - end - - # This method downloads files, and yields each file object if a block is given. - def test_download - source = tempfile() - dest = tempfile() - sfile = File.join(source, "file") - dfile = File.join(dest, "file") - Dir.mkdir(source) - File.open(sfile, "w") {|f| f.puts "yay"} - - files = [] - assert_nothing_raised do - files = Puppet::Network::Client.master.download(:dest => dest, :source => source, :name => "testing") - end - - assert(FileTest.directory?(dest), "dest dir was not created") - assert(FileTest.file?(dfile), "dest file was not created") - assert_equal(File.read(sfile), File.read(dfile), "Dest file had incorrect contents") - assert_equal([dest, dfile].sort, files.sort, "Changed files were not returned correctly") - end - - def test_getplugins - Puppet[:filetimeout] = -1 - Puppet[:pluginsource] = tempfile() - Dir.mkdir(Puppet[:pluginsource]) - Dir.mkdir(File.join(Puppet[:pluginsource], "testing")) - - $loaded = [] - loader = Puppet::Util::Autoload.new(self, "testing") - - myplugin = File.join(Puppet[:pluginsource], "testing", "myplugin.rb") - File.open(myplugin, "w") do |f| - f.puts %{$loaded << :myplugin} - end - - assert_nothing_raised("Could not get plugins") { - Puppet::Network::Client.master.getplugins - } - - destfile = File.join(Puppet[:plugindest], "testing", "myplugin.rb") - - assert(File.exists?(destfile), "Did not get plugin") - - assert(loader.load(:myplugin), "Did not load downloaded plugin") - - assert($loaded.include?(:myplugin), "Downloaded code was not evaluated") - - # Now modify the file and make sure the type is replaced - File.open(myplugin, "w") do |f| - f.puts %{$loaded << :changed} - end - - assert_nothing_raised("Could not get plugin changes") { - Puppet::Network::Client.master.getplugins - } - - assert($loaded.include?(:changed), "Changed code was not evaluated") - - # Now try it again, to make sure we don't have any objects lying around - assert_nothing_raised { - Puppet::Network::Client.master.getplugins - } - end - - def test_getfacts - Puppet[:filetimeout] = -1 - Puppet[:factsource] = tempfile() - Dir.mkdir(Puppet[:factsource]) - hostname = Facter.value(:hostname) - - myfact = File.join(Puppet[:factsource], "myfact.rb") - File.open(myfact, "w") do |f| - f.puts %{Facter.add("myfact") do - setcode { "yayness" } -end -} - end - - assert_nothing_raised { - Puppet::Network::Client.master.getfacts - } - - destfile = File.join(Puppet[:factdest], "myfact.rb") - - assert(File.exists?(destfile), "Did not get fact") - - facts = Puppet::Network::Client.master.facts - - assert_equal(hostname, facts["hostname"], - "Lost value to hostname") - - assert_equal("yayness", facts["myfact"], - "Did not get correct fact value") - - # Now modify the file and make sure the type is replaced - File.open(myfact, "w") do |f| - f.puts %{Facter.add("myfact") do - setcode { "funtest" } -end -} - end - - assert_nothing_raised { - Puppet::Network::Client.master.getfacts - } - facts = Puppet::Network::Client.master.facts - - assert_equal("funtest", facts["myfact"], - "Did not reload fact") - assert_equal(hostname, facts["hostname"], - "Lost value to hostname") - - # Now run it again and make sure the fact still loads - assert_nothing_raised { - Puppet::Network::Client.master.getfacts - } - facts = Puppet::Network::Client.master.facts - - assert_equal("funtest", facts["myfact"], - "Did not reload fact") - assert_equal(hostname, facts["hostname"], - "Lost value to hostname") - end - - # Make sure that setting environment by fact takes precedence to configuration - def test_setenvironmentwithfact - name = "environment" - value = "test_environment" - - Facter.stubs(:to_hash).returns(name => value) - - assert_equal(value, Puppet::Network::Client.master.facts[name]) - end - - # Make sure we load all facts on startup. - def test_loadfacts - dirs = [tempfile(), tempfile()] - count = 0 - names = [] - dirs.each do |dir| - Dir.mkdir(dir) - name = "fact%s" % count - names << name - file = File.join(dir, "%s.rb" % name) - - # Write out a plugin file - File.open(file, "w") do |f| - f.puts %{Facter.add("#{name}") do setcode { "#{name}" } end } - end - count += 1 - end - - Puppet[:factpath] = dirs.join(":") - - names.each do |name| - assert_nil(Facter.value(name), "Somehow retrieved invalid fact") - end - - assert_nothing_raised { - Puppet::Network::Client.master.loadfacts - } - - names.each do |name| - assert_equal(name, Facter.value(name), - "Did not retrieve facts") - end - end - - if Process.uid == 0 - # Testing #283. Make sure plugins et al are downloaded as the running user. - def test_download_ownership - dir = tstdir() - dest = tstdir() - file = File.join(dir, "file") - File.open(file, "w") { |f| f.puts "funtest" } - - user = nonrootuser() - group = nonrootgroup() - chowner = Puppet::Type.type(:file).new :path => dir, - :owner => user.name, :group => group.name, :recurse => true - assert_apply(chowner) - chowner.remove - - assert_equal(user.uid, File.stat(file).uid) - assert_equal(group.gid, File.stat(file).gid) - - - assert_nothing_raised { - Puppet::Network::Client.master.download(:dest => dest, :source => dir, - :name => "testing" - ) {} - } - - destfile = File.join(dest, "file") - - assert(FileTest.exists?(destfile), "Did not create destfile") - - assert_equal(Process.uid, File.stat(destfile).uid) - end - end - - # Test retrieving all of the facts. - def test_facts - facts = nil - assert_nothing_raised do - facts = Puppet::Network::Client.master.facts - end - Facter.to_hash.each do |fact, value| - assert_equal(facts[fact.downcase], value.to_s, "%s is not equal" % fact.inspect) - end - - # Make sure the puppet version got added - assert_equal(Puppet::PUPPETVERSION, facts["clientversion"], "client version did not get added") - - # And make sure the ruby version is in there - assert_equal(RUBY_VERSION, facts["rubyversion"], "ruby version did not get added") - end - - # #540 - make sure downloads aren't affected by noop - def test_download_in_noop - source = tempfile - File.open(source, "w") { |f| f.puts "something" } - dest = tempfile - Puppet[:noop] = true - node = stub 'node', :environment => "development" - Puppet::Node.stubs(:find).returns node - assert_nothing_raised("Could not download in noop") do - @master.download(:dest => dest, :source => source, :tag => "yay") - end - - assert(FileTest.exists?(dest), "did not download in noop mode") - - assert(Puppet[:noop], "noop got disabled in run") - end - - # #491 - make sure a missing config doesn't kill us - def test_missing_localconfig - master = mkclient - master.local = false - driver = master.send(:instance_variable_get, "@driver") - driver.local = false - Puppet::Node::Facts.indirection.stubs(:save) - # Retrieve the configuration - - master.getconfig - - # Now the config is up to date, so get rid of the @objects var and - # the cached config - master.clear - File.unlink(master.cachefile) - - assert_nothing_raised("Missing cache file threw error") do - master.getconfig - end - - assert(! @logs.detect { |l| l.message =~ /Could not load/}, - "Tried to load cache when it is non-existent") - end - - def test_locking - master = mkclient - - class << master - def getconfig - raise ArgumentError, "Just testing" - end - end - - master.run - - assert(! master.send(:lockfile).locked?, - "Master is still locked after failure") - end - - # Make sure we get a value for timeout - def test_config_timeout - master = Puppet::Network::Client.client(:master) - time = Integer(Puppet[:configtimeout]) - assert_equal(time, master.timeout, "Did not get default value for timeout") - assert_equal(time, master.timeout, "Did not get default value for timeout on second run") - - # Reset it - Puppet[:configtimeout] = "50" - assert_equal(50, master.timeout, "Did not get changed default value for timeout") - assert_equal(50, master.timeout, "Did not get changed default value for timeout on second run") - - # Now try an integer - Puppet[:configtimeout] = 100 - assert_equal(100, master.timeout, "Did not get changed integer default value for timeout") - assert_equal(100, master.timeout, "Did not get changed integer default value for timeout on second run") - end - - def test_splay - client = mkclient - - # Make sure we default to no splay - client.expects(:sleep).never - - assert_nothing_raised("Failed to call splay") do - client.send(:splay) - end - - # Now set it to true and make sure we get the right value - client = mkclient - client.expects(:sleep) - - Puppet[:splay] = true - assert_nothing_raised("Failed to call sleep when splay is true") do - client.send(:splay) - end - - # Now try it again - client = mkclient - client.expects(:sleep) - - assert_nothing_raised("Failed to call sleep when splay is true with a cached value") do - client.send(:splay) - end - end - - def test_environment_is_added_to_facts - facts = Puppet::Network::Client::Master.facts - assert_equal(facts["environment"], Puppet[:environment], "Did not add environment to client facts") - - # Now set it to a real value - Puppet[:environment] = "something" - facts = Puppet::Network::Client::Master.facts - assert_equal(facts["environment"], Puppet[:environment], "Did not add environment to client facts") - end - - # #685 - def test_http_failures_do_not_kill_puppetd - client = mkclient - - client.meta_def(:getconfig) { raise "A failure" } - - assert_nothing_raised("Failure in getconfig threw an error") do - client.run - end - end - - def test_invalid_catalogs_do_not_get_cached - master = mkmaster :Code => "notify { one: require => File[yaytest] }" - master.local = false # so it gets cached - client = mkclient(master) - client.stubs(:facts).returns({}) - client.local = false - - Puppet::Node::Facts.indirection.stubs(:terminus_class).returns(:memory) - - # Make sure the config is not cached. - client.expects(:cache).never - - client.getconfig - # Doesn't throw an exception, but definitely fails. - client.run - end - - def test_classfile - Puppet[:code] = "class yaytest {}\n class bootest {}\n include yaytest, bootest" - - Puppet::Node::Facts.indirection.stubs(:save) - - master = Puppet::Network::Handler.master.new( :Local => false) - client = Puppet::Network::Client.master.new( :Master => master) - - # Fake that it's local, so it creates the class file - client.local = false - - # We can't guarantee class ordering - client.expects(:setclasses).with do |array| - array.length == 2 and array.include?("yaytest") and array.include?("bootest") - end - - assert_nothing_raised { - client.getconfig - } - end -end -- cgit