vagrant-kvm 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -25,12 +25,11 @@ module VagrantPlugins
25
25
  def shared_folders
26
26
  {}.tap do |result|
27
27
  @env[:machine].config.vm.synced_folders.each do |id, data|
28
- # Ignore NFS shared folders
29
- #next if data[:nfs]
28
+ next if data[:disabled]
30
29
 
31
- unless data[:disabled]
32
- # convert to NFS share
33
- data[:nfs] = true
30
+ data[:nfs] = true unless @env[:machine].provider_config.enable_virtfs
31
+
32
+ if data[:nfs]
34
33
  # This to prevent overwriting the actual shared folders data
35
34
  result[id] = data.dup
36
35
  end
@@ -0,0 +1,40 @@
1
+ require "digest/md5"
2
+ require "vagrant/util/retryable"
3
+
4
+ module VagrantPlugins
5
+ module ProviderKvm
6
+ module Cap
7
+ class MountP9
8
+ extend Vagrant::Util::Retryable
9
+
10
+ def self.mount_p9_shared_folder(machine, folders, options)
11
+ folders.each do |name, opts|
12
+ # Expand the guest path so we can handle things like "~/vagrant"
13
+ expanded_guest_path = machine.guest.capability(
14
+ :shell_expand_guest_path, opts[:guestpath])
15
+
16
+ # Do the actual creating and mounting
17
+ machine.communicate.sudo("mkdir -p #{expanded_guest_path}")
18
+
19
+ # Mount
20
+ # tag maximum len is 31
21
+ mount_tag = Digest::MD5.new.update(name).to_s[0,31]
22
+
23
+ mount_opts="-o trans=virtio"
24
+ mount_opts += ",access=#{options[:owner]}" if options[:owner]
25
+ mount_opts += ",version=#{options[:version]}" if options[:version]
26
+ mount_opts += ",#{opts[:mount_options]}" if opts[:mount_options]
27
+
28
+ mount_command = "mount -t 9p #{mount_opts} '#{mount_tag}' #{expanded_guest_path}"
29
+ retryable(:on => Vagrant::Errors::LinuxMountFailed,
30
+ :tries => 5,
31
+ :sleep => 3) do
32
+ machine.communicate.sudo(mount_command,
33
+ :error_class => Vagrant::Errors::LinuxMountFailed)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,3 +1,5 @@
1
+ require 'etc'
2
+
1
3
  module VagrantPlugins
2
4
  module ProviderKvm
3
5
  class Config < Vagrant.plugin("2", :config)
@@ -21,6 +23,11 @@ module VagrantPlugins
21
23
  # @return [Hash]
22
24
  attr_reader :network_adapters
23
25
 
26
+ # The storage pool to use
27
+ #
28
+ # @return [String]
29
+ attr_accessor :storage_pool
30
+
24
31
  # The VM image format
25
32
  #
26
33
  # @return [String]
@@ -63,11 +70,27 @@ module VagrantPlugins
63
70
  attr_accessor :machine_type
64
71
  attr_accessor :network_model
65
72
  attr_accessor :video_model
73
+ attr_accessor :sound
74
+ attr_accessor :virtio_rng
75
+
76
+ # disk bus type
77
+ # sata/virtio
78
+ #
79
+ # @return [String]
80
+ attr_accessor :disk_bus
81
+
82
+ # Security labelling
83
+ # default: off
84
+ #
85
+ # @return [String]
86
+ attr_accessor :seclabel
66
87
  attr_accessor :force_pause
67
88
 
68
89
  def initialize
90
+ @customizations = []
69
91
  @name = UNSET_VALUE
70
92
  @gui = UNSET_VALUE
93
+ @storage_pool = UNSET_VALUE
71
94
  @image_type = UNSET_VALUE
72
95
  @image_mode = UNSET_VALUE
73
96
  @qemu_bin = UNSET_VALUE
@@ -80,7 +103,27 @@ module VagrantPlugins
80
103
  @machine_type = UNSET_VALUE
