chef-apply 0.1.17 → 0.1.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -7
  3. data/Gemfile.lock +176 -84
  4. data/chef-apply.gemspec +2 -2
  5. data/lib/chef_apply/version.rb +1 -1
  6. data/spec/fixtures/custom_config.toml +2 -0
  7. data/spec/integration/chef-run_spec.rb +41 -0
  8. data/spec/integration/fixtures/chef_help.out +69 -0
  9. data/spec/integration/fixtures/chef_version.out +1 -0
  10. data/spec/integration/spec_helper.rb +55 -0
  11. data/spec/spec_helper.rb +114 -0
  12. data/spec/support/matchers/output_to_terminal.rb +36 -0
  13. data/spec/unit/action/base_spec.rb +89 -0
  14. data/spec/unit/action/converge_target_spec.rb +292 -0
  15. data/spec/unit/action/generate_local_policy_spec.rb +114 -0
  16. data/spec/unit/action/generate_temp_cookbook_spec.rb +75 -0
  17. data/spec/unit/action/install_chef/base_spec.rb +234 -0
  18. data/spec/unit/action/install_chef_spec.rb +69 -0
  19. data/spec/unit/cli/options_spec.rb +75 -0
  20. data/spec/unit/cli/validation_spec.rb +78 -0
  21. data/spec/unit/cli_spec.rb +440 -0
  22. data/spec/unit/config_spec.rb +70 -0
  23. data/spec/unit/errors/ccr_failure_mapper_spec.rb +103 -0
  24. data/spec/unit/file_fetcher_spec.rb +40 -0
  25. data/spec/unit/fixtures/multi-error.out +2 -0
  26. data/spec/unit/log_spec.rb +37 -0
  27. data/spec/unit/recipe_lookup_spec.rb +122 -0
  28. data/spec/unit/startup_spec.rb +283 -0
  29. data/spec/unit/target_host_spec.rb +231 -0
  30. data/spec/unit/target_resolver_spec.rb +380 -0
  31. data/spec/unit/telemeter/sender_spec.rb +140 -0
  32. data/spec/unit/telemeter_spec.rb +191 -0
  33. data/spec/unit/temp_cookbook_spec.rb +199 -0
  34. data/spec/unit/ui/error_printer_spec.rb +173 -0
  35. data/spec/unit/ui/terminal_spec.rb +109 -0
  36. data/spec/unit/version_spec.rb +31 -0
  37. data/warning.txt +3 -0
  38. metadata +34 -2
