summaryrefslogtreecommitdiffstats
path: root/lib/puppet/parser/resource.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/puppet/parser/resource.rb')
-rw-r--r--lib/puppet/parser/resource.rb324
1 files changed, 324 insertions, 0 deletions
diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb
new file mode 100644
index 000000000..5d09eaa9b
--- /dev/null
+++ b/lib/puppet/parser/resource.rb
@@ -0,0 +1,324 @@
+# A resource that we're managing. This handles making sure that only subclasses
+# can set parameters.
+class Puppet::Parser::Resource
+ require 'puppet/parser/resource/param'
+ require 'puppet/parser/resource/reference'
+ ResParam = Struct.new :name, :value, :source, :line, :file
+ include Puppet::Util
+ include Puppet::Util::MethodHelper
+ include Puppet::Util::Errors
+ include Puppet::Util::Logging
+
+ attr_accessor :source, :line, :file, :scope
+ attr_accessor :virtual, :override, :params, :translated
+
+ attr_reader :exported
+
+ attr_writer :tags
+
+ # Proxy a few methods to our @ref object.
+ [:builtin?, :type, :title].each do |method|
+ define_method(method) do
+ @ref.send(method)
+ end
+ end
+
+ # Set up some boolean test methods
+ [:exported, :translated, :override].each do |method|
+ newmeth = (method.to_s + "?").intern
+ define_method(newmeth) do
+ self.send(method)
+ end
+ end
+
+ def [](param)
+ param = symbolize(param)
+ if param == :title
+ return self.title
+ end
+ if @params.has_key?(param)
+ @params[param].value
+ else
+ nil
+ 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|
+ 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.lookupoverrides(self)
+
+ overrides.each do |over|
+ self.merge(over)
+ end
+
+ overrides.clear
+ end
+
+ def builtin=(bool)
+ @ref.builtin = bool
+ end
+
+ # Retrieve the associated definition and evaluate it.
+ def evaluate
+ if builtin?
+ devfail "Cannot evaluate a builtin type"
+ end
+
+ unless klass = scope.finddefine(self.type)
+ self.fail "Cannot find definition %s" % self.type
+ end
+
+ finish()
+
+ scope.deleteresource(self)
+
+ return klass.evaluate(:scope => scope,
+ :type => self.type,
+ :name => self.title,
+ :arguments => self.to_hash,
+ :scope => self.scope,
+ :exported => self.exported
+ )
+ ensure
+ @evaluated = true
+ end
+
+ def exported=(value)
+ if value
+ @virtual = true
+ @exported = value
+ else
+ @exported = value
+ 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()
+ 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] ||
+ devfail("%s must be passed to Resources" % param)
+ options.delete(param)
+ hash
+ end
+
+ @params = {}
+ tmpparams = nil
+ if tmpparams = options[:params]
+ options.delete(:params)
+ end
+
+ # Now set the rest of the options.
+ set_options(options)
+
+ @ref = Reference.new(refopts)
+
+ requiredopts(:scope, :source)
+
+ @ref.scope = self.scope
+
+ if tmpparams
+ tmpparams.each do |param|
+ # We use the method here, because it does type-checking.
+ set(param)
+ end
+ end
+ end
+
+ # Merge an override resource in.
+ def merge(resource)
+ # Some of these might fail, but they'll fail in the way we want.
+ resource.params.each do |name, param|
+ set(param)
+ 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)
+ # This defaults to true
+ unless Puppet[:paramcheck]
+ return
+ end
+
+ return if param == "name" or param == "title" # always allow these
+
+ # FIXME We might need to do more here eventually. Metaparams
+ # behave strangely on containers.
+ return if Puppet::Type.metaparam?(param)
+
+ # Now make sure it's a valid argument to our class.
+ unless @ref.typeclass.validattr?(param)
+ 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
+ end
+
+ # Return the short version of our name.
+ def ref
+ @ref.to_s
+ end
+
+ # You have to pass a Resource::Param to this.
+ def set(param)
+ # Because definitions are now parse-time, I can paramcheck immediately.
+ paramcheck(param.name)
+
+ if current = @params[param.name]
+ # XXX Should we ignore any settings that have the same values?
+ if param.source.child_of?(current.source)
+ # Replace it, keeping all of its info.
+ @params[param.name] = param
+ else
+ fail Puppet::ParseError, "Parameter %s is already set on %s by %s" %
+ [param.name, self.to_s, param.source]
+ 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
+
+ # Store our object as a Rails object. We need the host object we're storing it
+ # with.
+ def store(host)
+ args = {}
+ %w{type title tags file line exported}.each do |param|
+ if value = self.send(param)
+ args[param] = value
+ end
+ end
+
+ # 'type' isn't a valid column name, so we have to use something else.
+ args = symbolize_options(args)
+ args[:restype] = args[:type]
+ args.delete(:type)
+
+ # Let's see if the object exists
+ #if obj = host.rails_resources.find_by_type_and_title(self.type, self.title)
+ if obj = host.rails_resources.find_by_restype_and_title(self.type, self.title)
+ # We exist
+ args.each do |param, value|
+ obj[param] = value
+ end
+ else
+ # Else create it anew
+ obj = host.rails_resources.build(args)
+ end
+
+ # Either way, now add our parameters
+ @params.each do |name, param|
+ param.store(obj)
+ end
+
+ return obj
+ end
+
+ def tags
+ unless defined? @tags
+ @tags = scope.tags
+ @tags << self.type
+ end
+ @tags
+ end
+
+ def to_hash
+ @params.inject({}) do |hash, ary|
+ param = ary[1]
+ hash[param.name] = param.value
+ hash
+ end
+ end
+
+ def to_s
+ self.ref
+ end
+
+ # Translate our object to a transportable object.
+ def to_trans
+ unless builtin?
+ devfail "Tried to translate a non-builtin resource"
+ end
+
+ return nil if virtual?
+
+ # Now convert to a transobject
+ obj = Puppet::TransObject.new(@ref.title, @ref.type)
+ to_hash.each do |p, v|
+ if v.is_a?(Reference)
+ v = v.to_ref
+ elsif v.is_a?(Array)
+ v = v.collect { |av|
+ if av.is_a?(Reference)
+ av = av.to_ref
+ end
+ av
+ }
+ end
+ obj[p.to_s] = v
+ end
+
+ obj.file = self.file
+ obj.line = self.line
+
+ obj.tags = self.tags
+
+ return obj
+ end
+
+ def virtual?
+ self.virtual
+ end
+end
+
+# $Id$