chef-apply 0.4.6 → 0.4.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -7
- data/chef-apply.gemspec +3 -3
- data/lib/chef_apply/version.rb +1 -1
- metadata +3 -38
- data/README.md +0 -62
- data/spec/fixtures/custom_config.toml +0 -2
- data/spec/integration/chef-run_spec.rb +0 -41
- data/spec/integration/fixtures/chef_help.out +0 -70
- data/spec/integration/fixtures/chef_version.out +0 -1
- data/spec/integration/spec_helper.rb +0 -55
- data/spec/spec_helper.rb +0 -154
- data/spec/support/matchers/output_to_terminal.rb +0 -36
- data/spec/unit/action/base_spec.rb +0 -60
- data/spec/unit/action/converge_target/ccr_failure_mapper_spec.rb +0 -106
- data/spec/unit/action/converge_target_spec.rb +0 -400
- data/spec/unit/action/generate_local_policy_spec.rb +0 -114
- data/spec/unit/action/generate_temp_cookbook/recipe_lookup_spec.rb +0 -122
- data/spec/unit/action/generate_temp_cookbook/temp_cookbook_spec.rb +0 -198
- data/spec/unit/action/generate_temp_cookbook_spec.rb +0 -73
- data/spec/unit/action/install_chef/minimum_chef_version_spec.rb +0 -90
- data/spec/unit/action/install_chef_spec.rb +0 -164
- data/spec/unit/cli/options_spec.rb +0 -75
- data/spec/unit/cli/validation_spec.rb +0 -81
- data/spec/unit/cli_spec.rb +0 -475
- data/spec/unit/config_spec.rb +0 -70
- data/spec/unit/file_fetcher_spec.rb +0 -40
- data/spec/unit/fixtures/multi-error.out +0 -2
- data/spec/unit/log_spec.rb +0 -37
- data/spec/unit/startup_spec.rb +0 -323
- data/spec/unit/target_host/linux_spec.rb +0 -57
- data/spec/unit/target_host/windows_spec.rb +0 -43
- data/spec/unit/target_host_spec.rb +0 -297
- data/spec/unit/target_resolver_spec.rb +0 -380
- data/spec/unit/telemeter/sender_spec.rb +0 -140
- data/spec/unit/telemeter_spec.rb +0 -191
- data/spec/unit/text/error_translation_spec.rb +0 -109
- data/spec/unit/ui/error_printer_spec.rb +0 -196
- data/spec/unit/ui/terminal_spec.rb +0 -119
- data/spec/unit/version_spec.rb +0 -31
@@ -1,90 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Copyright:: Copyright (c) 2018 Chef Software Inc.
|
3
|
-
# License:: Apache License, Version 2.0
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
-
# you may not use this file except in compliance with the License.
|
7
|
-
# You may obtain a copy of the License at
|
8
|
-
#
|
9
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
#
|
11
|
-
# Unless required by applicable law or agreed to in writing, software
|
12
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
-
# See the License for the specific language governing permissions and
|
15
|
-
# limitations under the License.
|
16
|
-
#
|
17
|
-
|
18
|
-
require "chef_apply/action/install_chef/minimum_chef_version"
|
19
|
-
require "chef_apply/target_host"
|
20
|
-
require "spec_helper"
|
21
|
-
|
22
|
-
RSpec.describe ChefApply::Action::InstallChef::MinimumChefVersion do
|
23
|
-
let(:base_os) { :linux }
|
24
|
-
let(:version) { 14 }
|
25
|
-
let(:target) { instance_double(ChefApply::TargetHost, base_os: base_os, installed_chef_version: version) }
|
26
|
-
subject(:klass) { ChefApply::Action::InstallChef::MinimumChefVersion }
|
27
|
-
|
28
|
-
context "#check!" do
|
29
|
-
context "when chef is not already installed on target" do
|
30
|
-
before do
|
31
|
-
expect(target).to receive(:installed_chef_version)
|
32
|
-
.and_raise ChefApply::TargetHost::ChefNotInstalled.new
|
33
|
-
end
|
34
|
-
|
35
|
-
it "should return :client_not_installed" do
|
36
|
-
actual = klass.check!(target, false)
|
37
|
-
expect(:client_not_installed).to eq(actual)
|
38
|
-
end
|
39
|
-
|
40
|
-
context "when config is set to check_only" do
|
41
|
-
it "raises ClientNotInstalled" do
|
42
|
-
expect do
|
43
|
-
klass.check!(target, true)
|
44
|
-
end.to raise_error(ChefApply::Action::InstallChef::MinimumChefVersion::ClientNotInstalled)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
%i{windows linux}.each do |os|
|
50
|
-
context "on #{os}" do
|
51
|
-
let(:base_os) { os }
|
52
|
-
[13, 14].each do |major_version|
|
53
|
-
context "when chef is already installed at the correct minimum Chef #{major_version} version" do
|
54
|
-
let(:version) { ChefApply::Action::InstallChef::MinimumChefVersion::CONSTRAINTS[os][major_version] }
|
55
|
-
it "should return :minimum_version_met" do
|
56
|
-
actual = klass.check!(target, false)
|
57
|
-
expect(:minimum_version_met).to eq(actual)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
installed_expected = {
|
65
|
-
windows: {
|
66
|
-
Gem::Version.new("12.1.1") => ChefApply::Action::InstallChef::MinimumChefVersion::Client13Outdated,
|
67
|
-
Gem::Version.new("13.9.0") => ChefApply::Action::InstallChef::MinimumChefVersion::Client13Outdated,
|
68
|
-
Gem::Version.new("14.3.37") => ChefApply::Action::InstallChef::MinimumChefVersion::Client14Outdated,
|
69
|
-
},
|
70
|
-
linux: {
|
71
|
-
Gem::Version.new("12.1.1") => ChefApply::Action::InstallChef::MinimumChefVersion::Client13Outdated,
|
72
|
-
Gem::Version.new("13.9.0") => ChefApply::Action::InstallChef::MinimumChefVersion::Client13Outdated,
|
73
|
-
Gem::Version.new("14.1.0") => ChefApply::Action::InstallChef::MinimumChefVersion::Client14Outdated,
|
74
|
-
},
|
75
|
-
}
|
76
|
-
%i{windows linux}.each do |os|
|
77
|
-
context "on #{os}" do
|
78
|
-
let(:base_os) { os }
|
79
|
-
installed_expected[os].each do |installed, expected|
|
80
|
-
context "when chef is already installed on target at version #{installed}" do
|
81
|
-
let(:version) { installed }
|
82
|
-
it "notifies of failure and takes no further action" do
|
83
|
-
expect { klass.check!(target, false) }.to raise_error(expected)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
@@ -1,164 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Copyright:: Copyright (c) 2018 Chef Software Inc.
|
3
|
-
# License:: Apache License, Version 2.0
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
-
# you may not use this file except in compliance with the License.
|
7
|
-
# You may obtain a copy of the License at
|
8
|
-
#
|
9
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
#
|
11
|
-
# Unless required by applicable law or agreed to in writing, software
|
12
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
-
# See the License for the specific language governing permissions and
|
15
|
-
# limitations under the License.
|
16
|
-
#
|
17
|
-
|
18
|
-
require "spec_helper"
|
19
|
-
require "chef_apply/action/install_chef"
|
20
|
-
|
21
|
-
RSpec.describe ChefApply::Action::InstallChef do
|
22
|
-
let(:mock_os_name) { "linux" }
|
23
|
-
let(:mock_os_family) { "linux" }
|
24
|
-
let(:mock_os_release ) { "unknown" }
|
25
|
-
let(:mock_opts) do
|
26
|
-
{
|
27
|
-
name: mock_os_name,
|
28
|
-
family: mock_os_family,
|
29
|
-
release: mock_os_release,
|
30
|
-
arch: "x86_64",
|
31
|
-
}
|
32
|
-
end
|
33
|
-
let(:target_host) do
|
34
|
-
ChefApply::TargetHost.mock_instance("mock://user1:password1@localhost", mock_opts)
|
35
|
-
end
|
36
|
-
|
37
|
-
let(:reporter) do
|
38
|
-
ChefApply::MockReporter.new
|
39
|
-
end
|
40
|
-
|
41
|
-
subject(:install) do
|
42
|
-
ChefApply::Action::InstallChef.new(target_host: target_host,
|
43
|
-
reporter: reporter,
|
44
|
-
check_only: false)
|
45
|
-
end
|
46
|
-
|
47
|
-
context "#perform_action" do
|
48
|
-
context "when chef is already installed on target" do
|
49
|
-
it "notifies of success and takes no further action" do
|
50
|
-
expect(ChefApply::Action::InstallChef::MinimumChefVersion).to receive(:check!).with(install.target_host, false)
|
51
|
-
.and_return(:minimum_version_met)
|
52
|
-
expect(install).not_to receive(:perform_local_install)
|
53
|
-
install.perform_action
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
context "when chef is not already installed on target" do
|
58
|
-
it "should invoke perform_local_install" do
|
59
|
-
expect(ChefApply::Action::InstallChef::MinimumChefVersion).to receive(:check!).with(install.target_host, false)
|
60
|
-
.and_return(:client_not_installed)
|
61
|
-
expect(install).to receive(:perform_local_install)
|
62
|
-
install.perform_action
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
context "#perform_local_install" do
|
68
|
-
let(:artifact) { double("artifact") }
|
69
|
-
let(:package_url) { "https://chef.io/download/package/here" }
|
70
|
-
before do
|
71
|
-
allow(artifact).to receive(:url).and_return package_url
|
72
|
-
end
|
73
|
-
|
74
|
-
it "performs the steps necessary to perform an installation" do
|
75
|
-
expect(install).to receive(:lookup_artifact).and_return artifact
|
76
|
-
expect(install).to receive(:download_to_workstation).with(package_url) .and_return "/local/path"
|
77
|
-
expect(install).to receive(:upload_to_target).with("/local/path").and_return("/remote/path")
|
78
|
-
expect(target_host).to receive(:install_package).with("/remote/path")
|
79
|
-
|
80
|
-
install.perform_local_install
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
context "#train_to_mixlib" do
|
85
|
-
let(:platform) { double }
|
86
|
-
before do
|
87
|
-
allow(platform).to receive(:release).and_return "1234"
|
88
|
-
allow(platform).to receive(:name).and_return "beos"
|
89
|
-
allow(platform).to receive(:arch).and_return "ppc"
|
90
|
-
end
|
91
|
-
|
92
|
-
context "when any flavor of windows" do
|
93
|
-
before do
|
94
|
-
allow(platform).to receive(:name).and_return "windows_10_pro_n"
|
95
|
-
end
|
96
|
-
|
97
|
-
it "sets platform name to 'windows'" do
|
98
|
-
mixlib_info = install.train_to_mixlib(platform)
|
99
|
-
expect(mixlib_info[:platform]).to eq "windows"
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
context "when redhat" do
|
104
|
-
before do
|
105
|
-
allow(platform).to receive(:name).and_return "redhat"
|
106
|
-
end
|
107
|
-
|
108
|
-
it "sets platform name to 'el'" do
|
109
|
-
mixlib_info = install.train_to_mixlib(platform)
|
110
|
-
expect(mixlib_info[:platform]).to eq "el"
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
context "when centos" do
|
115
|
-
before do
|
116
|
-
allow(platform).to receive(:name).and_return "centos"
|
117
|
-
end
|
118
|
-
|
119
|
-
it "sets platform name to 'el'" do
|
120
|
-
mixlib_info = install.train_to_mixlib(platform)
|
121
|
-
expect(mixlib_info[:platform]).to eq "el"
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
context "when suse" do
|
126
|
-
before do
|
127
|
-
allow(platform).to receive(:name).and_return "suse"
|
128
|
-
end
|
129
|
-
|
130
|
-
it "sets platform name to 'sles'" do
|
131
|
-
mixlib_info = install.train_to_mixlib(platform)
|
132
|
-
expect(mixlib_info[:platform]).to eq "sles"
|
133
|
-
end
|
134
|
-
end
|
135
|
-
context "when amazon" do
|
136
|
-
before do
|
137
|
-
allow(platform).to receive(:name).and_return "amazon"
|
138
|
-
end
|
139
|
-
|
140
|
-
context "when amazon linux 1.x" do
|
141
|
-
before do
|
142
|
-
allow(platform).to receive(:release).and_return "2017.09"
|
143
|
-
end
|
144
|
-
|
145
|
-
it "sets platform name to 'amazon' and plaform_version to '6'" do
|
146
|
-
mixlib_info = install.train_to_mixlib(platform)
|
147
|
-
expect(mixlib_info[:platform]).to eq "el"
|
148
|
-
expect(mixlib_info[:platform_version]).to eq "6"
|
149
|
-
end
|
150
|
-
end
|
151
|
-
context "when amazon linux 2.x" do
|
152
|
-
before do
|
153
|
-
allow(platform).to receive(:release).and_return "2"
|
154
|
-
end
|
155
|
-
|
156
|
-
it "sets platform name to 'amazon' and plaform_version to '7'" do
|
157
|
-
mixlib_info = install.train_to_mixlib(platform)
|
158
|
-
expect(mixlib_info[:platform]).to eq "el"
|
159
|
-
expect(mixlib_info[:platform_version]).to eq "7"
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
163
|
-
end
|
164
|
-
end
|
@@ -1,75 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Copyright:: Copyright (c) 2018 Chef Software Inc.
|
3
|
-
# License:: Apache License, Version 2.0
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
-
# you may not use this file except in compliance with the License.
|
7
|
-
# You may obtain a copy of the License at
|
8
|
-
#
|
9
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
#
|
11
|
-
# Unless required by applicable law or agreed to in writing, software
|
12
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
-
# See the License for the specific language governing permissions and
|
15
|
-
# limitations under the License.
|
16
|
-
#
|
17
|
-
|
18
|
-
require "spec_helper"
|
19
|
-
require "mixlib/cli"
|
20
|
-
require "chef_apply/cli/options"
|
21
|
-
require "chef-config/config"
|
22
|
-
|
23
|
-
ChefApply::Config.load
|
24
|
-
|
25
|
-
module ChefApply
|
26
|
-
module CLIOptions
|
27
|
-
class TestClass
|
28
|
-
include Mixlib::CLI
|
29
|
-
include ChefApply::CLI::Options
|
30
|
-
end
|
31
|
-
|
32
|
-
def parse(argv)
|
33
|
-
parse_options(argv)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
RSpec.describe ChefApply::CLIOptions do
|
39
|
-
let(:klass) { ChefApply::CLIOptions::TestClass.new }
|
40
|
-
|
41
|
-
it "contains the specified options" do
|
42
|
-
expect(klass.options.keys).to eq(%i{
|
43
|
-
version
|
44
|
-
help
|
45
|
-
config_path
|
46
|
-
identity_file
|
47
|
-
ssl
|
48
|
-
ssl_verify
|
49
|
-
protocol
|
50
|
-
user
|
51
|
-
password
|
52
|
-
cookbook_repo_paths
|
53
|
-
install
|
54
|
-
sudo
|
55
|
-
sudo_command
|
56
|
-
sudo_password
|
57
|
-
sudo_options
|
58
|
-
})
|
59
|
-
end
|
60
|
-
|
61
|
-
it "persists certain CLI options back to the ChefApply::Config" do
|
62
|
-
# First we check the default value beforehand
|
63
|
-
expect(ChefApply::Config.connection.winrm.ssl).to eq(false)
|
64
|
-
expect(ChefApply::Config.connection.winrm.ssl_verify).to eq(true)
|
65
|
-
expect(ChefApply::Config.connection.default_protocol).to eq("ssh")
|
66
|
-
expect(ChefApply::Config.chef.cookbook_repo_paths).to_not be_empty
|
67
|
-
# Then we set the values and check they are changed
|
68
|
-
klass.parse_options(["--ssl", "--no-ssl-verify", "--protocol", "winrm", "--cookbook-repo-paths", "a,b"])
|
69
|
-
expect(ChefApply::Config.connection.winrm.ssl).to eq(true)
|
70
|
-
expect(ChefApply::Config.connection.winrm.ssl_verify).to eq(false)
|
71
|
-
expect(ChefApply::Config.connection.default_protocol).to eq("winrm")
|
72
|
-
expect(ChefApply::Config.chef.cookbook_repo_paths).to eq(%w{a b})
|
73
|
-
end
|
74
|
-
|
75
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "chef_apply/error"
|
3
|
-
require "chef_apply/cli/validation"
|
4
|
-
|
5
|
-
RSpec.describe ChefApply::CLI::Validation do
|
6
|
-
class Validator
|
7
|
-
include ChefApply::CLI::Validation
|
8
|
-
end
|
9
|
-
subject { Validator.new }
|
10
|
-
|
11
|
-
context "#validate_params" do
|
12
|
-
OptionValidationError = ChefApply::CLI::OptionValidationError
|
13
|
-
it "raises an error if not enough params are specified" do
|
14
|
-
params = [
|
15
|
-
[],
|
16
|
-
%w{one},
|
17
|
-
]
|
18
|
-
params.each do |p|
|
19
|
-
expect { subject.validate_params(p) }.to raise_error(OptionValidationError) do |e|
|
20
|
-
e.id == "CHEFVAL002"
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
it "succeeds if the second command is a valid file path" do
|
26
|
-
params = %w{target /some/path}
|
27
|
-
expect(File).to receive(:exist?).with("/some/path").and_return true
|
28
|
-
expect { subject.validate_params(params) }.to_not raise_error
|
29
|
-
end
|
30
|
-
|
31
|
-
it "succeeds if the second argument looks like a cookbook name" do
|
32
|
-
params = [
|
33
|
-
%w{target cb},
|
34
|
-
%w{target cb::recipe},
|
35
|
-
]
|
36
|
-
params.each do |p|
|
37
|
-
expect { subject.validate_params(p) }.to_not raise_error
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
it "raises an error if the second argument is neither a valid path or a valid cookbook name" do
|
42
|
-
params = %w{target weird%name}
|
43
|
-
expect { subject.validate_params(params) }.to raise_error(OptionValidationError) do |e|
|
44
|
-
e.id == "CHEFVAL004"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
it "raises an error if properties are not specified as key value pairs" do
|
49
|
-
params = [
|
50
|
-
%w{one two three four},
|
51
|
-
%w{one two three four=value five six=value},
|
52
|
-
%w{one two three non.word=value},
|
53
|
-
]
|
54
|
-
params.each do |p|
|
55
|
-
expect { subject.validate_params(p) }.to raise_error(OptionValidationError) do |e|
|
56
|
-
e.id == "CHEFVAL003"
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
describe "#properties_from_string" do
|
62
|
-
it "parses properties into a hash" do
|
63
|
-
provided = %w{key1=value key2=1 key3=true key4=FaLsE key5=0777 key6=https://some.website key7=num1and2digit key_8=underscore key9=127.0.0.1 key10=1. key11=1.1}
|
64
|
-
expected = {
|
65
|
-
"key1" => "value",
|
66
|
-
"key2" => 1,
|
67
|
-
"key3" => true,
|
68
|
-
"key4" => false,
|
69
|
-
"key5" => "0777",
|
70
|
-
"key6" => "https://some.website",
|
71
|
-
"key7" => "num1and2digit",
|
72
|
-
"key_8" => "underscore",
|
73
|
-
"key9" => "127.0.0.1",
|
74
|
-
"key10" => 1.0,
|
75
|
-
"key11" => 1.1,
|
76
|
-
}
|
77
|
-
expect(subject.properties_from_string(provided)).to eq(expected)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
end
|
data/spec/unit/cli_spec.rb
DELETED
@@ -1,475 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Copyright:: Copyright (c) 2018 Chef Software Inc.
|
3
|
-
# License:: Apache License, Version 2.0
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
-
# you may not use this file except in compliance with the License.
|
7
|
-
# You may obtain a copy of the License at
|
8
|
-
#
|
9
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
#
|
11
|
-
# Unless required by applicable law or agreed to in writing, software
|
12
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
-
# See the License for the specific language governing permissions and
|
15
|
-
# limitations under the License.
|
16
|
-
#
|
17
|
-
|
18
|
-
require "spec_helper"
|
19
|
-
require "chef_apply/cli"
|
20
|
-
require "chef_apply/error"
|
21
|
-
require "chef_apply/telemeter"
|
22
|
-
require "chef_apply/telemeter/sender"
|
23
|
-
require "chef_apply/ui/terminal"
|
24
|
-
require "chef_apply/action/generate_temp_cookbook"
|
25
|
-
require "chef_apply/action/generate_temp_cookbook/temp_cookbook"
|
26
|
-
|
27
|
-
require "chef-cli/ui"
|
28
|
-
|
29
|
-
RSpec.describe ChefApply::CLI do
|
30
|
-
subject { ChefApply::CLI.new(argv) }
|
31
|
-
let(:argv) { [] }
|
32
|
-
# TODO why isn't this mocked?
|
33
|
-
let(:telemetry) { ChefApply::Telemeter.instance }
|
34
|
-
|
35
|
-
before do
|
36
|
-
# Avoid messy object dumps in failures because subject is an object instance
|
37
|
-
allow(subject).to receive(:inspect).and_return("The subject instance")
|
38
|
-
end
|
39
|
-
|
40
|
-
describe "run" do
|
41
|
-
before do
|
42
|
-
# Catch all of the calls by default, to prevent the various
|
43
|
-
# startup actions from actually occuring on the workstatoin.
|
44
|
-
allow(telemetry).to receive(:timed_run_capture).and_yield
|
45
|
-
allow(subject).to receive(:perform_run)
|
46
|
-
allow(telemetry).to receive(:commit)
|
47
|
-
end
|
48
|
-
|
49
|
-
it "captures and commits the run to telemetry" do
|
50
|
-
expect(telemetry).to receive(:timed_run_capture)
|
51
|
-
expect(telemetry).to receive(:commit)
|
52
|
-
expect { subject.run }.to exit_with_code(0)
|
53
|
-
end
|
54
|
-
|
55
|
-
it "calls perform_run" do
|
56
|
-
expect(subject).to receive(:perform_run)
|
57
|
-
expect { subject.run }.to exit_with_code(0)
|
58
|
-
end
|
59
|
-
|
60
|
-
context "perform_run raises WrappedError" do
|
61
|
-
let(:e) { ChefApply::WrappedError.new(RuntimeError.new("Test"), "host") }
|
62
|
-
|
63
|
-
it "prints the error and exits" do
|
64
|
-
expect(subject).to receive(:perform_run).and_raise(e)
|
65
|
-
expect(ChefApply::UI::ErrorPrinter).to receive(:show_error).with(e)
|
66
|
-
expect { subject.run }.to exit_with_code(1)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
context "perform_run raises SystemExit" do
|
71
|
-
it "exits with same exit code" do
|
72
|
-
expect(subject).to receive(:perform_run).and_raise(SystemExit.new(99))
|
73
|
-
expect { subject.run }.to exit_with_code(99)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
context "perform_run raises any other exception" do
|
78
|
-
let(:e) { Exception.new("test") }
|
79
|
-
|
80
|
-
it "exits with code 64" do
|
81
|
-
expect(subject).to receive(:perform_run).and_raise(e)
|
82
|
-
expect(ChefApply::UI::ErrorPrinter).to receive(:dump_unexpected_error).with(e)
|
83
|
-
expect { subject.run }.to exit_with_code(64)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
describe "#perform_run" do
|
89
|
-
it "parses options" do
|
90
|
-
expect(subject).to receive(:parse_options).with(argv)
|
91
|
-
subject.perform_run
|
92
|
-
end
|
93
|
-
|
94
|
-
context "when any error is raised" do
|
95
|
-
let(:e) { RuntimeError.new("Test") }
|
96
|
-
before do
|
97
|
-
allow(subject).to receive(:parse_options).and_raise(e)
|
98
|
-
end
|
99
|
-
|
100
|
-
it "calls handle_perform_error" do
|
101
|
-
expect(subject).to receive(:handle_perform_error).with(e)
|
102
|
-
subject.perform_run
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
context "when argv is empty" do
|
107
|
-
let(:argv) { [] }
|
108
|
-
it "shows the help text" do
|
109
|
-
expect(subject).to receive(:show_help)
|
110
|
-
subject.perform_run
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
context "when help flags are passed" do
|
115
|
-
%w{-h --help}.each do |flag|
|
116
|
-
context flag do
|
117
|
-
let(:argv) { [flag] }
|
118
|
-
it "shows the help text" do
|
119
|
-
expect(subject).to receive(:show_help)
|
120
|
-
subject.perform_run
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
%w{-v --version}.each do |flag|
|
126
|
-
context flag do
|
127
|
-
let(:argv) { [flag] }
|
128
|
-
it "shows the help text" do
|
129
|
-
expect(subject).to receive(:show_version)
|
130
|
-
subject.perform_run
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
context "when arguments are provided" do
|
137
|
-
let(:argv) { ["hostname", "resourcetype", "resourcename", "someproperty=true"] }
|
138
|
-
let(:target_hosts) { [double("TargetHost")] }
|
139
|
-
before do
|
140
|
-
# parse_options sets `cli_argument` - because we stub out parse_options,
|
141
|
-
# later calls that rely on cli_arguments will fail without this.
|
142
|
-
allow(subject).to receive(:cli_arguments).and_return argv
|
143
|
-
end
|
144
|
-
|
145
|
-
context "and they are valid" do
|
146
|
-
it "creates the cookbook locally and converges it" do
|
147
|
-
expect(subject).to receive(:parse_options)
|
148
|
-
expect(subject).to receive(:check_license_acceptance)
|
149
|
-
expect(subject).to receive(:validate_params)
|
150
|
-
expect(subject).to receive(:resolve_targets).and_return target_hosts
|
151
|
-
expect(subject).to receive(:render_cookbook_setup)
|
152
|
-
expect(subject).to receive(:render_converge).with(target_hosts)
|
153
|
-
subject.perform_run
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
describe "#check_license_acceptance" do
|
160
|
-
let(:acceptance_value) { "accept-no-persist" }
|
161
|
-
let(:acceptor) { instance_double(LicenseAcceptance::Acceptor) }
|
162
|
-
|
163
|
-
before do
|
164
|
-
ChefApply::Config.reset
|
165
|
-
expect(LicenseAcceptance::Acceptor).to receive(:new).with(provided: ChefApply::Config.chef.chef_license).and_return(acceptor)
|
166
|
-
end
|
167
|
-
|
168
|
-
it "sets the config value to the acceptance value" do
|
169
|
-
expect(ChefApply::Config.chef.chef_license).to eq(nil)
|
170
|
-
expect(acceptor).to receive(:check_and_persist).with("infra-client", "latest")
|
171
|
-
expect(acceptor).to receive(:acceptance_value).and_return(acceptance_value)
|
172
|
-
subject.check_license_acceptance
|
173
|
-
expect(ChefApply::Config.chef.chef_license).to eq(acceptance_value)
|
174
|
-
end
|
175
|
-
|
176
|
-
describe "when the user does not accept the license" do
|
177
|
-
it "raises a LicenseCheckFailed error" do
|
178
|
-
expect(ChefApply::Config.chef.chef_license).to eq(nil)
|
179
|
-
expect(acceptor).to receive(:check_and_persist).with("infra-client", "latest").and_raise(LicenseAcceptance::LicenseNotAcceptedError.new(nil, []))
|
180
|
-
expect { subject.check_license_acceptance }.to raise_error(ChefApply::LicenseCheckFailed)
|
181
|
-
expect(ChefApply::Config.chef.chef_license).to eq(nil)
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
describe "#connect_target" do
|
187
|
-
let(:host) { double("TargetHost", config: {}, user: "root" ) }
|
188
|
-
let(:reporter) { double("reporter", update: :ok, success: :ok) }
|
189
|
-
it "invokes do_connect with correct options" do
|
190
|
-
expect(subject).to receive(:do_connect)
|
191
|
-
.with(host, reporter)
|
192
|
-
subject.connect_target(host, reporter)
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
describe "#generate_temp_cookbook" do
|
197
|
-
before do
|
198
|
-
allow(subject).to receive(:parsed_options).and_return({ cookbook_repo_paths: "/tmp" })
|
199
|
-
end
|
200
|
-
let(:temp_cookbook) { double("TempCookbook") }
|
201
|
-
let(:action) { double("generator", generated_cookbook: temp_cookbook) }
|
202
|
-
|
203
|
-
context "when a resource is provided" do
|
204
|
-
it "gets an action via GenerateTempCookbook.from_options and executes it " do
|
205
|
-
expect(ChefApply::Action::GenerateTempCookbook)
|
206
|
-
.to receive(:from_options)
|
207
|
-
.with(resource_type: "user",
|
208
|
-
resource_name: "test", resource_properties: {})
|
209
|
-
.and_return(action)
|
210
|
-
expect(action).to receive(:run)
|
211
|
-
expect(subject.generate_temp_cookbook(%w{user test}, nil)).to eq temp_cookbook
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
context "when a recipe specifier is provided" do
|
216
|
-
|
217
|
-
it "gets an action via GenerateTempCookbook.from_options and executes it" do
|
218
|
-
expect(ChefApply::Action::GenerateTempCookbook)
|
219
|
-
.to receive(:from_options)
|
220
|
-
.with(recipe_spec: "mycookbook::default", cookbook_repo_paths: "/tmp")
|
221
|
-
.and_return(action)
|
222
|
-
expect(action).to receive(:run)
|
223
|
-
subject.generate_temp_cookbook(["mycookbook::default"], nil)
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
context "when generator posts event:" do
|
228
|
-
let(:reporter) { double("reporter") }
|
229
|
-
before do
|
230
|
-
expect(ChefApply::Action::GenerateTempCookbook)
|
231
|
-
.to receive(:from_options)
|
232
|
-
.and_return(action)
|
233
|
-
allow(action).to receive(:run) { |&block| block.call(event, event_args) }
|
234
|
-
end
|
235
|
-
|
236
|
-
context ":generating" do
|
237
|
-
let(:event) { :generating }
|
238
|
-
let(:event_args) { nil }
|
239
|
-
it "updates message text via reporter" do
|
240
|
-
expected_text = ChefApply::CLI::TS.generate_temp_cookbook.generating
|
241
|
-
expect(reporter).to receive(:update).with(expected_text)
|
242
|
-
subject.generate_temp_cookbook(%w{user jimbo}, reporter)
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
context ":success" do
|
247
|
-
let(:event) { :success }
|
248
|
-
let(:event_args) { [ temp_cookbook ] }
|
249
|
-
it "indicates success via reporter and returns the cookbook" do
|
250
|
-
expected_text = ChefApply::CLI::TS.generate_temp_cookbook.success
|
251
|
-
expect(reporter).to receive(:success).with(expected_text)
|
252
|
-
expect(subject.generate_temp_cookbook(%w{user jimbo}, reporter))
|
253
|
-
.to eq temp_cookbook
|
254
|
-
end
|
255
|
-
end
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
|
-
describe "#generate_local_policy" do
|
260
|
-
let(:reporter) { double("reporter") }
|
261
|
-
let(:action) { double("GenerateLocalPolicy") }
|
262
|
-
let(:temp_cookbook) { instance_double("TempCookbook") }
|
263
|
-
let(:archive_file_location) { "/temp/archive.gz" }
|
264
|
-
|
265
|
-
before do
|
266
|
-
allow(subject).to receive(:temp_cookbook).and_return temp_cookbook
|
267
|
-
allow(action).to receive(:archive_file_location).and_return archive_file_location
|
268
|
-
end
|
269
|
-
it "creates a GenerateLocalPolicy action and executes it" do
|
270
|
-
expect(ChefApply::Action::GenerateLocalPolicy).to receive(:new)
|
271
|
-
.with(cookbook: temp_cookbook)
|
272
|
-
.and_return(action)
|
273
|
-
expect(action).to receive(:run)
|
274
|
-
subject.generate_local_policy(reporter)
|
275
|
-
end
|
276
|
-
|
277
|
-
context "when generator posts an event:" do
|
278
|
-
before do
|
279
|
-
expect(ChefApply::Action::GenerateLocalPolicy).to receive(:new)
|
280
|
-
.with(cookbook: temp_cookbook)
|
281
|
-
.and_return(action)
|
282
|
-
allow(action).to receive(:run) { |&block| block.call(event, event_args) }
|
283
|
-
end
|
284
|
-
|
285
|
-
context ":generating" do
|
286
|
-
let(:event) { :generating }
|
287
|
-
let(:event_args) { nil }
|
288
|
-
let(:expected_msg) { ChefApply::CLI::TS.generate_local_policy.generating }
|
289
|
-
it "updates message text correctly via reporter" do
|
290
|
-
expect(reporter).to receive(:update).with(expected_msg)
|
291
|
-
subject.generate_local_policy(reporter)
|
292
|
-
end
|
293
|
-
|
294
|
-
end
|
295
|
-
|
296
|
-
context ":exporting" do
|
297
|
-
let(:event) { :exporting }
|
298
|
-
let(:event_args) { nil }
|
299
|
-
let(:expected_msg) { ChefApply::CLI::TS.generate_local_policy.exporting }
|
300
|
-
it "updates message text correctly via reporter" do
|
301
|
-
expect(reporter).to receive(:update).with(expected_msg)
|
302
|
-
subject.generate_local_policy(reporter)
|
303
|
-
end
|
304
|
-
end
|
305
|
-
|
306
|
-
context ":success" do
|
307
|
-
let(:event) { :success }
|
308
|
-
let(:expected_msg) { ChefApply::CLI::TS.generate_local_policy.success }
|
309
|
-
let(:event_args) { [archive_file_location] }
|
310
|
-
it "indicates success via reporter and returns the archive file location" do
|
311
|
-
expect(reporter).to receive(:success).with(expected_msg)
|
312
|
-
expect(subject.generate_local_policy(reporter)).to eq archive_file_location
|
313
|
-
end
|
314
|
-
end
|
315
|
-
end
|
316
|
-
end
|
317
|
-
|
318
|
-
describe "#render_cookbook_setup" do
|
319
|
-
let(:reporter) { instance_double(ChefApply::StatusReporter) }
|
320
|
-
let(:temp_cookbook) { double(ChefApply::Action::GenerateTempCookbook::TempCookbook) }
|
321
|
-
let(:archive_file_location) { "/path/to/archive" }
|
322
|
-
let(:args) { [] }
|
323
|
-
# before do
|
324
|
-
# allow(ChefApply::UI::Terminal).to receive(:render_job).and_yield(reporter)
|
325
|
-
# end
|
326
|
-
|
327
|
-
it "generates the cookbook and local policy" do
|
328
|
-
expect(ChefApply::UI::Terminal).to receive(:render_job) do |initial_msg, job|
|
329
|
-
job.run(reporter)
|
330
|
-
end
|
331
|
-
expect(subject).to receive(:generate_temp_cookbook)
|
332
|
-
.with(args, reporter).and_return temp_cookbook
|
333
|
-
expect(ChefApply::UI::Terminal).to receive(:render_job) do |initial_msg, job|
|
334
|
-
job.run(reporter)
|
335
|
-
end
|
336
|
-
expect(subject).to receive(:generate_local_policy)
|
337
|
-
.with(reporter).and_return archive_file_location
|
338
|
-
subject.render_cookbook_setup(args)
|
339
|
-
end
|
340
|
-
end
|
341
|
-
|
342
|
-
describe "#render_converge" do
|
343
|
-
|
344
|
-
let(:reporter) { instance_double(ChefApply::StatusReporter) }
|
345
|
-
let(:host1) { ChefApply::TargetHost.new("ssh://host1") }
|
346
|
-
let(:host2) { ChefApply::TargetHost.new("ssh://host2") }
|
347
|
-
let(:cookbook_type) { :resource } # || :recipe
|
348
|
-
let(:temp_cookbook) do
|
349
|
-
instance_double(ChefApply::Action::GenerateTempCookbook::TempCookbook,
|
350
|
-
descriptor: "resource[name]",
|
351
|
-
from: "resource")
|
352
|
-
end
|
353
|
-
let(:archive_file_location) { "/path/to/archive" }
|
354
|
-
|
355
|
-
before do
|
356
|
-
allow(subject).to receive(:temp_cookbook).and_return temp_cookbook
|
357
|
-
allow(subject).to receive(:archive_file_location).and_return archive_file_location
|
358
|
-
expected_header = ChefApply::CLI::TS.converge.header(2, temp_cookbook.descriptor, temp_cookbook.from)
|
359
|
-
allow(ChefApply::UI::Terminal).to receive(:render_parallel_jobs) do |header, jobs|
|
360
|
-
expect(header).to eq expected_header
|
361
|
-
jobs.each { |j| j.run(reporter) }
|
362
|
-
end
|
363
|
-
end
|
364
|
-
|
365
|
-
let(:target_hosts) { [host1, host2] }
|
366
|
-
it "connects, installs chef, and converges for each target" do
|
367
|
-
target_hosts.each do |host|
|
368
|
-
expect(subject).to receive(:connect_target).with(host, reporter)
|
369
|
-
expect(subject).to receive(:install).with(host, reporter)
|
370
|
-
expect(subject).to receive(:converge).with(reporter, archive_file_location, host)
|
371
|
-
end
|
372
|
-
subject.render_converge(target_hosts)
|
373
|
-
end
|
374
|
-
end
|
375
|
-
|
376
|
-
describe "#install" do
|
377
|
-
let(:upgrading) { false }
|
378
|
-
let(:target_host) { double("targethost", installed_chef_version: "14.0") }
|
379
|
-
let(:reporter) { double("reporter") }
|
380
|
-
let(:action) do
|
381
|
-
double("ChefApply::Actions::InstallChef",
|
382
|
-
upgrading?: upgrading,
|
383
|
-
version_to_install: "14.0")
|
384
|
-
end
|
385
|
-
|
386
|
-
it "updates status, creates an InstallChef action and executes it" do
|
387
|
-
expect(reporter)
|
388
|
-
.to receive(:update)
|
389
|
-
.with(ChefApply::CLI::TS.install_chef.verifying)
|
390
|
-
expect(ChefApply::Action::InstallChef).to receive(:new)
|
391
|
-
.with(target_host: target_host, check_only: false)
|
392
|
-
.and_return action
|
393
|
-
expect(action).to receive(:run)
|
394
|
-
subject.install(target_host, reporter)
|
395
|
-
end
|
396
|
-
|
397
|
-
context "when generator posts event:" do
|
398
|
-
let(:event_args) { nil }
|
399
|
-
let(:text_context) { ChefApply::Text.status.install_chef }
|
400
|
-
|
401
|
-
before do
|
402
|
-
allow(ChefApply::Action::InstallChef)
|
403
|
-
.to receive(:new).and_return action
|
404
|
-
allow(action)
|
405
|
-
.to receive(:run) { |&block| block.call(event, event_args) }
|
406
|
-
allow(reporter)
|
407
|
-
.to receive(:update).with(ChefApply::CLI::TS.install_chef.verifying)
|
408
|
-
end
|
409
|
-
|
410
|
-
context ":installing" do
|
411
|
-
let(:event) { :installing }
|
412
|
-
|
413
|
-
context "when installer is upgrading" do
|
414
|
-
let(:upgrading) { true }
|
415
|
-
it "reports the update correctly" do
|
416
|
-
expect(reporter).to receive(:update).with(text_context.upgrading(target_host.installed_chef_version, action.version_to_install))
|
417
|
-
subject.install(target_host, reporter)
|
418
|
-
end
|
419
|
-
end
|
420
|
-
|
421
|
-
context "when installer is installing clean" do
|
422
|
-
let(:upgrading) { false }
|
423
|
-
it "reports the update correctly" do
|
424
|
-
expect(reporter).to receive(:update).with(text_context.installing(action.version_to_install))
|
425
|
-
subject.install(target_host, reporter)
|
426
|
-
end
|
427
|
-
end
|
428
|
-
end
|
429
|
-
|
430
|
-
context ":uploading" do
|
431
|
-
let(:event) { :uploading }
|
432
|
-
it "reports the update correctly" do
|
433
|
-
expect(reporter).to receive(:update).with(text_context.uploading)
|
434
|
-
subject.install(target_host, reporter)
|
435
|
-
end
|
436
|
-
end
|
437
|
-
|
438
|
-
context ":downloading" do
|
439
|
-
let(:event) { :downloading }
|
440
|
-
it "reports the update correctly" do
|
441
|
-
expect(reporter).to receive(:update).with(text_context.downloading)
|
442
|
-
subject.install(target_host, reporter)
|
443
|
-
end
|
444
|
-
end
|
445
|
-
|
446
|
-
context ":already_installed" do
|
447
|
-
let(:event) { :already_installed }
|
448
|
-
it "reports the update correctly" do
|
449
|
-
expect(reporter).to receive(:update).with(text_context.already_present(target_host.installed_chef_version))
|
450
|
-
subject.install(target_host, reporter)
|
451
|
-
end
|
452
|
-
end
|
453
|
-
|
454
|
-
context ":install_complete" do
|
455
|
-
let(:event) { :install_complete }
|
456
|
-
context "when installer is upgrading" do
|
457
|
-
let(:upgrading) { true }
|
458
|
-
it "reports the update correctly" do
|
459
|
-
expect(reporter).to receive(:update).with(text_context.upgrade_success(target_host.installed_chef_version,
|
460
|
-
action.version_to_install))
|
461
|
-
subject.install(target_host, reporter)
|
462
|
-
end
|
463
|
-
end
|
464
|
-
|
465
|
-
context "when installer installing clean" do
|
466
|
-
let(:upgrading) { false }
|
467
|
-
it "reports the update correctly" do
|
468
|
-
expect(reporter).to receive(:update).with(text_context.install_success(target_host.installed_chef_version))
|
469
|
-
subject.install(target_host, reporter)
|
470
|
-
end
|
471
|
-
end
|
472
|
-
end
|
473
|
-
end
|
474
|
-
end
|
475
|
-
end
|