# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, 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 'support/shared/integration/integration_helper' require 'chef/knife/download' require 'chef/knife/diff' describe 'knife download', :workstation do include IntegrationSupport include KnifeSupport context 'without versioned cookbooks' do when_the_chef_server "has one of each thing" do before do client 'x', {} cookbook 'x', '1.0.0' data_bag 'x', { 'y' => {} } environment 'x', {} node 'x', {} role 'x', {} user 'x', {} end when_the_repository 'has only top-level directories' do before do directory 'clients' directory 'cookbooks' directory 'data_bags' directory 'environments' directory 'nodes' directory 'roles' directory 'users' end it 'knife download downloads everything' do knife('download /').should_succeed < true, 'public_key' => ChefZero::PUBLIC_KEY } file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY } file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY } file 'cookbooks/x/metadata.rb', cb_metadata("x", "1.0.0") file 'data_bags/x/y.json', {} file 'environments/_default.json', { "description" => "The default Chef environment" } file 'environments/x.json', {} file 'nodes/x.json', {} file 'roles/x.json', {} file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY } file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY } end it 'knife download makes no changes' do knife('download /').should_succeed '' knife('diff --name-status /').should_succeed '' end it 'knife download --purge makes no changes' do knife('download --purge /').should_succeed '' knife('diff --name-status /').should_succeed '' end context 'except the role file' do before do file 'roles/x.json', < ChefZero::PUBLIC_KEY } file 'cookbooks/x/blah.rb', '' file 'cookbooks/y/metadata.rb', cb_metadata("x", "1.0.0") file 'data_bags/x/z.json', {} file 'data_bags/y/zz.json', {} file 'environments/y.json', {} file 'nodes/y.json', {} file 'roles/y.json', {} file 'users/y.json', { 'public_key' => ChefZero::PUBLIC_KEY } end it 'knife download does nothing' do knife('download /').should_succeed '' knife('diff --name-status /').should_succeed < /USAGE/ end end end end # Test download of an item when the other end doesn't even have the container when_the_repository 'is empty' do when_the_chef_server 'has two data bag items' do before do data_bag 'x', { 'y' => {}, 'z' => {} } end it 'knife download of one data bag item itself succeeds' do knife('download /data_bags/x/y.json').should_succeed < {}, 'modified' => { 'foo' => 'bar' }, 'unmodified' => {}, } end it 'knife download of the modified file succeeds' do knife('download /data_bags/x/modified.json').should_succeed < /USAGE/ end it 'knife download --purge . downloads everything' do knife('download --purge .').should_succeed < cb_metadata("x", "1.0.0", "#extra content"), 'y.rb' => 'hi' } end it 'knife download of a modified file succeeds' do knife('download /cookbooks/x/metadata.rb').should_succeed "Updated /cookbooks/x/metadata.rb\n" knife('diff --name-status /cookbooks').should_succeed < '' } cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' } end it 'knife download /cookbooks/x downloads the latest version' do knife('download --purge /cookbooks/x').should_succeed < ''} cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' } end it 'knife download /cookbooks/x downloads the updated file' do knife('download --purge /cookbooks/x').should_succeed < 'hi' } end it 'knife download /cookbooks/x downloads the latest version' do knife('download --purge /cookbooks/x').should_succeed < 'hi' } end it 'knife download /cookbooks/x downloads the old version' do knife('download --purge /cookbooks/x').should_succeed < warning knife('diff --name-status /environments/x.json').should_succeed '' end end when_the_repository 'has the same environment with the wrong name in the file' do before do file 'environments/x.json', { 'name' => 'y' } end it 'knife download succeeds' do knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n" knife('diff --name-status /environments/x.json').should_succeed '' end end when_the_repository 'has the same environment with no name in the file' do before do file 'environments/x.json', { 'description' => 'hi' } end it 'knife download succeeds' do knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n" knife('diff --name-status /environments/x.json').should_succeed '' end end end end # without versioned cookbooks with_versioned_cookbooks do when_the_chef_server "has one of each thing" do before do client 'x', {} cookbook 'x', '1.0.0' data_bag 'x', { 'y' => {} } environment 'x', {} node 'x', {} role 'x', {} user 'x', {} end when_the_repository 'has only top-level directories' do before do directory 'clients' directory 'cookbooks' directory 'data_bags' directory 'environments' directory 'nodes' directory 'roles' directory 'users' end it 'knife download downloads everything' do knife('download /').should_succeed < true, 'public_key' => ChefZero::PUBLIC_KEY } file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY } file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY } file 'cookbooks/x-1.0.0/metadata.rb', cb_metadata("x", "1.0.0") file 'data_bags/x/y.json', {} file 'environments/_default.json', { "description" => "The default Chef environment" } file 'environments/x.json', {} file 'nodes/x.json', {} file 'roles/x.json', {} file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY } file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY } end it 'knife download makes no changes' do knife('download /').should_succeed '' knife('diff --name-status /').should_succeed '' end it 'knife download --purge makes no changes' do knife('download --purge /').should_succeed '' knife('diff --name-status /').should_succeed '' end context 'except the role file' do before do file 'roles/x.json', { "description" => "blarghle" } end it 'knife download changes the role' do knife('download /').should_succeed "Updated /roles/x.json\n" knife('diff --name-status /').should_succeed '' end end context 'except the role file is textually different, but not ACTUALLY different' do before do file 'roles/x.json', < ChefZero::PUBLIC_KEY } file 'cookbooks/x-1.0.0/blah.rb', '' file 'cookbooks/x-2.0.0/metadata.rb', 'version "2.0.0"' file 'cookbooks/y-1.0.0/metadata.rb', 'version "1.0.0"' file 'data_bags/x/z.json', {} file 'data_bags/y/zz.json', {} file 'environments/y.json', {} file 'nodes/y.json', {} file 'roles/y.json', {} file 'users/y.json', { 'public_key' => ChefZero::PUBLIC_KEY } end it 'knife download does nothing' do knife('download /').should_succeed '' knife('diff --name-status /').should_succeed < /USAGE/ end end end end # Test download of an item when the other end doesn't even have the container when_the_repository 'is empty' do when_the_chef_server 'has two data bag items' do before do data_bag 'x', { 'y' => {}, 'z' => {} } end it 'knife download of one data bag item itself succeeds' do knife('download /data_bags/x/y.json').should_succeed < {}, 'modified' => { 'foo' => 'bar' }, 'unmodified' => {}, } end it 'knife download of the modified file succeeds' do knife('download /data_bags/x/modified.json').should_succeed < /USAGE/ end it 'knife download --purge . downloads everything' do knife('download --purge .').should_succeed < 'hi' } end it 'knife download of a modified file succeeds' do knife('download /cookbooks/x-1.0.0/metadata.rb').should_succeed "Updated /cookbooks/x-1.0.0/metadata.rb\n" knife('diff --name-status /cookbooks').should_succeed < '' } cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' } end it 'knife download /cookbooks/x downloads the latest version' do knife('download --purge /cookbooks').should_succeed < ''} cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' } end it 'knife download /cookbooks downloads the updated file' do knife('download --purge /cookbooks').should_succeed < 'hi' } end it 'knife download /cookbooks/x downloads the latest version' do knife('download --purge /cookbooks').should_succeed < 'hi' } end it 'knife download --purge /cookbooks downloads the old version and deletes the new version' do knife('download --purge /cookbooks').should_succeed < 'y' } end it 'knife download succeeds' do knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n" knife('diff --name-status /environments/x.json').should_succeed '' end end when_the_repository 'has the same environment with no name in the file' do before do file 'environments/x.json', { 'description' => 'hi' } end it 'knife download succeeds' do knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n" knife('diff --name-status /environments/x.json').should_succeed '' end end end end # with versioned cookbooks when_the_chef_server 'has a cookbook' do before do cookbook 'x', '1.0.0' end when_the_repository 'is empty' do it 'knife download /cookbooks/x signs all requests' do # Check that BasicClient.request() always gets called with X-OPS-USERID original_new = Chef::HTTP::BasicClient.method(:new) expect(Chef::HTTP::BasicClient).to receive(:new) { |args| new_result = original_new.call(*args) original_request = new_result.method(:request) expect(new_result).to receive(:request) { |method, url, body, headers, &response_handler| expect(headers['X-OPS-USERID']).not_to be_nil original_request.call(method, url, body, headers, &response_handler) }.at_least(:once) new_result }.at_least(:once) knife('download /cookbooks/x').should_succeed < false, :single_org => false do before do user 'foo', {} user 'bar', {} user 'foobar', {} organization 'foo', { 'full_name' => 'Something' } end before :each do Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, '/organizations/foo') end when_the_repository "has all the default stuff" do before do knife('download /').should_succeed < {} } environment 'x', {} group 'x', {} org_invite 'foo' org_member 'bar' node 'x', {} policy 'x', '1.0.0', {} policy 'blah', '1.0.0', {} policy_group 'x', { 'policies' => { 'x' => { 'revision_id' => '1.0.0' }, 'blah' => { 'revision_id' => '1.0.0' }, } } role 'x', {} end before do knife('download /acls /groups/clients.json /groups/users.json').should_succeed <<-EOM Created /acls/clients/x.json Created /acls/containers/x.json Created /acls/cookbooks/x.json Created /acls/data_bags/x.json Created /acls/environments/x.json Created /acls/groups/x.json Created /acls/nodes/x.json Created /acls/roles/x.json Updated /groups/clients.json Updated /groups/users.json EOM end it 'knife download / downloads everything' do knife('download /').should_succeed < ChefZero::PUBLIC_KEY } file 'containers/x.json', {} file 'cookbooks/x/metadata.rb', cb_metadata("x", "1.0.0") file 'data_bags/x/y.json', {} file 'environments/x.json', {} file 'groups/x.json', {} file 'invitations.json', [ 'foo' ] file 'members.json', [ 'bar' ] file 'nodes/x.json', {} file 'org.json', { 'full_name' => 'Something' } file 'policies/x-1.0.0.json', { } file 'policies/blah-1.0.0.json', { } file 'policy_groups/x.json', { 'policies' => { 'x' => { 'revision_id' => '1.0.0' }, 'blah' => { 'revision_id' => '1.0.0' } } } file 'roles/x.json', {} end it 'knife download makes no changes' do knife('download /').should_succeed '' end end context "and the repository has a slightly different copy of each thing" do before do # acl_for %w(organizations foo groups blah) file 'clients/x.json', { 'validator' => true } file 'containers/x.json', {} file 'cookbooks/x/metadata.rb', cb_metadata("x", "1.0.1") file 'data_bags/x/y.json', { 'a' => 'b' } file 'environments/x.json', { 'description' => 'foo' } file 'groups/x.json', { 'description' => 'foo' } file 'groups/x.json', { 'groups' => [ 'admin' ] } file 'nodes/x.json', { 'run_list' => [ 'blah' ] } file 'org.json', { 'full_name' => 'Something Else ' } file 'policies/x-1.0.0.json', { 'run_list' => [ 'blah' ] } file 'policy_groups/x.json', { 'policies' => { 'x' => { 'revision_id' => '1.0.1' }, 'y' => { 'revision_id' => '1.0.0' }, } } file 'roles/x.json', { 'run_list' => [ 'blah' ] } end it 'knife download updates everything' do knife('download /').should_succeed <