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
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
|