chef-apply 0.1.17 → 0.1.18

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.
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