81
104
  @network_model = UNSET_VALUE
82
105
  @video_model = UNSET_VALUE
83
- @force_pause = UNSET_VALUE
106
+ @disk_bus = UNSET_VALUE
107
+ @sound = UNSET_VALUE
108
+ @force_pause = UNSET_VALUE
109
+ @enable_virtfs = UNSET_VALUE
110
+ @virtio_rng = UNSET_VALUE
111
+ end
112
+
113
+ # Customize the VM by predefined actions.
114
+ #
115
+ # When called multiple times, the customizations will be applied
116
+ # in the order given.
117
+ #
118
+ # The special `:name` parameter in the command will be replaced with
119
+ # the unique ID or name of the virtual machine. This is useful for
120
+ # parameters to `modifyvm` and the like.
121
+ #
122
+ # @param [Array] command An array of arguments to pass to
123
+ def customize(*command)
124
+ event = command.first.is_a?(String) ? command.shift : "pre-boot"
125
+ command = command[0]
126
+ @customizations << [event, command]
84
127
  end
85
128
 
86
129
  # This is the hook that is called to finalize the object before it
@@ -90,6 +133,9 @@ module VagrantPlugins
90
133
  @name = nil if @name == UNSET_VALUE
91
134
  # Default is to not show a GUI
92
135
  @gui = false if @gui == UNSET_VALUE
136
+ # Default is a storage pool we create for vagrant
137
+ login = Etc.getlogin
138
+ @storage_pool = 'vagrant-'+login.to_s if @storage_pool == UNSET_VALUE
93
139
  # Default image type is a sparsed raw
94
140
  @image_type = 'qcow2' if @image_type == UNSET_VALUE
95
141
  case @image_mode
@@ -141,7 +187,33 @@ module VagrantPlugins
141
187
  @machine_type = "pc-1.2" if @machine_type == UNSET_VALUE
142
188
  @network_model = "virtio" if @network_model == UNSET_VALUE
143
189
  @video_model = "cirrus" if @video_model == UNSET_VALUE
190
+ @disk_bus = nil if @disk_bus == UNSET_VALUE
191
+ @sound = false if @sound == UNSET_VALUE
144
192
  @force_pause = false if @force_pause == UNSET_VALUE
193
+ @enable_virtfs = false if @enable_virtfs == UNSET_VALUE
194
+ @virtio_rng = nil if @virtio_rng == UNSET_VALUE
195
+ end
196
+
197
+ def validate(machine)
198
+ errors = []
199
+
200
+ valid_events = ["pre-import", "pre-boot", "post-boot"]
201
+ @customizations.each do |event, _|
202
+ if !valid_events.include?(event)
203
+ errors << I18n.t(
204
+ "vagrant.kvm.config.invalid_event",
205
+ event: event.to_s,
206
+ valid_events: valid_events.join(", "))
207
+ end
208
+ end
209
+
210
+ @customizations.each do |event, command|
211
+ if event == "pre-import" && command.index(:id)
212
+ errors << I18n.t("vagrant.kvm.config.id_in_pre_import")
213
+ end
214
+ end
215
+
216
+ { "KVM Provider" => errors }
145
217
  end
146
218
  end
147
219
  end
@@ -1,5 +1,7 @@
1
1
  require 'libvirt'
2
2
  require 'log4r'
3
+ require 'pathname'
4
+ require "rexml/document"
3
5
 
4
6
  module VagrantPlugins
5
7
  module ProviderKvm
@@ -29,27 +31,17 @@ module VagrantPlugins
29
31
  # The UUID of the virtual machine we represent
30
32
  attr_reader :uuid
31
33
 
32
- # The QEMU version
33
- # XXX sufficient or have to check kvm and libvirt versions?
34
- attr_reader :version
35
-
36
- # KVM support status
37
- attr_reader :kvm
38
-
39
34
  # Vagrant 1.5.x pool migration
40
35
  attr_reader :pool_migrate
41
36
 
42
37
  def initialize(uuid=nil)
