# # Author:: John Keiser () # Copyright:: Copyright (c) Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "knife_spec_helper" require "support/shared/integration/integration_helper" require "support/shared/context/config" require "chef/knife/list" require "chef/knife/show" describe "chef_repo_path tests", :workstation do include IntegrationSupport include KnifeSupport let(:error_rel_path_outside_repo) { /^ERROR: Attempt to use relative path '' when current directory is outside the repository path/ } # TODO alternate repo_path / *_path context "alternate *_path" do when_the_repository "has clients and clients2, cookbooks and cookbooks2, etc." do before do file "clients/client1.json", {} file "cookbooks/cookbook1/metadata.rb", "" file "data_bags/bag/item.json", {} file "environments/env1.json", {} file "nodes/node1.json", {} file "roles/role1.json", {} file "users/user1.json", {} file "clients2/client2.json", {} file "cookbooks2/cookbook2/metadata.rb", "" file "data_bags2/bag2/item2.json", {} file "environments2/env2.json", {} file "nodes2/node2.json", {} file "roles2/role2.json", {} file "users2/user2.json", {} directory "chef_repo2" do file "clients/client3.json", {} file "cookbooks/cookbook3/metadata.rb", "name 'cookbook3'" file "data_bags/bag3/item3.json", {} file "environments/env3.json", {} file "nodes/node3.json", {} file "roles/role3.json", {} file "users/user3.json", {} end end it "knife list --local -Rfp --chef-repo-path chef_repo2 / grabs chef_repo2 stuff" do Chef::Config.delete(:chef_repo_path) knife("list --local -Rfp --chef-repo-path #{path_to("chef_repo2")} /").should_succeed <<~EOM /clients/ /clients/client3.json /cookbooks/ /cookbooks/cookbook3/ /cookbooks/cookbook3/metadata.rb /data_bags/ /data_bags/bag3/ /data_bags/bag3/item3.json /environments/ /environments/env3.json /nodes/ /nodes/node3.json /roles/ /roles/role3.json /users/ /users/user3.json EOM end # "Skipping for BK... As Windows 2019 has 8dot3name disabled by default" it "knife list --local -Rfp --chef-repo-path chef_r~1 / grabs chef_repo2 stuff", :windows_only, :skip_buildkite do Chef::Config.delete(:chef_repo_path) knife("list --local -Rfp --chef-repo-path #{path_to("chef_r~1")} /").should_succeed <<~EOM /clients/ /clients/client3.json /cookbooks/ /cookbooks/cookbook3/ /cookbooks/cookbook3/metadata.rb /data_bags/ /data_bags/bag3/ /data_bags/bag3/item3.json /environments/ /environments/env3.json /nodes/ /nodes/node3.json /roles/ /roles/role3.json /users/ /users/user3.json EOM end # "Skipping for BK... As Windows 2019 has 8dot3name disabled by default" it "knife list --local -Rfp --chef-repo-path chef_r~1 / grabs chef_repo2 stuff", :windows_only, :skip_buildkite do Chef::Config.delete(:chef_repo_path) knife("list -z -Rfp --chef-repo-path #{path_to("chef_r~1")} /").should_succeed <<~EOM /acls/ /acls/clients/ /acls/clients/client3.json /acls/containers/ /acls/cookbook_artifacts/ /acls/cookbooks/ /acls/cookbooks/cookbook3.json /acls/data_bags/ /acls/data_bags/bag3.json /acls/environments/ /acls/environments/env3.json /acls/groups/ /acls/nodes/ /acls/nodes/node3.json /acls/organization.json /acls/policies/ /acls/policy_groups/ /acls/roles/ /acls/roles/role3.json /clients/ /clients/client3.json /containers/ /cookbook_artifacts/ /cookbooks/ /cookbooks/cookbook3/ /cookbooks/cookbook3/metadata.rb /data_bags/ /data_bags/bag3/ /data_bags/bag3/item3.json /environments/ /environments/env3.json /groups/ /invitations.json /members.json /nodes/ /nodes/node3.json /org.json /policies/ /policy_groups/ /roles/ /roles/role3.json EOM end context "when all _paths are set to alternates" do before :each do %w{client cookbook data_bag environment node role user}.each do |object_name| Chef::Config["#{object_name}_path".to_sym] = File.join(Chef::Config.chef_repo_path, "#{object_name}s2") end Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "chef_repo2") end it "knife list --local -Rfp --chef-repo-path chef_repo2 / grabs chef_repo2 stuff" do knife("list --local -Rfp --chef-repo-path #{path_to("chef_repo2")} /").should_succeed <<~EOM /clients/ /clients/client3.json /cookbooks/ /cookbooks/cookbook3/ /cookbooks/cookbook3/metadata.rb /data_bags/ /data_bags/bag3/ /data_bags/bag3/item3.json /environments/ /environments/env3.json /nodes/ /nodes/node3.json /roles/ /roles/role3.json /users/ /users/user3.json EOM end context "when cwd is at the top level" do before { cwd "." } it "knife list --local -Rfp fails" do knife("list --local -Rfp").should_fail(error_rel_path_outside_repo) end end context "when cwd is inside the data_bags directory" do before { cwd "data_bags" } it "knife list --local -Rfp fails" do knife("list --local -Rfp").should_fail(error_rel_path_outside_repo) end end context "when cwd is inside chef_repo2" do before { cwd "chef_repo2" } it "knife list --local -Rfp lists everything" do knife("list --local -Rfp").should_succeed <<~EOM clients/ clients/client2.json cookbooks/ cookbooks/cookbook2/ cookbooks/cookbook2/metadata.rb data_bags/ data_bags/bag2/ data_bags/bag2/item2.json environments/ environments/env2.json nodes/ nodes/node2.json roles/ roles/role2.json users/ users/user2.json EOM end end context "when cwd is inside data_bags2" do before { cwd "data_bags2" } it "knife list --local -Rfp lists data bags" do knife("list --local -Rfp").should_succeed <<~EOM bag2/ bag2/item2.json EOM end it "knife list --local -Rfp ../roles lists roles" do knife("list --local -Rfp ../roles").should_succeed "/roles/role2.json\n" end end end context "when all _paths except chef_repo_path are set to alternates" do before :each do %w{client cookbook data_bag environment node role user}.each do |object_name| Chef::Config["#{object_name}_path".to_sym] = File.join(Chef::Config.chef_repo_path, "#{object_name}s2") end end context "when cwd is at the top level" do before { cwd "." } it "knife list --local -Rfp lists everything" do knife("list --local -Rfp").should_succeed <<~EOM clients/ clients/client2.json cookbooks/ cookbooks/cookbook2/ cookbooks/cookbook2/metadata.rb data_bags/ data_bags/bag2/ data_bags/bag2/item2.json environments/ environments/env2.json nodes/ nodes/node2.json roles/ roles/role2.json users/ users/user2.json EOM end end context "when cwd is inside the data_bags directory" do before { cwd "data_bags" } it "knife list --local -Rfp fails" do knife("list --local -Rfp").should_fail(error_rel_path_outside_repo) end end context "when cwd is inside chef_repo2" do before { cwd "chef_repo2" } it "knife list -Rfp fails" do knife("list --local -Rfp").should_fail(error_rel_path_outside_repo) end end context "when cwd is inside data_bags2" do before { cwd "data_bags2" } it "knife list --local -Rfp lists data bags" do knife("list --local -Rfp").should_succeed <<~EOM bag2/ bag2/item2.json EOM end end end context "when only chef_repo_path is set to its alternate" do before :each do %w{client cookbook data_bag environment node role user}.each do |object_name| Chef::Config.delete("#{object_name}_path".to_sym) end Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "chef_repo2") end context "when cwd is at the top level" do before { cwd "." } it "knife list --local -Rfp fails" do knife("list --local -Rfp").should_fail(error_rel_path_outside_repo) end end context "when cwd is inside the data_bags directory" do before { cwd "data_bags" } it "knife list --local -Rfp fails" do knife("list --local -Rfp").should_fail(error_rel_path_outside_repo) end end context "when cwd is inside chef_repo2" do before { cwd "chef_repo2" } it "knife list --local -Rfp lists everything" do knife("list --local -Rfp").should_succeed <<~EOM clients/ clients/client3.json cookbooks/ cookbooks/cookbook3/ cookbooks/cookbook3/metadata.rb data_bags/ data_bags/bag3/ data_bags/bag3/item3.json environments/ environments/env3.json nodes/ nodes/node3.json roles/ roles/role3.json users/ users/user3.json EOM end end context "when cwd is inside chef_repo2/data_bags" do before { cwd "chef_repo2/data_bags" } it "knife list --local -Rfp lists data bags" do knife("list --local -Rfp").should_succeed <<~EOM bag3/ bag3/item3.json EOM end end end context "when paths are set to point to both versions of each" do before :each do %w{client cookbook data_bag environment node role user}.each do |object_name| Chef::Config["#{object_name}_path".to_sym] = [ File.join(Chef::Config.chef_repo_path, "#{object_name}s"), File.join(Chef::Config.chef_repo_path, "#{object_name}s2"), ] end Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "chef_repo2") end context "when there is a directory in clients1 and file in clients2 with the same name" do before do directory "clients/blah.json" file "clients2/blah.json", {} end it "knife show /clients/blah.json succeeds" do knife("show --local /clients/blah.json").should_succeed <<~EOM /clients/blah.json: { } EOM end end context "when there is a file in cookbooks1 and directory in cookbooks2 with the same name" do before do file "cookbooks/blah", "" file "cookbooks2/blah/metadata.rb", "" end it "knife list -Rfp cookbooks shows files in blah" do knife("list --local -Rfp /cookbooks").should_succeed <<~EOM /cookbooks/blah/ /cookbooks/blah/metadata.rb /cookbooks/cookbook1/ /cookbooks/cookbook1/metadata.rb /cookbooks/cookbook2/ /cookbooks/cookbook2/metadata.rb EOM end end context "when there is an empty directory in cookbooks1 and a real cookbook in cookbooks2 with the same name" do before do directory "cookbooks/blah" file "cookbooks2/blah/metadata.rb", "" end it "knife list -Rfp cookbooks shows files in blah" do knife("list --local -Rfp /cookbooks").should_succeed(<<~EOM, stderr: "WARN: Cookbook 'blah' is empty or entirely chefignored at #{Chef::Config.cookbook_path[0]}/blah\n") /cookbooks/blah/ /cookbooks/blah/metadata.rb /cookbooks/cookbook1/ /cookbooks/cookbook1/metadata.rb /cookbooks/cookbook2/ /cookbooks/cookbook2/metadata.rb EOM end end context "when there is a cookbook in cookbooks1 and a cookbook in cookbooks2 with the same name" do before do file "cookbooks/blah/metadata.json", {} file "cookbooks2/blah/metadata.rb", "" end it "knife list -Rfp cookbooks shows files in the first cookbook and not the second" do knife("list --local -Rfp /cookbooks").should_succeed(<<~EOM, stderr: "WARN: Child with name 'blah' found in multiple directories: #{Chef::Config.cookbook_path[0]}/blah and #{Chef::Config.cookbook_path[1]}/blah\n") /cookbooks/blah/ /cookbooks/blah/metadata.json /cookbooks/cookbook1/ /cookbooks/cookbook1/metadata.rb /cookbooks/cookbook2/ /cookbooks/cookbook2/metadata.rb EOM end end context "when there is a file in data_bags1 and a directory in data_bags2 with the same name" do before do file "data_bags/blah", "" file "data_bags2/blah/item.json", "" end it "knife list -Rfp data_bags shows files in blah" do knife("list --local -Rfp /data_bags").should_succeed <<~EOM /data_bags/bag/ /data_bags/bag/item.json /data_bags/bag2/ /data_bags/bag2/item2.json /data_bags/blah/ /data_bags/blah/item.json EOM end end context "when there is a data bag in data_bags1 and a data bag in data_bags2 with the same name" do before do file "data_bags/blah/item1.json", "" file "data_bags2/blah/item2.json", "" end it "knife list -Rfp data_bags shows only items in data_bags1" do knife("list --local -Rfp /data_bags").should_succeed(<<~EOM, stderr: "WARN: Child with name 'blah' found in multiple directories: #{Chef::Config.data_bag_path[0]}/blah and #{Chef::Config.data_bag_path[1]}/blah\n") /data_bags/bag/ /data_bags/bag/item.json /data_bags/bag2/ /data_bags/bag2/item2.json /data_bags/blah/ /data_bags/blah/item1.json EOM end end context "when there is a directory in environments1 and file in environments2 with the same name" do before do directory "environments/blah.json" file "environments2/blah.json", {} end it "knife show /environments/blah.json succeeds" do knife("show --local /environments/blah.json").should_succeed <<~EOM /environments/blah.json: { } EOM end end context "when there is a directory in nodes1 and file in nodes2 with the same name" do before do directory "nodes/blah.json" file "nodes2/blah.json", {} end it "knife show /nodes/blah.json succeeds" do knife("show --local /nodes/blah.json").should_succeed <<~EOM /nodes/blah.json: { } EOM end end context "when there is a directory in roles1 and file in roles2 with the same name" do before do directory "roles/blah.json" file "roles2/blah.json", {} end it "knife show /roles/blah.json succeeds" do knife("show --local /roles/blah.json").should_succeed <<~EOM /roles/blah.json: { } EOM end end context "when there is a directory in users1 and file in users2 with the same name" do before do directory "users/blah.json" file "users2/blah.json", {} end it "knife show /users/blah.json succeeds" do knife("show --local /users/blah.json").should_succeed <<~EOM /users/blah.json: { } EOM end end context "when cwd is at the top level" do before { cwd "." } it "knife list --local -Rfp fails" do knife("list --local -Rfp").should_fail(error_rel_path_outside_repo) end end context "when cwd is inside the data_bags directory" do before { cwd "data_bags" } it "knife list --local -Rfp lists data bags" do knife("list --local -Rfp").should_succeed <<~EOM bag/ bag/item.json bag2/ bag2/item2.json EOM end end context "when cwd is inside chef_repo2" do before { cwd "chef_repo2" } it "knife list --local -Rfp lists everything" do knife("list --local -Rfp").should_succeed <<~EOM clients/ clients/client1.json clients/client2.json cookbooks/ cookbooks/cookbook1/ cookbooks/cookbook1/metadata.rb cookbooks/cookbook2/ cookbooks/cookbook2/metadata.rb data_bags/ data_bags/bag/ data_bags/bag/item.json data_bags/bag2/ data_bags/bag2/item2.json environments/ environments/env1.json environments/env2.json nodes/ nodes/node1.json nodes/node2.json roles/ roles/role1.json roles/role2.json users/ users/user1.json users/user2.json EOM end end context "when cwd is inside data_bags2" do before { cwd "data_bags2" } it "knife list --local -Rfp lists data bags" do knife("list --local -Rfp").should_succeed <<~EOM bag/ bag/item.json bag2/ bag2/item2.json EOM end end end context "when when chef_repo_path is set to both places and no other _path is set" do before :each do %w{client cookbook data_bag environment node role user}.each do |object_name| Chef::Config.delete("#{object_name}_path".to_sym) end Chef::Config.chef_repo_path = [ Chef::Config.chef_repo_path, File.join(Chef::Config.chef_repo_path, "chef_repo2"), ] end context "when cwd is at the top level" do before { cwd "." } it "knife list --local -Rfp lists everything" do knife("list --local -Rfp").should_succeed <<~EOM clients/ clients/client1.json clients/client3.json cookbooks/ cookbooks/cookbook1/ cookbooks/cookbook1/metadata.rb cookbooks/cookbook3/ cookbooks/cookbook3/metadata.rb data_bags/ data_bags/bag/ data_bags/bag/item.json data_bags/bag3/ data_bags/bag3/item3.json environments/ environments/env1.json environments/env3.json nodes/ nodes/node1.json nodes/node3.json roles/ roles/role1.json roles/role3.json users/ users/user1.json users/user3.json EOM end end context "when cwd is inside the data_bags directory" do before { cwd "data_bags" } it "knife list --local -Rfp lists data bags" do knife("list --local -Rfp").should_succeed <<~EOM bag/ bag/item.json bag3/ bag3/item3.json EOM end end context "when cwd is inside chef_repo2" do before { cwd "chef_repo2" } it "knife list --local -Rfp lists everything" do knife("list --local -Rfp").should_succeed <<~EOM clients/ clients/client1.json clients/client3.json cookbooks/ cookbooks/cookbook1/ cookbooks/cookbook1/metadata.rb cookbooks/cookbook3/ cookbooks/cookbook3/metadata.rb data_bags/ data_bags/bag/ data_bags/bag/item.json data_bags/bag3/ data_bags/bag3/item3.json environments/ environments/env1.json environments/env3.json nodes/ nodes/node1.json nodes/node3.json roles/ roles/role1.json roles/role3.json users/ users/user1.json users/user3.json EOM end end context "when cwd is inside chef_repo2/data_bags" do before { cwd "chef_repo2/data_bags" } it "knife list --local -Rfp lists data bags" do knife("list --local -Rfp").should_succeed <<~EOM bag/ bag/item.json bag3/ bag3/item3.json EOM end end end context "when cookbook_path is set and nothing else" do before :each do %w{client data_bag environment node role user}.each do |object_name| Chef::Config.delete("#{object_name}_path".to_sym) end Chef::Config.delete(:chef_repo_path) Chef::Config.cookbook_path = File.join(@repository_dir, "chef_repo2", "cookbooks") end context "when cwd is at the top level" do before { cwd "." } it "knife list --local -Rfp fails" do knife("list --local -Rfp").should_fail(error_rel_path_outside_repo) end end context "when cwd is inside the data_bags directory" do before { cwd "data_bags" } it "knife list --local -Rfp fails" do knife("list --local -Rfp").should_fail(error_rel_path_outside_repo) end end context "when cwd is inside chef_repo2" do before { cwd "chef_repo2" } it "knife list --local -Rfp lists everything" do knife("list --local -Rfp").should_succeed <<~EOM clients/ clients/client3.json cookbooks/ cookbooks/cookbook3/ cookbooks/cookbook3/metadata.rb data_bags/ data_bags/bag3/ data_bags/bag3/item3.json environments/ environments/env3.json nodes/ nodes/node3.json roles/ roles/role3.json users/ users/user3.json EOM end end context "when cwd is inside chef_repo2/data_bags" do before { cwd "chef_repo2/data_bags" } it "knife list --local -Rfp lists data bags" do knife("list --local -Rfp").should_succeed <<~EOM bag3/ bag3/item3.json EOM end end end context "when cookbook_path is set to multiple places and nothing else is set" do before :each do %w{client data_bag environment node role user}.each do |object_name| Chef::Config.delete("#{object_name}_path".to_sym) end Chef::Config.delete(:chef_repo_path) Chef::Config.cookbook_path = [ File.join(@repository_dir, "cookbooks"), File.join(@repository_dir, "chef_repo2", "cookbooks"), ] end context "when cwd is at the top level" do before { cwd "." } it "knife list --local -Rfp lists everything" do knife("list --local -Rfp").should_succeed <<~EOM clients/ clients/client1.json clients/client3.json cookbooks/ cookbooks/cookbook1/ cookbooks/cookbook1/metadata.rb cookbooks/cookbook3/ cookbooks/cookbook3/metadata.rb data_bags/ data_bags/bag/ data_bags/bag/item.json data_bags/bag3/ data_bags/bag3/item3.json environments/ environments/env1.json environments/env3.json nodes/ nodes/node1.json nodes/node3.json roles/ roles/role1.json roles/role3.json users/ users/user1.json users/user3.json EOM end end context "when cwd is inside the data_bags directory" do before { cwd "data_bags" } it "knife list --local -Rfp lists data bags" do knife("list --local -Rfp").should_succeed <<~EOM bag/ bag/item.json bag3/ bag3/item3.json EOM end end context "when cwd is inside chef_repo2" do before { cwd "chef_repo2" } it "knife list --local -Rfp lists everything" do knife("list --local -Rfp").should_succeed <<~EOM clients/ clients/client1.json clients/client3.json cookbooks/ cookbooks/cookbook1/ cookbooks/cookbook1/metadata.rb cookbooks/cookbook3/ cookbooks/cookbook3/metadata.rb data_bags/ data_bags/bag/ data_bags/bag/item.json data_bags/bag3/ data_bags/bag3/item3.json environments/ environments/env1.json environments/env3.json nodes/ nodes/node1.json nodes/node3.json roles/ roles/role1.json roles/role3.json users/ users/user1.json users/user3.json EOM end end context "when cwd is inside chef_repo2/data_bags" do before { cwd "chef_repo2/data_bags" } it "knife list --local -Rfp lists data bags" do knife("list --local -Rfp").should_succeed <<~EOM bag/ bag/item.json bag3/ bag3/item3.json EOM end end end context "when data_bag_path and chef_repo_path are set, and nothing else" do before :each do %w{client cookbook environment node role user}.each do |object_name| Chef::Config.delete("#{object_name}_path".to_sym) end Chef::Config.data_bag_path = File.join(Chef::Config.chef_repo_path, "data_bags") Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "chef_repo2") end context "when cwd is at the top level" do before { cwd "." } it "knife list --local -Rfp fails" do knife("list --local -Rfp").should_fail(error_rel_path_outside_repo) end end context "when cwd is inside the data_bags directory" do before { cwd "data_bags" } it "knife list --local -Rfp lists data bags" do knife("list --local -Rfp").should_succeed <<~EOM bag/ bag/item.json EOM end end context "when cwd is inside chef_repo2" do before { cwd "chef_repo2" } it "knife list --local -Rfp lists everything" do knife("list --local -Rfp").should_succeed <<~EOM clients/ clients/client3.json cookbooks/ cookbooks/cookbook3/ cookbooks/cookbook3/metadata.rb data_bags/ data_bags/bag/ data_bags/bag/item.json environments/ environments/env3.json nodes/ nodes/node3.json roles/ roles/role3.json users/ users/user3.json EOM end end context "when cwd is inside chef_repo2/data_bags" do before { cwd "chef_repo2/data_bags" } it "knife list --local -Rfp fails" do knife("list --local -Rfp").should_fail(error_rel_path_outside_repo) end end end context "when data_bag_path is set and nothing else" do include_context "default config options" before :each do %w{client cookbook environment node role user}.each do |object_name| Chef::Config.delete("#{object_name}_path".to_sym) end Chef::Config.delete(:chef_repo_path) Chef::Config.data_bag_path = File.join(@repository_dir, "data_bags") end it "knife list --local -Rfp / lists data bags" do knife("list --local -Rfp /").should_succeed <<~EOM /data_bags/ /data_bags/bag/ /data_bags/bag/item.json EOM end it "knife list --local -Rfp /data_bags lists data bags" do knife("list --local -Rfp /data_bags").should_succeed <<~EOM /data_bags/bag/ /data_bags/bag/item.json EOM end context "when cwd is inside the data_bags directory" do before { cwd "data_bags" } it "knife list --local -Rfp lists data bags" do knife("list --local -Rfp").should_succeed <<~EOM bag/ bag/item.json EOM end end end end when_the_repository "is empty" do context "when the repository _paths point to places that do not exist" do before :each do %w{client cookbook data_bag environment node role user}.each do |object_name| Chef::Config["#{object_name}_path".to_sym] = File.join(Chef::Config.chef_repo_path, "nowhere", object_name) end Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "nowhere") end it "knife list --local -Rfp / fails" do knife("list --local -Rfp /").should_succeed "" end it "knife list --local -Rfp /data_bags fails" do knife("list --local -Rfp /data_bags").should_fail("ERROR: /data_bags: No such file or directory\n") end end end end end