chef-metal 0.10.1 → 0.10.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/chef_metal/chef_run_data.rb +5 -1
- data/lib/chef_metal/machine_spec.rb +81 -0
- data/lib/chef_metal/provider.rb +239 -0
- data/lib/chef_metal/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af79447510d93b295a7d77a3223d670bdc569415
|
4
|
+
data.tar.gz: ac28faf8d8afa3026960b9997de94d9c4fc77369
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 49762ba3a7f0f71677b85d6f9657cdb05174c1d389ba96825bb218f9af7dd557f35ab515dd391865caba7dc20a6a3ddfbd12b1a3c566219bab1e6cda7d8248fa
|
7
|
+
data.tar.gz: 5412dfb1f503aa30259bf37c16a7f8e46dffc98c7434375fefaf208a3745af25208052d60a4982a6a809444eaaeb82211e6490fa5a9c52cced6a7347cf70c0a0
|
data/CHANGELOG.md
CHANGED
@@ -9,7 +9,11 @@ module ChefMetal
|
|
9
9
|
with :machine_batch
|
10
10
|
|
11
11
|
def add_provisioner_options(options, &block)
|
12
|
-
|
12
|
+
if current_provisioner_options
|
13
|
+
with_provisioner_options(Chef::Mixin::DeepMerge.hash_only_merge(current_provisioner_options, options), &block)
|
14
|
+
else
|
15
|
+
with_provisioner_options(options)
|
16
|
+
end
|
13
17
|
end
|
14
18
|
end
|
15
19
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'cheffish'
|
2
|
+
require 'cheffish/cheffish_server_api'
|
3
|
+
|
4
|
+
module ChefMetal
|
5
|
+
#
|
6
|
+
# Specification for a machine. Sufficient information to find and contact it
|
7
|
+
# after it has been set up.
|
8
|
+
#
|
9
|
+
class MachineSpec
|
10
|
+
def initialize(node, chef_server)
|
11
|
+
@node = node
|
12
|
+
@chef_server = chef_server
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.get(name, chef_server)
|
16
|
+
rest = Cheffish::CheffishServerAPI.new(chef_server || Cheffish.current_chef_server)
|
17
|
+
MachineSpec.new(rest.get("/nodes/#{name}"), chef_server)
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# Globally unique identifier for this machine. Does not depend on the machine's
|
22
|
+
# location or existence.
|
23
|
+
#
|
24
|
+
def id
|
25
|
+
"#{@chef_server[:chef_server_url]}/nodes/#{name}"
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Name of the machine. Corresponds to the name in "machine 'name' do" ...
|
30
|
+
#
|
31
|
+
def name
|
32
|
+
@node['name']
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Location of this machine. This should be a freeform hash, with enough
|
37
|
+
# information for the provider to look it up and create a Machine object to
|
38
|
+
# access it.
|
39
|
+
#
|
40
|
+
# This MUST include a 'provider_url' attribute with the provider's URL in it.
|
41
|
+
#
|
42
|
+
# chef-metal will do its darnedest to not lose this information.
|
43
|
+
#
|
44
|
+
def location
|
45
|
+
metal_attr('location')
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Set the location for this machine.
|
50
|
+
#
|
51
|
+
def location=(value)
|
52
|
+
@node['normal']['metal'] ||= {}
|
53
|
+
@node['normal']['metal']['spec'] = value
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# Save this node to the server. If you have significant information that
|
58
|
+
# could be lost, you should do this as quickly as possible. Data will be
|
59
|
+
# saved automatically for you after allocate_machine and ready_machine.
|
60
|
+
#
|
61
|
+
def save(action_handler)
|
62
|
+
# Save the node to the server.
|
63
|
+
ChefMetal.inline_resource(action_handler) do
|
64
|
+
chef_node node['name'] do
|
65
|
+
chef_server @chef_server
|
66
|
+
raw_json node
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def metal_attr(attr)
|
74
|
+
if @node['normal'] && @node['normal']['metal']
|
75
|
+
@node['normal']['metal'][attr]
|
76
|
+
else
|
77
|
+
nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,239 @@
|
|
1
|
+
module ChefMetal
|
2
|
+
#
|
3
|
+
# A Provider instance represents a place where machines can be created and found,
|
4
|
+
# and contains methods to create, delete, start, stop, and find them.
|
5
|
+
#
|
6
|
+
# For AWS, a Provider instance corresponds to a single account.
|
7
|
+
# For Vagrant, it is a directory where VM files are found.
|
8
|
+
#
|
9
|
+
# == How to Make a Provider
|
10
|
+
#
|
11
|
+
# To implement a Provider, you must implement the following methods:
|
12
|
+
#
|
13
|
+
# - initialize(driver_url) - create a new driver with the given URL
|
14
|
+
# - driver_url - a URL representing everything unique about your provider.
|
15
|
+
# But 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
|
18
|
+
# accessible (for example, accessible via SSH transport).
|
19
|
+
# - stop_machine - stop the machine.
|
20
|
+
# - delete_machine - delete the machine.
|
21
|
+
# - connect_to_machine - connect to the given machine.
|
22
|
+
#
|
23
|
+
# Optionally, you can also implement:
|
24
|
+
# - allocate_machines - allocate an entire group of machines.
|
25
|
+
# - resource_created - a hook to tell you when a resource associated with your
|
26
|
+
# provider has been created.
|
27
|
+
#
|
28
|
+
# Additionally, you must create a file named `chef_metal/provider_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
|
31
|
+
#
|
32
|
+
# All of these methods must be idempotent - if the work is already done, they
|
33
|
+
# just don't do anything.
|
34
|
+
#
|
35
|
+
class Provider
|
36
|
+
#
|
37
|
+
# Inflate a driver from node information; we don't want to force the
|
38
|
+
# driver to figure out what the driver really needs, since it varies
|
39
|
+
# from driver to driver.
|
40
|
+
#
|
41
|
+
# ## Parameters
|
42
|
+
# driver_url - the URL to inflate the driver
|
43
|
+
#
|
44
|
+
# ## Returns
|
45
|
+
# A Provider representing the given driver_url.
|
46
|
+
def initialize(driver_url)
|
47
|
+
# We do not save it ... it's up to the driver to extract whatever information
|
48
|
+
# it wants.
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# A URL representing the driver and the place where machines come from.
|
53
|
+
# This will be stuffed in attributes in the node so that the node can be
|
54
|
+
# reinflated. URLs must have a unique scheme identifying the driver
|
55
|
+
# class, and enough information to identify the place where created machines
|
56
|
+
# can be found. For AWS, this is the account number; for lxc and vagrant,
|
57
|
+
# it is the directory in which VMs and containers are.
|
58
|
+
#
|
59
|
+
# For example:
|
60
|
+
# - fog:AWS:123456789012
|
61
|
+
# - vagrant:/var/vms
|
62
|
+
# - lxc:
|
63
|
+
# - docker:
|
64
|
+
#
|
65
|
+
def driver_url
|
66
|
+
raise "#{self.class} does not implement driver_url"
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# Allocate a machine from the PXE/cloud/VM/container provider. This method
|
71
|
+
# does not need to wait for the machine to boot or have an IP, but it must
|
72
|
+
# store enough information in node['normal']['driver_output'] to find
|
73
|
+
# the machine later in ready_machine.
|
74
|
+
#
|
75
|
+
# If a machine is powered off or otherwise unusable, this method may start
|
76
|
+
# it, but does not need to wait until it is started. The idea is to get the
|
77
|
+
# gears moving, but the job doesn't need to be done :)
|
78
|
+
#
|
79
|
+
# ## Parameters
|
80
|
+
# action_handler - the action_handler object that is calling this method; this
|
81
|
+
# is generally a provider, but could be anything that can support the
|
82
|
+
# interface (i.e., in the case of the test kitchen metal driver for
|
83
|
+
# acquiring and destroying VMs).
|
84
|
+
#
|
85
|
+
# existing_machine - a MachineSpec representing the existing machine (if any).
|
86
|
+
#
|
87
|
+
# machine_options - a set of options representing the desired provisioning
|
88
|
+
# state of the machine (image name, bootstrap ssh credentials,
|
89
|
+
# etc.). This will NOT be stored in the node, and is
|
90
|
+
# ephemeral.
|
91
|
+
#
|
92
|
+
# ## Returns
|
93
|
+
#
|
94
|
+
# Modifies the passed-in machine_spec. Anything in here will be saved
|
95
|
+
# back to the node.
|
96
|
+
#
|
97
|
+
def allocate_machine(action_handler, machine_spec, machine_options)
|
98
|
+
raise "#{self.class} does not implement allocate_machine"
|
99
|
+
end
|
100
|
+
|
101
|
+
#
|
102
|
+
# Ready a machine, to the point where it is running and accessible via a
|
103
|
+
# transport. This will NOT allocate a machine, but may kick it if it is down.
|
104
|
+
# This method waits for the machine to be usable, returning a Machine object
|
105
|
+
# pointing at the machine, allowing useful actions like setup, converge,
|
106
|
+
# execute, file and directory.
|
107
|
+
#
|
108
|
+
# ## Parameters
|
109
|
+
# action_handler - the action_handler object that is calling this method; this
|
110
|
+
# is generally a provider, but could be anything that can support the
|
111
|
+
# interface (i.e., in the case of the test kitchen metal driver for
|
112
|
+
# acquiring and destroying VMs).
|
113
|
+
# machine_spec - MachineSpec representing this machine.
|
114
|
+
#
|
115
|
+
# ## Returns
|
116
|
+
#
|
117
|
+
# Machine object pointing at the machine, allowing useful actions like setup,
|
118
|
+
# converge, execute, file and directory.
|
119
|
+
#
|
120
|
+
def ready_machine(action_handler, machine_spec)
|
121
|
+
raise "#{self.class} does not implement ready_machine"
|
122
|
+
end
|
123
|
+
|
124
|
+
#
|
125
|
+
# Connect to a machine without allocating or readying it. This method will
|
126
|
+
# NOT make any changes to anything, or attempt to wait.
|
127
|
+
#
|
128
|
+
# ## Parameters
|
129
|
+
# machine_spec - MachineSpec representing this machine.
|
130
|
+
#
|
131
|
+
# ## Returns
|
132
|
+
#
|
133
|
+
# Machine object pointing at the machine, allowing useful actions like setup,
|
134
|
+
# converge, execute, file and directory.
|
135
|
+
#
|
136
|
+
def connect_to_machine(machine_spec)
|
137
|
+
raise "#{self.class} does not implement connect_to_machine"
|
138
|
+
end
|
139
|
+
|
140
|
+
#
|
141
|
+
# Delete the given machine (idempotent). Should destroy the machine,
|
142
|
+
# returning things to the state before allocate_machine was called.
|
143
|
+
#
|
144
|
+
def delete_machine(action_handler, machine_spec)
|
145
|
+
raise "#{self.class} does not implement delete_machine"
|
146
|
+
end
|
147
|
+
|
148
|
+
#
|
149
|
+
# Stop the given machine.
|
150
|
+
#
|
151
|
+
def stop_machine(action_handler, machine_spec)
|
152
|
+
raise "#{self.class} does not implement stop_machine"
|
153
|
+
end
|
154
|
+
|
155
|
+
#
|
156
|
+
# Optional interface methods
|
157
|
+
#
|
158
|
+
|
159
|
+
#
|
160
|
+
# Allocate a set of machines. This should have the same effect as running
|
161
|
+
# allocate_machine on all nodes.
|
162
|
+
#
|
163
|
+
# Providers do not need to implement this; the default implementation
|
164
|
+
# calls acquire_machine in parallel.
|
165
|
+
#
|
166
|
+
# ## Parameter
|
167
|
+
# action_handler - the action_handler object that is calling this method; this
|
168
|
+
# is generally a provider, but could be anything that can support the
|
169
|
+
# interface (i.e., in the case of the test kitchen metal driver for
|
170
|
+
# acquiring and destroying VMs).
|
171
|
+
# nodes - a list of nodes representing the nodes to acquire.
|
172
|
+
# parallelizer - an object with a parallelize() method that works like this:
|
173
|
+
#
|
174
|
+
# parallelizer.parallelize(nodes) do |node|
|
175
|
+
# allocate_machine(action_handler, node)
|
176
|
+
# end.to_a
|
177
|
+
# # The to_a at the end causes you to wait until the parallelization is done
|
178
|
+
#
|
179
|
+
# This object is shared among other chef-metal actions, ensuring that you do
|
180
|
+
# not go over parallelization limits set by the user. Use of the parallelizer
|
181
|
+
# to parallelizer machines is not required.
|
182
|
+
#
|
183
|
+
def allocate_machines(action_handler, machine_specs, parallelizer)
|
184
|
+
parallelizer.parallelize(machine_specs) do |machine_spec|
|
185
|
+
allocate_machine(add_prefix(machine_spec, action_handler), machine_spec)
|
186
|
+
yield machine_spec if block_given?
|
187
|
+
machine
|
188
|
+
end.to_a
|
189
|
+
end
|
190
|
+
|
191
|
+
# Acquire machines in batch, in parallel if possible.
|
192
|
+
def acquire_machines(action_handler, machine_specs, parallelizer)
|
193
|
+
parallelizer.parallelize(machine_specs) do |machine_spec|
|
194
|
+
machine = acquire_machine(add_prefix(machine_spec, action_handler), machine_spec)
|
195
|
+
yield machine_spec, machine if block_given?
|
196
|
+
machine
|
197
|
+
end.to_a
|
198
|
+
end
|
199
|
+
|
200
|
+
# Stop machines in batch, in parallel if possible.
|
201
|
+
def stop_machines(action_handler, nodes_json, parallelizer)
|
202
|
+
parallelizer.parallelize(machine_specs) do |machine_spec|
|
203
|
+
stop_machine(add_prefix(machine_spec, action_handler), machine_spec)
|
204
|
+
yield machine_spec if block_given?
|
205
|
+
end.to_a
|
206
|
+
end
|
207
|
+
|
208
|
+
# Delete machines in batch, in parallel if possible.
|
209
|
+
def delete_machines(action_handler, machine_specs, parallelizer)
|
210
|
+
parallelizer.parallelize(machine_specs) do |machine_spec|
|
211
|
+
delete_machine(add_prefix(machine_spec, action_handler), machine_spec)
|
212
|
+
yield machine_spec if block_given?
|
213
|
+
end.to_a
|
214
|
+
end
|
215
|
+
|
216
|
+
#
|
217
|
+
# Provider notification that happens at the point a machine resource is declared
|
218
|
+
# (after all properties have been set on it)
|
219
|
+
#
|
220
|
+
def resource_created(machine)
|
221
|
+
end
|
222
|
+
|
223
|
+
protected
|
224
|
+
|
225
|
+
def save_node(provider, node, chef_server)
|
226
|
+
# Save the node and create the client. TODO strip automatic attributes first so we don't race with "current state"
|
227
|
+
ChefMetal.inline_resource(provider) do
|
228
|
+
chef_node node['name'] do
|
229
|
+
chef_server chef_server
|
230
|
+
raw_json node
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def add_prefix(node_json, action_handler)
|
236
|
+
AddPrefixActionHandler.new(action_handler, "[#{node_json['name']}] ")
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
data/lib/chef_metal/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chef-metal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.10.
|
4
|
+
version: 0.10.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Keiser
|
@@ -172,7 +172,9 @@ files:
|
|
172
172
|
- lib/chef_metal/machine/unix_machine.rb
|
173
173
|
- lib/chef_metal/machine/windows_machine.rb
|
174
174
|
- lib/chef_metal/machine.rb
|
175
|
+
- lib/chef_metal/machine_spec.rb
|
175
176
|
- lib/chef_metal/openstack_credentials.rb
|
177
|
+
- lib/chef_metal/provider.rb
|
176
178
|
- lib/chef_metal/provider_action_handler.rb
|
177
179
|
- lib/chef_metal/provisioner.rb
|
178
180
|
- lib/chef_metal/recipe_dsl.rb
|