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.
- checksums.yaml +4 -4
- data/.gitignore +5 -0
- data/CHANGELOG.md +0 -7
- data/DEVELOPMENT.md +69 -0
- data/INSTALL.md +1 -1
- data/README.md +61 -47
- data/bin/package.sh +83 -0
- data/install.rb +7 -0
- data/lib/vagrant-kvm/action.rb +23 -31
- data/lib/vagrant-kvm/action/customize.rb +44 -0
- data/lib/vagrant-kvm/action/import.rb +52 -23
- data/lib/vagrant-kvm/action/init_storage_pool.rb +5 -4
- data/lib/vagrant-kvm/action/network.rb +127 -30
- data/lib/vagrant-kvm/action/{prepare_gui.rb → prepare_kvmconfig.rb} +4 -1
- data/lib/vagrant-kvm/action/prepare_nfs_settings.rb +16 -23
- data/lib/vagrant-kvm/action/set_name.rb +27 -3
- data/lib/vagrant-kvm/action/share_folders.rb +4 -5
- data/lib/vagrant-kvm/cap/mount_p9.rb +40 -0
- data/lib/vagrant-kvm/config.rb +73 -1
- data/lib/vagrant-kvm/driver/driver.rb +303 -117
- data/lib/vagrant-kvm/errors.rb +4 -4
- data/lib/vagrant-kvm/plugin.rb +12 -2
- data/lib/vagrant-kvm/provider.rb +2 -19
- data/lib/vagrant-kvm/synced_folder.rb +57 -0
- data/lib/vagrant-kvm/util/network_definition.rb +30 -3
- data/lib/vagrant-kvm/util/vm_definition.rb +110 -11
- data/lib/vagrant-kvm/version.rb +1 -1
- data/locales/en.yml +5 -3
- data/locales/ja.yml +11 -4
- data/spec/vagrant-kvm/config_spec.rb +6 -0
- data/spec/vagrant-kvm/driver/driver_spec.rb +4 -3
- data/spec/vagrant-kvm/util/vm_definition_spec.rb +4 -8
- data/templates/libvirt_domain.erb +29 -3
- data/vagrant-kvm.gemspec +3 -3
- metadata +21 -9
- data/lib/vagrant-kvm/action/prune_nfs_exports.rb +0 -20
@@ -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
|
-
|
29
|
-
#next if data[:nfs]
|
28
|
+
next if data[:disabled]
|
30
29
|
|
31
|
-
unless
|
32
|
-
|
33
|
-
|
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
|
data/lib/vagrant-kvm/config.rb
CHANGED
@@ -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
|
-
@
|
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
|
-
|
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(
|
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(
|
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
|
-
:
|
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
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
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
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
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
|
-
|
214
|
-
|
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
|
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
|
-
#
|
230
|
-
pool = @conn.lookup_storage_pool_by_name(
|
231
|
-
@logger.info("
|
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
|
-
|
234
|
-
|
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>#{
|
290
|
+
<name>#{pool_name}</name>
|
237
291
|
<target>
|
238
|
-
<path>#{
|
292
|
+
<path>#{pool_path}</path>
|
239
293
|
<permissions>
|
240
|
-
<owner>#{
|
241
|
-
<group>#{
|
242
|
-
<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
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
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
|
-
|
270
|
-
|
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
|
-
|
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
|
-
#
|
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
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
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
|
-
|
488
|
-
|
653
|
+
def host_suse?
|
654
|
+
check_os_release?("/etc/SuSE-release")
|
655
|
+
end
|
489
656
|
|
490
|
-
|
491
|
-
|
492
|
-
|
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
|
-
|
665
|
+
check_os_release?("/etc/debian_version")
|
500
666
|
end
|
501
667
|
|
502
668
|
def host_gentoo?
|
503
|
-
|
669
|
+
check_os_release?("/etc/gentoo-release")
|
504
670
|
end
|
505
671
|
|
506
672
|
def host_arch?
|
507
|
-
|
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
|
-
|
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 =>
|
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
|