chef-apply 0.4.6 → 0.4.9
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/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,36 +0,0 @@
|
|
1
|
-
require "rspec/matchers/built_in/output"
|
2
|
-
require "chef_apply/ui/terminal"
|
3
|
-
|
4
|
-
# Custom behavior for the builtin output matcher
|
5
|
-
# to allow it to handle to_terminal, which integrates
|
6
|
-
# with our UI::Terminal interface.
|
7
|
-
module RSpec
|
8
|
-
module Matchers
|
9
|
-
module BuiltIn
|
10
|
-
class Output < BaseMatcher
|
11
|
-
# @api private
|
12
|
-
# Provides the implementation for `output`.
|
13
|
-
# Not intended to be instantiated directly.
|
14
|
-
def to_terminal
|
15
|
-
@stream_capturer = CaptureTerminal
|
16
|
-
self
|
17
|
-
end
|
18
|
-
module CaptureTerminal
|
19
|
-
def self.name
|
20
|
-
"terminal"
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.capture(block)
|
24
|
-
captured_stream = StringIO.new
|
25
|
-
original_stream = ::ChefApply::UI::Terminal.location
|
26
|
-
::ChefApply::UI::Terminal.location = captured_stream
|
27
|
-
block.call
|
28
|
-
captured_stream.string
|
29
|
-
ensure
|
30
|
-
::ChefApply::UI::Terminal.location = original_stream
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,60 +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/base"
|
20
|
-
require "chef_apply/telemeter"
|
21
|
-
require "chef_apply/target_host"
|
22
|
-
|
23
|
-
RSpec.describe ChefApply::Action::Base do
|
24
|
-
let(:family) { "windows" }
|
25
|
-
let(:target_host) do
|
26
|
-
p = double("platform", family: family)
|
27
|
-
instance_double(ChefApply::TargetHost, platform: p)
|
28
|
-
end
|
29
|
-
let(:opts) do
|
30
|
-
{ target_host: target_host,
|
31
|
-
other: "something-else" }
|
32
|
-
end
|
33
|
-
subject(:action) { ChefApply::Action::Base.new(opts) }
|
34
|
-
|
35
|
-
context "#initialize" do
|
36
|
-
it "properly initializes exposed attr readers" do
|
37
|
-
expect(action.target_host).to eq target_host
|
38
|
-
expect(action.config).to eq({ other: "something-else" })
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
context "#run" do
|
43
|
-
it "runs the underlying action, capturing timing via telemetry" do
|
44
|
-
expect(ChefApply::Telemeter).to receive(:timed_action_capture).with(subject).and_yield
|
45
|
-
expect(action).to receive(:perform_action)
|
46
|
-
action.run
|
47
|
-
end
|
48
|
-
|
49
|
-
it "invokes an action handler when actions occur and a handler is provided" do
|
50
|
-
@run_action = nil
|
51
|
-
@args = nil
|
52
|
-
expect(ChefApply::Telemeter).to receive(:timed_action_capture).with(subject).and_yield
|
53
|
-
expect(action).to receive(:perform_action) { action.notify(:test_success, "some arg", "some other arg") }
|
54
|
-
action.run { |action, args| @run_action = action; @args = args }
|
55
|
-
expect(@run_action).to eq :test_success
|
56
|
-
expect(@args).to eq ["some arg", "some other arg"]
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
end
|
@@ -1,106 +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/converge_target/ccr_failure_mapper"
|
20
|
-
|
21
|
-
RSpec.describe ChefApply::Action::ConvergeTarget::CCRFailureMapper do
|
22
|
-
let(:cause_line) { nil }
|
23
|
-
let(:resource) { "apt_package" }
|
24
|
-
let(:params) do
|
25
|
-
{ resource: resource, resource_name: "a-test-thing",
|
26
|
-
stderr: "an error", stdout: "other output" }
|
27
|
-
end
|
28
|
-
subject { ChefApply::Action::ConvergeTarget::CCRFailureMapper.new(cause_line, params) }
|
29
|
-
|
30
|
-
describe "#exception_args_from_cause" do
|
31
|
-
context "when resource properties have valid names but invalid values" do
|
32
|
-
context "and the property is 'action'" do
|
33
|
-
let(:cause_line) { "Chef::Exceptions::ValidationFailed: Option action must be equal to one of: nothing, install, upgrade, remove, purge, reconfig, lock, unlock! You passed :marve." }
|
34
|
-
it "returns a correct CHEFCCR003" do
|
35
|
-
expect(subject.exception_args_from_cause).to eq(
|
36
|
-
["CHEFCCR003", "marve",
|
37
|
-
"nothing, install, upgrade, remove, purge, reconfig, lock, unlock"]
|
38
|
-
)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
context "and the property is something else" do
|
43
|
-
context "and details are available" do
|
44
|
-
let(:cause_line) { "Chef::Exceptions::ValidationFailed: Option force must be a kind of [TrueClass, FalseClass]! You passed \"purle\"." }
|
45
|
-
it "returns a correct CHEFCCR004 when details are available" do
|
46
|
-
expect(subject.exception_args_from_cause).to eq(
|
47
|
-
["CHEFCCR004",
|
48
|
-
"Option force must be a kind of [TrueClass, FalseClass]! You passed \"purle\"."]
|
49
|
-
)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
context "And less detail is available" do
|
53
|
-
let(:cause_line) { "Chef::Exceptions::User: linux_user[marc] ((chef-client cookbook)::(chef-client recipe) line 1) had an error: Chef::Exceptions::User: Couldn't lookup integer GID for group name blah" }
|
54
|
-
it "returns a correct CHEFCCR002" do
|
55
|
-
expect(subject.exception_args_from_cause).to eq(
|
56
|
-
["CHEFCCR002", "Couldn't lookup integer GID for group name blah"]
|
57
|
-
)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
context "when resource is not a known Chef resource" do
|
64
|
-
let(:cause_line) { "NoMethodError: undefined method `useraaa' for cookbook: (chef-client cookbook), recipe: (chef-client recipe) :Chef::Recipe" }
|
65
|
-
let(:resource) { "useraaa" }
|
66
|
-
it "returns a correct CHEFCCR005" do
|
67
|
-
expect(subject.exception_args_from_cause).to eq(["CHEFCCR005", resource])
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
context "when a resource property does not exist for the given resource" do
|
72
|
-
let(:cause_line) { "NoMethodError: undefined method `badresourceprop' for Chef::Resource::User::LinuxUser" }
|
73
|
-
it "returns a correct CHEFCCR006 " do
|
74
|
-
expect(subject.exception_args_from_cause).to eq(
|
75
|
-
["CHEFCCR006", "badresourceprop", "Chef::Resource::User::LinuxUser"]
|
76
|
-
)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
describe "#raise_mapped_exception!" do
|
82
|
-
context "when no cause is provided" do
|
83
|
-
let(:cause_line) { nil }
|
84
|
-
it "raises a RemoteChefRunFailedToResolveError" do
|
85
|
-
expect { subject.raise_mapped_exception! }.to raise_error(ChefApply::Action::ConvergeTarget::CCRFailureMapper::RemoteChefRunFailedToResolveError)
|
86
|
-
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
context "when a cause is provided" do
|
91
|
-
context "but can't resolve it" do
|
92
|
-
let(:cause_line) { "unparseable mess" }
|
93
|
-
it "raises a RemoteChefClientRunFailedUnknownReason" do
|
94
|
-
expect { subject.raise_mapped_exception! }.to raise_error(ChefApply::Action::ConvergeTarget::CCRFailureMapper::RemoteChefClientRunFailedUnknownReason)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
context "and can resolve the cause" do
|
99
|
-
let(:cause_line) { "NoMethodError: undefined method `badresourceprop' for Chef::Resource::User::LinuxUser" }
|
100
|
-
it "raises a RemoteChefClientRunFailed" do
|
101
|
-
expect { subject.raise_mapped_exception! }.to raise_error(ChefApply::Action::ConvergeTarget::CCRFailureMapper::RemoteChefClientRunFailed)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
@@ -1,400 +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/target_host"
|
20
|
-
require "chef_apply/action/converge_target"
|
21
|
-
require "chef_apply/action/converge_target/ccr_failure_mapper"
|
22
|
-
|
23
|
-
RSpec.describe ChefApply::Action::ConvergeTarget do
|
24
|
-
let(:archive) { "archive.tgz" }
|
25
|
-
let(:cache_path) { "/var/chef-workstation" }
|
26
|
-
let(:platform_family) { "windows" }
|
27
|
-
let(:base_os) { :windows }
|
28
|
-
let(:target_host) do
|
29
|
-
p = double("platform", family: platform_family)
|
30
|
-
double(ChefApply::TargetHost,
|
31
|
-
platform: p, base_os: base_os, ws_cache_path: cache_path)
|
32
|
-
end
|
33
|
-
let(:local_policy_path) { "/local/policy/path/archive.tgz" }
|
34
|
-
let(:opts) { { target_host: target_host, local_policy_path: local_policy_path } }
|
35
|
-
subject { ChefApply::Action::ConvergeTarget.new(opts) }
|
36
|
-
|
37
|
-
before do
|
38
|
-
allow(target_host).to receive(:normalize_path) { |arg| arg }
|
39
|
-
end
|
40
|
-
describe "#create_remote_policy" do
|
41
|
-
let(:remote_archive) { File.join(cache_path, File.basename(archive)) }
|
42
|
-
|
43
|
-
it "pushes it to the remote machine" do
|
44
|
-
expect(target_host).to receive(:upload_file).with(local_policy_path, remote_archive)
|
45
|
-
expect(subject.create_remote_policy(local_policy_path, cache_path)).to eq(remote_archive)
|
46
|
-
end
|
47
|
-
|
48
|
-
it "raises an error if the upload fails" do
|
49
|
-
expect(target_host).to receive(:upload_file).with(local_policy_path, remote_archive).and_raise("foo")
|
50
|
-
err = ChefApply::Action::ConvergeTarget::PolicyUploadFailed
|
51
|
-
expect { subject.create_remote_policy(local_policy_path, cache_path) }.to raise_error(err)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
describe "#create_remote_config" do
|
56
|
-
|
57
|
-
@closed = false # tempfile close indicator
|
58
|
-
let(:remote_folder) { "/tmp/foo" }
|
59
|
-
let(:remote_config_path) { "#{remote_folder}/workstation.rb" }
|
60
|
-
# TODO - mock this, I think we're leaving things behind in /tmp in test runs.
|
61
|
-
let!(:local_tempfile) { Tempfile.new }
|
62
|
-
|
63
|
-
before do
|
64
|
-
allow(Tempfile).to receive(:new).and_return(local_tempfile)
|
65
|
-
end
|
66
|
-
|
67
|
-
it "pushes it to the remote machine" do
|
68
|
-
expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config_path)
|
69
|
-
expect(subject.create_remote_config(remote_folder)).to eq(remote_config_path)
|
70
|
-
# ensure the tempfile is deleted locally
|
71
|
-
expect(local_tempfile.closed?).to eq(true)
|
72
|
-
end
|
73
|
-
|
74
|
-
it "raises an error if the upload fails" do
|
75
|
-
expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config_path).and_raise("foo")
|
76
|
-
err = ChefApply::Action::ConvergeTarget::ConfigUploadFailed
|
77
|
-
expect { subject.create_remote_config(remote_folder) }.to raise_error(err)
|
78
|
-
# ensure the tempfile is deleted locally
|
79
|
-
expect(local_tempfile.closed?).to eq(true)
|
80
|
-
end
|
81
|
-
|
82
|
-
describe "when chef_license is configured" do
|
83
|
-
before do
|
84
|
-
ChefApply::Config.chef.chef_license = "accept-no-persist"
|
85
|
-
end
|
86
|
-
|
87
|
-
after do
|
88
|
-
ChefApply::Config.reset
|
89
|
-
end
|
90
|
-
|
91
|
-
it "creates a config file with chef_license set and quoted" do
|
92
|
-
expect(Tempfile).to receive(:new).and_return(local_tempfile)
|
93
|
-
expect(local_tempfile).to receive(:write).with(<<~EOM
|
94
|
-
local_mode true
|
95
|
-
color false
|
96
|
-
cache_path "#{cache_path}"
|
97
|
-
chef_repo_path "#{cache_path}"
|
98
|
-
require_relative "reporter"
|
99
|
-
reporter = ChefApply::Reporter.new
|
100
|
-
report_handlers << reporter
|
101
|
-
exception_handlers << reporter
|
102
|
-
chef_license "accept-no-persist"
|
103
|
-
EOM
|
104
|
-
)
|
105
|
-
expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config_path)
|
106
|
-
expect(subject.create_remote_config(remote_folder)).to eq(remote_config_path)
|
107
|
-
expect(local_tempfile.closed?).to eq(true)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
describe "when target_level is left default" do
|
112
|
-
before do
|
113
|
-
ChefApply::Config.reset
|
114
|
-
end
|
115
|
-
# TODO - this is a windows config, but we don't set windows?
|
116
|
-
it "creates a config file without a specific log_level (leaving default for chef-client)" do
|
117
|
-
expect(Tempfile).to receive(:new).and_return(local_tempfile)
|
118
|
-
expect(local_tempfile).to receive(:write).with(<<~EOM
|
119
|
-
local_mode true
|
120
|
-
color false
|
121
|
-
cache_path "#{cache_path}"
|
122
|
-
chef_repo_path "#{cache_path}"
|
123
|
-
require_relative "reporter"
|
124
|
-
reporter = ChefApply::Reporter.new
|
125
|
-
report_handlers << reporter
|
126
|
-
exception_handlers << reporter
|
127
|
-
EOM
|
128
|
-
)
|
129
|
-
expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config_path)
|
130
|
-
expect(subject.create_remote_config(remote_folder)).to eq(remote_config_path)
|
131
|
-
expect(local_tempfile.closed?).to eq(true)
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
describe "when target_level is set to a value" do
|
136
|
-
before do
|
137
|
-
ChefApply::Config.log.target_level = "info"
|
138
|
-
end
|
139
|
-
|
140
|
-
after do
|
141
|
-
ChefApply::Config.reset
|
142
|
-
end
|
143
|
-
|
144
|
-
it "creates a config file with the log_level set to the right value" do
|
145
|
-
expect(Tempfile).to receive(:new).and_return(local_tempfile)
|
146
|
-
expect(local_tempfile).to receive(:write).with(<<~EOM
|
147
|
-
local_mode true
|
148
|
-
color false
|
149
|
-
cache_path "#{cache_path}"
|
150
|
-
chef_repo_path "#{cache_path}"
|
151
|
-
require_relative "reporter"
|
152
|
-
reporter = ChefApply::Reporter.new
|
153
|
-
report_handlers << reporter
|
154
|
-
exception_handlers << reporter
|
155
|
-
log_level :info
|
156
|
-
EOM
|
157
|
-
)
|
158
|
-
expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config_path)
|
159
|
-
expect(subject.create_remote_config(remote_folder)).to eq(remote_config_path)
|
160
|
-
expect(local_tempfile.closed?).to eq(true)
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
describe "when data_collector is set in config" do
|
165
|
-
before do
|
166
|
-
ChefApply::Config.data_collector.url = "dc.url"
|
167
|
-
ChefApply::Config.data_collector.token = "dc.token"
|
168
|
-
end
|
169
|
-
|
170
|
-
after do
|
171
|
-
ChefApply::Config.reset
|
172
|
-
end
|
173
|
-
|
174
|
-
it "creates a config file with data collector config values" do
|
175
|
-
expect(Tempfile).to receive(:new).and_return(local_tempfile)
|
176
|
-
expect(local_tempfile).to receive(:write).with(<<~EOM
|
177
|
-
local_mode true
|
178
|
-
color false
|
179
|
-
cache_path "#{cache_path}"
|
180
|
-
chef_repo_path "#{cache_path}"
|
181
|
-
require_relative "reporter"
|
182
|
-
reporter = ChefApply::Reporter.new
|
183
|
-
report_handlers << reporter
|
184
|
-
exception_handlers << reporter
|
185
|
-
data_collector.server_url "dc.url"
|
186
|
-
data_collector.token "dc.token"
|
187
|
-
data_collector.mode :solo
|
188
|
-
data_collector.organization "Chef Workstation"
|
189
|
-
EOM
|
190
|
-
)
|
191
|
-
expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config_path)
|
192
|
-
expect(subject.create_remote_config(remote_folder)).to eq(remote_config_path)
|
193
|
-
# ensure the tempfile is deleted locally
|
194
|
-
expect(local_tempfile.closed?).to eq(true)
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
describe "when data_collector is not set" do
|
199
|
-
before do
|
200
|
-
ChefApply::Config.data_collector.url = nil
|
201
|
-
ChefApply::Config.data_collector.token = nil
|
202
|
-
end
|
203
|
-
|
204
|
-
it "creates a config file without data collector config values" do
|
205
|
-
expect(Tempfile).to receive(:new).and_return(local_tempfile)
|
206
|
-
expect(local_tempfile).to receive(:write).with(<<~EOM
|
207
|
-
local_mode true
|
208
|
-
color false
|
209
|
-
cache_path "#{cache_path}"
|
210
|
-
chef_repo_path "#{cache_path}"
|
211
|
-
require_relative "reporter"
|
212
|
-
reporter = ChefApply::Reporter.new
|
213
|
-
report_handlers << reporter
|
214
|
-
exception_handlers << reporter
|
215
|
-
EOM
|
216
|
-
)
|
217
|
-
expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config_path)
|
218
|
-
expect(subject.create_remote_config(remote_folder)).to eq(remote_config_path)
|
219
|
-
# ensure the tempfile is deleted locally
|
220
|
-
expect(local_tempfile.closed?).to eq(true)
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
describe "#create_remote_handler" do
|
226
|
-
let(:remote_folder) { "/tmp/foo" }
|
227
|
-
let(:remote_reporter) { "#{remote_folder}/reporter.rb" }
|
228
|
-
let!(:local_tempfile) { Tempfile.new }
|
229
|
-
|
230
|
-
it "pushes it to the remote machine" do
|
231
|
-
expect(Tempfile).to receive(:new).and_return(local_tempfile)
|
232
|
-
expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_reporter)
|
233
|
-
expect(subject.create_remote_handler(remote_folder)).to eq(remote_reporter)
|
234
|
-
# ensure the tempfile is deleted locally
|
235
|
-
expect(local_tempfile.closed?).to eq(true)
|
236
|
-
end
|
237
|
-
|
238
|
-
it "raises an error if the upload fails" do
|
239
|
-
expect(Tempfile).to receive(:new).and_return(local_tempfile)
|
240
|
-
expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_reporter).and_raise("foo")
|
241
|
-
err = ChefApply::Action::ConvergeTarget::HandlerUploadFailed
|
242
|
-
expect { subject.create_remote_handler(remote_folder) }.to raise_error(err)
|
243
|
-
# ensure the tempfile is deleted locally
|
244
|
-
expect(local_tempfile.closed?).to eq(true)
|
245
|
-
end
|
246
|
-
end
|
247
|
-
|
248
|
-
describe "#upload_trusted_certs" do
|
249
|
-
let(:remote_folder) { "/tmp/foo" }
|
250
|
-
let(:remote_tcd) { File.join(remote_folder, "trusted_certs") }
|
251
|
-
let(:tmpdir) { Dir.mktmpdir }
|
252
|
-
let(:certs_dir) { File.join(tmpdir, "weird/glob/chars[/") }
|
253
|
-
|
254
|
-
before do
|
255
|
-
ChefApply::Config.chef.trusted_certs_dir = certs_dir
|
256
|
-
FileUtils.mkdir_p(certs_dir)
|
257
|
-
end
|
258
|
-
|
259
|
-
after do
|
260
|
-
ChefApply::Config.reset
|
261
|
-
FileUtils.remove_entry tmpdir
|
262
|
-
end
|
263
|
-
|
264
|
-
context "when there are local certificates" do
|
265
|
-
let!(:cert1) { FileUtils.touch(File.join(certs_dir, "1.crt"))[0] }
|
266
|
-
let!(:cert2) { FileUtils.touch(File.join(certs_dir, "2.pem"))[0] }
|
267
|
-
|
268
|
-
it "uploads the local certs" do
|
269
|
-
expect(target_host).to receive(:make_directory).with(remote_tcd)
|
270
|
-
expect(target_host).to receive(:upload_file).with(cert1, File.join(remote_tcd, File.basename(cert1)))
|
271
|
-
expect(target_host).to receive(:upload_file).with(cert2, File.join(remote_tcd, File.basename(cert2)))
|
272
|
-
subject.upload_trusted_certs(remote_folder)
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
context "when there are no local certificates" do
|
277
|
-
it "does not upload any certs" do
|
278
|
-
expect(target_host).to_not receive(:run_command)
|
279
|
-
expect(target_host).to_not receive(:upload_file)
|
280
|
-
subject.upload_trusted_certs(remote_folder)
|
281
|
-
end
|
282
|
-
end
|
283
|
-
|
284
|
-
end
|
285
|
-
|
286
|
-
describe "#perform_action" do
|
287
|
-
let(:remote_folder) { "/tmp/foo" }
|
288
|
-
let(:remote_archive) { File.join(remote_folder, File.basename(archive)) }
|
289
|
-
let(:remote_config) { "#{remote_folder}/workstation.rb" }
|
290
|
-
let(:remote_handler) { "#{remote_folder}/reporter.rb" }
|
291
|
-
let(:tmpdir) { remote_folder }
|
292
|
-
before do
|
293
|
-
expect(target_host).to receive(:temp_dir).and_return(tmpdir)
|
294
|
-
expect(subject).to receive(:create_remote_policy).with(local_policy_path, remote_folder).and_return(remote_archive)
|
295
|
-
expect(subject).to receive(:create_remote_config).with(remote_folder).and_return(remote_config)
|
296
|
-
expect(subject).to receive(:create_remote_handler).with(remote_folder).and_return(remote_handler)
|
297
|
-
expect(subject).to receive(:upload_trusted_certs).with(remote_folder)
|
298
|
-
end
|
299
|
-
let(:result) { double("command result", exit_status: 0, stdout: "") }
|
300
|
-
|
301
|
-
it "runs the converge and reports back success" do
|
302
|
-
# Note we're only ensuring the command looks the same as #run_chef_cmd - we verify that run_chef_cmd
|
303
|
-
# is correct in its own test elsewhere in this file
|
304
|
-
expect(target_host).to receive(:run_command).with(subject.run_chef_cmd(remote_folder,
|
305
|
-
"workstation.rb",
|
306
|
-
"archive.tgz")).and_return result
|
307
|
-
expect(target_host).to receive(:del_dir).with(remote_folder).and_return result
|
308
|
-
|
309
|
-
%i{running_chef success}.each do |n|
|
310
|
-
expect(subject).to receive(:notify).with(n)
|
311
|
-
end
|
312
|
-
subject.perform_action
|
313
|
-
end
|
314
|
-
|
315
|
-
context "when chef schedules restart" do
|
316
|
-
let(:result) { double("command result", exit_status: 35) }
|
317
|
-
|
318
|
-
it "runs the converge and reports back reboot" do
|
319
|
-
expect(target_host).to receive(:run_command).with(subject.run_chef_cmd(remote_folder,
|
320
|
-
"workstation.rb",
|
321
|
-
"archive.tgz")).and_return result
|
322
|
-
expect(target_host).to receive(:del_dir).with(remote_folder).and_return result
|
323
|
-
%i{running_chef reboot}.each do |n|
|
324
|
-
expect(subject).to receive(:notify).with(n)
|
325
|
-
end
|
326
|
-
subject.perform_action
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
|
-
context "when command fails" do
|
331
|
-
let(:result) { double("command result", exit_status: 1, stdout: "", stderr: "") }
|
332
|
-
let(:report_result) { '{ "exception": "thing" }' }
|
333
|
-
let(:exception_mapper) { double("mapper") }
|
334
|
-
before do
|
335
|
-
expect(ChefApply::Action::ConvergeTarget::CCRFailureMapper).to receive(:new)
|
336
|
-
.and_return exception_mapper
|
337
|
-
end
|
338
|
-
|
339
|
-
it "reports back failure and reads the remote report" do
|
340
|
-
expect(target_host).to receive(:run_command).with(subject.run_chef_cmd(remote_folder,
|
341
|
-
"workstation.rb",
|
342
|
-
"archive.tgz")).and_return result
|
343
|
-
expect(target_host).to receive(:del_dir).with(remote_folder).and_return result
|
344
|
-
%i{running_chef converge_error}.each do |n|
|
345
|
-
expect(subject).to receive(:notify).with(n)
|
346
|
-
end
|
347
|
-
expect(target_host).to receive(:fetch_file_contents).with(subject.chef_report_path).and_return(report_result)
|
348
|
-
expect(target_host).to receive(:del_file).with(subject.chef_report_path)
|
349
|
-
expect(exception_mapper).to receive(:raise_mapped_exception!)
|
350
|
-
subject.perform_action
|
351
|
-
end
|
352
|
-
|
353
|
-
context "when remote report cannot be read" do
|
354
|
-
let(:report_result) { nil }
|
355
|
-
it "reports back failure" do
|
356
|
-
expect(target_host).to receive(:run_command).with(subject.run_chef_cmd(remote_folder,
|
357
|
-
"workstation.rb",
|
358
|
-
"archive.tgz")).and_return result
|
359
|
-
expect(target_host).to receive(:del_dir).with(remote_folder).and_return result
|
360
|
-
%i{running_chef converge_error}.each do |n|
|
361
|
-
expect(subject).to receive(:notify).with(n)
|
362
|
-
end
|
363
|
-
expect(target_host).to receive(:fetch_file_contents).with(subject.chef_report_path).and_return(report_result)
|
364
|
-
expect(exception_mapper).to receive(:raise_mapped_exception!)
|
365
|
-
subject.perform_action
|
366
|
-
end
|
367
|
-
end
|
368
|
-
end
|
369
|
-
|
370
|
-
end
|
371
|
-
|
372
|
-
context "#run_chef_cmd" do
|
373
|
-
describe "when connecting to a windows target" do
|
374
|
-
let(:base_os) { :windows }
|
375
|
-
# BOOTSTRAP TODO - can't find these examples anywhere - not sure how this was passing
|
376
|
-
# include_examples "check path fetching"
|
377
|
-
|
378
|
-
it "correctly returns chef run string" do
|
379
|
-
expect(subject.run_chef_cmd("a", "b", "c")).to eq(
|
380
|
-
"Set-Location -Path a; " \
|
381
|
-
"chef-client -z --config #{File.join("a", "b")} --recipe-url #{File.join("a", "c")} | Out-Null; " \
|
382
|
-
"Set-Location C:/; " \
|
383
|
-
"exit $LASTEXITCODE"
|
384
|
-
)
|
385
|
-
end
|
386
|
-
end
|
387
|
-
|
388
|
-
describe "when connecting to a non-windows target" do
|
389
|
-
let(:base_os) { :linux }
|
390
|
-
# BOOTSTRAP TODO - can't find these examples anywhere - not sure how this was passing
|
391
|
-
# include_examples "check path fetching"
|
392
|
-
|
393
|
-
it "correctly returns chef run string" do
|
394
|
-
expect(subject.run_chef_cmd("a", "b", "c")).to eq("bash -c 'cd a; chef-client -z --config a/b --recipe-url a/c'")
|
395
|
-
end
|
396
|
-
end
|
397
|
-
|
398
|
-
end
|
399
|
-
|
400
|
-
end
|