diff --git a/lib/puppet/configurer/downloader.rb b/lib/puppet/configurer/downloader.rb index 13424d6e1..c8554dcde 100644 --- a/lib/puppet/configurer/downloader.rb +++ b/lib/puppet/configurer/downloader.rb @@ -1,71 +1,71 @@ require 'puppet/configurer' require 'puppet/resource/catalog' class Puppet::Configurer::Downloader attr_reader :name, :path, :source, :ignore # Evaluate our download, returning the list of changed values. def evaluate Puppet.info "Retrieving #{name}" files = [] begin ::Timeout.timeout(Puppet[:configtimeout]) do catalog.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 Puppet.log_exception(detail, "Could not retrieve #{name}: #{detail}") end files end - def initialize(name, path, source, ignore = nil, environment = nil) - @name, @path, @source, @ignore, @environment = name, path, source, ignore, environment + def initialize(name, path, source, ignore = nil, environment = nil, source_permissions = :ignore) + @name, @path, @source, @ignore, @environment, @source_permissions = name, path, source, ignore, environment, source_permissions end def catalog catalog = Puppet::Resource::Catalog.new("PluginSync", @environment) catalog.host_config = false catalog.add_resource(file) catalog end def file args = default_arguments.merge(:path => path, :source => source) args[:ignore] = ignore.split if ignore Puppet::Type.type(:file).new(args) end private require 'sys/admin' if Puppet.features.microsoft_windows? def default_arguments defargs = { :path => path, :recurse => true, :source => source, - :source_permissions => :ignore, + :source_permissions => @source_permissions, :tag => name, :purge => true, :force => true, :backup => false, :noop => false } if !Puppet.features.microsoft_windows? defargs.merge!( { :owner => Process.uid, :group => Process.gid } ) end return defargs end end diff --git a/lib/puppet/configurer/plugin_handler.rb b/lib/puppet/configurer/plugin_handler.rb index 2e14fdb3c..b8aeb95a5 100644 --- a/lib/puppet/configurer/plugin_handler.rb +++ b/lib/puppet/configurer/plugin_handler.rb @@ -1,28 +1,29 @@ # Break out the code related to plugins. This module is # just included into the agent, but having it here makes it # easier to test. module Puppet::Configurer::PluginHandler # Retrieve facts from the central server. def download_plugins(environment) plugin_downloader = Puppet::Configurer::Downloader.new( "plugin", Puppet[:plugindest], Puppet[:pluginsource], Puppet[:pluginsignore], environment ) if Puppet.features.external_facts? plugin_fact_downloader = Puppet::Configurer::Downloader.new( "pluginfacts", Puppet[:pluginfactdest], Puppet[:pluginfactsource], Puppet[:pluginsignore], - environment + environment, + :use ) plugin_fact_downloader.evaluate end plugin_downloader.evaluate Puppet::Util::Autoload.reload_changed end end diff --git a/spec/unit/configurer/downloader_spec.rb b/spec/unit/configurer/downloader_spec.rb index 9e1d3a29b..6003fd10f 100755 --- a/spec/unit/configurer/downloader_spec.rb +++ b/spec/unit/configurer/downloader_spec.rb @@ -1,211 +1,243 @@ #! /usr/bin/env ruby require 'spec_helper' require 'puppet/configurer/downloader' describe Puppet::Configurer::Downloader do require 'puppet_spec/files' include PuppetSpec::Files + + let(:path) { Puppet[:plugindest] } + let(:source) { 'puppet://puppet/plugins' } + it "should require a name" do lambda { Puppet::Configurer::Downloader.new }.should raise_error(ArgumentError) end it "should require a path and a source at initialization" do lambda { Puppet::Configurer::Downloader.new("name") }.should raise_error(ArgumentError) end it "should set the name, path and source appropriately" do dler = Puppet::Configurer::Downloader.new("facts", "path", "source") dler.name.should == "facts" dler.path.should == "path" dler.source.should == "source" end - describe "when creating the file that does the downloading" do - before do - @dler = Puppet::Configurer::Downloader.new("foo", "path", "source") - end + def downloader(options = {}) + options[:name] ||= "facts" + options[:path] ||= path + options[:source_permissions] ||= :ignore + Puppet::Configurer::Downloader.new(options[:name], options[:path], source, options[:ignore], options[:environment], options[:source_permissions]) + end + def generate_file_resource(options = {}) + dler = downloader(options) + dler.file + end + + describe "when creating the file that does the downloading" do it "should create a file instance with the right path and source" do - Puppet::Type.type(:file).expects(:new).with { |opts| opts[:path] == "path" and opts[:source] == "source" } - @dler.file + file = generate_file_resource(:path => path, :source => source) + + expect(file[:path]).to eq(path) + expect(file[:source]).to eq([source]) end it "should tag the file with the downloader name" do - Puppet::Type.type(:file).expects(:new).with { |opts| opts[:tag] == "foo" } - @dler.file + name = "mydownloader" + file = generate_file_resource(:name => name) + + expect(file[:tag]).to eq([name]) end it "should always recurse" do - Puppet::Type.type(:file).expects(:new).with { |opts| opts[:recurse] == true } - @dler.file + file = generate_file_resource + + expect(file[:recurse]).to be_true end it "should always purge" do - Puppet::Type.type(:file).expects(:new).with { |opts| opts[:purge] == true } - @dler.file + file = generate_file_resource + + expect(file[:purge]).to be_true end it "should never be in noop" do - Puppet::Type.type(:file).expects(:new).with { |opts| opts[:noop] == false } - @dler.file + file = generate_file_resource + + expect(file[:noop]).to be_false end - it "should set source_permissions to ignore" do - Puppet::Type.type(:file).expects(:new).with { |opts| opts[:source_permissions] == :ignore } - @dler.file + it "should set source_permissions to ignore by default" do + file = generate_file_resource + + expect(file[:source_permissions]).to eq(:ignore) + end + + it "should allow source_permissions to be overridden" do + file = generate_file_resource(:source_permissions => :use) + + expect(file[:source_permissions]).to eq(:use) end describe "on POSIX", :as_platform => :posix do it "should always set the owner to the current UID" do Process.expects(:uid).returns 51 - Puppet::Type.type(:file).expects(:new).with { |opts| opts[:owner] == 51 } - @dler.file + + file = generate_file_resource(:path => '/path') + expect(file[:owner]).to eq(51) end it "should always set the group to the current GID" do Process.expects(:gid).returns 61 - Puppet::Type.type(:file).expects(:new).with { |opts| opts[:group] == 61 } - @dler.file + + file = generate_file_resource(:path => '/path') + expect(file[:group]).to eq(61) end end describe "on Windows", :as_platform => :windows do it "should omit the owner" do - Puppet::Type.type(:file).expects(:new).with { |opts| opts[:owner] == nil } - @dler.file + file = generate_file_resource(:path => 'C:/path') + + expect(file[:owner]).to be_nil end it "should omit the group" do - Puppet::Type.type(:file).expects(:new).with { |opts| opts[:group] == nil } - @dler.file + file = generate_file_resource(:path => 'C:/path') + + expect(file[:group]).to be_nil end end it "should always force the download" do - Puppet::Type.type(:file).expects(:new).with { |opts| opts[:force] == true } - @dler.file + file = generate_file_resource + + expect(file[:force]).to be_true end it "should never back up when downloading" do - Puppet::Type.type(:file).expects(:new).with { |opts| opts[:backup] == false } - @dler.file + file = generate_file_resource + + expect(file[:backup]).to be_false end it "should support providing an 'ignore' parameter" do - Puppet::Type.type(:file).expects(:new).with { |opts| opts[:ignore] == [".svn"] } - @dler = Puppet::Configurer::Downloader.new("foo", "path", "source", ".svn") - @dler.file + file = generate_file_resource(:ignore => '.svn') + + expect(file[:ignore]).to eq(['.svn']) end it "should split the 'ignore' parameter on whitespace" do - Puppet::Type.type(:file).expects(:new).with { |opts| opts[:ignore] == %w{.svn CVS} } - @dler = Puppet::Configurer::Downloader.new("foo", "path", "source", ".svn CVS") - @dler.file + file = generate_file_resource(:ignore => '.svn CVS') + + expect(file[:ignore]).to eq(['.svn', 'CVS']) end end describe "when creating the catalog to do the downloading" do before do @path = make_absolute("/download/path") @dler = Puppet::Configurer::Downloader.new("foo", @path, make_absolute("source")) end it "should create a catalog and add the file to it" do catalog = @dler.catalog catalog.resources.size.should == 1 catalog.resources.first.class.should == Puppet::Type::File catalog.resources.first.name.should == @path end it "should specify that it is not managing a host catalog" do @dler.catalog.host_config.should == false end end describe "when downloading" do before do @dl_name = tmpfile("downloadpath") source_name = tmpfile("source") File.open(source_name, 'w') {|f| f.write('hola mundo') } env = Puppet::Node::Environment.remote('foo') @dler = Puppet::Configurer::Downloader.new("foo", @dl_name, source_name, Puppet[:pluginsignore], env) end it "should not skip downloaded resources when filtering on tags" do Puppet[:tags] = 'maytag' @dler.evaluate Puppet::FileSystem.exist?(@dl_name).should be_true end it "should log that it is downloading" do Puppet.expects(:info) Timeout.stubs(:timeout) @dler.evaluate end it "should set a timeout for the download using the `configtimeout` setting" do Puppet[:configtimeout] = 50 Timeout.expects(:timeout).with(50) @dler.evaluate end it "should apply the catalog within the timeout block" do catalog = mock 'catalog' @dler.expects(:catalog).returns(catalog) Timeout.expects(:timeout).yields catalog.expects(:apply) @dler.evaluate end it "should return all changed file paths" do trans = mock 'transaction' catalog = mock 'catalog' @dler.expects(:catalog).returns(catalog) catalog.expects(:apply).yields(trans) Timeout.expects(:timeout).yields resource = mock 'resource' resource.expects(:[]).with(:path).returns "/changed/file" trans.expects(:changed?).returns([resource]) @dler.evaluate.should == %w{/changed/file} end it "should yield the resources if a block is given" do trans = mock 'transaction' catalog = mock 'catalog' @dler.expects(:catalog).returns(catalog) catalog.expects(:apply).yields(trans) Timeout.expects(:timeout).yields resource = mock 'resource' resource.expects(:[]).with(:path).returns "/changed/file" trans.expects(:changed?).returns([resource]) yielded = nil @dler.evaluate { |r| yielded = r } yielded.should == resource end it "should catch and log exceptions" do Puppet.expects(:err) Timeout.stubs(:timeout).raises(Puppet::Error, "testing") lambda { @dler.evaluate }.should_not raise_error end end end diff --git a/spec/unit/configurer/plugin_handler_spec.rb b/spec/unit/configurer/plugin_handler_spec.rb index 295629481..8093fe708 100755 --- a/spec/unit/configurer/plugin_handler_spec.rb +++ b/spec/unit/configurer/plugin_handler_spec.rb @@ -1,39 +1,39 @@ #! /usr/bin/env ruby require 'spec_helper' require 'puppet/configurer' require 'puppet/configurer/plugin_handler' class PluginHandlerTester include Puppet::Configurer::PluginHandler attr_accessor :environment end describe Puppet::Configurer::PluginHandler do before do @pluginhandler = PluginHandlerTester.new # PluginHandler#load_plugin has an extra-strong rescue clause # this mock is to make sure that we don't silently ignore errors Puppet.expects(:err).never end it "should use an Agent Downloader, with the name, source, destination, ignore, and environment set correctly, to download plugins when downloading is enabled" do environment = Puppet::Node::Environment.create(:myenv, []) Puppet.features.stubs(:external_facts?).returns(:true) plugindest = File.expand_path("/tmp/pdest") Puppet[:pluginsource] = "psource" Puppet[:plugindest] = plugindest Puppet[:pluginsignore] = "pignore" Puppet[:pluginfactsource] = "psource" Puppet[:pluginfactdest] = plugindest downloader = mock 'downloader' - Puppet::Configurer::Downloader.expects(:new).with("pluginfacts", plugindest, "psource", "pignore", environment).returns downloader + Puppet::Configurer::Downloader.expects(:new).with("pluginfacts", plugindest, "psource", "pignore", environment, :use).returns downloader Puppet::Configurer::Downloader.expects(:new).with("plugin", plugindest, "psource", "pignore", environment).returns downloader downloader.stubs(:evaluate).returns([]) downloader.expects(:evaluate).twice @pluginhandler.download_plugins(environment) end end