summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/puppet/resource.rb107
-rw-r--r--lib/puppet/resource_reference.rb10
-rwxr-xr-xspec/unit/resource.rb196
-rwxr-xr-xspec/unit/resource_reference.rb8
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