43
38
  @logger = Log4r::Logger.new("vagrant::provider::kvm::driver")
44
39
  @uuid = uuid
45
- # This should be configurable
46
- @pool_name = "vagrant"
47
- @network_name = "vagrant"
40
+ @virsh_path = "virsh"
48
41
  @pool_migrate = false
49
42
 
50
43
  load_kvm_module!
51
44
  connect_libvirt_qemu!
52
- init_storage_pool!
53
45
 
54
46
  if @uuid
55
47
  # Verify the VM exists, and if it doesn't, then don't worry
@@ -150,17 +142,20 @@ module VagrantPlugins
150
142
  # @param [String] definition Path to the VM XML file.
151
143
  # @param [String] volume_name Name of the imported volume
152
144
  # @param [Hash] attributes
153
- def import(definition, volume_name, args={})
145
+ def import(box_xml_filename, volume_name, args={})
154
146
  @logger.info("Importing VM #{@name}")
155
147
  # create vm definition from xml
156
- definition = File.open(definition) { |f| Util::VmDefinition.new(f.read) }
148
+ definition = File.open(box_xml_filename) { |f| Util::VmDefinition.new(f.read) }
157
149
  volume_path = lookup_volume_path_by_name(volume_name)
158
150
  args = {
159
151
  :image_type => "qcow2",
160
152
  :qemu_bin => "/usr/bin/qemu",
161
153
  :disk => volume_path,
162
- :name => @name
154
+ :network => 'vagrant',
155
+ :name => @name,
156
+ :uuid => nil
163
157
  }.merge(args)
158
+ args.merge!(:virtio_rng => nil) if @conn.version.to_i < 1003000 # virtio_rng supported in 1.3.0+
164
159
  definition.update(args)
165
160
  # create vm
166
161
  @logger.info("Creating new VM")
@@ -172,33 +167,58 @@ module VagrantPlugins
172
167
 
173
168
  # Create network
174
169
  def create_network(config)
170
+ # Get the network if it exists
171
+ network_name = config[:name]
172
+ hosts = config[:hosts]
173
+ @logger.info("empty host!") unless hosts
175
174
  begin
176
- # Get the network if it exists
177
- @network = @conn.lookup_network_by_name(@network_name)
178
- definition = Util::NetworkDefinition.new(@network_name,
179
- @network.xml_desc)
180
- rescue Libvirt::RetrieveError
181
- # Network doesn't exist, create with defaults
182
- definition = Util::NetworkDefinition.new(@network_name)
183
- end
184
- definition.update(config)
185
- if @network.nil?
186
- @logger.info("Creating network #{@network_name}")
187
- @network = define_network(definition)
188
- else
175
+ network = @conn.lookup_network_by_name(network_name)
176
+ definition = Util::NetworkDefinition.new(network_name,
177
+ network.xml_desc)
178
+ old_def = Util::NetworkDefinition.new(network_name,
179
+ network.xml_desc)
180
+ definition.update(config)
181
+ @logger.info("Update network #{network_name}")
182
+ @logger.debug("From:\n#{old_def.as_xml}")
183
+ @logger.debug("TO:\n#{definition.as_xml}")
184
+
189
185
  # Only destroy existing network if config has changed. This is
190
186
  # necessary because other VM could be currently using this network
191
187
  # and will loose connectivity if the network is destroyed.
