chef-apply 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|