diff options
author | Paul Berry <paul@puppetlabs.com> | 2010-09-02 18:10:37 -0700 |
---|---|---|
committer | Paul Berry <paul@puppetlabs.com> | 2010-09-02 18:37:28 -0700 |
commit | 6b278503021c4404904f56ced6995d0fbfa5b8fe (patch) | |
tree | 134f89786a38137a89dc6e846920d9dfc57e59c3 /lib | |
parent | 25048ecc40db746f7e88bb6c5e1fc4f2c0150a4f (diff) | |
download | puppet-6b278503021c4404904f56ced6995d0fbfa5b8fe.tar.gz puppet-6b278503021c4404904f56ced6995d0fbfa5b8fe.tar.xz puppet-6b278503021c4404904f56ced6995d0fbfa5b8fe.zip |
[#4657] Customer-supplied .rb files are not compatible with multiple environments or staleness check
Changed the resource type API to create AST objects rather than
directly instantiating resource types. This allows the same code
paths to be used to handle the results of parsing both .pp and .rb
files. This makes .rb files work properly in multiple environments,
because the types are now instantiated by code that is aware of which
environment the compilation is happening in. It also reduces the risk
of future changes breaking .rb file support.
Also, switched to using "instance_eval" rather than "require" to
evaluate the contents of the .rb file. This ensures that if the file
has to be recompiled (because it became stale), it will actually get
re-evaluated. As a side benefit, ResourceTypeAPI is now a class
rather than a mixin to Object, so its methods do not pollute the
global namespace.
To reduce the risk of customers coming to rely on implementation
details of the resource type API, changed its methods to return nil,
and removed methods from it that were misleadingly labeled as
"private".
Diffstat (limited to 'lib')
-rw-r--r-- | lib/puppet/dsl.rb | 4 | ||||
-rw-r--r-- | lib/puppet/dsl/resource_type_api.rb | 48 | ||||
-rw-r--r-- | lib/puppet/parser/ast/definition.rb | 7 | ||||
-rw-r--r-- | lib/puppet/parser/ast/hostclass.rb | 7 | ||||
-rw-r--r-- | lib/puppet/parser/ast/node.rb | 7 | ||||
-rw-r--r-- | lib/puppet/parser/parser_support.rb | 11 |
6 files changed, 44 insertions, 40 deletions
diff --git a/lib/puppet/dsl.rb b/lib/puppet/dsl.rb index abdb78f67..97a310436 100644 --- a/lib/puppet/dsl.rb +++ b/lib/puppet/dsl.rb @@ -5,7 +5,3 @@ end require 'puppet/dsl/resource_type_api' require 'puppet/dsl/resource_api' - -class Object - include Puppet::DSL::ResourceTypeAPI -end diff --git a/lib/puppet/dsl/resource_type_api.rb b/lib/puppet/dsl/resource_type_api.rb index 487aab99d..8810d5368 100644 --- a/lib/puppet/dsl/resource_type_api.rb +++ b/lib/puppet/dsl/resource_type_api.rb @@ -1,34 +1,15 @@ require 'puppet/resource/type' -module Puppet::DSL::ResourceTypeAPI - def define(name, *args, &block) - result = mk_resource_type(:definition, name, Hash.new, block) - result.set_arguments(munge_type_arguments(args)) - result - end - - def hostclass(name, options = {}, &block) - mk_resource_type(:hostclass, name, options, block) - end - - def node(name, options = {}, &block) - mk_resource_type(:node, name, options, block) - end - - private - - def mk_resource_type(type, name, options, code) - klass = Puppet::Resource::Type.new(type, name, options) - - klass.ruby_code = code if code - - Puppet::Node::Environment.new.known_resource_types.add klass - - klass +# Type of the objects inside of which pure ruby manifest files are +# executed. Provides methods for creating defines, hostclasses, and +# nodes. +class Puppet::DSL::ResourceTypeAPI + def initialize + @__created_ast_objects__ = [] end - def munge_type_arguments(args) - args.inject([]) do |result, item| + def define(name, *args, &block) + args = args.inject([]) do |result, item| if item.is_a?(Hash) item.each { |p, v| result << [p, v] } else @@ -36,5 +17,18 @@ module Puppet::DSL::ResourceTypeAPI end result end + @__created_ast_objects__.push Puppet::Parser::AST::Definition.new(name, {:arguments => args}, &block) + nil + end + + def hostclass(name, options = {}, &block) + @__created_ast_objects__.push Puppet::Parser::AST::Hostclass.new(name, options, &block) + nil + end + + def node(name, options = {}, &block) + name = [name] unless name.is_a?(Array) + @__created_ast_objects__.push Puppet::Parser::AST::Node.new(name, options, &block) + nil end end diff --git a/lib/puppet/parser/ast/definition.rb b/lib/puppet/parser/ast/definition.rb index 09f52b519..985f8f286 100644 --- a/lib/puppet/parser/ast/definition.rb +++ b/lib/puppet/parser/ast/definition.rb @@ -1,12 +1,15 @@ require 'puppet/parser/ast/top_level_construct' class Puppet::Parser::AST::Definition < Puppet::Parser::AST::TopLevelConstruct - def initialize(name, context = {}) + def initialize(name, context = {}, &ruby_code) @name = name @context = context + @ruby_code = ruby_code end def instantiate(modname) - return [Puppet::Resource::Type.new(:definition, @name, @context.merge(:module_name => modname))] + new_definition = Puppet::Resource::Type.new(:definition, @name, @context.merge(:module_name => modname)) + new_definition.ruby_code = @ruby_code if @ruby_code + [new_definition] end end diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb index d539e4deb..cab5e4a24 100644 --- a/lib/puppet/parser/ast/hostclass.rb +++ b/lib/puppet/parser/ast/hostclass.rb @@ -3,13 +3,16 @@ require 'puppet/parser/ast/top_level_construct' class Puppet::Parser::AST::Hostclass < Puppet::Parser::AST::TopLevelConstruct attr_accessor :name, :context - def initialize(name, context = {}) + def initialize(name, context = {}, &ruby_code) @context = context @name = name + @ruby_code = ruby_code end def instantiate(modname) - all_types = [Puppet::Resource::Type.new(:hostclass, @name, @context.merge(:module_name => modname))] + new_class = Puppet::Resource::Type.new(:hostclass, @name, @context.merge(:module_name => modname)) + new_class.ruby_code = @ruby_code if @ruby_code + all_types = [new_class] if code code.each do |nested_ast_node| if nested_ast_node.respond_to? :instantiate diff --git a/lib/puppet/parser/ast/node.rb b/lib/puppet/parser/ast/node.rb index c19a24ce0..9767399f7 100644 --- a/lib/puppet/parser/ast/node.rb +++ b/lib/puppet/parser/ast/node.rb @@ -3,15 +3,18 @@ require 'puppet/parser/ast/top_level_construct' class Puppet::Parser::AST::Node < Puppet::Parser::AST::TopLevelConstruct attr_accessor :names - def initialize(names, context = {}) + def initialize(names, context = {}, &ruby_code) raise ArgumentError, "names should be an array" unless names.is_a? Array @names = names @context = context + @ruby_code = ruby_code end def instantiate(modname) @names.collect do |name| - Puppet::Resource::Type.new(:node, name, @context.merge(:module_name => modname)) + new_node = Puppet::Resource::Type.new(:node, name, @context.merge(:module_name => modname)) + new_node.ruby_code = @ruby_code if @ruby_code + new_node end end end diff --git a/lib/puppet/parser/parser_support.rb b/lib/puppet/parser/parser_support.rb index 859897a16..a9df33f8b 100644 --- a/lib/puppet/parser/parser_support.rb +++ b/lib/puppet/parser/parser_support.rb @@ -155,8 +155,7 @@ class Puppet::Parser::Parser # how should I do error handling here? def parse(string = nil) if self.file =~ /\.rb$/ - parse_ruby_file - main = nil + main = parse_ruby_file else self.string = string if string begin @@ -196,7 +195,13 @@ class Puppet::Parser::Parser end def parse_ruby_file - require self.file + # Execute the contents of the file inside its own "main" object so + # that it can call methods in the resource type API. + main_object = Puppet::DSL::ResourceTypeAPI.new + main_object.instance_eval(File.read(self.file)) + + # Then extract any types that were created. + Puppet::Parser::AST::ASTArray.new :children => main_object.instance_eval { @__created_ast_objects__ } end def string=(string) |