class Puppet::Resource::Type

Puppet::Resource::Type represents nodes, classes and defined types.

@api public

Constants

CALLER_MODULE_NAME
DOUBLE_COLON
EMPTY_ARRAY
KIND
MODULE_NAME
NAME
NODES
PARAMETERS
RESOURCE_EXTERNAL_NAMES_TO_KINDS
RESOURCE_KINDS
RESOURCE_KINDS_TO_EXTERNAL_NAMES

Map the names used in our documentation to the names used internally

TITLE

Attributes

argument_types[R]

Map from argument (aka parameter) names to Puppet Type @return [Hash<Symbol, Puppet::Pops::Types::PAnyType] map from name to type

arguments[R]
behaves_like[R]
code[RW]
doc[RW]
file[RW]
line[RW]
module_name[R]
namespace[R]
override[RW]
parent[RW]
resource_type_collection[RW]
type[R]

This should probably be renamed to 'kind' eventually, in accordance with the changes

made for serialization and API usability (#14137).  At the moment that seems like
it would touch a whole lot of places in the code, though.  --cprice 2012-04-23

Public Class Methods

new(type, name, options = {}) click to toggle source
    # File lib/puppet/resource/type.rb
 86 def initialize(type, name, options = {})
 87   @type = type.to_s.downcase.to_sym
 88   raise ArgumentError, _("Invalid resource supertype '%{type}'") % { type: type } unless RESOURCE_KINDS.include?(@type)
 89 
 90   name = convert_from_ast(name) if name.is_a?(Puppet::Parser::AST::HostName)
 91 
 92   set_name_and_namespace(name)
 93 
 94   [:code, :doc, :line, :file, :parent].each do |param|
 95     value = options[param]
 96     next unless value
 97     send(param.to_s + '=', value)
 98   end
 99 
100   set_arguments(options[:arguments])
101   set_argument_types(options[:argument_types])
102 
103   @match = nil
104 
105   @module_name = options[:module_name]
106 end

Public Instance Methods

child_of?(klass) click to toggle source

Are we a child of the passed class? Do a recursive search up our parentage tree to figure it out.

   # File lib/puppet/resource/type.rb
54 def child_of?(klass)
55   return true if override
56   return false unless parent
57 
58   return(klass == parent_type ? true : parent_type.child_of?(klass))
59 end
ensure_in_catalog(scope, parameters=nil) click to toggle source

Make an instance of the resource type, and place it in the catalog if it isn't in the catalog already. This is only possible for classes and nodes. No parameters are be supplied–if this is a parameterized class, then all parameters take on their default values.

    # File lib/puppet/resource/type.rb
154 def ensure_in_catalog(scope, parameters=nil)
155   resource_type =
156   case type
157   when :definition
158     raise ArgumentError, _('Cannot create resources for defined resource types')
159   when :hostclass
160     :class
161   when :node
162     :node
163   end
164 
165   # Do nothing if the resource already exists; this makes sure we don't
166   # get multiple copies of the class resource, which helps provide the
167   # singleton nature of classes.
168   # we should not do this for classes with parameters
169   # if parameters are passed, we should still try to create the resource
170   # even if it exists so that we can fail
171   # this prevents us from being able to combine param classes with include
172   if parameters.nil?
173     resource = scope.catalog.resource(resource_type, name)
174     return resource unless resource.nil?
175   elsif parameters.is_a?(Hash)
176     parameters = parameters.map {|k, v| Puppet::Parser::Resource::Param.new(:name => k, :value => v, :source => self)}
177   end
178   resource = Puppet::Parser::Resource.new(resource_type, name, :scope => scope, :source => self, :parameters => parameters)
179   instantiate_resource(scope, resource)
180   scope.compiler.add_resource(scope, resource)
181   resource
182 end
evaluate_code(resource) click to toggle source

Now evaluate the code associated with this class or definition.

   # File lib/puppet/resource/type.rb
62 def evaluate_code(resource)
63 
64   static_parent = evaluate_parent_type(resource)
65   scope = static_parent || resource.scope
66 
67   scope = scope.newscope(:source => self, :resource => resource) unless resource.title == :main
68   scope.compiler.add_class(name) unless definition?
69 
70   set_resource_parameters(resource, scope)
71 
72   resource.add_edge_to_stage
73 
74   if code
75     if @match # Only bother setting up the ephemeral scope if there are match variables to add into it
76       scope.with_guarded_scope do
77         scope.ephemeral_from(@match, file, line)
78         code.safeevaluate(scope)
79       end
80     else
81       code.safeevaluate(scope)
82     end
83   end
84 end
instantiate_resource(scope, resource) click to toggle source
    # File lib/puppet/resource/type.rb
184 def instantiate_resource(scope, resource)
185   # Make sure our parent class has been evaluated, if we have one.
186   if parent && !scope.catalog.resource(resource.type, parent)
187     parent_type(scope).ensure_in_catalog(scope)
188   end
189 
190   if ['Class', 'Node'].include? resource.type
191     scope.catalog.merge_tags_from(resource)
192   end
193 end
match(string) click to toggle source

This is only used for node names, and really only when the node name is a regexp.

    # File lib/puppet/resource/type.rb
110 def match(string)
111   return string.to_s.downcase == name unless name_is_regex?
112 
113   @match = @name.match(string)
114 end
merge(other) click to toggle source

Add code from a new instance to our code.

    # File lib/puppet/resource/type.rb
117 def merge(other)
118   fail _("%{name} is not a class; cannot add code to it") % { name: name } unless type == :hostclass
119   fail _("%{name} is not a class; cannot add code from it") % { name: other.name } unless other.type == :hostclass
120   if name == "" && Puppet.settings[:freeze_main]
121     # It is ok to merge definitions into main even if freeze is on (definitions are nodes, classes, defines, functions, and types)
122     unless other.code.is_definitions_only?
123       fail _("Cannot have code outside of a class/node/define because 'freeze_main' is enabled")
124     end
125   end
126   if parent and other.parent and parent != other.parent
127     fail _("Cannot merge classes with different parent classes (%{name} => %{parent} vs. %{other_name} => %{other_parent})") % { name: name, parent: parent, other_name: other.name, other_parent: other.parent }
128   end
129 
130   # We know they're either equal or only one is set, so keep whichever parent is specified.
131   self.parent ||= other.parent
132 
133   if other.doc
134     self.doc ||= ""
135     self.doc += other.doc
136   end
137 
138   # This might just be an empty, stub class.
139   return unless other.code
140 
141   unless self.code
142     self.code = other.code
143     return
144   end
145 
146   self.code = Puppet::Parser::ParserFactory.code_merger.concatenate([self, other])
147 end
name() click to toggle source
    # File lib/puppet/resource/type.rb
195 def name
196   if type == :node && name_is_regex?
197     "__node_regexp__#{@name.source.downcase.gsub(/[^-\w:.]/,'').sub(/^\.+/,'')}"
198   else
199     @name
200   end
201 end
name_is_regex?() click to toggle source
    # File lib/puppet/resource/type.rb
203 def name_is_regex?
204   @name.is_a?(Regexp)
205 end
parent_type(scope = nil) click to toggle source
    # File lib/puppet/resource/type.rb
207 def parent_type(scope = nil)
208   return nil unless parent
209 
210   @parent_type ||= scope.environment.known_resource_types.send("find_#{type}", parent) ||
211     fail(Puppet::ParseError, _("Could not find parent resource type '%{parent}' of type %{parent_type} in %{env}") % { parent: parent, parent_type: type, env: scope.environment })
212 end
set_argument_types(name_to_type_hash) click to toggle source

Sets the argument name to Puppet Type hash used for type checking. Names must correspond to available arguments (they must be defined first). Arguments not mentioned will not be type-checked.

    # File lib/puppet/resource/type.rb
330 def set_argument_types(name_to_type_hash)
331   @argument_types = {}
332   @parameter_struct = nil
333   return unless name_to_type_hash
334   name_to_type_hash.each do |name, t|
335     # catch internal errors
336     unless @arguments.include?(name)
337       raise Puppet::DevError, _("Parameter '%{name}' is given a type, but is not a valid parameter.") % { name: name }
338     end
339     unless t.is_a? Puppet::Pops::Types::PAnyType
340       raise Puppet::DevError, _("Parameter '%{name}' is given a type that is not a Puppet Type, got %{class_name}") % { name: name, class_name: t.class }
341     end
342     @argument_types[name] = t
343   end
344 end
set_arguments(arguments) click to toggle source
    # File lib/puppet/resource/type.rb
314 def set_arguments(arguments)
315   @arguments = {}
316   @parameter_struct = nil
317   return if arguments.nil?
318 
319   arguments.each do |arg, default|
320     arg = arg.to_s
321     warn_if_metaparam(arg, default)
322     @arguments[arg] = default
323   end
324 end
set_resource_parameters(resource, scope) click to toggle source

Validate and set any arguments passed by the resource as variables in the scope.

This method is known to only be used on the server/compile side.

@param resource [Puppet::Parser::Resource] the resource @param scope [Puppet::Parser::Scope] the scope

@api private

    # File lib/puppet/resource/type.rb
222 def set_resource_parameters(resource, scope)
223   # Inject parameters from using external lookup
224   modname = resource[:module_name] || module_name
225   scope[MODULE_NAME] = modname unless modname.nil?
226   caller_name = resource[:caller_module_name] || scope.parent_module_name
227   scope[CALLER_MODULE_NAME] = caller_name unless caller_name.nil?
228 
229   inject_external_parameters(resource, scope)
230 
231   if @type == :hostclass
232     scope[TITLE] = resource.title.to_s.downcase
233     scope[NAME] =  resource.name.to_s.downcase
234   else
235     scope[TITLE] = resource.title
236     scope[NAME] =  resource.name
237   end
238   scope.class_set(self.name,scope) if hostclass? || node?
239 
240   param_hash = scope.with_parameter_scope(resource.to_s, arguments.keys) do |param_scope|
241     # Assign directly to the parameter scope to avoid scope parameter validation at this point. It
242     # will happen anyway when the values are assigned to the scope after the parameter scoped has
243     # been popped.
244     resource.each { |k, v| param_scope[k.to_s] = v.value unless k == :name || k == :title }
245     assign_defaults(resource, param_scope, scope)
246     param_scope.to_hash
247   end
248 
249   validate_resource_hash(resource, param_hash)
250 
251   # Assign parameter values to current scope
252   param_hash.each { |param, value| exceptwrap { scope[param] = value }}
253 end
valid_parameter?(param) click to toggle source

Check whether a given argument is valid.

    # File lib/puppet/resource/type.rb
310 def valid_parameter?(param)
311   parameter_struct.hashed_elements.include?(param.to_s)
312 end
validate_resource(resource) click to toggle source

Validate that all parameters given to the resource are correct @param resource [Puppet::Resource] the resource to validate

    # File lib/puppet/resource/type.rb
297 def validate_resource(resource)
298   # Since Sensitive values have special encoding (in a separate parameter) an unwrapped sensitive value must be
299   # recreated as a Sensitive in order to perform correct type checking.
300   sensitives = Set.new(resource.sensitive_parameters)
301   validate_resource_hash(resource,
302     Hash[resource.parameters.map do |name, value|
303       value_to_validate = sensitives.include?(name) ? Puppet::Pops::Types::PSensitiveType::Sensitive.new(value.value) : value.value
304       [name.to_s, value_to_validate]
305     end
306   ])
307 end

Private Instance Methods

assign_defaults(resource, param_scope, scope) click to toggle source
    # File lib/puppet/resource/type.rb
275 def assign_defaults(resource, param_scope, scope)
276   return unless resource.is_a?(Puppet::Parser::Resource)
277   parameters = resource.parameters
278   arguments.each do |param_name, default|
279     next if default.nil?
280     name = param_name.to_sym
281     param = parameters[name]
282     next unless param.nil? || param.value.nil?
283     value = exceptwrap { param_scope.evaluate3x(param_name, default, scope) }
284     resource[name] = value
285     param_scope[param_name] = value
286   end
287 end
convert_from_ast(name) click to toggle source
    # File lib/puppet/resource/type.rb
348 def convert_from_ast(name)
349   value = name.value
350   if value.is_a?(Puppet::Parser::AST::Regex)
351     value.value
352   else
353     value
354   end
355 end
create_params_struct() click to toggle source
    # File lib/puppet/resource/type.rb
405 def create_params_struct
406   arg_types = argument_types
407   type_factory = Puppet::Pops::Types::TypeFactory
408   members = { type_factory.optional(type_factory.string(NAME)) =>  type_factory.any }
409 
410   Puppet::Type.eachmetaparam do |name|
411     # TODO: Once meta parameters are typed, this should change to reflect that type
412     members[name.to_s] = type_factory.any
413   end
414 
415   arguments.each_pair do |name, default|
416     key_type = type_factory.string(name.to_s)
417     key_type = type_factory.optional(key_type) unless default.nil?
418 
419     arg_type = arg_types[name]
420     arg_type = type_factory.any if arg_type.nil?
421     members[key_type] = arg_type
422   end
423   type_factory.struct(members)
424 end
evaluate_parent_type(resource) click to toggle source
    # File lib/puppet/resource/type.rb
357 def evaluate_parent_type(resource)
358   klass = parent_type(resource.scope)
359   parent_resource = resource.scope.compiler.catalog.resource(:class, klass.name) || resource.scope.compiler.catalog.resource(:node, klass.name) if klass
360   return unless klass && parent_resource
361   parent_resource.evaluate unless parent_resource.evaluated?
362   parent_scope(resource.scope, klass)
363 end
inject_external_parameters(resource, scope) click to toggle source

Lookup and inject parameters from external scope @param resource [Puppet::Parser::Resource] the resource @param scope [Puppet::Parser::Scope] the scope

    # File lib/puppet/resource/type.rb
258 def inject_external_parameters(resource, scope)
259   # Only lookup parameters for host classes
260   return unless type == :hostclass
261   parameters = resource.parameters
262   arguments.each do |param_name, default|
263     sym_name = param_name.to_sym
264     param = parameters[sym_name]
265     next unless param.nil? || param.value.nil?
266     catch(:no_such_key) do
267       bound_value = Puppet::Pops::Lookup.search_and_merge("#{name}::#{param_name}", Puppet::Pops::Lookup::Invocation.new(scope), nil)
268       # Assign bound value but don't let an undef trump a default expression
269       resource[sym_name] = bound_value unless bound_value.nil? && !default.nil?
270     end
271   end
272 end
namesplit(fullname) click to toggle source

Split an fq name into a namespace and name

    # File lib/puppet/resource/type.rb
366 def namesplit(fullname)
367   ary = fullname.split(DOUBLE_COLON)
368   n = ary.pop || ""
369   ns = ary.join(DOUBLE_COLON)
370   return ns, n
371 end
parameter_struct() click to toggle source
    # File lib/puppet/resource/type.rb
401 def parameter_struct
402   @parameter_struct ||= create_params_struct
403 end
parent_scope(scope, klass) click to toggle source
    # File lib/puppet/resource/type.rb
373 def parent_scope(scope, klass)
374   scope.class_scope(klass) || raise(Puppet::DevError, _("Could not find scope for %{class_name}") % { class_name: klass.name })
375 end
set_name_and_namespace(name) click to toggle source
    # File lib/puppet/resource/type.rb
377 def set_name_and_namespace(name)
378   if name.is_a?(Regexp)
379     @name = name
380     @namespace = ""
381   else
382     @name = name.to_s.downcase
383 
384     # Note we're doing something somewhat weird here -- we're setting
385     # the class's namespace to its fully qualified name.  This means
386     # anything inside that class starts looking in that namespace first.
387     @namespace, _ = @type == :hostclass ? [@name, ''] : namesplit(@name)
388   end
389 end
validate_resource_hash(resource, resource_hash) click to toggle source
    # File lib/puppet/resource/type.rb
290 def validate_resource_hash(resource, resource_hash)
291   Puppet::Pops::Types::TypeMismatchDescriber.validate_parameters(resource.to_s, parameter_struct, resource_hash, false)
292 end
warn_if_metaparam(param, default) click to toggle source
    # File lib/puppet/resource/type.rb
391 def warn_if_metaparam(param, default)
392   return unless Puppet::Type.metaparamclass(param)
393 
394   if default
395     warnonce _("%{param} is a metaparam; this value will inherit to all contained resources in the %{name} definition") % { param: param, name: self.name }
396   else
397     raise Puppet::ParseError, _("%{param} is a metaparameter; please choose another parameter name in the %{name} definition") % { param: param, name: self.name }
398   end
399 end