192
- old_def = Util::NetworkDefinition.new(@network_name, @network.xml_desc)
193
- if old_def == definition && @network.active?
194
- @logger.info "Reusing existing configuration for #{@network_name}"
195
- else
196
- @logger.info "Recreating network config for #{@network_name}"
197
- @logger.debug "Old definition was:\n#{@network.xml_desc}"
198
- @network.destroy if @network.active?
199
- @network.undefine
200
- @network = define_network(definition)
188
+ if network.active?
189
+ @logger.info "Reusing existing configuration for #{network_name}"
190
+ update_command = Libvirt::Network::NETWORK_UPDATE_COMMAND_ADD_LAST
191
+ hosts.each do |host|
192
+ if old_def.already_exist_host?(host)
193
+ update_command = Libvirt::Network::NETWORK_UPDATE_COMMAND_MODIFY
194
+ end
195
+ end
196
+ if update_command == Libvirt::Network::NETWORK_UPDATE_COMMAND_MODIFY
197
+ @logger.info ("Updating network #{network_name} using UPDATE_COMMAND_MODIFY")
198
+ else
199
+ @logger.info ("Updating network #{network_name} using UPDATE_COMMAND_ADD_LAST")
200
+ end
201
+
202
+ network.update(update_command,
203
+ Libvirt::Network::NETWORK_SECTION_IP_DHCP_HOST,
204
+ -1,
205
+ definition.as_host_xml,
206
+ Libvirt::Network::NETWORK_UPDATE_AFFECT_CURRENT
207
+ )
208
+ network.create unless network.active?
209
+ else # network is not active
210
+ @logger.info "Recreating network config for #{network_name}"
211
+ network.undefine
212
+ network = define_network(definition)
201
213
  end
214
+
215
+ rescue Libvirt::RetrieveError
216
+ # Network doesn't exist, create with defaults
217
+ definition = Util::NetworkDefinition.new(network_name)
218
+ definition.update(config)
219
+ @logger.info("Creating network #{network_name}")
220
+ @logger.debug("with\n#{definition.as_xml}")
221
+ network = define_network(definition)
202
222
  end
203
223
  end
204
224
 
@@ -210,68 +230,100 @@ module VagrantPlugins
210
230
  network
211
231
  end
212
232
 
213
- # Initialize or create storage pool
214
- def init_storage(base_path, uid, gid)
215
- # Storage pool doesn't exist so we create it
216
- # create dir if it doesn't exist
217
- # if we let libvirt create the dir it is owned by root
218
- pool_path = File.join(base_path, "/storage-pool")
219
- FileUtils.mkpath(pool_path) unless Dir.exists?(pool_path)
220
- init_storage_directory(
221
- :pool_path => pool_path,
222
- :pool_name => @pool_name,
223
- :owner => uid, :group=>gid, :mode=>'755')
224
- init_storage_pool!
233
+ def get_default_ip
234
+ "192.168.123.10"
225
235
  end
226
236
 
227
- def init_storage_directory(args={})
237
+ def read_machine_ip
238
+ if @uuid && vm_exists?(@uuid)
239
+ begin
240
+ domain = @conn.lookup_domain_by_uuid(@uuid)
241
+ definition = Util::VmDefinition.new(domain.xml_desc)
242
+ mac_address = definition.get(:mac)
243
+ network_name = definition.get(:network)
244
+ network = @conn.lookup_network_by_name(network_name)
245
+ network_definition = Util::NetworkDefinition.new(network_name,
246
+ network.xml_desc)
247
+ network_definition.get(:hosts).each do |host|
248
+ return host[:ip] if mac_address == host[:mac]
249
+ end
250
+ rescue Libvirt::RetrieveError
251
+ @logger.info("cannot get definition og #{@uuid}")
252
+ end
253
+ else
254
+ @logger.debug("missing uuid? #{@uuid}")
255
+ end
256
+ get_default_ip
257
+ end
258
+
259
+ # Activate the driver's storage pool
260
+ def activate_storage_pool(pool_name)
261
+ # Get storage pool if it exists
262
+ @pool = init_storage_pool(pool_name)
263
+ # check neccesity of migrating to new storage pool format
264
+ # this is happen when user has already used vagrant-kvm 0.1.5 and after
265
+ # XXX needs clarification
266
+ check_migrate_box_storage_pool
267
+ @logger.info("Retrieving storage pool #{pool_name}")
268
+ end
269
+
270
+ # Initialize or Create a new storage pool
271
+ def init_storage_pool(pool_name, pool_path='/tmp', dir_mode='0755')
228
272
  begin
