omf_rc 6.0.0.pre.7 → 6.0.0.pre.8
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.
- 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
|
+
|