clc-fork-chef-metal 0.11.beta.5
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/CHANGELOG.md +106 -0
- data/LICENSE +201 -0
- data/README.md +201 -0
- data/Rakefile +6 -0
- data/bin/metal +276 -0
- data/lib/chef/provider/machine.rb +147 -0
- data/lib/chef/provider/machine_batch.rb +130 -0
- data/lib/chef/provider/machine_execute.rb +30 -0
- data/lib/chef/provider/machine_file.rb +49 -0
- data/lib/chef/resource/machine.rb +95 -0
- data/lib/chef/resource/machine_batch.rb +20 -0
- data/lib/chef/resource/machine_execute.rb +22 -0
- data/lib/chef/resource/machine_file.rb +28 -0
- data/lib/chef_metal.rb +62 -0
- data/lib/chef_metal/action_handler.rb +63 -0
- data/lib/chef_metal/add_prefix_action_handler.rb +29 -0
- data/lib/chef_metal/chef_machine_spec.rb +64 -0
- data/lib/chef_metal/chef_provider_action_handler.rb +72 -0
- data/lib/chef_metal/chef_run_data.rb +80 -0
- data/lib/chef_metal/convergence_strategy.rb +26 -0
- data/lib/chef_metal/convergence_strategy/install_cached.rb +157 -0
- data/lib/chef_metal/convergence_strategy/install_msi.rb +56 -0
- data/lib/chef_metal/convergence_strategy/install_sh.rb +51 -0
- data/lib/chef_metal/convergence_strategy/no_converge.rb +38 -0
- data/lib/chef_metal/convergence_strategy/precreate_chef_objects.rb +180 -0
- data/lib/chef_metal/driver.rb +267 -0
- data/lib/chef_metal/machine.rb +110 -0
- data/lib/chef_metal/machine/basic_machine.rb +82 -0
- data/lib/chef_metal/machine/unix_machine.rb +276 -0
- data/lib/chef_metal/machine/windows_machine.rb +102 -0
- data/lib/chef_metal/machine_spec.rb +78 -0
- data/lib/chef_metal/recipe_dsl.rb +84 -0
- data/lib/chef_metal/transport.rb +87 -0
- data/lib/chef_metal/transport/ssh.rb +235 -0
- data/lib/chef_metal/transport/winrm.rb +109 -0
- data/lib/chef_metal/version.rb +3 -0
- metadata +223 -0
@@ -0,0 +1,72 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Douglas Triggs (<doug@getchef.com>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2014, Chef, Inc.
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
require 'chef_metal/action_handler'
|
20
|
+
|
21
|
+
# This is included in the metal drivers to proxy from generic requests needed
|
22
|
+
# to specific driver actions
|
23
|
+
module ChefMetal
|
24
|
+
class ChefProviderActionHandler < ActionHandler
|
25
|
+
def initialize(provider)
|
26
|
+
@provider = provider
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :provider
|
30
|
+
|
31
|
+
def updated!
|
32
|
+
provider.new_resource.updated_by_last_action(true)
|
33
|
+
end
|
34
|
+
|
35
|
+
def should_perform_actions
|
36
|
+
!provider.run_context.config.why_run
|
37
|
+
end
|
38
|
+
|
39
|
+
def report_progress(description)
|
40
|
+
# TODO this seems wrong but Chef doesn't have another thing
|
41
|
+
provider.converge_by description do
|
42
|
+
# We already did the action, but we trust whoever told us that they did it.
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def performed_action(description)
|
47
|
+
provider.converge_by description do
|
48
|
+
# We already did the action, but we trust whoever told us that they did it.
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def perform_action(description, &block)
|
53
|
+
provider.converge_by(description, &block)
|
54
|
+
end
|
55
|
+
|
56
|
+
def open_stream(name, &block)
|
57
|
+
if provider.run_context.respond_to?(:open_stream)
|
58
|
+
provider.run_context.open_stream({ :name => name }, &block)
|
59
|
+
else
|
60
|
+
if block_given?
|
61
|
+
yield STDOUT
|
62
|
+
else
|
63
|
+
STDOUT
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def host_node
|
69
|
+
"#{provider.run_context.config[:chef_server_url]}/nodes/#{provider.run_context.node['name']}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'chef/mixin/deep_merge'
|
2
|
+
require 'cheffish/with_pattern'
|
3
|
+
require 'cheffish/merged_config'
|
4
|
+
require 'chef_metal/chef_machine_spec'
|
5
|
+
|
6
|
+
module ChefMetal
|
7
|
+
class ChefRunData
|
8
|
+
extend Cheffish::WithPattern
|
9
|
+
def initialize(config)
|
10
|
+
@config = config
|
11
|
+
@drivers = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :config
|
15
|
+
attr_reader :drivers
|
16
|
+
|
17
|
+
with :driver
|
18
|
+
with :machine_options
|
19
|
+
with :machine_batch
|
20
|
+
|
21
|
+
def current_driver
|
22
|
+
@current_driver || config[:driver]
|
23
|
+
end
|
24
|
+
|
25
|
+
def current_machine_options
|
26
|
+
if @current_machine_options
|
27
|
+
@current_machine_options
|
28
|
+
elsif config[:drivers] && driver_for(current_driver) && config[:drivers][driver_for(current_driver).driver_url]
|
29
|
+
Cheffish::MergedConfig.new(config[:drivers][driver_for(current_driver).driver_url], config)[:machine_options] || {}
|
30
|
+
else
|
31
|
+
config[:machine_options] || {}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_machine_options(options, &block)
|
36
|
+
with_machine_options(Chef::Mixin::DeepMerge.hash_only_merge(current_machine_options, options), &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
def driver_for(driver)
|
40
|
+
driver.is_a?(String) ? driver_for_url(driver) : driver
|
41
|
+
end
|
42
|
+
|
43
|
+
def driver_config_for(driver)
|
44
|
+
ChefMetal.config_for_url(driver_for(driver).driver_url, config)
|
45
|
+
end
|
46
|
+
|
47
|
+
def driver_for_url(driver_url)
|
48
|
+
drivers[driver_url] ||= begin
|
49
|
+
driver = ChefMetal.driver_for_url(driver_url, config)
|
50
|
+
# Check the canonicalized driver_url from the driver
|
51
|
+
if driver.driver_url != driver_url
|
52
|
+
drivers[driver.driver_url] ||= driver
|
53
|
+
else
|
54
|
+
driver
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def connect_to_machine(name, chef_server = nil)
|
60
|
+
if name.is_a?(MachineSpec)
|
61
|
+
machine_spec = name
|
62
|
+
else
|
63
|
+
machine_spec = ChefMetal::ChefMachineSpec.get(name, chef_server)
|
64
|
+
end
|
65
|
+
ChefMetal.connect_to_machine(machine_spec, config)
|
66
|
+
end
|
67
|
+
|
68
|
+
def keys
|
69
|
+
result = (config.keys || {}).dup
|
70
|
+
Array(config.key_path) do |key_path|
|
71
|
+
Dir.entries(key_path).each do |key|
|
72
|
+
if File.extname(key) == '.pem'
|
73
|
+
result[File.basename(key)[0..-5]] ||= key
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
result
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module ChefMetal
|
2
|
+
class ConvergenceStrategy
|
3
|
+
# convergence_options - a freeform hash of options to the converger.
|
4
|
+
# config - a Chef::Config-like object with global config like :log_level
|
5
|
+
def initialize(convergence_options, config)
|
6
|
+
@convergence_options = convergence_options || {}
|
7
|
+
@config = config
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :convergence_options
|
11
|
+
attr_reader :config
|
12
|
+
|
13
|
+
# Get the machine ready to converge, but do not converge.
|
14
|
+
def setup_convergence(action_handler, machine)
|
15
|
+
raise "setup_convergence not overridden on #{self.class}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def converge(action_handler, machine)
|
19
|
+
raise "converge not overridden on #{self.class}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def cleanup_convergence(action_handler, machine_spec)
|
23
|
+
raise "cleanup_convergence not overridden on #{self.class}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'chef_metal/convergence_strategy/precreate_chef_objects'
|
2
|
+
require 'pathname'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'digest/md5'
|
5
|
+
require 'thread'
|
6
|
+
|
7
|
+
module ChefMetal
|
8
|
+
class ConvergenceStrategy
|
9
|
+
class InstallCached < PrecreateChefObjects
|
10
|
+
# convergence_options is a hash of setup convergence_options, including:
|
11
|
+
# - :chef_server
|
12
|
+
# - :allow_overwrite_keys
|
13
|
+
# - :source_key, :source_key_path, :source_key_pass_phrase
|
14
|
+
# - :private_key_options
|
15
|
+
# - :ohai_hints
|
16
|
+
# - :public_key_path, :public_key_format
|
17
|
+
# - :admin, :validator
|
18
|
+
# - :chef_client_timeout
|
19
|
+
# - :client_rb_path, :client_pem_path
|
20
|
+
# - :chef_version, :prerelease, :package_cache_path
|
21
|
+
def initialize(convergence_options, config)
|
22
|
+
convergence_options = Cheffish::MergedConfig.new(convergence_options, {
|
23
|
+
:client_rb_path => '/etc/chef/client.rb',
|
24
|
+
:client_pem_path => '/etc/chef/client.pem'
|
25
|
+
})
|
26
|
+
super(convergence_options, config)
|
27
|
+
@chef_version ||= convergence_options[:chef_version]
|
28
|
+
@prerelease ||= convergence_options[:prerelease]
|
29
|
+
@package_cache_path ||= convergence_options[:package_cache_path] || "#{ENV['HOME']}/.chef/package_cache"
|
30
|
+
@package_cache = {}
|
31
|
+
@tmp_dir = '/tmp'
|
32
|
+
@chef_client_timeout = convergence_options.has_key?(:chef_client_timeout) ? convergence_options[:chef_client_timeout] : 120*60 # Default: 2 hours
|
33
|
+
FileUtils.mkdir_p(@package_cache_path)
|
34
|
+
@package_cache_lock = Mutex.new
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :client_rb_path
|
38
|
+
attr_reader :client_pem_path
|
39
|
+
|
40
|
+
def setup_convergence(action_handler, machine)
|
41
|
+
super
|
42
|
+
|
43
|
+
# Install chef-client. TODO check and update version if not latest / not desired
|
44
|
+
if machine.execute_always('chef-client -v').exitstatus != 0
|
45
|
+
platform, platform_version, machine_architecture = machine.detect_os(action_handler)
|
46
|
+
package_file = download_package_for_platform(action_handler, machine, platform, platform_version, machine_architecture)
|
47
|
+
remote_package_file = "#{@tmp_dir}/#{File.basename(package_file)}"
|
48
|
+
machine.upload_file(action_handler, package_file, remote_package_file)
|
49
|
+
install_package(action_handler, machine, remote_package_file)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def converge(action_handler, machine)
|
54
|
+
super
|
55
|
+
|
56
|
+
action_handler.open_stream(machine.node['name']) do |stdout|
|
57
|
+
action_handler.open_stream(machine.node['name']) do |stderr|
|
58
|
+
command_line = "chef-client"
|
59
|
+
command_line << " -l #{config[:log_level].to_s}" if config[:log_level]
|
60
|
+
machine.execute(action_handler, command_line,
|
61
|
+
:stream_stdout => stdout,
|
62
|
+
:stream_stderr => stderr,
|
63
|
+
:timeout => @chef_client_timeout)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def download_package_for_platform(action_handler, machine, platform, platform_version, machine_architecture)
|
71
|
+
@package_cache_lock.synchronize do
|
72
|
+
@package_cache ||= {}
|
73
|
+
@package_cache[platform] ||= {}
|
74
|
+
@package_cache[platform][platform_version] ||= {}
|
75
|
+
@package_cache[platform][platform_version][machine_architecture] ||= { :lock => Mutex.new }
|
76
|
+
end
|
77
|
+
@package_cache[platform][platform_version][machine_architecture][:lock].synchronize do
|
78
|
+
if !@package_cache[platform][platform_version][machine_architecture][:file]
|
79
|
+
#
|
80
|
+
# Grab metadata
|
81
|
+
#
|
82
|
+
metadata = download_metadata_for_platform(machine, platform, platform_version, machine_architecture)
|
83
|
+
|
84
|
+
# Download actual package desired by metadata
|
85
|
+
package_file = "#{@package_cache_path}/#{URI(metadata['url']).path.split('/')[-1]}"
|
86
|
+
|
87
|
+
ChefMetal.inline_resource(action_handler) do
|
88
|
+
remote_file package_file do
|
89
|
+
source metadata['url']
|
90
|
+
checksum metadata['sha256']
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
@package_cache[platform][platform_version][machine_architecture][:file] = package_file
|
95
|
+
end
|
96
|
+
end
|
97
|
+
@package_cache[platform][platform_version][machine_architecture][:file]
|
98
|
+
end
|
99
|
+
|
100
|
+
def download_metadata_for_platform(machine, platform, platform_version, machine_architecture)
|
101
|
+
#
|
102
|
+
# Figure out the URL to the metadata
|
103
|
+
#
|
104
|
+
metadata_url="https://www.opscode.com/chef/metadata"
|
105
|
+
metadata_url << "?v=#{@chef_version}"
|
106
|
+
metadata_url << "&prerelease=#{@prerelease ? 'true' : 'false'}"
|
107
|
+
metadata_url << "&p=#{platform.strip}"
|
108
|
+
metadata_url << "&pv=#{platform_version.strip}"
|
109
|
+
metadata_url << "&m=#{machine_architecture.strip}"
|
110
|
+
use_ssl = true
|
111
|
+
|
112
|
+
# solaris 9 lacks openssl, solaris 10 lacks recent enough credentials - your base O/S is completely insecure, please upgrade
|
113
|
+
if platform == 'solaris2' && (platform_version == '5.9' || platform_version == '5.10')
|
114
|
+
metadata_url.sub(/^https/, 'http')
|
115
|
+
use_ssl = false
|
116
|
+
end
|
117
|
+
|
118
|
+
# Download and parse the metadata
|
119
|
+
Chef::Log.debug("Getting metadata for machine #{machine.node['name']}: #{metadata_url}")
|
120
|
+
uri = URI(metadata_url)
|
121
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
122
|
+
http.use_ssl = use_ssl
|
123
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
124
|
+
response = http.request(request)
|
125
|
+
metadata_str = response.body
|
126
|
+
metadata = {}
|
127
|
+
metadata_str.each_line do |line|
|
128
|
+
key, value = line.split("\t", 2)
|
129
|
+
metadata[key] = value
|
130
|
+
end
|
131
|
+
metadata
|
132
|
+
end
|
133
|
+
|
134
|
+
def install_package(action_handler, machine, remote_package_file)
|
135
|
+
extension = File.extname(remote_package_file)
|
136
|
+
result = case extension
|
137
|
+
when '.rpm'
|
138
|
+
machine.execute(action_handler, "rpm -Uvh --oldpackage --replacepkgs \"#{remote_package_file}\"")
|
139
|
+
when '.deb'
|
140
|
+
machine.execute(action_handler, "dpkg -i \"#{remote_package_file}\"")
|
141
|
+
when '.solaris'
|
142
|
+
machine.write_file(action_handler, "#{@tmp_dir}/nocheck", <<EOM)
|
143
|
+
conflict=nocheck
|
144
|
+
action=nocheck
|
145
|
+
mail=
|
146
|
+
EOM
|
147
|
+
machine.execute(action_handler, "pkgrm -a \"#{@tmp_dir}/nocheck\" -n chef")
|
148
|
+
machine.execute(action_handler, "pkgadd -n -d \"#{remote_package_file}\" -a \"#{@tmp_dir}/nocheck\" chef")
|
149
|
+
when '.sh'
|
150
|
+
machine.execute(action_handler, "sh \"#{remote_package_file}\"")
|
151
|
+
else
|
152
|
+
raise "Unknown package extension '#{extension}' for file #{remote_package_file}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'chef_metal/convergence_strategy/precreate_chef_objects'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
module ChefMetal
|
5
|
+
class ConvergenceStrategy
|
6
|
+
class InstallMsi < PrecreateChefObjects
|
7
|
+
@@install_msi_cache = {}
|
8
|
+
|
9
|
+
def initialize(convergence_options, config)
|
10
|
+
super
|
11
|
+
@install_msi_url = convergence_options[:install_msi_url] || 'http://www.opscode.com/chef/install.msi'
|
12
|
+
@install_msi_path = convergence_options[:install_msi_path] || "%TEMP%\\#{File.basename(@install_msi_url)}"
|
13
|
+
@chef_client_timeout = convergence_options.has_key?(:chef_client_timeout) ? convergence_options[:chef_client_timeout] : 120*60 # Default: 2 hours
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :install_msi_url
|
17
|
+
attr_reader :install_msi_path
|
18
|
+
|
19
|
+
def setup_convergence(action_handler, machine)
|
20
|
+
if !convergence_options.has_key?(:client_rb_path) || !convergence_options.has_key?(:client_pem_path)
|
21
|
+
system_drive = machine.execute_always('$env:SystemDrive').stdout.strip
|
22
|
+
@convergence_options = Cheffish::MergedConfig.new(convergence_options, {
|
23
|
+
:client_rb_path => "#{system_drive}\\chef\\client.rb",
|
24
|
+
:client_pem_path => "#{system_drive}\\chef\\client.pem"
|
25
|
+
})
|
26
|
+
end
|
27
|
+
|
28
|
+
super
|
29
|
+
|
30
|
+
# Install chef-client. TODO check and update version if not latest / not desired
|
31
|
+
if machine.execute_always('chef-client -v').exitstatus != 0
|
32
|
+
# TODO ssh verification of install.msi before running arbtrary code would be nice?
|
33
|
+
# TODO find a way to cache this on the host like with the Unix stuff.
|
34
|
+
# Limiter is we don't know how to efficiently upload large files to
|
35
|
+
# the remote machine with WMI.
|
36
|
+
machine.execute(action_handler, "(New-Object System.Net.WebClient).DownloadFile(#{machine.escape(install_msi_url)}, #{machine.escape(install_msi_path)})")
|
37
|
+
machine.execute(action_handler, "msiexec /qn /i #{machine.escape(install_msi_path)}")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def converge(action_handler, machine)
|
42
|
+
super
|
43
|
+
|
44
|
+
# TODO For some reason I get a 500 back if I don't do -l debug
|
45
|
+
action_handler.open_stream(machine.node['name']) do |stdout|
|
46
|
+
action_handler.open_stream(machine.node['name']) do |stderr|
|
47
|
+
machine.execute(action_handler, "chef-client -l debug",
|
48
|
+
:stream_stdout => stdout,
|
49
|
+
:stream_stderr => stderr,
|
50
|
+
:timeout => @chef_client_timeout)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'chef_metal/convergence_strategy/precreate_chef_objects'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
module ChefMetal
|
5
|
+
class ConvergenceStrategy
|
6
|
+
class InstallSh < PrecreateChefObjects
|
7
|
+
@@install_sh_cache = {}
|
8
|
+
|
9
|
+
def initialize(convergence_options, config)
|
10
|
+
convergence_options = Cheffish::MergedConfig.new(convergence_options, {
|
11
|
+
:client_rb_path => '/etc/chef/client.rb',
|
12
|
+
:client_pem_path => '/etc/chef/client.pem'
|
13
|
+
})
|
14
|
+
super(convergence_options, config)
|
15
|
+
@install_sh_url = convergence_options[:install_sh_url] || 'http://www.opscode.com/chef/install.sh'
|
16
|
+
@install_sh_path = convergence_options[:install_sh_path] || '/tmp/chef-install.sh'
|
17
|
+
@chef_client_timeout = convergence_options.has_key?(:chef_client_timeout) ? convergence_options[:chef_client_timeout] : 120*60 # Default: 2 hours
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :install_sh_url
|
21
|
+
attr_reader :install_sh_path
|
22
|
+
|
23
|
+
def setup_convergence(action_handler, machine)
|
24
|
+
super
|
25
|
+
|
26
|
+
# Install chef-client. TODO check and update version if not latest / not desired
|
27
|
+
if machine.execute_always('chef-client -v').exitstatus != 0
|
28
|
+
# TODO ssh verification of install.sh before running arbtrary code would be nice?
|
29
|
+
@@install_sh_cache[install_sh_url] ||= Net::HTTP.get(URI(install_sh_url))
|
30
|
+
machine.write_file(action_handler, install_sh_path, @@install_sh_cache[install_sh_url], :ensure_dir => true)
|
31
|
+
machine.execute(action_handler, "bash #{install_sh_path}")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def converge(action_handler, machine)
|
36
|
+
super
|
37
|
+
|
38
|
+
action_handler.open_stream(machine.node['name']) do |stdout|
|
39
|
+
action_handler.open_stream(machine.node['name']) do |stderr|
|
40
|
+
command_line = "chef-client"
|
41
|
+
command_line << " -l #{config[:log_level].to_s}" if config[:log_level]
|
42
|
+
machine.execute(action_handler, command_line,
|
43
|
+
:stream_stdout => stdout,
|
44
|
+
:stream_stderr => stderr,
|
45
|
+
:timeout => @chef_client_timeout)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|