229
- # Get the storage pool if it exists
230
- pool = @conn.lookup_storage_pool_by_name(args[:pool_name])
231
- @logger.info("Init storage pool #{args[:pool_name]}")
273
+ # Try to retrieve the storage pool
274
+ pool = @conn.lookup_storage_pool_by_name(pool_name)
275
+ @logger.info("Activating storage pool #{pool_name}")
276
+ pool.create unless pool.active?
277
+ pool.refresh
278
+ pool
232
279
  rescue Libvirt::RetrieveError
233
- @logger.info("Init storage pool with owner: #{args[:owner]}")
234
- storage_pool_xml = <<-EOF
280
+ create_storage_pool(pool_name, pool_path, dir_mode)
281
+ end
282
+ end
283
+
284
+ def create_storage_pool(pool_name, pool_path, dir_mode)
285
+ @logger.info("Creating new storage pool #{pool_name} in #{pool_path}")
286
+ # create dir if it doesn't exist
287
+ FileUtils.mkpath(pool_path) unless Dir.exists?(pool_path)
288
+ storage_pool_xml = <<-EOF
235
289
  <pool type="dir">
236
- <name>#{args[:pool_name]}</name>
290
+ <name>#{pool_name}</name>
237
291
  <target>
238
- <path>#{args[:pool_path]}</path>
292
+ <path>#{pool_path}</path>
239
293
  <permissions>
240
- <owner>#{args[:owner]}</owner>
241
- <group>#{args[:group]}</group>
242
- <mode>#{args[:mode]}</mode>
294
+ <owner>#{Process.uid}</owner>
295
+ <group>#{Process.gid}</group>
296
+ <mode>#{dir_mode}</mode>
243
297
  </permissions>
244
298
  </target>
245
299
  </pool>
246
- EOF
247
- # create transient pool
248
- #
249
- # WARN:
250
- # vagrant-kvm 0.1.5 uses
251
- # pool = @conn.define_storage_pool_xml(storage_pool_xml)
252
- # that made 'pesistent' storage pool
253
- # this caused problem when following sinario:
254
- #
255
- # 1. user use vagrant-kvm 0.1.5 with vagrant-1.4.x
256
- # 2. user upgrade vagrant 1.5.x
257
- # 3. user upgrade vagrant 0.1.5.1 and after
258
- #
259
- # vagrant-kvm 0.1.5 don't work with vagrant 1.5.x
260
- # previous synario can be happned on many user.
261
- #
262
- # We use transient pool instead of persistent one
263
- # in vagrant-kvm 0.1.5.x, 0.1.6 and after
264
- #
265
- # Pools defined here will be removed after system reboot.
266
- #
300
+ EOF
301
+ # Create transient pool
302
+ # Pools defined here will be removed after system reboot.
303
+ @logger.debug("Creating storage pool with XML:\n #{storage_pool_xml}")
304
+ begin
267
305
  pool = @conn.create_storage_pool_xml(storage_pool_xml)
268
306
  pool.build unless pool.active?
269
- #XXX use? pool.build(Libvirt::StoragePool::BUILD_NO_OVERWRITE)
270
- @logger.info("Creating storage pool #{args[:pool_name]} in #{args[:pool_path]}")
307
+ pool.refresh
308
+ pool
309
+ rescue
310
+ # check conflict and shutdown old pool
311
+ defined_pool_list = @conn.list_storage_pools
312
+ defined_pool_list.each do |defined_pool_name|
313
+ defined_pool = @conn.lookup_storage_pool_by_name(defined_pool_name)
314
+ defined_pool_doc = REXML::Document.new defined_pool.xml_desc
315
+ defined_pool_path = File.expand_path(defined_pool_doc.elements["/pool/target/path"].text)
316
+ @logger.debug("check whether conflict with #{defined_pool_name} on #{defined_pool_path}")
317
+ if defined_pool_path == File.expand_path(pool_path)
318
+ defined_pool.destroy
319
+ pool = @conn.create_storage_pool_xml(storage_pool_xml)
320
+ pool.build unless pool.active?
321
+ pool.refresh
322
+ return pool
323
+ end
324
+ end
325
+ raise Errors::KvmFailStoragePool
271
326
  end
