Skip to content

Commit fb2ffd6

Browse files
committed
(#8596) Detect resource alias conflicts when titles do not match
The introduction of composite namevars caused the resource title used in resource aliases to be set as an array, even when the resource only had one namevar. This would fail to conflict with non-alias entries in the resource table, which used a string for the title, even though the single element array contained the same string. Now, we flatten the key used in the resource table, so that single element arrays are represented as strings, and will properly conflict with resource titles. Paired-With: Jacob Helwig <jacob@puppetlabs.com>
1 parent c736162 commit fb2ffd6

File tree

2 files changed

+60
-10
lines changed

2 files changed

+60
-10
lines changed

lib/puppet/resource/catalog.rb

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def alias(resource, key)
9898
resource.ref =~ /^(.+)\[/
9999
class_name = $1 || resource.class.name
100100

101-
newref = [class_name, key]
101+
newref = [class_name, key].flatten
102102

103103
if key.is_a? String
104104
ref_string = "#{class_name}[#{key}]"
@@ -111,7 +111,10 @@ def alias(resource, key)
111111
# isn't sufficient.
112112
if existing = @resource_table[newref]
113113
return if existing == resource
114-
raise(ArgumentError, "Cannot alias #{resource.ref} to #{key.inspect}; resource #{newref.inspect} already exists")
114+
resource_definition = " at #{resource.file}:#{resource.line}" if resource.file and resource.line
115+
existing_definition = " at #{existing.file}:#{existing.line}" if existing.file and existing.line
116+
msg = "Cannot alias #{resource.ref} to #{key.inspect}#{resource_definition}; resource #{newref.inspect} already defined#{existing_definition}"
117+
raise ArgumentError, msg
115118
end
116119
@resource_table[newref] = resource
117120
@aliases[resource.ref] ||= []
@@ -377,7 +380,7 @@ def resource(type, title = nil)
377380
res = Puppet::Resource.new(nil, type)
378381
end
379382
title_key = [res.type, res.title.to_s]
380-
uniqueness_key = [res.type, res.uniqueness_key]
383+
uniqueness_key = [res.type, res.uniqueness_key].flatten
381384
@resource_table[title_key] || @resource_table[uniqueness_key]
382385
end
383386

spec/unit/resource/catalog_spec.rb

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -507,15 +507,15 @@ def mkresource(type, name)
507507
lambda { @catalog.alias(@one, "other") }.should_not raise_error
508508
end
509509

510-
it "should create aliases for resources isomorphic resources whose names do not match their titles" do
510+
it "should create aliases for isomorphic resources whose names do not match their titles" do
511511
resource = Puppet::Type::File.new(:title => "testing", :path => @basepath+"/something")
512512

513513
@catalog.add_resource(resource)
514514

515515
@catalog.resource(:file, @basepath+"/something").should equal(resource)
516516
end
517517

518-
it "should not create aliases for resources non-isomorphic resources whose names do not match their titles" do
518+
it "should not create aliases for non-isomorphic resources whose names do not match their titles" do
519519
resource = Puppet::Type.type(:exec).new(:title => "testing", :command => "echo", :path => %w{/bin /usr/bin /usr/local/bin})
520520

521521
@catalog.add_resource(resource)
@@ -531,11 +531,6 @@ def mkresource(type, name)
531531
@catalog.resource("notify", "other").should equal(@one)
532532
end
533533

534-
it "should ignore conflicting aliases that point to the aliased resource" do
535-
@catalog.alias(@one, "other")
536-
lambda { @catalog.alias(@one, "other") }.should_not raise_error
537-
end
538-
539534
it "should fail to add an alias if the aliased name already exists" do
540535
@catalog.add_resource @one
541536
proc { @catalog.alias @two, "one" }.should raise_error(ArgumentError)
@@ -589,6 +584,58 @@ def mkresource(type, name)
589584
@catalog.create_resource :file, args
590585
@catalog.resource("File[/yay]").should equal(resource)
591586
end
587+
588+
describe "when adding resources with multiple namevars" do
589+
before :each do
590+
Puppet::Type.newtype(:multiple) do
591+
newparam(:color, :namevar => true)
592+
newparam(:designation, :namevar => true)
593+
594+
def self.title_patterns
595+
[ [
596+
/^(\w+) (\w+)$/,
597+
[
598+
[:color, lambda{|x| x}],
599+
[:designation, lambda{|x| x}]
600+
]
601+
] ]
602+
end
603+
end
604+
end
605+
606+
it "should add an alias using the uniqueness key" do
607+
@resource = Puppet::Type.type(:multiple).new(:title => "some resource", :color => "red", :designation => "5")
608+
609+
@catalog.add_resource(@resource)
610+
@catalog.resource(:multiple, "some resource").must == @resource
611+
@catalog.resource("Multiple[some resource]").must == @resource
612+
@catalog.resource("Multiple[red 5]").must == @resource
613+
end
614+
615+
it "should conflict with a resource with the same uniqueness key" do
616+
@resource = Puppet::Type.type(:multiple).new(:title => "some resource", :color => "red", :designation => "5")
617+
@other = Puppet::Type.type(:multiple).new(:title => "another resource", :color => "red", :designation => "5")
618+
619+
@catalog.add_resource(@resource)
620+
expect { @catalog.add_resource(@other) }.to raise_error(ArgumentError, /Cannot alias Multiple\[another resource\] to \["red", "5"\].*resource \["Multiple", "red", "5"\] already defined/)
621+
end
622+
623+
it "should conflict when its uniqueness key matches another resource's title" do
624+
@resource = Puppet::Type.type(:file).new(:title => "/tmp/foo")
625+
@other = Puppet::Type.type(:file).new(:title => "another file", :path => "/tmp/foo")
626+
627+
@catalog.add_resource(@resource)
628+
expect { @catalog.add_resource(@other) }.to raise_error(ArgumentError, /Cannot alias File\[another file\] to \["\/tmp\/foo"\].*resource \["File", "\/tmp\/foo"\] already defined/)
629+
end
630+
631+
it "should conflict when its uniqueness key matches the uniqueness key derived from another resource's title" do
632+
@resource = Puppet::Type.type(:multiple).new(:title => "red leader")
633+
@other = Puppet::Type.type(:multiple).new(:title => "another resource", :color => "red", :designation => "leader")
634+
635+
@catalog.add_resource(@resource)
636+
expect { @catalog.add_resource(@other) }.to raise_error(ArgumentError, /Cannot alias Multiple\[another resource\] to \["red", "leader"\].*resource \["Multiple", "red", "leader"\] already defined/)
637+
end
638+
end
592639
end
593640

594641
describe "when applying" do

0 commit comments

Comments
 (0)