diff options
Diffstat (limited to 'lib/puppet/network/handler')
| -rw-r--r-- | lib/puppet/network/handler/node.rb | 178 |
1 files changed, 136 insertions, 42 deletions
diff --git a/lib/puppet/network/handler/node.rb b/lib/puppet/network/handler/node.rb index 0c532144a..c9548f10b 100644 --- a/lib/puppet/network/handler/node.rb +++ b/lib/puppet/network/handler/node.rb @@ -9,12 +9,10 @@ require 'puppet/util/instance_loader' class Puppet::Network::Handler::Node < Puppet::Network::Handler # A simplistic class for managing the node information itself. class SimpleNode - attr_accessor :name, :classes, :parameters, :environment + attr_accessor :name, :classes, :parameters, :environment, :source - def initialize(options) - unless @name = options[:name] - raise ArgumentError, "Nodes require names" unless self.name - end + def initialize(name, options = {}) + @name = name if classes = options[:classes] if classes.is_a?(String) @@ -27,19 +25,35 @@ class Puppet::Network::Handler::Node < Puppet::Network::Handler end @parameters = options[:parameters] || {} + + unless @environment = options[:environment] + if env = Puppet[:environment] and env != "" + @environment = env + end + end + end + + # Merge the node facts with parameters from the node source. + # This is only called if the node source has 'fact_merge' set to true. + def fact_merge(facts) + facts.each do |name, value| + @parameters[name] = value unless @parameters.include?(name) + end end end + desc "Retrieve information about nodes." extend Puppet::Util::ClassGen extend Puppet::Util::InstanceLoader + # A simple base module we can use for modifying how our node sources work. module SourceBase include Puppet::Util::Docs end @interface = XMLRPC::Service::Interface.new("nodes") { |iface| - iface.add_method("string node(key)") + iface.add_method("string details(key)") iface.add_method("string parameters(key)") iface.add_method("string environment(key)") iface.add_method("string classes(key)") @@ -48,11 +62,18 @@ class Puppet::Network::Handler::Node < Puppet::Network::Handler # Set up autoloading and retrieving of reports. autoload :node_source, 'puppet/node_source' + attr_reader :source + # Add a new node source. def self.newnode_source(name, options = {}, &block) name = symbolize(name) - genmodule(name, :extend => SourceBase, :hash => instance_hash(:node_source), :block => block) + fact_merge = options[:fact_merge] + mod = genmodule(name, :extend => SourceBase, :hash => instance_hash(:node_source), :block => block) + mod.send(:define_method, :fact_merge?) do + fact_merge + end + mod end # Collect the docs for all of our node sources. @@ -79,68 +100,141 @@ class Puppet::Network::Handler::Node < Puppet::Network::Handler # Remove a defined node source; basically only used for testing. def self.rm_node_source(name) - instance_hash(:node_source).delete(name) + rmclass(name, :hash => instance_hash(:node_source)) end # Return a given node's classes. def classes(key) - raise "look up classes" - end - - # Return a given node's environment. - def environment(key) - raise "look up environment" - if node = node(key) - node.environment + if node = details(key) + node.classes else nil end end - # Return an entire node configuration. - def node(key) - # Try to find our node... - nodes = nodes.collect { |n| n.to_s.downcase } - - method = "nodesearch_%s" % @nodesource - # Do an inverse sort on the length, so the longest match always - # wins - nodes.sort { |a,b| b.length <=> a.length }.each do |node| - node = node.to_s if node.is_a?(Symbol) - if obj = self.send(method, node) - if obj.is_a?(AST::Node) - nsource = obj.file - else - nsource = obj.source - end - Puppet.info "Found %s in %s" % [node, nsource] - return obj + # Return an entire node configuration. This uses the 'nodesearch' method + # defined in the node_source to look for the node. + def details(key) + facts = node_facts(key) + node = nil + names = node_names(key, facts) + names.each do |name| + name = name.to_s if name.is_a?(Symbol) + if node = nodesearch(name) + Puppet.info "Found %s in %s" % [name, @source] + break end end # If they made it this far, we haven't found anything, so look for a # default node. - unless nodes.include?("default") - if defobj = self.nodesearch("default") - Puppet.notice "Using default node for %s" % [nodes[0]] - return defobj + unless node or names.include?("default") + if node = nodesearch("default") + Puppet.notice "Using default node for %s" % key + end + end + + if node + node.source = @source + + # Merge the facts into the parameters. + if fact_merge? + node.fact_merge(facts) end + return node + else + return nil + end + end + + # Return a given node's environment. + def environment(key) + if node = details(key) + node.environment + else + nil end + end + + # Create our node lookup tool. + def initialize(hash = {}) + @source = hash[:Source] || Puppet[:node_source] + + unless mod = self.class.node_source(@source) + raise ArgumentError, "Unknown node source '%s'" % @source + end + + extend(mod) - return nil + super end + # Short-hand for creating a new node, so the node sources don't need to + # specify the constant. + def newnode(options) + SimpleNode.new(options) + end + + # Try to retrieve a given node's parameters. def parameters(key) - raise "Look up parameters" + if node = details(key) + node.parameters + else + nil + end end private + + # Create/cache a fact handler. + def fact_handler + unless defined?(@fact_handler) + @fact_handler = Puppet::Network::Handler.handler(:facts).new + end + @fact_handler + end + + # Look up the node facts from our fact handler. def node_facts(key) - raise "Look up node facts" + if facts = fact_handler.get(key) + facts + else + {} + end end + # Calculate the list of node names we should use for looking + # up our node. def node_names(key, facts = nil) facts ||= node_facts(key) - raise "Calculate node names" + names = [] + + if hostname = facts["hostname"] + unless hostname == key + names << hostname + end + else + hostname = key + end + + if fqdn = facts["fqdn"] + hostname = fqdn + names << fqdn + end + + # Make sure both the fqdn and the short name of the + # host can be used in the manifest + if hostname =~ /\./ + names << hostname.sub(/\..+/,'') + elsif domain = facts['domain'] + names << hostname + "." + domain + end + + # Sort the names inversely by name length. + names.sort! { |a,b| b.length <=> a.length } + + # And make sure the key is first, since that's the most + # likely usage. + ([key] + names).uniq end end |
