summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorLuke Kanies <luke@madstop.com>2007-08-20 13:28:40 -0500
committerLuke Kanies <luke@madstop.com>2007-08-20 13:28:40 -0500
commit6467c21e15b8a28e627d1395f76fe8f42ee77d70 (patch)
treec36f4e350074a028ba6cc9f8e4230284e880ab46 /lib
parenta846ea900f9fa7a2baaa4fbd0742f080e7fd7a04 (diff)
downloadpuppet-6467c21e15b8a28e627d1395f76fe8f42ee77d70.tar.gz
puppet-6467c21e15b8a28e627d1395f76fe8f42ee77d70.tar.xz
puppet-6467c21e15b8a28e627d1395f76fe8f42ee77d70.zip
The first pass where at least all of the snippet tests pass. I have unfortunately had to stop being so assiduous in my rewriting of tests, but I am in too much of a time crunch to do this "right". The basic structure is definitely in place, though, and from here it is a question of making the rest of the tests work and hopefully writing some sufficient new tests, rather than making the code itself work.
Diffstat (limited to 'lib')
-rw-r--r--lib/puppet/network/handler/configuration.rb7
-rw-r--r--lib/puppet/network/handler/master.rb192
-rw-r--r--lib/puppet/parser/ast/astarray.rb63
-rw-r--r--lib/puppet/parser/ast/collection.rb2
-rw-r--r--lib/puppet/parser/ast/hostclass.rb1
-rw-r--r--lib/puppet/parser/collector.rb11
-rw-r--r--lib/puppet/parser/configuration.rb70
-rw-r--r--lib/puppet/parser/functions.rb7
-rw-r--r--lib/puppet/parser/interpreter.rb3
-rw-r--r--lib/puppet/parser/resource.rb319
-rw-r--r--lib/puppet/parser/resource/reference.rb2
-rw-r--r--lib/puppet/parser/scope.rb75
12 files changed, 336 insertions, 416 deletions
diff --git a/lib/puppet/network/handler/configuration.rb b/lib/puppet/network/handler/configuration.rb
index c1c77a357..f1a20ee74 100644
--- a/lib/puppet/network/handler/configuration.rb
+++ b/lib/puppet/network/handler/configuration.rb
@@ -46,6 +46,8 @@ class Puppet::Network::Handler
# immediately. Mostly, this is so we can create the interpreter
# on-demand, which is easier for testing.
@options = options
+
+ set_server_facts
end
# Are we running locally, or are our clients networked?
@@ -58,7 +60,7 @@ class Puppet::Network::Handler
v = interpreter.configuration_version
# If we can find the node, then store the fact that the node
# has checked in.
- if node = node_handler.details(client)
+ if client and node = node_handler.details(client)
update_node_check(node)
end
@@ -95,6 +97,9 @@ class Puppet::Network::Handler
begin
config = interpreter.compile(node)
rescue Puppet::Error => detail
+ if Puppet[:trace]
+ puts detail.backtrace
+ end
Puppet.err detail
raise XMLRPC::FaultException.new(
1, detail.to_s
diff --git a/lib/puppet/network/handler/master.rb b/lib/puppet/network/handler/master.rb
index e889c1ba8..0aa50a426 100644
--- a/lib/puppet/network/handler/master.rb
+++ b/lib/puppet/network/handler/master.rb
@@ -21,66 +21,9 @@ class Puppet::Network::Handler
iface.add_method("int freshness()")
}
- # FIXME At some point, this should be autodocumenting.
- def addfacts(facts)
- # Add our server version to the fact list
- facts["serverversion"] = Puppet.version.to_s
-
- # And then add the server name and IP
- {"servername" => "fqdn",
- "serverip" => "ipaddress"
- }.each do |var, fact|
- if obj = Facter[fact]
- facts[var] = obj.value
- else
- Puppet.warning "Could not retrieve fact %s" % fact
- end
- end
-
- if facts["servername"].nil?
- host = Facter.value(:hostname)
- if domain = Facter.value(:domain)
- facts["servername"] = [host, domain].join(".")
- else
- facts["servername"] = host
- end
- end
- end
-
- # Manipulate the client name as appropriate.
- def clientname(name, ip, facts)
- # Always use the hostname from Facter.
- client = facts["hostname"]
- clientip = facts["ipaddress"]
- if Puppet[:node_name] == 'cert'
- if name
- client = name
- end
- if ip
- clientip = ip
- end
- end
-
- return client, clientip
- end
-
# Tell a client whether there's a fresh config for it
def freshness(client = nil, clientip = nil)
- if Puppet.features.rails? and Puppet[:storeconfigs]
- Puppet::Rails.connect
-
- host = Puppet::Rails::Host.find_or_create_by_name(client)
- host.last_freshcheck = Time.now
- if clientip and (! host.ip or host.ip == "" or host.ip == "NULL")
- host.ip = clientip
- end
- host.save
- end
- if defined? @interpreter
- return @interpreter.parsedate
- else
- return 0
- end
+ config_handler.version(client)
end
def initialize(hash = {})
@@ -121,104 +64,81 @@ class Puppet::Network::Handler
args[:Classes] = hash[:Classes]
end
- @interpreter = Puppet::Parser::Interpreter.new(args)
+ @config_handler = Puppet::Network::Handler.handler(:configuration).new(args)
end
+ # Call our various handlers; this handler is getting deprecated.
def getconfig(facts, format = "marshal", client = nil, clientip = nil)
- if @local
- # we don't need to do anything, since we should already
- # have raw objects
- Puppet.debug "Our client is local"
- else
- Puppet.debug "Our client is remote"
-
- # XXX this should definitely be done in the protocol, somehow
- case format
- when "marshal":
- Puppet.warning "You should upgrade your client. 'Marshal' will not be supported much longer."
- begin
- facts = Marshal::load(CGI.unescape(facts))
- rescue => detail
- raise XMLRPC::FaultException.new(
- 1, "Could not rebuild facts"
- )
- end
- when "yaml":
- begin
- facts = YAML.load(CGI.unescape(facts))
- rescue => detail
- raise XMLRPC::FaultException.new(
- 1, "Could not rebuild facts"
- )
- end
- else
- raise XMLRPC::FaultException.new(
- 1, "Unavailable config format %s" % format
- )
- end
- end
-
+ facts = decode_facts(facts)
client, clientip = clientname(client, clientip, facts)
- # Add any server-side facts to our server.
- addfacts(facts)
+ # Pass the facts to the fact handler
+ fact_handler.set(client, facts)
- retobjects = nil
+ # And get the configuration from the config handler
+ return config_handler.configuration(client)
+ end
- # This is hackish, but there's no "silence" option for benchmarks
- # right now
- if @local
- #begin
- retobjects = @interpreter.run(client, facts)
- #rescue Puppet::Error => detail
- # Puppet.err detail
- # raise XMLRPC::FaultException.new(
- # 1, detail.to_s
- # )
- #rescue => detail
- # Puppet.err detail.to_s
- # return ""
- #end
+ def local?
+ if defined? @local and @local
+ return true
else
- benchmark(:notice, "Compiled configuration for %s" % client) do
- begin
- retobjects = @interpreter.run(client, facts)
- rescue Puppet::Error => detail
- Puppet.err detail
- raise XMLRPC::FaultException.new(
- 1, detail.to_s
- )
- rescue => detail
- Puppet.err detail.to_s
- return ""
- end
+ return false
+ end
+ end
+
+ private
+
+ # Manipulate the client name as appropriate.
+ def clientname(name, ip, facts)
+ # Always use the hostname from Facter.
+ client = facts["hostname"]
+ clientip = facts["ipaddress"]
+ if Puppet[:node_name] == 'cert'
+ if name
+ client = name
end
+ if ip
+ clientip = ip
+ end
+ end
+
+ return client, clientip
+ end
+
+ def config_handler
+ unless defined? @config_handler
+ @config_handler = Puppet::Network::Handler.handler(:config).new :local => local?
end
+ @config_handler
+ end
+ #
+ def decode_facts(facts)
if @local
- return retobjects
+ # we don't need to do anything, since we should already
+ # have raw objects
+ Puppet.debug "Our client is local"
else
- str = nil
- case format
- when "marshal":
- str = Marshal::dump(retobjects)
- when "yaml":
- str = retobjects.to_yaml(:UseBlock => true)
- else
+ Puppet.debug "Our client is remote"
+
+ begin
+ facts = YAML.load(CGI.unescape(facts))
+ rescue => detail
raise XMLRPC::FaultException.new(
- 1, "Unavailable config format %s" % format
+ 1, "Could not rebuild facts"
)
end
- return CGI.escape(str)
end
+
+ return facts
end
- def local?
- if defined? @local and @local
- return true
- else
- return false
+ def fact_handler
+ unless defined? @fact_handler
+ @fact_handler = Puppet::Network::Handler.handler(:facts).new :local => local?
end
+ @fact_handler
end
end
end
diff --git a/lib/puppet/parser/ast/astarray.rb b/lib/puppet/parser/ast/astarray.rb
index a0bd5bf89..c0212f919 100644
--- a/lib/puppet/parser/ast/astarray.rb
+++ b/lib/puppet/parser/ast/astarray.rb
@@ -21,45 +21,38 @@ class Puppet::Parser::AST
# We basically always operate declaratively, and when we
# do we need to evaluate the settor-like statements first. This
# is basically variable and type-default declarations.
- if scope.declarative?
- # This is such a stupid hack. I've no real idea how to make a
- # "real" declarative language, so I hack it so it looks like
- # one, yay.
- settors = []
- others = []
+ # This is such a stupid hack. I've no real idea how to make a
+ # "real" declarative language, so I hack it so it looks like
+ # one, yay.
+ settors = []
+ others = []
- # Make a new array, so we don't have to deal with the details of
- # flattening and such
- items = []
-
- # First clean out any AST::ASTArrays
- @children.each { |child|
- if child.instance_of?(AST::ASTArray)
- child.each do |ac|
- if ac.class.settor?
- settors << ac
- else
- others << ac
- end
- end
- else
- if child.class.settor?
- settors << child
+ # Make a new array, so we don't have to deal with the details of
+ # flattening and such
+ items = []
+
+ # First clean out any AST::ASTArrays
+ @children.each { |child|
+ if child.instance_of?(AST::ASTArray)
+ child.each do |ac|
+ if ac.class.settor?
+ settors << ac
else
- others << child
+ others << ac
end
end
- }
- rets = [settors, others].flatten.collect { |child|
- child.safeevaluate(:scope => scope)
- }
- return rets.reject { |o| o.nil? }
- else
- # If we're not declarative, just do everything in order.
- return @children.collect { |item|
- item.safeevaluate(:scope => scope)
- }.reject { |o| o.nil? }
- end
+ else
+ if child.class.settor?
+ settors << child
+ else
+ others << child
+ end
+ end
+ }
+ rets = [settors, others].flatten.collect { |child|
+ child.safeevaluate(:scope => scope)
+ }
+ return rets.reject { |o| o.nil? }
end
def push(*ary)
diff --git a/lib/puppet/parser/ast/collection.rb b/lib/puppet/parser/ast/collection.rb
index c817b5c5e..7daf031cf 100644
--- a/lib/puppet/parser/ast/collection.rb
+++ b/lib/puppet/parser/ast/collection.rb
@@ -20,7 +20,7 @@ class Collection < AST::Branch
newcoll = Puppet::Parser::Collector.new(scope, @type, str, code, self.form)
- scope.newcollection(newcoll)
+ scope.configuration.add_collection(newcoll)
newcoll
end
diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb
index d1ce370da..9b60c692f 100644
--- a/lib/puppet/parser/ast/hostclass.rb
+++ b/lib/puppet/parser/ast/hostclass.rb
@@ -27,7 +27,6 @@ class Puppet::Parser::AST
# Verify that we haven't already been evaluated, and if we have been evaluated,
# make sure that we match the class.
if existing_scope = scope.class_scope(self)
- raise "Fix this portion of the code -- check that the scopes match classes"
#if existing_scope.source.object_id == self.object_id
Puppet.debug "%s class already evaluated" % @type
return nil
diff --git a/lib/puppet/parser/collector.rb b/lib/puppet/parser/collector.rb
index 6c49c6d57..0846c40ab 100644
--- a/lib/puppet/parser/collector.rb
+++ b/lib/puppet/parser/collector.rb
@@ -81,7 +81,7 @@ class Puppet::Parser::Collector
# If there are no more resources to find, delete this from the list
# of collections.
if @resources.empty?
- @scope.collections.delete(self)
+ @scope.configuration.delete_collection(self)
end
return result
@@ -94,7 +94,7 @@ class Puppet::Parser::Collector
else
method = :virtual?
end
- scope.resources.find_all do |resource|
+ scope.configuration.resources.find_all do |resource|
resource.type == @type and resource.send(method) and match?(resource)
end
end
@@ -117,13 +117,6 @@ class Puppet::Parser::Collector
return objects
end
end
-
-# if objects and ! objects.empty?
-# objects.each { |r| r.virtual = false }
-# return objects
-# else
-# return false
-# end
end
def initialize(scope, type, equery, vquery, form)
diff --git a/lib/puppet/parser/configuration.rb b/lib/puppet/parser/configuration.rb
index 617d7d231..90812899a 100644
--- a/lib/puppet/parser/configuration.rb
+++ b/lib/puppet/parser/configuration.rb
@@ -60,7 +60,7 @@ class Puppet::Parser::Configuration
evaluate_main()
- evaluate_ast_nodes()
+ evaluate_ast_node()
evaluate_classes()
@@ -73,9 +73,32 @@ class Puppet::Parser::Configuration
return extract()
end
- # Should the scopes behave declaratively?
- def declarative?
- true
+ # FIXME There are no tests for this.
+ def delete_collection(coll)
+ @collections.delete(coll) if @collections.include?(coll)
+ end
+
+ # FIXME There are no tests for this.
+ def delete_resource(resource)
+ @resource_table.delete(resource.ref) if @resource_table.include?(resource.ref)
+
+ @resource_graph.remove_vertex!(resource) if @resource_graph.vertex?(resource)
+ end
+
+ # Evaluate each class in turn. If there are any classes we can't find,
+ # just tag the configuration and move on.
+ def evaluate_classes(classes = nil)
+ classes ||= node.classes
+ classes.each do |name|
+ if klass = @parser.findclass("", name)
+ # This will result in class_set getting called, which
+ # will in turn result in tags. Yay.
+ klass.safeevaluate(:scope => topscope)
+ else
+ Puppet.info "Could not find class %s for %s" % [name, node.name]
+ tag(name)
+ end
+ end
end
# Make sure we support the requested extraction format.
@@ -119,9 +142,11 @@ class Puppet::Parser::Configuration
# 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)
+ def newscope(parent, options = {})
parent ||= @topscope
- scope = Puppet::Parser::Scope.new(:configuration => self)
+ options[:configuration] = self
+ options[:parser] ||= self.parser
+ scope = Puppet::Parser::Scope.new(options)
@scope_graph.add_edge!(parent, scope)
scope
end
@@ -141,6 +166,11 @@ class Puppet::Parser::Configuration
@resource_overrides[resource.ref]
end
+ # Return a list of all resources.
+ def resources
+ @resource_table.values
+ end
+
# Store a resource override.
def store_override(override)
override.override = true
@@ -179,7 +209,7 @@ class Puppet::Parser::Configuration
astnode = nil
#nodes = @parser.nodes
@node.names.each do |name|
- break if astnode = @parser.nodes[name]
+ break if astnode = @parser.nodes[name.to_s.downcase]
end
unless astnode
@@ -192,21 +222,6 @@ class Puppet::Parser::Configuration
astnode.safeevaluate :scope => topscope
end
- # Evaluate each class in turn. If there are any classes we can't find,
- # just tag the configuration and move on.
- def evaluate_classes
- node.classes.each do |name|
- if klass = @parser.findclass("", name)
- # This will result in class_set getting called, which
- # will in turn result in tags. Yay.
- klass.safeevaluate(:scope => topscope)
- else
- Puppet.info "Could not find class %s for %s" % [name, node.name]
- tag(name)
- end
- end
- end
-
# Evaluate our collections and return true if anything returned an object.
# The 'true' is used to continue a loop, so it's important.
def evaluate_collections
@@ -305,8 +320,13 @@ class Puppet::Parser::Configuration
end
# Then add the resources.
- @resource_graph.adjacent(scope, :direction => :out).each do |vertex|
- bucket.push vertex.to_trans
+ if @resource_graph.vertex?(scope)
+ @resource_graph.adjacent(scope, :direction => :out).each do |vertex|
+ # Some resources don't get translated, e.g., virtual resources.
+ if obj = vertex.to_trans
+ bucket.push obj
+ end
+ end
end
end
@@ -396,7 +416,7 @@ class Puppet::Parser::Configuration
@tags = []
# 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")
+ @topscope = Puppet::Parser::Scope.new(:configuration => self, :type => "main", :name => "top", :parser => self.parser)
# For maintaining scope relationships.
@scope_graph = GRATR::Digraph.new
diff --git a/lib/puppet/parser/functions.rb b/lib/puppet/parser/functions.rb
index 946501154..ad58c7040 100644
--- a/lib/puppet/parser/functions.rb
+++ b/lib/puppet/parser/functions.rb
@@ -109,7 +109,8 @@ module Functions
# Include the specified classes
newfunction(:include, :doc => "Evaluate one or more classes.") do |vals|
- klasses = evalclasses(*vals)
+ vals = [vals] unless vals.is_a?(Array)
+ klasses = configuration.evaluate_classes(vals)
missing = vals.find_all do |klass|
! klasses.include?(klass)
@@ -144,7 +145,7 @@ module Functions
tells you whether the current container is tagged with the specified tags.
The tags are ANDed, so that all of the specified tags must be included for
the function to return true.") do |vals|
- classlist = self.classlist
+ classlist = configuration.classlist
retval = true
vals.each do |val|
@@ -234,7 +235,7 @@ module Functions
vals = [vals] unless vals.is_a?(Array)
coll.resources = vals
- newcollection(coll)
+ configuration.add_collection(coll)
end
newfunction(:search, :doc => "Add another namespace for this class to search.
diff --git a/lib/puppet/parser/interpreter.rb b/lib/puppet/parser/interpreter.rb
index f0b9d0179..cf3027a5a 100644
--- a/lib/puppet/parser/interpreter.rb
+++ b/lib/puppet/parser/interpreter.rb
@@ -3,6 +3,7 @@ require 'timeout'
require 'puppet/rails'
require 'puppet/util/methodhelper'
require 'puppet/parser/parser'
+require 'puppet/parser/configuration'
require 'puppet/parser/scope'
# The interpreter is a very simple entry-point class that
@@ -93,7 +94,7 @@ class Puppet::Parser::Interpreter
def compile(node)
parsefiles()
- return Puppet::Parser::Configuration.new(node).compile
+ return Puppet::Parser::Configuration.new(node, @parser).compile
end
private
diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb
index 371f56ec1..eace88645 100644
--- a/lib/puppet/parser/resource.rb
+++ b/lib/puppet/parser/resource.rb
@@ -10,9 +10,9 @@ class Puppet::Parser::Resource
include Puppet::Util::Logging
attr_accessor :source, :line, :file, :scope, :rails_id
- attr_accessor :virtual, :override, :params, :translated
+ attr_accessor :virtual, :override, :translated
- attr_reader :exported
+ attr_reader :exported, :evaluated, :params
attr_writer :tags
@@ -24,7 +24,7 @@ class Puppet::Parser::Resource
end
# Set up some boolean test methods
- [:exported, :translated, :override].each do |method|
+ [:exported, :translated, :override, :virtual, :evaluated].each do |method|
newmeth = (method.to_s + "?").intern
define_method(newmeth) do
self.send(method)
@@ -43,47 +43,6 @@ class Puppet::Parser::Resource
end
end
- # Add default values from our definition.
- def adddefaults
- defaults = scope.lookupdefaults(self.type)
-
- defaults.each do |name, param|
- unless @params.include?(param.name)
- self.debug "Adding default for %s" % param.name
-
- @params[param.name] = param
- end
- end
- end
-
- # Add any metaparams defined in our scope. This actually adds any metaparams
- # from any parent scope, and there's currently no way to turn that off.
- def addmetaparams
- Puppet::Type.eachmetaparam do |name|
- next if self[name]
- if val = scope.lookupvar(name.to_s, false)
- unless val == :undefined
- set Param.new(:name => name, :value => val,
- :source => scope.source)
- end
- end
- end
- end
-
- # Add any overrides for this object.
- def addoverrides
- overrides = scope.configuration.resource_overrides(self)
- raise "fix this test"
-
- overrides.each do |over|
- self.merge(over)
- end
-
- # Remove the overrides, so that the configuration knows there
- # are none left.
- overrides.clear
- end
-
def builtin=(bool)
@ref.builtin = bool
end
@@ -92,7 +51,7 @@ class Puppet::Parser::Resource
def evaluate
if klass = @ref.definedtype
finish()
- scope.deleteresource(self)
+ scope.configuration.delete_resource(self)
return klass.evaluate(:scope => scope,
:type => self.type,
:title => self.title,
@@ -110,6 +69,8 @@ class Puppet::Parser::Resource
@evaluated = true
end
+ # Mark this resource as both exported and virtual,
+ # or remove the exported mark.
def exported=(value)
if value
@virtual = true
@@ -119,63 +80,71 @@ class Puppet::Parser::Resource
end
end
- def evaluated?
- if defined? @evaluated and @evaluated
- true
- else
- false
- end
- end
-
# Do any finishing work on this object, called before evaluation or
# before storage/translation.
def finish
- addoverrides()
- adddefaults()
- addmetaparams()
+ add_overrides()
+ add_defaults()
+ add_metaparams()
+ validate()
end
def initialize(options)
- options = symbolize_options(options)
-
- # Collect the options necessary to make the reference.
- refopts = [:type, :title].inject({}) do |hash, param|
- hash[param] = options[param]
- options.delete(param)
- hash
+ # Set all of the options we can.
+ options.each do |option, value|
+ if respond_to?(option.to_s + "=")
+ send(option.to_s + "=", value)
+ options.delete(option)
+ end
end
- @params = {}
- tmpparams = nil
- if tmpparams = options[:params]
- options.delete(:params)
+ [:scope, :source].each do |attribute|
+ unless self.send(attribute)
+ raise ArgumentError, "Resources require a %s" % attribute
+ end
end
- # Now set the rest of the options.
- set_options(options)
-
- @ref = Reference.new(refopts)
+ # Set up our reference.
+ if type = options[:type] and title = options[:title]
+ options.delete(:type)
+ options.delete(:title)
+ else
+ raise ArgumentError, "Resources require a type and title"
+ end
- requiredopts(:scope, :source)
+ @ref = Reference.new(:type => type, :title => title, :scope => self.scope)
- @ref.scope = self.scope
+ @params = {}
- if tmpparams
- tmpparams.each do |param|
- # We use the method here, because it does type-checking.
- set(param)
+ # Define all of the parameters
+ if params = options[:params]
+ options.delete(:params)
+ params.each do |param|
+ set_parameter(param)
end
end
+
+ # Throw an exception if we've got any arguments left to set.
+ unless options.empty?
+ raise ArgumentError, "Resources do not accept %s" % options.keys.collect { |k| k.to_s }.join(", ")
+ end
end
- # Merge an override resource in.
+ # Merge an override resource in. This will throw exceptions if
+ # any overrides aren't allowed.
def merge(resource)
+ # Test the resource scope, to make sure the resource is even allowed
+ # to override.
+ unless self.source.object_id == resource.source.object_id || resource.source.child_of?(self.source)
+ raise Puppet::ParseError.new("Only subclasses can override parameters", resource.line, resource.file)
+ end
# Some of these might fail, but they'll fail in the way we want.
resource.params.each do |name, param|
- set(param)
+ override_parameter(param)
end
end
+ # Modify this resource in the Rails database. Poor design, yo.
def modify_rails(db_resource)
args = rails_args
args.each do |param, value|
@@ -226,23 +195,6 @@ class Puppet::Parser::Resource
@@paramcheck
end
- # Verify that all passed parameters are valid. This throws an error if
- # there's a problem, so we don't have to worry about the return value.
- def paramcheck(param)
- param = param.to_s
- # Now make sure it's a valid argument to our class. These checks
- # are organized in order of commonhood -- most types, it's a valid
- # argument and paramcheck is enabled.
- if @ref.typeclass.validattr?(param)
- true
- elsif %w{name title}.include?(param) # always allow these
- true
- elsif paramcheck?
- self.fail Puppet::ParseError, "Invalid parameter '%s' for type '%s'" %
- [param.inspect, @ref.type]
- end
- end
-
# A temporary occasion, until I get paths in the scopes figured out.
def path
to_s
@@ -253,59 +205,6 @@ class Puppet::Parser::Resource
@ref.to_s
end
- # You have to pass a Resource::Param to this.
- def set(param, value = nil, source = nil)
- if value and source
- param = Puppet::Parser::Resource::Param.new(
- :name => param, :value => value, :source => source
- )
- elsif ! param.is_a?(Puppet::Parser::Resource::Param)
- raise ArgumentError, "Must pass a parameter or all necessary values"
- end
- # Because definitions are now parse-time, I can paramcheck immediately.
- paramcheck(param.name)
-
- if current = @params[param.name]
- # This is where we'd ignore any equivalent values if we wanted to,
- # but that would introduce a lot of really bad ordering issues.
- if param.source.child_of?(current.source)
- if param.add
- # Merge with previous value.
- param.value = [ current.value, param.value ].flatten
- end
-
- # Replace it, keeping all of its info.
- @params[param.name] = param
- else
- if Puppet[:trace]
- puts caller
- end
- msg = "Parameter '%s' is already set on %s" %
- [param.name, self.to_s]
- if current.source.to_s != ""
- msg += " by %s" % current.source
- end
- if current.file or current.line
- fields = []
- fields << current.file if current.file
- fields << current.line.to_s if current.line
- msg += " at %s" % fields.join(":")
- end
- msg += "; cannot redefine"
- error = Puppet::ParseError.new(msg)
- error.file = param.file if param.file
- error.line = param.line if param.line
- raise error
- end
- else
- if self.source == param.source or param.source.child_of?(self.source)
- @params[param.name] = param
- else
- fail Puppet::ParseError, "Only subclasses can set parameters"
- end
- end
- end
-
def tags
unless defined? @tags
@tags = scope.tags
@@ -387,12 +286,102 @@ class Puppet::Parser::Resource
return obj
end
-
- def virtual?
- self.virtual
- end
private
+
+ # Add default values from our definition.
+ def add_defaults
+ scope.lookupdefaults(self.type).each do |name, param|
+ unless @params.include?(name)
+ self.debug "Adding default for %s" % name
+
+ @params[name] = param
+ end
+ end
+ end
+
+ # Add any metaparams defined in our scope. This actually adds any metaparams
+ # from any parent scope, and there's currently no way to turn that off.
+ def add_metaparams
+ Puppet::Type.eachmetaparam do |name|
+ # Skip metaparams that we already have defined.
+ next if @params[name]
+ if val = scope.lookupvar(name.to_s, false)
+ unless val == :undefined
+ set_parameter(name, val)
+ end
+ end
+ end
+ end
+
+ # Add any overrides for this object.
+ def add_overrides
+ if overrides = scope.configuration.resource_overrides(self)
+ overrides.each do |over|
+ self.merge(over)
+ end
+
+ # Remove the overrides, so that the configuration knows there
+ # are none left.
+ overrides.clear
+ end
+ end
+
+ # Accept a parameter from an override.
+ def override_parameter(param)
+ # This can happen if the override is defining a new parameter, rather
+ # than replacing an existing one.
+ unless current = @params[param.name]
+ @params[param.name] = param
+ return
+ end
+
+ # The parameter is already set. See if they're allowed to override it.
+ if param.source.child_of?(current.source)
+ if param.add
+ # Merge with previous value.
+ param.value = [ current.value, param.value ].flatten
+ end
+
+ # Replace it, keeping all of its info.
+ @params[param.name] = param
+ else
+ if Puppet[:trace]
+ puts caller
+ end
+ msg = "Parameter '%s' is already set on %s" %
+ [param.name, self.to_s]
+ if current.source.to_s != ""
+ msg += " by %s" % current.source
+ end
+ if current.file or current.line
+ fields = []
+ fields << current.file if current.file
+ fields << current.line.to_s if current.line
+ msg += " at %s" % fields.join(":")
+ end
+ msg += "; cannot redefine"
+ raise Puppet::ParseError.new(msg, param.line, param.file)
+ end
+ end
+
+ # Verify that all passed parameters are valid. This throws an error if
+ # there's a problem, so we don't have to worry about the return value.
+ def paramcheck(param)
+ param = param.to_s
+ # Now make sure it's a valid argument to our class. These checks
+ # are organized in order of commonhood -- most types, it's a valid
+ # argument and paramcheck is enabled.
+ if @ref.typeclass.validattr?(param)
+ true
+ elsif %w{name title}.include?(param) # always allow these
+ true
+ elsif paramcheck?
+ self.fail Puppet::ParseError, "Invalid parameter '%s' for type '%s'" %
+ [param, @ref.type]
+ end
+ end
+
def rails_args
return [:type, :title, :line, :exported].inject({}) do |hash, param|
# 'type' isn't a valid column name, so we have to use another name.
@@ -403,6 +392,26 @@ class Puppet::Parser::Resource
hash
end
end
-end
-# $Id$
+ # Define a parameter in our resource.
+ def set_parameter(param, value = nil)
+ if value
+ param = Puppet::Parser::Resource::Param.new(
+ :name => param, :value => value, :source => self.source
+ )
+ elsif ! param.is_a?(Puppet::Parser::Resource::Param)
+ raise ArgumentError, "Must pass a parameter or all necessary values"
+ end
+
+ # And store it in our parameter hash.
+ @params[param.name] = param
+ end
+
+ # Make sure the resource's parameters are all valid for the type.
+ def validate
+ @params.each do |name, param|
+ # Make sure it's a valid parameter.
+ paramcheck(name)
+ end
+ end
+end
diff --git a/lib/puppet/parser/resource/reference.rb b/lib/puppet/parser/resource/reference.rb
index 19d179660..b19dd2258 100644
--- a/lib/puppet/parser/resource/reference.rb
+++ b/lib/puppet/parser/resource/reference.rb
@@ -67,5 +67,3 @@ class Puppet::Parser::Resource::Reference
@typeclass
end
end
-
-# $Id$
diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb
index cb6d98584..808362858 100644
--- a/lib/puppet/parser/scope.rb
+++ b/lib/puppet/parser/scope.rb
@@ -15,7 +15,7 @@ class Puppet::Parser::Scope
include Enumerable
include Puppet::Util::Errors
- attr_accessor :parent, :level, :interp, :source
+ attr_accessor :parent, :level, :parser, :source
attr_accessor :name, :type, :base, :keyword
attr_accessor :top, :translated, :exported, :virtual, :configuration
@@ -56,6 +56,11 @@ class Puppet::Parser::Scope
end
end
+ # Retrieve a given class scope from the configuration.
+ def class_scope(klass)
+ configuration.class_scope(klass)
+ end
+
# Are we the top scope?
def topscope?
@level == 1
@@ -67,7 +72,7 @@ class Puppet::Parser::Scope
def findclass(name)
@namespaces.each do |namespace|
- if r = interp.findclass(namespace, name)
+ if r = parser.findclass(namespace, name)
return r
end
end
@@ -76,7 +81,7 @@ class Puppet::Parser::Scope
def finddefine(name)
@namespaces.each do |namespace|
- if r = interp.finddefine(namespace, name)
+ if r = parser.finddefine(namespace, name)
return r
end
end
@@ -87,8 +92,7 @@ class Puppet::Parser::Scope
configuration.findresource(string, name)
end
- # Initialize our new scope. Defaults to having no parent and to
- # being declarative.
+ # Initialize our new scope. Defaults to having no parent.
def initialize(hash = {})
if hash.include?(:namespace)
if n = hash[:namespace]
@@ -115,7 +119,7 @@ class Puppet::Parser::Scope
# All of the defaults set for types. It's a hash of hashes,
# with the first key being the type, then the second key being
# the parameter.
- @defaultstable = Hash.new { |dhash,type|
+ @defaults = Hash.new { |dhash,type|
dhash[type] = {}
}
end
@@ -136,8 +140,8 @@ class Puppet::Parser::Scope
# then override them with any current values
# this should probably be done differently
- if @defaultstable.include?(type)
- @defaultstable[type].each { |var,value|
+ if @defaults.include?(type)
+ @defaults[type].each { |var,value|
values[var] = value
}
end
@@ -195,11 +199,9 @@ class Puppet::Parser::Scope
@namespaces.dup
end
- # Create a new scope.
- def newscope(hash = {})
- hash[:parent] = self
- #debug "Creating new scope, level %s" % [self.level + 1]
- return Puppet::Parser::Scope.new(hash)
+ # Create a new scope and set these options.
+ def newscope(options)
+ configuration.newscope(self, options)
end
# Is this class for a node? This is used to make sure that
@@ -256,7 +258,7 @@ class Puppet::Parser::Scope
# Add a new object to our object table and the global list, and do any necessary
# checks.
def setresource(resource)
- @configuration.store_resource(resource)
+ @configuration.store_resource(self, resource)
# Mark the resource as virtual or exported, as necessary.
if self.exported?
@@ -264,7 +266,6 @@ class Puppet::Parser::Scope
elsif self.virtual?
resource.virtual = true
end
- raise "setresource's tests aren't fixed"
return resource
end
@@ -274,19 +275,13 @@ class Puppet::Parser::Scope
# at the end.
def setoverride(resource)
@configuration.store_override(resource)
- raise "setoverride tests aren't fixed"
- if obj = @definedtable[resource.ref]
- obj.merge(resource)
- else
- @overridetable[resource.ref] << resource
- end
end
# Set defaults for a type. The typename should already be downcased,
# so that the syntax is isolated. We don't do any kind of type-checking
# here; instead we let the resource do it when the defaults are used.
def setdefaults(type, params)
- table = @defaultstable[type]
+ table = @defaults[type]
# if we got a single param, it'll be in its own array
params = [params] unless params.is_a?(Array)
@@ -294,17 +289,8 @@ class Puppet::Parser::Scope
params.each { |param|
#Puppet.debug "Default for %s is %s => %s" %
# [type,ary[0].inspect,ary[1].inspect]
- if @@declarative
- if table.include?(param.name)
- self.fail "Default already defined for %s { %s }" %
- [type,param.name]
- end
- else
- if table.include?(param.name)
- # we should maybe allow this warning to be turned off...
- Puppet.warning "Replacing default for %s { %s }" %
- [type,param.name]
- end
+ if table.include?(param.name)
+ raise Puppet::ParseError.new("Default already defined for %s { %s }; cannot redefine" % [type, param.name], param.line, param.file)
end
table[param.name] = param
}
@@ -312,23 +298,19 @@ class Puppet::Parser::Scope
# Set a variable in the current scope. This will override settings
# in scopes above, but will not allow variables in the current scope
- # to be reassigned if we're declarative (which is the default).
+ # to be reassigned.
def setvar(name,value, file = nil, line = nil)
#Puppet.debug "Setting %s to '%s' at level %s" %
# [name.inspect,value,self.level]
if @symtable.include?(name)
- if @@declarative
- error = Puppet::ParseError.new("Cannot reassign variable %s" % name)
- if file
- error.file = file
- end
- if line
- error.line = line
- end
- raise error
- else
- Puppet.warning "Reassigning %s to %s" % [name,value]
+ error = Puppet::ParseError.new("Cannot reassign variable %s" % name)
+ if file
+ error.file = file
+ end
+ if line
+ error.line = line
end
+ raise error
end
@symtable[name] = value
end
@@ -446,8 +428,7 @@ class Puppet::Parser::Scope
# Convert our resource to a TransBucket.
def to_trans
- raise "Scope#to_trans needs to be tested"
- bucket = Puppet::TransBucket.new ret
+ bucket = Puppet::TransBucket.new([])
case self.type
when "": bucket.type = "main"