The uniqueness_key method of a type or resource object should return a
key that can be used to identify this resource. In fact puppet seldomly
uses this method and instead uses resource[:name] as an identifier.

While this is totally fine for resourcetypes with a single
key_attribute (and resource[:name] returning the namevar), it breaks
things as soon as one creates a type with a composite key (prefetching
for example is broken). To ease the process of replacing calls to
resource[:name] to resource.uniqueness_key, the method uniqueness_key now
just returns name_var if there is only one key_attribute (immitating
self[:name]) and only returns an array of all the values of all the
key_attributes if we have more than one key_attribute.

The resourcehash which is passed to providers in their prefetch method
is now build with uniqueness_key as the hashkey. Because of the new
behaviour of uniqueness_key we hopefully wont break existing providers
while allowing new providers for types with composite keys to implement
correct prefetch methods.

Signed-off-by: Stefan Schulte <[email protected]>
---
 lib/puppet/resource.rb     |    9 +++++++--
 lib/puppet/transaction.rb  |    2 +-
 lib/puppet/type.rb         |    8 +++++++-
 spec/unit/resource_spec.rb |   11 +++++++++--
 4 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/lib/puppet/resource.rb b/lib/puppet/resource.rb
index 4f0d507..a527968 100644
--- a/lib/puppet/resource.rb
+++ b/lib/puppet/resource.rb
@@ -237,11 +237,16 @@ class Puppet::Resource
     h = self.to_hash
     h[namevar] ||= h[:name]
     h[:name]   ||= h[namevar]
-    h.values_at(*key_attributes.sort_by { |k| k.to_s })
+    # Simulate the same behaviour like Type#uniqueness_key
+    if key_attributes.size == 1
+      h[namevar]
+    else
+      h.values_at(*key_attributes)
+    end
   end
 
   def key_attributes
-    return(resource_type.respond_to? :key_attributes) ? 
resource_type.key_attributes : [:name]
+    resource_type.respond_to?(:key_attributes) ? resource_type.key_attributes 
: [:name]
   end
 
   # Convert our resource to Puppet code.
diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb
index dcd9aad..0bb98f8 100644
--- a/lib/puppet/transaction.rb
+++ b/lib/puppet/transaction.rb
@@ -252,7 +252,7 @@ class Puppet::Transaction
     @catalog.vertices.each do |resource|
       if provider = resource.provider and provider.class.respond_to?(:prefetch)
         prefetchers[provider.class] ||= {}
-        prefetchers[provider.class][resource.name] = resource
+        prefetchers[provider.class][resource.uniqueness_key] = resource
       end
     end
 
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index 1b6e7dc..c50f8de 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -200,7 +200,13 @@ class Type
   end
 
   def uniqueness_key
-    to_resource.uniqueness_key
+    # If we have only one namevar use that one (res.uniqueness_key behaves
+    # like res[:name] in that case). Otherwise use an array of all 
keyattributes
+    if name_var
+      self[:name]
+    else
+      @parameters.values_at(*self.class.key_attributes).collect {|p| p.value }
+    end
   end
 
   # Create a new parameter.  Requires a block and a name, stores it in the
diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb
index e65e8a1..092ae8c 100755
--- a/spec/unit/resource_spec.rb
+++ b/spec/unit/resource_spec.rb
@@ -268,7 +268,7 @@ describe Puppet::Resource do
   describe "when referring to a resource with name canonicalization" do
     it "should canonicalize its own name" do
       res = Puppet::Resource.new("file", "/path/")
-      res.uniqueness_key.should == ["/path"]
+      res.uniqueness_key.should == "/path"
       res.ref.should == "File[/path/]"
     end
   end
@@ -770,7 +770,14 @@ describe Puppet::Resource do
   end
 
   describe "when generating the uniqueness key" do
-    it "should include all of the key_attributes in alphabetical order by 
attribute name" do
+
+    it "should use namevar if there is only one key_attribute" do
+      Puppet::Type.type(:file).stubs(:key_attributes).returns [:path]
+      res = Puppet::Resource.new("file", "/my/file", :parameters => {:owner => 
'root', :content => 'hello'})
+      res.uniqueness_key.should == '/my/file'
+    end
+
+    it "should include all of the key_attributes" do
       Puppet::Type.type(:file).stubs(:key_attributes).returns [:myvar, :owner, 
:path]
       Puppet::Type.type(:file).stubs(:title_patterns).returns(
         [ [ /(.*)/, [ [:path, lambda{|x| x} ] ] ] ]
-- 
1.7.3.4

-- 
You received this message because you are subscribed to the Google Groups 
"Puppet Developers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/puppet-dev?hl=en.

Reply via email to