diff options
-rw-r--r-- | lib/puppet/resource.rb | 107 | ||||
-rw-r--r-- | lib/puppet/resource_reference.rb | 10 | ||||
-rwxr-xr-x | spec/unit/resource.rb | 196 | ||||
-rwxr-xr-x | spec/unit/resource_reference.rb | 8 |
4 files changed, 316 insertions, 5 deletions
diff --git a/lib/puppet/resource.rb b/lib/puppet/resource.rb new file mode 100644 index 000000000..8dc09e521 --- /dev/null +++ b/lib/puppet/resource.rb @@ -0,0 +1,107 @@ +require 'puppet' +require 'puppet/util/tagging' +require 'puppet/resource_reference' + +# The simplest resource class. Eventually it will function as the +# base class for all resource-like behaviour. +class Puppet::Resource + include Puppet::Util::Tagging + include Enumerable + attr_accessor :type, :title, :file, :line, :catalog + + # Proxy these methods to the parameters hash. It's likely they'll + # be overridden at some point, but this works for now. + %w{has_key? length delete empty? <<}.each do |method| + define_method(method) do |*args| + @parameters.send(method, *args) + end + end + + # Set a given parameter. Converts all passed names + # to lower-case symbols. + def []=(param, value) + @parameters[parameter_name(param)] = value + end + + # Return a given parameter's value. Converts all passed names + # to lower-case symbols. + def [](param) + @parameters[parameter_name(param)] + end + + # Iterate over each param/value pair, as required for Enumerable. + def each + @parameters.each { |p,v| yield p, v } + end + + # Create our resource. + def initialize(type, title, parameters = {}) + @reference = Puppet::ResourceReference.new(type, title) + @parameters = {} + + parameters.each do |param, value| + self[param] = value + end + + tag(@reference.type) + tag(@reference.title) if valid_tag?(@reference.title) + end + + # Provide a reference to our resource in the canonical form. + def ref + @reference.to_s + end + + # Get our title information from the reference, since it will canonize it for us. + def title + @reference.title + end + + # Get our type information from the reference, since it will canonize it for us. + def type + @reference.type + end + + # Produce a simple hash of our parameters. + def to_hash + @parameters.dup + end + + def to_s + return ref + end + + # Convert our resource to Puppet code. + def to_manifest + "%s { '%s':\n%s\n}" % [self.type.to_s.downcase, self.title, + @parameters.collect { |p, v| + if v.is_a? Array + " #{p} => [\'#{v.join("','")}\']" + else + " #{p} => \'#{v}\'" + end + }.join(",\n") + ] + end + + def to_ref + ref + end + + # Convert our resource to a RAL resource instance. Creates component + # instances for resource types that don't exist. + def to_ral + if typeklass = Puppet::Type.type(self.type) + return typeklass.create(self) + else + return Puppet::Type::Component.create(self) + end + end + + private + + # Produce a canonical method name. + def parameter_name(param) + param.to_s.downcase.to_sym + end +end diff --git a/lib/puppet/resource_reference.rb b/lib/puppet/resource_reference.rb index 12b9f54a9..a3e0a7514 100644 --- a/lib/puppet/resource_reference.rb +++ b/lib/puppet/resource_reference.rb @@ -10,6 +10,10 @@ class Puppet::ResourceReference attr_reader :type attr_accessor :title, :catalog + def builtin_type? + builtin_type ? true : false + end + def initialize(type, title) # This will set @type if it looks like a resource reference. self.title = title @@ -54,16 +58,12 @@ class Puppet::ResourceReference private - def builtin_type? - builtin_type ? true : false - end - def builtin_type if @builtin_type.nil? if @type =~ /::/ @builtin_type = false elsif klass = Puppet::Type.type(@type.to_s.downcase) - @builtin_type = klass + @builtin_type = true else @builtin_type = false end diff --git a/spec/unit/resource.rb b/spec/unit/resource.rb new file mode 100755 index 000000000..9c936f0bb --- /dev/null +++ b/spec/unit/resource.rb @@ -0,0 +1,196 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../spec_helper' +require 'puppet/resource' + +describe Puppet::Resource do + [:catalog, :file, :line].each do |attr| + it "should have an #{attr} attribute" do + resource = Puppet::Resource.new("file", "/my/file") + resource.should respond_to(attr) + resource.should respond_to(attr.to_s + "=") + end + end + + describe "when initializing" do + it "should require the type and title" do + lambda { Puppet::Resource.new }.should raise_error(ArgumentError) + end + + it "should create a resource reference with its type and title" do + ref = Puppet::ResourceReference.new("file", "/f") + Puppet::ResourceReference.expects(:new).with("file", "/f").returns ref + Puppet::Resource.new("file", "/f") + end + + it "should allow setting of parameters" do + Puppet::Resource.new("file", "/f", :noop => true)[:noop].should be_true + end + + it "should tag itself with its type" do + Puppet::Resource.new("file", "/f").should be_tagged("file") + end + + it "should tag itself with its title if the title is a valid tag" do + Puppet::Resource.new("file", "bar").should be_tagged("bar") + end + + it "should not tag itself with its title if the title is a not valid tag" do + Puppet::Resource.new("file", "/bar").should_not be_tagged("/bar") + end + end + + it "should use the resource reference to determine its type" do + ref = Puppet::ResourceReference.new("file", "/f") + Puppet::ResourceReference.expects(:new).returns ref + resource = Puppet::Resource.new("file", "/f") + ref.expects(:type).returns "mytype" + resource.type.should == "mytype" + end + + it "should use its resource reference to determine its title" do + ref = Puppet::ResourceReference.new("file", "/f") + Puppet::ResourceReference.expects(:new).returns ref + resource = Puppet::Resource.new("file", "/f") + ref.expects(:title).returns "mytitle" + resource.title.should == "mytitle" + end + + it "should use its resource reference to produce its canonical reference string" do + ref = Puppet::ResourceReference.new("file", "/f") + Puppet::ResourceReference.expects(:new).returns ref + resource = Puppet::Resource.new("file", "/f") + ref.expects(:to_s).returns "Foo[bar]" + resource.ref.should == "Foo[bar]" + end + + it "should be taggable" do + Puppet::Resource.ancestors.should be_include(Puppet::Util::Tagging) + end + + describe "when managing parameters" do + before do + @resource = Puppet::Resource.new("file", "/my/file") + end + + it "should allow setting and retrieving of parameters" do + @resource[:foo] = "bar" + @resource[:foo].should == "bar" + end + + it "should canonicalize retrieved parameter names to treat symbols and strings equivalently" do + @resource[:foo] = "bar" + @resource["foo"].should == "bar" + end + + it "should canonicalize set parameter names to treat symbols and strings equivalently" do + @resource["foo"] = "bar" + @resource[:foo].should == "bar" + end + + it "should be able to iterate over parameters" do + @resource[:foo] = "bar" + @resource[:fee] = "bare" + params = {} + @resource.each do |key, value| + params[key] = value + end + params.should == {:foo => "bar", :fee => "bare"} + end + + it "should include Enumerable" do + @resource.class.ancestors.should be_include(Enumerable) + end + + it "should have a method for testing whether a parameter is included" do + @resource[:foo] = "bar" + @resource.should be_has_key(:foo) + @resource.should_not be_has_key(:eh) + end + + it "should have a method for providing the number of parameters" do + @resource[:foo] = "bar" + @resource.length.should == 1 + end + + it "should have a method for deleting parameters" do + @resource[:foo] = "bar" + @resource.delete(:foo) + @resource[:foo].should be_nil + end + + it "should have a method for testing whether the parameter list is empty" do + @resource.should be_empty + @resource[:foo] = "bar" + @resource.should_not be_empty + end + end + + describe "when serializing" do + before do + @resource = Puppet::Resource.new("file", "/my/file") + @resource["one"] = "test" + @resource["two"] = "other" + end + + it "should be able to be dumped to yaml" do + proc { YAML.dump(@resource) }.should_not raise_error + end + + it "should produce an equivalent yaml object" do + text = YAML.dump(@resource) + + newresource = YAML.load(text) + newresource.title.should == @resource.title + newresource.type.should == @resource.type + %w{one two}.each do |param| + newresource[param].should == @resource[param] + end + end + end + + describe "when converting to a RAL resource" do + before do + @resource = Puppet::Resource.new("file", "/my/file") + @resource["one"] = "test" + @resource["two"] = "other" + end + + it "should use the resource type's :create method to create the resource if the resource is of a builtin type" do + type = mock 'resource type' + type.expects(:create).with(@resource).returns(:myresource) + Puppet::Type.expects(:type).with(@resource.type).returns(type) + @resource.to_ral.should == :myresource + end + + it "should convert to a component instance if the resource type is not of a builtin type" do + component = mock 'component type' + Puppet::Type::Component.expects(:create).with(@resource).returns "meh" + + Puppet::Type.expects(:type).with(@resource.type).returns(nil) + @resource.to_ral.should == "meh" + end + end + + it "should be able to convert itself to Puppet code" do + Puppet::Resource.new("one::two", "/my/file").should respond_to(:to_manifest) + end + + describe "when converting to puppet code" do + before do + @resource = Puppet::Resource.new("one::two", "/my/file", :noop => true, :foo => %w{one two}) + end + + it "should print the type and title" do + @resource.to_manifest.should be_include("one::two { '/my/file':\n") + end + + it "should print each parameter, with the value single-quoted" do + @resource.to_manifest.should be_include(" noop => 'true'") + end + + it "should print array values appropriately" do + @resource.to_manifest.should be_include(" foo => ['one','two']") + end + end +end diff --git a/spec/unit/resource_reference.rb b/spec/unit/resource_reference.rb index ee71a5077..a81a8a0d1 100755 --- a/spec/unit/resource_reference.rb +++ b/spec/unit/resource_reference.rb @@ -46,6 +46,14 @@ describe Puppet::ResourceReference do ref.type.should == "Foo::Bar" ref.title.should =="baz[yay]" end + + it "should be considered builtin if an existing resource type matches the type" do + Puppet::ResourceReference.new("file", "/f").should be_builtin_type + end + + it "should be not considered builtin if an existing resource type does not match the type" do + Puppet::ResourceReference.new("foobar", "/f").should_not be_builtin_type + end end describe Puppet::ResourceReference, "when resolving resources with a catalog" do |