clc-fork-chef-metal 0.11.beta.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/Rakefile
ADDED
data/bin/metal
ADDED
@@ -0,0 +1,276 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
5
|
+
require 'chef_metal'
|
6
|
+
require 'chef/rest'
|
7
|
+
require 'chef/application'
|
8
|
+
require 'chef/knife'
|
9
|
+
require 'chef/run_context'
|
10
|
+
require 'chef/server_api'
|
11
|
+
require 'chef_metal/action_handler'
|
12
|
+
require 'chef_metal/version'
|
13
|
+
require 'chef_metal/chef_machine_spec'
|
14
|
+
|
15
|
+
class ChefMetal::Application < Chef::Application
|
16
|
+
|
17
|
+
# Mimic self_pipe sleep from Unicorn to capture signals safely
|
18
|
+
SELF_PIPE = []
|
19
|
+
|
20
|
+
option :config_file,
|
21
|
+
:short => "-c CONFIG",
|
22
|
+
:long => "--config CONFIG",
|
23
|
+
:description => "The configuration file to use"
|
24
|
+
|
25
|
+
option :log_level,
|
26
|
+
:short => "-l LEVEL",
|
27
|
+
:long => "--log_level LEVEL",
|
28
|
+
:description => "Set the log level (debug, info, warn, error, fatal)",
|
29
|
+
:proc => lambda { |l| l.to_sym }
|
30
|
+
|
31
|
+
option :log_location,
|
32
|
+
:short => "-L LOGLOCATION",
|
33
|
+
:long => "--logfile LOGLOCATION",
|
34
|
+
:description => "Set the log file location, defaults to STDOUT - recommended for daemonizing",
|
35
|
+
:proc => nil
|
36
|
+
|
37
|
+
option :node_name,
|
38
|
+
:short => "-N NODE_NAME",
|
39
|
+
:long => "--node-name NODE_NAME",
|
40
|
+
:description => "The node name for this client",
|
41
|
+
:proc => nil
|
42
|
+
|
43
|
+
option :chef_server_url,
|
44
|
+
:short => "-S CHEFSERVERURL",
|
45
|
+
:long => "--server CHEFSERVERURL",
|
46
|
+
:description => "The chef server URL",
|
47
|
+
:proc => nil
|
48
|
+
|
49
|
+
option :client_key,
|
50
|
+
:short => "-k KEY_FILE",
|
51
|
+
:long => "--client_key KEY_FILE",
|
52
|
+
:description => "Set the client key file location",
|
53
|
+
:proc => nil
|
54
|
+
|
55
|
+
option :local_mode,
|
56
|
+
:short => "-z",
|
57
|
+
:long => "--local-mode",
|
58
|
+
:description => "Point chef-client at local repository",
|
59
|
+
:boolean => true
|
60
|
+
|
61
|
+
option :chef_repo_path,
|
62
|
+
:long => '--chef-repo-path=PATH',
|
63
|
+
:description => "Path to Chef repository"
|
64
|
+
|
65
|
+
option :chef_zero_port,
|
66
|
+
:long => "--chef-zero-port PORT",
|
67
|
+
:description => "Port to start chef-zero on"
|
68
|
+
|
69
|
+
option :read_only,
|
70
|
+
:long => "--[no-]read-only",
|
71
|
+
:description => "Promise that execution will not modify the machine (helps with Docker in particular)"
|
72
|
+
|
73
|
+
option :stream,
|
74
|
+
:long => "--[no-]stream",
|
75
|
+
:default => true,
|
76
|
+
:boolean => true,
|
77
|
+
:description => "Whether to stream output from the machine (default: true)"
|
78
|
+
|
79
|
+
option :timeout,
|
80
|
+
:long => "--timeout=TIMEOUT",
|
81
|
+
:default => 15*60,
|
82
|
+
:description => "Time to wait for program to execute, or 0 for no timeout (default: 15 minutes)"
|
83
|
+
|
84
|
+
def reconfigure
|
85
|
+
super
|
86
|
+
|
87
|
+
Chef::Config.chef_server_url = config[:chef_server_url] if config.has_key? :chef_server_url
|
88
|
+
|
89
|
+
Chef::Config.chef_repo_path = config[:chef_repo_path] if config.has_key? :chef_repo_path
|
90
|
+
|
91
|
+
Chef::Config.local_mode = config[:local_mode] if config.has_key?(:local_mode)
|
92
|
+
if Chef::Config.local_mode && !Chef::Config.has_key?(:cookbook_path) && !Chef::Config.has_key?(:chef_repo_path)
|
93
|
+
Chef::Config.chef_repo_path = Chef::Config.find_chef_repo_path(Dir.pwd)
|
94
|
+
end
|
95
|
+
Chef::Config.chef_zero.port = config[:chef_zero_port] if config[:chef_zero_port]
|
96
|
+
end
|
97
|
+
|
98
|
+
def setup_application
|
99
|
+
end
|
100
|
+
|
101
|
+
def load_config_file
|
102
|
+
if !config.has_key?(:config_file)
|
103
|
+
require 'chef/knife'
|
104
|
+
config[:config_file] = Chef::Knife.locate_config_file
|
105
|
+
end
|
106
|
+
super
|
107
|
+
end
|
108
|
+
|
109
|
+
def run_application
|
110
|
+
exit_code = 0
|
111
|
+
|
112
|
+
Cheffish.honor_local_mode do
|
113
|
+
command = cli_arguments.shift
|
114
|
+
case command
|
115
|
+
when 'execute'
|
116
|
+
connect_to_machines(cli_arguments.shift) do |machine|
|
117
|
+
machine.execute(action_handler, cli_arguments.join(' '), :read_only => config[:read_only], :stream => config[:stream], :timeout => config[:timeout].to_f)
|
118
|
+
puts result.stdout if result.stdout != '' && !config[:stream] && Chef::Config.log_level != :debug
|
119
|
+
STDERR.puts result.stderr if result.stderr != '' && !config[:stream] && Chef::Config.log_level != :debug
|
120
|
+
exit_code = result.exitstatus if result.exitstatus != 0
|
121
|
+
end
|
122
|
+
when 'destroy'
|
123
|
+
each_current_machine(cli_arguments.shift) do |driver, specs_and_options|
|
124
|
+
driver.destroy_machines(action_handler, specs_and_options, parallelizer)
|
125
|
+
end
|
126
|
+
when 'allocate'
|
127
|
+
each_new_machine(cli_arguments.shift) do |driver, specs_and_options|
|
128
|
+
driver.allocate_machines(action_handler, specs_and_options, parallelizer)
|
129
|
+
end
|
130
|
+
when 'ready'
|
131
|
+
each_new_machine(cli_arguments.shift) do |driver, specs_and_options|
|
132
|
+
driver.allocate_machines(action_handler, specs_and_options, parallelizer)
|
133
|
+
driver.ready_machines(action_handler, specs_and_options, parallelizer)
|
134
|
+
end
|
135
|
+
when 'setup'
|
136
|
+
each_new_machine(cli_arguments.shift) do |driver, specs_and_options|
|
137
|
+
driver.allocate_machines(action_handler, specs_and_options, parallelizer)
|
138
|
+
driver.ready_machines(action_handler, specs_and_options, parallelizer) do |machine|
|
139
|
+
machine.setup_convergence(action_handler)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
when 'converge'
|
143
|
+
each_new_machine(cli_arguments.shift) do |driver, specs_and_options|
|
144
|
+
driver.allocate_machines(action_handler, specs_and_options, parallelizer)
|
145
|
+
driver.ready_machines(action_handler, specs_and_options, parallelizer) do |machine|
|
146
|
+
# TODO upload files? Maybe they should be in machine_options?
|
147
|
+
machine.setup_convergence(action_handler)
|
148
|
+
machine.converge(action_handler)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
when 'reconverge'
|
152
|
+
connect_to_machines(cli_arguments.shift) do |machine|
|
153
|
+
machine.converge(action_handler)
|
154
|
+
end
|
155
|
+
when 'stop'
|
156
|
+
each_current_machine(cli_arguments.shift) do |driver, specs_and_options|
|
157
|
+
driver.stop_machines(action_handler, specs_and_options, parallelizer)
|
158
|
+
end
|
159
|
+
when 'cat'
|
160
|
+
connect_to_machines(cli_arguments.shift) do |machine|
|
161
|
+
cli_arguments.each do |remote_path|
|
162
|
+
puts machine.read_file(remote_path)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
when 'cp'
|
166
|
+
machines = {}
|
167
|
+
to = cli_arguments.pop
|
168
|
+
if to =~ /^([^\/:]+):(.+)$/
|
169
|
+
to_server = $1
|
170
|
+
machines[to_server] ||= ChefMetal.connect_to_machine(to_server)
|
171
|
+
to_path = $2
|
172
|
+
to_is_directory = machines[to_server].is_directory?(to_path)
|
173
|
+
else
|
174
|
+
to_server = nil
|
175
|
+
to_path = File.absolute_path(to)
|
176
|
+
end
|
177
|
+
|
178
|
+
cli_arguments.each do |from|
|
179
|
+
if from =~ /^([^\/:]+):(.+)$/
|
180
|
+
from_server = $1
|
181
|
+
from_path = $2
|
182
|
+
if to_server
|
183
|
+
raise "Cannot copy from one server to another, or intraserver (from=#{from}, to=#{to})"
|
184
|
+
end
|
185
|
+
|
186
|
+
machines[from_server] ||= connect_to_machine(from_server)
|
187
|
+
if File.directory?(to_path)
|
188
|
+
machines[from_server].download_file(action_handler, from_path, "#{to_path}/#{File.basename(from_path)}")
|
189
|
+
else
|
190
|
+
machines[from_server].download_file(action_handler, from_path, to_path)
|
191
|
+
end
|
192
|
+
else
|
193
|
+
from_server = nil
|
194
|
+
from_path = File.absolute_path(from)
|
195
|
+
if !to_server
|
196
|
+
raise "Cannot copy two local files. One of the arguments must be MACHINE:PATH. (from=#{from}, to=#{to})"
|
197
|
+
end
|
198
|
+
|
199
|
+
if to_is_directory
|
200
|
+
machines[to_server].upload_file(action_handler, from_path, "#{to_path}/#{File.basename(from_path)}")
|
201
|
+
else
|
202
|
+
machines[to_server].upload_file(action_handler, from_path, to_path)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
else
|
207
|
+
Chef::Log.error("Command '#{command}' unrecognized")
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
exit(exit_code) if exit_code != 0
|
212
|
+
end
|
213
|
+
|
214
|
+
private
|
215
|
+
|
216
|
+
def rest
|
217
|
+
@rest ||= Chef::ServerAPI.new()
|
218
|
+
end
|
219
|
+
|
220
|
+
def machine_specs(*specs)
|
221
|
+
names = specs.collect_concat { |spec| spec.split(',') }.uniq
|
222
|
+
parallelizer.parallelize(names) { |name| ChefMetal::ChefMachineSpec.get(name) }.to_a
|
223
|
+
end
|
224
|
+
|
225
|
+
def each_new_machine(spec)
|
226
|
+
driver = ChefMetal.default_driver
|
227
|
+
specs_and_options = {}
|
228
|
+
machine_specs(spec).each do |machine_spec|
|
229
|
+
specs_and_options[machine_spec] = driver.config[:machine_options]
|
230
|
+
end
|
231
|
+
[ [ driver, specs_and_options ] ]
|
232
|
+
end
|
233
|
+
|
234
|
+
def each_current_machine(spec)
|
235
|
+
grouped = machine_specs(spec).group_by { |machine_spec| machine_spec.driver_url }
|
236
|
+
parallelizer.parallelize(grouped) do |driver_url, machine_specs|
|
237
|
+
if driver_url
|
238
|
+
driver = ChefMetal.driver_for_url(driver_url)
|
239
|
+
specs_and_options = {}
|
240
|
+
machine_specs(spec).each do |machine_spec|
|
241
|
+
specs_and_options[machine_spec] = driver.config[:machine_options]
|
242
|
+
end
|
243
|
+
yield driver, specs_and_options
|
244
|
+
end
|
245
|
+
end.to_a
|
246
|
+
end
|
247
|
+
|
248
|
+
def connect_to_machines(spec)
|
249
|
+
grouped = machine_specs(spec).group_by { |machine_spec| machine_spec.driver_url }
|
250
|
+
grouped.collect_concat do |driver_url, machine_specs|
|
251
|
+
machine_specs.map { |machine_spec| ChefMetal.connect_to_machine(machine_spec) }
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def parallelizer
|
256
|
+
Chef::ChefFS::Parallelizer
|
257
|
+
end
|
258
|
+
|
259
|
+
def action_handler
|
260
|
+
@action_handler ||= ActionHandler.new
|
261
|
+
end
|
262
|
+
|
263
|
+
class ActionHandler < ChefMetal::ActionHandler
|
264
|
+
def recipe_context
|
265
|
+
# TODO: somehow remove this code; should context really always be needed?
|
266
|
+
node = Chef::Node.new
|
267
|
+
node.name 'nothing'
|
268
|
+
node.automatic[:platform] = 'metal'
|
269
|
+
node.automatic[:platform_version] = ChefMetal::VERSION
|
270
|
+
Chef::RunContext.new(node, {},
|
271
|
+
Chef::EventDispatch::Dispatcher.new(Chef::Formatters::Doc.new(STDOUT,STDERR)))
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
ChefMetal::Application.new.run
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'chef/provider/lwrp_base'
|
2
|
+
require 'chef/provider/chef_node'
|
3
|
+
require 'openssl'
|
4
|
+
require 'chef_metal/chef_provider_action_handler'
|
5
|
+
require 'chef_metal/chef_machine_spec'
|
6
|
+
|
7
|
+
class Chef::Provider::Machine < Chef::Provider::LWRPBase
|
8
|
+
|
9
|
+
def action_handler
|
10
|
+
@action_handler ||= ChefMetal::ChefProviderActionHandler.new(self)
|
11
|
+
end
|
12
|
+
|
13
|
+
use_inline_resources
|
14
|
+
|
15
|
+
def whyrun_supported?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
action :allocate do
|
20
|
+
new_driver.allocate_machine(action_handler, machine_spec, machine_options)
|
21
|
+
machine_spec.save(action_handler)
|
22
|
+
end
|
23
|
+
|
24
|
+
action :ready do
|
25
|
+
action_allocate
|
26
|
+
machine = current_driver.ready_machine(action_handler, machine_spec, machine_options)
|
27
|
+
machine_spec.save(action_handler)
|
28
|
+
machine
|
29
|
+
end
|
30
|
+
|
31
|
+
action :setup do
|
32
|
+
machine = action_ready
|
33
|
+
begin
|
34
|
+
machine.setup_convergence(action_handler)
|
35
|
+
machine_spec.save(action_handler)
|
36
|
+
upload_files(machine)
|
37
|
+
ensure
|
38
|
+
machine.disconnect
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
action :converge do
|
43
|
+
machine = action_ready
|
44
|
+
begin
|
45
|
+
machine.setup_convergence(action_handler)
|
46
|
+
machine_spec.save(action_handler)
|
47
|
+
upload_files(machine)
|
48
|
+
# If we were asked to converge, or anything changed, or if a converge has never succeeded, converge.
|
49
|
+
if new_resource.converge || (new_resource.converge.nil? && resource_updated?) ||
|
50
|
+
!machine_spec.node['automatic'] || machine_spec.node['automatic'].size == 0
|
51
|
+
machine.converge(action_handler)
|
52
|
+
end
|
53
|
+
ensure
|
54
|
+
machine.disconnect
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
action :converge_only do
|
59
|
+
machine = run_context.chef_metal.connect_to_machine(machine_spec, machine_options)
|
60
|
+
begin
|
61
|
+
machine.converge(action_handler)
|
62
|
+
ensure
|
63
|
+
machine.disconnect
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
action :stop do
|
68
|
+
if current_driver
|
69
|
+
current_driver.stop_machine(action_handler, machine_spec, machine_options)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
action :destroy do
|
74
|
+
if current_driver
|
75
|
+
current_driver.destroy_machine(action_handler, machine_spec, machine_options)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def new_driver
|
80
|
+
run_context.chef_metal.driver_for(new_resource.driver)
|
81
|
+
end
|
82
|
+
|
83
|
+
def new_driver_config
|
84
|
+
run_context.chef_metal.driver_config_for(new_resource.driver)
|
85
|
+
end
|
86
|
+
|
87
|
+
def current_driver
|
88
|
+
run_context.chef_metal.current_driver || (
|
89
|
+
if machine_spec.driver_url
|
90
|
+
run_context.chef_metal.driver_for_url(machine_spec.driver_url)
|
91
|
+
end
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
attr_reader :machine_spec
|
96
|
+
|
97
|
+
def machine_options
|
98
|
+
configs = []
|
99
|
+
configs << {
|
100
|
+
:convergence_options =>
|
101
|
+
[ :chef_server,
|
102
|
+
:allow_overwrite_keys,
|
103
|
+
:source_key, :source_key_path, :source_key_pass_phrase,
|
104
|
+
:private_key_options,
|
105
|
+
:ohai_hints,
|
106
|
+
:public_key_path, :public_key_format,
|
107
|
+
:admin, :validator
|
108
|
+
].inject({}) do |result, key|
|
109
|
+
result[key] = new_resource.send(key)
|
110
|
+
result
|
111
|
+
end
|
112
|
+
}
|
113
|
+
configs << new_resource.machine_options if new_resource.machine_options
|
114
|
+
configs << new_driver_config[:machine_options] if new_driver_config[:machine_options]
|
115
|
+
Cheffish::MergedConfig.new(*configs)
|
116
|
+
end
|
117
|
+
|
118
|
+
def load_current_resource
|
119
|
+
node_driver = Chef::Provider::ChefNode.new(new_resource, run_context)
|
120
|
+
node_driver.load_current_resource
|
121
|
+
json = node_driver.new_json
|
122
|
+
json['normal']['metal'] = node_driver.current_json['normal']['metal']
|
123
|
+
@machine_spec = ChefMetal::ChefMachineSpec.new(json, new_resource.chef_server)
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.upload_files(action_handler, machine, files)
|
127
|
+
if files
|
128
|
+
files.each_pair do |remote_file, local|
|
129
|
+
if local.is_a?(Hash)
|
130
|
+
if local[:local_path]
|
131
|
+
machine.upload_file(action_handler, local[:local_path], remote_file)
|
132
|
+
else
|
133
|
+
machine.write_file(action_handler, remote_file, local[:content])
|
134
|
+
end
|
135
|
+
else
|
136
|
+
machine.upload_file(action_handler, local, remote_file)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
|
144
|
+
def upload_files(machine)
|
145
|
+
Machine.upload_files(action_handler, machine, new_resource.files)
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'chef/chef_fs/parallelizer'
|
2
|
+
require 'chef/provider/lwrp_base'
|
3
|
+
require 'chef/provider/machine'
|
4
|
+
require 'chef_metal/chef_provider_action_handler'
|
5
|
+
require 'chef_metal/add_prefix_action_handler'
|
6
|
+
|
7
|
+
class Chef::Provider::MachineBatch < Chef::Provider::LWRPBase
|
8
|
+
|
9
|
+
def action_handler
|
10
|
+
@action_handler ||= ChefMetal::ChefProviderActionHandler.new(self)
|
11
|
+
end
|
12
|
+
|
13
|
+
use_inline_resources
|
14
|
+
|
15
|
+
def whyrun_supported?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
def parallelizer
|
20
|
+
@parallelizer ||= Chef::ChefFS::Parallelizer.new(new_resource.max_simultaneous || 100)
|
21
|
+
end
|
22
|
+
|
23
|
+
action :allocate do
|
24
|
+
by_new_driver.each do |driver, specs_and_options|
|
25
|
+
driver.allocate_machines(action_handler, specs_and_options, parallelizer) do |machine_spec|
|
26
|
+
machine_spec.save(action_handler)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
action :ready do
|
32
|
+
with_ready_machines
|
33
|
+
end
|
34
|
+
|
35
|
+
action :setup do
|
36
|
+
with_ready_machines do |m|
|
37
|
+
prefixed_handler = ChefMetal::AddPrefixActionHandler.new(action_handler, "[#{m[:resource].name}] ")
|
38
|
+
machine[:machine].setup_convergence(prefixed_handler)
|
39
|
+
m[:spec].save(action_handler)
|
40
|
+
Chef::Provider::Machine.upload_files(prefixed_handler, m[:machine], m[:resource].files)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
action :converge do
|
45
|
+
with_ready_machines do |m|
|
46
|
+
prefixed_handler = ChefMetal::AddPrefixActionHandler.new(action_handler, "[#{m[:resource].name}] ")
|
47
|
+
m[:machine].setup_convergence(prefixed_handler)
|
48
|
+
m[:spec].save(action_handler)
|
49
|
+
Chef::Provider::Machine.upload_files(prefixed_handler, m[:machine], m[:resource].files)
|
50
|
+
m[:machine].converge(prefixed_handler)
|
51
|
+
m[:spec].save(action_handler)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
action :stop do
|
56
|
+
parallel_do(by_current_driver) do |driver, specs_and_options|
|
57
|
+
driver.stop_machines(action_handler, specs_and_options, parallelizer)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
action :destroy do
|
62
|
+
parallel_do(by_current_driver) do |driver, specs_and_options|
|
63
|
+
driver.destroy_machines(action_handler, specs_and_options, parallelizer)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def with_ready_machines
|
68
|
+
action_allocate
|
69
|
+
by_id = @machines.inject({}) { |hash,m| hash[m[:spec].id] = m; hash }
|
70
|
+
parallel_do(by_new_driver) do |driver, specs_and_options|
|
71
|
+
driver.ready_machines(action_handler, specs_and_options, parallelizer) do |machine|
|
72
|
+
machine.machine_spec.save(action_handler)
|
73
|
+
|
74
|
+
m = by_id[machine.machine_spec.id]
|
75
|
+
|
76
|
+
m[:machine] = machine
|
77
|
+
begin
|
78
|
+
yield m if block_given?
|
79
|
+
ensure
|
80
|
+
machine.disconnect
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# TODO in many of these cases, the order of the results only matters because you
|
87
|
+
# want to match it up with the input. Make a parallelize method that doesn't
|
88
|
+
# care about order and spits back results as quickly as possible.
|
89
|
+
def parallel_do(enum, options = {}, &block)
|
90
|
+
parallelizer.parallelize(enum, options, &block).to_a
|
91
|
+
end
|
92
|
+
|
93
|
+
def by_new_driver
|
94
|
+
result = {}
|
95
|
+
@machines.each do |m|
|
96
|
+
if m[:resource].driver
|
97
|
+
driver = run_context.chef_metal.driver_for(m[:resource].driver)
|
98
|
+
result[driver] ||= {}
|
99
|
+
result[driver][m[:spec]] = m[:options]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
result
|
103
|
+
end
|
104
|
+
|
105
|
+
def by_current_driver
|
106
|
+
result = {}
|
107
|
+
@machines.each do |m|
|
108
|
+
if m[:spec].driver_url
|
109
|
+
driver = run_context.chef_metal.driver_for_url(m[:spec].driver_url)
|
110
|
+
result[driver] ||= {}
|
111
|
+
result[driver][m[:spec]] = m[:options]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
result
|
115
|
+
end
|
116
|
+
|
117
|
+
def load_current_resource
|
118
|
+
# Load nodes in parallel
|
119
|
+
@machines = parallel_do(new_resource.machines) do |machine_resource|
|
120
|
+
provider = Chef::Provider::Machine.new(machine_resource, machine_resource.run_context)
|
121
|
+
provider.load_current_resource
|
122
|
+
{
|
123
|
+
:resource => machine_resource,
|
124
|
+
:spec => provider.machine_spec,
|
125
|
+
:options => provider.machine_options
|
126
|
+
}
|
127
|
+
end.to_a
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|