@@ -0,0 +1,114 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2017 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
+ require "spec_helper"
18
+ require "chef_apply/action/generate_local_policy"
19
+ require "chef-dk/policyfile_services/install"
20
+ require "chef-dk/ui"
21
+ require "chef-dk/policyfile_services/export_repo"
22
+
23
+ RSpec.describe ChefApply::Action::GenerateLocalPolicy do
24
+ subject { ChefApply::Action::GenerateLocalPolicy.new(cookbook: cookbook) }
25
+ let(:cookbook) do
26
+ double("TempCookbook",
27
+ path: "/my/temp/cookbook",
28
+ export_path: "/my/temp/cookbook/export",
29
+ policyfile_lock_path: "/my/temp/cookbook/policyfile.lock")
30
+ end
31
+
32
+ let(:installer_double) do
33
+ instance_double(ChefDK::PolicyfileServices::Install, run: :ok)
34
+ end
35
+
36
+ let(:exporter_double) do
37
+ instance_double(ChefDK::PolicyfileServices::ExportRepo,
38
+ archive_file_location: "/path/to/export",
39
+ run: :ok)
40
+ end
41
+
42
+ before do
43
+ allow(subject).to receive(:notify)
44
+ end
45
+
46
+ describe "#perform_action" do
47
+ context "in the normal case" do
48
+ it "exports the policy notifying caller of progress, setting archive_file_location" do
49
+ expect(subject).to receive(:notify).ordered.with(:generating)
50
+ expect(subject).to receive(:installer).ordered.and_return installer_double
51
+ expect(installer_double).to receive(:run).ordered
52
+ expect(subject).to receive(:notify).ordered.with(:exporting)
53
+ expect(subject).to receive(:exporter).ordered.and_return exporter_double
54
+ expect(exporter_double).to receive(:run).ordered
55
+ expect(subject).to receive(:exporter).ordered.and_return exporter_double
56
+ expect(subject).to receive(:notify).ordered.with(:success)
57
+ subject.perform_action
58
+ expect(subject.archive_file_location).to eq("/path/to/export")
59
+ end
60
+ end
61
+
62
+ context "when PolicyfileServices raises an error" do
63
+ it "reraises as PolicyfileInstallError" do
64
+ expect(subject).to receive(:installer).and_return installer_double
65
+ expect(installer_double).to receive(:run).and_raise(ChefDK::PolicyfileInstallError.new("", nil))
66
+ expect { subject.perform_action }.to raise_error(ChefApply::Action::PolicyfileInstallError)
67
+ end
68
+ end
69
+
70
+ context "when the path name is too long" do
71
+ let(:name) { "THIS_IS_A_REALLY_LONG_STRING111111111111111111111111111111111111111111111111111111" }
72
+
73
+ # There is an issue with policyfile generation where, if we have a cookbook with too long
74
+ # of a name or directory name the policyfile will not generate. This is because the tar
75
+ # library that ChefDK uses comes from the Rubygems package and is meant for packaging
76
+ # gems up, so it can impose a 100 character limit. We attempt to solve this by ensuring
77
+ # that the paths/names we generate with `TempCookbook` are short.
78
+ #
79
+ # This is here for documentation
80
+ # 2018-05-18 mp addendum: this cna take upwards of 15s to run on ci nodes, pending
81
+ # for now since it's not testing any Chef Apply functionality.
82
+ xit "fails to create when there is a long path name" do
83
+ err = ChefDK::PolicyfileExportRepoError
84
+ expect { subject.perform_action }.to raise_error(err) do |e|
85
+ expect(e.cause.class).to eq(Gem::Package::TooLongFileName)
86
+ expect(e.cause.message).to match(/should be 100 or less/)
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ describe "#exporter" do
93
+
94
+ it "returns a correctly constructed ExportRepo" do
95
+ expect(ChefDK::PolicyfileServices::ExportRepo).to receive(:new)
96
+ .with(policyfile: cookbook.policyfile_lock_path,
97
+ root_dir: cookbook.path,
98
+ export_dir: cookbook.export_path,
99
+ archive: true, force: true)
100
+ .and_return exporter_double
101
+ expect(subject.exporter).to eq exporter_double
102
+ end
103
+ end
104
+
105
+ describe "#installer" do
106
+ it "returns a correctly constructed Install service" do
107
+ expect(ChefDK::PolicyfileServices::Install).to receive(:new)
108
+ .with(ui: ChefDK::UI, root_dir: cookbook.path)
109
+ .and_return(installer_double)
110
+ expect(subject.installer).to eq installer_double
111
+ end
112
+ end
113
+
114
+ end
@@ -0,0 +1,75 @@
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/generate_temp_cookbook"
19
+
20
+ RSpec.describe ChefApply::Action::GenerateTempCookbook do
21
+ let(:options) { {} }
22
+ subject { ChefApply::Action::GenerateTempCookbook }
23
+
24
+ describe ".from_options" do
25
+ context "when given options for a recipe" do
26
+ let(:options) { { recipe_spec: "some::recipe" } }
27
+ it "returns a GenerateCookbookFromRecipe action" do
28
+ expect(subject.from_options(options)).to be_a(ChefApply::Action::GenerateCookbookFromRecipe)
29
+ end
30
+ end
31
+
32
+ context "when given options for a resource" do
33
+ let(:resource_properties) { {} }
34
+ let(:options) do
35
+ { resource_name: "user1", resource_type: "user",
36
+ resource_properties: resource_properties } end
37
+
38
+ it "returns a GenerateCookbookFromResource action" do
39
+ expect(subject.from_options(options)).to be_a ChefApply::Action::GenerateCookbookFromResource
40
+ end
41
+ end
42
+
43
+ context "when not given sufficient options for either" do
44
+ let(:options) { {} }
45
+ it "raises MissingOptions" do
46
+ expect { subject.from_options(options) }.to raise_error ChefApply::Action::MissingOptions
47
+ end
48
+ end
49
+
50
+ end
51
+
52
+ describe "#perform_action" do
53
+ subject { ChefApply::Action::GenerateTempCookbook.new( {} ) }
54
+ it "generates a cookbook, notifies caller, and makes the cookbook available" do
55
+
56
+ expect(subject).to receive(:notify).ordered.with(:generating)
57
+ expect(subject).to receive(:generate)
58
+ expect(subject).to receive(:notify).ordered.with(:success)
59
+ subject.perform_action
60
+ expect(subject.generated_cookbook).to_not be nil
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+
67
+ RSpec.describe ChefApply::Action::GenerateCookbookFromRecipe do
68
+ describe "#generate" do
69
+ end
70
+ end
71
+
72
+ RSpec.describe ChefApply::Action::GenerateCookbookFromResource do
73
+ describe "#generate" do
74
+ end
75
+ end
@@ -0,0 +1,234 @@
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
+ require "chef_apply/target_host"
21
+
22
+ RSpec.describe ChefApply::Action::InstallChef::Base do
23
+ let(:mock_os_name) { "mock" }
24
+ let(:mock_os_family) { "mock" }
25
+ let(:mock_os_release ) { "unknown" }
26
+ let(:mock_opts) do
27
+ {
28
+ name: mock_os_name,
29
+ family: mock_os_family,
30
+ release: mock_os_release,
31
+ arch: "x86_64",
32
+ }
33
+ end
34
+ let(:target_host) do
35
+ ChefApply::TargetHost.new("mock://user1:password1@localhost")
36
+ end
37
+
38
+ let(:reporter) do
39
+ ChefApply::MockReporter.new
40
+ end
41
+
42
+ subject(:install) do
43
+ ChefApply::Action::InstallChef::Base.new(target_host: target_host,
44
+ reporter: reporter) end
45
+ before do
46
+ target_host.connect!
47
+ target_host.backend.mock_os(mock_opts)
48
+ end
49
+
50
+ context "#perform_action" do
51
+ context "when chef is already installed on target" do
52
+ it "notifies of success and takes no further action" do
53
+ expect(install).to receive(:check_minimum_chef_version!).with(install.target_host)
54
+ .and_return(:minimum_version_met)
55
+ expect(install).not_to receive(:perform_local_install)
56
+ install.perform_action
57
+ end
58
+ end
59
+
60
+ context "when chef is not already installed on target" do
61
+ it "should invoke perform_local_install" do
62
+ expect(install).to receive(:check_minimum_chef_version!).with(install.target_host)
63
+ .and_return(:client_not_installed)
64
+ expect(install).to receive(:perform_local_install)
65
+ install.perform_action
66
+ end
67
+ end
68
+ end
69
+
70
+ context "#perform_local_install" do
71
+ let(:artifact) { double("artifact") }
72
+ let(:package_url) { "https://chef.io/download/package/here" }
73
+ before do
74
+ allow(artifact).to receive(:url).and_return package_url
75
+ end
76
+
77
+ it "performs the steps necessary to perform an installation" do
78
+ expect(install).to receive(:lookup_artifact).and_return artifact
79
+ expect(install).to receive(:download_to_workstation).with(package_url) .and_return "/local/path"
80
+ expect(install).to receive(:upload_to_target).with("/local/path").and_return("/remote/path")
81
+ expect(install).to receive(:install_chef_to_target).with("/remote/path")
82
+
83
+ install.perform_local_install
84
+ end
85
+ end
86
+
87
+ context "#train_to_mixlib" do
88
+ let(:platform) { double }
89
+ before do
90
+ allow(platform).to receive(:release).and_return "1234"
91
+ allow(platform).to receive(:name).and_return "beos"
92
+ allow(platform).to receive(:arch).and_return "ppc"
93
+ end
94
+
95
+ context "when any flavor of windows" do
96
+ before do
97
+ allow(platform).to receive(:name).and_return "windows_10_pro_n"
98
+ end
99
+
100
+ it "sets platform name to 'windows'" do
101
+ mixlib_info = install.train_to_mixlib(platform)
102
+ expect(mixlib_info[:platform]).to eq "windows"
103
+ end
104
+ end
105
+
106
+ context "when redhat" do
107
+ before do
108
+ allow(platform).to receive(:name).and_return "redhat"
109
+ end
110
+
111
+ it "sets platform name to 'el'" do
112
+ mixlib_info = install.train_to_mixlib(platform)
113
+ expect(mixlib_info[:platform]).to eq "el"
114
+ end
115
+ end
116
+
117
+ context "when centos" do
118
+ before do
119
+ allow(platform).to receive(:name).and_return "centos"
120
+ end
121
+
122
+ it "sets platform name to 'el'" do
123
+ mixlib_info = install.train_to_mixlib(platform)
124
+ expect(mixlib_info[:platform]).to eq "el"
125
+ end
126
+ end
127
+
128
+ context "when suse" do
129
+ before do
130
+ allow(platform).to receive(:name).and_return "suse"
131
+ end
132
+
133
+ it "sets platform name to 'sles'" do
134
+ mixlib_info = install.train_to_mixlib(platform)
135
+ expect(mixlib_info[:platform]).to eq "sles"
136
+ end
137
+ end
138
+ context "when amazon" do
139
+ before do
140
+ allow(platform).to receive(:name).and_return "amazon"
141
+ end
142
+
143
+ context "when amazon linux 1.x" do
144
+ before do
145
+ allow(platform).to receive(:release).and_return "2017.09"
146
+ end
147
+
148
+ it "sets platform name to 'amazon' and plaform_version to '6'" do
149
+ mixlib_info = install.train_to_mixlib(platform)
150
+ expect(mixlib_info[:platform]).to eq "el"
151
+ expect(mixlib_info[:platform_version]).to eq "6"
152
+ end
153
+ end
154
+ context "when amazon linux 2.x" do
155
+ before do
156
+ allow(platform).to receive(:release).and_return "2"
157
+ end
158
+
159
+ it "sets platform name to 'amazon' and plaform_version to '7'" do
160
+ mixlib_info = install.train_to_mixlib(platform)
161
+ expect(mixlib_info[:platform]).to eq "el"
162
+ expect(mixlib_info[:platform_version]).to eq "7"
163
+ end
164
+ end
165
+ end
166
+ end
167
+
168
+ context "#check_minimum_chef_version!" do
169
+ let(:target) { install.target_host }
170
+ context "when chef is not already installed on target" do
171
+ before do
172
+ expect(target).to receive(:installed_chef_version).
173
+ and_raise ChefApply::TargetHost::ChefNotInstalled.new
174
+ end
175
+
176
+ it "should return :client_not_installed" do
177
+ actual = install.check_minimum_chef_version!(target)
178
+ expect(:client_not_installed).to eq(actual)
179
+ end
180
+
181
+ context "when config is set to check_only" do
182
+ after do
183
+ install.config.clear
184
+ end
185
+
186
+ it "raises ClientNotInstalled" do
187
+ install.config[:check_only] = true
188
+ expect do
189
+ install.check_minimum_chef_version!(target)
190
+ end.to raise_error(ChefApply::Action::InstallChef::ClientNotInstalled)
191
+ end
192
+ end
193
+ end
194
+
195
+ min_14_version = ChefApply::Action::InstallChef::Base::MIN_14_VERSION
196
+ min_13_version = ChefApply::Action::InstallChef::Base::MIN_13_VERSION
197
+ context "when chef is already installed on target at the correct minimum Chef 14 version" do
198
+ before do
199
+ expect(target).to receive(:installed_chef_version).and_return min_14_version
200
+ end
201
+ it "should return :minimum_version_met" do
202
+ actual = install.check_minimum_chef_version!(target)
203
+ expect(:minimum_version_met).to eq(actual)
204
+ end
205
+ end
206
+
207
+ context "when chef is already installed on target at the correct minimum Chef 13 version" do
208
+ before do
209
+ expect(target).to receive(:installed_chef_version).and_return min_13_version
210
+ end
211
+ it "should return :minimum_version_met" do
212
+ actual = install.check_minimum_chef_version!(target)
213
+ expect(:minimum_version_met).to eq(actual)
214
+ end
215
+ end
216
+
217
+ installed_expected = {
218
+ Gem::Version.new("12.1.1") => ChefApply::Action::InstallChef::Client13Outdated,
219
+ Gem::Version.new("13.9.0") => ChefApply::Action::InstallChef::Client13Outdated,
220
+ Gem::Version.new("14.1.0") => ChefApply::Action::InstallChef::Client14Outdated,
221
+ }
222
+ installed_expected.each do |installed, expected|
223
+ context "when chef is already installed on target at version #{installed}" do
224
+ before do
225
+ expect(target).to receive(:installed_chef_version).
226
+ and_return installed
227
+ end
228
+ it "notifies of failure and takes no further action" do
229
+ expect { install.check_minimum_chef_version!(target) }.to raise_error(expected)
230
+ end
231
+ end
232
+ end
233
+ end
234
+ end
@@ -0,0 +1,69 @@
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) { "mock" }
23
+ let(:mock_os_family) { "mock" }
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.new("mock://user1:password1@localhost")
35
+ end
36
+
37
+ subject(:installer) do
38
+ ChefApply::Action::InstallChef
39
+ end
40
+
41
+ before do
42
+ target_host.connect!
43
+ target_host.backend.mock_os(mock_opts)
44
+ end
45
+
46
+ context ".instance_for_target" do
47
+ context "windows target" do
48
+ let(:mock_os_name) { "Windows_Server" }
49
+ let(:mock_os_family) { "windows" }
50
+ let(:mock_os_release) { "10.0.0" }
51
+
52
+ it "should return a InstallChef::Windows instance" do
53
+ inst = installer.instance_for_target(target_host)
54
+ expect(inst).to be_a installer::Windows
55
+ end
56
+ end
57
+
58
+ context "linux target" do
59
+ let(:mock_os_name) { "ubuntu" }
60
+ let(:mock_os_family) { "debian" }
61
+ let(:mock_os_release) { "16.04" }
62
+
63
+ it "should return a InstallChef::Linux instance" do
64
+ inst = installer.instance_for_target(target_host)
65
+ expect(inst).to be_a installer::Linux
66
+ end
67
+ end
68
+ end
69
+ end