chef-provisioning 0.15
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 +207 -0
- data/LICENSE +201 -0
- data/README.md +260 -0
- data/Rakefile +6 -0
- data/lib/chef/provider/load_balancer.rb +77 -0
- data/lib/chef/provider/machine.rb +176 -0
- data/lib/chef/provider/machine_batch.rb +191 -0
- data/lib/chef/provider/machine_execute.rb +35 -0
- data/lib/chef/provider/machine_file.rb +54 -0
- data/lib/chef/provider/machine_image.rb +60 -0
- data/lib/chef/provisioning.rb +95 -0
- data/lib/chef/provisioning/action_handler.rb +68 -0
- data/lib/chef/provisioning/add_prefix_action_handler.rb +31 -0
- data/lib/chef/provisioning/chef_image_spec.rb +108 -0
- data/lib/chef/provisioning/chef_load_balancer_spec.rb +108 -0
- data/lib/chef/provisioning/chef_machine_spec.rb +84 -0
- data/lib/chef/provisioning/chef_provider_action_handler.rb +74 -0
- data/lib/chef/provisioning/chef_run_data.rb +139 -0
- data/lib/chef/provisioning/convergence_strategy.rb +28 -0
- data/lib/chef/provisioning/convergence_strategy/install_cached.rb +156 -0
- data/lib/chef/provisioning/convergence_strategy/install_msi.rb +58 -0
- data/lib/chef/provisioning/convergence_strategy/install_sh.rb +55 -0
- data/lib/chef/provisioning/convergence_strategy/no_converge.rb +39 -0
- data/lib/chef/provisioning/convergence_strategy/precreate_chef_objects.rb +183 -0
- data/lib/chef/provisioning/driver.rb +304 -0
- data/lib/chef/provisioning/image_spec.rb +72 -0
- data/lib/chef/provisioning/load_balancer_spec.rb +86 -0
- data/lib/chef/provisioning/machine.rb +112 -0
- data/lib/chef/provisioning/machine/basic_machine.rb +84 -0
- data/lib/chef/provisioning/machine/unix_machine.rb +278 -0
- data/lib/chef/provisioning/machine/windows_machine.rb +104 -0
- data/lib/chef/provisioning/machine_spec.rb +82 -0
- data/lib/chef/provisioning/recipe_dsl.rb +103 -0
- data/lib/chef/provisioning/transport.rb +95 -0
- data/lib/chef/provisioning/transport/ssh.rb +343 -0
- data/lib/chef/provisioning/transport/winrm.rb +151 -0
- data/lib/chef/provisioning/version.rb +5 -0
- data/lib/chef/resource/chef_data_bag_resource.rb +148 -0
- data/lib/chef/resource/load_balancer.rb +57 -0
- data/lib/chef/resource/machine.rb +124 -0
- data/lib/chef/resource/machine_batch.rb +78 -0
- data/lib/chef/resource/machine_execute.rb +28 -0
- data/lib/chef/resource/machine_file.rb +34 -0
- data/lib/chef/resource/machine_image.rb +35 -0
- data/lib/chef_metal.rb +1 -0
- metadata +217 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'chef/provisioning/convergence_strategy/precreate_chef_objects'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
class Chef
|
5
|
+
module Provisioning
|
6
|
+
class ConvergenceStrategy
|
7
|
+
class InstallMsi < PrecreateChefObjects
|
8
|
+
@@install_msi_cache = {}
|
9
|
+
|
10
|
+
def initialize(convergence_options, config)
|
11
|
+
super
|
12
|
+
@install_msi_url = convergence_options[:install_msi_url] || 'http://www.opscode.com/chef/install.msi'
|
13
|
+
@install_msi_path = convergence_options[:install_msi_path] || "$env:TEMP\\#{File.basename(@install_msi_url)}"
|
14
|
+
@chef_client_timeout = convergence_options.has_key?(:chef_client_timeout) ? convergence_options[:chef_client_timeout] : 120*60 # Default: 2 hours
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :install_msi_url
|
18
|
+
attr_reader :install_msi_path
|
19
|
+
|
20
|
+
def setup_convergence(action_handler, machine)
|
21
|
+
if !convergence_options.has_key?(:client_rb_path) || !convergence_options.has_key?(:client_pem_path)
|
22
|
+
system_drive = machine.execute_always('$env:SystemDrive').stdout.strip
|
23
|
+
@convergence_options = Cheffish::MergedConfig.new(convergence_options, {
|
24
|
+
:client_rb_path => "#{system_drive}\\chef\\client.rb",
|
25
|
+
:client_pem_path => "#{system_drive}\\chef\\client.pem"
|
26
|
+
})
|
27
|
+
end
|
28
|
+
|
29
|
+
super
|
30
|
+
|
31
|
+
# Install chef-client. TODO check and update version if not latest / not desired
|
32
|
+
if machine.execute_always('chef-client -v').exitstatus != 0
|
33
|
+
# TODO ssh verification of install.msi before running arbtrary code would be nice?
|
34
|
+
# TODO find a way to cache this on the host like with the Unix stuff.
|
35
|
+
# Limiter is we don't know how to efficiently upload large files to
|
36
|
+
# the remote machine with WMI.
|
37
|
+
machine.execute(action_handler, "(New-Object System.Net.WebClient).DownloadFile(#{machine.escape(install_msi_url)}, #{machine.escape(install_msi_path)})")
|
38
|
+
machine.execute(action_handler, "msiexec /qn /i #{machine.escape(install_msi_path)}")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def converge(action_handler, machine)
|
43
|
+
super
|
44
|
+
|
45
|
+
# TODO For some reason I get a 500 back if I don't do -l debug
|
46
|
+
action_handler.open_stream(machine.node['name']) do |stdout|
|
47
|
+
action_handler.open_stream(machine.node['name']) do |stderr|
|
48
|
+
machine.execute(action_handler, "chef-client -l debug",
|
49
|
+
:stream_stdout => stdout,
|
50
|
+
:stream_stderr => stderr,
|
51
|
+
:timeout => @chef_client_timeout)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'chef/provisioning/convergence_strategy/precreate_chef_objects'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
class Chef
|
5
|
+
module Provisioning
|
6
|
+
class ConvergenceStrategy
|
7
|
+
class InstallSh < PrecreateChefObjects
|
8
|
+
@@install_sh_cache = {}
|
9
|
+
|
10
|
+
def initialize(convergence_options, config)
|
11
|
+
convergence_options = Cheffish::MergedConfig.new(convergence_options, {
|
12
|
+
:client_rb_path => '/etc/chef/client.rb',
|
13
|
+
:client_pem_path => '/etc/chef/client.pem'
|
14
|
+
})
|
15
|
+
super(convergence_options, config)
|
16
|
+
@install_sh_url = convergence_options[:install_sh_url] || 'http://www.opscode.com/chef/install.sh'
|
17
|
+
@install_sh_path = convergence_options[:install_sh_path] || '/tmp/chef-install.sh'
|
18
|
+
@bootstrap_env = convergence_options[:bootstrap_proxy] ? "http_proxy=#{convergence_options[:bootstrap_proxy]}" : ""
|
19
|
+
@chef_client_timeout = convergence_options.has_key?(:chef_client_timeout) ? convergence_options[:chef_client_timeout] : 120*60 # Default: 2 hours
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :install_sh_url
|
23
|
+
attr_reader :install_sh_path
|
24
|
+
attr_reader :bootstrap_env
|
25
|
+
|
26
|
+
def setup_convergence(action_handler, machine)
|
27
|
+
super
|
28
|
+
|
29
|
+
# Install chef-client. TODO check and update version if not latest / not desired
|
30
|
+
if machine.execute_always('chef-client -v').exitstatus != 0
|
31
|
+
# TODO ssh verification of install.sh before running arbtrary code would be nice?
|
32
|
+
@@install_sh_cache[install_sh_url] ||= Net::HTTP.get(URI(install_sh_url))
|
33
|
+
machine.write_file(action_handler, install_sh_path, @@install_sh_cache[install_sh_url], :ensure_dir => true)
|
34
|
+
machine.execute(action_handler, "bash -c '#{bootstrap_env} bash #{install_sh_path}'")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def converge(action_handler, machine)
|
39
|
+
super
|
40
|
+
|
41
|
+
action_handler.open_stream(machine.node['name']) do |stdout|
|
42
|
+
action_handler.open_stream(machine.node['name']) do |stderr|
|
43
|
+
command_line = "chef-client"
|
44
|
+
command_line << " -l #{config[:log_level].to_s}" if config[:log_level]
|
45
|
+
machine.execute(action_handler, command_line,
|
46
|
+
:stream_stdout => stdout,
|
47
|
+
:stream_stderr => stderr,
|
48
|
+
:timeout => @chef_client_timeout)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'chef/provisioning/convergence_strategy'
|
2
|
+
require 'pathname'
|
3
|
+
require 'cheffish'
|
4
|
+
|
5
|
+
class Chef
|
6
|
+
module Provisioning
|
7
|
+
class ConvergenceStrategy
|
8
|
+
class NoConverge < ConvergenceStrategy
|
9
|
+
def initialize(convergence_options, config)
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def chef_server
|
14
|
+
@chef_server ||= convergence_options[:chef_server] || Cheffish.default_chef_server(config)
|
15
|
+
end
|
16
|
+
|
17
|
+
def setup_convergence(action_handler, machine)
|
18
|
+
end
|
19
|
+
|
20
|
+
def converge(action_handler, machine)
|
21
|
+
end
|
22
|
+
|
23
|
+
def cleanup_convergence(action_handler, machine_spec)
|
24
|
+
_self = self
|
25
|
+
Chef::Provisioning.inline_resource(action_handler) do
|
26
|
+
chef_node machine_spec.name do
|
27
|
+
chef_server _self.chef_server
|
28
|
+
action :delete
|
29
|
+
end
|
30
|
+
chef_client machine_spec.name do
|
31
|
+
chef_server _self.chef_server
|
32
|
+
action :delete
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
require 'chef/provisioning/convergence_strategy'
|
2
|
+
require 'pathname'
|
3
|
+
require 'cheffish'
|
4
|
+
|
5
|
+
class Chef
|
6
|
+
module Provisioning
|
7
|
+
class ConvergenceStrategy
|
8
|
+
class PrecreateChefObjects < ConvergenceStrategy
|
9
|
+
def initialize(convergence_options, config)
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def chef_server
|
14
|
+
@chef_server ||= convergence_options[:chef_server] || Cheffish.default_chef_server(config)
|
15
|
+
end
|
16
|
+
|
17
|
+
def setup_convergence(action_handler, machine)
|
18
|
+
# Create keys on machine
|
19
|
+
public_key = create_keys(action_handler, machine)
|
20
|
+
# Create node and client on chef server
|
21
|
+
create_chef_objects(action_handler, machine, public_key)
|
22
|
+
|
23
|
+
# If the chef server lives on localhost, tunnel the port through to the guest
|
24
|
+
# (we need to know what got tunneled!)
|
25
|
+
chef_server_url = chef_server[:chef_server_url]
|
26
|
+
chef_server_url = machine.make_url_available_to_remote(chef_server_url)
|
27
|
+
|
28
|
+
# Support for multiple ohai hints, required on some platforms
|
29
|
+
create_ohai_files(action_handler, machine)
|
30
|
+
|
31
|
+
# Create client.rb and client.pem on machine
|
32
|
+
content = client_rb_content(chef_server_url, machine.node['name'])
|
33
|
+
machine.write_file(action_handler, convergence_options[:client_rb_path], content, :ensure_dir => true)
|
34
|
+
end
|
35
|
+
|
36
|
+
def converge(action_handler, machine)
|
37
|
+
machine.make_url_available_to_remote(chef_server[:chef_server_url])
|
38
|
+
end
|
39
|
+
|
40
|
+
def cleanup_convergence(action_handler, machine_spec)
|
41
|
+
_self = self
|
42
|
+
Chef::Provisioning.inline_resource(action_handler) do
|
43
|
+
chef_node machine_spec.name do
|
44
|
+
chef_server _self.chef_server
|
45
|
+
action :delete
|
46
|
+
end
|
47
|
+
chef_client machine_spec.name do
|
48
|
+
chef_server _self.chef_server
|
49
|
+
action :delete
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
def create_keys(action_handler, machine)
|
57
|
+
server_private_key = machine.read_file(convergence_options[:client_pem_path])
|
58
|
+
if server_private_key
|
59
|
+
begin
|
60
|
+
server_private_key, format = Cheffish::KeyFormatter.decode(server_private_key)
|
61
|
+
rescue
|
62
|
+
server_private_key = nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
if server_private_key
|
67
|
+
if source_key && server_private_key.to_pem != source_key.to_pem
|
68
|
+
# If the server private key does not match our source key, overwrite it
|
69
|
+
server_private_key = source_key
|
70
|
+
if convergence_options[:allow_overwrite_keys]
|
71
|
+
machine.write_file(action_handler, convergence_options[:client_pem_path], server_private_key.to_pem, :ensure_dir => true)
|
72
|
+
else
|
73
|
+
raise "Private key on machine #{machine.name} does not match desired input key."
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
else
|
78
|
+
|
79
|
+
# If the server does not already have keys, create them and upload
|
80
|
+
_convergence_options = convergence_options
|
81
|
+
Chef::Provisioning.inline_resource(action_handler) do
|
82
|
+
private_key 'in_memory' do
|
83
|
+
path :none
|
84
|
+
if _convergence_options[:private_key_options]
|
85
|
+
_convergence_options[:private_key_options].each_pair do |key,value|
|
86
|
+
send(key, value)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
after { |resource, private_key| server_private_key = private_key }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
machine.write_file(action_handler, convergence_options[:client_pem_path], server_private_key.to_pem, :ensure_dir => true)
|
94
|
+
end
|
95
|
+
|
96
|
+
server_private_key.public_key
|
97
|
+
end
|
98
|
+
|
99
|
+
def is_localhost(host)
|
100
|
+
host == '127.0.0.1' || host == 'localhost' || host == '[::1]'
|
101
|
+
end
|
102
|
+
|
103
|
+
def source_key
|
104
|
+
if convergence_options[:source_key].is_a?(String)
|
105
|
+
key, format = Cheffish::KeyFormatter.decode(convergence_options[:source_key], convergence_options[:source_key_pass_phrase])
|
106
|
+
key
|
107
|
+
elsif convergence_options[:source_key]
|
108
|
+
convergence_options[:source_key]
|
109
|
+
elsif convergence_options[:source_key_path]
|
110
|
+
key, format = Cheffish::KeyFormatter.decode(IO.read(convergence_options[:source_key_path]), convergence_options[:source_key_pass_phrase], convergence_options[:source_key_path])
|
111
|
+
key
|
112
|
+
else
|
113
|
+
nil
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Create the ohai file(s)
|
118
|
+
def create_ohai_files(action_handler, machine)
|
119
|
+
if convergence_options[:ohai_hints]
|
120
|
+
convergence_options[:ohai_hints].each_pair do |hint, data|
|
121
|
+
# The location of the ohai hint
|
122
|
+
ohai_hint = "/etc/chef/ohai/hints/#{hint}.json"
|
123
|
+
machine.write_file(action_handler, ohai_hint, data.to_json, :ensure_dir => true)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def create_chef_objects(action_handler, machine, public_key)
|
129
|
+
_convergence_options = convergence_options
|
130
|
+
_chef_server = chef_server
|
131
|
+
# Save the node and create the client keys and client.
|
132
|
+
Chef::Provisioning.inline_resource(action_handler) do
|
133
|
+
# Create client
|
134
|
+
chef_client machine.name do
|
135
|
+
chef_server _chef_server
|
136
|
+
source_key public_key
|
137
|
+
output_key_path _convergence_options[:public_key_path]
|
138
|
+
output_key_format _convergence_options[:public_key_format]
|
139
|
+
admin _convergence_options[:admin]
|
140
|
+
validator _convergence_options[:validator]
|
141
|
+
end
|
142
|
+
|
143
|
+
# Create node
|
144
|
+
# TODO strip automatic attributes first so we don't race with "current state"
|
145
|
+
chef_node machine.name do
|
146
|
+
chef_server _chef_server
|
147
|
+
raw_json machine.node
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# If using enterprise/hosted chef, fix acls
|
152
|
+
if chef_server[:chef_server_url] =~ /\/+organizations\/.+/
|
153
|
+
grant_client_node_permissions(action_handler, chef_server, machine.name, ["read", "update"])
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Grant the client permissions to the node
|
158
|
+
# This procedure assumes that the client name and node name are the same
|
159
|
+
def grant_client_node_permissions(action_handler, chef_server, node_name, perms)
|
160
|
+
api = Cheffish.chef_server_api(chef_server)
|
161
|
+
node_perms = api.get("/nodes/#{node_name}/_acl")
|
162
|
+
perms.each do |p|
|
163
|
+
if !node_perms[p]['actors'].include?(node_name)
|
164
|
+
action_handler.perform_action "Add #{node_name} to client #{p} ACLs" do
|
165
|
+
node_perms[p]['actors'] << node_name
|
166
|
+
api.put("/nodes/#{node_name}/_acl/#{p}", p => node_perms[p])
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def client_rb_content(chef_server_url, node_name)
|
173
|
+
<<EOM
|
174
|
+
chef_server_url #{chef_server_url.inspect}
|
175
|
+
node_name #{node_name.inspect}
|
176
|
+
client_key #{convergence_options[:client_pem_path].inspect}
|
177
|
+
ssl_verify_mode :verify_peer
|
178
|
+
EOM
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,304 @@
|
|
1
|
+
class Chef
|
2
|
+
module Provisioning
|
3
|
+
#
|
4
|
+
# A Driver instance represents a place where machines can be created and found,
|
5
|
+
# and contains methods to create, delete, start, stop, and find them.
|
6
|
+
#
|
7
|
+
# For AWS, a Driver instance corresponds to a single account.
|
8
|
+
# For Vagrant, it is a directory where VM files are found.
|
9
|
+
#
|
10
|
+
# = How to Make a Driver
|
11
|
+
#
|
12
|
+
# To implement a Driver, you must implement the following methods:
|
13
|
+
#
|
14
|
+
# * initialize(driver_url) - create a new driver with the given URL
|
15
|
+
# * driver_url - a URL representing everything unique about your driver. (NOT credentials)
|
16
|
+
# * allocate_machine - ask the driver to allocate a machine to you.
|
17
|
+
# * ready_machine - get the machine "ready" - wait for it to be booted and accessible (for example, accessible via SSH transport).
|
18
|
+
# * stop_machine - stop the machine.
|
19
|
+
# * destroy_machine - delete the machine.
|
20
|
+
# * connect_to_machine - connect to the given machine.
|
21
|
+
#
|
22
|
+
# Optionally, you can also implement:
|
23
|
+
# * allocate_machines - allocate an entire group of machines.
|
24
|
+
# * ready_machines - get a group of machines warm and booted.
|
25
|
+
# * stop_machines - stop a group of machines.
|
26
|
+
# * destroy_machines - delete a group of machines.
|
27
|
+
#
|
28
|
+
# Additionally, you must create a file named `chef/provisioning/driver_init/<scheme>.rb`,
|
29
|
+
# where <scheme> is the name of the scheme you chose for your driver_url. This
|
30
|
+
# file, when required, must call Chef::Provisioning.add_registered_driver(<scheme>, <class>).
|
31
|
+
# The given <class>.from_url(url, config) will be called with a driver_url and
|
32
|
+
# configuration.
|
33
|
+
#
|
34
|
+
# All of these methods must be idempotent - if the work is already done, they
|
35
|
+
# just don't do anything.
|
36
|
+
#
|
37
|
+
class Driver
|
38
|
+
#
|
39
|
+
# Inflate a driver from a driver URL.
|
40
|
+
#
|
41
|
+
#
|
42
|
+
# @param [String] driver_url the URL to inflate the driver
|
43
|
+
# config - a configuration hash. See "config" for a list of known keys.
|
44
|
+
#
|
45
|
+
# == Returns
|
46
|
+
# A Driver representing the given driver_url.
|
47
|
+
#
|
48
|
+
def initialize(driver_url, config)
|
49
|
+
@driver_url = driver_url
|
50
|
+
@config = config
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# Override this on specific driver classes
|
55
|
+
#
|
56
|
+
def self.from_url(driver_url, config)
|
57
|
+
Chef::Provisioning.from_url(driver_url, config)
|
58
|
+
end
|
59
|
+
|
60
|
+
#
|
61
|
+
# A URL representing the driver and the place where machines come from.
|
62
|
+
# This will be stuffed in machine_spec.location['driver_url'] so that the
|
63
|
+
# machine can be re-inflated. URLs must have a unique scheme identifying the
|
64
|
+
# driver class, and enough information to identify the place where created
|
65
|
+
# machines can be found. For AWS, this is the account number; for lxc and
|
66
|
+
# vagrant, it is the directory in which VMs and containers are.
|
67
|
+
#
|
68
|
+
# For example:
|
69
|
+
# - fog:AWS:123456789012
|
70
|
+
# - vagrant:/var/vms
|
71
|
+
# - lxc:
|
72
|
+
# - docker:
|
73
|
+
#
|
74
|
+
attr_reader :driver_url
|
75
|
+
|
76
|
+
# A configuration hash. These keys may be present:
|
77
|
+
# - :driver_options: a driver-defined object containing driver config.
|
78
|
+
# - :private_keys: a hash of private keys, with a "name" and a "value". Values are either strings (paths) or PrivateKey objects.
|
79
|
+
# - :private_key_paths: a list of paths to directories containing private keys.
|
80
|
+
# - :write_private_key_path: the path to which we write new keys by default.
|
81
|
+
# - :log_level: :debug/:info/:warn/:error/:fatal
|
82
|
+
# - :chef_server_url: url to chef server
|
83
|
+
# - :node_name: username to talk to chef server
|
84
|
+
# - :client_key: path to key used to talk to chef server
|
85
|
+
attr_reader :config
|
86
|
+
|
87
|
+
#
|
88
|
+
# Driver configuration. Equivalent to config[:driver_options] || {}
|
89
|
+
#
|
90
|
+
def driver_options
|
91
|
+
config[:driver_options] || {}
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
# Allocate a machine from the underlying service. This method
|
96
|
+
# does not need to wait for the machine to boot or have an IP, but it must
|
97
|
+
# store enough information in machine_spec.location to find the machine
|
98
|
+
# later in ready_machine.
|
99
|
+
#
|
100
|
+
# If a machine is powered off or otherwise unusable, this method may start
|
101
|
+
# it, but does not need to wait until it is started. The idea is to get the
|
102
|
+
# gears moving, but the job doesn't need to be done :)
|
103
|
+
#
|
104
|
+
# @param [Chef::Provisioning::ActionHandler] action_handler The action_handler object that is calling this method
|
105
|
+
# @param [Chef::Provisioning::MachineSpec] machine_spec A machine specification representing this machine.
|
106
|
+
# @param [Hash] machine_options A set of options representing the desired options when
|
107
|
+
# constructing the machine
|
108
|
+
#
|
109
|
+
# @return [Chef::Provisioning::MachineSpec] Modifies the passed-in machine_spec. Anything in here will be saved
|
110
|
+
# back after allocate_machine completes.
|
111
|
+
#
|
112
|
+
def allocate_machine(action_handler, machine_spec, machine_options)
|
113
|
+
raise "#{self.class} does not implement allocate_machine"
|
114
|
+
end
|
115
|
+
|
116
|
+
# Ready a machine, to the point where it is running and accessible via a
|
117
|
+
# transport. This will NOT allocate a machine, but may kick it if it is down.
|
118
|
+
# This method waits for the machine to be usable, returning a Machine object
|
119
|
+
# pointing at the machine, allowing useful actions like setup, converge,
|
120
|
+
# execute, file and directory.
|
121
|
+
#
|
122
|
+
#
|
123
|
+
# @param [Chef::Provisioning::ActionHandler] action_handler The action_handler object that is calling this method
|
124
|
+
# @param [Chef::Provisioning::MachineSpec] machine_spec A machine specification representing this machine.
|
125
|
+
# @param [Hash] machine_options A set of options representing the desired state of the machine
|
126
|
+
#
|
127
|
+
# @return [Machine] A machine object pointing at the machine, allowing useful actions like setup,
|
128
|
+
# converge, execute, file and directory.
|
129
|
+
#
|
130
|
+
def ready_machine(action_handler, machine_spec, machine_options)
|
131
|
+
raise "#{self.class} does not implement ready_machine"
|
132
|
+
end
|
133
|
+
|
134
|
+
# Connect to a machine without allocating or readying it. This method will
|
135
|
+
# NOT make any changes to anything, or attempt to wait.
|
136
|
+
#
|
137
|
+
# @param [Chef::Provisioning::MachineSpec] machine_spec MachineSpec representing this machine.
|
138
|
+
# @param [Hash] machine_options
|
139
|
+
# @return [Machine] A machine object pointing at the machine, allowing useful actions like setup,
|
140
|
+
# converge, execute, file and directory.
|
141
|
+
#
|
142
|
+
def connect_to_machine(machine_spec, machine_options)
|
143
|
+
raise "#{self.class} does not implement connect_to_machine"
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
# Delete the given machine -- destroy the machine,
|
148
|
+
# returning things to the state before allocate_machine was called.
|
149
|
+
#
|
150
|
+
# @param [Chef::Provisioning::ActionHandler] action_handler The action_handler object that is calling this method
|
151
|
+
# @param [Chef::Provisioning::MachineSpec] machine_spec A machine specification representing this machine.
|
152
|
+
# @param [Hash] machine_options A set of options representing the desired state of the machine
|
153
|
+
def destroy_machine(action_handler, machine_spec, machine_options)
|
154
|
+
raise "#{self.class} does not implement destroy_machine"
|
155
|
+
end
|
156
|
+
|
157
|
+
# Stop the given machine.
|
158
|
+
#
|
159
|
+
# @param [Chef::Provisioning::ActionHandler] action_handler The action_handler object that is calling this method
|
160
|
+
# @param [Chef::Provisioning::MachineSpec] machine_spec A machine specification representing this machine.
|
161
|
+
# @param [Hash] machine_options A set of options representing the desired state of the machine
|
162
|
+
def stop_machine(action_handler, machine_spec, machine_options)
|
163
|
+
raise "#{self.class} does not implement stop_machine"
|
164
|
+
end
|
165
|
+
|
166
|
+
# Allocate an image. Returns quickly with an ID that tracks the image.
|
167
|
+
#
|
168
|
+
# @param [Chef::Provisioning::ActionHandler] action_handler The action_handler object that is calling this method
|
169
|
+
# @param [Chef::Provisioning::ImageSpec] image_spec A machine specification representing this machine.
|
170
|
+
# @param [Hash] image_options A set of options representing the desired state of the machine
|
171
|
+
def allocate_image(action_handler, image_spec, image_options, machine_spec)
|
172
|
+
raise "#{self.class} does not implement create_image"
|
173
|
+
end
|
174
|
+
|
175
|
+
# Ready an image, waiting till the point where it is ready to be used.
|
176
|
+
#
|
177
|
+
# @param [Chef::Provisioning::ActionHandler] action_handler The action_handler object that is calling this method
|
178
|
+
# @param [Chef::Provisioning::ImageSpec] image_spec A machine specification representing this machine.
|
179
|
+
# @param [Hash] image_options A set of options representing the desired state of the machine
|
180
|
+
def ready_image(action_handler, image_spec, image_options)
|
181
|
+
raise "#{self.class} does not implement ready_image"
|
182
|
+
end
|
183
|
+
|
184
|
+
# Destroy an image using this service.
|
185
|
+
#
|
186
|
+
# @param [Chef::Provisioning::ActionHandler] action_handler The action_handler object that is calling this method
|
187
|
+
# @param [Chef::Provisioning::ImageSpec] image_spec A machine specification representing this machine.
|
188
|
+
# @param [Hash] image_options A set of options representing the desired state of the machine
|
189
|
+
def destroy_image(action_handler, image_spec, image_options)
|
190
|
+
raise "#{self.class} does not implement destroy_image"
|
191
|
+
end
|
192
|
+
|
193
|
+
#
|
194
|
+
# Optional interface methods
|
195
|
+
#
|
196
|
+
|
197
|
+
#
|
198
|
+
# Allocate a set of machines. This should have the same effect as running
|
199
|
+
# allocate_machine on all machine_specs.
|
200
|
+
#
|
201
|
+
# Drivers do not need to implement this; the default implementation
|
202
|
+
# calls acquire_machine in parallel.
|
203
|
+
#
|
204
|
+
# == Parallelizing
|
205
|
+
#
|
206
|
+
# The parallelizer must implement #parallelize
|
207
|
+
# @example Example parallelizer
|
208
|
+
# parallelizer.parallelize(specs_and_options) do |machine_spec|
|
209
|
+
# allocate_machine(action_handler, machine_spec)
|
210
|
+
# end.to_a
|
211
|
+
# # The to_a at the end causes you to wait until the parallelization is done
|
212
|
+
#
|
213
|
+
# This object is shared among other chef-provisioning actions, ensuring that you do
|
214
|
+
# not go over parallelization limits set by the user. Use of the parallelizer
|
215
|
+
# to parallelizer machines is not required.
|
216
|
+
#
|
217
|
+
# == Passing a block
|
218
|
+
#
|
219
|
+
# If you pass a block to this function, each machine will be yielded to you
|
220
|
+
# as it completes, and then the function will return when all machines are
|
221
|
+
# yielded.
|
222
|
+
#
|
223
|
+
# @example Passing a block
|
224
|
+
# allocate_machines(action_handler, specs_and_options, parallelizer) do |machine_spec|
|
225
|
+
# ...
|
226
|
+
# end
|
227
|
+
#
|
228
|
+
# @param [Chef::Provisioning::ActionHandler] action_handler The action_handler object that is calling this method; this
|
229
|
+
# is generally a driver, but could be anything that can support the
|
230
|
+
# interface (i.e., in the case of the test kitchen provisioning driver for
|
231
|
+
# acquiring and destroying VMs).
|
232
|
+
# @param [Hash] specs_and_options A hash of machine_spec -> machine_options representing the
|
233
|
+
# machines to allocate.
|
234
|
+
# @param [Parallelizer] parallelizer an object with a parallelize() method that works like this:
|
235
|
+
# @return [Array<Machine>] An array of machine objects created
|
236
|
+
def allocate_machines(action_handler, specs_and_options, parallelizer)
|
237
|
+
parallelizer.parallelize(specs_and_options) do |machine_spec, machine_options|
|
238
|
+
allocate_machine(add_prefix(machine_spec, action_handler), machine_spec, machine_options)
|
239
|
+
yield machine_spec if block_given?
|
240
|
+
machine_spec
|
241
|
+
end.to_a
|
242
|
+
end
|
243
|
+
|
244
|
+
# Ready machines in batch, in parallel if possible.
|
245
|
+
def ready_machines(action_handler, specs_and_options, parallelizer)
|
246
|
+
parallelizer.parallelize(specs_and_options) do |machine_spec, machine_options|
|
247
|
+
machine = ready_machine(add_prefix(machine_spec, action_handler), machine_spec, machine_options)
|
248
|
+
yield machine if block_given?
|
249
|
+
machine
|
250
|
+
end.to_a
|
251
|
+
end
|
252
|
+
|
253
|
+
# Stop machines in batch, in parallel if possible.
|
254
|
+
def stop_machines(action_handler, specs_and_options, parallelizer)
|
255
|
+
parallelizer.parallelize(specs_and_options) do |machine_spec, machine_options|
|
256
|
+
stop_machine(add_prefix(machine_spec, action_handler), machine_spec, machine_options)
|
257
|
+
yield machine_spec if block_given?
|
258
|
+
end.to_a
|
259
|
+
end
|
260
|
+
|
261
|
+
# Delete machines in batch, in parallel if possible.
|
262
|
+
def destroy_machines(action_handler, specs_and_options, parallelizer)
|
263
|
+
parallelizer.parallelize(specs_and_options) do |machine_spec, machine_options|
|
264
|
+
destroy_machine(add_prefix(machine_spec, action_handler), machine_spec, machine_options)
|
265
|
+
yield machine_spec if block_given?
|
266
|
+
end.to_a
|
267
|
+
end
|
268
|
+
|
269
|
+
# Allocate a load balancer
|
270
|
+
# @param [ChefMetal::ActionHandler] action_handler The action handler
|
271
|
+
# @param [ChefMetal::LoadBalancerSpec] lb_spec Frozen LB specification
|
272
|
+
# @param [Hash] lb_options A hash of options to pass the LB
|
273
|
+
def allocate_load_balancer(action_handler, lb_spec, lb_options)
|
274
|
+
end
|
275
|
+
|
276
|
+
# Make the load balancer ready
|
277
|
+
# @param [ChefMetal::ActionHandler] action_handler The action handler
|
278
|
+
# @param [ChefMetal::LoadBalancerSpec] lb_spec Frozen LB specification
|
279
|
+
# @param [Hash] lb_options A hash of options to pass the LB
|
280
|
+
def ready_load_balancer(action_handler, lb_spec, lb_options)
|
281
|
+
end
|
282
|
+
|
283
|
+
# Destroy the load balancer
|
284
|
+
# @param [ChefMetal::ActionHandler] action_handler The action handler
|
285
|
+
# @param [ChefMetal::LoadBalancerSpec] lb_spec Frozen LB specification
|
286
|
+
# @param [Hash] lb_options A hash of options to pass the LB
|
287
|
+
def destroy_load_balancer(action_handler, lb_spec, lb_options)
|
288
|
+
end
|
289
|
+
|
290
|
+
def update_load_balancer(action_handler, lb_spec, lb_options, opts = {})
|
291
|
+
end
|
292
|
+
|
293
|
+
protected
|
294
|
+
|
295
|
+
def add_prefix(machine_spec, action_handler)
|
296
|
+
AddPrefixActionHandler.new(action_handler, "[#{machine_spec.name}] ")
|
297
|
+
end
|
298
|
+
|
299
|
+
def get_private_key(name)
|
300
|
+
Cheffish.get_private_key(name, config)
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|