[Pkg-puppet-devel] [SCM] Puppet packaging for Debian branch, experimental, updated. debian/2.6.8-1-844-g7ec39d5

Dan Bode bodepd at gmail.com
Tue May 10 08:06:13 UTC 2011


The following commit has been merged in the experimental branch:
commit 49059568d0e4e00bbc35d6f9b2a6cd23e7d00f46
Author: Dan Bode <bodepd at gmail.com>
Date:   Wed Mar 16 14:26:04 2011 -0500

    (5909) Function to dyncamically generate resources.
    
    This function allows you to dynamically generate resources,
    passing them as a hash to the create_resources function.
    
    This was originally written to be used together with an ENC.
    
    Resources can be programitally generated as yaml and passed to a class.
    
    classes:
      webserver::instances:
        instances:
          instance1:
            foo: bar
          instance2:
            foo: blah
    
    Then puppet code can consume the hash parameters and convert then into resources
    
    class webserver::instances (
      $instances = {}
    ) {
      create_resources('webserver::instance', $instances)
    }
    
    Now I can dynamically determine how webserver instances are deployed to nodes
    by updating the YAML files.

diff --git a/lib/puppet/parser/functions/create_resources.rb b/lib/puppet/parser/functions/create_resources.rb
new file mode 100644
index 0000000..430f110
--- /dev/null
+++ b/lib/puppet/parser/functions/create_resources.rb
@@ -0,0 +1,47 @@
+Puppet::Parser::Functions::newfunction(:create_resources, :doc => '
+Converts a hash into a set of resources and adds them to the catalog.
+Takes two parameters:
+  create_resource($type, $resources)
+    Creates resources of type $type from the $resources hash. Assumes that
+    hash is in the following form:
+     {title=>{parameters}}
+  This is currently tested for defined resources, classes, as well as native types
+') do |args|
+  raise ArgumentError, ("create_resources(): wrong number of arguments (#{args.length}; must be 2)") if args.length != 2
+  #raise ArgumentError, 'requires resource type and param hash' if args.size < 2
+  # figure out what kind of resource we are
+  type_of_resource = nil
+  type_name = args[0].downcase
+  if type_name == 'class'
+    type_of_resource = :class
+  else
+    if resource = Puppet::Type.type(type_name.to_sym)
+      type_of_resource = :type
+    elsif resource = find_definition(type_name.downcase)
+      type_of_resource = :define
+    else 
+      raise ArgumentError, "could not create resource of unknown type #{type_name}"
+    end
+  end
+  # iterate through the resources to create
+  args[1].each do |title, params|
+    raise ArgumentError, 'params should not contain title' if(params['title'])
+    case type_of_resource
+    when :type
+      res = resource.hash2resource(params.merge(:title => title))
+      catalog.add_resource(res)
+    when :define
+      p_resource = Puppet::Parser::Resource.new(type_name, title, :scope => self, :source => resource)
+      params.merge(:name => title).each do |k,v|
+        p_resource.set_parameter(k,v)
+      end
+      resource.instantiate_resource(self, p_resource)
+      compiler.add_resource(self, p_resource)
+    when :class
+      klass = find_hostclass(title)
+      raise ArgumentError, "could not find hostclass #{title}" unless klass
+      klass.ensure_in_catalog(self, params)
+      compiler.catalog.add_class([title])
+    end
+  end
+end
diff --git a/spec/unit/parser/functions/create_resources_spec.rb b/spec/unit/parser/functions/create_resources_spec.rb
new file mode 100755
index 0000000..d4095b7
--- /dev/null
+++ b/spec/unit/parser/functions/create_resources_spec.rb
@@ -0,0 +1,135 @@
+require 'puppet'
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+describe 'function for dynamically creating resources' do
+
+  def get_scope
+    @topscope = Puppet::Parser::Scope.new
+    # This is necessary so we don't try to use the compiler to discover our parent.
+    @topscope.parent = nil
+    @scope = Puppet::Parser::Scope.new
+    @scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => 'production'))
+    @scope.parent = @topscope
+    @compiler = @scope.compiler
+  end
+  before :each do
+    get_scope
+    Puppet::Parser::Functions.function(:create_resources)
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function(:create_resources).should == "function_create_resources"
+  end
+  it 'should require two arguments' do
+    lambda { @scope.function_create_resources(['foo']) }.should raise_error(ArgumentError, 'create_resources(): wrong number of arguments (1; must be 2)')
+  end
+  describe 'when creating native types' do
+    before :each do
+      Puppet[:code]='notify{test:}'
+      get_scope
+      @scope.resource=Puppet::Parser::Resource.new('class', 't', :scope => @scope)
+    end
+    it 'empty hash should not cause resources to be added' do
+      @scope.function_create_resources(['file', {}])
+      @compiler.catalog.resources.size == 1
+    end
+    it 'should be able to add' do
+      @scope.function_create_resources(['file', {'/etc/foo'=>{'ensure'=>'present'}}])
+      @compiler.catalog.resource(:file, "/etc/foo")['ensure'].should == 'present'
+    end
+    it 'should accept multiple types' do
+      type_hash = {}
+      type_hash['foo'] = {'message' => 'one'}
+      type_hash['bar'] = {'message' => 'two'}
+      @scope.function_create_resources(['notify', type_hash])
+      @compiler.catalog.resource(:notify, "foo")['message'].should == 'one'
+      @compiler.catalog.resource(:notify, "bar")['message'].should == 'two'
+    end
+    it 'should fail to add non-existing type' do
+      lambda { @scope.function_create_resources(['foo', {}]) }.should raise_error(ArgumentError, 'could not create resource of unknown type foo')
+    end
+    it 'should be able to add edges' do
+      @scope.function_create_resources(['notify', {'foo'=>{'require' => 'Notify[test]'}}])
+      @scope.compiler.compile
+      edge = @scope.compiler.catalog.to_ral.relationship_graph.edges.detect do |edge|
+        edge.source.title == 'test'
+      end
+      edge.source.title.should == 'test'
+      edge.target.title.should == 'foo'
+    end
+  end
+  describe 'when dynamically creating resource types' do
+    before :each do 
+      Puppet[:code]=
+'define foo($one){notify{$name: message => $one}}
+notify{test:}
+'
+      get_scope
+      @scope.resource=Puppet::Parser::Resource.new('class', 't', :scope => @scope)
+      Puppet::Parser::Functions.function(:create_resources)
+    end
+    it 'should be able to create defined resoure types' do
+      @scope.function_create_resources(['foo', {'blah'=>{'one'=>'two'}}])
+      # still have to compile for this to work...
+      # I am not sure if this constraint ruins the tests
+      @scope.compiler.compile
+      @compiler.catalog.resource(:notify, "blah")['message'].should == 'two'
+    end
+    it 'should fail if defines are missing params' do
+      @scope.function_create_resources(['foo', {'blah'=>{}}])
+      lambda { @scope.compiler.compile }.should raise_error(Puppet::ParseError, 'Must pass one to Foo[blah] at line 1')
+    end
+    it 'should be able to add multiple defines' do
+      hash = {}
+      hash['blah'] = {'one' => 'two'}
+      hash['blaz'] = {'one' => 'three'}
+      @scope.function_create_resources(['foo', hash])
+      # still have to compile for this to work...
+      # I am not sure if this constraint ruins the tests
+      @scope.compiler.compile
+      @compiler.catalog.resource(:notify, "blah")['message'].should == 'two'
+      @compiler.catalog.resource(:notify, "blaz")['message'].should == 'three'
+    end
+    it 'should be able to add edges' do
+      @scope.function_create_resources(['foo', {'blah'=>{'one'=>'two', 'require' => 'Notify[test]'}}])
+      @scope.compiler.compile
+      edge = @scope.compiler.catalog.to_ral.relationship_graph.edges.detect do |edge|
+        edge.source.title == 'test'
+      end
+      edge.source.title.should == 'test'
+      edge.target.title.should == 'blah'
+      @compiler.catalog.resource(:notify, "blah")['message'].should == 'two'
+    end
+  end
+  describe 'when creating classes' do
+    before :each do
+      Puppet[:code]=
+'class bar($one){notify{test: message => $one}}
+notify{tester:}
+'
+      get_scope
+      @scope.resource=Puppet::Parser::Resource.new('class', 't', :scope => @scope)
+      Puppet::Parser::Functions.function(:create_resources)
+    end
+    it 'should be able to create classes' do
+      @scope.function_create_resources(['class', {'bar'=>{'one'=>'two'}}])
+      @scope.compiler.compile
+      @compiler.catalog.resource(:notify, "test")['message'].should == 'two'
+      @compiler.catalog.resource(:class, "bar").should_not be_nil#['message'].should == 'two'
+    end
+    it 'should fail to create non-existing classes' do
+      lambda { @scope.function_create_resources(['class', {'blah'=>{'one'=>'two'}}]) }.should raise_error(ArgumentError ,'could not find hostclass blah')
+    end
+    it 'should be able to add edges' do
+      @scope.function_create_resources(['class', {'bar'=>{'one'=>'two', 'require' => 'Notify[tester]'}}])
+      @scope.compiler.compile
+      edge = @scope.compiler.catalog.to_ral.relationship_graph.edges.detect do |e|
+        e.source.title == 'tester'
+      end
+      edge.source.title.should == 'tester'
+      edge.target.title.should == 'test'
+      #@compiler.catalog.resource(:notify, "blah")['message'].should == 'two'
+    end
+
+  end
+end

-- 
Puppet packaging for Debian



More information about the Pkg-puppet-devel mailing list