diff --git a/lib/puppet/indirector/node/exec.rb b/lib/puppet/indirector/node/exec.rb index d4faf74f4..2535ffac5 100644 --- a/lib/puppet/indirector/node/exec.rb +++ b/lib/puppet/indirector/node/exec.rb @@ -1,69 +1,69 @@ require 'puppet/node' require 'puppet/indirector/exec' class Puppet::Node::Exec < Puppet::Indirector::Exec desc "Call an external program to get node information. See the [External Nodes](http://docs.puppetlabs.com/guides/external_nodes.html) page for more information." include Puppet::Util def command command = Puppet[:external_nodes] raise ArgumentError, "You must set the 'external_nodes' parameter to use the external node terminus" unless command != "none" command.split end # Look for external node definitions. def find(request) output = super or return nil # Translate the output to ruby. result = translate(request.key, output) # Set the requested environment if it wasn't overridden # If we don't do this it gets set to the local default - result[:environment] ||= request.environment.name + result[:environment] ||= request.environment create_node(request.key, result) end private # Proxy the execution, so it's easier to test. def execute(command, arguments) Puppet::Util::Execution.execute(command,arguments) end # Turn our outputted objects into a Puppet::Node instance. def create_node(name, result) node = Puppet::Node.new(name) set = false [:parameters, :classes, :environment].each do |param| if value = result[param] node.send(param.to_s + "=", value) set = true end end node.fact_merge node end # Translate the yaml string into Ruby objects. def translate(name, output) YAML.load(output).inject({}) do |hash, data| case data[0] when String hash[data[0].intern] = data[1] when Symbol hash[data[0]] = data[1] else raise Puppet::Error, "key is a #{data[0].class}, not a string or symbol" end hash end rescue => detail raise Puppet::Error, "Could not load external node results for #{name}: #{detail}", detail.backtrace end end diff --git a/spec/integration/application/apply_spec.rb b/spec/integration/application/apply_spec.rb index e48808120..1aeb44f3c 100755 --- a/spec/integration/application/apply_spec.rb +++ b/spec/integration/application/apply_spec.rb @@ -1,109 +1,147 @@ #! /usr/bin/env ruby require 'spec_helper' require 'puppet_spec/files' require 'puppet/application/apply' describe "apply" do include PuppetSpec::Files before :each do Puppet[:reports] = "none" end describe "when applying provided catalogs" do it "can apply catalogs provided in a file in pson" do file_to_create = tmpfile("pson_catalog") catalog = Puppet::Resource::Catalog.new('mine', Puppet.lookup(:environments).get(Puppet[:environment])) resource = Puppet::Resource.new(:file, file_to_create, :parameters => {:content => "my stuff"}) catalog.add_resource resource manifest = tmpfile("manifest") File.open(manifest, "w") { |f| f.print catalog.to_pson } puppet = Puppet::Application[:apply] puppet.options[:catalog] = manifest puppet.apply expect(Puppet::FileSystem.exist?(file_to_create)).to be_true expect(File.read(file_to_create)).to eq("my stuff") end end it "applies a given file even when a directory environment is specified" do manifest = tmpfile("manifest.pp") File.open(manifest, "w") do |f| f.puts <<-EOF notice('it was applied') EOF end special = Puppet::Node::Environment.create(:special, []) Puppet.override(:current_environment => special) do Puppet[:environment] = 'special' puppet = Puppet::Application[:apply] puppet.stubs(:command_line).returns(stub('command_line', :args => [manifest])) expect { puppet.run_command }.to exit_with(0) end expect(@logs.map(&:to_s)).to include('it was applied') end + it "applies a given file even when an ENC is configured", :if => !Puppet.features.microsoft_windows? do + manifest = tmpfile("manifest.pp") + File.open(manifest, "w") do |f| + f.puts <<-EOF + notice('specific manifest applied') + EOF + end + + site_manifest = tmpfile("site_manifest.pp") + File.open(site_manifest, "w") do |f| + f.puts <<-EOF + notice('the site manifest was applied instead') + EOF + end + + enc = tmpfile("enc_script") + File.open(enc, "w") do |f| + f.puts <<-EOF + #!/bin/sh + echo 'classes: []' + EOF + end + File.chmod(0755, enc) + + special = Puppet::Node::Environment.create(:special, []) + Puppet.override(:current_environment => special) do + Puppet[:environment] = 'special' + Puppet[:node_terminus] = 'exec' + Puppet[:external_nodes] = enc + Puppet[:manifest] = site_manifest + puppet = Puppet::Application[:apply] + puppet.stubs(:command_line).returns(stub('command_line', :args => [manifest])) + expect { puppet.run_command }.to exit_with(0) + end + + expect(@logs.map(&:to_s)).to include('specific manifest applied') + end + context "with a module" do let(:modulepath) { tmpdir('modulepath') } let(:execute) { 'include amod' } let(:args) { ['-e', execute, '--modulepath', modulepath] } before(:each) do Puppet::FileSystem.mkpath("#{modulepath}/amod/manifests") File.open("#{modulepath}/amod/manifests/init.pp", "w") do |f| f.puts <<-EOF class amod{ notice('amod class included') } EOF end environmentdir = Dir.mktmpdir('environments') Puppet[:environmentpath] = environmentdir create_default_directory_environment end def create_default_directory_environment Puppet::FileSystem.mkpath("#{Puppet[:environmentpath]}/#{Puppet[:environment]}") end def init_cli_args_and_apply_app(args, execute) Puppet.initialize_settings(args) puppet = Puppet::Application.find(:apply).new(stub('command_line', :subcommand_name => :apply, :args => args)) puppet.options[:code] = execute return puppet end it "looks in --modulepath even when the default directory environment exists" do apply = init_cli_args_and_apply_app(args, execute) expect do expect { apply.run }.to exit_with(0) end.to have_printed('amod class included') end it "looks in --modulepath even when given a specific directory --environment" do args << '--environment' << 'production' apply = init_cli_args_and_apply_app(args, execute) expect do expect { apply.run }.to exit_with(0) end.to have_printed('amod class included') end it "looks in --modulepath when given multiple paths in --modulepath" do args = ['-e', execute, '--modulepath', [tmpdir('notmodulepath'), modulepath].join(File::PATH_SEPARATOR)] apply = init_cli_args_and_apply_app(args, execute) expect do expect { apply.run }.to exit_with(0) end.to have_printed('amod class included') end end end