test-kitchen 1.7.0 → 1.7.1.dev
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.cane +8 -8
- data/.gitattributes +3 -0
- data/.github/ISSUE_TEMPLATE.md +55 -55
- data/.gitignore +28 -28
- data/.kitchen.ci.yml +23 -23
- data/.kitchen.proxy.yml +27 -27
- data/.rubocop.yml +3 -3
- data/.travis.yml +70 -70
- data/.yardopts +3 -3
- data/Berksfile +3 -3
- data/CHANGELOG.md +1090 -1083
- data/CONTRIBUTING.md +14 -14
- data/Gemfile +19 -19
- data/Gemfile.proxy_tests +4 -4
- data/Guardfile +42 -42
- data/LICENSE +15 -15
- data/MAINTAINERS.md +23 -23
- data/README.md +135 -135
- data/Rakefile +61 -61
- data/appveyor.yml +44 -44
- data/features/kitchen_action_commands.feature +164 -164
- data/features/kitchen_command.feature +16 -16
- data/features/kitchen_console_command.feature +34 -34
- data/features/kitchen_defaults.feature +38 -38
- data/features/kitchen_diagnose_command.feature +96 -96
- data/features/kitchen_driver_create_command.feature +64 -64
- data/features/kitchen_driver_discover_command.feature +25 -25
- data/features/kitchen_help_command.feature +16 -16
- data/features/kitchen_init_command.feature +274 -274
- data/features/kitchen_list_command.feature +104 -104
- data/features/kitchen_login_command.feature +62 -62
- data/features/kitchen_sink_command.feature +30 -30
- data/features/kitchen_test_command.feature +88 -88
- data/features/step_definitions/gem_steps.rb +36 -36
- data/features/step_definitions/git_steps.rb +5 -5
- data/features/step_definitions/output_steps.rb +5 -5
- data/features/support/env.rb +75 -75
- data/lib/kitchen.rb +150 -150
- data/lib/kitchen/base64_stream.rb +55 -55
- data/lib/kitchen/cli.rb +419 -419
- data/lib/kitchen/collection.rb +55 -55
- data/lib/kitchen/color.rb +65 -65
- data/lib/kitchen/command.rb +185 -185
- data/lib/kitchen/command/action.rb +45 -45
- data/lib/kitchen/command/console.rb +58 -58
- data/lib/kitchen/command/diagnose.rb +92 -92
- data/lib/kitchen/command/driver_discover.rb +105 -105
- data/lib/kitchen/command/exec.rb +41 -41
- data/lib/kitchen/command/list.rb +119 -119
- data/lib/kitchen/command/login.rb +43 -43
- data/lib/kitchen/command/sink.rb +54 -54
- data/lib/kitchen/command/test.rb +51 -51
- data/lib/kitchen/config.rb +322 -322
- data/lib/kitchen/configurable.rb +529 -529
- data/lib/kitchen/data_munger.rb +959 -959
- data/lib/kitchen/diagnostic.rb +141 -141
- data/lib/kitchen/driver.rb +56 -56
- data/lib/kitchen/driver/base.rb +134 -134
- data/lib/kitchen/driver/dummy.rb +108 -108
- data/lib/kitchen/driver/proxy.rb +72 -72
- data/lib/kitchen/driver/ssh_base.rb +357 -357
- data/lib/kitchen/errors.rb +229 -229
- data/lib/kitchen/generator/driver_create.rb +177 -177
- data/lib/kitchen/generator/init.rb +296 -296
- data/lib/kitchen/instance.rb +662 -662
- data/lib/kitchen/lazy_hash.rb +142 -142
- data/lib/kitchen/loader/yaml.rb +349 -349
- data/lib/kitchen/logger.rb +423 -423
- data/lib/kitchen/logging.rb +56 -56
- data/lib/kitchen/login_command.rb +52 -52
- data/lib/kitchen/metadata_chopper.rb +52 -52
- data/lib/kitchen/platform.rb +67 -67
- data/lib/kitchen/provisioner.rb +54 -54
- data/lib/kitchen/provisioner/base.rb +236 -236
- data/lib/kitchen/provisioner/chef/berkshelf.rb +114 -114
- data/lib/kitchen/provisioner/chef/common_sandbox.rb +322 -322
- data/lib/kitchen/provisioner/chef/librarian.rb +112 -112
- data/lib/kitchen/provisioner/chef_apply.rb +124 -124
- data/lib/kitchen/provisioner/chef_base.rb +341 -341
- data/lib/kitchen/provisioner/chef_solo.rb +88 -88
- data/lib/kitchen/provisioner/chef_zero.rb +245 -245
- data/lib/kitchen/provisioner/dummy.rb +79 -79
- data/lib/kitchen/provisioner/shell.rb +138 -138
- data/lib/kitchen/rake_tasks.rb +63 -63
- data/lib/kitchen/shell_out.rb +93 -93
- data/lib/kitchen/ssh.rb +276 -276
- data/lib/kitchen/state_file.rb +120 -120
- data/lib/kitchen/suite.rb +51 -51
- data/lib/kitchen/thor_tasks.rb +66 -66
- data/lib/kitchen/transport.rb +54 -54
- data/lib/kitchen/transport/base.rb +176 -176
- data/lib/kitchen/transport/dummy.rb +79 -79
- data/lib/kitchen/transport/ssh.rb +364 -364
- data/lib/kitchen/transport/winrm.rb +486 -486
- data/lib/kitchen/util.rb +147 -147
- data/lib/kitchen/verifier.rb +55 -55
- data/lib/kitchen/verifier/base.rb +235 -235
- data/lib/kitchen/verifier/busser.rb +277 -277
- data/lib/kitchen/verifier/dummy.rb +79 -79
- data/lib/kitchen/verifier/shell.rb +101 -101
- data/lib/kitchen/version.rb +21 -21
- data/lib/vendor/hash_recursive_merge.rb +82 -82
- data/spec/kitchen/base64_stream_spec.rb +77 -77
- data/spec/kitchen/cli_spec.rb +56 -56
- data/spec/kitchen/collection_spec.rb +80 -80
- data/spec/kitchen/color_spec.rb +54 -54
- data/spec/kitchen/config_spec.rb +408 -408
- data/spec/kitchen/configurable_spec.rb +1095 -1095
- data/spec/kitchen/data_munger_spec.rb +2694 -2694
- data/spec/kitchen/diagnostic_spec.rb +129 -129
- data/spec/kitchen/driver/base_spec.rb +121 -121
- data/spec/kitchen/driver/dummy_spec.rb +199 -199
- data/spec/kitchen/driver/proxy_spec.rb +138 -138
- data/spec/kitchen/driver/ssh_base_spec.rb +1115 -1115
- data/spec/kitchen/driver_spec.rb +112 -112
- data/spec/kitchen/errors_spec.rb +309 -309
- data/spec/kitchen/instance_spec.rb +1419 -1419
- data/spec/kitchen/lazy_hash_spec.rb +117 -117
- data/spec/kitchen/loader/yaml_spec.rb +774 -774
- data/spec/kitchen/logger_spec.rb +429 -429
- data/spec/kitchen/logging_spec.rb +59 -59
- data/spec/kitchen/login_command_spec.rb +68 -68
- data/spec/kitchen/metadata_chopper_spec.rb +82 -82
- data/spec/kitchen/platform_spec.rb +89 -89
- data/spec/kitchen/provisioner/base_spec.rb +386 -386
- data/spec/kitchen/provisioner/chef_apply_spec.rb +136 -136
- data/spec/kitchen/provisioner/chef_base_spec.rb +1161 -1161
- data/spec/kitchen/provisioner/chef_solo_spec.rb +557 -557
- data/spec/kitchen/provisioner/chef_zero_spec.rb +1001 -1001
- data/spec/kitchen/provisioner/dummy_spec.rb +99 -99
- data/spec/kitchen/provisioner/shell_spec.rb +566 -566
- data/spec/kitchen/provisioner_spec.rb +107 -107
- data/spec/kitchen/shell_out_spec.rb +150 -150
- data/spec/kitchen/ssh_spec.rb +693 -693
- data/spec/kitchen/state_file_spec.rb +129 -129
- data/spec/kitchen/suite_spec.rb +62 -62
- data/spec/kitchen/transport/base_spec.rb +89 -89
- data/spec/kitchen/transport/ssh_spec.rb +1255 -1255
- data/spec/kitchen/transport/winrm_spec.rb +1143 -1143
- data/spec/kitchen/transport_spec.rb +112 -112
- data/spec/kitchen/util_spec.rb +165 -165
- data/spec/kitchen/verifier/base_spec.rb +362 -362
- data/spec/kitchen/verifier/busser_spec.rb +610 -610
- data/spec/kitchen/verifier/dummy_spec.rb +99 -99
- data/spec/kitchen/verifier/shell_spec.rb +160 -160
- data/spec/kitchen/verifier_spec.rb +120 -120
- data/spec/kitchen_spec.rb +114 -114
- data/spec/spec_helper.rb +85 -85
- data/spec/support/powershell_max_size_spec.rb +40 -40
- data/support/busser_install_command.ps1 +14 -14
- data/support/busser_install_command.sh +14 -14
- data/support/chef-client-zero.rb +77 -77
- data/support/chef_base_init_command.ps1 +18 -18
- data/support/chef_base_init_command.sh +2 -2
- data/support/chef_base_install_command.ps1 +85 -85
- data/support/chef_base_install_command.sh +229 -229
- data/support/chef_zero_prepare_command_legacy.ps1 +9 -9
- data/support/chef_zero_prepare_command_legacy.sh +10 -10
- data/support/download_helpers.sh +109 -109
- data/support/dummy-validation.pem +27 -27
- data/templates/driver/CHANGELOG.md.erb +3 -3
- data/templates/driver/Gemfile.erb +3 -3
- data/templates/driver/README.md.erb +64 -64
- data/templates/driver/Rakefile.erb +21 -21
- data/templates/driver/driver.rb.erb +23 -23
- data/templates/driver/gemspec.erb +29 -29
- data/templates/driver/gitignore.erb +17 -17
- data/templates/driver/license_apachev2.erb +15 -15
- data/templates/driver/license_lgplv3.erb +16 -16
- data/templates/driver/license_mit.erb +22 -22
- data/templates/driver/license_reserved.erb +5 -5
- data/templates/driver/tailor.erb +4 -4
- data/templates/driver/travis.yml.erb +11 -11
- data/templates/driver/version.rb.erb +12 -12
- data/templates/init/chefignore.erb +1 -1
- data/templates/init/kitchen.yml.erb +18 -18
- data/test-kitchen.gemspec +62 -62
- data/test/integration/default/default_spec.rb +3 -3
- data/testing_windows.md +37 -37
- metadata +5 -4
|
@@ -1,136 +1,136 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
|
-
#
|
|
3
|
-
# Author:: SAWANOBORI Yukihiko <sawanoboriyu@higanworks.com>)
|
|
4
|
-
#
|
|
5
|
-
# Copyright (C) 2015, HiganWorks LLC
|
|
6
|
-
#
|
|
7
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
-
# you may not use this file except in compliance with the License.
|
|
9
|
-
# You may obtain a copy of the License at
|
|
10
|
-
#
|
|
11
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
-
#
|
|
13
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
-
# See the License for the specific language governing permissions and
|
|
17
|
-
# limitations under the License.
|
|
18
|
-
|
|
19
|
-
require_relative "../../spec_helper"
|
|
20
|
-
|
|
21
|
-
require "kitchen"
|
|
22
|
-
require "kitchen/provisioner/chef_apply"
|
|
23
|
-
|
|
24
|
-
describe Kitchen::Provisioner::ChefApply do
|
|
25
|
-
|
|
26
|
-
let(:logged_output) { StringIO.new }
|
|
27
|
-
let(:logger) { Logger.new(logged_output) }
|
|
28
|
-
let(:platform) { stub(:os_type => nil) }
|
|
29
|
-
let(:suite) { stub(:name => "fries") }
|
|
30
|
-
|
|
31
|
-
let(:config) do
|
|
32
|
-
{ :test_base_path => "/b", :kitchen_root => "/r" }
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
let(:instance) do
|
|
36
|
-
stub(
|
|
37
|
-
:name => "coolbeans",
|
|
38
|
-
:logger => logger,
|
|
39
|
-
:suite => suite,
|
|
40
|
-
:platform => platform
|
|
41
|
-
)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
let(:provisioner) do
|
|
45
|
-
Kitchen::Provisioner::ChefApply.new(config).finalize_config!(instance)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
it "provisioner api_version is 2" do
|
|
49
|
-
provisioner.diagnose_plugin[:api_version].must_equal 2
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
it "plugin_version is set to Kitchen::VERSION" do
|
|
53
|
-
provisioner.diagnose_plugin[:version].must_equal Kitchen::VERSION
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
describe "default config" do
|
|
57
|
-
|
|
58
|
-
it "sets :chef_apply_path to a path using :chef_omnibus_root" do
|
|
59
|
-
config[:chef_omnibus_root] = "/nice/place"
|
|
60
|
-
|
|
61
|
-
provisioner[:chef_apply_path].must_equal "/nice/place/bin/chef-apply"
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
describe "#create_sandbox" do
|
|
66
|
-
|
|
67
|
-
before do
|
|
68
|
-
@root = Dir.mktmpdir
|
|
69
|
-
config[:kitchen_root] = @root
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
after do
|
|
73
|
-
FileUtils.remove_entry(@root)
|
|
74
|
-
begin
|
|
75
|
-
provisioner.cleanup_sandbox
|
|
76
|
-
rescue # rubocop:disable Lint/HandleExceptions
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
describe "#run_command" do
|
|
82
|
-
|
|
83
|
-
before do
|
|
84
|
-
config[:run_list] = %w[appry_recipe1 appry_recipe2]
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
let(:cmd) { provisioner.run_command }
|
|
88
|
-
|
|
89
|
-
describe "for bourne shells" do
|
|
90
|
-
|
|
91
|
-
before { platform.stubs(:shell_type).returns("bourne") }
|
|
92
|
-
|
|
93
|
-
it "uses bourne shell" do
|
|
94
|
-
cmd.must_match(/\Ash -c '$/)
|
|
95
|
-
cmd.must_match(/'\Z/)
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
it "uses sudo for chef-apply when configured" do
|
|
99
|
-
config[:chef_omnibus_root] = "/c"
|
|
100
|
-
config[:sudo] = true
|
|
101
|
-
|
|
102
|
-
cmd.must_match regexify("sudo -E /c/bin/chef-apply apply/appry_recipe1.rb ", :partial_line)
|
|
103
|
-
cmd.must_match regexify("sudo -E /c/bin/chef-apply apply/appry_recipe2.rb ", :partial_line)
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
it "does not use sudo for chef-apply when configured" do
|
|
107
|
-
config[:chef_omnibus_root] = "/c"
|
|
108
|
-
config[:sudo] = false
|
|
109
|
-
|
|
110
|
-
cmd.must_match regexify("chef-apply apply/appry_recipe1.rb ", :partial_line)
|
|
111
|
-
cmd.must_match regexify("chef-apply apply/appry_recipe2.rb ", :partial_line)
|
|
112
|
-
cmd.wont_match regexify("sudo -E /c/bin/chef-apply ")
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
it "sets log level flag on chef-apply to auto by default" do
|
|
116
|
-
cmd.must_match regexify(" --log_level auto", :partial_line)
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
it "set log level flag for custom level" do
|
|
120
|
-
config[:log_level] = :extreme
|
|
121
|
-
|
|
122
|
-
cmd.must_match regexify(" --log_level extreme", :partial_line)
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
it "sets no color flag on chef-apply" do
|
|
126
|
-
cmd.must_match regexify(" --no-color", :partial_line)
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def regexify(str, line = :whole_line)
|
|
132
|
-
r = Regexp.escape(str)
|
|
133
|
-
r = "^\s*#{r}$" if line == :whole_line
|
|
134
|
-
Regexp.new(r)
|
|
135
|
-
end
|
|
136
|
-
end
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Author:: SAWANOBORI Yukihiko <sawanoboriyu@higanworks.com>)
|
|
4
|
+
#
|
|
5
|
+
# Copyright (C) 2015, HiganWorks LLC
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
|
|
19
|
+
require_relative "../../spec_helper"
|
|
20
|
+
|
|
21
|
+
require "kitchen"
|
|
22
|
+
require "kitchen/provisioner/chef_apply"
|
|
23
|
+
|
|
24
|
+
describe Kitchen::Provisioner::ChefApply do
|
|
25
|
+
|
|
26
|
+
let(:logged_output) { StringIO.new }
|
|
27
|
+
let(:logger) { Logger.new(logged_output) }
|
|
28
|
+
let(:platform) { stub(:os_type => nil) }
|
|
29
|
+
let(:suite) { stub(:name => "fries") }
|
|
30
|
+
|
|
31
|
+
let(:config) do
|
|
32
|
+
{ :test_base_path => "/b", :kitchen_root => "/r" }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
let(:instance) do
|
|
36
|
+
stub(
|
|
37
|
+
:name => "coolbeans",
|
|
38
|
+
:logger => logger,
|
|
39
|
+
:suite => suite,
|
|
40
|
+
:platform => platform
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
let(:provisioner) do
|
|
45
|
+
Kitchen::Provisioner::ChefApply.new(config).finalize_config!(instance)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "provisioner api_version is 2" do
|
|
49
|
+
provisioner.diagnose_plugin[:api_version].must_equal 2
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "plugin_version is set to Kitchen::VERSION" do
|
|
53
|
+
provisioner.diagnose_plugin[:version].must_equal Kitchen::VERSION
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
describe "default config" do
|
|
57
|
+
|
|
58
|
+
it "sets :chef_apply_path to a path using :chef_omnibus_root" do
|
|
59
|
+
config[:chef_omnibus_root] = "/nice/place"
|
|
60
|
+
|
|
61
|
+
provisioner[:chef_apply_path].must_equal "/nice/place/bin/chef-apply"
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe "#create_sandbox" do
|
|
66
|
+
|
|
67
|
+
before do
|
|
68
|
+
@root = Dir.mktmpdir
|
|
69
|
+
config[:kitchen_root] = @root
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
after do
|
|
73
|
+
FileUtils.remove_entry(@root)
|
|
74
|
+
begin
|
|
75
|
+
provisioner.cleanup_sandbox
|
|
76
|
+
rescue # rubocop:disable Lint/HandleExceptions
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
describe "#run_command" do
|
|
82
|
+
|
|
83
|
+
before do
|
|
84
|
+
config[:run_list] = %w[appry_recipe1 appry_recipe2]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
let(:cmd) { provisioner.run_command }
|
|
88
|
+
|
|
89
|
+
describe "for bourne shells" do
|
|
90
|
+
|
|
91
|
+
before { platform.stubs(:shell_type).returns("bourne") }
|
|
92
|
+
|
|
93
|
+
it "uses bourne shell" do
|
|
94
|
+
cmd.must_match(/\Ash -c '$/)
|
|
95
|
+
cmd.must_match(/'\Z/)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "uses sudo for chef-apply when configured" do
|
|
99
|
+
config[:chef_omnibus_root] = "/c"
|
|
100
|
+
config[:sudo] = true
|
|
101
|
+
|
|
102
|
+
cmd.must_match regexify("sudo -E /c/bin/chef-apply apply/appry_recipe1.rb ", :partial_line)
|
|
103
|
+
cmd.must_match regexify("sudo -E /c/bin/chef-apply apply/appry_recipe2.rb ", :partial_line)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "does not use sudo for chef-apply when configured" do
|
|
107
|
+
config[:chef_omnibus_root] = "/c"
|
|
108
|
+
config[:sudo] = false
|
|
109
|
+
|
|
110
|
+
cmd.must_match regexify("chef-apply apply/appry_recipe1.rb ", :partial_line)
|
|
111
|
+
cmd.must_match regexify("chef-apply apply/appry_recipe2.rb ", :partial_line)
|
|
112
|
+
cmd.wont_match regexify("sudo -E /c/bin/chef-apply ")
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "sets log level flag on chef-apply to auto by default" do
|
|
116
|
+
cmd.must_match regexify(" --log_level auto", :partial_line)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it "set log level flag for custom level" do
|
|
120
|
+
config[:log_level] = :extreme
|
|
121
|
+
|
|
122
|
+
cmd.must_match regexify(" --log_level extreme", :partial_line)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "sets no color flag on chef-apply" do
|
|
126
|
+
cmd.must_match regexify(" --no-color", :partial_line)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def regexify(str, line = :whole_line)
|
|
132
|
+
r = Regexp.escape(str)
|
|
133
|
+
r = "^\s*#{r}$" if line == :whole_line
|
|
134
|
+
Regexp.new(r)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -1,1161 +1,1161 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
|
-
#
|
|
3
|
-
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
4
|
-
#
|
|
5
|
-
# Copyright (C) 2014, Fletcher Nichol
|
|
6
|
-
#
|
|
7
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
-
# you may not use this file except in compliance with the License.
|
|
9
|
-
# You may obtain a copy of the License at
|
|
10
|
-
#
|
|
11
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
-
#
|
|
13
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
-
# See the License for the specific language governing permissions and
|
|
17
|
-
# limitations under the License.
|
|
18
|
-
|
|
19
|
-
require_relative "../../spec_helper"
|
|
20
|
-
|
|
21
|
-
require "kitchen"
|
|
22
|
-
require "kitchen/provisioner/chef_base"
|
|
23
|
-
|
|
24
|
-
describe Kitchen::Provisioner::ChefBase do
|
|
25
|
-
|
|
26
|
-
let(:logged_output) { StringIO.new }
|
|
27
|
-
let(:logger) { Logger.new(logged_output) }
|
|
28
|
-
let(:platform) { stub(:os_type => nil) }
|
|
29
|
-
let(:suite) { stub(:name => "fries") }
|
|
30
|
-
let(:default_version) { true }
|
|
31
|
-
|
|
32
|
-
let(:config) do
|
|
33
|
-
{ :test_base_path => "/basist", :kitchen_root => "/rooty" }
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
let(:instance) do
|
|
37
|
-
stub(
|
|
38
|
-
:name => "coolbeans",
|
|
39
|
-
:logger => logger,
|
|
40
|
-
:suite => suite,
|
|
41
|
-
:platform => platform
|
|
42
|
-
)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
let(:provisioner) do
|
|
46
|
-
Class.new(Kitchen::Provisioner::ChefBase) {
|
|
47
|
-
def calculate_path(path, _opts = {})
|
|
48
|
-
"<calculated>/#{path}"
|
|
49
|
-
end
|
|
50
|
-
}.new(config).finalize_config!(instance)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
describe "configuration" do
|
|
54
|
-
|
|
55
|
-
describe "for unix operating systems" do
|
|
56
|
-
|
|
57
|
-
before { platform.stubs(:os_type).returns("unix") }
|
|
58
|
-
|
|
59
|
-
it ":chef_omnibus_url has a default" do
|
|
60
|
-
provisioner[:chef_omnibus_url].
|
|
61
|
-
must_equal "https://www.chef.io/chef/install.sh"
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
it ":chef_metadata_url defaults to nil" do
|
|
65
|
-
provisioner[:chef_metadata_url].must_equal(nil)
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
describe "for windows operating systems" do
|
|
70
|
-
|
|
71
|
-
before { platform.stubs(:os_type).returns("windows") }
|
|
72
|
-
|
|
73
|
-
it ":chef_omnibus_url has a default" do
|
|
74
|
-
provisioner[:chef_omnibus_url].
|
|
75
|
-
must_equal "https://www.chef.io/chef/install.sh"
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
it ":require_chef_omnibus defaults to true" do
|
|
81
|
-
provisioner[:require_chef_omnibus].must_equal true
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
it ":chef_omnibus_install_options defaults to nil" do
|
|
85
|
-
provisioner[:chef_omnibus_install_options].must_equal nil
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
it ":run_list defaults to an empty array" do
|
|
89
|
-
provisioner[:run_list].must_equal []
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
it ":attributes defaults to an empty hash" do
|
|
93
|
-
provisioner[:attributes].must_equal Hash.new
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
it ":log_file defaults to nil" do
|
|
97
|
-
provisioner[:log_file].must_equal nil
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
it ":cookbook_files_glob includes recipes" do
|
|
101
|
-
provisioner[:cookbook_files_glob].must_match %r{,recipes/}
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
it ":data_path uses calculate_path and is expanded" do
|
|
105
|
-
provisioner[:data_path].
|
|
106
|
-
must_equal os_safe_root_path("/rooty/<calculated>/data")
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
it ":data_bags_path uses calculate_path and is expanded" do
|
|
110
|
-
provisioner[:data_bags_path].
|
|
111
|
-
must_equal os_safe_root_path("/rooty/<calculated>/data_bags")
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
it ":environments_path uses calculate_path and is expanded" do
|
|
115
|
-
provisioner[:environments_path].
|
|
116
|
-
must_equal os_safe_root_path("/rooty/<calculated>/environments")
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
it ":nodes_path uses calculate_path and is expanded" do
|
|
120
|
-
provisioner[:nodes_path].
|
|
121
|
-
must_equal os_safe_root_path("/rooty/<calculated>/nodes")
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
it ":roles_path uses calculate_path and is expanded" do
|
|
125
|
-
provisioner[:roles_path].
|
|
126
|
-
must_equal os_safe_root_path("/rooty/<calculated>/roles")
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
it ":clients_path uses calculate_path and is expanded" do
|
|
130
|
-
provisioner[:clients_path].
|
|
131
|
-
must_equal os_safe_root_path("/rooty/<calculated>/clients")
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
it "...secret_key_path uses calculate_path and is expanded" do
|
|
135
|
-
provisioner[:encrypted_data_bag_secret_key_path].
|
|
136
|
-
must_equal os_safe_root_path("/rooty/<calculated>/encrypted_data_bag_secret_key")
|
|
137
|
-
end
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
describe "#install_command" do
|
|
141
|
-
|
|
142
|
-
before do
|
|
143
|
-
platform.stubs(:shell_type).returns("bourne")
|
|
144
|
-
Mixlib::Install::ScriptGenerator.stubs(:new).returns(installer)
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
let(:installer) { stub(:root => "/rooty", :install_command => "make_it_so") }
|
|
148
|
-
|
|
149
|
-
let(:cmd) { provisioner.install_command }
|
|
150
|
-
|
|
151
|
-
let(:install_opts) {
|
|
152
|
-
{ :omnibus_url => "https://www.chef.io/chef/install.sh",
|
|
153
|
-
:project => nil, :install_flags => nil, :sudo_command => "sudo -E",
|
|
154
|
-
:http_proxy => nil, :https_proxy => nil }
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
it "returns nil if :require_chef_omnibus is falsey" do
|
|
158
|
-
config[:require_chef_omnibus] = false
|
|
159
|
-
|
|
160
|
-
installer.expects(:root).never
|
|
161
|
-
installer.expects(:install_command).never
|
|
162
|
-
cmd.must_equal nil
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
describe "common behaviour" do
|
|
166
|
-
before do
|
|
167
|
-
installer.expects(:root).at_least_once.returns("/opt/chef")
|
|
168
|
-
installer.expects(:install_command)
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
it "passes sensible defaults" do
|
|
172
|
-
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
173
|
-
with(default_version, false, install_opts).returns(installer)
|
|
174
|
-
cmd
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
it "exports http_proxy & HTTP_PROXY when :http_proxy is set" do
|
|
178
|
-
config[:http_proxy] = "http://proxy"
|
|
179
|
-
install_opts[:http_proxy] = "http://proxy"
|
|
180
|
-
|
|
181
|
-
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
182
|
-
with(default_version, false, install_opts).returns(installer)
|
|
183
|
-
cmd
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
it "exports https_proxy & HTTPS_PROXY when :https_proxy is set" do
|
|
187
|
-
config[:https_proxy] = "https://proxy"
|
|
188
|
-
install_opts[:https_proxy] = "https://proxy"
|
|
189
|
-
|
|
190
|
-
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
191
|
-
with(default_version, false, install_opts).returns(installer)
|
|
192
|
-
cmd
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
it "exports all http proxy variables when both are set" do
|
|
196
|
-
config[:http_proxy] = "http://proxy"
|
|
197
|
-
config[:https_proxy] = "https://proxy"
|
|
198
|
-
install_opts[:http_proxy] = "http://proxy"
|
|
199
|
-
install_opts[:https_proxy] = "https://proxy"
|
|
200
|
-
|
|
201
|
-
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
202
|
-
with(default_version, false, install_opts).returns(installer)
|
|
203
|
-
cmd
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
it "installs chef using :chef_omnibus_url, if necessary" do
|
|
207
|
-
config[:chef_omnibus_url] = "FROM_HERE"
|
|
208
|
-
install_opts[:omnibus_url] = "FROM_HERE"
|
|
209
|
-
|
|
210
|
-
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
211
|
-
with(default_version, false, install_opts).returns(installer)
|
|
212
|
-
cmd
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
it "will install a specific version of chef, if necessary" do
|
|
216
|
-
config[:require_chef_omnibus] = "1.2.3"
|
|
217
|
-
|
|
218
|
-
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
219
|
-
with("1.2.3", false, install_opts).returns(installer)
|
|
220
|
-
cmd
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
it "will install a major/minor version of chef, if necessary" do
|
|
224
|
-
config[:require_chef_omnibus] = "11.10"
|
|
225
|
-
|
|
226
|
-
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
227
|
-
with("11.10", false, install_opts).returns(installer)
|
|
228
|
-
cmd
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
it "will install a major version of chef, if necessary" do
|
|
232
|
-
config[:require_chef_omnibus] = "12"
|
|
233
|
-
|
|
234
|
-
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
235
|
-
with("12", false, install_opts).returns(installer)
|
|
236
|
-
cmd
|
|
237
|
-
end
|
|
238
|
-
|
|
239
|
-
it "will install a nightly, if necessary" do
|
|
240
|
-
config[:require_chef_omnibus] =
|
|
241
|
-
"12.5.0-current.0+20150721082808.git.14.c91b337-1"
|
|
242
|
-
|
|
243
|
-
Mixlib::Install::ScriptGenerator.expects(:new).with(
|
|
244
|
-
"12.5.0-current.0+20150721082808.git.14.c91b337-1",
|
|
245
|
-
false,
|
|
246
|
-
install_opts
|
|
247
|
-
).returns(installer)
|
|
248
|
-
cmd
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
it "will install the latest chef, if necessary" do
|
|
252
|
-
config[:require_chef_omnibus] = "latest"
|
|
253
|
-
|
|
254
|
-
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
255
|
-
with("latest", false, install_opts).returns(installer)
|
|
256
|
-
cmd
|
|
257
|
-
end
|
|
258
|
-
|
|
259
|
-
it "will install a version of chef, unless it exists" do
|
|
260
|
-
config[:require_chef_omnibus] = true
|
|
261
|
-
|
|
262
|
-
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
263
|
-
with(default_version, false, install_opts).returns(installer)
|
|
264
|
-
cmd
|
|
265
|
-
end
|
|
266
|
-
|
|
267
|
-
it "will pass a project, when given" do
|
|
268
|
-
config[:chef_omnibus_install_options] = "-P chefdk"
|
|
269
|
-
install_opts[:install_flags] = "-P chefdk"
|
|
270
|
-
install_opts[:project] = "chefdk"
|
|
271
|
-
|
|
272
|
-
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
273
|
-
with(default_version, false, install_opts).returns(installer)
|
|
274
|
-
cmd
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
it "will pass install options and version info, when given" do
|
|
278
|
-
config[:require_chef_omnibus] = "11"
|
|
279
|
-
config[:chef_omnibus_install_options] = "-d /tmp/place"
|
|
280
|
-
install_opts[:install_flags] = "-d /tmp/place"
|
|
281
|
-
|
|
282
|
-
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
283
|
-
with("11", false, install_opts).returns(installer)
|
|
284
|
-
cmd
|
|
285
|
-
end
|
|
286
|
-
|
|
287
|
-
it "will set the install root" do
|
|
288
|
-
config[:chef_omnibus_root] = "/tmp/test"
|
|
289
|
-
install_opts[:root] = "/tmp/test"
|
|
290
|
-
|
|
291
|
-
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
292
|
-
with(default_version, false, install_opts).returns(installer)
|
|
293
|
-
cmd
|
|
294
|
-
end
|
|
295
|
-
|
|
296
|
-
it "will set the msi url" do
|
|
297
|
-
config[:install_msi_url] = "http://blah/blah.msi"
|
|
298
|
-
install_opts[:install_msi_url] = "http://blah/blah.msi"
|
|
299
|
-
|
|
300
|
-
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
301
|
-
with(default_version, false, install_opts).returns(installer)
|
|
302
|
-
cmd
|
|
303
|
-
end
|
|
304
|
-
|
|
305
|
-
it "prefixs the whole command with the command_prefix if set" do
|
|
306
|
-
config[:command_prefix] = "my_prefix"
|
|
307
|
-
|
|
308
|
-
cmd.must_match(/\Amy_prefix /)
|
|
309
|
-
end
|
|
310
|
-
|
|
311
|
-
it "does not prefix the command if command_prefix is not set" do
|
|
312
|
-
config[:command_prefix] = nil
|
|
313
|
-
|
|
314
|
-
cmd.wont_match(/\Amy_prefix /)
|
|
315
|
-
end
|
|
316
|
-
end
|
|
317
|
-
|
|
318
|
-
describe "for product" do
|
|
319
|
-
before do
|
|
320
|
-
installer.expects(:root).at_least_once.returns("/opt/chef")
|
|
321
|
-
installer.expects(:install_command)
|
|
322
|
-
config[:product_name] = "my_product"
|
|
323
|
-
end
|
|
324
|
-
|
|
325
|
-
it "will set the product name, version and channel" do
|
|
326
|
-
config[:product_version] = "version"
|
|
327
|
-
config[:channel] = "channel"
|
|
328
|
-
|
|
329
|
-
Mixlib::Install.expects(:new).with do |opts|
|
|
330
|
-
opts[:product_name].must_equal "my_product"
|
|
331
|
-
opts[:product_version].must_equal "version"
|
|
332
|
-
opts[:channel].must_equal :channel
|
|
333
|
-
end.returns(installer)
|
|
334
|
-
cmd
|
|
335
|
-
end
|
|
336
|
-
|
|
337
|
-
it "will set the architecture if given" do
|
|
338
|
-
config[:architecture] = "architecture"
|
|
339
|
-
|
|
340
|
-
Mixlib::Install.expects(:new).with do |opts|
|
|
341
|
-
opts[:architecture].must_equal "architecture"
|
|
342
|
-
end.returns(installer)
|
|
343
|
-
cmd
|
|
344
|
-
end
|
|
345
|
-
|
|
346
|
-
it "will set the platform if given" do
|
|
347
|
-
config[:platform] = "platform"
|
|
348
|
-
|
|
349
|
-
Mixlib::Install.expects(:new).with do |opts|
|
|
350
|
-
opts[:platform].must_equal "platform"
|
|
351
|
-
end.returns(installer)
|
|
352
|
-
cmd
|
|
353
|
-
end
|
|
354
|
-
|
|
355
|
-
it "will set the platform_version if given" do
|
|
356
|
-
config[:platform_version] = "platform_version"
|
|
357
|
-
|
|
358
|
-
Mixlib::Install.expects(:new).with do |opts|
|
|
359
|
-
opts[:platform_version].must_equal "platform_version"
|
|
360
|
-
end.returns(installer)
|
|
361
|
-
cmd
|
|
362
|
-
end
|
|
363
|
-
|
|
364
|
-
it "will omit the architecture if not given" do
|
|
365
|
-
Mixlib::Install.expects(:new).with do |opts|
|
|
366
|
-
opts.key?(:architecture).must_equal false
|
|
367
|
-
end.returns(installer)
|
|
368
|
-
cmd
|
|
369
|
-
end
|
|
370
|
-
|
|
371
|
-
it "will omit the platform if not given" do
|
|
372
|
-
Mixlib::Install.expects(:new).with do |opts|
|
|
373
|
-
opts.key?(:platform).must_equal false
|
|
374
|
-
end.returns(installer)
|
|
375
|
-
cmd
|
|
376
|
-
end
|
|
377
|
-
|
|
378
|
-
it "will omit the platform_version if not given" do
|
|
379
|
-
Mixlib::Install.expects(:new).with do |opts|
|
|
380
|
-
opts.key?(:platform_version).must_equal false
|
|
381
|
-
end.returns(installer)
|
|
382
|
-
cmd
|
|
383
|
-
end
|
|
384
|
-
|
|
385
|
-
it "will use stable channel when none specified" do
|
|
386
|
-
Mixlib::Install.expects(:new).with do |opts|
|
|
387
|
-
opts[:channel].must_equal :stable
|
|
388
|
-
end.returns(installer)
|
|
389
|
-
cmd
|
|
390
|
-
end
|
|
391
|
-
end
|
|
392
|
-
|
|
393
|
-
describe "for bourne shells" do
|
|
394
|
-
before do
|
|
395
|
-
installer.expects(:root).at_least_once.returns("/opt/chef")
|
|
396
|
-
installer.expects(:install_command).returns("my_install_command")
|
|
397
|
-
end
|
|
398
|
-
|
|
399
|
-
it "prepends sudo for sh commands when :sudo is set" do
|
|
400
|
-
config[:sudo] = true
|
|
401
|
-
config[:sudo_command] = "my_sudo_command"
|
|
402
|
-
install_opts_clone = install_opts.clone
|
|
403
|
-
install_opts_clone[:sudo_command] = config[:sudo_command]
|
|
404
|
-
|
|
405
|
-
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
406
|
-
with(default_version, false, install_opts_clone).returns(installer)
|
|
407
|
-
cmd.must_equal "my_sudo_command my_install_command"
|
|
408
|
-
end
|
|
409
|
-
|
|
410
|
-
it "does not pass shell type for product based command" do
|
|
411
|
-
config[:product_name] = "product_name"
|
|
412
|
-
|
|
413
|
-
Mixlib::Install.expects(:new).with do |opts|
|
|
414
|
-
opts.key?(:shell_type).must_equal false
|
|
415
|
-
end.returns(installer)
|
|
416
|
-
cmd
|
|
417
|
-
end
|
|
418
|
-
|
|
419
|
-
it "does not sudo for sh commands when :sudo is falsey" do
|
|
420
|
-
config[:sudo] = false
|
|
421
|
-
|
|
422
|
-
install_opts_clone = install_opts.clone
|
|
423
|
-
install_opts_clone[:sudo_command] = ""
|
|
424
|
-
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
425
|
-
with(default_version, false, install_opts_clone).returns(installer)
|
|
426
|
-
cmd.must_equal "my_install_command"
|
|
427
|
-
end
|
|
428
|
-
end
|
|
429
|
-
|
|
430
|
-
describe "for powershell shells on windows os types" do
|
|
431
|
-
before do
|
|
432
|
-
installer.expects(:root).at_least_once.returns("/opt/chef")
|
|
433
|
-
installer.expects(:install_command)
|
|
434
|
-
platform.stubs(:shell_type).returns("powershell")
|
|
435
|
-
platform.stubs(:os_type).returns("windows")
|
|
436
|
-
end
|
|
437
|
-
|
|
438
|
-
it "sets the powershell flag for Mixlib::Install" do
|
|
439
|
-
install_opts_clone = install_opts.clone
|
|
440
|
-
install_opts_clone[:sudo_command] = ""
|
|
441
|
-
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
442
|
-
with(default_version, true, install_opts_clone).returns(installer)
|
|
443
|
-
cmd
|
|
444
|
-
end
|
|
445
|
-
|
|
446
|
-
it "passes ps1 shell type for product based command" do
|
|
447
|
-
config[:product_name] = "product_name"
|
|
448
|
-
|
|
449
|
-
Mixlib::Install.expects(:new).with do |opts|
|
|
450
|
-
opts[:shell_type].must_equal :ps1
|
|
451
|
-
end.returns(installer)
|
|
452
|
-
cmd
|
|
453
|
-
end
|
|
454
|
-
end
|
|
455
|
-
end
|
|
456
|
-
|
|
457
|
-
describe "#init_command" do
|
|
458
|
-
|
|
459
|
-
let(:cmd) { provisioner.init_command }
|
|
460
|
-
|
|
461
|
-
describe "common behavior" do
|
|
462
|
-
|
|
463
|
-
before { platform.stubs(:shell_type).returns("fake") }
|
|
464
|
-
|
|
465
|
-
it "prefixs the whole command with the command_prefix if set" do
|
|
466
|
-
config[:command_prefix] = "my_prefix"
|
|
467
|
-
|
|
468
|
-
cmd.must_match(/\Amy_prefix /)
|
|
469
|
-
end
|
|
470
|
-
|
|
471
|
-
it "does not prefix the command if command_prefix is not set" do
|
|
472
|
-
config[:command_prefix] = nil
|
|
473
|
-
|
|
474
|
-
cmd.wont_match(/\Amy_prefix /)
|
|
475
|
-
end
|
|
476
|
-
end
|
|
477
|
-
|
|
478
|
-
describe "for bourne shells" do
|
|
479
|
-
|
|
480
|
-
before { platform.stubs(:shell_type).returns("bourne") }
|
|
481
|
-
|
|
482
|
-
it "uses bourne shell" do
|
|
483
|
-
cmd.must_match(/\Ash -c '$/)
|
|
484
|
-
cmd.must_match(/'\Z/)
|
|
485
|
-
end
|
|
486
|
-
|
|
487
|
-
it "ends with a single quote" do
|
|
488
|
-
cmd.must_match(/'\Z/)
|
|
489
|
-
end
|
|
490
|
-
|
|
491
|
-
it "exports http_proxy & HTTP_PROXY when :http_proxy is set" do
|
|
492
|
-
config[:http_proxy] = "http://proxy"
|
|
493
|
-
|
|
494
|
-
cmd.lines.to_a[1..2].must_equal([
|
|
495
|
-
%{http_proxy="http://proxy"; export http_proxy\n},
|
|
496
|
-
%{HTTP_PROXY="http://proxy"; export HTTP_PROXY\n}
|
|
497
|
-
])
|
|
498
|
-
end
|
|
499
|
-
|
|
500
|
-
it "exports https_proxy & HTTPS_PROXY when :https_proxy is set" do
|
|
501
|
-
config[:https_proxy] = "https://proxy"
|
|
502
|
-
|
|
503
|
-
cmd.lines.to_a[1..2].must_equal([
|
|
504
|
-
%{https_proxy="https://proxy"; export https_proxy\n},
|
|
505
|
-
%{HTTPS_PROXY="https://proxy"; export HTTPS_PROXY\n}
|
|
506
|
-
])
|
|
507
|
-
end
|
|
508
|
-
|
|
509
|
-
it "exports all http proxy variables when both are set" do
|
|
510
|
-
config[:http_proxy] = "http://proxy"
|
|
511
|
-
config[:https_proxy] = "https://proxy"
|
|
512
|
-
|
|
513
|
-
cmd.lines.to_a[1..4].must_equal([
|
|
514
|
-
%{http_proxy="http://proxy"; export http_proxy\n},
|
|
515
|
-
%{HTTP_PROXY="http://proxy"; export HTTP_PROXY\n},
|
|
516
|
-
%{https_proxy="https://proxy"; export https_proxy\n},
|
|
517
|
-
%{HTTPS_PROXY="https://proxy"; export HTTPS_PROXY\n}
|
|
518
|
-
])
|
|
519
|
-
end
|
|
520
|
-
|
|
521
|
-
it "prepends sudo for rm when :sudo is set" do
|
|
522
|
-
config[:sudo] = true
|
|
523
|
-
|
|
524
|
-
cmd.must_match regexify(%{sudo_rm="sudo -E rm"})
|
|
525
|
-
end
|
|
526
|
-
|
|
527
|
-
it "does not sudo for sh commands when :sudo is falsey" do
|
|
528
|
-
config[:sudo] = false
|
|
529
|
-
|
|
530
|
-
cmd.must_match regexify(%{sudo_rm="rm"})
|
|
531
|
-
end
|
|
532
|
-
|
|
533
|
-
it "sets chef component dirs for deletion" do
|
|
534
|
-
config[:root_path] = "/route"
|
|
535
|
-
dirs = %W[
|
|
536
|
-
/route/clients /route/cookbooks /route/data /route/data_bags
|
|
537
|
-
/route/encrypted_data_bag_secret /route/environments /route/roles
|
|
538
|
-
].join(" ")
|
|
539
|
-
|
|
540
|
-
cmd.must_match regexify(%{dirs="#{dirs}"})
|
|
541
|
-
end
|
|
542
|
-
|
|
543
|
-
it "sets the root_path from :root_path" do
|
|
544
|
-
config[:root_path] = "RIGHT_HERE"
|
|
545
|
-
|
|
546
|
-
cmd.must_match regexify(%{root_path="RIGHT_HERE"})
|
|
547
|
-
end
|
|
548
|
-
end
|
|
549
|
-
|
|
550
|
-
describe "for powershell shells on windows os types" do
|
|
551
|
-
|
|
552
|
-
before do
|
|
553
|
-
platform.stubs(:shell_type).returns("powershell")
|
|
554
|
-
platform.stubs(:os_type).returns("windows")
|
|
555
|
-
end
|
|
556
|
-
|
|
557
|
-
it "exports http_proxy & HTTP_PROXY when :http_proxy is set" do
|
|
558
|
-
config[:http_proxy] = "http://proxy"
|
|
559
|
-
|
|
560
|
-
cmd.lines.to_a[0..1].must_equal([
|
|
561
|
-
%{$env:http_proxy = "http://proxy"\n},
|
|
562
|
-
%{$env:HTTP_PROXY = "http://proxy"\n}
|
|
563
|
-
])
|
|
564
|
-
end
|
|
565
|
-
|
|
566
|
-
it "exports https_proxy & HTTPS_PROXY when :https_proxy is set" do
|
|
567
|
-
config[:https_proxy] = "https://proxy"
|
|
568
|
-
|
|
569
|
-
cmd.lines.to_a[0..1].must_equal([
|
|
570
|
-
%{$env:https_proxy = "https://proxy"\n},
|
|
571
|
-
%{$env:HTTPS_PROXY = "https://proxy"\n}
|
|
572
|
-
])
|
|
573
|
-
end
|
|
574
|
-
|
|
575
|
-
it "exports all http proxy variables when both are set" do
|
|
576
|
-
config[:http_proxy] = "http://proxy"
|
|
577
|
-
config[:https_proxy] = "https://proxy"
|
|
578
|
-
|
|
579
|
-
cmd.lines.to_a[0..3].must_equal([
|
|
580
|
-
%{$env:http_proxy = "http://proxy"\n},
|
|
581
|
-
%{$env:HTTP_PROXY = "http://proxy"\n},
|
|
582
|
-
%{$env:https_proxy = "https://proxy"\n},
|
|
583
|
-
%{$env:HTTPS_PROXY = "https://proxy"\n}
|
|
584
|
-
])
|
|
585
|
-
end
|
|
586
|
-
|
|
587
|
-
it "sets chef component dirs for deletion" do
|
|
588
|
-
config[:root_path] = "\\route"
|
|
589
|
-
dirs = %W[
|
|
590
|
-
"\\route\\clients" "\\route\\cookbooks" "\\route\\data"
|
|
591
|
-
"\\route\\data_bags" "\\route\\encrypted_data_bag_secret"
|
|
592
|
-
"\\route\\environments" "\\route\\roles"
|
|
593
|
-
].join(", ")
|
|
594
|
-
|
|
595
|
-
cmd.must_match regexify(%{$dirs = @(#{dirs})})
|
|
596
|
-
end
|
|
597
|
-
|
|
598
|
-
it "sets the root_path from :root_path" do
|
|
599
|
-
config[:root_path] = "RIGHT_HERE"
|
|
600
|
-
|
|
601
|
-
cmd.must_match regexify(%{$root_path = "RIGHT_HERE"})
|
|
602
|
-
end
|
|
603
|
-
end
|
|
604
|
-
end
|
|
605
|
-
|
|
606
|
-
describe "#create_sandbox" do
|
|
607
|
-
|
|
608
|
-
before do
|
|
609
|
-
@root = Dir.mktmpdir
|
|
610
|
-
config[:kitchen_root] = @root
|
|
611
|
-
end
|
|
612
|
-
|
|
613
|
-
after do
|
|
614
|
-
FileUtils.remove_entry(@root)
|
|
615
|
-
begin
|
|
616
|
-
provisioner.cleanup_sandbox
|
|
617
|
-
rescue # rubocop:disable Lint/HandleExceptions
|
|
618
|
-
end
|
|
619
|
-
end
|
|
620
|
-
|
|
621
|
-
let(:provisioner) do
|
|
622
|
-
Class.new(Kitchen::Provisioner::ChefBase) {
|
|
623
|
-
default_config :generic_rb, {}
|
|
624
|
-
|
|
625
|
-
def create_sandbox
|
|
626
|
-
super
|
|
627
|
-
|
|
628
|
-
data = default_config_rb.merge(config[:generic_rb])
|
|
629
|
-
File.open(File.join(sandbox_path, "generic.rb"), "wb") do |file|
|
|
630
|
-
file.write(format_config_file(data))
|
|
631
|
-
end
|
|
632
|
-
end
|
|
633
|
-
}.new(config).finalize_config!(instance)
|
|
634
|
-
end
|
|
635
|
-
|
|
636
|
-
describe "json file" do
|
|
637
|
-
|
|
638
|
-
let(:json) { JSON.parse(IO.read(sandbox_path("dna.json"))) }
|
|
639
|
-
|
|
640
|
-
it "creates a json file with node attributes" do
|
|
641
|
-
config[:attributes] = { "one" => { "two" => "three" } }
|
|
642
|
-
provisioner.create_sandbox
|
|
643
|
-
|
|
644
|
-
json["one"].must_equal("two" => "three")
|
|
645
|
-
end
|
|
646
|
-
|
|
647
|
-
it "creates a json file with run_list" do
|
|
648
|
-
config[:run_list] = %w[alpha bravo charlie]
|
|
649
|
-
provisioner.create_sandbox
|
|
650
|
-
|
|
651
|
-
json["run_list"].must_equal %w[alpha bravo charlie]
|
|
652
|
-
end
|
|
653
|
-
|
|
654
|
-
it "creates a json file with an empty run_list" do
|
|
655
|
-
config[:run_list] = []
|
|
656
|
-
provisioner.create_sandbox
|
|
657
|
-
|
|
658
|
-
json["run_list"].must_equal []
|
|
659
|
-
end
|
|
660
|
-
|
|
661
|
-
it "logs a message on info" do
|
|
662
|
-
provisioner.create_sandbox
|
|
663
|
-
|
|
664
|
-
logged_output.string.must_match info_line("Preparing dna.json")
|
|
665
|
-
end
|
|
666
|
-
|
|
667
|
-
it "logs a message on debug" do
|
|
668
|
-
config[:run_list] = ["yo"]
|
|
669
|
-
provisioner.create_sandbox
|
|
670
|
-
|
|
671
|
-
logged_output.string.
|
|
672
|
-
must_match debug_line(%|Creating dna.json from {:run_list=>["yo"]}|)
|
|
673
|
-
end
|
|
674
|
-
end
|
|
675
|
-
|
|
676
|
-
it "creates a cache directory" do
|
|
677
|
-
provisioner.create_sandbox
|
|
678
|
-
|
|
679
|
-
sandbox_path("cache").directory?.must_equal true
|
|
680
|
-
end
|
|
681
|
-
|
|
682
|
-
%w[data data_bags environments nodes roles clients].each do |thing|
|
|
683
|
-
describe "#{thing} files" do
|
|
684
|
-
|
|
685
|
-
before do
|
|
686
|
-
create_files_under("#{config[:kitchen_root]}/my_#{thing}")
|
|
687
|
-
config[:"#{thing}_path"] = "#{config[:kitchen_root]}/my_#{thing}"
|
|
688
|
-
end
|
|
689
|
-
|
|
690
|
-
it "skips directory creation if :#{thing}_path is not set" do
|
|
691
|
-
config[:"#{thing}_path"] = nil
|
|
692
|
-
provisioner.create_sandbox
|
|
693
|
-
|
|
694
|
-
sandbox_path(thing).directory?.must_equal false
|
|
695
|
-
end
|
|
696
|
-
|
|
697
|
-
it "copies tree from :#{thing}_path into sandbox" do
|
|
698
|
-
provisioner.create_sandbox
|
|
699
|
-
|
|
700
|
-
sandbox_path("#{thing}/alpha.txt").file?.must_equal true
|
|
701
|
-
IO.read(sandbox_path("#{thing}/alpha.txt")).must_equal "stuff"
|
|
702
|
-
sandbox_path("#{thing}/sub").directory?.must_equal true
|
|
703
|
-
sandbox_path("#{thing}/sub/bravo.txt").file?.must_equal true
|
|
704
|
-
IO.read(sandbox_path("#{thing}/sub/bravo.txt")).must_equal "junk"
|
|
705
|
-
end
|
|
706
|
-
|
|
707
|
-
it "logs a message on info" do
|
|
708
|
-
provisioner.create_sandbox
|
|
709
|
-
|
|
710
|
-
logged_output.string.must_match info_line("Preparing #{thing}")
|
|
711
|
-
end
|
|
712
|
-
|
|
713
|
-
it "logs a message on debug" do
|
|
714
|
-
provisioner.create_sandbox
|
|
715
|
-
|
|
716
|
-
logged_output.string.must_match debug_line(
|
|
717
|
-
"Using #{thing} from #{config[:kitchen_root]}/my_#{thing}")
|
|
718
|
-
end
|
|
719
|
-
end
|
|
720
|
-
end
|
|
721
|
-
|
|
722
|
-
describe "secret files" do
|
|
723
|
-
|
|
724
|
-
before do
|
|
725
|
-
config[:encrypted_data_bag_secret_key_path] =
|
|
726
|
-
"#{config[:kitchen_root]}/my_secret"
|
|
727
|
-
File.open("#{config[:kitchen_root]}/my_secret", "wb") do |file|
|
|
728
|
-
file.write("p@ss")
|
|
729
|
-
end
|
|
730
|
-
end
|
|
731
|
-
|
|
732
|
-
it "skips file if :encrypted_data_bag_secret_key_path is not set" do
|
|
733
|
-
config[:encrypted_data_bag_secret_key_path] = nil
|
|
734
|
-
provisioner.create_sandbox
|
|
735
|
-
|
|
736
|
-
sandbox_path("encrypted_data_bag_secret").file?.must_equal false
|
|
737
|
-
end
|
|
738
|
-
|
|
739
|
-
it "copies file from :encrypted_data_bag_secret_key_path into sandbox" do
|
|
740
|
-
provisioner.create_sandbox
|
|
741
|
-
|
|
742
|
-
sandbox_path("encrypted_data_bag_secret").file?.must_equal true
|
|
743
|
-
IO.read(sandbox_path("encrypted_data_bag_secret")).must_equal "p@ss"
|
|
744
|
-
end
|
|
745
|
-
|
|
746
|
-
it "logs a message on info" do
|
|
747
|
-
provisioner.create_sandbox
|
|
748
|
-
|
|
749
|
-
logged_output.string.must_match info_line("Preparing secret")
|
|
750
|
-
end
|
|
751
|
-
|
|
752
|
-
it "logs a message on debug" do
|
|
753
|
-
provisioner.create_sandbox
|
|
754
|
-
|
|
755
|
-
logged_output.string.must_match debug_line(
|
|
756
|
-
"Using secret from #{config[:kitchen_root]}/my_secret")
|
|
757
|
-
end
|
|
758
|
-
end
|
|
759
|
-
|
|
760
|
-
describe "cookbooks" do
|
|
761
|
-
|
|
762
|
-
let(:kitchen_root) { config[:kitchen_root] }
|
|
763
|
-
|
|
764
|
-
describe "with a cookbooks/ directory under kitchen_root" do
|
|
765
|
-
|
|
766
|
-
it "copies cookbooks/" do
|
|
767
|
-
create_cookbook("#{kitchen_root}/cookbooks/epache")
|
|
768
|
-
create_cookbook("#{kitchen_root}/cookbooks/jahva")
|
|
769
|
-
provisioner.create_sandbox
|
|
770
|
-
|
|
771
|
-
sandbox_path("cookbooks/epache").directory?.must_equal true
|
|
772
|
-
sandbox_path("cookbooks/epache/recipes/default.rb").
|
|
773
|
-
file?.must_equal true
|
|
774
|
-
sandbox_path("cookbooks/jahva").directory?.must_equal true
|
|
775
|
-
sandbox_path("cookbooks/jahva/recipes/default.rb").
|
|
776
|
-
file?.must_equal true
|
|
777
|
-
end
|
|
778
|
-
|
|
779
|
-
it "copies from kitchen_root as cookbook if it contains metadata.rb" do
|
|
780
|
-
File.open("#{kitchen_root}/metadata.rb", "wb") do |file|
|
|
781
|
-
file.write("name 'wat'")
|
|
782
|
-
end
|
|
783
|
-
create_cookbook("#{kitchen_root}/cookbooks/bk")
|
|
784
|
-
provisioner.create_sandbox
|
|
785
|
-
|
|
786
|
-
sandbox_path("cookbooks/bk").directory?.must_equal true
|
|
787
|
-
sandbox_path("cookbooks/wat").directory?.must_equal true
|
|
788
|
-
sandbox_path("cookbooks/wat/metadata.rb").file?.must_equal true
|
|
789
|
-
end
|
|
790
|
-
|
|
791
|
-
it "copies site-cookbooks/ if it exists" do
|
|
792
|
-
create_cookbook("#{kitchen_root}/cookbooks/upstream")
|
|
793
|
-
create_cookbook("#{kitchen_root}/site-cookbooks/mine")
|
|
794
|
-
provisioner.create_sandbox
|
|
795
|
-
|
|
796
|
-
sandbox_path("cookbooks/upstream").directory?.must_equal true
|
|
797
|
-
sandbox_path("cookbooks/mine").directory?.must_equal true
|
|
798
|
-
sandbox_path("cookbooks/mine/attributes/all.rb").file?.must_equal true
|
|
799
|
-
end
|
|
800
|
-
|
|
801
|
-
it "logs a message on info for cookbooks/ directory" do
|
|
802
|
-
create_cookbook("#{kitchen_root}/cookbooks/epache")
|
|
803
|
-
provisioner.create_sandbox
|
|
804
|
-
|
|
805
|
-
logged_output.string.must_match info_line(
|
|
806
|
-
"Preparing cookbooks from project directory")
|
|
807
|
-
end
|
|
808
|
-
|
|
809
|
-
it "logs a meesage on debug for cookbooks/ directory" do
|
|
810
|
-
create_cookbook("#{kitchen_root}/cookbooks/epache")
|
|
811
|
-
provisioner.create_sandbox
|
|
812
|
-
|
|
813
|
-
logged_output.string.must_match debug_line(
|
|
814
|
-
"Using cookbooks from #{kitchen_root}/cookbooks")
|
|
815
|
-
end
|
|
816
|
-
|
|
817
|
-
it "logs a message on info for site-cookbooks/ directory" do
|
|
818
|
-
create_cookbook("#{kitchen_root}/cookbooks/epache")
|
|
819
|
-
create_cookbook("#{kitchen_root}/site-cookbooks/mine")
|
|
820
|
-
provisioner.create_sandbox
|
|
821
|
-
|
|
822
|
-
logged_output.string.must_match info_line(
|
|
823
|
-
"Preparing site-cookbooks from project directory")
|
|
824
|
-
end
|
|
825
|
-
|
|
826
|
-
it "logs a meesage on debug for site-cookbooks/ directory" do
|
|
827
|
-
create_cookbook("#{kitchen_root}/cookbooks/epache")
|
|
828
|
-
create_cookbook("#{kitchen_root}/site-cookbooks/mine")
|
|
829
|
-
provisioner.create_sandbox
|
|
830
|
-
|
|
831
|
-
logged_output.string.must_match debug_line(
|
|
832
|
-
"Using cookbooks from #{kitchen_root}/site-cookbooks")
|
|
833
|
-
end
|
|
834
|
-
end
|
|
835
|
-
|
|
836
|
-
describe "with a cookbook as the project" do
|
|
837
|
-
|
|
838
|
-
before do
|
|
839
|
-
File.open("#{kitchen_root}/metadata.rb", "wb") do |file|
|
|
840
|
-
file.write("name 'wat'")
|
|
841
|
-
end
|
|
842
|
-
end
|
|
843
|
-
|
|
844
|
-
it "copies from kitchen_root as cookbook if it contains metadata.rb" do
|
|
845
|
-
provisioner.create_sandbox
|
|
846
|
-
|
|
847
|
-
sandbox_path("cookbooks/wat").directory?.must_equal true
|
|
848
|
-
sandbox_path("cookbooks/wat/metadata.rb").file?.must_equal true
|
|
849
|
-
end
|
|
850
|
-
|
|
851
|
-
it "logs a message on info" do
|
|
852
|
-
provisioner.create_sandbox
|
|
853
|
-
|
|
854
|
-
logged_output.string.must_match info_line(
|
|
855
|
-
"Preparing current project directory as a cookbook")
|
|
856
|
-
end
|
|
857
|
-
|
|
858
|
-
it "logs a meesage on debug" do
|
|
859
|
-
provisioner.create_sandbox
|
|
860
|
-
|
|
861
|
-
logged_output.string.must_match debug_line(
|
|
862
|
-
"Using metadata.rb from #{kitchen_root}/metadata.rb")
|
|
863
|
-
end
|
|
864
|
-
|
|
865
|
-
it "raises a UserError is name cannot be determined from metadata.rb" do
|
|
866
|
-
File.open("#{kitchen_root}/metadata.rb", "wb") do |file|
|
|
867
|
-
file.write("nameeeeee 'wat'")
|
|
868
|
-
end
|
|
869
|
-
|
|
870
|
-
proc { provisioner.create_sandbox }.must_raise Kitchen::UserError
|
|
871
|
-
end
|
|
872
|
-
end
|
|
873
|
-
|
|
874
|
-
describe "with no referenced cookbooks" do
|
|
875
|
-
|
|
876
|
-
it "makes a fake cookbook" do
|
|
877
|
-
name = File.basename(@root)
|
|
878
|
-
provisioner.create_sandbox
|
|
879
|
-
|
|
880
|
-
sandbox_path("cookbooks/#{name}").directory?.must_equal true
|
|
881
|
-
sandbox_path("cookbooks/#{name}/metadata.rb").file?.must_equal true
|
|
882
|
-
IO.read(sandbox_path("cookbooks/#{name}/metadata.rb")).
|
|
883
|
-
must_equal %{name "#{name}"\n}
|
|
884
|
-
end
|
|
885
|
-
|
|
886
|
-
it "logs a warning" do
|
|
887
|
-
provisioner.create_sandbox
|
|
888
|
-
|
|
889
|
-
logged_output.string.must_match regexify(
|
|
890
|
-
"Berksfile, Cheffile, cookbooks/, or metadata.rb not found",
|
|
891
|
-
:partial_line
|
|
892
|
-
)
|
|
893
|
-
end
|
|
894
|
-
end
|
|
895
|
-
|
|
896
|
-
describe "with a Berksfile under kitchen_root" do
|
|
897
|
-
|
|
898
|
-
let(:resolver) { stub(:resolve => true) }
|
|
899
|
-
|
|
900
|
-
before do
|
|
901
|
-
File.open("#{kitchen_root}/Berksfile", "wb") do |file|
|
|
902
|
-
file.write("cookbook 'wat'")
|
|
903
|
-
end
|
|
904
|
-
Kitchen::Provisioner::Chef::Berkshelf.stubs(:new).returns(resolver)
|
|
905
|
-
end
|
|
906
|
-
|
|
907
|
-
it "raises a UserError if Berkshelf library can't be loaded" do
|
|
908
|
-
proc { provisioner }.must_raise Kitchen::UserError
|
|
909
|
-
end
|
|
910
|
-
|
|
911
|
-
it "logs on debug that Berkshelf is loading" do
|
|
912
|
-
Kitchen::Provisioner::Chef::Berkshelf.stubs(:load!)
|
|
913
|
-
provisioner
|
|
914
|
-
|
|
915
|
-
logged_output.string.must_match debug_line(
|
|
916
|
-
"Berksfile found at #{kitchen_root}/Berksfile, loading Berkshelf")
|
|
917
|
-
end
|
|
918
|
-
|
|
919
|
-
it "uses Berkshelf" do
|
|
920
|
-
Kitchen::Provisioner::Chef::Berkshelf.stubs(:load!)
|
|
921
|
-
resolver.expects(:resolve)
|
|
922
|
-
|
|
923
|
-
provisioner.create_sandbox
|
|
924
|
-
end
|
|
925
|
-
|
|
926
|
-
it "uses Kitchen.mutex for resolving" do
|
|
927
|
-
Kitchen::Provisioner::Chef::Berkshelf.stubs(:load!)
|
|
928
|
-
Kitchen.mutex.expects(:synchronize)
|
|
929
|
-
|
|
930
|
-
provisioner.create_sandbox
|
|
931
|
-
end
|
|
932
|
-
end
|
|
933
|
-
|
|
934
|
-
describe "with a Cheffile under kitchen_root" do
|
|
935
|
-
|
|
936
|
-
let(:resolver) { stub(:resolve => true) }
|
|
937
|
-
|
|
938
|
-
before do
|
|
939
|
-
File.open("#{kitchen_root}/Cheffile", "wb") do |file|
|
|
940
|
-
file.write("cookbook 'wat'")
|
|
941
|
-
end
|
|
942
|
-
Kitchen::Provisioner::Chef::Librarian.stubs(:new).returns(resolver)
|
|
943
|
-
end
|
|
944
|
-
|
|
945
|
-
it "raises a UserError if Librarian library can't be loaded" do
|
|
946
|
-
proc { provisioner }.must_raise Kitchen::UserError
|
|
947
|
-
end
|
|
948
|
-
|
|
949
|
-
it "logs on debug that Berkshelf is loading" do
|
|
950
|
-
Kitchen::Provisioner::Chef::Librarian.stubs(:load!)
|
|
951
|
-
provisioner
|
|
952
|
-
|
|
953
|
-
logged_output.string.must_match debug_line(
|
|
954
|
-
"Cheffile found at #{kitchen_root}/Cheffile, loading Librarian-Chef"
|
|
955
|
-
)
|
|
956
|
-
end
|
|
957
|
-
|
|
958
|
-
it "uses Librarian" do
|
|
959
|
-
Kitchen::Provisioner::Chef::Librarian.stubs(:load!)
|
|
960
|
-
resolver.expects(:resolve)
|
|
961
|
-
|
|
962
|
-
provisioner.create_sandbox
|
|
963
|
-
end
|
|
964
|
-
|
|
965
|
-
it "uses Kitchen.mutex for resolving" do
|
|
966
|
-
Kitchen::Provisioner::Chef::Librarian.stubs(:load!)
|
|
967
|
-
Kitchen.mutex.expects(:synchronize)
|
|
968
|
-
|
|
969
|
-
provisioner.create_sandbox
|
|
970
|
-
end
|
|
971
|
-
end
|
|
972
|
-
|
|
973
|
-
describe "filtering cookbooks files" do
|
|
974
|
-
|
|
975
|
-
it "retains all useful cookbook files" do
|
|
976
|
-
create_full_cookbook("#{kitchen_root}/cookbooks/full")
|
|
977
|
-
provisioner.create_sandbox
|
|
978
|
-
|
|
979
|
-
full_cookbook_files.each do |file|
|
|
980
|
-
sandbox_path("cookbooks/full/#{file}").file?.must_equal true
|
|
981
|
-
end
|
|
982
|
-
end
|
|
983
|
-
|
|
984
|
-
it "strips extra cookbook files" do
|
|
985
|
-
extras = %w[
|
|
986
|
-
.gitignore tmp/librarian chefignore .git/info/excludes
|
|
987
|
-
cookbooks/another/metadata.rb CONTRIBUTING.md metadata.py
|
|
988
|
-
]
|
|
989
|
-
|
|
990
|
-
create_full_cookbook("#{kitchen_root}/cookbooks/full")
|
|
991
|
-
extras.each do |file|
|
|
992
|
-
create_file("#{kitchen_root}/cookbooks/full/#{file}")
|
|
993
|
-
end
|
|
994
|
-
provisioner.create_sandbox
|
|
995
|
-
|
|
996
|
-
extras.each do |file|
|
|
997
|
-
sandbox_path("cookbooks/full/#{file}").file?.must_equal false
|
|
998
|
-
end
|
|
999
|
-
end
|
|
1000
|
-
|
|
1001
|
-
it "logs on info" do
|
|
1002
|
-
create_full_cookbook("#{kitchen_root}/cookbooks/full")
|
|
1003
|
-
provisioner.create_sandbox
|
|
1004
|
-
|
|
1005
|
-
logged_output.string.must_match info_line(
|
|
1006
|
-
"Removing non-cookbook files before transfer")
|
|
1007
|
-
end
|
|
1008
|
-
end
|
|
1009
|
-
|
|
1010
|
-
describe "Chef config files" do
|
|
1011
|
-
|
|
1012
|
-
let(:file) do
|
|
1013
|
-
IO.read(sandbox_path("generic.rb")).lines.map(&:chomp)
|
|
1014
|
-
end
|
|
1015
|
-
|
|
1016
|
-
it "#create_sanbox creates a generic.rb" do
|
|
1017
|
-
provisioner.create_sandbox
|
|
1018
|
-
|
|
1019
|
-
sandbox_path("generic.rb").file?.must_equal true
|
|
1020
|
-
end
|
|
1021
|
-
|
|
1022
|
-
describe "defaults" do
|
|
1023
|
-
|
|
1024
|
-
before { provisioner.create_sandbox }
|
|
1025
|
-
|
|
1026
|
-
it "sets node_name to the instance name" do
|
|
1027
|
-
file.must_include %{node_name "#{instance.name}"}
|
|
1028
|
-
end
|
|
1029
|
-
|
|
1030
|
-
it "sets checksum_path" do
|
|
1031
|
-
file.must_include %{checksum_path "/tmp/kitchen/checksums"}
|
|
1032
|
-
end
|
|
1033
|
-
|
|
1034
|
-
it "sets file_backup_path" do
|
|
1035
|
-
file.must_include %{file_backup_path "/tmp/kitchen/backup"}
|
|
1036
|
-
end
|
|
1037
|
-
|
|
1038
|
-
it "sets cookbook_path" do
|
|
1039
|
-
file.must_include %{cookbook_path } +
|
|
1040
|
-
%{["/tmp/kitchen/cookbooks", "/tmp/kitchen/site-cookbooks"]}
|
|
1041
|
-
end
|
|
1042
|
-
|
|
1043
|
-
it "sets data_bag_path" do
|
|
1044
|
-
file.must_include %{data_bag_path "/tmp/kitchen/data_bags"}
|
|
1045
|
-
end
|
|
1046
|
-
|
|
1047
|
-
it "sets environment_path" do
|
|
1048
|
-
file.must_include %{environment_path "/tmp/kitchen/environments"}
|
|
1049
|
-
end
|
|
1050
|
-
|
|
1051
|
-
it "sets node_path" do
|
|
1052
|
-
file.must_include %{node_path "/tmp/kitchen/nodes"}
|
|
1053
|
-
end
|
|
1054
|
-
|
|
1055
|
-
it "sets role_path" do
|
|
1056
|
-
file.must_include %{role_path "/tmp/kitchen/roles"}
|
|
1057
|
-
end
|
|
1058
|
-
|
|
1059
|
-
it "sets client_path" do
|
|
1060
|
-
file.must_include %{client_path "/tmp/kitchen/clients"}
|
|
1061
|
-
end
|
|
1062
|
-
|
|
1063
|
-
it "sets user_path" do
|
|
1064
|
-
file.must_include %{user_path "/tmp/kitchen/users"}
|
|
1065
|
-
end
|
|
1066
|
-
|
|
1067
|
-
it "sets validation_key" do
|
|
1068
|
-
file.must_include %{validation_key "/tmp/kitchen/validation.pem"}
|
|
1069
|
-
end
|
|
1070
|
-
|
|
1071
|
-
it "sets client_key" do
|
|
1072
|
-
file.must_include %{client_key "/tmp/kitchen/client.pem"}
|
|
1073
|
-
end
|
|
1074
|
-
|
|
1075
|
-
it "sets chef_server_url" do
|
|
1076
|
-
file.must_include %{chef_server_url "http://127.0.0.1:8889"}
|
|
1077
|
-
end
|
|
1078
|
-
|
|
1079
|
-
it "sets encrypted_data_bag_secret" do
|
|
1080
|
-
file.must_include %{encrypted_data_bag_secret } +
|
|
1081
|
-
%{"/tmp/kitchen/encrypted_data_bag_secret"}
|
|
1082
|
-
end
|
|
1083
|
-
end
|
|
1084
|
-
|
|
1085
|
-
it "supports overwriting defaults" do
|
|
1086
|
-
config[:generic_rb] = {
|
|
1087
|
-
:node_name => "eagles",
|
|
1088
|
-
:user_path => "/a/b/c/u",
|
|
1089
|
-
:chef_server_url => "https://whereever.io"
|
|
1090
|
-
}
|
|
1091
|
-
provisioner.create_sandbox
|
|
1092
|
-
|
|
1093
|
-
file.must_include %{node_name "eagles"}
|
|
1094
|
-
file.must_include %{user_path "/a/b/c/u"}
|
|
1095
|
-
file.must_include %{chef_server_url "https://whereever.io"}
|
|
1096
|
-
end
|
|
1097
|
-
|
|
1098
|
-
it " supports adding new configuration" do
|
|
1099
|
-
config[:generic_rb] = {
|
|
1100
|
-
:dark_secret => "golang"
|
|
1101
|
-
}
|
|
1102
|
-
provisioner.create_sandbox
|
|
1103
|
-
|
|
1104
|
-
file.must_include %{dark_secret "golang"}
|
|
1105
|
-
end
|
|
1106
|
-
end
|
|
1107
|
-
|
|
1108
|
-
def create_cookbook(path)
|
|
1109
|
-
%w[metadata.rb attributes/all.rb recipes/default.rb].each do |file|
|
|
1110
|
-
create_file(File.join(path, file))
|
|
1111
|
-
end
|
|
1112
|
-
end
|
|
1113
|
-
|
|
1114
|
-
def full_cookbook_files
|
|
1115
|
-
%w[
|
|
1116
|
-
README.org metadata.rb attributes/all.rb definitions/def.rb
|
|
1117
|
-
files/default/config.conf libraries/one.rb libraries/two.rb
|
|
1118
|
-
providers/sweet.rb recipes/default.rb resources/sweet.rb
|
|
1119
|
-
templates/ubuntu/12.04/nginx.conf.erb
|
|
1120
|
-
]
|
|
1121
|
-
end
|
|
1122
|
-
|
|
1123
|
-
def create_full_cookbook(path)
|
|
1124
|
-
full_cookbook_files.each { |file| create_file(File.join(path, file)) }
|
|
1125
|
-
end
|
|
1126
|
-
|
|
1127
|
-
def create_file(path)
|
|
1128
|
-
FileUtils.mkdir_p(File.dirname(path))
|
|
1129
|
-
File.open(path, "wb") { |f| f.write(path) }
|
|
1130
|
-
end
|
|
1131
|
-
end
|
|
1132
|
-
|
|
1133
|
-
def sandbox_path(path)
|
|
1134
|
-
Pathname.new(provisioner.sandbox_path).join(path)
|
|
1135
|
-
end
|
|
1136
|
-
|
|
1137
|
-
def create_files_under(path)
|
|
1138
|
-
FileUtils.mkdir_p(File.join(path, "sub"))
|
|
1139
|
-
File.open(File.join(path, "alpha.txt"), "wb") do |file|
|
|
1140
|
-
file.write("stuff")
|
|
1141
|
-
end
|
|
1142
|
-
File.open(File.join(path, "sub", "bravo.txt"), "wb") do |file|
|
|
1143
|
-
file.write("junk")
|
|
1144
|
-
end
|
|
1145
|
-
end
|
|
1146
|
-
|
|
1147
|
-
def info_line(msg)
|
|
1148
|
-
%r{^I, .* : #{Regexp.escape(msg)}$}
|
|
1149
|
-
end
|
|
1150
|
-
|
|
1151
|
-
def debug_line(msg)
|
|
1152
|
-
%r{^D, .* : #{Regexp.escape(msg)}$}
|
|
1153
|
-
end
|
|
1154
|
-
end
|
|
1155
|
-
|
|
1156
|
-
def regexify(str, line = :whole_line)
|
|
1157
|
-
r = Regexp.escape(str)
|
|
1158
|
-
r = "^\s*#{r}$" if line == :whole_line
|
|
1159
|
-
Regexp.new(r)
|
|
1160
|
-
end
|
|
1161
|
-
end
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
4
|
+
#
|
|
5
|
+
# Copyright (C) 2014, Fletcher Nichol
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
|
|
19
|
+
require_relative "../../spec_helper"
|
|
20
|
+
|
|
21
|
+
require "kitchen"
|
|
22
|
+
require "kitchen/provisioner/chef_base"
|
|
23
|
+
|
|
24
|
+
describe Kitchen::Provisioner::ChefBase do
|
|
25
|
+
|
|
26
|
+
let(:logged_output) { StringIO.new }
|
|
27
|
+
let(:logger) { Logger.new(logged_output) }
|
|
28
|
+
let(:platform) { stub(:os_type => nil) }
|
|
29
|
+
let(:suite) { stub(:name => "fries") }
|
|
30
|
+
let(:default_version) { true }
|
|
31
|
+
|
|
32
|
+
let(:config) do
|
|
33
|
+
{ :test_base_path => "/basist", :kitchen_root => "/rooty" }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
let(:instance) do
|
|
37
|
+
stub(
|
|
38
|
+
:name => "coolbeans",
|
|
39
|
+
:logger => logger,
|
|
40
|
+
:suite => suite,
|
|
41
|
+
:platform => platform
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
let(:provisioner) do
|
|
46
|
+
Class.new(Kitchen::Provisioner::ChefBase) {
|
|
47
|
+
def calculate_path(path, _opts = {})
|
|
48
|
+
"<calculated>/#{path}"
|
|
49
|
+
end
|
|
50
|
+
}.new(config).finalize_config!(instance)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe "configuration" do
|
|
54
|
+
|
|
55
|
+
describe "for unix operating systems" do
|
|
56
|
+
|
|
57
|
+
before { platform.stubs(:os_type).returns("unix") }
|
|
58
|
+
|
|
59
|
+
it ":chef_omnibus_url has a default" do
|
|
60
|
+
provisioner[:chef_omnibus_url].
|
|
61
|
+
must_equal "https://www.chef.io/chef/install.sh"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it ":chef_metadata_url defaults to nil" do
|
|
65
|
+
provisioner[:chef_metadata_url].must_equal(nil)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
describe "for windows operating systems" do
|
|
70
|
+
|
|
71
|
+
before { platform.stubs(:os_type).returns("windows") }
|
|
72
|
+
|
|
73
|
+
it ":chef_omnibus_url has a default" do
|
|
74
|
+
provisioner[:chef_omnibus_url].
|
|
75
|
+
must_equal "https://www.chef.io/chef/install.sh"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it ":require_chef_omnibus defaults to true" do
|
|
81
|
+
provisioner[:require_chef_omnibus].must_equal true
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it ":chef_omnibus_install_options defaults to nil" do
|
|
85
|
+
provisioner[:chef_omnibus_install_options].must_equal nil
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it ":run_list defaults to an empty array" do
|
|
89
|
+
provisioner[:run_list].must_equal []
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it ":attributes defaults to an empty hash" do
|
|
93
|
+
provisioner[:attributes].must_equal Hash.new
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it ":log_file defaults to nil" do
|
|
97
|
+
provisioner[:log_file].must_equal nil
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it ":cookbook_files_glob includes recipes" do
|
|
101
|
+
provisioner[:cookbook_files_glob].must_match %r{,recipes/}
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it ":data_path uses calculate_path and is expanded" do
|
|
105
|
+
provisioner[:data_path].
|
|
106
|
+
must_equal os_safe_root_path("/rooty/<calculated>/data")
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it ":data_bags_path uses calculate_path and is expanded" do
|
|
110
|
+
provisioner[:data_bags_path].
|
|
111
|
+
must_equal os_safe_root_path("/rooty/<calculated>/data_bags")
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it ":environments_path uses calculate_path and is expanded" do
|
|
115
|
+
provisioner[:environments_path].
|
|
116
|
+
must_equal os_safe_root_path("/rooty/<calculated>/environments")
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it ":nodes_path uses calculate_path and is expanded" do
|
|
120
|
+
provisioner[:nodes_path].
|
|
121
|
+
must_equal os_safe_root_path("/rooty/<calculated>/nodes")
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
it ":roles_path uses calculate_path and is expanded" do
|
|
125
|
+
provisioner[:roles_path].
|
|
126
|
+
must_equal os_safe_root_path("/rooty/<calculated>/roles")
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it ":clients_path uses calculate_path and is expanded" do
|
|
130
|
+
provisioner[:clients_path].
|
|
131
|
+
must_equal os_safe_root_path("/rooty/<calculated>/clients")
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it "...secret_key_path uses calculate_path and is expanded" do
|
|
135
|
+
provisioner[:encrypted_data_bag_secret_key_path].
|
|
136
|
+
must_equal os_safe_root_path("/rooty/<calculated>/encrypted_data_bag_secret_key")
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
describe "#install_command" do
|
|
141
|
+
|
|
142
|
+
before do
|
|
143
|
+
platform.stubs(:shell_type).returns("bourne")
|
|
144
|
+
Mixlib::Install::ScriptGenerator.stubs(:new).returns(installer)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
let(:installer) { stub(:root => "/rooty", :install_command => "make_it_so") }
|
|
148
|
+
|
|
149
|
+
let(:cmd) { provisioner.install_command }
|
|
150
|
+
|
|
151
|
+
let(:install_opts) {
|
|
152
|
+
{ :omnibus_url => "https://www.chef.io/chef/install.sh",
|
|
153
|
+
:project => nil, :install_flags => nil, :sudo_command => "sudo -E",
|
|
154
|
+
:http_proxy => nil, :https_proxy => nil }
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
it "returns nil if :require_chef_omnibus is falsey" do
|
|
158
|
+
config[:require_chef_omnibus] = false
|
|
159
|
+
|
|
160
|
+
installer.expects(:root).never
|
|
161
|
+
installer.expects(:install_command).never
|
|
162
|
+
cmd.must_equal nil
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
describe "common behaviour" do
|
|
166
|
+
before do
|
|
167
|
+
installer.expects(:root).at_least_once.returns("/opt/chef")
|
|
168
|
+
installer.expects(:install_command)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it "passes sensible defaults" do
|
|
172
|
+
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
173
|
+
with(default_version, false, install_opts).returns(installer)
|
|
174
|
+
cmd
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it "exports http_proxy & HTTP_PROXY when :http_proxy is set" do
|
|
178
|
+
config[:http_proxy] = "http://proxy"
|
|
179
|
+
install_opts[:http_proxy] = "http://proxy"
|
|
180
|
+
|
|
181
|
+
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
182
|
+
with(default_version, false, install_opts).returns(installer)
|
|
183
|
+
cmd
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
it "exports https_proxy & HTTPS_PROXY when :https_proxy is set" do
|
|
187
|
+
config[:https_proxy] = "https://proxy"
|
|
188
|
+
install_opts[:https_proxy] = "https://proxy"
|
|
189
|
+
|
|
190
|
+
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
191
|
+
with(default_version, false, install_opts).returns(installer)
|
|
192
|
+
cmd
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
it "exports all http proxy variables when both are set" do
|
|
196
|
+
config[:http_proxy] = "http://proxy"
|
|
197
|
+
config[:https_proxy] = "https://proxy"
|
|
198
|
+
install_opts[:http_proxy] = "http://proxy"
|
|
199
|
+
install_opts[:https_proxy] = "https://proxy"
|
|
200
|
+
|
|
201
|
+
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
202
|
+
with(default_version, false, install_opts).returns(installer)
|
|
203
|
+
cmd
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
it "installs chef using :chef_omnibus_url, if necessary" do
|
|
207
|
+
config[:chef_omnibus_url] = "FROM_HERE"
|
|
208
|
+
install_opts[:omnibus_url] = "FROM_HERE"
|
|
209
|
+
|
|
210
|
+
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
211
|
+
with(default_version, false, install_opts).returns(installer)
|
|
212
|
+
cmd
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
it "will install a specific version of chef, if necessary" do
|
|
216
|
+
config[:require_chef_omnibus] = "1.2.3"
|
|
217
|
+
|
|
218
|
+
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
219
|
+
with("1.2.3", false, install_opts).returns(installer)
|
|
220
|
+
cmd
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
it "will install a major/minor version of chef, if necessary" do
|
|
224
|
+
config[:require_chef_omnibus] = "11.10"
|
|
225
|
+
|
|
226
|
+
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
227
|
+
with("11.10", false, install_opts).returns(installer)
|
|
228
|
+
cmd
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
it "will install a major version of chef, if necessary" do
|
|
232
|
+
config[:require_chef_omnibus] = "12"
|
|
233
|
+
|
|
234
|
+
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
235
|
+
with("12", false, install_opts).returns(installer)
|
|
236
|
+
cmd
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
it "will install a nightly, if necessary" do
|
|
240
|
+
config[:require_chef_omnibus] =
|
|
241
|
+
"12.5.0-current.0+20150721082808.git.14.c91b337-1"
|
|
242
|
+
|
|
243
|
+
Mixlib::Install::ScriptGenerator.expects(:new).with(
|
|
244
|
+
"12.5.0-current.0+20150721082808.git.14.c91b337-1",
|
|
245
|
+
false,
|
|
246
|
+
install_opts
|
|
247
|
+
).returns(installer)
|
|
248
|
+
cmd
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
it "will install the latest chef, if necessary" do
|
|
252
|
+
config[:require_chef_omnibus] = "latest"
|
|
253
|
+
|
|
254
|
+
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
255
|
+
with("latest", false, install_opts).returns(installer)
|
|
256
|
+
cmd
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
it "will install a version of chef, unless it exists" do
|
|
260
|
+
config[:require_chef_omnibus] = true
|
|
261
|
+
|
|
262
|
+
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
263
|
+
with(default_version, false, install_opts).returns(installer)
|
|
264
|
+
cmd
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
it "will pass a project, when given" do
|
|
268
|
+
config[:chef_omnibus_install_options] = "-P chefdk"
|
|
269
|
+
install_opts[:install_flags] = "-P chefdk"
|
|
270
|
+
install_opts[:project] = "chefdk"
|
|
271
|
+
|
|
272
|
+
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
273
|
+
with(default_version, false, install_opts).returns(installer)
|
|
274
|
+
cmd
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
it "will pass install options and version info, when given" do
|
|
278
|
+
config[:require_chef_omnibus] = "11"
|
|
279
|
+
config[:chef_omnibus_install_options] = "-d /tmp/place"
|
|
280
|
+
install_opts[:install_flags] = "-d /tmp/place"
|
|
281
|
+
|
|
282
|
+
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
283
|
+
with("11", false, install_opts).returns(installer)
|
|
284
|
+
cmd
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
it "will set the install root" do
|
|
288
|
+
config[:chef_omnibus_root] = "/tmp/test"
|
|
289
|
+
install_opts[:root] = "/tmp/test"
|
|
290
|
+
|
|
291
|
+
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
292
|
+
with(default_version, false, install_opts).returns(installer)
|
|
293
|
+
cmd
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
it "will set the msi url" do
|
|
297
|
+
config[:install_msi_url] = "http://blah/blah.msi"
|
|
298
|
+
install_opts[:install_msi_url] = "http://blah/blah.msi"
|
|
299
|
+
|
|
300
|
+
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
301
|
+
with(default_version, false, install_opts).returns(installer)
|
|
302
|
+
cmd
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
it "prefixs the whole command with the command_prefix if set" do
|
|
306
|
+
config[:command_prefix] = "my_prefix"
|
|
307
|
+
|
|
308
|
+
cmd.must_match(/\Amy_prefix /)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
it "does not prefix the command if command_prefix is not set" do
|
|
312
|
+
config[:command_prefix] = nil
|
|
313
|
+
|
|
314
|
+
cmd.wont_match(/\Amy_prefix /)
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
describe "for product" do
|
|
319
|
+
before do
|
|
320
|
+
installer.expects(:root).at_least_once.returns("/opt/chef")
|
|
321
|
+
installer.expects(:install_command)
|
|
322
|
+
config[:product_name] = "my_product"
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
it "will set the product name, version and channel" do
|
|
326
|
+
config[:product_version] = "version"
|
|
327
|
+
config[:channel] = "channel"
|
|
328
|
+
|
|
329
|
+
Mixlib::Install.expects(:new).with do |opts|
|
|
330
|
+
opts[:product_name].must_equal "my_product"
|
|
331
|
+
opts[:product_version].must_equal "version"
|
|
332
|
+
opts[:channel].must_equal :channel
|
|
333
|
+
end.returns(installer)
|
|
334
|
+
cmd
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
it "will set the architecture if given" do
|
|
338
|
+
config[:architecture] = "architecture"
|
|
339
|
+
|
|
340
|
+
Mixlib::Install.expects(:new).with do |opts|
|
|
341
|
+
opts[:architecture].must_equal "architecture"
|
|
342
|
+
end.returns(installer)
|
|
343
|
+
cmd
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
it "will set the platform if given" do
|
|
347
|
+
config[:platform] = "platform"
|
|
348
|
+
|
|
349
|
+
Mixlib::Install.expects(:new).with do |opts|
|
|
350
|
+
opts[:platform].must_equal "platform"
|
|
351
|
+
end.returns(installer)
|
|
352
|
+
cmd
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
it "will set the platform_version if given" do
|
|
356
|
+
config[:platform_version] = "platform_version"
|
|
357
|
+
|
|
358
|
+
Mixlib::Install.expects(:new).with do |opts|
|
|
359
|
+
opts[:platform_version].must_equal "platform_version"
|
|
360
|
+
end.returns(installer)
|
|
361
|
+
cmd
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
it "will omit the architecture if not given" do
|
|
365
|
+
Mixlib::Install.expects(:new).with do |opts|
|
|
366
|
+
opts.key?(:architecture).must_equal false
|
|
367
|
+
end.returns(installer)
|
|
368
|
+
cmd
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
it "will omit the platform if not given" do
|
|
372
|
+
Mixlib::Install.expects(:new).with do |opts|
|
|
373
|
+
opts.key?(:platform).must_equal false
|
|
374
|
+
end.returns(installer)
|
|
375
|
+
cmd
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
it "will omit the platform_version if not given" do
|
|
379
|
+
Mixlib::Install.expects(:new).with do |opts|
|
|
380
|
+
opts.key?(:platform_version).must_equal false
|
|
381
|
+
end.returns(installer)
|
|
382
|
+
cmd
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
it "will use stable channel when none specified" do
|
|
386
|
+
Mixlib::Install.expects(:new).with do |opts|
|
|
387
|
+
opts[:channel].must_equal :stable
|
|
388
|
+
end.returns(installer)
|
|
389
|
+
cmd
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
describe "for bourne shells" do
|
|
394
|
+
before do
|
|
395
|
+
installer.expects(:root).at_least_once.returns("/opt/chef")
|
|
396
|
+
installer.expects(:install_command).returns("my_install_command")
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
it "prepends sudo for sh commands when :sudo is set" do
|
|
400
|
+
config[:sudo] = true
|
|
401
|
+
config[:sudo_command] = "my_sudo_command"
|
|
402
|
+
install_opts_clone = install_opts.clone
|
|
403
|
+
install_opts_clone[:sudo_command] = config[:sudo_command]
|
|
404
|
+
|
|
405
|
+
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
406
|
+
with(default_version, false, install_opts_clone).returns(installer)
|
|
407
|
+
cmd.must_equal "my_sudo_command my_install_command"
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
it "does not pass shell type for product based command" do
|
|
411
|
+
config[:product_name] = "product_name"
|
|
412
|
+
|
|
413
|
+
Mixlib::Install.expects(:new).with do |opts|
|
|
414
|
+
opts.key?(:shell_type).must_equal false
|
|
415
|
+
end.returns(installer)
|
|
416
|
+
cmd
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
it "does not sudo for sh commands when :sudo is falsey" do
|
|
420
|
+
config[:sudo] = false
|
|
421
|
+
|
|
422
|
+
install_opts_clone = install_opts.clone
|
|
423
|
+
install_opts_clone[:sudo_command] = ""
|
|
424
|
+
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
425
|
+
with(default_version, false, install_opts_clone).returns(installer)
|
|
426
|
+
cmd.must_equal "my_install_command"
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
describe "for powershell shells on windows os types" do
|
|
431
|
+
before do
|
|
432
|
+
installer.expects(:root).at_least_once.returns("/opt/chef")
|
|
433
|
+
installer.expects(:install_command)
|
|
434
|
+
platform.stubs(:shell_type).returns("powershell")
|
|
435
|
+
platform.stubs(:os_type).returns("windows")
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
it "sets the powershell flag for Mixlib::Install" do
|
|
439
|
+
install_opts_clone = install_opts.clone
|
|
440
|
+
install_opts_clone[:sudo_command] = ""
|
|
441
|
+
Mixlib::Install::ScriptGenerator.expects(:new).
|
|
442
|
+
with(default_version, true, install_opts_clone).returns(installer)
|
|
443
|
+
cmd
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
it "passes ps1 shell type for product based command" do
|
|
447
|
+
config[:product_name] = "product_name"
|
|
448
|
+
|
|
449
|
+
Mixlib::Install.expects(:new).with do |opts|
|
|
450
|
+
opts[:shell_type].must_equal :ps1
|
|
451
|
+
end.returns(installer)
|
|
452
|
+
cmd
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
describe "#init_command" do
|
|
458
|
+
|
|
459
|
+
let(:cmd) { provisioner.init_command }
|
|
460
|
+
|
|
461
|
+
describe "common behavior" do
|
|
462
|
+
|
|
463
|
+
before { platform.stubs(:shell_type).returns("fake") }
|
|
464
|
+
|
|
465
|
+
it "prefixs the whole command with the command_prefix if set" do
|
|
466
|
+
config[:command_prefix] = "my_prefix"
|
|
467
|
+
|
|
468
|
+
cmd.must_match(/\Amy_prefix /)
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
it "does not prefix the command if command_prefix is not set" do
|
|
472
|
+
config[:command_prefix] = nil
|
|
473
|
+
|
|
474
|
+
cmd.wont_match(/\Amy_prefix /)
|
|
475
|
+
end
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
describe "for bourne shells" do
|
|
479
|
+
|
|
480
|
+
before { platform.stubs(:shell_type).returns("bourne") }
|
|
481
|
+
|
|
482
|
+
it "uses bourne shell" do
|
|
483
|
+
cmd.must_match(/\Ash -c '$/)
|
|
484
|
+
cmd.must_match(/'\Z/)
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
it "ends with a single quote" do
|
|
488
|
+
cmd.must_match(/'\Z/)
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
it "exports http_proxy & HTTP_PROXY when :http_proxy is set" do
|
|
492
|
+
config[:http_proxy] = "http://proxy"
|
|
493
|
+
|
|
494
|
+
cmd.lines.to_a[1..2].must_equal([
|
|
495
|
+
%{http_proxy="http://proxy"; export http_proxy\n},
|
|
496
|
+
%{HTTP_PROXY="http://proxy"; export HTTP_PROXY\n}
|
|
497
|
+
])
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
it "exports https_proxy & HTTPS_PROXY when :https_proxy is set" do
|
|
501
|
+
config[:https_proxy] = "https://proxy"
|
|
502
|
+
|
|
503
|
+
cmd.lines.to_a[1..2].must_equal([
|
|
504
|
+
%{https_proxy="https://proxy"; export https_proxy\n},
|
|
505
|
+
%{HTTPS_PROXY="https://proxy"; export HTTPS_PROXY\n}
|
|
506
|
+
])
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
it "exports all http proxy variables when both are set" do
|
|
510
|
+
config[:http_proxy] = "http://proxy"
|
|
511
|
+
config[:https_proxy] = "https://proxy"
|
|
512
|
+
|
|
513
|
+
cmd.lines.to_a[1..4].must_equal([
|
|
514
|
+
%{http_proxy="http://proxy"; export http_proxy\n},
|
|
515
|
+
%{HTTP_PROXY="http://proxy"; export HTTP_PROXY\n},
|
|
516
|
+
%{https_proxy="https://proxy"; export https_proxy\n},
|
|
517
|
+
%{HTTPS_PROXY="https://proxy"; export HTTPS_PROXY\n}
|
|
518
|
+
])
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
it "prepends sudo for rm when :sudo is set" do
|
|
522
|
+
config[:sudo] = true
|
|
523
|
+
|
|
524
|
+
cmd.must_match regexify(%{sudo_rm="sudo -E rm"})
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
it "does not sudo for sh commands when :sudo is falsey" do
|
|
528
|
+
config[:sudo] = false
|
|
529
|
+
|
|
530
|
+
cmd.must_match regexify(%{sudo_rm="rm"})
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
it "sets chef component dirs for deletion" do
|
|
534
|
+
config[:root_path] = "/route"
|
|
535
|
+
dirs = %W[
|
|
536
|
+
/route/clients /route/cookbooks /route/data /route/data_bags
|
|
537
|
+
/route/encrypted_data_bag_secret /route/environments /route/roles
|
|
538
|
+
].join(" ")
|
|
539
|
+
|
|
540
|
+
cmd.must_match regexify(%{dirs="#{dirs}"})
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
it "sets the root_path from :root_path" do
|
|
544
|
+
config[:root_path] = "RIGHT_HERE"
|
|
545
|
+
|
|
546
|
+
cmd.must_match regexify(%{root_path="RIGHT_HERE"})
|
|
547
|
+
end
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
describe "for powershell shells on windows os types" do
|
|
551
|
+
|
|
552
|
+
before do
|
|
553
|
+
platform.stubs(:shell_type).returns("powershell")
|
|
554
|
+
platform.stubs(:os_type).returns("windows")
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
it "exports http_proxy & HTTP_PROXY when :http_proxy is set" do
|
|
558
|
+
config[:http_proxy] = "http://proxy"
|
|
559
|
+
|
|
560
|
+
cmd.lines.to_a[0..1].must_equal([
|
|
561
|
+
%{$env:http_proxy = "http://proxy"\n},
|
|
562
|
+
%{$env:HTTP_PROXY = "http://proxy"\n}
|
|
563
|
+
])
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
it "exports https_proxy & HTTPS_PROXY when :https_proxy is set" do
|
|
567
|
+
config[:https_proxy] = "https://proxy"
|
|
568
|
+
|
|
569
|
+
cmd.lines.to_a[0..1].must_equal([
|
|
570
|
+
%{$env:https_proxy = "https://proxy"\n},
|
|
571
|
+
%{$env:HTTPS_PROXY = "https://proxy"\n}
|
|
572
|
+
])
|
|
573
|
+
end
|
|
574
|
+
|
|
575
|
+
it "exports all http proxy variables when both are set" do
|
|
576
|
+
config[:http_proxy] = "http://proxy"
|
|
577
|
+
config[:https_proxy] = "https://proxy"
|
|
578
|
+
|
|
579
|
+
cmd.lines.to_a[0..3].must_equal([
|
|
580
|
+
%{$env:http_proxy = "http://proxy"\n},
|
|
581
|
+
%{$env:HTTP_PROXY = "http://proxy"\n},
|
|
582
|
+
%{$env:https_proxy = "https://proxy"\n},
|
|
583
|
+
%{$env:HTTPS_PROXY = "https://proxy"\n}
|
|
584
|
+
])
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
it "sets chef component dirs for deletion" do
|
|
588
|
+
config[:root_path] = "\\route"
|
|
589
|
+
dirs = %W[
|
|
590
|
+
"\\route\\clients" "\\route\\cookbooks" "\\route\\data"
|
|
591
|
+
"\\route\\data_bags" "\\route\\encrypted_data_bag_secret"
|
|
592
|
+
"\\route\\environments" "\\route\\roles"
|
|
593
|
+
].join(", ")
|
|
594
|
+
|
|
595
|
+
cmd.must_match regexify(%{$dirs = @(#{dirs})})
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
it "sets the root_path from :root_path" do
|
|
599
|
+
config[:root_path] = "RIGHT_HERE"
|
|
600
|
+
|
|
601
|
+
cmd.must_match regexify(%{$root_path = "RIGHT_HERE"})
|
|
602
|
+
end
|
|
603
|
+
end
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
describe "#create_sandbox" do
|
|
607
|
+
|
|
608
|
+
before do
|
|
609
|
+
@root = Dir.mktmpdir
|
|
610
|
+
config[:kitchen_root] = @root
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
after do
|
|
614
|
+
FileUtils.remove_entry(@root)
|
|
615
|
+
begin
|
|
616
|
+
provisioner.cleanup_sandbox
|
|
617
|
+
rescue # rubocop:disable Lint/HandleExceptions
|
|
618
|
+
end
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
let(:provisioner) do
|
|
622
|
+
Class.new(Kitchen::Provisioner::ChefBase) {
|
|
623
|
+
default_config :generic_rb, {}
|
|
624
|
+
|
|
625
|
+
def create_sandbox
|
|
626
|
+
super
|
|
627
|
+
|
|
628
|
+
data = default_config_rb.merge(config[:generic_rb])
|
|
629
|
+
File.open(File.join(sandbox_path, "generic.rb"), "wb") do |file|
|
|
630
|
+
file.write(format_config_file(data))
|
|
631
|
+
end
|
|
632
|
+
end
|
|
633
|
+
}.new(config).finalize_config!(instance)
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
describe "json file" do
|
|
637
|
+
|
|
638
|
+
let(:json) { JSON.parse(IO.read(sandbox_path("dna.json"))) }
|
|
639
|
+
|
|
640
|
+
it "creates a json file with node attributes" do
|
|
641
|
+
config[:attributes] = { "one" => { "two" => "three" } }
|
|
642
|
+
provisioner.create_sandbox
|
|
643
|
+
|
|
644
|
+
json["one"].must_equal("two" => "three")
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
it "creates a json file with run_list" do
|
|
648
|
+
config[:run_list] = %w[alpha bravo charlie]
|
|
649
|
+
provisioner.create_sandbox
|
|
650
|
+
|
|
651
|
+
json["run_list"].must_equal %w[alpha bravo charlie]
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
it "creates a json file with an empty run_list" do
|
|
655
|
+
config[:run_list] = []
|
|
656
|
+
provisioner.create_sandbox
|
|
657
|
+
|
|
658
|
+
json["run_list"].must_equal []
|
|
659
|
+
end
|
|
660
|
+
|
|
661
|
+
it "logs a message on info" do
|
|
662
|
+
provisioner.create_sandbox
|
|
663
|
+
|
|
664
|
+
logged_output.string.must_match info_line("Preparing dna.json")
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
it "logs a message on debug" do
|
|
668
|
+
config[:run_list] = ["yo"]
|
|
669
|
+
provisioner.create_sandbox
|
|
670
|
+
|
|
671
|
+
logged_output.string.
|
|
672
|
+
must_match debug_line(%|Creating dna.json from {:run_list=>["yo"]}|)
|
|
673
|
+
end
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
it "creates a cache directory" do
|
|
677
|
+
provisioner.create_sandbox
|
|
678
|
+
|
|
679
|
+
sandbox_path("cache").directory?.must_equal true
|
|
680
|
+
end
|
|
681
|
+
|
|
682
|
+
%w[data data_bags environments nodes roles clients].each do |thing|
|
|
683
|
+
describe "#{thing} files" do
|
|
684
|
+
|
|
685
|
+
before do
|
|
686
|
+
create_files_under("#{config[:kitchen_root]}/my_#{thing}")
|
|
687
|
+
config[:"#{thing}_path"] = "#{config[:kitchen_root]}/my_#{thing}"
|
|
688
|
+
end
|
|
689
|
+
|
|
690
|
+
it "skips directory creation if :#{thing}_path is not set" do
|
|
691
|
+
config[:"#{thing}_path"] = nil
|
|
692
|
+
provisioner.create_sandbox
|
|
693
|
+
|
|
694
|
+
sandbox_path(thing).directory?.must_equal false
|
|
695
|
+
end
|
|
696
|
+
|
|
697
|
+
it "copies tree from :#{thing}_path into sandbox" do
|
|
698
|
+
provisioner.create_sandbox
|
|
699
|
+
|
|
700
|
+
sandbox_path("#{thing}/alpha.txt").file?.must_equal true
|
|
701
|
+
IO.read(sandbox_path("#{thing}/alpha.txt")).must_equal "stuff"
|
|
702
|
+
sandbox_path("#{thing}/sub").directory?.must_equal true
|
|
703
|
+
sandbox_path("#{thing}/sub/bravo.txt").file?.must_equal true
|
|
704
|
+
IO.read(sandbox_path("#{thing}/sub/bravo.txt")).must_equal "junk"
|
|
705
|
+
end
|
|
706
|
+
|
|
707
|
+
it "logs a message on info" do
|
|
708
|
+
provisioner.create_sandbox
|
|
709
|
+
|
|
710
|
+
logged_output.string.must_match info_line("Preparing #{thing}")
|
|
711
|
+
end
|
|
712
|
+
|
|
713
|
+
it "logs a message on debug" do
|
|
714
|
+
provisioner.create_sandbox
|
|
715
|
+
|
|
716
|
+
logged_output.string.must_match debug_line(
|
|
717
|
+
"Using #{thing} from #{config[:kitchen_root]}/my_#{thing}")
|
|
718
|
+
end
|
|
719
|
+
end
|
|
720
|
+
end
|
|
721
|
+
|
|
722
|
+
describe "secret files" do
|
|
723
|
+
|
|
724
|
+
before do
|
|
725
|
+
config[:encrypted_data_bag_secret_key_path] =
|
|
726
|
+
"#{config[:kitchen_root]}/my_secret"
|
|
727
|
+
File.open("#{config[:kitchen_root]}/my_secret", "wb") do |file|
|
|
728
|
+
file.write("p@ss")
|
|
729
|
+
end
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
it "skips file if :encrypted_data_bag_secret_key_path is not set" do
|
|
733
|
+
config[:encrypted_data_bag_secret_key_path] = nil
|
|
734
|
+
provisioner.create_sandbox
|
|
735
|
+
|
|
736
|
+
sandbox_path("encrypted_data_bag_secret").file?.must_equal false
|
|
737
|
+
end
|
|
738
|
+
|
|
739
|
+
it "copies file from :encrypted_data_bag_secret_key_path into sandbox" do
|
|
740
|
+
provisioner.create_sandbox
|
|
741
|
+
|
|
742
|
+
sandbox_path("encrypted_data_bag_secret").file?.must_equal true
|
|
743
|
+
IO.read(sandbox_path("encrypted_data_bag_secret")).must_equal "p@ss"
|
|
744
|
+
end
|
|
745
|
+
|
|
746
|
+
it "logs a message on info" do
|
|
747
|
+
provisioner.create_sandbox
|
|
748
|
+
|
|
749
|
+
logged_output.string.must_match info_line("Preparing secret")
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
it "logs a message on debug" do
|
|
753
|
+
provisioner.create_sandbox
|
|
754
|
+
|
|
755
|
+
logged_output.string.must_match debug_line(
|
|
756
|
+
"Using secret from #{config[:kitchen_root]}/my_secret")
|
|
757
|
+
end
|
|
758
|
+
end
|
|
759
|
+
|
|
760
|
+
describe "cookbooks" do
|
|
761
|
+
|
|
762
|
+
let(:kitchen_root) { config[:kitchen_root] }
|
|
763
|
+
|
|
764
|
+
describe "with a cookbooks/ directory under kitchen_root" do
|
|
765
|
+
|
|
766
|
+
it "copies cookbooks/" do
|
|
767
|
+
create_cookbook("#{kitchen_root}/cookbooks/epache")
|
|
768
|
+
create_cookbook("#{kitchen_root}/cookbooks/jahva")
|
|
769
|
+
provisioner.create_sandbox
|
|
770
|
+
|
|
771
|
+
sandbox_path("cookbooks/epache").directory?.must_equal true
|
|
772
|
+
sandbox_path("cookbooks/epache/recipes/default.rb").
|
|
773
|
+
file?.must_equal true
|
|
774
|
+
sandbox_path("cookbooks/jahva").directory?.must_equal true
|
|
775
|
+
sandbox_path("cookbooks/jahva/recipes/default.rb").
|
|
776
|
+
file?.must_equal true
|
|
777
|
+
end
|
|
778
|
+
|
|
779
|
+
it "copies from kitchen_root as cookbook if it contains metadata.rb" do
|
|
780
|
+
File.open("#{kitchen_root}/metadata.rb", "wb") do |file|
|
|
781
|
+
file.write("name 'wat'")
|
|
782
|
+
end
|
|
783
|
+
create_cookbook("#{kitchen_root}/cookbooks/bk")
|
|
784
|
+
provisioner.create_sandbox
|
|
785
|
+
|
|
786
|
+
sandbox_path("cookbooks/bk").directory?.must_equal true
|
|
787
|
+
sandbox_path("cookbooks/wat").directory?.must_equal true
|
|
788
|
+
sandbox_path("cookbooks/wat/metadata.rb").file?.must_equal true
|
|
789
|
+
end
|
|
790
|
+
|
|
791
|
+
it "copies site-cookbooks/ if it exists" do
|
|
792
|
+
create_cookbook("#{kitchen_root}/cookbooks/upstream")
|
|
793
|
+
create_cookbook("#{kitchen_root}/site-cookbooks/mine")
|
|
794
|
+
provisioner.create_sandbox
|
|
795
|
+
|
|
796
|
+
sandbox_path("cookbooks/upstream").directory?.must_equal true
|
|
797
|
+
sandbox_path("cookbooks/mine").directory?.must_equal true
|
|
798
|
+
sandbox_path("cookbooks/mine/attributes/all.rb").file?.must_equal true
|
|
799
|
+
end
|
|
800
|
+
|
|
801
|
+
it "logs a message on info for cookbooks/ directory" do
|
|
802
|
+
create_cookbook("#{kitchen_root}/cookbooks/epache")
|
|
803
|
+
provisioner.create_sandbox
|
|
804
|
+
|
|
805
|
+
logged_output.string.must_match info_line(
|
|
806
|
+
"Preparing cookbooks from project directory")
|
|
807
|
+
end
|
|
808
|
+
|
|
809
|
+
it "logs a meesage on debug for cookbooks/ directory" do
|
|
810
|
+
create_cookbook("#{kitchen_root}/cookbooks/epache")
|
|
811
|
+
provisioner.create_sandbox
|
|
812
|
+
|
|
813
|
+
logged_output.string.must_match debug_line(
|
|
814
|
+
"Using cookbooks from #{kitchen_root}/cookbooks")
|
|
815
|
+
end
|
|
816
|
+
|
|
817
|
+
it "logs a message on info for site-cookbooks/ directory" do
|
|
818
|
+
create_cookbook("#{kitchen_root}/cookbooks/epache")
|
|
819
|
+
create_cookbook("#{kitchen_root}/site-cookbooks/mine")
|
|
820
|
+
provisioner.create_sandbox
|
|
821
|
+
|
|
822
|
+
logged_output.string.must_match info_line(
|
|
823
|
+
"Preparing site-cookbooks from project directory")
|
|
824
|
+
end
|
|
825
|
+
|
|
826
|
+
it "logs a meesage on debug for site-cookbooks/ directory" do
|
|
827
|
+
create_cookbook("#{kitchen_root}/cookbooks/epache")
|
|
828
|
+
create_cookbook("#{kitchen_root}/site-cookbooks/mine")
|
|
829
|
+
provisioner.create_sandbox
|
|
830
|
+
|
|
831
|
+
logged_output.string.must_match debug_line(
|
|
832
|
+
"Using cookbooks from #{kitchen_root}/site-cookbooks")
|
|
833
|
+
end
|
|
834
|
+
end
|
|
835
|
+
|
|
836
|
+
describe "with a cookbook as the project" do
|
|
837
|
+
|
|
838
|
+
before do
|
|
839
|
+
File.open("#{kitchen_root}/metadata.rb", "wb") do |file|
|
|
840
|
+
file.write("name 'wat'")
|
|
841
|
+
end
|
|
842
|
+
end
|
|
843
|
+
|
|
844
|
+
it "copies from kitchen_root as cookbook if it contains metadata.rb" do
|
|
845
|
+
provisioner.create_sandbox
|
|
846
|
+
|
|
847
|
+
sandbox_path("cookbooks/wat").directory?.must_equal true
|
|
848
|
+
sandbox_path("cookbooks/wat/metadata.rb").file?.must_equal true
|
|
849
|
+
end
|
|
850
|
+
|
|
851
|
+
it "logs a message on info" do
|
|
852
|
+
provisioner.create_sandbox
|
|
853
|
+
|
|
854
|
+
logged_output.string.must_match info_line(
|
|
855
|
+
"Preparing current project directory as a cookbook")
|
|
856
|
+
end
|
|
857
|
+
|
|
858
|
+
it "logs a meesage on debug" do
|
|
859
|
+
provisioner.create_sandbox
|
|
860
|
+
|
|
861
|
+
logged_output.string.must_match debug_line(
|
|
862
|
+
"Using metadata.rb from #{kitchen_root}/metadata.rb")
|
|
863
|
+
end
|
|
864
|
+
|
|
865
|
+
it "raises a UserError is name cannot be determined from metadata.rb" do
|
|
866
|
+
File.open("#{kitchen_root}/metadata.rb", "wb") do |file|
|
|
867
|
+
file.write("nameeeeee 'wat'")
|
|
868
|
+
end
|
|
869
|
+
|
|
870
|
+
proc { provisioner.create_sandbox }.must_raise Kitchen::UserError
|
|
871
|
+
end
|
|
872
|
+
end
|
|
873
|
+
|
|
874
|
+
describe "with no referenced cookbooks" do
|
|
875
|
+
|
|
876
|
+
it "makes a fake cookbook" do
|
|
877
|
+
name = File.basename(@root)
|
|
878
|
+
provisioner.create_sandbox
|
|
879
|
+
|
|
880
|
+
sandbox_path("cookbooks/#{name}").directory?.must_equal true
|
|
881
|
+
sandbox_path("cookbooks/#{name}/metadata.rb").file?.must_equal true
|
|
882
|
+
IO.read(sandbox_path("cookbooks/#{name}/metadata.rb")).
|
|
883
|
+
must_equal %{name "#{name}"\n}
|
|
884
|
+
end
|
|
885
|
+
|
|
886
|
+
it "logs a warning" do
|
|
887
|
+
provisioner.create_sandbox
|
|
888
|
+
|
|
889
|
+
logged_output.string.must_match regexify(
|
|
890
|
+
"Berksfile, Cheffile, cookbooks/, or metadata.rb not found",
|
|
891
|
+
:partial_line
|
|
892
|
+
)
|
|
893
|
+
end
|
|
894
|
+
end
|
|
895
|
+
|
|
896
|
+
describe "with a Berksfile under kitchen_root" do
|
|
897
|
+
|
|
898
|
+
let(:resolver) { stub(:resolve => true) }
|
|
899
|
+
|
|
900
|
+
before do
|
|
901
|
+
File.open("#{kitchen_root}/Berksfile", "wb") do |file|
|
|
902
|
+
file.write("cookbook 'wat'")
|
|
903
|
+
end
|
|
904
|
+
Kitchen::Provisioner::Chef::Berkshelf.stubs(:new).returns(resolver)
|
|
905
|
+
end
|
|
906
|
+
|
|
907
|
+
it "raises a UserError if Berkshelf library can't be loaded" do
|
|
908
|
+
proc { provisioner }.must_raise Kitchen::UserError
|
|
909
|
+
end
|
|
910
|
+
|
|
911
|
+
it "logs on debug that Berkshelf is loading" do
|
|
912
|
+
Kitchen::Provisioner::Chef::Berkshelf.stubs(:load!)
|
|
913
|
+
provisioner
|
|
914
|
+
|
|
915
|
+
logged_output.string.must_match debug_line(
|
|
916
|
+
"Berksfile found at #{kitchen_root}/Berksfile, loading Berkshelf")
|
|
917
|
+
end
|
|
918
|
+
|
|
919
|
+
it "uses Berkshelf" do
|
|
920
|
+
Kitchen::Provisioner::Chef::Berkshelf.stubs(:load!)
|
|
921
|
+
resolver.expects(:resolve)
|
|
922
|
+
|
|
923
|
+
provisioner.create_sandbox
|
|
924
|
+
end
|
|
925
|
+
|
|
926
|
+
it "uses Kitchen.mutex for resolving" do
|
|
927
|
+
Kitchen::Provisioner::Chef::Berkshelf.stubs(:load!)
|
|
928
|
+
Kitchen.mutex.expects(:synchronize)
|
|
929
|
+
|
|
930
|
+
provisioner.create_sandbox
|
|
931
|
+
end
|
|
932
|
+
end
|
|
933
|
+
|
|
934
|
+
describe "with a Cheffile under kitchen_root" do
|
|
935
|
+
|
|
936
|
+
let(:resolver) { stub(:resolve => true) }
|
|
937
|
+
|
|
938
|
+
before do
|
|
939
|
+
File.open("#{kitchen_root}/Cheffile", "wb") do |file|
|
|
940
|
+
file.write("cookbook 'wat'")
|
|
941
|
+
end
|
|
942
|
+
Kitchen::Provisioner::Chef::Librarian.stubs(:new).returns(resolver)
|
|
943
|
+
end
|
|
944
|
+
|
|
945
|
+
it "raises a UserError if Librarian library can't be loaded" do
|
|
946
|
+
proc { provisioner }.must_raise Kitchen::UserError
|
|
947
|
+
end
|
|
948
|
+
|
|
949
|
+
it "logs on debug that Berkshelf is loading" do
|
|
950
|
+
Kitchen::Provisioner::Chef::Librarian.stubs(:load!)
|
|
951
|
+
provisioner
|
|
952
|
+
|
|
953
|
+
logged_output.string.must_match debug_line(
|
|
954
|
+
"Cheffile found at #{kitchen_root}/Cheffile, loading Librarian-Chef"
|
|
955
|
+
)
|
|
956
|
+
end
|
|
957
|
+
|
|
958
|
+
it "uses Librarian" do
|
|
959
|
+
Kitchen::Provisioner::Chef::Librarian.stubs(:load!)
|
|
960
|
+
resolver.expects(:resolve)
|
|
961
|
+
|
|
962
|
+
provisioner.create_sandbox
|
|
963
|
+
end
|
|
964
|
+
|
|
965
|
+
it "uses Kitchen.mutex for resolving" do
|
|
966
|
+
Kitchen::Provisioner::Chef::Librarian.stubs(:load!)
|
|
967
|
+
Kitchen.mutex.expects(:synchronize)
|
|
968
|
+
|
|
969
|
+
provisioner.create_sandbox
|
|
970
|
+
end
|
|
971
|
+
end
|
|
972
|
+
|
|
973
|
+
describe "filtering cookbooks files" do
|
|
974
|
+
|
|
975
|
+
it "retains all useful cookbook files" do
|
|
976
|
+
create_full_cookbook("#{kitchen_root}/cookbooks/full")
|
|
977
|
+
provisioner.create_sandbox
|
|
978
|
+
|
|
979
|
+
full_cookbook_files.each do |file|
|
|
980
|
+
sandbox_path("cookbooks/full/#{file}").file?.must_equal true
|
|
981
|
+
end
|
|
982
|
+
end
|
|
983
|
+
|
|
984
|
+
it "strips extra cookbook files" do
|
|
985
|
+
extras = %w[
|
|
986
|
+
.gitignore tmp/librarian chefignore .git/info/excludes
|
|
987
|
+
cookbooks/another/metadata.rb CONTRIBUTING.md metadata.py
|
|
988
|
+
]
|
|
989
|
+
|
|
990
|
+
create_full_cookbook("#{kitchen_root}/cookbooks/full")
|
|
991
|
+
extras.each do |file|
|
|
992
|
+
create_file("#{kitchen_root}/cookbooks/full/#{file}")
|
|
993
|
+
end
|
|
994
|
+
provisioner.create_sandbox
|
|
995
|
+
|
|
996
|
+
extras.each do |file|
|
|
997
|
+
sandbox_path("cookbooks/full/#{file}").file?.must_equal false
|
|
998
|
+
end
|
|
999
|
+
end
|
|
1000
|
+
|
|
1001
|
+
it "logs on info" do
|
|
1002
|
+
create_full_cookbook("#{kitchen_root}/cookbooks/full")
|
|
1003
|
+
provisioner.create_sandbox
|
|
1004
|
+
|
|
1005
|
+
logged_output.string.must_match info_line(
|
|
1006
|
+
"Removing non-cookbook files before transfer")
|
|
1007
|
+
end
|
|
1008
|
+
end
|
|
1009
|
+
|
|
1010
|
+
describe "Chef config files" do
|
|
1011
|
+
|
|
1012
|
+
let(:file) do
|
|
1013
|
+
IO.read(sandbox_path("generic.rb")).lines.map(&:chomp)
|
|
1014
|
+
end
|
|
1015
|
+
|
|
1016
|
+
it "#create_sanbox creates a generic.rb" do
|
|
1017
|
+
provisioner.create_sandbox
|
|
1018
|
+
|
|
1019
|
+
sandbox_path("generic.rb").file?.must_equal true
|
|
1020
|
+
end
|
|
1021
|
+
|
|
1022
|
+
describe "defaults" do
|
|
1023
|
+
|
|
1024
|
+
before { provisioner.create_sandbox }
|
|
1025
|
+
|
|
1026
|
+
it "sets node_name to the instance name" do
|
|
1027
|
+
file.must_include %{node_name "#{instance.name}"}
|
|
1028
|
+
end
|
|
1029
|
+
|
|
1030
|
+
it "sets checksum_path" do
|
|
1031
|
+
file.must_include %{checksum_path "/tmp/kitchen/checksums"}
|
|
1032
|
+
end
|
|
1033
|
+
|
|
1034
|
+
it "sets file_backup_path" do
|
|
1035
|
+
file.must_include %{file_backup_path "/tmp/kitchen/backup"}
|
|
1036
|
+
end
|
|
1037
|
+
|
|
1038
|
+
it "sets cookbook_path" do
|
|
1039
|
+
file.must_include %{cookbook_path } +
|
|
1040
|
+
%{["/tmp/kitchen/cookbooks", "/tmp/kitchen/site-cookbooks"]}
|
|
1041
|
+
end
|
|
1042
|
+
|
|
1043
|
+
it "sets data_bag_path" do
|
|
1044
|
+
file.must_include %{data_bag_path "/tmp/kitchen/data_bags"}
|
|
1045
|
+
end
|
|
1046
|
+
|
|
1047
|
+
it "sets environment_path" do
|
|
1048
|
+
file.must_include %{environment_path "/tmp/kitchen/environments"}
|
|
1049
|
+
end
|
|
1050
|
+
|
|
1051
|
+
it "sets node_path" do
|
|
1052
|
+
file.must_include %{node_path "/tmp/kitchen/nodes"}
|
|
1053
|
+
end
|
|
1054
|
+
|
|
1055
|
+
it "sets role_path" do
|
|
1056
|
+
file.must_include %{role_path "/tmp/kitchen/roles"}
|
|
1057
|
+
end
|
|
1058
|
+
|
|
1059
|
+
it "sets client_path" do
|
|
1060
|
+
file.must_include %{client_path "/tmp/kitchen/clients"}
|
|
1061
|
+
end
|
|
1062
|
+
|
|
1063
|
+
it "sets user_path" do
|
|
1064
|
+
file.must_include %{user_path "/tmp/kitchen/users"}
|
|
1065
|
+
end
|
|
1066
|
+
|
|
1067
|
+
it "sets validation_key" do
|
|
1068
|
+
file.must_include %{validation_key "/tmp/kitchen/validation.pem"}
|
|
1069
|
+
end
|
|
1070
|
+
|
|
1071
|
+
it "sets client_key" do
|
|
1072
|
+
file.must_include %{client_key "/tmp/kitchen/client.pem"}
|
|
1073
|
+
end
|
|
1074
|
+
|
|
1075
|
+
it "sets chef_server_url" do
|
|
1076
|
+
file.must_include %{chef_server_url "http://127.0.0.1:8889"}
|
|
1077
|
+
end
|
|
1078
|
+
|
|
1079
|
+
it "sets encrypted_data_bag_secret" do
|
|
1080
|
+
file.must_include %{encrypted_data_bag_secret } +
|
|
1081
|
+
%{"/tmp/kitchen/encrypted_data_bag_secret"}
|
|
1082
|
+
end
|
|
1083
|
+
end
|
|
1084
|
+
|
|
1085
|
+
it "supports overwriting defaults" do
|
|
1086
|
+
config[:generic_rb] = {
|
|
1087
|
+
:node_name => "eagles",
|
|
1088
|
+
:user_path => "/a/b/c/u",
|
|
1089
|
+
:chef_server_url => "https://whereever.io"
|
|
1090
|
+
}
|
|
1091
|
+
provisioner.create_sandbox
|
|
1092
|
+
|
|
1093
|
+
file.must_include %{node_name "eagles"}
|
|
1094
|
+
file.must_include %{user_path "/a/b/c/u"}
|
|
1095
|
+
file.must_include %{chef_server_url "https://whereever.io"}
|
|
1096
|
+
end
|
|
1097
|
+
|
|
1098
|
+
it " supports adding new configuration" do
|
|
1099
|
+
config[:generic_rb] = {
|
|
1100
|
+
:dark_secret => "golang"
|
|
1101
|
+
}
|
|
1102
|
+
provisioner.create_sandbox
|
|
1103
|
+
|
|
1104
|
+
file.must_include %{dark_secret "golang"}
|
|
1105
|
+
end
|
|
1106
|
+
end
|
|
1107
|
+
|
|
1108
|
+
def create_cookbook(path)
|
|
1109
|
+
%w[metadata.rb attributes/all.rb recipes/default.rb].each do |file|
|
|
1110
|
+
create_file(File.join(path, file))
|
|
1111
|
+
end
|
|
1112
|
+
end
|
|
1113
|
+
|
|
1114
|
+
def full_cookbook_files
|
|
1115
|
+
%w[
|
|
1116
|
+
README.org metadata.rb attributes/all.rb definitions/def.rb
|
|
1117
|
+
files/default/config.conf libraries/one.rb libraries/two.rb
|
|
1118
|
+
providers/sweet.rb recipes/default.rb resources/sweet.rb
|
|
1119
|
+
templates/ubuntu/12.04/nginx.conf.erb
|
|
1120
|
+
]
|
|
1121
|
+
end
|
|
1122
|
+
|
|
1123
|
+
def create_full_cookbook(path)
|
|
1124
|
+
full_cookbook_files.each { |file| create_file(File.join(path, file)) }
|
|
1125
|
+
end
|
|
1126
|
+
|
|
1127
|
+
def create_file(path)
|
|
1128
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
1129
|
+
File.open(path, "wb") { |f| f.write(path) }
|
|
1130
|
+
end
|
|
1131
|
+
end
|
|
1132
|
+
|
|
1133
|
+
def sandbox_path(path)
|
|
1134
|
+
Pathname.new(provisioner.sandbox_path).join(path)
|
|
1135
|
+
end
|
|
1136
|
+
|
|
1137
|
+
def create_files_under(path)
|
|
1138
|
+
FileUtils.mkdir_p(File.join(path, "sub"))
|
|
1139
|
+
File.open(File.join(path, "alpha.txt"), "wb") do |file|
|
|
1140
|
+
file.write("stuff")
|
|
1141
|
+
end
|
|
1142
|
+
File.open(File.join(path, "sub", "bravo.txt"), "wb") do |file|
|
|
1143
|
+
file.write("junk")
|
|
1144
|
+
end
|
|
1145
|
+
end
|
|
1146
|
+
|
|
1147
|
+
def info_line(msg)
|
|
1148
|
+
%r{^I, .* : #{Regexp.escape(msg)}$}
|
|
1149
|
+
end
|
|
1150
|
+
|
|
1151
|
+
def debug_line(msg)
|
|
1152
|
+
%r{^D, .* : #{Regexp.escape(msg)}$}
|
|
1153
|
+
end
|
|
1154
|
+
end
|
|
1155
|
+
|
|
1156
|
+
def regexify(str, line = :whole_line)
|
|
1157
|
+
r = Regexp.escape(str)
|
|
1158
|
+
r = "^\s*#{r}$" if line == :whole_line
|
|
1159
|
+
Regexp.new(r)
|
|
1160
|
+
end
|
|
1161
|
+
end
|