272
- pool.create unless pool.active?
273
- pool.refresh
274
- pool
275
327
  end
276
328
 
277
329
  def check_migrate_box_storage_pool
@@ -286,7 +338,7 @@ module VagrantPlugins
286
338
  @pool_migrate = true
287
339
  end
288
340
  rescue Libvirt::RetrieveError
289
- @logger.info("fail to retrieve storage pool")
341
+ raise Errors::KvmFailStoragePool
290
342
  end
291
343
  end
292
344
  end
@@ -302,11 +354,45 @@ module VagrantPlugins
302
354
  end
303
355
  end
304
356
 
357
+ def storage_pool_path
358
+ doc = REXML::Document.new @pool.xml_desc
359
+ doc.elements["/pool/target/path"].text
360
+ end
361
+
305
362
  def lookup_volume_path_by_name(volume_name)
306
363
  volume = @pool.lookup_volume_by_name(volume_name)
307
364
  volume.path
308
365
  end
309
366
 
367
+ def list_all_network_ips
368
+ interfaces = read_network_interfaces
369
+ ips = []
370
+ interfaces.each do |interface|
371
+ next if interface.type == :user
372
+ ips << list_network_ips(interface.name)
373
+ end
374
+ ips
375
+ end
376
+
377
+ def list_default_network_ips
378
+ list_network_ips('vagrant')
379
+ end
380
+
381
+ def list_network_ips(network_name)
382
+ begin
383
+ network = @conn.lookup_network_by_name(network_name)
384
+ network_definition = Util::NetworkDefinition.new(network_name, network.xml_desc)
385
+ ips = []
386
+ if network_definition
387
+ ips = network_definition.hosts.map {|host| host[:ip]}
388
+ end
389
+ ips
390
+ rescue Libvirt::RetrieveError
391
+ @logger.info("error when getting network xml")
392
+ []
393
+ end
394
+ end
395
+
310
396
  # Returns a list of network interfaces of the VM.
311
397
  #
312
398
  # @return [Hash]
@@ -333,6 +419,22 @@ module VagrantPlugins
333
419
  end
334
420
  end
335
421
 
422
+ # Returns a hostname of the guest
423
+ # introduced from ruby-libvirt 0.5.0
424
+ #
425
+ # @return [String]
426
+ def hostname?
427
+ domain = @conn.lookup_domain_by_uuid(@uuid)
428
+ domain.hostname
429
+ end
430
+
431
+ # reset the guest
432
+ # introduced from ruby-libvirt 0.5.0
433
+ def reset
434
+ domain = @conn.lookup_domain_by_uuid(@uuid)
435
+ domain.reset
436
+ end
437
+
336
438
  def read_state
337
439
  domain = @conn.lookup_domain_by_uuid(@uuid)
338
440
  state, reason = domain.state
@@ -369,6 +471,7 @@ module VagrantPlugins
369
471
 
370
472
  def set_mac_address(mac)
371
473
  update_domain_xml(:mac => mac)
474
+ @logger.debug("set mac: #{mac}")
372
475
  end
373
476
 
374
477
  def set_gui(vnc_port, vnc_autoport, vnc_password)
@@ -384,6 +487,14 @@ module VagrantPlugins
384
487
  update_domain_xml(:disk_bus => disk_bus)
385
488
  end
386
489
 
490
+ def share_folders(folders)
491
+ update_domain_xml(:p9 => folders)
492
+ end
493
+
494
+ def clear_shared_folders
495
+ #stub
496
+ end
497
+
387
498
  def update_domain_xml(options)
388
499
  domain = @conn.lookup_domain_by_uuid(@uuid)
389
500
  # Use DOMAIN_XML_SECURE to dump ALL options (including VNC password)
@@ -396,6 +507,18 @@ module VagrantPlugins
396
507
  @conn.define_domain_xml(xml)
397
508
  end
398
509
 
