diff options
Diffstat (limited to 'lib/puppet/node/configuration.rb')
-rw-r--r-- | lib/puppet/node/configuration.rb | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/lib/puppet/node/configuration.rb b/lib/puppet/node/configuration.rb new file mode 100644 index 000000000..e667007e9 --- /dev/null +++ b/lib/puppet/node/configuration.rb @@ -0,0 +1,123 @@ +require 'puppet/external/gratr/digraph' + +# This class models a node configuration. It is the thing +# meant to be passed from server to client, and it contains all +# of the information in the configuration, including the resources +# and the relationships between them. +class Puppet::Node::Configuration < GRATR::Digraph + attr_accessor :name + attr_reader :extraction_format + + # Add classes to our class list. + def add_class(*classes) + classes.each do |klass| + @classes << klass + end + + # Add the class names as tags, too. + tag(*classes) + end + + def classes + @classes.dup + end + + # Make sure we support the requested extraction format. + def extraction_format=(value) + unless respond_to?("extract_to_%s" % value) + raise ArgumentError, "Invalid extraction format %s" % value + end + @extraction_format = value + end + + # Turn our configuration graph into whatever the client is expecting. + def extract + send("extract_to_%s" % extraction_format) + end + + # Create the traditional TransBuckets and TransObjects from our configuration + # graph. This will hopefully be deprecated soon. + def extract_to_transportable + top = nil + current = nil + buckets = {} + + unless main = vertices.find { |res| res.type == "class" and res.title == :main } + raise Puppet::DevError, "Could not find 'main' class; cannot generate configuration" + end + + # Create a proc for examining edges, which we'll use to build our tree + # of TransBuckets and TransObjects. + bucket = nil + edges = proc do |edge| + # The sources are always non-builtins. + source, target = edge.source, edge.target + unless tmp = buckets[source.to_s] + if tmp = buckets[source.to_s] = source.to_trans + bucket = tmp + else + # This is because virtual resources return nil. If a virtual + # container resource contains realized resources, we still need to get + # to them. So, we keep a reference to the last valid bucket + # we returned and use that if the container resource is virtual. + end + end + bucket = tmp || bucket + if child = target.to_trans + unless bucket + raise "No bucket created for %s" % source + end + bucket.push child + + # It's important that we keep a reference to any TransBuckets we've created, so + # we don't create multiple buckets for children. + unless target.builtin? + buckets[target.to_s] = child + end + end + end + dfs(:start => main, :examine_edge => edges) + + unless main + raise Puppet::DevError, "Could not find 'main' class; cannot generate configuration" + end + + # Retrive the bucket for the top-level scope and set the appropriate metadata. + unless result = buckets[main.to_s] + raise Puppet::DevError, "Did not evaluate top scope" + end + + result.classes = classes + + # Clear the cache to encourage the GC + buckets.clear + return result + end + + def initialize(name) + super() + @name = name + @extraction_format ||= :transportable + @tags = [] + @classes = [] + end + + # Add a tag. + def tag(*names) + names.each do |name| + name = name.to_s + @tags << name unless @tags.include?(name) + if name.include?("::") + name.split("::").each do |sub| + @tags << sub unless @tags.include?(sub) + end + end + end + nil + end + + # Return the list of tags. + def tags + @tags.dup + end +end |