diff options
Diffstat (limited to 'lib/puppet')
-rw-r--r-- | lib/puppet/configuration.rb | 10 | ||||
-rw-r--r-- | lib/puppet/network/handler/node.rb | 178 | ||||
-rw-r--r-- | lib/puppet/node_source/external.rb | 4 | ||||
-rw-r--r-- | lib/puppet/node_source/ldap.rb | 4 | ||||
-rw-r--r-- | lib/puppet/parser/node.rb | 133 |
5 files changed, 148 insertions, 181 deletions
diff --git a/lib/puppet/configuration.rb b/lib/puppet/configuration.rb index 65e0d9fa8..574038338 100644 --- a/lib/puppet/configuration.rb +++ b/lib/puppet/configuration.rb @@ -122,7 +122,11 @@ module Puppet "The configuration file that defines the rights to the different namespaces and methods. This can be used as a coarse-grained authorization system for both ``puppetd`` and ``puppetmasterd``." - ] + ], + :environment => ["", "The environment Puppet is running in. For clients (e.g., ``puppetd``) this + determines the environment itself, which is used to find modules and much more. For + servers (i.e., ``puppetmasterd``) this provides the default environment for nodes we + know nothing about."] ) hostname = Facter["hostname"].value @@ -544,7 +548,9 @@ module Puppet setdefaults(:parser, :typecheck => [true, "Whether to validate types during parsing."], - :paramcheck => [true, "Whether to validate parameters during parsing."] + :paramcheck => [true, "Whether to validate parameters during parsing."], + :node_source => ["", "Where to look for node configuration information. + See the `NodeSourceReference`:trac: for more information."] ) setdefaults(:main, 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 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 diff --git a/lib/puppet/parser/node.rb b/lib/puppet/parser/node.rb deleted file mode 100644 index c7979e51f..000000000 --- a/lib/puppet/parser/node.rb +++ /dev/null @@ -1,133 +0,0 @@ -# Created by Luke A. Kanies on 2007-08-13. -# Copyright (c) 2007. All rights reserved. - -require 'puppet/external/gratr/digraph' -require 'puppet/external/gratr/import' -require 'puppet/external/gratr/dot' - -# Maintain a graph of scopes, along with a bunch of data -# about the individual configuration we're compiling. -class Puppet::Parser::Configuration - attr_reader :topscope, :interpreter, :host, :facts - - # Add a collection to the global list. - def add_collection(coll) - @collections << coll - end - - # Store the fact that we've evaluated a class, and store a reference to - # the scope in which it was evaluated, so that we can look it up later. - def class_set(name, scope) - @class_scopes[name] = scope - end - - # Return the scope associated with a class. This is just here so - # that subclasses can set their parent scopes to be the scope of - # their parent class, and it's also used when looking up qualified - # variables. - def class_scope(klass) - # They might pass in either the class or class name - if klass.respond_to?(:classname) - @class_scopes[klass.classname] - else - @class_scopes[klass] - end - end - - # Return a list of all of the defined classes. - def classlist - return @class_scopes.keys.reject { |k| k == "" } - end - - # Should the scopes behave declaratively? - def declarative? - true - end - - # Set up our configuration. We require an interpreter - # and a host name, and we normally are passed facts, too. - def initialize(options) - @interpreter = options[:interpreter] or - raise ArgumentError, "You must pass an interpreter to the configuration" - @facts = options[:facts] || {} - @host = options[:host] or - raise ArgumentError, "You must pass a host name to the configuration" - - # Call the setup methods from the base class. - super() - - initvars() - end - - # Create a new scope, with either a specified parent scope or - # using the top scope. Adds an edge between the scope and - # its parent to the graph. - def newscope(parent = nil) - parent ||= @topscope - scope = Puppet::Parser::Scope.new(:configuration => self) - @graph.add_edge!(parent, scope) - scope - end - - # Find the parent of a given scope. Assumes scopes only ever have - # one in edge, which will always be true. - def parent(scope) - if ary = @graph.adjacent(scope, :direction => :in) and ary.length > 0 - ary[0] - else - nil - end - end - - # Return an array of all of the unevaluated objects - def unevaluated - ary = @definedtable.find_all do |name, object| - ! object.builtin? and ! object.evaluated? - end.collect { |name, object| object } - - if ary.empty? - return nil - else - return ary - end - end - - private - - # Set up all of our internal variables. - def initvars - # The table for storing class singletons. This will only actually - # be used by top scopes and node scopes. - @class_scopes = {} - - # The table for all defined resources. - @resource_table = {} - - # The list of objects that will available for export. - @exported_resources = {} - - # The list of overrides. This is used to cache overrides on objects - # that don't exist yet. We store an array of each override. - @resource_overrides = Hash.new do |overs, ref| - overs[ref] = [] - end - - # The list of collections that have been created. This is a global list, - # but they each refer back to the scope that created them. - @collections = [] - - # Create our initial scope, our scope graph, and add the initial scope to the graph. - @topscope = Puppet::Parser::Scope.new(:configuration => self, :type => "main", :name => "top") - @graph = GRATR::Digraph.new - @graph.add_vertex!(@topscope) - end - - # Return the list of remaining overrides. - def overrides - @resource_overrides.values.flatten - end - - def resources - @resourcetable - end -end |