vagrant-libvirt 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +51 -2079
- data/lib/vagrant-libvirt/action/create_domain.rb +39 -4
- data/lib/vagrant-libvirt/action/create_network_interfaces.rb +1 -1
- data/lib/vagrant-libvirt/action/create_networks.rb +3 -3
- data/lib/vagrant-libvirt/action/destroy_domain.rb +1 -1
- data/lib/vagrant-libvirt/action/destroy_networks.rb +1 -1
- data/lib/vagrant-libvirt/action/handle_box_image.rb +1 -1
- data/lib/vagrant-libvirt/action/package_domain.rb +1 -5
- data/lib/vagrant-libvirt/action/remove_libvirt_image.rb +3 -1
- data/lib/vagrant-libvirt/action/resolve_disk_settings.rb +15 -8
- data/lib/vagrant-libvirt/action/snapshot_delete.rb +26 -0
- data/lib/vagrant-libvirt/action/snapshot_restore.rb +22 -0
- data/lib/vagrant-libvirt/action/snapshot_save.rb +27 -0
- data/lib/vagrant-libvirt/action/start_domain.rb +43 -14
- data/lib/vagrant-libvirt/action.rb +49 -1
- data/lib/vagrant-libvirt/cap/snapshots.rb +12 -0
- data/lib/vagrant-libvirt/cap/synced_folder_9p.rb +4 -4
- data/lib/vagrant-libvirt/cap/synced_folder_virtiofs.rb +4 -4
- data/lib/vagrant-libvirt/config.rb +101 -6
- data/lib/vagrant-libvirt/driver.rb +108 -46
- data/lib/vagrant-libvirt/errors.rb +23 -3
- data/lib/vagrant-libvirt/plugin.rb +7 -3
- data/lib/vagrant-libvirt/provider.rb +1 -1
- data/lib/vagrant-libvirt/templates/domain.xml.erb +30 -4
- data/lib/vagrant-libvirt/util/byte_number.rb +0 -1
- data/lib/vagrant-libvirt/util/compat.rb +23 -0
- data/lib/vagrant-libvirt/util/unindent.rb +7 -0
- data/lib/vagrant-libvirt/version +1 -1
- data/locales/en.yml +24 -2
- data/spec/acceptance/additional_storage_spec.rb +32 -0
- data/spec/acceptance/package_domain_spec.rb +90 -0
- data/spec/acceptance/provider_settings_spec.rb +54 -0
- data/spec/acceptance/simple_vm_provision_via_shell_spec.rb +31 -0
- data/spec/acceptance/snapshots_spec.rb +41 -0
- data/spec/acceptance/support-skeletons/package_complex/Vagrantfile.testbox +14 -0
- data/spec/acceptance/support-skeletons/package_complex/scripts/sysprep.sh +32 -0
- data/spec/acceptance/support-skeletons/package_simple/Vagrantfile.testbox +10 -0
- data/spec/acceptance/two_disks_spec.rb +29 -0
- data/spec/acceptance/use_qemu_agent_for_connectivity_spec.rb +35 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/acceptance/configuration.rb +21 -0
- data/spec/support/acceptance/context.rb +70 -0
- data/spec/support/acceptance/isolated_environment.rb +41 -0
- data/spec/support/libvirt_acceptance_context.rb +64 -0
- data/spec/support/sharedcontext.rb +1 -0
- data/spec/unit/action/create_domain_spec/sysinfo.xml +66 -0
- data/spec/unit/action/create_domain_spec/sysinfo_only_required.xml +49 -0
- data/spec/unit/action/create_domain_spec.rb +82 -0
- data/spec/unit/action/forward_ports_spec.rb +0 -1
- data/spec/unit/action/handle_box_image_spec.rb +18 -1
- data/spec/unit/action/remove_libvirt_image_spec.rb +43 -0
- data/spec/unit/action/resolve_disk_settings_spec.rb +24 -0
- data/spec/unit/action/start_domain_spec/clock_timer_removed.xml +38 -0
- data/spec/unit/action/start_domain_spec/clock_timer_rtc_tsc.xml +39 -0
- data/spec/unit/action/start_domain_spec/nvram_domain_other_setting.xml +2 -2
- data/spec/unit/action/start_domain_spec.rb +72 -30
- data/spec/unit/action_spec.rb +88 -0
- data/spec/unit/cap/synced_folder_9p_spec.rb +120 -0
- data/spec/unit/cap/synced_folder_virtiofs_spec.rb +120 -0
- data/spec/unit/config_spec.rb +133 -6
- data/spec/unit/driver_spec.rb +1 -1
- data/spec/unit/plugin_spec.rb +42 -0
- data/spec/unit/templates/domain_all_settings.xml +13 -4
- data/spec/unit/templates/domain_scsi_bus_storage.xml +44 -0
- data/spec/unit/templates/domain_scsi_device_storage.xml +44 -0
- data/spec/unit/templates/domain_scsi_multiple_controllers_storage.xml +130 -0
- data/spec/unit/templates/domain_spec.rb +105 -21
- data/spec/unit/util/byte_number_spec.rb +1 -1
- metadata +155 -87
- data/spec/unit/provider_spec.rb +0 -11
@@ -11,7 +11,7 @@ module VagrantPlugins
|
|
11
11
|
module ProviderLibvirt
|
12
12
|
class Config < Vagrant.plugin('2', :config)
|
13
13
|
# manually specify URI
|
14
|
-
# will
|
14
|
+
# will supersede most other options if provided
|
15
15
|
attr_accessor :uri
|
16
16
|
|
17
17
|
# A hypervisor name to access via Libvirt.
|
@@ -99,6 +99,7 @@ module VagrantPlugins
|
|
99
99
|
attr_accessor :machine_virtual_size
|
100
100
|
attr_accessor :disk_bus
|
101
101
|
attr_accessor :disk_device
|
102
|
+
attr_accessor :disk_controller_model
|
102
103
|
attr_accessor :disk_driver_opts
|
103
104
|
attr_accessor :nic_model_type
|
104
105
|
attr_accessor :nested
|
@@ -128,6 +129,9 @@ module VagrantPlugins
|
|
128
129
|
attr_accessor :tpm_path
|
129
130
|
attr_accessor :tpm_version
|
130
131
|
|
132
|
+
# Configure sysinfo values
|
133
|
+
attr_accessor :sysinfo
|
134
|
+
|
131
135
|
# Configure the memballoon
|
132
136
|
attr_accessor :memballoon_enabled
|
133
137
|
attr_accessor :memballoon_model
|
@@ -195,6 +199,9 @@ module VagrantPlugins
|
|
195
199
|
# serial consoles
|
196
200
|
attr_accessor :serials
|
197
201
|
|
202
|
+
# internal helper attributes
|
203
|
+
attr_accessor :host_device_exclude_prefixes
|
204
|
+
|
198
205
|
def initialize
|
199
206
|
@uri = UNSET_VALUE
|
200
207
|
@driver = UNSET_VALUE
|
@@ -253,6 +260,7 @@ module VagrantPlugins
|
|
253
260
|
@machine_virtual_size = UNSET_VALUE
|
254
261
|
@disk_bus = UNSET_VALUE
|
255
262
|
@disk_device = UNSET_VALUE
|
263
|
+
@disk_controller_model = UNSET_VALUE
|
256
264
|
@disk_driver_opts = {}
|
257
265
|
@nic_model_type = UNSET_VALUE
|
258
266
|
@nested = UNSET_VALUE
|
@@ -280,6 +288,8 @@ module VagrantPlugins
|
|
280
288
|
@tpm_path = UNSET_VALUE
|
281
289
|
@tpm_version = UNSET_VALUE
|
282
290
|
|
291
|
+
@sysinfo = UNSET_VALUE
|
292
|
+
|
283
293
|
@memballoon_enabled = UNSET_VALUE
|
284
294
|
@memballoon_model = UNSET_VALUE
|
285
295
|
@memballoon_pci_bus = UNSET_VALUE
|
@@ -342,6 +352,9 @@ module VagrantPlugins
|
|
342
352
|
@qemu_use_agent = UNSET_VALUE
|
343
353
|
|
344
354
|
@serials = UNSET_VALUE
|
355
|
+
|
356
|
+
# internal options to help override behaviour
|
357
|
+
@host_device_exclude_prefixes = UNSET_VALUE
|
345
358
|
end
|
346
359
|
|
347
360
|
def boot(device)
|
@@ -865,8 +878,15 @@ module VagrantPlugins
|
|
865
878
|
@machine_type = nil if @machine_type == UNSET_VALUE
|
866
879
|
@machine_arch = nil if @machine_arch == UNSET_VALUE
|
867
880
|
@machine_virtual_size = nil if @machine_virtual_size == UNSET_VALUE
|
868
|
-
@
|
869
|
-
@
|
881
|
+
@disk_device = @disk_bus == 'scsi' ? 'sda' : 'vda' if @disk_device == UNSET_VALUE
|
882
|
+
@disk_bus = @disk_device.start_with?('sd') ? 'scsi' : 'virtio' if @disk_bus == UNSET_VALUE
|
883
|
+
if @disk_controller_model == UNSET_VALUE
|
884
|
+
if @disk_bus == 'scsi' or @disk_device.start_with?('sd') == 'sd'
|
885
|
+
@disk_controller_model = 'virtio-scsi'
|
886
|
+
else
|
887
|
+
@disk_controller_model = nil
|
888
|
+
end
|
889
|
+
end
|
870
890
|
@disk_driver_opts = {} if @disk_driver_opts == UNSET_VALUE
|
871
891
|
@nic_model_type = nil if @nic_model_type == UNSET_VALUE
|
872
892
|
@nested = false if @nested == UNSET_VALUE
|
@@ -902,6 +922,8 @@ module VagrantPlugins
|
|
902
922
|
@nic_adapter_count = 8 if @nic_adapter_count == UNSET_VALUE
|
903
923
|
@emulator_path = nil if @emulator_path == UNSET_VALUE
|
904
924
|
|
925
|
+
@sysinfo = {} if @sysinfo == UNSET_VALUE
|
926
|
+
|
905
927
|
# Boot order
|
906
928
|
@boot_order = [] if @boot_order == UNSET_VALUE
|
907
929
|
|
@@ -972,6 +994,8 @@ module VagrantPlugins
|
|
972
994
|
@qemu_use_agent = false if @qemu_use_agent == UNSET_VALUE
|
973
995
|
|
974
996
|
@serials = [{:type => 'pty', :source => nil}] if @serials == UNSET_VALUE
|
997
|
+
|
998
|
+
@host_device_exclude_prefixes = ['docker', 'macvtap', 'virbr', 'vnet'] if @host_device_exclude_prefixes == UNSET_VALUE
|
975
999
|
end
|
976
1000
|
|
977
1001
|
def validate(machine)
|
@@ -999,7 +1023,7 @@ module VagrantPlugins
|
|
999
1023
|
end
|
1000
1024
|
|
1001
1025
|
if @qemu_use_agent == true
|
1002
|
-
# if qemu agent is used to
|
1026
|
+
# if qemu agent is used to obtain domain ip configuration, at least
|
1003
1027
|
# one qemu channel has to be configured. As there are various options,
|
1004
1028
|
# error out and leave configuration to the user
|
1005
1029
|
unless machine.provider_config.channels.any? { |channel| channel[:target_name].start_with?("org.qemu.guest_agent") }
|
@@ -1029,7 +1053,9 @@ module VagrantPlugins
|
|
1029
1053
|
errors << "#{e}"
|
1030
1054
|
end
|
1031
1055
|
|
1032
|
-
machine.config.vm.networks.
|
1056
|
+
machine.config.vm.networks.each_with_index do |network, index|
|
1057
|
+
type, opts = network
|
1058
|
+
|
1033
1059
|
if opts[:mac]
|
1034
1060
|
if opts[:mac] =~ /\A([0-9a-fA-F]{12})\z/
|
1035
1061
|
opts[:mac] = opts[:mac].scan(/../).join(':')
|
@@ -1038,6 +1064,13 @@ module VagrantPlugins
|
|
1038
1064
|
errors << "Configured NIC MAC '#{opts[:mac]}' is not in 'xx:xx:xx:xx:xx:xx' or 'xxxxxxxxxxxx' format"
|
1039
1065
|
end
|
1040
1066
|
end
|
1067
|
+
|
1068
|
+
# only interested in public networks where portgroup is nil, as then source will be a host device
|
1069
|
+
if type == :public_network && opts[:portgroup] == nil
|
1070
|
+
if !host_devices.include?(opts[:dev])
|
1071
|
+
errors << "network configuration #{index} for machine #{machine.name} is a public_network referencing host device '#{opts[:dev]}' which does not exist, consider adding ':dev => ....' referencing one of #{host_devices.join(", ")}"
|
1072
|
+
end
|
1073
|
+
end
|
1041
1074
|
end
|
1042
1075
|
|
1043
1076
|
if !machine.provider_config.volume_cache.nil? and machine.provider_config.volume_cache != UNSET_VALUE
|
@@ -1048,6 +1081,8 @@ module VagrantPlugins
|
|
1048
1081
|
end
|
1049
1082
|
end
|
1050
1083
|
|
1084
|
+
errors = validate_sysinfo(machine, errors)
|
1085
|
+
|
1051
1086
|
{ 'Libvirt Provider' => errors }
|
1052
1087
|
end
|
1053
1088
|
|
@@ -1062,7 +1097,11 @@ module VagrantPlugins
|
|
1062
1097
|
result.cdroms = c
|
1063
1098
|
|
1064
1099
|
result.disk_driver_opts = disk_driver_opts.merge(other.disk_driver_opts)
|
1065
|
-
|
1100
|
+
|
1101
|
+
c = sysinfo == UNSET_VALUE ? {} : sysinfo.dup
|
1102
|
+
c.merge!(other.sysinfo) { |_k, x, y| x.respond_to?(:each_pair) ? x.merge(y) : x + y } if other.sysinfo != UNSET_VALUE
|
1103
|
+
result.sysinfo = c
|
1104
|
+
|
1066
1105
|
c = clock_timers.dup
|
1067
1106
|
c += other.clock_timers
|
1068
1107
|
result.clock_timers = c
|
@@ -1170,6 +1209,62 @@ module VagrantPlugins
|
|
1170
1209
|
@proxy_command = nil
|
1171
1210
|
end
|
1172
1211
|
end
|
1212
|
+
|
1213
|
+
def host_devices
|
1214
|
+
@host_devices ||= begin
|
1215
|
+
require 'socket'
|
1216
|
+
|
1217
|
+
Socket.getifaddrs.map { |iface| iface.name }.uniq.select do |dev|
|
1218
|
+
dev != "lo" && !@host_device_exclude_prefixes.any? { |exclude| dev.start_with?(exclude) }
|
1219
|
+
end
|
1220
|
+
end
|
1221
|
+
end
|
1222
|
+
|
1223
|
+
def validate_sysinfo(machine, errors)
|
1224
|
+
valid_sysinfo = {
|
1225
|
+
'bios' => %w[vendor version date release],
|
1226
|
+
'system' => %w[manufacturer product version serial uuid sku family],
|
1227
|
+
'base board' => %w[manufacturer product version serial asset location],
|
1228
|
+
'chassis' => %w[manufacturer version serial asset sku],
|
1229
|
+
'oem strings' => nil,
|
1230
|
+
}
|
1231
|
+
|
1232
|
+
machine.provider_config.sysinfo.each_pair do |block_name, entries|
|
1233
|
+
block_name = block_name.to_s
|
1234
|
+
unless valid_sysinfo.key?(block_name)
|
1235
|
+
errors << "invalid sysinfo element '#{block_name}'; smbios sysinfo elements supported: #{valid_sysinfo.keys.join(', ')}"
|
1236
|
+
next
|
1237
|
+
end
|
1238
|
+
|
1239
|
+
if valid_sysinfo[block_name].nil?
|
1240
|
+
# assume simple array of text entries
|
1241
|
+
entries.each do |entry|
|
1242
|
+
if entry.respond_to?(:to_str)
|
1243
|
+
if entry.to_s.empty?
|
1244
|
+
machine.ui.warn("Libvirt Provider: 'sysinfo.#{block_name}' contains an empty or nil entry and will be discarded")
|
1245
|
+
end
|
1246
|
+
else
|
1247
|
+
errors << "sysinfo.#{block_name} expects entries to be stringy, got #{entry.class} containing '#{entry}'"
|
1248
|
+
end
|
1249
|
+
end
|
1250
|
+
else
|
1251
|
+
entries.each_pair do |entry_name, entry_text|
|
1252
|
+
entry_name = entry_name.to_s
|
1253
|
+
unless valid_sysinfo[block_name].include?(entry_name)
|
1254
|
+
errors << "'sysinfo.#{block_name}' does not support entry name '#{entry_name}'; entries supported: #{valid_sysinfo[block_name].join(', ')}"
|
1255
|
+
next
|
1256
|
+
end
|
1257
|
+
|
1258
|
+
# this allows removal of entries specified by other Vagrantfile's in the hierarchy
|
1259
|
+
if entry_text.to_s.empty?
|
1260
|
+
machine.ui.warn("Libvirt Provider: sysinfo.#{block_name}.#{entry_name} is nil or empty and therefore has no effect.")
|
1261
|
+
end
|
1262
|
+
end
|
1263
|
+
end
|
1264
|
+
end
|
1265
|
+
|
1266
|
+
errors
|
1267
|
+
end
|
1173
1268
|
end
|
1174
1269
|
end
|
1175
1270
|
end
|
@@ -32,16 +32,17 @@ module VagrantPlugins
|
|
32
32
|
config = @machine.provider_config
|
33
33
|
uri = config.uri
|
34
34
|
|
35
|
-
conn_attr = {}
|
36
|
-
conn_attr[:provider] = 'libvirt'
|
37
|
-
conn_attr[:libvirt_uri] = uri
|
38
|
-
conn_attr[:libvirt_username] = config.username if config.username
|
39
|
-
conn_attr[:libvirt_password] = config.password if config.password
|
40
|
-
|
41
35
|
# Setup command for retrieving IP address for newly created machine
|
42
36
|
# with some MAC address. Get it from dnsmasq leases table
|
43
37
|
ip_command = %q( awk "/$mac/ {print \$1}" /proc/net/arp )
|
44
|
-
|
38
|
+
|
39
|
+
conn_attr = {
|
40
|
+
provider: 'libvirt',
|
41
|
+
libvirt_uri: uri,
|
42
|
+
libvirt_ip_command: ip_command,
|
43
|
+
}
|
44
|
+
conn_attr[:libvirt_username] = config.username if config.username
|
45
|
+
conn_attr[:libvirt_password] = config.password if config.password
|
45
46
|
|
46
47
|
@logger.info("Connecting to Libvirt (#{uri}) ...")
|
47
48
|
begin
|
@@ -61,7 +62,7 @@ module VagrantPlugins
|
|
61
62
|
|
62
63
|
config = @machine.provider_config
|
63
64
|
|
64
|
-
@system_connection = Libvirt
|
65
|
+
@system_connection = Libvirt.open_read_only(config.system_uri)
|
65
66
|
@system_connection
|
66
67
|
end
|
67
68
|
|
@@ -69,12 +70,10 @@ module VagrantPlugins
|
|
69
70
|
begin
|
70
71
|
domain = connection.servers.get(machine.id)
|
71
72
|
rescue Libvirt::RetrieveError => e
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
raise e
|
77
|
-
end
|
73
|
+
raise e unless e.libvirt_code == ProviderLibvirt::Util::ErrorCodes::VIR_ERR_NO_DOMAIN
|
74
|
+
|
75
|
+
@logger.debug("machine #{machine.name} domain not found #{e}.")
|
76
|
+
return nil
|
78
77
|
end
|
79
78
|
|
80
79
|
domain
|
@@ -99,32 +98,82 @@ module VagrantPlugins
|
|
99
98
|
|
100
99
|
def get_domain_ipaddress(machine, domain)
|
101
100
|
# attempt to get ip address from qemu agent
|
102
|
-
if
|
101
|
+
if machine.provider_config.qemu_use_agent == true
|
103
102
|
@logger.info('Get IP via qemu agent')
|
104
|
-
return get_ipaddress_from_qemu_agent(domain, machine.id)
|
103
|
+
return get_ipaddress_from_qemu_agent(domain, machine.id, machine.config.vm.boot_timeout)
|
105
104
|
end
|
106
105
|
|
107
|
-
if
|
108
|
-
return get_ipaddress_from_system domain.mac
|
109
|
-
end
|
106
|
+
return get_ipaddress_from_system domain.mac if machine.provider_config.qemu_use_session
|
110
107
|
|
111
108
|
# Get IP address from dhcp leases table
|
112
109
|
begin
|
113
110
|
ip_address = get_ipaddress_from_domain(domain)
|
114
111
|
rescue Fog::Errors::TimeoutError
|
115
|
-
@logger.info(
|
112
|
+
@logger.info("Timeout at waiting for an ip address for machine #{machine.name}")
|
116
113
|
|
117
114
|
raise
|
118
115
|
end
|
119
116
|
|
120
117
|
unless ip_address
|
121
|
-
@logger.info(
|
118
|
+
@logger.info("No arp table entry found for machine #{machine.name}")
|
122
119
|
return nil
|
123
120
|
end
|
124
121
|
|
125
122
|
ip_address
|
126
123
|
end
|
127
124
|
|
125
|
+
def restore_snapshot(machine, snapshot_name)
|
126
|
+
domain = get_libvirt_domain(machine)
|
127
|
+
snapshot = get_snapshot_if_exists(machine, snapshot_name)
|
128
|
+
begin
|
129
|
+
# 4 is VIR_DOMAIN_SNAPSHOT_REVERT_FORCE
|
130
|
+
# needed due to https://bugzilla.redhat.com/show_bug.cgi?id=1006886
|
131
|
+
domain.revert_to_snapshot(snapshot, 4)
|
132
|
+
rescue Fog::Errors::Error => e
|
133
|
+
raise Errors::SnapshotReversionError, error_message: e.message
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def list_snapshots(machine)
|
138
|
+
get_libvirt_domain(machine).list_snapshots
|
139
|
+
rescue Fog::Errors::Error => e
|
140
|
+
raise Errors::SnapshotListError, error_message: e.message
|
141
|
+
end
|
142
|
+
|
143
|
+
def delete_snapshot(machine, snapshot_name)
|
144
|
+
get_snapshot_if_exists(machine, snapshot_name).delete
|
145
|
+
rescue Errors::SnapshotMissing => e
|
146
|
+
raise Errors::SnapshotDeletionError, error_message: e.message
|
147
|
+
end
|
148
|
+
|
149
|
+
def create_new_snapshot(machine, snapshot_name)
|
150
|
+
snapshot_desc = <<-EOF
|
151
|
+
<domainsnapshot>
|
152
|
+
<name>#{snapshot_name}</name>
|
153
|
+
<description>Snapshot for vagrant sandbox</description>
|
154
|
+
</domainsnapshot>
|
155
|
+
EOF
|
156
|
+
get_libvirt_domain(machine).snapshot_create_xml(snapshot_desc)
|
157
|
+
rescue Fog::Errors::Error => e
|
158
|
+
raise Errors::SnapshotCreationError, error_message: e.message
|
159
|
+
end
|
160
|
+
|
161
|
+
def create_snapshot(machine, snapshot_name)
|
162
|
+
begin
|
163
|
+
delete_snapshot(machine, snapshot_name)
|
164
|
+
rescue Errors::SnapshotDeletionError
|
165
|
+
end
|
166
|
+
create_new_snapshot(machine, snapshot_name)
|
167
|
+
end
|
168
|
+
|
169
|
+
# if we can get snapshot description without exception it exists
|
170
|
+
def get_snapshot_if_exists(machine, snapshot_name)
|
171
|
+
snapshot = get_libvirt_domain(machine).lookup_snapshot_by_name(snapshot_name)
|
172
|
+
return snapshot if snapshot.xml_desc
|
173
|
+
rescue Libvirt::RetrieveError => e
|
174
|
+
raise Errors::SnapshotMissing, error_message: e.message
|
175
|
+
end
|
176
|
+
|
128
177
|
def state(machine)
|
129
178
|
# may be other error states with initial retreival we can't handle
|
130
179
|
begin
|
@@ -149,7 +198,7 @@ module VagrantPlugins
|
|
149
198
|
end
|
150
199
|
end
|
151
200
|
|
152
|
-
|
201
|
+
state
|
153
202
|
end
|
154
203
|
|
155
204
|
private
|
@@ -160,43 +209,44 @@ module VagrantPlugins
|
|
160
209
|
system_connection.list_all_networks.each do |net|
|
161
210
|
leases = net.dhcp_leases(mac, 0)
|
162
211
|
# Assume the lease expiring last is the current IP address
|
163
|
-
ip_address = leases.
|
212
|
+
ip_address = leases.max_by { |lse| lse['expirytime'] }['ipaddr'] unless leases.empty?
|
164
213
|
break if ip_address
|
165
214
|
end
|
166
215
|
|
167
216
|
ip_address
|
168
217
|
end
|
169
218
|
|
170
|
-
def get_ipaddress_from_qemu_agent(domain, machine_id)
|
219
|
+
def get_ipaddress_from_qemu_agent(domain, machine_id, timeout)
|
171
220
|
ip_address = nil
|
172
221
|
addresses = nil
|
173
222
|
libvirt_domain = connection.client.lookup_domain_by_uuid(machine_id)
|
174
223
|
begin
|
175
|
-
response = libvirt_domain.qemu_agent_command('{"execute":"guest-network-get-interfaces"}', timeout
|
176
|
-
@logger.debug(
|
224
|
+
response = libvirt_domain.qemu_agent_command('{"execute":"guest-network-get-interfaces"}', timeout)
|
225
|
+
@logger.debug('Got Response from qemu agent')
|
177
226
|
@logger.debug(response)
|
178
227
|
addresses = JSON.parse(response)
|
179
|
-
rescue => e
|
180
|
-
|
228
|
+
rescue StandardError => e
|
229
|
+
puts "Unable to receive IP via qemu agent: [#{e.message}]"
|
230
|
+
@logger.debug("Unable to receive IP via qemu agent: [#{e.message}]")
|
181
231
|
end
|
182
232
|
|
183
233
|
unless addresses.nil?
|
184
|
-
addresses[
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
234
|
+
addresses['return'].each do |interface|
|
235
|
+
next unless domain.mac.downcase == interface['hardware-address'].downcase
|
236
|
+
|
237
|
+
@logger.debug("Found matching interface: [#{interface['name']}]")
|
238
|
+
next unless interface.key?('ip-addresses')
|
239
|
+
|
240
|
+
interface['ip-addresses'].each do |ip|
|
241
|
+
# returning ipv6 addresses might break windows guests because
|
242
|
+
# winrm can't handle connection, winrm fails with "invalid uri"
|
243
|
+
next unless ip['ip-address-type'] == 'ipv4'
|
244
|
+
|
245
|
+
ip_address = ip['ip-address']
|
246
|
+
@logger.debug("Return IP: [#{ip_address}]")
|
247
|
+
break
|
198
248
|
end
|
199
|
-
|
249
|
+
end
|
200
250
|
end
|
201
251
|
ip_address
|
202
252
|
end
|
@@ -204,18 +254,30 @@ module VagrantPlugins
|
|
204
254
|
def get_ipaddress_from_domain(domain)
|
205
255
|
ip_address = nil
|
206
256
|
domain.wait_for(2) do
|
207
|
-
addresses.each_pair do |
|
257
|
+
addresses.each_pair do |_type, ip|
|
208
258
|
# Multiple leases are separated with a newline, return only
|
209
259
|
# the most recent address
|
210
|
-
ip_address = ip[0].split("\n").first
|
260
|
+
ip_address = ip[0].split("\n").first unless ip[0].nil?
|
211
261
|
end
|
212
262
|
|
213
|
-
ip_address
|
263
|
+
!ip_address.nil?
|
214
264
|
end
|
215
265
|
|
216
266
|
ip_address
|
217
267
|
end
|
218
268
|
|
269
|
+
def get_libvirt_domain(machine)
|
270
|
+
begin
|
271
|
+
libvirt_domain = connection.client.lookup_domain_by_uuid(machine.id)
|
272
|
+
rescue Libvirt::RetrieveError => e
|
273
|
+
raise e unless e.libvirt_code == ProviderLibvirt::Util::ErrorCodes::VIR_ERR_NO_DOMAIN
|
274
|
+
|
275
|
+
@logger.debug("machine #{machine.name} not found #{e}.")
|
276
|
+
return nil
|
277
|
+
end
|
278
|
+
|
279
|
+
libvirt_domain
|
280
|
+
end
|
219
281
|
end
|
220
282
|
end
|
221
283
|
end
|
@@ -109,7 +109,7 @@ module VagrantPlugins
|
|
109
109
|
end
|
110
110
|
|
111
111
|
class FogCreateServerError < VagrantLibvirtError
|
112
|
-
error_key(:
|
112
|
+
error_key(:create_server_error)
|
113
113
|
end
|
114
114
|
|
115
115
|
# Network exceptions
|
@@ -154,6 +154,10 @@ module VagrantPlugins
|
|
154
154
|
end
|
155
155
|
|
156
156
|
# Other exceptions
|
157
|
+
class UpdateServerError < VagrantLibvirtError
|
158
|
+
error_key(:create_server_error)
|
159
|
+
end
|
160
|
+
|
157
161
|
class InterfaceSlotNotAvailable < VagrantLibvirtError
|
158
162
|
error_key(:interface_slot_not_available)
|
159
163
|
end
|
@@ -186,8 +190,24 @@ module VagrantPlugins
|
|
186
190
|
error_key(:no_ip_address_error)
|
187
191
|
end
|
188
192
|
|
189
|
-
class
|
190
|
-
error_key(:
|
193
|
+
class SnapshotMissing < VagrantLibvirtError
|
194
|
+
error_key(:snapshot_missing)
|
195
|
+
end
|
196
|
+
|
197
|
+
class SnapshotDeletionError < VagrantLibvirtError
|
198
|
+
error_key(:snapshot_deletion_error)
|
199
|
+
end
|
200
|
+
|
201
|
+
class SnapshotListError < VagrantLibvirtError
|
202
|
+
error_key(:snapshot_list_error)
|
203
|
+
end
|
204
|
+
|
205
|
+
class SnapshotCreationError < VagrantLibvirtError
|
206
|
+
error_key(:snapshot_creation_error)
|
207
|
+
end
|
208
|
+
|
209
|
+
class SnapshotReversionError < VagrantLibvirtError
|
210
|
+
error_key(:snapshot_reversion_error)
|
191
211
|
end
|
192
212
|
|
193
213
|
class SerialCannotCreatePathError < VagrantLibvirtError
|
@@ -6,8 +6,7 @@ rescue LoadError
|
|
6
6
|
raise 'The Vagrant Libvirt plugin must be run within Vagrant.'
|
7
7
|
end
|
8
8
|
|
9
|
-
|
10
|
-
::Vagrant::MachineState::NOT_CREATED_ID ||= :not_created
|
9
|
+
require 'vagrant-libvirt/util/compat'
|
11
10
|
|
12
11
|
module VagrantPlugins
|
13
12
|
module ProviderLibvirt
|
@@ -27,7 +26,7 @@ module VagrantPlugins
|
|
27
26
|
Provider
|
28
27
|
end
|
29
28
|
|
30
|
-
action_hook(:remove_libvirt_image) do |hook|
|
29
|
+
action_hook(*(Util::Compat.action_hook_args(:remove_libvirt_image, :box_remove))) do |hook|
|
31
30
|
require_relative 'action'
|
32
31
|
hook.after Vagrant::Action::Builtin::BoxRemove, Action.remove_libvirt_image
|
33
32
|
end
|
@@ -51,6 +50,11 @@ module VagrantPlugins
|
|
51
50
|
Cap::PublicAddress
|
52
51
|
end
|
53
52
|
|
53
|
+
provider_capability(:libvirt, :snapshot_list) do
|
54
|
+
require_relative 'cap/snapshots'
|
55
|
+
Cap::Snapshots
|
56
|
+
end
|
57
|
+
|
54
58
|
# lower priority than nfs or rsync
|
55
59
|
# https://github.com/vagrant-libvirt/vagrant-libvirt/pull/170
|
56
60
|
synced_folder('9p', 4) do
|
@@ -52,7 +52,7 @@ module VagrantPlugins
|
|
52
52
|
# :username => "mitchellh",
|
53
53
|
# :private_key_path => "/path/to/my/key"
|
54
54
|
# }
|
55
|
-
# note that
|
55
|
+
# note that modifying @machine.id or accessing @machine.state is not
|
56
56
|
# thread safe, so be careful to avoid these here as this method may
|
57
57
|
# be called from other threads of execution.
|
58
58
|
return nil if state.id != :running
|
@@ -81,8 +81,28 @@
|
|
81
81
|
<cmdline><%= @cmd_line %></cmdline>
|
82
82
|
<%- if @dtb -%>
|
83
83
|
<dtb><%= @dtb %></dtb>
|
84
|
+
<% end -%>
|
85
|
+
<%- unless @sysinfo.empty? -%>
|
86
|
+
<smbios mode='sysinfo'/>
|
84
87
|
<% end -%>
|
85
88
|
</os>
|
89
|
+
<%- unless @sysinfo.empty? -%>
|
90
|
+
<sysinfo type='smbios'>
|
91
|
+
<%- @sysinfo.each_pair do |block, values| -%>
|
92
|
+
<<%= @sysinfo_blocks[block.to_s][:xml] %>>
|
93
|
+
<%- if values.respond_to?(:each_pair) -%>
|
94
|
+
<%- values.each do |name, value| -%>
|
95
|
+
<entry name='<%= name %>'><%= value %></entry>
|
96
|
+
<% end -%>
|
97
|
+
<%- else -%>
|
98
|
+
<%- values.each do |value| -%>
|
99
|
+
<entry><%= value %></entry>
|
100
|
+
<% end -%>
|
101
|
+
<% end -%>
|
102
|
+
</<%= @sysinfo_blocks[block.to_s][:xml] %>>
|
103
|
+
<% end -%>
|
104
|
+
</sysinfo>
|
105
|
+
<% end -%>
|
86
106
|
<features>
|
87
107
|
<%- @features.each do |feature| -%>
|
88
108
|
<<%= feature %>/>
|
@@ -122,6 +142,12 @@
|
|
122
142
|
<target dev='<%= volume[:device] %>' bus='<%= volume[:bus] %>'/>
|
123
143
|
</disk>
|
124
144
|
<%- end -%>
|
145
|
+
<%- scsi_volumes = @domain_volumes.select { |x| x[:bus] == 'scsi' } %>
|
146
|
+
<%- if !scsi_volumes.empty? and !@disk_controller_model.nil? %>
|
147
|
+
<%- for idx in 0..(scsi_volumes.length / 7) do %>
|
148
|
+
<controller type='scsi' model='<%= @disk_controller_model %>' index='<%= idx -%>'/>
|
149
|
+
<%- end -%>
|
150
|
+
<%- end -%>
|
125
151
|
<%# additional disks -%>
|
126
152
|
<%- @disks.each_with_index do |d, index| -%>
|
127
153
|
<disk type='file' device='disk'>
|
@@ -220,7 +246,7 @@
|
|
220
246
|
</graphics><% end -%>
|
221
247
|
<video>
|
222
248
|
<model type='<%= @video_type %>' vram='<%= @video_vram %>' heads='1'<% if not @video_accel3d %>/><% else %>>
|
223
|
-
|
249
|
+
<acceleration accel3d='yes'/>
|
224
250
|
</model><% end -%>
|
225
251
|
</video>
|
226
252
|
<%#End Video -%>
|
@@ -250,13 +276,13 @@
|
|
250
276
|
<hostdev mode='subsystem' type='usb'>
|
251
277
|
<source startupPolicy='<%= usb[:startupPolicy] || "mandatory" %>'>
|
252
278
|
<%- if usb[:vendor] -%>
|
253
|
-
|
279
|
+
<vendor id='<%= usb[:vendor] %>'/>
|
254
280
|
<%- end -%>
|
255
281
|
<%- if usb[:product] -%>
|
256
|
-
|
282
|
+
<product id='<%= usb[:product] %>'/>
|
257
283
|
<%- end -%>
|
258
284
|
<%- if usb[:bus] && usb[:device] -%>
|
259
|
-
|
285
|
+
<address bus='<%= usb[:bus] %>' device='<%= usb[:device] %>'/>
|
260
286
|
<%- end -%>
|
261
287
|
</source>
|
262
288
|
</hostdev>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'vagrant'
|
4
|
+
|
5
|
+
# compatibility fix to define constant not available Vagrant <1.6
|
6
|
+
::Vagrant::MachineState::NOT_CREATED_ID ||= :not_created
|
7
|
+
|
8
|
+
module VagrantPlugins
|
9
|
+
module ProviderLibvirt
|
10
|
+
module Util
|
11
|
+
module Compat
|
12
|
+
def self.action_hook_args(name, action)
|
13
|
+
# handle different number of arguments for action_hook depending on vagrant version
|
14
|
+
if Gem::Version.new(Vagrant::VERSION) >= Gem::Version.new('2.2.11')
|
15
|
+
return name, action
|
16
|
+
end
|
17
|
+
|
18
|
+
return name
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/vagrant-libvirt/version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.10.0
|