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
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
# File lib/puppet/resource/type.rb 85 def initialize(type, name, options = {}) 86 @type = type.to_s.downcase.to_sym 87 raise ArgumentError, _("Invalid resource supertype '%{type}'") % { type: type } unless RESOURCE_KINDS.include?(@type) 88 89 name = convert_from_ast(name) if name.is_a?(Puppet::Parser::AST::HostName) 90 91 set_name_and_namespace(name) 92 93 [:code, :doc, :line, :file, :parent].each do |param| 94 value = options[param] 95 next unless value 96 send(param.to_s + '=', value) 97 end 98 99 set_arguments(options[:arguments]) 100 set_argument_types(options[:argument_types]) 101 102 @match = nil 103 104 @module_name = options[:module_name] 105 end
Public Instance Methods
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 53 def child_of?(klass) 54 return true if override 55 return false unless parent 56 57 return(klass == parent_type ? true : parent_type.child_of?(klass)) 58 end
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 153 def ensure_in_catalog(scope, parameters=nil) 154 resource_type = 155 case type 156 when :definition 157 raise ArgumentError, _('Cannot create resources for defined resource types') 158 when :hostclass 159 :class 160 when :node 161 :node 162 end 163 164 # Do nothing if the resource already exists; this makes sure we don't 165 # get multiple copies of the class resource, which helps provide the 166 # singleton nature of classes. 167 # we should not do this for classes with parameters 168 # if parameters are passed, we should still try to create the resource 169 # even if it exists so that we can fail 170 # this prevents us from being able to combine param classes with include 171 if parameters.nil? 172 resource = scope.catalog.resource(resource_type, name) 173 return resource unless resource.nil? 174 elsif parameters.is_a?(Hash) 175 parameters = parameters.map {|k, v| Puppet::Parser::Resource::Param.new(:name => k, :value => v, :source => self)} 176 end 177 resource = Puppet::Parser::Resource.new(resource_type, name, :scope => scope, :source => self, :parameters => parameters) 178 instantiate_resource(scope, resource) 179 scope.compiler.add_resource(scope, resource) 180 resource 181 end
Now evaluate the code associated with this class or definition.
# File lib/puppet/resource/type.rb 61 def evaluate_code(resource) 62 63 static_parent = evaluate_parent_type(resource) 64 scope = static_parent || resource.scope 65 66 scope = scope.newscope(:source => self, :resource => resource) unless resource.title == :main 67 scope.compiler.add_class(name) unless definition? 68 69 set_resource_parameters(resource, scope) 70 71 resource.add_edge_to_stage 72 73 if code 74 if @match # Only bother setting up the ephemeral scope if there are match variables to add into it 75 scope.with_guarded_scope do 76 scope.ephemeral_from(@match, file, line) 77 code.safeevaluate(scope) 78 end 79 else 80 code.safeevaluate(scope) 81 end 82 end 83 end
# File lib/puppet/resource/type.rb 183 def instantiate_resource(scope, resource) 184 # Make sure our parent class has been evaluated, if we have one. 185 if parent && !scope.catalog.resource(resource.type, parent) 186 parent_type(scope).ensure_in_catalog(scope) 187 end 188 189 if ['Class', 'Node'].include? resource.type 190 scope.catalog.merge_tags_from(resource) 191 end 192 end
This is only used for node names, and really only when the node name is a regexp.
# File lib/puppet/resource/type.rb 109 def match(string) 110 return string.to_s.downcase == name unless name_is_regex? 111 112 @match = @name.match(string) 113 end
Add code from a new instance to our code.
# File lib/puppet/resource/type.rb 116 def merge(other) 117 fail _("%{name} is not a class; cannot add code to it") % { name: name } unless type == :hostclass 118 fail _("%{name} is not a class; cannot add code from it") % { name: other.name } unless other.type == :hostclass 119 if name == "" && Puppet.settings[:freeze_main] 120 # It is ok to merge definitions into main even if freeze is on (definitions are nodes, classes, defines, functions, and types) 121 unless other.code.is_definitions_only? 122 fail _("Cannot have code outside of a class/node/define because 'freeze_main' is enabled") 123 end 124 end 125 if parent and other.parent and parent != other.parent 126 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 } 127 end 128 129 # We know they're either equal or only one is set, so keep whichever parent is specified. 130 self.parent ||= other.parent 131 132 if other.doc 133 self.doc ||= "" 134 self.doc += other.doc 135 end 136 137 # This might just be an empty, stub class. 138 return unless other.code 139 140 unless self.code 141 self.code = other.code 142 return 143 end 144 145 self.code = Puppet::Parser::ParserFactory.code_merger.concatenate([self, other]) 146 end
# File lib/puppet/resource/type.rb 194 def name 195 if type == :node && name_is_regex? 196 "__node_regexp__#{@name.source.downcase.gsub(/[^-\w:.]/,'').sub(/^\.+/,'')}" 197 else 198 @name 199 end 200 end
# File lib/puppet/resource/type.rb 202 def name_is_regex? 203 @name.is_a?(Regexp) 204 end
# File lib/puppet/resource/type.rb 206 def parent_type(scope = nil) 207 return nil unless parent 208 209 @parent_type ||= scope.environment.known_resource_types.send("find_#{type}", parent) || 210 fail(Puppet::ParseError, _("Could not find parent resource type '%{parent}' of type %{parent_type} in %{env}") % { parent: parent, parent_type: type, env: scope.environment }) 211 end
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 329 def set_argument_types(name_to_type_hash) 330 @argument_types = {} 331 @parameter_struct = nil 332 return unless name_to_type_hash 333 name_to_type_hash.each do |name, t| 334 # catch internal errors 335 unless @arguments.include?(name) 336 raise Puppet::DevError, _("Parameter '%{name}' is given a type, but is not a valid parameter.") % { name: name } 337 end 338 unless t.is_a? Puppet::Pops::Types::PAnyType 339 raise Puppet::DevError, _("Parameter '%{name}' is given a type that is not a Puppet Type, got %{class_name}") % { name: name, class_name: t.class } 340 end 341 @argument_types[name] = t 342 end 343 end
# File lib/puppet/resource/type.rb 313 def set_arguments(arguments) 314 @arguments = {} 315 @parameter_struct = nil 316 return if arguments.nil? 317 318 arguments.each do |arg, default| 319 arg = arg.to_s 320 warn_if_metaparam(arg, default) 321 @arguments[arg] = default 322 end 323 end
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 221 def set_resource_parameters(resource, scope) 222 # Inject parameters from using external lookup 223 modname = resource[:module_name] || module_name 224 scope[MODULE_NAME] = modname unless modname.nil? 225 caller_name = resource[:caller_module_name] || scope.parent_module_name 226 scope[CALLER_MODULE_NAME] = caller_name unless caller_name.nil? 227 228 inject_external_parameters(resource, scope) 229 230 if @type == :hostclass 231 scope[TITLE] = resource.title.to_s.downcase 232 scope[NAME] = resource.name.to_s.downcase 233 else 234 scope[TITLE] = resource.title 235 scope[NAME] = resource.name 236 end 237 scope.class_set(self.name,scope) if hostclass? || node? 238 239 param_hash = scope.with_parameter_scope(resource.to_s, arguments.keys) do |param_scope| 240 # Assign directly to the parameter scope to avoid scope parameter validation at this point. It 241 # will happen anyway when the values are assigned to the scope after the parameter scoped has 242 # been popped. 243 resource.each { |k, v| param_scope[k.to_s] = v.value unless k == :name || k == :title } 244 assign_defaults(resource, param_scope, scope) 245 param_scope.to_hash 246 end 247 248 validate_resource_hash(resource, param_hash) 249 250 # Assign parameter values to current scope 251 param_hash.each { |param, value| exceptwrap { scope[param] = value }} 252 end
Check whether a given argument is valid.
# File lib/puppet/resource/type.rb 309 def valid_parameter?(param) 310 parameter_struct.hashed_elements.include?(param.to_s) 311 end
Validate that all parameters given to the resource are correct @param resource [Puppet::Resource] the resource to validate
# File lib/puppet/resource/type.rb 296 def validate_resource(resource) 297 # Since Sensitive values have special encoding (in a separate parameter) an unwrapped sensitive value must be 298 # recreated as a Sensitive in order to perform correct type checking. 299 sensitives = Set.new(resource.sensitive_parameters) 300 validate_resource_hash(resource, 301 Hash[resource.parameters.map do |name, value| 302 value_to_validate = sensitives.include?(name) ? Puppet::Pops::Types::PSensitiveType::Sensitive.new(value.value) : value.value 303 [name.to_s, value_to_validate] 304 end 305 ]) 306 end
Private Instance Methods
# File lib/puppet/resource/type.rb 274 def assign_defaults(resource, param_scope, scope) 275 return unless resource.is_a?(Puppet::Parser::Resource) 276 parameters = resource.parameters 277 arguments.each do |param_name, default| 278 next if default.nil? 279 name = param_name.to_sym 280 param = parameters[name] 281 next unless param.nil? || param.value.nil? 282 value = exceptwrap { param_scope.evaluate3x(param_name, default, scope) } 283 resource[name] = value 284 param_scope[param_name] = value 285 end 286 end
# File lib/puppet/resource/type.rb 347 def convert_from_ast(name) 348 value = name.value 349 if value.is_a?(Puppet::Parser::AST::Regex) 350 value.value 351 else 352 value 353 end 354 end
# File lib/puppet/resource/type.rb 404 def create_params_struct 405 arg_types = argument_types 406 type_factory = Puppet::Pops::Types::TypeFactory 407 members = { type_factory.optional(type_factory.string(NAME)) => type_factory.any } 408 409 Puppet::Type.eachmetaparam do |name| 410 # TODO: Once meta parameters are typed, this should change to reflect that type 411 members[name.to_s] = type_factory.any 412 end 413 414 arguments.each_pair do |name, default| 415 key_type = type_factory.string(name.to_s) 416 key_type = type_factory.optional(key_type) unless default.nil? 417 418 arg_type = arg_types[name] 419 arg_type = type_factory.any if arg_type.nil? 420 members[key_type] = arg_type 421 end 422 type_factory.struct(members) 423 end
# File lib/puppet/resource/type.rb 356 def evaluate_parent_type(resource) 357 klass = parent_type(resource.scope) 358 parent_resource = resource.scope.compiler.catalog.resource(:class, klass.name) || resource.scope.compiler.catalog.resource(:node, klass.name) if klass 359 return unless klass && parent_resource 360 parent_resource.evaluate unless parent_resource.evaluated? 361 parent_scope(resource.scope, klass) 362 end
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 257 def inject_external_parameters(resource, scope) 258 # Only lookup parameters for host classes 259 return unless type == :hostclass 260 parameters = resource.parameters 261 arguments.each do |param_name, default| 262 sym_name = param_name.to_sym 263 param = parameters[sym_name] 264 next unless param.nil? || param.value.nil? 265 catch(:no_such_key) do 266 bound_value = Puppet::Pops::Lookup.search_and_merge("#{name}::#{param_name}", Puppet::Pops::Lookup::Invocation.new(scope), nil) 267 # Assign bound value but don't let an undef trump a default expression 268 resource[sym_name] = bound_value unless bound_value.nil? && !default.nil? 269 end 270 end 271 end
Split an fq name into a namespace and name
# File lib/puppet/resource/type.rb 365 def namesplit(fullname) 366 ary = fullname.split(DOUBLE_COLON) 367 n = ary.pop || "" 368 ns = ary.join(DOUBLE_COLON) 369 return ns, n 370 end
# File lib/puppet/resource/type.rb 400 def parameter_struct 401 @parameter_struct ||= create_params_struct 402 end
# File lib/puppet/resource/type.rb 372 def parent_scope(scope, klass) 373 scope.class_scope(klass) || raise(Puppet::DevError, _("Could not find scope for %{class_name}") % { class_name: klass.name }) 374 end
# File lib/puppet/resource/type.rb 376 def set_name_and_namespace(name) 377 if name.is_a?(Regexp) 378 @name = name 379 @namespace = "" 380 else 381 @name = name.to_s.downcase 382 383 # Note we're doing something somewhat weird here -- we're setting 384 # the class's namespace to its fully qualified name. This means 385 # anything inside that class starts looking in that namespace first. 386 @namespace, _ = @type == :hostclass ? [@name, ''] : namesplit(@name) 387 end 388 end
# File lib/puppet/resource/type.rb 289 def validate_resource_hash(resource, resource_hash) 290 Puppet::Pops::Types::TypeMismatchDescriber.validate_parameters(resource.to_s, parameter_struct, resource_hash, false) 291 end
# File lib/puppet/resource/type.rb 390 def warn_if_metaparam(param, default) 391 return unless Puppet::Type.metaparamclass(param) 392 393 if default 394 warnonce _("%{param} is a metaparam; this value will inherit to all contained resources in the %{name} definition") % { param: param, name: self.name } 395 else 396 raise Puppet::ParseError, _("%{param} is a metaparameter; please choose another parameter name in the %{name} definition") % { param: param, name: self.name } 397 end 398 end