summaryrefslogtreecommitdiffstats
path: root/lib/puppet
diff options
context:
space:
mode:
Diffstat (limited to 'lib/puppet')
-rw-r--r--lib/puppet/configuration.rb10
-rw-r--r--lib/puppet/network/handler/node.rb178
-rw-r--r--lib/puppet/node_source/external.rb4
-rw-r--r--lib/puppet/node_source/ldap.rb4
-rw-r--r--lib/puppet/parser/node.rb133
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