omf_rc 6.0.0.pre.7 → 6.0.0.pre.8
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/omf_rc +13 -1
- data/lib/omf_rc/resource_proxy/abstract_resource.rb +76 -35
- data/lib/omf_rc/resource_proxy/application.rb +82 -61
- data/lib/omf_rc/resource_proxy/net.rb +1 -0
- data/lib/omf_rc/resource_proxy/node.rb +1 -31
- data/lib/omf_rc/resource_proxy/virtual_machine.rb +388 -0
- data/lib/omf_rc/resource_proxy/virtual_machine_factory.rb +52 -0
- data/lib/omf_rc/resource_proxy/wlan.rb +1 -0
- data/lib/omf_rc/resource_proxy_dsl.rb +1 -1
- data/lib/omf_rc/util/ip.rb +8 -0
- data/lib/omf_rc/util/iw.rb +2 -0
- data/lib/omf_rc/util/libvirt.rb +118 -0
- data/lib/omf_rc/util/sysfs.rb +40 -0
- data/lib/omf_rc/util/vmbuilder.rb +181 -0
- data/lib/omf_rc/version.rb +1 -1
- data/test/omf_rc/resource_proxy/abstract_resource_spec.rb +6 -4
- data/test/omf_rc/util/ip_spec.rb +3 -1
- metadata +47 -39
@@ -0,0 +1,388 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2012 National ICT Australia (NICTA), Australia
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
|
22
|
+
#
|
23
|
+
# This module defines a Resource Proxy (RP) for a Virtual Machine Factory
|
24
|
+
#
|
25
|
+
# Utility dependencies: common_tools, libvirt, vmbuilder
|
26
|
+
#
|
27
|
+
# This VM Proxy has the following properties:
|
28
|
+
# - :use_sudo, use 'sudo' when running VM-related commands (default => true)
|
29
|
+
# - :hypervisor, the hypervisor to use (default => HYPERVISOR_DEFAULT)
|
30
|
+
# - :hypervisor_uri, the URI of the hypervisor to use (default => HYPERVISOR_URI_DEFAULT)
|
31
|
+
# - :virt_mngt, the virtualisation management tool to use (default => VIRTUAL_MNGT_DEFAULT)
|
32
|
+
# - :img_builder, the tool to use to build VM image (default => IMAGE_BUILDER_DEFAULT)
|
33
|
+
# - :state, the current state of this VM Proxy (default => :stopped)
|
34
|
+
# - :ready, is the VM for this Proxy ready to be run? (default => false)
|
35
|
+
# - :action, the next action to perform on this VM Proxy (build, define, stop, run, delete, attach, or clone_from)
|
36
|
+
# - :vm_name, the name of this VM (default => VM_NAME_DEFAULT_PREFIX + "_" + current time)
|
37
|
+
# - :image_directory, the directory holding this VM's disk image (default => VM_DIR_DEFAULT)
|
38
|
+
# - :image_path, the full path to this VM's disk image (default => image_directory + vm_name)
|
39
|
+
# - :vm_os, the OS to use on this VM (default => VM_OS_DEFAULT)
|
40
|
+
# - :vm_definition, the path to an definition file for this VM
|
41
|
+
# - :vm_original_clone, the name of an existing VM that may be used as a template for this one
|
42
|
+
# - :enable_omf, is an OMF Resource Proxy (to be) installed on this VM? (default => true)
|
43
|
+
# - :omf_opts, the options to set for the OMF v6 RC on this VM (default => OMF_DEFAULT)
|
44
|
+
#
|
45
|
+
# USAGE NOTES:
|
46
|
+
#
|
47
|
+
# A VirtualMachine Proxy is an interface to an underlying VM resource on a
|
48
|
+
# physical resource. When a VM Proxy is created, it is not necessarily yet
|
49
|
+
# associated with such a VM resource (unless the original 'create' command
|
50
|
+
# for this VM Proxy had some optional property configuration as described
|
51
|
+
# below).
|
52
|
+
#
|
53
|
+
# Thus you must associate this VM Proxy with an underlying VM resource. This
|
54
|
+
# could be done in the following manner:
|
55
|
+
# - A) build a brand new VM resource, including building a new disk image for it
|
56
|
+
# - B) build a new VM resource from an existing VM definition file
|
57
|
+
# - C) build a new VM resource by cloning an existing VM resource
|
58
|
+
# - D) attach a VM resource (existing already on the system) to this VM Proxy
|
59
|
+
#
|
60
|
+
# Once the VM Proxy is associated to an underlying VM resource, it can
|
61
|
+
# start/stop it or de-associated ('delete' action) from it, according to the
|
62
|
+
# following state diagram:
|
63
|
+
#
|
64
|
+
# build,
|
65
|
+
# clone,define,
|
66
|
+
# +---------+ attach +---------+ run +---------+
|
67
|
+
# | |--------|------->| stopped |------|----->| |
|
68
|
+
# | stopped | | + ready | | running |
|
69
|
+
# | |<-------|--------| |<-----|------| |
|
70
|
+
# +---------+ delete +---------+ stop +---------+
|
71
|
+
#
|
72
|
+
#
|
73
|
+
# Some examples of message sequences to send to a freshly created VM proxy
|
74
|
+
# 'new_VMP' to realise each of the above association cases are given in the
|
75
|
+
# 'Examples' section below.
|
76
|
+
#
|
77
|
+
# @example Case A: create and then run a new VM with a new disk image using all the default settings:
|
78
|
+
#
|
79
|
+
# # Communication setup
|
80
|
+
# comm = Comm.new(:xmpp)
|
81
|
+
# vm_topic = comm.get_topic('new_VMP')
|
82
|
+
#
|
83
|
+
# # Define the messages to publish
|
84
|
+
# conf_vm_name = comm.configure_message([vm_name: 'my_VM_123'])
|
85
|
+
# conf_vm_options = comm.configure_message([
|
86
|
+
# ubuntu_opts: { bridge: 'br0' },
|
87
|
+
# vmbuilder_opts: {ip: '10.0.0.240',
|
88
|
+
# net: '10.0.0.0',
|
89
|
+
# bcast: '10.255.255.255',
|
90
|
+
# mask: '255.0.0.0',
|
91
|
+
# gw: '10.0.0.200',
|
92
|
+
# dns: '10.0.0.200'} ])
|
93
|
+
# conf_vm_build = comm.configure_message([action: :build])
|
94
|
+
# conf_vm_run = comm.configure_message([action: :run])
|
95
|
+
#
|
96
|
+
# # Define a new event to run the VM resource once it is 'ready'
|
97
|
+
# vm_topic.on_message do |m|
|
98
|
+
# if (m.operation == :inform) && (m.read_content("inform_type") == 'STATUS') && m.read_property('ready')
|
99
|
+
# conf_vm_run.publish vm_topic.id
|
100
|
+
# end
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# # Publish the defined messages
|
104
|
+
# conf_vm_name.publish vm_topic.id
|
105
|
+
# conf_vm_options.publish vm_topic.id
|
106
|
+
# conf_vm_build.publish vm_topic.id
|
107
|
+
#
|
108
|
+
# @example Case B: create and run a new VM using an existing definition file:
|
109
|
+
#
|
110
|
+
# # Do the communication setup as in the above example...
|
111
|
+
#
|
112
|
+
# # Define the messages to publish
|
113
|
+
# conf_vm_name = comm.configure_message([vm_name: 'my_VM_123'])
|
114
|
+
# conf_vm_definition = comm.configure_message([vm_definition: '/home/me/my_vm_definition.xml'])
|
115
|
+
# conf_vm_define = comm.configure_message([action: :define])
|
116
|
+
# conf_vm_run = comm.configure_message([action: :run])
|
117
|
+
#
|
118
|
+
# # Define a new event to run the VM resource as in the above example...
|
119
|
+
#
|
120
|
+
# # Publish the defined messages
|
121
|
+
# conf_vm_name.publish vm_topic.id
|
122
|
+
# conf_vm_definition.publish vm_topic.id
|
123
|
+
# conf_vm_define.publish vm_topic.id
|
124
|
+
#
|
125
|
+
# @example Case C: create and run a new VM by cloning an existing VM:
|
126
|
+
#
|
127
|
+
# # Do the communication setup as in the above example...
|
128
|
+
#
|
129
|
+
# # Define the messages to publish
|
130
|
+
# # Note that the existing VM to clone from must be defined and known
|
131
|
+
# # by the virtualisation management tool set in the :virt_mngt property
|
132
|
+
# conf_vm_name = comm.configure_message([vm_name: 'my_VM_123'])
|
133
|
+
# conf_vm_original_name: comm.configure_message([vm_original_clone: 'existing_VM_456']),
|
134
|
+
# conf_vm_clone = comm.configure_message([action: :clone_from])
|
135
|
+
# conf_vm_run = comm.configure_message([action: :run])
|
136
|
+
#
|
137
|
+
# # Define a new event to run the VM resource as in the above example...
|
138
|
+
#
|
139
|
+
# # Publish the defined messages
|
140
|
+
# conf_vm_name.publish vm_topic.id
|
141
|
+
# conf_vm_original_name.publish vm_topic.id
|
142
|
+
# conf_vm_clone.publish vm_topic.id
|
143
|
+
#
|
144
|
+
# @example Case D: associate an existing VM to this VM Proxy and run it:
|
145
|
+
#
|
146
|
+
# # Do the communication setup as in the above example...
|
147
|
+
#
|
148
|
+
# # Define the messages to publish
|
149
|
+
# # Note that the existing VM to associate to this VM Proxy must be defined
|
150
|
+
# # and known by the virtualisation management tool set in the :virt_mngt property
|
151
|
+
# conf_vm_name = comm.configure_message([vm_name: 'my_VM_123'])
|
152
|
+
# conf_vm_attach: comm.configure_message([action: :attach]),
|
153
|
+
# conf_vm_run = comm.configure_message([action: :run])
|
154
|
+
#
|
155
|
+
# # Define a new event to run the VM resource as in the above example...
|
156
|
+
#
|
157
|
+
# # Publish the defined messages
|
158
|
+
# conf_vm_name.publish vm_topic.id
|
159
|
+
# conf_vm_attach.publish vm_topic.id
|
160
|
+
#
|
161
|
+
# EXTENSION NOTES:
|
162
|
+
#
|
163
|
+
# By default this VM Proxy interacts with a KVM hypervisor using the libvirt
|
164
|
+
# virtualisation tools (i.e. virsh, virt-clone) to manipulate Ubuntu-based VMs,
|
165
|
+
# which may be built using ubuntu's vmbuilder tool. However, one can extend this
|
166
|
+
# to support other hypervisors and tools.
|
167
|
+
#
|
168
|
+
# - to extend:
|
169
|
+
# - create one/many utility file(s) to hold the code of your extension,
|
170
|
+
# e.g. "myext.rb"
|
171
|
+
# - assuming you will use the "foo" virtualisation management tools, and
|
172
|
+
# the "bar" image building tool, then you must define within your utility
|
173
|
+
# file(s) the following work methods, which should perform the obvious
|
174
|
+
# tasks mention by their names. In addition they must return 'true' if
|
175
|
+
# their tasks were successfully performed, or 'false' otherwise. See the
|
176
|
+
# provided libvirt and vmbuilder utility files for some examples.
|
177
|
+
# - define_vm_with_foo
|
178
|
+
# - stop_vm_with_foo
|
179
|
+
# - run_vm_with_foo
|
180
|
+
# - attach_vm_with_foo
|
181
|
+
# - clone_vm_with_foo
|
182
|
+
# - delete_vm_with_foo
|
183
|
+
# - build_img_with_bar
|
184
|
+
#
|
185
|
+
# - to use that extension:
|
186
|
+
# - require that/these utility files
|
187
|
+
# - set the virt_mngt, virt_mngt properties to "foo", "bar" respectively
|
188
|
+
#
|
189
|
+
# @see OmfRc::Util::Libvirt
|
190
|
+
# @see OmfRc::Util::Vmbuilder
|
191
|
+
module OmfRc::ResourceProxy::VirtualMachine
|
192
|
+
include OmfRc::ResourceProxyDSL
|
193
|
+
|
194
|
+
register_proxy :virtual_machine
|
195
|
+
utility :common_tools
|
196
|
+
utility :libvirt
|
197
|
+
utility :vmbuilder
|
198
|
+
|
199
|
+
# Default Hypervisor to use
|
200
|
+
HYPERVISOR_DEFAULT = :kvm
|
201
|
+
# Default URI for the default Hypervisor
|
202
|
+
HYPERVISOR_URI_DEFAULT = 'qemu:///system'
|
203
|
+
# Default virtualisation management tool to use
|
204
|
+
VIRTUAL_MNGT_DEFAULT = :libvirt
|
205
|
+
# Default VM image building tool to use
|
206
|
+
IMAGE_BUILDER_DEFAULT = :vmbuilder
|
207
|
+
# Default prefix to use for the VM's name
|
208
|
+
VM_NAME_DEFAULT_PREFIX = "vm"
|
209
|
+
# Default directory to store the VM's disk image
|
210
|
+
VM_DIR_DEFAULT = "/home/thierry/experiments/omf6-dev/images"
|
211
|
+
# Default OS used on this VM
|
212
|
+
VM_OS_DEFAULT = 'ubuntu'
|
213
|
+
# Default OMF v6 parameters for the Resource Controller on the VM
|
214
|
+
OMF_DEFAULT = Hashie::Mash.new({
|
215
|
+
server: 'srv.mytestbed.net',
|
216
|
+
user: nil, password: nil,
|
217
|
+
topic: nil
|
218
|
+
})
|
219
|
+
|
220
|
+
property :use_sudo, :default => true
|
221
|
+
property :hypervisor, :default => HYPERVISOR_DEFAULT
|
222
|
+
property :hypervisor_uri, :default => HYPERVISOR_URI_DEFAULT
|
223
|
+
property :virt_mngt, :default => VIRTUAL_MNGT_DEFAULT
|
224
|
+
property :img_builder, :default => IMAGE_BUILDER_DEFAULT
|
225
|
+
property :action, :default => :stop
|
226
|
+
property :state, :default => :stopped
|
227
|
+
property :ready, :default => false
|
228
|
+
property :enable_omf, :default => true
|
229
|
+
property :vm_name, :default => "#{VM_NAME_DEFAULT_PREFIX}_#{Time.now.to_i}"
|
230
|
+
property :image_directory, :default => VM_DIR_DEFAULT
|
231
|
+
property :image_path, :default => VM_DIR_DEFAULT
|
232
|
+
property :vm_definition, :default => ''
|
233
|
+
property :vm_original_clone, :default => ''
|
234
|
+
property :vm_os, :default => VM_OS_DEFAULT
|
235
|
+
property :omf_opts, :default => OMF_DEFAULT
|
236
|
+
|
237
|
+
# Configure the OMF property of this VM Proxy.
|
238
|
+
# These are the parameters to pass to an OMF v6 Resource Controller
|
239
|
+
# installed (or to be installed) on the VM associated to this VM Proxy.
|
240
|
+
#
|
241
|
+
# @yieldparam [Hash] opts a hash with the OMF RC parameters
|
242
|
+
# - server (String) the PubSub sever for this OMF RC to connect to
|
243
|
+
# - user (String) the username to use for that server
|
244
|
+
# - password (String) the password to use for that server
|
245
|
+
# - topic (String) the PubSub topic to subscribe to
|
246
|
+
#
|
247
|
+
configure :omf_opts do |res, opts|
|
248
|
+
if opts.kind_of? Hash
|
249
|
+
if res.property.omf_opts.empty?
|
250
|
+
res.property.omf_opts = OMF_DEFAULT.merge(opts)
|
251
|
+
else
|
252
|
+
res.property.omf_opts = res.property.omf_opts.merge(opts)
|
253
|
+
end
|
254
|
+
else
|
255
|
+
res.log_inform_error "OMF option configuration failed! "+
|
256
|
+
"Options not passed as Hash (#{opts.inspect})"
|
257
|
+
end
|
258
|
+
res.property.omf_opts
|
259
|
+
end
|
260
|
+
|
261
|
+
# Configure the name for the VM associated to this VM Proxy.
|
262
|
+
# Changing this name will also change the path for the VM's disk image:
|
263
|
+
# image_path = image_directory + "/" + vm_name
|
264
|
+
#
|
265
|
+
# @yieldparam [String] name the name of the VM
|
266
|
+
#
|
267
|
+
configure :vm_name do |res, name|
|
268
|
+
res.property.image_path = "#{res.property.image_directory}/#{name}"
|
269
|
+
res.property.vm_name = name
|
270
|
+
end
|
271
|
+
|
272
|
+
# Configure the directory for the disk image of the VM associated to this
|
273
|
+
# VM Proxy.
|
274
|
+
# Changing this directory will also change the path for the VM's disk image:
|
275
|
+
# image_path = image_directory + "/" + vm_name
|
276
|
+
#
|
277
|
+
# @yieldparam [String] name the name of the directory
|
278
|
+
#
|
279
|
+
configure :image_directory do |res, name|
|
280
|
+
res.property.image_path = "#{name}/#{res.property.vm_name}"
|
281
|
+
res.property.image_directory = name
|
282
|
+
end
|
283
|
+
|
284
|
+
# Configure the next action to execute for this VM Proxy.
|
285
|
+
# Available actions are: build, define, stop, run, delete, attach, clone_from.
|
286
|
+
# For details about these actions, refer to the overview description at the
|
287
|
+
# start of this file.
|
288
|
+
#
|
289
|
+
# @yieldparam [String] value the name of the action
|
290
|
+
#
|
291
|
+
configure :action do |res, value|
|
292
|
+
act = value.to_s.downcase
|
293
|
+
res.send("#{act}_vm")
|
294
|
+
res.property.action = value
|
295
|
+
end
|
296
|
+
|
297
|
+
work :build_vm do |res|
|
298
|
+
res.log_inform_warn "Trying to build an already built VM, make sure to "+
|
299
|
+
"have the 'overwrite' property set to true!" if res.property.ready
|
300
|
+
if res.property.state.to_sym == :stopped
|
301
|
+
res.property.ready = res.send("build_img_with_#{res.property.img_builder}")
|
302
|
+
res.inform(:status, Hashie::Mash.new({:status => {:ready => res.property.ready}}))
|
303
|
+
else
|
304
|
+
res.log_inform_error "Cannot build VM image: it is not stopped"+
|
305
|
+
"(name: '#{res.property.vm_name}' - state: #{res.property.state} "+
|
306
|
+
"- path: '#{res.property.image_path}')"
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
work :define_vm do |res|
|
311
|
+
unless File.exist?(res.property.vm_definition)
|
312
|
+
res.log_inform_error "Cannot define VM (name: "+
|
313
|
+
"'#{res.property.vm_name}'): definition path not set "+
|
314
|
+
"or file does not exist (path: '#{res.property.vm_definition}')"
|
315
|
+
else
|
316
|
+
if res.property.state.to_sym == :stopped
|
317
|
+
res.property.ready = res.send("define_vm_with_#{res.property.virt_mngt}")
|
318
|
+
res.inform(:status, Hashie::Mash.new({:status => {:ready => res.property.ready}}))
|
319
|
+
else
|
320
|
+
res.log_inform_warn "Cannot define VM: it is not stopped"+
|
321
|
+
"(name: '#{res.property.vm_name}' - state: #{res.property.state})"
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
work :attach_vm do |res|
|
327
|
+
unless !res.property.vm_name.nil? || !res.property.vm_name == ""
|
328
|
+
res.log_inform_error "Cannot attach VM, name not set"+
|
329
|
+
"(name: '#{res.property.vm_name})'"
|
330
|
+
else
|
331
|
+
if res.property.state.to_sym == :stopped
|
332
|
+
res.property.ready = res.send("attach_vm_with_#{res.property.virt_mngt}")
|
333
|
+
res.inform(:status, Hashie::Mash.new({:status => {:ready => res.property.ready}}))
|
334
|
+
else
|
335
|
+
res.log_inform_warn "Cannot attach VM: it is not stopped"+
|
336
|
+
"(name: '#{res.property.vm_name}' - state: #{res.property.state})"
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
work :clone_from_vm do |res|
|
342
|
+
unless !res.property.vm_name.nil? || !res.property.vm_name == "" ||
|
343
|
+
!res.image_directory.nil? || !res.image_directory == ""
|
344
|
+
res.log_inform_error "Cannot clone VM: name or directory not set "+
|
345
|
+
"(name: '#{res.property.vm_name}' - dir: '#{res.property.image_directory}')"
|
346
|
+
else
|
347
|
+
if res.property.state.to_sym == :stopped
|
348
|
+
res.property.ready = res.send("clone_vm_with_#{res.property.virt_mngt}")
|
349
|
+
res.inform(:status, Hashie::Mash.new({:status => {:ready => res.property.ready}}))
|
350
|
+
else
|
351
|
+
res.log_inform_warn "Cannot clone VM: it is not stopped"+
|
352
|
+
"(name: '#{res.property.vm_name}' - state: #{res.property.state})"
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
work :stop_vm do |res|
|
358
|
+
if res.property.state.to_sym == :running
|
359
|
+
success = res.send("stop_vm_with_#{res.property.virt_mngt}")
|
360
|
+
res.property.state = :stopped if success
|
361
|
+
else
|
362
|
+
res.log_inform_warn "Cannot stop VM: it is not running "+
|
363
|
+
"(name: '#{res.property.vm_name}' - state: #{res.property.state})"
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
work :run_vm do |res|
|
368
|
+
if res.property.state.to_sym == :stopped && res.property.ready
|
369
|
+
success = res.send("run_vm_with_#{res.property.virt_mngt}")
|
370
|
+
res.property.state = :running if success
|
371
|
+
else
|
372
|
+
res.log_inform_warn "Cannot run VM: it is not stopped or ready yet "+
|
373
|
+
"(name: '#{res.property.vm_name}' - state: #{res.property.state})"
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
work :delete_vm do |res|
|
378
|
+
if res.property.state.to_sym == :stopped && res.property.ready
|
379
|
+
success = res.send("delete_vm_with_#{res.property.virt_mngt}")
|
380
|
+
res.property.ready = false if success
|
381
|
+
else
|
382
|
+
res.log_inform_warn "Cannot delete VM: it is not stopped or ready yet "+
|
383
|
+
"(name: '#{res.property.vm_name}' - state: #{res.property.state} "+
|
384
|
+
"- ready: #{res.property.ready}"
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2012 National ICT Australia (NICTA), Australia
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
|
22
|
+
#
|
23
|
+
# This module defines a Resource Proxy (RP) for a Virtual Machine Factory
|
24
|
+
#
|
25
|
+
# Utility dependencies: common_tools
|
26
|
+
#
|
27
|
+
# This VM Factory Proxy is the resource entity that can create VM Proxies.
|
28
|
+
# @see OmfRc::ResourceProxy::VirtualMachine
|
29
|
+
#
|
30
|
+
module OmfRc::ResourceProxy::VirtualMachineFactory
|
31
|
+
include OmfRc::ResourceProxyDSL
|
32
|
+
|
33
|
+
register_proxy :virtual_machine_factory
|
34
|
+
utility :common_tools
|
35
|
+
|
36
|
+
hook :before_ready do |res|
|
37
|
+
res.property.vms_path ||= "/var/lib/libvirt/images/"
|
38
|
+
res.property.vm_list ||= []
|
39
|
+
end
|
40
|
+
|
41
|
+
hook :before_create do |res, type, opts = nil|
|
42
|
+
if type.to_sym != :virtual_machine
|
43
|
+
raise "This resource only creates VM! (Cannot create a resource: #{type})"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
hook :after_create do |res, child_res|
|
48
|
+
logger.info "Created new child VM: #{child_res.uid}"
|
49
|
+
res.property.vm_list << child_res.uid
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
data/lib/omf_rc/util/ip.rb
CHANGED
@@ -15,14 +15,22 @@ module OmfRc::Util::Ip
|
|
15
15
|
end
|
16
16
|
|
17
17
|
configure :ip_addr do |resource, value|
|
18
|
+
# Remove all ip addrs associated with the device
|
19
|
+
resource.flush_ip_addrs
|
18
20
|
CommandLine.new("ip", "addr add :ip_address dev :device",
|
19
21
|
:ip_address => value,
|
20
22
|
:device => resource.hrn
|
21
23
|
).run
|
24
|
+
resource.interface_up
|
22
25
|
resource.request_ip_addr
|
23
26
|
end
|
24
27
|
|
25
28
|
work :interface_up do |resource|
|
26
29
|
CommandLine.new("ip", "link set :dev up", :dev => resource.hrn).run
|
27
30
|
end
|
31
|
+
|
32
|
+
work :flush_ip_addrs do |resource|
|
33
|
+
CommandLine.new("ip", "addr flush dev :device",
|
34
|
+
:device => resource.hrn).run
|
35
|
+
end
|
28
36
|
end
|
data/lib/omf_rc/util/iw.rb
CHANGED
@@ -0,0 +1,118 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2012 National ICT Australia (NICTA), Australia
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
|
22
|
+
#
|
23
|
+
# This module defines the command specifics to manage VMs using the
|
24
|
+
# virsh and virt-clone tools
|
25
|
+
#
|
26
|
+
# Utility dependencies: common_tools
|
27
|
+
#
|
28
|
+
# @see OmfRc::ResourceProxy::VirtualMachine
|
29
|
+
#
|
30
|
+
module OmfRc::Util::Libvirt
|
31
|
+
include OmfRc::ResourceProxyDSL
|
32
|
+
|
33
|
+
VIRSH = "/usr/bin/virsh"
|
34
|
+
VIRTCLONE = "/usr/bin/virt-clone"
|
35
|
+
|
36
|
+
work :execute_cmd do |res,cmd,intro_msg,error_msg,success_msg|
|
37
|
+
logger.info "#{intro_msg} with: '#{cmd}'"
|
38
|
+
result = `#{cmd} 2>&1`
|
39
|
+
if $?.exitstatus != 0
|
40
|
+
res.log_inform_error "#{error_msg}: '#{result}'"
|
41
|
+
false
|
42
|
+
else
|
43
|
+
logger.info "#{success_msg}"
|
44
|
+
true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
work :define_vm_with_libvirt do |res|
|
49
|
+
cmd = "#{VIRSH} -c #{res.property.hypervisor_uri} "+
|
50
|
+
"define #{res.property.vm_definition}"
|
51
|
+
res.execute_cmd(cmd, "Defining VM",
|
52
|
+
"Cannot define VM", "VM defined successfully!")
|
53
|
+
end
|
54
|
+
|
55
|
+
work :stop_vm_with_libvirt do |res|
|
56
|
+
cmd = "#{VIRSH} -c #{res.property.hypervisor_uri} "+
|
57
|
+
"destroy #{res.property.vm_name}"
|
58
|
+
res.execute_cmd(cmd, "Stopping VM",
|
59
|
+
"Cannot stop VM", "VM stopped successfully!")
|
60
|
+
end
|
61
|
+
|
62
|
+
work :run_vm_with_libvirt do |res|
|
63
|
+
cmd = "#{VIRSH} -c #{res.property.hypervisor_uri} "+
|
64
|
+
"start #{res.property.vm_name}"
|
65
|
+
res.execute_cmd(cmd, "Running VM",
|
66
|
+
"Cannot run VM", "VM running now!")
|
67
|
+
end
|
68
|
+
|
69
|
+
work :delete_vm_with_libvirt do |res|
|
70
|
+
cmd = "#{VIRSH} -c #{res.property.hypervisor_uri} "+
|
71
|
+
"undefine #{res.property.vm_name} ; rm -rf #{res.property.image_path}"
|
72
|
+
res.execute_cmd(cmd, "Deleting VM",
|
73
|
+
"Cannot delete VM", "VM deleted!")
|
74
|
+
end
|
75
|
+
|
76
|
+
work :clone_vm_with_libvirt do |res|
|
77
|
+
cmd = "#{VIRTCLONE} --connect #{res.property.hypervisor_uri} "+
|
78
|
+
"-n #{res.property.vm_name} -f #{res.property.image_path} "
|
79
|
+
|
80
|
+
# virt-clone v 0.600.1 reports an error when running with --original-xml
|
81
|
+
# even directly on the command line. The error is:
|
82
|
+
# "ERROR 'NoneType' object is not iterable"
|
83
|
+
# TODO: find-out why we have this error
|
84
|
+
# For now we only try to clone from a known VM name and disable the
|
85
|
+
# option to clone it from a known XML definition
|
86
|
+
#
|
87
|
+
#if res.property.vm_definition != ''
|
88
|
+
# cmd += "--original-xml #{res.property.vm_definition}"
|
89
|
+
#elsif res.property.vm_original_clone != ''
|
90
|
+
|
91
|
+
if res.property.vm_original_clone != ''
|
92
|
+
cmd += "--original #{res.property.vm_original_clone}"
|
93
|
+
else
|
94
|
+
res.log_inform_error "Cannot clone VM '#{res.property.vm_name}' as "+
|
95
|
+
"no original VM or template definition are set "+
|
96
|
+
"(oritinal: '#{res.property.vm_definition}' - "+
|
97
|
+
"template: '#{res.property.vm_original_clone}')"
|
98
|
+
end
|
99
|
+
res.execute_cmd(cmd, "Cloning VM from '#{res.property.vm_definition}' "+
|
100
|
+
" or '#{res.property.vm_original_clone}'",
|
101
|
+
"Cannot clone VM", "Cloned VM successfully!")
|
102
|
+
end
|
103
|
+
|
104
|
+
work :attach_vm_with_libvirt do |res|
|
105
|
+
found = false
|
106
|
+
cmd = "#{VIRSH} -c #{res.property.hypervisor_uri} list --all"
|
107
|
+
o = `#{cmd} 2>&1`
|
108
|
+
o.each_line { |l| found = true if l.split(' ')[1] == res.property.vm_name }
|
109
|
+
unless found
|
110
|
+
res.log_inform_error "Cannot attach to the VM '#{res.property.vm_name}'"+
|
111
|
+
" (maybe it does not exist?)"
|
112
|
+
else
|
113
|
+
logger.info "Now attached to existing VM '#{res.property.vm_name}'!"
|
114
|
+
end
|
115
|
+
found
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module OmfRc::Util::Sysfs
|
2
|
+
include OmfRc::ResourceProxyDSL
|
3
|
+
|
4
|
+
request :devices do |resource|
|
5
|
+
devices = []
|
6
|
+
# Support net devices for now
|
7
|
+
category = "net"
|
8
|
+
|
9
|
+
Dir.glob("/sys/class/net/eth*").each do |v|
|
10
|
+
File.exist?("#{v}/uevent") && File.open("#{v}/uevent") do |f|
|
11
|
+
subcategory = f.read.match(/DEVTYPE=(.+)/) && $1
|
12
|
+
proxy = "net"
|
13
|
+
File.exist?("#{v}/device/uevent") && File.open("#{v}/device/uevent") do |f|
|
14
|
+
driver = f.read.match(/DRIVER=(.+)/) && $1
|
15
|
+
device = { name: File.basename(v), driver: driver, category: category }
|
16
|
+
device[:subcategory] = subcategory if subcategory
|
17
|
+
device[:proxy] = proxy if OmfRc::ResourceFactory.proxy_list.include?(proxy.to_sym)
|
18
|
+
devices << device
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
Dir.glob("/sys/class/ieee80211/*").each do |v|
|
24
|
+
subcategory = "wlan"
|
25
|
+
proxy = "wlan"
|
26
|
+
File.exist?("#{v}/device/uevent") && File.open("#{v}/device/uevent") do |f|
|
27
|
+
driver = f.read.match(/DRIVER=(.+)/) && $1
|
28
|
+
device = { name: File.basename(v), driver: driver, category: category, subcategory: subcategory }
|
29
|
+
device[:proxy] = proxy if OmfRc::ResourceFactory.proxy_list.include?(proxy.to_sym)
|
30
|
+
devices << device
|
31
|
+
end
|
32
|
+
end
|
33
|
+
devices
|
34
|
+
end
|
35
|
+
|
36
|
+
request :wlan_devices do |resource|
|
37
|
+
resource.request_devices.find_all { |v| v[:proxy] == 'wlan' }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|