diff options
author | Ben Somers <somers.ben@gmail.com> | 2013-05-14 11:25:07 -0700 |
---|---|---|
committer | Ben Somers <somers.ben@gmail.com> | 2013-05-14 11:25:07 -0700 |
commit | 437ca9a3ba08f3b4288303db1d1ed7c53b452ffb (patch) | |
tree | 7d66a19c9e2e9e5b0b0f123d0d7ca15c6d865ae7 | |
parent | cba4cccb2d12283f8e39a23bc92c8e925f3ec8ee (diff) | |
download | chef-437ca9a3ba08f3b4288303db1d1ed7c53b452ffb.tar.gz |
Enabling storage of roles in subdirectories
Storing roles in subdirectories is already effectively enabled
for Hosted Chef, as the directory structure gets flattened when
they are uploaded. But it is not currently possible with Chef-Solo;
one has to flatten the directory manually before running Chef-Solo.
This patch changes that behavior, and enables Chef-Solo with roles
in subdirectories.
-rw-r--r-- | lib/chef/role.rb | 15 | ||||
-rw-r--r-- | spec/unit/role_spec.rb | 31 |
2 files changed, 31 insertions, 15 deletions
diff --git a/lib/chef/role.rb b/lib/chef/role.rb index 78bbfadb88..a7e3f657a7 100644 --- a/lib/chef/role.rb +++ b/lib/chef/role.rb @@ -231,18 +231,19 @@ class Chef end # Load a role from disk - prefers to load the JSON, but will happily load - # the raw rb files as well. + # the raw rb files as well. Can search within directories in the role_path. def self.from_disk(name, force=nil) - js_file = File.join(Chef::Config[:role_path], "#{name}.json") - rb_file = File.join(Chef::Config[:role_path], "#{name}.rb") + roles_files = Dir.glob(File.join(Chef::Config[:role_path], "**", "**")) + js_path = roles_files.detect { |file| file.match /#{name}\.json$/ } + rb_path = roles_files.detect { |file| file.match /#{name}\.rb$/ } - if File.exists?(js_file) || force == "json" + if js_path && (File.exists?(js_path) || force == "json") # from_json returns object.class => json_class in the JSON. - Chef::JSONCompat.from_json(IO.read(js_file)) - elsif File.exists?(rb_file) || force == "ruby" + Chef::JSONCompat.from_json(IO.read(js_path)) + elsif rb_path && (File.exists?(rb_path) || force == "ruby") role = Chef::Role.new role.name(name) - role.from_file(rb_file) + role.from_file(rb_path) role else raise Chef::Exceptions::RoleNotFound, "Role '#{name}' could not be loaded from disk" diff --git a/spec/unit/role_spec.rb b/spec/unit/role_spec.rb index 764d586903..77a47ee6fd 100644 --- a/spec/unit/role_spec.rb +++ b/spec/unit/role_spec.rb @@ -246,28 +246,43 @@ describe Chef::Role do describe "when loading from disk" do it "should return a Chef::Role object from JSON" do - File.should_receive(:exists?).with(File.join(Chef::Config[:role_path], 'lolcat.json')).exactly(1).times.and_return(true) - IO.should_receive(:read).with(File.join(Chef::Config[:role_path], 'lolcat.json')).and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }') + Dir.should_receive(:glob).and_return(["#{Chef::Config[:role_path]}/memes", "#{Chef::Config[:role_path]}/memes/lolcat.json"]) + file_path = File.join(Chef::Config[:role_path], 'memes/lolcat.json') + File.should_receive(:exists?).with(file_path).exactly(1).times.and_return(true) + IO.should_receive(:read).with(file_path).and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }') @role.should be_a_kind_of(Chef::Role) @role.class.from_disk("lolcat") end it "should return a Chef::Role object from a Ruby DSL" do - File.should_receive(:exists?).with(File.join(Chef::Config[:role_path], 'lolcat.json')).exactly(1).times.and_return(false) - File.should_receive(:exists?).with(File.join(Chef::Config[:role_path], 'lolcat.rb')).exactly(2).times.and_return(true) - File.should_receive(:readable?).with(File.join(Chef::Config[:role_path], 'lolcat.rb')).exactly(1).times.and_return(true) + Dir.should_receive(:glob).and_return(["#{Chef::Config[:role_path]}/memes", "#{Chef::Config[:role_path]}/memes/lolcat.rb"]) + js_path = File.join(Chef::Config[:role_path], 'memes/lolcat.rb') + rb_path = File.join(Chef::Config[:role_path], 'memes/lolcat.rb') + File.should_receive(:exists?).with(rb_path).exactly(2).times.and_return(true) + File.should_receive(:readable?).with(rb_path).exactly(1).times.and_return(true) ROLE_DSL=<<-EOR name "ceiling_cat" description "like Aliens, but furry" EOR - IO.should_receive(:read).with(File.join(Chef::Config[:role_path], 'lolcat.rb')).and_return(ROLE_DSL) + IO.should_receive(:read).with(rb_path).and_return(ROLE_DSL) + @role.should be_a_kind_of(Chef::Role) + @role.class.from_disk("lolcat") + end + + it "should prefer a Chef::Role Object from JSON over one from a Ruby DSL" do + Dir.should_receive(:glob).and_return(["#{Chef::Config[:role_path]}/memes", "#{Chef::Config[:role_path]}/memes/lolcat.json", "#{Chef::Config[:role_path]}/memes/lolcat.rb"]) + js_path = File.join(Chef::Config[:role_path], 'memes/lolcat.json') + rb_path = File.join(Chef::Config[:role_path], 'memes/lolcat.rb') + File.should_receive(:exists?).with(js_path).exactly(1).times.and_return(true) + File.should_not_receive(:exists?).with(rb_path) + IO.should_receive(:read).with(js_path).and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }') @role.should be_a_kind_of(Chef::Role) @role.class.from_disk("lolcat") end it "should raise an exception if the file does not exist" do - File.should_receive(:exists?).with(File.join(Chef::Config[:role_path], 'lolcat.json')).exactly(1).times.and_return(false) - File.should_receive(:exists?).with(File.join(Chef::Config[:role_path], 'lolcat.rb')).exactly(1).times.and_return(false) + Dir.should_receive(:glob).and_return(["#{Chef::Config[:role_path]}/meme.rb"]) + File.should_not_receive(:exists?) lambda {@role.class.from_disk("lolcat")}.should raise_error(Chef::Exceptions::RoleNotFound) end end |