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.
@@ -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
+