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.
@@ -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
@@ -6,6 +6,7 @@ module OmfRc::ResourceProxy::Wlan
6
6
  utility :ip
7
7
  utility :mod
8
8
  utility :iw
9
+ utility :sysfs
9
10
 
10
11
  hook :before_release do |device|
11
12
  case device.property.mode.to_sym
@@ -323,7 +323,7 @@ module OmfRc::ResourceProxyDSL
323
323
  opts = Hashie::Mash.new(opts)
324
324
 
325
325
  define_method("def_property_#{name}") do |*args, &block|
326
- self.property[name] = opts[:default]
326
+ self.property[name] ||= opts[:default]
327
327
  end
328
328
  end
329
329
  end
@@ -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
@@ -136,5 +136,7 @@ module OmfRc::Util::Iw
136
136
  device.add_interface(:monitor)
137
137
  device.interface_up
138
138
  end
139
+
140
+ device.configure_ip_addr(device.property.ip_addr) if device.property.ip_addr
139
141
  end
140
142
  end
@@ -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
+