chef-apply 0.1.2
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 +7 -0
- data/Gemfile +26 -0
- data/Gemfile.lock +423 -0
- data/LICENSE +201 -0
- data/README.md +41 -0
- data/Rakefile +32 -0
- data/bin/chef-run +23 -0
- data/chef-apply.gemspec +67 -0
- data/i18n/en.yml +513 -0
- data/lib/chef_apply.rb +20 -0
- data/lib/chef_apply/action/base.rb +158 -0
- data/lib/chef_apply/action/converge_target.rb +173 -0
- data/lib/chef_apply/action/install_chef.rb +30 -0
- data/lib/chef_apply/action/install_chef/base.rb +137 -0
- data/lib/chef_apply/action/install_chef/linux.rb +38 -0
- data/lib/chef_apply/action/install_chef/windows.rb +54 -0
- data/lib/chef_apply/action/reporter.rb +39 -0
- data/lib/chef_apply/cli.rb +470 -0
- data/lib/chef_apply/cli_options.rb +145 -0
- data/lib/chef_apply/config.rb +150 -0
- data/lib/chef_apply/error.rb +108 -0
- data/lib/chef_apply/errors/ccr_failure_mapper.rb +93 -0
- data/lib/chef_apply/file_fetcher.rb +70 -0
- data/lib/chef_apply/log.rb +42 -0
- data/lib/chef_apply/recipe_lookup.rb +117 -0
- data/lib/chef_apply/startup.rb +162 -0
- data/lib/chef_apply/status_reporter.rb +42 -0
- data/lib/chef_apply/target_host.rb +233 -0
- data/lib/chef_apply/target_resolver.rb +202 -0
- data/lib/chef_apply/telemeter.rb +162 -0
- data/lib/chef_apply/telemeter/patch.rb +32 -0
- data/lib/chef_apply/telemeter/sender.rb +121 -0
- data/lib/chef_apply/temp_cookbook.rb +159 -0
- data/lib/chef_apply/text.rb +77 -0
- data/lib/chef_apply/ui/error_printer.rb +261 -0
- data/lib/chef_apply/ui/plain_text_element.rb +75 -0
- data/lib/chef_apply/ui/terminal.rb +94 -0
- data/lib/chef_apply/version.rb +20 -0
- metadata +376 -0
data/lib/chef_apply.rb
ADDED
@@ -0,0 +1,20 @@
|
|
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
|
+
module ChefApply
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,158 @@
|
|
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
|
+
|
18
|
+
require "chef_apply/telemeter"
|
19
|
+
require "chef_apply/error"
|
20
|
+
|
21
|
+
module ChefApply
|
22
|
+
module Action
|
23
|
+
# Derive new Actions from Action::Base
|
24
|
+
# "target_host" is a TargetHost that the action is being applied to. May be nil
|
25
|
+
# if the action does not require a target.
|
26
|
+
# "config" is hash containing any options that your command may need
|
27
|
+
#
|
28
|
+
# Implement perform_action to perform whatever action your class is intended to do.
|
29
|
+
# Run time will be captured via telemetry and categorized under ":action" with the
|
30
|
+
# unqualified class name of your Action.
|
31
|
+
class Base
|
32
|
+
attr_reader :target_host, :config
|
33
|
+
|
34
|
+
def initialize(config = {})
|
35
|
+
c = config.dup
|
36
|
+
@target_host = c.delete :target_host
|
37
|
+
# Remaining options are for child classes to make use of.
|
38
|
+
@config = c
|
39
|
+
end
|
40
|
+
|
41
|
+
run_report = "$env:APPDATA/chef-workstation/cache/run-report.json"
|
42
|
+
PATH_MAPPING = {
|
43
|
+
chef_client: {
|
44
|
+
windows: "cmd /c C:/opscode/chef/bin/chef-client",
|
45
|
+
other: "/opt/chef/bin/chef-client",
|
46
|
+
},
|
47
|
+
cache_path: {
|
48
|
+
windows: '#{ENV[\'APPDATA\']}/chef-workstation',
|
49
|
+
other: "/var/chef-workstation",
|
50
|
+
},
|
51
|
+
read_chef_report: {
|
52
|
+
windows: "type #{run_report}",
|
53
|
+
other: "cat /var/chef-workstation/cache/run-report.json",
|
54
|
+
},
|
55
|
+
delete_chef_report: {
|
56
|
+
windows: "If (Test-Path #{run_report}){ Remove-Item -Force -Path #{run_report} }",
|
57
|
+
other: "rm -f /var/chef-workstation/cache/run-report.json",
|
58
|
+
},
|
59
|
+
tempdir: {
|
60
|
+
windows: "%TEMP%",
|
61
|
+
other: "$TMPDIR",
|
62
|
+
},
|
63
|
+
mkdir: {
|
64
|
+
windows: "New-Item -ItemType Directory -Force -Path ",
|
65
|
+
other: "mkdir -p ",
|
66
|
+
},
|
67
|
+
# TODO this is duplicating some stuff in the install_chef folder
|
68
|
+
# TODO maybe we start to break these out into actual functions, so
|
69
|
+
# we don't have to try and make really long one-liners
|
70
|
+
mktemp: {
|
71
|
+
windows: "$parent = [System.IO.Path]::GetTempPath(); [string] $name = [System.Guid]::NewGuid(); $tmp = New-Item -ItemType Directory -Path (Join-Path $parent $name); $tmp.FullName",
|
72
|
+
other: "bash -c 'd=$(mktemp -d -p${TMPDIR:-/tmp} chef_XXXXXX); chmod 777 $d; echo $d'"
|
73
|
+
},
|
74
|
+
delete_folder: {
|
75
|
+
windows: "Remove-Item -Recurse -Force –Path",
|
76
|
+
other: "rm -rf",
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
PATH_MAPPING.keys.each do |m|
|
81
|
+
define_method(m) { PATH_MAPPING[m][family] }
|
82
|
+
end
|
83
|
+
|
84
|
+
# Chef will try 'downloading' the policy from the internet unless we pass it a valid, local file
|
85
|
+
# in the working directory. By pointing it at a local file it will just copy it instead of trying
|
86
|
+
# to download it.
|
87
|
+
def run_chef(working_dir, config, policy)
|
88
|
+
case family
|
89
|
+
when :windows
|
90
|
+
"Set-Location -Path #{working_dir}; " +
|
91
|
+
# We must 'wait' for chef-client to finish before changing directories and Out-Null does that
|
92
|
+
"chef-client -z --config #{config} --recipe-url #{policy} | Out-Null; " +
|
93
|
+
# We have to leave working dir so we don't hold a lock on it, which allows us to delete this tempdir later
|
94
|
+
"Set-Location C:/; " +
|
95
|
+
"exit $LASTEXITCODE"
|
96
|
+
else
|
97
|
+
# cd is shell a builtin, so much call bash. This also means all commands are executed
|
98
|
+
# with sudo (as long as we are hardcoding our sudo use)
|
99
|
+
"bash -c 'cd #{working_dir}; chef-client -z --config #{config} --recipe-url #{policy}'"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Trying to perform File or Pathname operations on a Windows path with '\'
|
104
|
+
# characters in it fails. So lets convert them to '/' which these libraries
|
105
|
+
# handle better.
|
106
|
+
def escape_windows_path(p)
|
107
|
+
if family == :windows
|
108
|
+
p = p.tr("\\", "/")
|
109
|
+
end
|
110
|
+
p
|
111
|
+
end
|
112
|
+
|
113
|
+
def run(&block)
|
114
|
+
@notification_handler = block
|
115
|
+
Telemeter.timed_action_capture(self) do
|
116
|
+
begin
|
117
|
+
perform_action
|
118
|
+
rescue StandardError => e
|
119
|
+
# Give the caller a chance to clean up - if an exception is
|
120
|
+
# raised it'll otherwise get routed through the executing thread,
|
121
|
+
# providing no means of feedback for the caller's current task.
|
122
|
+
notify(:error, e)
|
123
|
+
@error = e
|
124
|
+
end
|
125
|
+
end
|
126
|
+
# Raise outside the block to ensure that the telemetry cpature completes
|
127
|
+
raise @error unless @error.nil?
|
128
|
+
end
|
129
|
+
|
130
|
+
def name
|
131
|
+
self.class.name.split("::").last
|
132
|
+
end
|
133
|
+
|
134
|
+
def perform_action
|
135
|
+
raise NotImplemented
|
136
|
+
end
|
137
|
+
|
138
|
+
def notify(action, *args)
|
139
|
+
return if @notification_handler.nil?
|
140
|
+
ChefApply::Log.debug("[#{self.class.name}] Action: #{action}, Action Data: #{args}")
|
141
|
+
@notification_handler.call(action, args) if @notification_handler
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def family
|
147
|
+
@family ||= begin
|
148
|
+
f = target_host.platform.family
|
149
|
+
if f == "windows"
|
150
|
+
:windows
|
151
|
+
else
|
152
|
+
:other
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,173 @@
|
|
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
|
+
|
18
|
+
require "chef_apply/action/base"
|
19
|
+
require "chef_apply/text"
|
20
|
+
require "pathname"
|
21
|
+
require "tempfile"
|
22
|
+
require "chef/util/path_helper"
|
23
|
+
|
24
|
+
module ChefApply::Action
|
25
|
+
class ConvergeTarget < Base
|
26
|
+
|
27
|
+
def perform_action
|
28
|
+
local_policy_path = config.delete :local_policy_path
|
29
|
+
remote_tmp = target_host.run_command!(mktemp, true)
|
30
|
+
remote_dir_path = escape_windows_path(remote_tmp.stdout.strip)
|
31
|
+
remote_policy_path = create_remote_policy(local_policy_path, remote_dir_path)
|
32
|
+
remote_config_path = create_remote_config(remote_dir_path)
|
33
|
+
create_remote_handler(remote_dir_path)
|
34
|
+
upload_trusted_certs(remote_dir_path)
|
35
|
+
|
36
|
+
notify(:running_chef)
|
37
|
+
cmd_str = run_chef(remote_dir_path,
|
38
|
+
File.basename(remote_config_path),
|
39
|
+
File.basename(remote_policy_path))
|
40
|
+
c = target_host.run_command(cmd_str)
|
41
|
+
target_host.run_command!("#{delete_folder} #{remote_dir_path}")
|
42
|
+
if c.exit_status == 0
|
43
|
+
ChefApply::Log.debug(c.stdout)
|
44
|
+
notify(:success)
|
45
|
+
elsif c.exit_status == 35
|
46
|
+
notify(:reboot)
|
47
|
+
else
|
48
|
+
notify(:converge_error)
|
49
|
+
ChefApply::Log.error("Error running command [#{cmd_str}]")
|
50
|
+
ChefApply::Log.error("stdout: #{c.stdout}")
|
51
|
+
ChefApply::Log.error("stderr: #{c.stderr}")
|
52
|
+
handle_ccr_error()
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def create_remote_policy(local_policy_path, remote_dir_path)
|
57
|
+
remote_policy_path = File.join(remote_dir_path, File.basename(local_policy_path))
|
58
|
+
notify(:creating_remote_policy)
|
59
|
+
begin
|
60
|
+
target_host.upload_file(local_policy_path, remote_policy_path)
|
61
|
+
rescue RuntimeError => e
|
62
|
+
ChefApply::Log.error(e)
|
63
|
+
raise PolicyUploadFailed.new()
|
64
|
+
end
|
65
|
+
remote_policy_path
|
66
|
+
end
|
67
|
+
|
68
|
+
def create_remote_config(dir)
|
69
|
+
remote_config_path = File.join(dir, "workstation.rb")
|
70
|
+
|
71
|
+
workstation_rb = <<~EOM
|
72
|
+
local_mode true
|
73
|
+
color false
|
74
|
+
cache_path "#{cache_path}"
|
75
|
+
chef_repo_path "#{cache_path}"
|
76
|
+
require_relative "reporter"
|
77
|
+
reporter = ChefApply::Reporter.new
|
78
|
+
report_handlers << reporter
|
79
|
+
exception_handlers << reporter
|
80
|
+
EOM
|
81
|
+
|
82
|
+
# Maybe add data collector endpoint.
|
83
|
+
dc = ChefApply::Config.data_collector
|
84
|
+
if !dc.url.nil? && !dc.token.nil?
|
85
|
+
workstation_rb << <<~EOM
|
86
|
+
data_collector.server_url "#{dc.url}"
|
87
|
+
data_collector.token "#{dc.token}"
|
88
|
+
data_collector.mode :solo
|
89
|
+
data_collector.organization "Chef Workstation"
|
90
|
+
EOM
|
91
|
+
end
|
92
|
+
|
93
|
+
begin
|
94
|
+
config_file = Tempfile.new
|
95
|
+
config_file.write(workstation_rb)
|
96
|
+
config_file.close
|
97
|
+
target_host.upload_file(config_file.path, remote_config_path)
|
98
|
+
rescue RuntimeError
|
99
|
+
raise ConfigUploadFailed.new()
|
100
|
+
ensure
|
101
|
+
config_file.unlink
|
102
|
+
end
|
103
|
+
remote_config_path
|
104
|
+
end
|
105
|
+
|
106
|
+
def create_remote_handler(dir)
|
107
|
+
remote_handler_path = File.join(dir, "reporter.rb")
|
108
|
+
begin
|
109
|
+
handler_file = Tempfile.new
|
110
|
+
handler_file.write(File.read(File.join(__dir__, "reporter.rb")))
|
111
|
+
handler_file.close
|
112
|
+
target_host.upload_file(handler_file.path, remote_handler_path)
|
113
|
+
rescue RuntimeError
|
114
|
+
raise HandlerUploadFailed.new()
|
115
|
+
ensure
|
116
|
+
handler_file.unlink
|
117
|
+
end
|
118
|
+
remote_handler_path
|
119
|
+
end
|
120
|
+
|
121
|
+
def upload_trusted_certs(dir)
|
122
|
+
local_tcd = Chef::Util::PathHelper.escape_glob_dir(ChefApply::Config.chef.trusted_certs_dir)
|
123
|
+
certs = Dir.glob(File.join(local_tcd, "*.{crt,pem}"))
|
124
|
+
return if certs.empty?
|
125
|
+
notify(:uploading_trusted_certs)
|
126
|
+
remote_tcd = "#{dir}/trusted_certs"
|
127
|
+
# We create the trusted_certs dir with the connection user (instead of the root
|
128
|
+
# user it would get as default since we run in sudo mode) because the `upload_file`
|
129
|
+
# uploads as the connection user. Without this upload_file would fail because
|
130
|
+
# it tries to write to a root-owned folder.
|
131
|
+
target_host.run_command("#{mkdir} #{remote_tcd}", true)
|
132
|
+
certs.each do |cert_file|
|
133
|
+
target_host.upload_file(cert_file, "#{remote_tcd}/#{File.basename(cert_file)}")
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def handle_ccr_error
|
138
|
+
require "chef_apply/errors/ccr_failure_mapper"
|
139
|
+
mapper_opts = {}
|
140
|
+
c = target_host.run_command(read_chef_report)
|
141
|
+
if c.exit_status == 0
|
142
|
+
report = JSON.parse(c.stdout)
|
143
|
+
# We need to delete the stacktrace after copying it over. Otherwise if we get a
|
144
|
+
# remote failure that does not write a chef stacktrace its possible to get an old
|
145
|
+
# stale stacktrace.
|
146
|
+
target_host.run_command!(delete_chef_report)
|
147
|
+
ChefApply::Log.error("Remote chef-client error follows:")
|
148
|
+
ChefApply::Log.error(report["exception"])
|
149
|
+
else
|
150
|
+
report = {}
|
151
|
+
ChefApply::Log.error("Could not read remote report:")
|
152
|
+
ChefApply::Log.error("stdout: #{c.stdout}")
|
153
|
+
ChefApply::Log.error("stderr: #{c.stderr}")
|
154
|
+
mapper_opts[:stdout] = c.stdout
|
155
|
+
mapper_opts[:stderr] = c.stderr
|
156
|
+
end
|
157
|
+
mapper = ChefApply::Errors::CCRFailureMapper.new(report["exception"], mapper_opts)
|
158
|
+
mapper.raise_mapped_exception!
|
159
|
+
end
|
160
|
+
|
161
|
+
class ConfigUploadFailed < ChefApply::Error
|
162
|
+
def initialize(); super("CHEFUPL003"); end
|
163
|
+
end
|
164
|
+
|
165
|
+
class HandlerUploadFailed < ChefApply::Error
|
166
|
+
def initialize(); super("CHEFUPL004"); end
|
167
|
+
end
|
168
|
+
|
169
|
+
class PolicyUploadFailed < ChefApply::Error
|
170
|
+
def initialize(); super("CHEFUPL005"); end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,30 @@
|
|
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
|
+
|
18
|
+
require "chef_apply/action/install_chef/base"
|
19
|
+
require "chef_apply/action/install_chef/windows"
|
20
|
+
require "chef_apply/action/install_chef/linux"
|
21
|
+
|
22
|
+
module ChefApply::Action::InstallChef
|
23
|
+
def self.instance_for_target(target_host, opts = { check_only: false })
|
24
|
+
opts[:target_host] = target_host
|
25
|
+
case target_host.base_os
|
26
|
+
when :windows then Windows.new(opts)
|
27
|
+
when :linux then Linux.new(opts)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,137 @@
|
|
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
|
+
|
18
|
+
require "chef_apply/action/base"
|
19
|
+
require "fileutils"
|
20
|
+
|
21
|
+
module ChefApply::Action::InstallChef
|
22
|
+
class Base < ChefApply::Action::Base
|
23
|
+
MIN_CHEF_VERSION = Gem::Version.new("13.0.0")
|
24
|
+
|
25
|
+
def perform_action
|
26
|
+
if target_host.installed_chef_version >= MIN_CHEF_VERSION
|
27
|
+
notify(:already_installed)
|
28
|
+
return
|
29
|
+
end
|
30
|
+
raise ClientOutdated.new(target_host.installed_chef_version, MIN_CHEF_VERSION)
|
31
|
+
# NOTE: 2018-05-10 below is an intentionally dead code path that
|
32
|
+
# will get re-visited once we determine how we want automatic
|
33
|
+
# upgrades to behave.
|
34
|
+
# @upgrading = true
|
35
|
+
# perform_local_install
|
36
|
+
rescue ChefApply::TargetHost::ChefNotInstalled
|
37
|
+
if config[:check_only]
|
38
|
+
raise ClientNotInstalled.new()
|
39
|
+
end
|
40
|
+
perform_local_install
|
41
|
+
end
|
42
|
+
|
43
|
+
def name
|
44
|
+
# We have subclasses - so this'll take the qualified name
|
45
|
+
# eg InstallChef::Windows, etc
|
46
|
+
self.class.name.split("::")[-2..-1].join("::")
|
47
|
+
end
|
48
|
+
|
49
|
+
def upgrading?
|
50
|
+
@upgrading
|
51
|
+
end
|
52
|
+
|
53
|
+
def perform_local_install
|
54
|
+
package = lookup_artifact()
|
55
|
+
notify(:downloading)
|
56
|
+
local_path = download_to_workstation(package.url)
|
57
|
+
notify(:uploading)
|
58
|
+
remote_path = upload_to_target(local_path)
|
59
|
+
notify(:installing)
|
60
|
+
install_chef_to_target(remote_path)
|
61
|
+
notify(:install_complete)
|
62
|
+
end
|
63
|
+
|
64
|
+
def perform_remote_install
|
65
|
+
raise NotImplementedError
|
66
|
+
end
|
67
|
+
|
68
|
+
def lookup_artifact
|
69
|
+
return @artifact_info if @artifact_info
|
70
|
+
require "mixlib/install"
|
71
|
+
c = train_to_mixlib(target_host.platform)
|
72
|
+
Mixlib::Install.new(c).artifact_info
|
73
|
+
end
|
74
|
+
|
75
|
+
def version_to_install
|
76
|
+
lookup_artifact.version
|
77
|
+
end
|
78
|
+
|
79
|
+
def train_to_mixlib(platform)
|
80
|
+
opts = {
|
81
|
+
platform_version: platform.release,
|
82
|
+
platform: platform.name,
|
83
|
+
architecture: platform.arch,
|
84
|
+
product_name: "chef",
|
85
|
+
product_version: :latest,
|
86
|
+
channel: :stable,
|
87
|
+
platform_version_compatibility_mode: true
|
88
|
+
}
|
89
|
+
case platform.name
|
90
|
+
when /windows/
|
91
|
+
opts[:platform] = "windows"
|
92
|
+
when "redhat", "centos"
|
93
|
+
opts[:platform] = "el"
|
94
|
+
when "suse"
|
95
|
+
opts[:platform] = "sles"
|
96
|
+
when "amazon"
|
97
|
+
opts[:platform] = "el"
|
98
|
+
if platform.release.to_i > 2010 # legacy Amazon version 1
|
99
|
+
opts[:platform_version] = "6"
|
100
|
+
else
|
101
|
+
opts[:platform_version] = "7"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
opts
|
105
|
+
end
|
106
|
+
|
107
|
+
def download_to_workstation(url_path)
|
108
|
+
require "chef_apply/file_fetcher"
|
109
|
+
ChefApply::FileFetcher.fetch(url_path)
|
110
|
+
end
|
111
|
+
|
112
|
+
def upload_to_target(local_path)
|
113
|
+
installer_dir = setup_remote_temp_path()
|
114
|
+
remote_path = File.join(installer_dir, File.basename(local_path))
|
115
|
+
target_host.upload_file(local_path, remote_path)
|
116
|
+
remote_path
|
117
|
+
end
|
118
|
+
|
119
|
+
def setup_remote_temp_path
|
120
|
+
raise NotImplementedError
|
121
|
+
end
|
122
|
+
|
123
|
+
def install_chef_to_target(remote_path)
|
124
|
+
raise NotImplementedError
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class ClientNotInstalled < ChefApply::ErrorNoLogs
|
129
|
+
def initialize(); super("CHEFINS002"); end
|
130
|
+
end
|
131
|
+
|
132
|
+
class ClientOutdated < ChefApply::ErrorNoLogs
|
133
|
+
def initialize(current_version, target_version)
|
134
|
+
super("CHEFINS003", current_version, target_version)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|