summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/puppet/parser/interpreter.rb50
-rwxr-xr-xtest/language/interpreter.rb62
2 files changed, 111 insertions, 1 deletions
diff --git a/lib/puppet/parser/interpreter.rb b/lib/puppet/parser/interpreter.rb
index a00b10042..0117ac2dd 100644
--- a/lib/puppet/parser/interpreter.rb
+++ b/lib/puppet/parser/interpreter.rb
@@ -15,7 +15,16 @@ class Puppet::Parser::Interpreter
:casesensitive => [false,
"Whether matching in case statements and selectors
should be case-sensitive. Case insensitivity is
- handled by downcasing all values before comparison."])
+ handled by downcasing all values before comparison."],
+ :external_nodes => ["none",
+ "An external command that can produce node information. The
+ first line of output must be either the parent node or blank,
+ and if there is a second line of output it should be a list of
+ whitespace-separated classes to include on that node. This command
+ makes it straightforward to store your node mapping information
+ in other data sources like databases.
+
+ For unknown nodes, the commands should exit with an exit code of 1."])
Puppet.setdefaults("ldap",
:ldapnodes => [false,
@@ -642,6 +651,45 @@ class Puppet::Parser::Interpreter
def nodesearch_code(name)
@nodetable[name]
end
+
+ # Look for external node definitions.
+ def nodesearch_external(name)
+ return nil unless Puppet[:external_nodes] != "none"
+
+ begin
+ output = Puppet::Util.execute([Puppet[:external_nodes], name])
+ rescue Puppet::ExecutionFailure => detail
+ if $?.exitstatus == 1
+ return nil
+ else
+ Puppet.err "Could not retrieve external node information for %s: %s" % [name, detail]
+ end
+ return nil
+ end
+
+ if output =~ /\A\s+\Z/ # all whitespace
+ puts "empty response for %s" % name
+ return nil
+ end
+
+ lines = output.split("\n")
+
+ args = {}
+ parent = lines[0].gsub(/\s+/, '')
+ args[:parentnode] = parent unless parent == ""
+
+ if lines[1]
+ classes = lines[1].sub(/^\s+/,'').sub(/\s+$/,'').split(/\s+/)
+ args[:classes] = classes unless classes.empty?
+ end
+
+ if args.empty?
+ Puppet.warning "Somehow got a node with no information"
+ return nil
+ else
+ return gennode(name, args)
+ end
+ end
# Look for our node in ldap.
def nodesearch_ldap(node)
diff --git a/test/language/interpreter.rb b/test/language/interpreter.rb
index 93d9b3720..c1c16b441 100755
--- a/test/language/interpreter.rb
+++ b/test/language/interpreter.rb
@@ -931,6 +931,68 @@ class TestInterpreter < Test::Unit::TestCase
assert_equal("root", pvalue[:value])
end
end
+
+ def test_nodesearch_external
+ interp = mkinterp
+
+ # Make a fake gennode method
+ class << interp
+ def gennode(name, args)
+ args[:name] = name
+ return args
+ end
+ end
+
+ # First, make sure our nodesearch command works as we expect
+ # Make a nodemapper
+ mapper = tempfile()
+ ruby = %x{which ruby}.chomp
+ File.open(mapper, "w") { |f|
+ f.puts "#!#{ruby}
+ name = ARGV[0]
+ if name =~ /a/
+ puts ARGV[0].gsub('a', 'b')
+ else
+ puts ''
+ end
+ if name =~ /p/
+ puts [1,2,3].collect { |n| ARGV[0] + n.to_s }.join(' ')
+ else
+ puts ''
+ end
+ "
+ }
+ File.chmod(0755, mapper)
+
+ # Make sure it gives the right response
+ assert_equal("bpple\napple1 apple2 apple3\n",
+ %x{#{mapper} apple})
+
+ # First make sure we get nil back by default
+ assert_nothing_raised {
+ assert_nil(interp.nodesearch_external("apple"),
+ "Interp#nodesearch_external defaulted to a non-nil response")
+ }
+ assert_nothing_raised { Puppet[:external_nodes] = mapper }
+
+ node = nil
+ assert_nothing_raised { node = interp.nodesearch_external("apple") }
+
+ assert_equal({:name => "apple", :classes => %w{apple1 apple2 apple3}, :parentnode => "bpple"},
+ node)
+
+ assert_nothing_raised { node = interp.nodesearch_external("plum")} # no a's, thus no parent
+ assert_equal({:name => "plum", :classes => %w{plum1 plum2 plum3}},
+ node)
+
+ assert_nothing_raised { node = interp.nodesearch_external("guava")} # no p's, thus no classes
+ assert_equal({:name => "guava", :parentnode => "gubvb"},
+ node)
+
+ assert_nothing_raised { node = interp.nodesearch_external("honeydew")} # neither, thus nil
+ assert_nil(node)
+
+ end
end
# $Id$