510
+ def add_nic(nic)
511
+ domain = @conn.lookup_domain_by_uuid(@uuid)
512
+ # Use DOMAIN_XML_SECURE to dump ALL options (including VNC password)
513
+ original_xml = domain.xml_desc(Libvirt::Domain::DOMAIN_XML_SECURE)
514
+ definition = Util::VmDefinition.new(original_xml)
515
+ definition.add_nic(nic)
516
+ domain.undefine
517
+ xml = definition.as_xml
518
+ @logger.debug("add nic\nFrom #{original_xml} \nTo: #{xml}")
519
+ @conn.define_domain_xml(xml)
520
+ end
521
+
399
522
  # Starts the virtual machine.
400
523
  def start
401
524
  domain = @conn.lookup_domain_by_uuid(@uuid)
@@ -409,6 +532,20 @@ module VagrantPlugins
409
532
  domain.managed_save
410
533
  end
411
534
 
535
+ # Suspend for duration
536
+ # introduced from ruby-libvirt 0.5.0
537
+ def suspend_for_duration(target, duration)
538
+ domain = @conn.lookup_domain_by_uuid(@uuid)
539
+ domain.pmsuspend_for_duration(target, duration)
540
+ end
541
+
542
+ # Wakeup the virtual machine
543
+ # introduced from ruby-libvirt 0.5.0
544
+ def wakeup
545
+ domain = @conn.lookup_domain_by_uuid(@uuid)
546
+ domain.pmwakeup
547
+ end
548
+
412
549
  def can_save?
413
550
  domain = @conn.lookup_domain_by_uuid(@uuid)
414
551
  definition = Util::VmDefinition.new(domain.xml_desc)
@@ -446,7 +583,36 @@ module VagrantPlugins
446
583
  end
447
584
  end
448
585
 
449
- # Verifies that the driver is ready and the connection is open
586
+ # Executes a command and returns the raw result object.
587
+ def raw(*command, &block)
588
+ int_callback = lambda do
589
+ @interrupted = true
590
+ @logger.info("Interrupted.")
591
+ end
592
+
593
+ # Append in the options for subprocess
594
+ command << { :notify => [:stdout, :stderr] }
595
+
596
+ Vagrant::Util::Busy.busy(int_callback) do
597
+ Vagrant::Util::Subprocess.execute(@virsh_path, *command, &block)
598
+ end
599
+ end
600
+
601
+ def execute_command(command)
602
+ raw(*command)
603
+ end
604
+
605
+ # Verifies that the connection is alive
606
+ # introduced from ruby-libvirt 0.5.0
607
+ #
608
+ # This will raise a VagrantError if things are not ready.
609
+ def alive!
610
+ unless @conn.alive?
611
+ raise Vagrant::Errors::KvmNoConnection
612
+ end
613
+ end
614
+
615
+ # Verifies that the driver is ready and the connection is open
450
616
  #
451
617
  # This will raise a VagrantError if things are not ready.
452
618
  def verify!
@@ -470,41 +636,41 @@ module VagrantPlugins
470
636
  # Checks which Linux OS variants
471
637
  #
472
638
  # host_redhat?
639
+ # host_ubuntu?
473
640
  # host_debian?
474
641
  # host_gentoo?
475
642
  # host_arch?
476
643
  # @return [Boolean]
477
644
  def host_redhat?
478
- release_file = Pathname.new("/etc/redhat-release")
479
-
480
- if release_file.exist?
481
- release_file.open("r:ISO-8859-1:UTF-8") do |f|
482
- contents = f.gets
483
- return true if contents =~ /^CentOS/ # CentOS
484
- return true if contents =~ /^Fedora/ # Fedora
485
- return true if contents =~ /^Korora/ # Korora
645
+ # Check also Korora, CentOS, Fedora,
646
+ # Oracle Linux < 5.3 and
647
+ # Red Hat Enterprise Linux and Oracle Linux >= 5.3
648
+ return true if check_os_release?("/etc/redhat-release",
649
+ ["CentOS","Fedora","Korora","Enterprise Linux Enterprise Linux","Red Hat Enterprise Linux"])
650
+ false
651
+ end
486
652
 
