diff --git a/lib/puppet/application/puppet.rb b/lib/puppet/application/puppet.rb index ee848a503..dd752846c 100644 --- a/lib/puppet/application/puppet.rb +++ b/lib/puppet/application/puppet.rb @@ -1,137 +1,171 @@ require 'puppet' require 'puppet/application' require 'puppet/network/handler' require 'puppet/network/client' Puppet::Application.new(:puppet) do should_parse_config option("--debug","-d") option("--execute EXECUTE","-e") do |arg| options[:code] = arg end option("--loadclasses","-L") option("--verbose","-v") option("--use-nodes") option("--detailed-exitcodes") + option("--apply catalog", "-a catalog") do |arg| + options[:catalog] = arg + end + option("--logdest LOGDEST", "-l") do |arg| begin Puppet::Util::Log.newdestination(arg) options[:logset] = true rescue => detail $stderr.puts detail.to_s end end dispatch do - return Puppet[:parseonly] ? :parseonly : :main + if options[:catalog] + :apply + elsif Puppet[:parseonly] + :parseonly + else + :main + end + end + + command(:apply) do + require 'puppet/configurer' + + if options[:catalog] == "-" + text = $stdin.read + else + text = File.read(options[:catalog]) + end + + begin + catalog = JSON.parse(text) + unless catalog.is_a?(Puppet::Resource::Catalog) + catalog = Puppet::Resource::Catalog.json_create(catalog) + end + rescue => detail + raise Puppet::Error, "Could not deserialize catalog from json: %s" % detail + end + + catalog = catalog.to_ral + + configurer = Puppet::Configurer.new + configurer.run :catalog => catalog end command(:parseonly) do begin Puppet::Parser::Interpreter.new.parser(Puppet[:environment]) rescue => detail Puppet.err detail exit 1 end exit 0 end command(:main) do + # Set our code or file to use. + if options[:code] or ARGV.length == 0 + Puppet[:code] = options[:code] || STDIN.read + else + Puppet[:manifest] = ARGV.shift + end + # Collect our facts. facts = Puppet::Node::Facts.find(Puppet[:certname]) # Find our Node unless node = Puppet::Node.find(Puppet[:certname]) raise "Could not find node %s" % Puppet[:certname] end # Merge in the facts. node.merge(facts.values) # Allow users to load the classes that puppetd creates. if options[:loadclasses] file = Puppet[:classfile] if FileTest.exists?(file) unless FileTest.readable?(file) $stderr.puts "%s is not readable" % file exit(63) end node.classes = File.read(file).split(/[\s\n]+/) end end begin # Compile our catalog starttime = Time.now catalog = Puppet::Resource::Catalog.find(node.name, :use_node => node) # Translate it to a RAL catalog catalog = catalog.to_ral catalog.host_config = true if Puppet[:graph] or Puppet[:report] catalog.finalize catalog.retrieval_duration = Time.now - starttime # And apply it transaction = catalog.apply status = 0 if not Puppet[:noop] and options[:detailed_exitcodes] then transaction.generate_report status |= 2 if transaction.report.metrics["changes"][:total] > 0 status |= 4 if transaction.report.metrics["resources"][:failed] > 0 end exit(status) rescue => detail if Puppet[:trace] puts detail.backtrace end if detail.is_a?(XMLRPC::FaultException) $stderr.puts detail.message else $stderr.puts detail end exit(1) end end setup do if Puppet.settings.print_configs? exit(Puppet.settings.print_configs ? 0 : 1) end # If noop is set, then also enable diffs if Puppet[:noop] Puppet[:show_diff] = true end unless options[:logset] Puppet::Util::Log.newdestination(:console) end client = nil server = nil trap(:INT) do $stderr.puts "Exiting" exit(1) end if options[:debug] Puppet::Util::Log.level = :debug elsif options[:verbose] Puppet::Util::Log.level = :info end - - # Set our code or file to use. - if options[:code] or ARGV.length == 0 - Puppet[:code] = options[:code] || STDIN.read - else - Puppet[:manifest] = ARGV.shift - end end end diff --git a/lib/puppet/configurer.rb b/lib/puppet/configurer.rb index 8ec0b0055..81845f5cf 100644 --- a/lib/puppet/configurer.rb +++ b/lib/puppet/configurer.rb @@ -1,170 +1,172 @@ # The client for interacting with the puppetmaster config server. require 'sync' require 'timeout' require 'puppet/network/http_pool' require 'puppet/util' class Puppet::Configurer require 'puppet/configurer/fact_handler' require 'puppet/configurer/plugin_handler' include Puppet::Configurer::FactHandler include Puppet::Configurer::PluginHandler # For benchmarking include Puppet::Util attr_accessor :catalog attr_reader :compile_time # Provide more helpful strings to the logging that the Agent does def self.to_s "Puppet configuration client" end class << self # Puppetd should only have one instance running, and we need a way # to retrieve it. attr_accessor :instance include Puppet::Util end # How to lock instances of this class. def self.lockfile_path Puppet[:puppetdlockfile] 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 # 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 # Prepare for catalog retrieval. Downloads everything necessary, etc. def prepare dostorage() download_plugins() download_fact_plugins() end # Get the remote catalog, yo. Returns nil if no catalog can be found. def retrieve_catalog name = Puppet[:certname] catalog_class = Puppet::Resource::Catalog # This is a bit complicated. We need the serialized and escaped facts, # and we need to know which format they're encoded in. Thus, we # get a hash with both of these pieces of information. fact_options = facts_for_uploading() # First try it with no cache, then with the cache. result = nil begin duration = thinmark do result = catalog_class.find(name, fact_options.merge(:ignore_cache => true)) end rescue => detail puts detail.backtrace if Puppet[:trace] Puppet.err "Could not retrieve catalog from remote server: %s" % detail end unless result begin duration = thinmark do result = catalog_class.find(name, fact_options.merge(:ignore_terminus => true)) end Puppet.notice "Using cached catalog" rescue => detail puts detail.backtrace if Puppet[:trace] Puppet.err "Could not retrieve catalog from cache: %s" % detail end end return nil unless result convert_catalog(result, duration) end # Convert a plain resource catalog into our full host catalog. def convert_catalog(result, duration) catalog = result.to_ral catalog.retrieval_duration = duration catalog.host_config = true catalog.write_class_file return catalog 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 = {}) prepare() - unless catalog = retrieve_catalog + if catalog = options[:catalog] + options.delete(:catalog) + elsif ! catalog = retrieve_catalog Puppet.err "Could not retrieve catalog; skipping run" return end begin benchmark(:notice, "Finished catalog run") do catalog.apply(options) end rescue => detail puts detail.backtrace if Puppet[:trace] Puppet.err "Failed to apply catalog: %s" % detail 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 private 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 end diff --git a/spec/integration/application/puppet.rb b/spec/integration/application/puppet.rb new file mode 100755 index 000000000..0047dd5a3 --- /dev/null +++ b/spec/integration/application/puppet.rb @@ -0,0 +1,30 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet_spec/files' + +require 'puppet/application/puppet' + +describe "Puppet" do + include PuppetSpec::Files + + it "should be able to apply catalogs provided in a file in json" do + file_to_create = tmpfile("json_catalog") + catalog = Puppet::Resource::Catalog.new + resource = Puppet::Resource.new(:file, file_to_create, :content => "my stuff") + catalog.add_resource resource + + manifest = tmpfile("manifest") + + File.open(manifest, "w") { |f| f.print catalog.to_json } + + puppet = Puppet::Application[:puppet] + puppet.options[:catalog] = manifest + + puppet.apply + + File.should be_exist(file_to_create) + File.read(file_to_create).should == "my stuff" + end +end diff --git a/spec/unit/application/puppet.rb b/spec/unit/application/puppet.rb index 9256b00dc..ca1203405 100644 --- a/spec/unit/application/puppet.rb +++ b/spec/unit/application/puppet.rb @@ -1,324 +1,402 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/application/puppet' describe "Puppet" do before :each do @puppet = Puppet::Application[:puppet] Puppet::Util::Log.stubs(:newdestination) Puppet::Util::Log.stubs(:level=) end [:debug,:loadclasses,:verbose,:use_nodes,:detailed_exitcodes].each do |option| it "should declare handle_#{option} method" do @puppet.should respond_to("handle_#{option}".to_sym) end it "should store argument value when calling handle_#{option}" do @puppet.options.expects(:[]=).with(option, 'arg') @puppet.send("handle_#{option}".to_sym, 'arg') end end it "should set the code to the provided code when :execute is used" do @puppet.options.expects(:[]=).with(:code, 'arg') @puppet.send("handle_execute".to_sym, 'arg') end it "should ask Puppet::Application to parse Puppet configuration file" do @puppet.should_parse_config?.should be_true end describe "when applying options" do it "should set the log destination with --logdest" do Puppet::Log.expects(:newdestination).with("console") @puppet.handle_logdest("console") end it "should put the logset options to true" do @puppet.options.expects(:[]=).with(:logset,true) @puppet.handle_logdest("console") end end describe "during setup" do before :each do Puppet::Log.stubs(:newdestination) Puppet.stubs(:trap) Puppet::Log.stubs(:level=) Puppet.stubs(:parse_config) Puppet::Network::Client.dipper.stubs(:new) STDIN.stubs(:read) @puppet.options.stubs(:[]).with(any_parameters) end it "should set show_diff on --noop" do Puppet.stubs(:[]=) Puppet.stubs(:[]).with(:config) Puppet.stubs(:[]).with(:noop).returns(true) Puppet.expects(:[]=).with(:show_diff, true) @puppet.run_setup end it "should set console as the log destination if logdest option wasn't provided" do Puppet::Log.expects(:newdestination).with(:console) @puppet.run_setup end it "should set INT trap" do @puppet.expects(:trap).with(:INT) @puppet.run_setup end it "should set log level to debug if --debug was passed" do @puppet.options.stubs(:[]).with(:debug).returns(true) Puppet::Log.expects(:level=).with(:debug) @puppet.run_setup end it "should set log level to info if --verbose was passed" do @puppet.options.stubs(:[]).with(:verbose).returns(true) Puppet::Log.expects(:level=).with(:info) @puppet.run_setup end it "should print puppet config if asked to in Puppet config" do @puppet.stubs(:exit) Puppet.settings.stubs(:print_configs?).returns(true) Puppet.settings.expects(:print_configs) @puppet.run_setup end it "should exit after printing puppet config if asked to in Puppet config" do Puppet.settings.stubs(:print_configs?).returns(true) lambda { @puppet.run_setup }.should raise_error(SystemExit) end - it "should set the code to run from --code" do - @puppet.options.stubs(:[]).with(:code).returns("code to run") - Puppet.expects(:[]=).with(:code,"code to run") - - @puppet.run_setup - end - - it "should set the code to run from STDIN if no arguments" do - ARGV.stubs(:length).returns(0) - STDIN.stubs(:read).returns("code to run") - - Puppet.expects(:[]=).with(:code,"code to run") - - @puppet.run_setup - end - - it "should set the manifest if some files are passed on command line" do - ARGV.stubs(:length).returns(1) - ARGV.stubs(:shift).returns("site.pp") - - Puppet.expects(:[]=).with(:manifest,"site.pp") - - @puppet.run_setup - end - end describe "when executing" do it "should dispatch to parseonly if parseonly is set" do + @puppet.stubs(:options).returns({}) Puppet.stubs(:[]).with(:parseonly).returns(true) @puppet.get_command.should == :parseonly end + it "should dispatch to 'apply' if it was called with 'apply'" do + @puppet.options[:catalog] = "foo" + + @puppet.get_command.should == :apply + end + it "should dispatch to main if parseonly is not set" do + @puppet.stubs(:options).returns({}) Puppet.stubs(:[]).with(:parseonly).returns(false) @puppet.get_command.should == :main end describe "the parseonly command" do before :each do Puppet.stubs(:[]).with(:environment) Puppet.stubs(:[]).with(:manifest).returns("site.pp") @interpreter = stub_everything Puppet.stubs(:err) @puppet.stubs(:exit) Puppet::Parser::Interpreter.stubs(:new).returns(@interpreter) end it "should delegate to the Puppet Parser" do @interpreter.expects(:parser) @puppet.parseonly end it "should exit with exit code 0 if no error" do @puppet.expects(:exit).with(0) @puppet.parseonly end it "should exit with exit code 1 if error" do @interpreter.stubs(:parser).raises(Puppet::ParseError) @puppet.expects(:exit).with(1) @puppet.parseonly end end describe "the main command" do before :each do Puppet.stubs(:[]) Puppet.stubs(:[]).with(:trace).returns(true) @puppet.options.stubs(:[]) @facts = stub_everything 'facts' Puppet::Node::Facts.stubs(:find).returns(@facts) @node = stub_everything 'node' Puppet::Node.stubs(:find).returns(@node) @catalog = stub_everything 'catalog' @catalog.stubs(:to_ral).returns(@catalog) Puppet::Resource::Catalog.stubs(:find).returns(@catalog) + STDIN.stubs(:read) + @transaction = stub_everything 'transaction' @catalog.stubs(:apply).returns(@transaction) @puppet.stubs(:exit) end + it "should set the code to run from --code" do + @puppet.options.stubs(:[]).with(:code).returns("code to run") + Puppet.expects(:[]=).with(:code,"code to run") + + @puppet.main + end + + it "should set the code to run from STDIN if no arguments" do + ARGV.stubs(:length).returns(0) + STDIN.stubs(:read).returns("code to run") + + Puppet.expects(:[]=).with(:code,"code to run") + + @puppet.main + end + + it "should set the manifest if some files are passed on command line" do + ARGV.stubs(:length).returns(1) + ARGV.stubs(:shift).returns("site.pp") + + Puppet.expects(:[]=).with(:manifest,"site.pp") + + @puppet.main + end + it "should collect the node facts" do Puppet::Node::Facts.expects(:find).returns(@facts) @puppet.main end it "should find the node" do Puppet::Node.expects(:find).returns(@node) @puppet.main end it "should raise an error if we can't find the node" do Puppet::Node.expects(:find).returns(nil) lambda { @puppet.main }.should raise_error end it "should merge in our node the loaded facts" do @facts.stubs(:values).returns("values") @node.expects(:merge).with("values") @puppet.main end it "should load custom classes if loadclasses" do @puppet.options.stubs(:[]).with(:loadclasses).returns(true) Puppet.stubs(:[]).with(:classfile).returns("/etc/puppet/classes.txt") FileTest.stubs(:exists?).with("/etc/puppet/classes.txt").returns(true) FileTest.stubs(:readable?).with("/etc/puppet/classes.txt").returns(true) File.stubs(:read).with("/etc/puppet/classes.txt").returns("class") @node.expects(:classes=) @puppet.main end it "should compile the catalog" do Puppet::Resource::Catalog.expects(:find).returns(@catalog) @puppet.main end it "should transform the catalog to ral" do @catalog.expects(:to_ral).returns(@catalog) @puppet.main end it "should finalize the catalog" do @catalog.expects(:finalize) @puppet.main end it "should apply the catalog" do @catalog.expects(:apply) @puppet.main end it "should generate a report if not noop" do Puppet.stubs(:[]).with(:noop).returns(false) @puppet.options.stubs(:[]).with(:detailed_exitcodes).returns(true) metrics = stub 'metrics', :[] => { :total => 10, :failed => 0} report = stub 'report', :metrics => metrics @transaction.stubs(:report).returns(report) @transaction.expects(:generate_report) @puppet.main end describe "with detailed_exitcodes" do before :each do Puppet.stubs(:[]).with(:noop).returns(false) @puppet.options.stubs(:[]).with(:detailed_exitcodes).returns(true) end it "should exit with exit code of 2 if changes" do report = stub 'report', :metrics => { "changes" => {:total => 1}, "resources" => {:failed => 0} } @transaction.stubs(:generate_report).returns(report) @transaction.stubs(:report).returns(report) @puppet.expects(:exit).with(2) @puppet.main end it "should exit with exit code of 4 if failures" do report = stub 'report', :metrics => { "changes" => {:total => 0}, "resources" => {:failed => 1} } @transaction.stubs(:generate_report).returns(report) @transaction.stubs(:report).returns(report) @puppet.expects(:exit).with(4) @puppet.main end it "should exit with exit code of 6 if changes and failures" do report = stub 'report', :metrics => { "changes" => {:total => 1}, "resources" => {:failed => 1} } @transaction.stubs(:generate_report).returns(report) @transaction.stubs(:report).returns(report) @puppet.expects(:exit).with(6) @puppet.main end end end - end + describe "the 'apply' command" do + before do + #Puppet::Resource::Catalog.stubs(:json_create).returns Puppet::Resource::Catalog.new + JSON.stubs(:parse).returns Puppet::Resource::Catalog.new + end + + it "should read the catalog in from disk if a file name is provided" do + @puppet.options[:catalog] = "/my/catalog.json" + + File.expects(:read).with("/my/catalog.json").returns "something" + + @puppet.apply + end + + it "should read the catalog in from stdin if '-' is provided" do + @puppet.options[:catalog] = "-" + + $stdin.expects(:read).returns "something" + + @puppet.apply + end + + it "should deserialize the catalog from json" do + @puppet.options[:catalog] = "/my/catalog.json" + + File.expects(:read).returns "something" + JSON.expects(:parse).with("something").returns Puppet::Resource::Catalog.new + + @puppet.apply + end + + it "should fail helpfully if deserializing fails" do + @puppet.options[:catalog] = "/my/catalog.json" + + File.expects(:read).returns "something" + JSON.expects(:parse).raises ArgumentError + + lambda { @puppet.apply }.should raise_error(Puppet::Error) + end + + it "should convert plain data structures into a catalog if deserialization does not do so" do + @puppet.options[:catalog] = "/my/catalog.json" + + File.expects(:read).returns "something" + JSON.expects(:parse).with("something").returns({:foo => "bar"}) + Puppet::Resource::Catalog.expects(:json_create).with({:foo => "bar"}).returns(Puppet::Resource::Catalog.new) + + @puppet.apply + end + + it "should convert the catalog to a RAL catalog and use a Configurer instance to apply it" do + @puppet.options[:catalog] = "/my/catalog.json" + + File.expects(:read).returns "something" + + catalog = Puppet::Resource::Catalog.new + JSON.expects(:parse).returns catalog + + catalog.expects(:to_ral).returns "mycatalog" + + configurer = stub 'configurer' + Puppet::Configurer.expects(:new).returns configurer + + configurer.expects(:run).with(:catalog => "mycatalog") + + @puppet.apply + end + end + end end diff --git a/spec/unit/configurer.rb b/spec/unit/configurer.rb index 9cf22c80c..85bdb9dac 100755 --- a/spec/unit/configurer.rb +++ b/spec/unit/configurer.rb @@ -1,214 +1,222 @@ #!/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/configurer' describe Puppet::Configurer do it "should include the Plugin Handler module" do Puppet::Configurer.ancestors.should be_include(Puppet::Configurer::PluginHandler) end it "should include the Fact Handler module" do Puppet::Configurer.ancestors.should be_include(Puppet::Configurer::FactHandler) end it "should use the puppetdlockfile as its lockfile path" do Puppet.settings.expects(:value).with(:puppetdlockfile).returns("/my/lock") Puppet::Configurer.lockfile_path.should == "/my/lock" end end describe Puppet::Configurer, "when executing a catalog run" do before do Puppet.settings.stubs(:use).returns(true) @agent = Puppet::Configurer.new @agent.stubs(:facts_for_uploading).returns({}) @agent.stubs(:retrieve_catalog).returns Puppet::Resource::Catalog.new end it "should prepare for the run" do @agent.expects(:prepare) @agent.run end it "should retrieve the catalog" do @agent.expects(:retrieve_catalog) @agent.run end it "should log a failure and do nothing if no catalog can be retrieved" do @agent.expects(:retrieve_catalog).returns nil Puppet.expects(:err) @agent.run end it "should apply the catalog with all options to :run" do catalog = stub 'catalog', :retrieval_duration= => nil @agent.expects(:retrieve_catalog).returns catalog catalog.expects(:apply).with(:one => true) @agent.run :one => true end + it "should accept a catalog and use it instead of retrieving a different one" do + catalog = stub 'catalog', :retrieval_duration= => nil + @agent.expects(:retrieve_catalog).never + + catalog.expects(:apply).with(:one => true) + @agent.run :one => true, :catalog => catalog + end + it "should benchmark how long it takes to apply the catalog" do @agent.expects(:benchmark).with(:notice, "Finished catalog run") catalog = stub 'catalog', :retrieval_duration= => nil @agent.expects(:retrieve_catalog).returns catalog catalog.expects(:apply).never # because we're not yielding @agent.run end end describe Puppet::Configurer, "when retrieving a catalog" do before do Puppet.settings.stubs(:use).returns(true) @agent = Puppet::Configurer.new @agent.stubs(:facts_for_uploading).returns({}) @catalog = Puppet::Resource::Catalog.new @agent.stubs(:convert_catalog).returns @catalog end it "should use the Catalog class to get its catalog" do Puppet::Resource::Catalog.expects(:find).returns @catalog @agent.retrieve_catalog end it "should use its certname to retrieve the catalog" do Facter.stubs(:value).returns "eh" Puppet.expects(:[]).with(:certname).returns "myhost.domain.com" Puppet::Resource::Catalog.expects(:find).with { |name, options| name == "myhost.domain.com" }.returns @catalog @agent.retrieve_catalog end it "should pass the prepared facts and the facts format as arguments when retrieving the catalog" do @agent.expects(:facts_for_uploading).returns(:facts => "myfacts", :facts_format => :foo) Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:facts] == "myfacts" and options[:facts_format] == :foo }.returns @catalog @agent.retrieve_catalog end it "should default to returning a catalog retrieved directly from the server, skipping the cache" do Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog @agent.retrieve_catalog.should == @catalog end it "should log and return the cached catalog when no catalog can be retrieved from the server" do Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog Puppet.expects(:notice) @agent.retrieve_catalog.should == @catalog end it "should not look in the cache for a catalog if one is returned from the server" do Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_terminus] == true }.never @agent.retrieve_catalog.should == @catalog end it "should return the cached catalog when retrieving the remote catalog throws an exception" do Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.raises "eh" Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog @agent.retrieve_catalog.should == @catalog end it "should return nil if no cached catalog is available and no catalog can be retrieved from the server" do Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns nil @agent.retrieve_catalog.should be_nil end it "should convert the catalog before returning" do Puppet::Resource::Catalog.stubs(:find).returns @catalog @agent.expects(:convert_catalog).with { |cat, dur| cat == @catalog }.returns "converted catalog" @agent.retrieve_catalog.should == "converted catalog" end it "should return nil if there is an error while retrieving the catalog" do Puppet::Resource::Catalog.expects(:find).raises "eh" @agent.retrieve_catalog.should be_nil end end describe Puppet::Configurer, "when converting the catalog" do before do Puppet.settings.stubs(:use).returns(true) @agent = Puppet::Configurer.new @catalog = Puppet::Resource::Catalog.new @oldcatalog = stub 'old_catalog', :to_ral => @catalog end it "should convert the catalog to a RAL-formed catalog" do @oldcatalog.expects(:to_ral).returns @catalog @agent.convert_catalog(@oldcatalog, 10).should equal(@catalog) end it "should record the passed retrieval time with the RAL catalog" do @catalog.expects(:retrieval_duration=).with 10 @agent.convert_catalog(@oldcatalog, 10) end it "should write the RAL catalog's class file" do @catalog.expects(:write_class_file) @agent.convert_catalog(@oldcatalog, 10) end it "should mark the RAL catalog as a host catalog" do @catalog.expects(:host_config=).with true @agent.convert_catalog(@oldcatalog, 10) end end describe Puppet::Configurer, "when preparing for a run" do before do Puppet.settings.stubs(:use).returns(true) @agent = Puppet::Configurer.new @agent.stubs(:dostorage) @facts = {"one" => "two", "three" => "four"} end it "should initialize the metadata store" do @agent.class.stubs(:facts).returns(@facts) @agent.expects(:dostorage) @agent.prepare end it "should download fact plugins" do @agent.stubs(:dostorage) @agent.expects(:download_fact_plugins) @agent.prepare end it "should download plugins" do @agent.stubs(:dostorage) @agent.expects(:download_plugins) @agent.prepare end end