vagrant-kvm 0.1.7 → 0.1.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.
@@ -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