487
- # Oracle Linux < 5.3
488
- return true if contents =~ /^Enterprise Linux Enterprise Linux/
653
+ def host_suse?
654
+ check_os_release?("/etc/SuSE-release")
655
+ end
489
656
 
490
- # Red Hat Enterprise Linux and Oracle Linux >= 5.3
491
- return true if contents =~ /^Red Hat Enterprise Linux/
492
- end
657
+ def host_ubuntu?
658
+ if rel = check_lsb_release?
659
+ return true if rel == "Ubuntu"
493
660
  end
494
-
495
661
  false
496
662
  end
497
663
 
498
664
  def host_debian?
499
- File.exists?("/etc/debian_version")
665
+ check_os_release?("/etc/debian_version")
500
666
  end
501
667
 
502
668
  def host_gentoo?
503
- File.exists?("/etc/gentoo-release")
669
+ check_os_release?("/etc/gentoo-release")
504
670
  end
505
671
 
506
672
  def host_arch?
507
- File.exist?("/etc/arch-release")
673
+ check_os_release?("/etc/arch-release")
508
674
  end
509
675
 
510
676
  private
@@ -520,6 +686,30 @@ module VagrantPlugins
520
686
  "#{maj}.#{min}.#{rel}"
521
687
  end
522
688
 
689
+ # Check contents of release file
690
+ #
691
+ # filename: release file path
692
+ # criteria: ["CentOS","Fedora",...]
693
+ def check_os_release?(filename, criteria=nil)
694
+ return File.exists?(filename) unless criteria
695
+
696
+ release_file = Pathname.new(filename)
697
+ if release_file.exist?
698
+ release_file.open("r:ISO-8859-1:UTF-8") do |f|
699
+ contents = f.gets
700
+ criteria.each do |c|
701
+ return true if contents =~ /^#{c}/
702
+ end
703
+ end
704
+ end
705
+ false
706
+ end
707
+
708
+ def check_lsb_release?
709
+ return false unless File.exists?("/usr/bin/lsb_release")
710
+ IO.popen('/usr/bin/lsb_release -i') { |o| o.read.chomp.split("\t") }[1]
711
+ end
712
+
523
713
  def load_kvm_module!
524
714
  @logger.info("Check KVM kernel modules")
525
715
  kvm = File.readlines('/proc/modules').any? { |line| line =~ /kvm_(intel|amd)/ }
@@ -542,6 +732,7 @@ module VagrantPlugins
542
732
  # Open a connection to the qemu driver
543
733
  begin
544
734
  @conn = Libvirt::open('qemu:///system')
735
+ @conn.capabilities
545
736
  rescue Libvirt::Error => e
546
737
  if e.libvirt_code == 5
547
738
  # can't connect to hypervisor
@@ -551,24 +742,19 @@ module VagrantPlugins
551
742
  end
552
743
  end
553
744
 
554
- @version = read_version
745
+ hv_type = @conn.type.to_s
746
+ unless hv_type == "QEMU"
747
+ raise Errors::KvmUnsupportedHypervisor,
748
+ :actual => hv_type, :required => "QEMU"
749
+ end
750
+
751
+ version = read_version
555
752
  if @conn.version.to_i < 1001000
556
753
  raise Errors::KvmInvalidVersion,
557
- :actual => @version, :required => ">= 1.1.0"
754
+ :actual => version, :required => ">= 1.1.0"
558
755
  end
559
756
  end
560
757
 
561
- def init_storage_pool!
562
- # Get storage pool if it exists
563
- begin
564
- @pool = @conn.lookup_storage_pool_by_name(@pool_name)
565
- # this is happen when user has already used vagrant-kvm 0.1.5 and after
566
- # check neccesity of migration
567
- check_migrate_box_storage_pool
568
- rescue Libvirt::RetrieveError
569
- # storage pool doesn't exist yet
570
- end
571
- end
572
758
  end
573
759
  end
574
760
  end