From aab419b8c1ad84e51c6f58839290bbe5d1e7b28b Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 14 Aug 2007 00:09:49 -0500 Subject: An intermediate commit in the work towards adding multi-environment support. This has required splitting the interpreter up considerably, which is much cleaner but is a large project. There is now a 'nodes' handler, but it is currently non-functional, although all the support structure is there. It just needs to have the individual methods fleshed out, and it needs to be connected to the 'facts' handler. --- lib/puppet/node_source/external.rb | 51 ++++++++++++++++ lib/puppet/node_source/ldap.rb | 118 +++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 lib/puppet/node_source/external.rb create mode 100644 lib/puppet/node_source/ldap.rb (limited to 'lib/puppet/node_source') diff --git a/lib/puppet/node_source/external.rb b/lib/puppet/node_source/external.rb new file mode 100644 index 000000000..4af68d8ae --- /dev/null +++ b/lib/puppet/node_source/external.rb @@ -0,0 +1,51 @@ +Puppet::Network::Handler::Node.newnode_source(:external) do + desc "Call an external program to get node information." + + include Puppet::Util + # Look for external node definitions. + def nodesearch(name) + return nil unless Puppet[:external_nodes] != "none" + + # This is a very cheap way to do this, since it will break on + # commands that have spaces in the arguments. But it's good + # enough for most cases. + external_node_command = Puppet[:external_nodes].split + external_node_command << name + begin + output = Puppet::Util.execute(external_node_command) + 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 + Puppet.debug "Empty response for %s from external node source" % name + return nil + end + + begin + result = YAML.load(output).inject({}) { |hash, data| hash[symbolize(data[0])] = data[1]; hash } + rescue => detail + raise Puppet::Error, "Could not load external node results for %s: %s" % [name, detail] + end + + node = Puppet::Network::Handler::Node::SimpleNode.new(:name => name) + set = false + [:parameters, :classes].each do |param| + if value = result[param] + node.send(param.to_s + "=", value) + set = true + end + end + + if set + return node + else + return nil + end + end +end diff --git a/lib/puppet/node_source/ldap.rb b/lib/puppet/node_source/ldap.rb new file mode 100644 index 000000000..6825f2b68 --- /dev/null +++ b/lib/puppet/node_source/ldap.rb @@ -0,0 +1,118 @@ +Puppet::Network::Handler::Node.newnode_source(:ldap) do + desc "Search in LDAP for node configuration information." + + # Find the ldap node, return the class list and parent node specially, + # and everything else in a parameter hash. + def ldapsearch(node) + unless defined? @ldap and @ldap + setup_ldap() + unless @ldap + Puppet.info "Skipping ldap source; no ldap connection" + return nil + end + end + + filter = Puppet[:ldapstring] + classattrs = Puppet[:ldapclassattrs].split("\s*,\s*") + if Puppet[:ldapattrs] == "all" + # A nil value here causes all attributes to be returned. + search_attrs = nil + else + search_attrs = classattrs + Puppet[:ldapattrs].split("\s*,\s*") + end + pattr = nil + if pattr = Puppet[:ldapparentattr] + if pattr == "" + pattr = nil + else + search_attrs << pattr unless search_attrs.nil? + end + end + + if filter =~ /%s/ + filter = filter.gsub(/%s/, node) + end + + parent = nil + classes = [] + parameters = nil + + found = false + count = 0 + + begin + # We're always doing a sub here; oh well. + @ldap.search(Puppet[:ldapbase], 2, filter, search_attrs) do |entry| + found = true + if pattr + if values = entry.vals(pattr) + if values.length > 1 + raise Puppet::Error, + "Node %s has more than one parent: %s" % + [node, values.inspect] + end + unless values.empty? + parent = values.shift + end + end + end + + classattrs.each { |attr| + if values = entry.vals(attr) + values.each do |v| classes << v end + end + } + + parameters = entry.to_hash.inject({}) do |hash, ary| + if ary[1].length == 1 + hash[ary[0]] = ary[1].shift + else + hash[ary[0]] = ary[1] + end + hash + end + end + rescue => detail + if count == 0 + # Try reconnecting to ldap + @ldap = nil + setup_ldap() + retry + else + raise Puppet::Error, "LDAP Search failed: %s" % detail + end + end + + classes.flatten! + + if classes.empty? + classes = nil + end + + if parent or classes or parameters + return parent, classes, parameters + else + return nil + end + end + + # Look for our node in ldap. + def nodesearch(node) + unless ary = ldapsearch(node) + return nil + end + parent, classes, parameters = ary + + while parent + parent, tmpclasses, tmpparams = ldapsearch(parent) + classes += tmpclasses if tmpclasses + tmpparams.each do |param, value| + # Specifically test for whether it's set, so false values are handled + # correctly. + parameters[param] = value unless parameters.include?(param) + end + end + + return Puppet::Network::Handler::Node::SimpleNode.new(:name => node, :classes => classes, :source => "ldap", :parameters => parameters) + end +end -- cgit From 90a9d09cd08ec072530e2f000e9f7b65f1c41095 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 14 Aug 2007 18:25:08 -0500 Subject: Finalizing the node handler. It now correctly uses the different node sources and knows how to retrieve data from those sources. Now I just need to fix the language stuff to use this handler instead of the existing node stuff. --- lib/puppet/node_source/external.rb | 4 ++-- lib/puppet/node_source/ldap.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'lib/puppet/node_source') diff --git a/lib/puppet/node_source/external.rb b/lib/puppet/node_source/external.rb index 4af68d8ae..54111d924 100644 --- a/lib/puppet/node_source/external.rb +++ b/lib/puppet/node_source/external.rb @@ -1,4 +1,4 @@ -Puppet::Network::Handler::Node.newnode_source(:external) do +Puppet::Network::Handler::Node.newnode_source(:external, :fact_merge => true) do desc "Call an external program to get node information." include Puppet::Util @@ -33,7 +33,7 @@ Puppet::Network::Handler::Node.newnode_source(:external) do raise Puppet::Error, "Could not load external node results for %s: %s" % [name, detail] end - node = Puppet::Network::Handler::Node::SimpleNode.new(:name => name) + node = newnode(name) set = false [:parameters, :classes].each do |param| if value = result[param] diff --git a/lib/puppet/node_source/ldap.rb b/lib/puppet/node_source/ldap.rb index 6825f2b68..9332fcb40 100644 --- a/lib/puppet/node_source/ldap.rb +++ b/lib/puppet/node_source/ldap.rb @@ -1,4 +1,4 @@ -Puppet::Network::Handler::Node.newnode_source(:ldap) do +Puppet::Network::Handler::Node.newnode_source(:ldap, :fact_merge => true) do desc "Search in LDAP for node configuration information." # Find the ldap node, return the class list and parent node specially, @@ -113,6 +113,6 @@ Puppet::Network::Handler::Node.newnode_source(:ldap) do end end - return Puppet::Network::Handler::Node::SimpleNode.new(:name => node, :classes => classes, :source => "ldap", :parameters => parameters) + return newnode(node, :classes => classes, :source => "ldap", :parameters => parameters) end end -- cgit From 65559af75e3da6522f4c3e952a73d80e0040609c Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Wed, 15 Aug 2007 13:55:55 -0500 Subject: Adding a "none" node source, which will be the default node source and will just return an empty node. --- lib/puppet/node_source/none.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 lib/puppet/node_source/none.rb (limited to 'lib/puppet/node_source') diff --git a/lib/puppet/node_source/none.rb b/lib/puppet/node_source/none.rb new file mode 100644 index 000000000..ce188add5 --- /dev/null +++ b/lib/puppet/node_source/none.rb @@ -0,0 +1,10 @@ +Puppet::Network::Handler::Node.newnode_source(:none, :fact_merge => true) do + desc "Always return an empty node object. This is the node source you should + use when you don't have some other, functional source you want to use, + as the compiler will not work without this node information." + + # Just return an empty node. + def nodesearch(name) + newnode(name) + end +end -- cgit From a846ea900f9fa7a2baaa4fbd0742f080e7fd7a04 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Thu, 16 Aug 2007 21:21:40 -0500 Subject: The new parser configuration object works now, but the rest of the compiling process is hosed (although the parser itself should still be fine). The configuration object is unifying a lot of work that was scattered around either the interpreter or the scopes, and it simplifies the whole system. However, its new simplicity has made the complexity of the rest of the system that much more apparent, and I am resolved to fixing the system rather than hacking it sufficiently to just make it work. --- lib/puppet/node_source/ldap.rb | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) (limited to 'lib/puppet/node_source') diff --git a/lib/puppet/node_source/ldap.rb b/lib/puppet/node_source/ldap.rb index 9332fcb40..7b60a3c62 100644 --- a/lib/puppet/node_source/ldap.rb +++ b/lib/puppet/node_source/ldap.rb @@ -4,14 +4,6 @@ Puppet::Network::Handler::Node.newnode_source(:ldap, :fact_merge => true) do # Find the ldap node, return the class list and parent node specially, # and everything else in a parameter hash. def ldapsearch(node) - unless defined? @ldap and @ldap - setup_ldap() - unless @ldap - Puppet.info "Skipping ldap source; no ldap connection" - return nil - end - end - filter = Puppet[:ldapstring] classattrs = Puppet[:ldapclassattrs].split("\s*,\s*") if Puppet[:ldapattrs] == "all" @@ -42,7 +34,7 @@ Puppet::Network::Handler::Node.newnode_source(:ldap, :fact_merge => true) do begin # We're always doing a sub here; oh well. - @ldap.search(Puppet[:ldapbase], 2, filter, search_attrs) do |entry| + ldap.search(Puppet[:ldapbase], 2, filter, search_attrs) do |entry| found = true if pattr if values = entry.vals(pattr) @@ -76,7 +68,6 @@ Puppet::Network::Handler::Node.newnode_source(:ldap, :fact_merge => true) do if count == 0 # Try reconnecting to ldap @ldap = nil - setup_ldap() retry else raise Puppet::Error, "LDAP Search failed: %s" % detail @@ -115,4 +106,33 @@ Puppet::Network::Handler::Node.newnode_source(:ldap, :fact_merge => true) do return newnode(node, :classes => classes, :source => "ldap", :parameters => parameters) end + + private + + # Create an ldap connection. + def ldap + unless defined? @ldap and @ldap + unless Puppet.features.ldap? + raise Puppet::Error, "Could not set up LDAP Connection: Missing ruby/ldap libraries" + end + begin + if Puppet[:ldapssl] + @ldap = LDAP::SSLConn.new(Puppet[:ldapserver], Puppet[:ldapport]) + elsif Puppet[:ldaptls] + @ldap = LDAP::SSLConn.new( + Puppet[:ldapserver], Puppet[:ldapport], true + ) + else + @ldap = LDAP::Conn.new(Puppet[:ldapserver], Puppet[:ldapport]) + end + @ldap.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3) + @ldap.set_option(LDAP::LDAP_OPT_REFERRALS, LDAP::LDAP_OPT_ON) + @ldap.simple_bind(Puppet[:ldapuser], Puppet[:ldappassword]) + rescue => detail + raise Puppet::Error, "Could not connect to LDAP: %s" % detail + end + end + + return @ldap + end end -- cgit