vagrant-libvirt 0.9.0 → 0.10.0

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.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +51 -2079
  3. data/lib/vagrant-libvirt/action/create_domain.rb +39 -4
  4. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +1 -1
  5. data/lib/vagrant-libvirt/action/create_networks.rb +3 -3
  6. data/lib/vagrant-libvirt/action/destroy_domain.rb +1 -1
  7. data/lib/vagrant-libvirt/action/destroy_networks.rb +1 -1
  8. data/lib/vagrant-libvirt/action/handle_box_image.rb +1 -1
  9. data/lib/vagrant-libvirt/action/package_domain.rb +1 -5
  10. data/lib/vagrant-libvirt/action/remove_libvirt_image.rb +3 -1
  11. data/lib/vagrant-libvirt/action/resolve_disk_settings.rb +15 -8
  12. data/lib/vagrant-libvirt/action/snapshot_delete.rb +26 -0
  13. data/lib/vagrant-libvirt/action/snapshot_restore.rb +22 -0
  14. data/lib/vagrant-libvirt/action/snapshot_save.rb +27 -0
  15. data/lib/vagrant-libvirt/action/start_domain.rb +43 -14
  16. data/lib/vagrant-libvirt/action.rb +49 -1
  17. data/lib/vagrant-libvirt/cap/snapshots.rb +12 -0
  18. data/lib/vagrant-libvirt/cap/synced_folder_9p.rb +4 -4
  19. data/lib/vagrant-libvirt/cap/synced_folder_virtiofs.rb +4 -4
  20. data/lib/vagrant-libvirt/config.rb +101 -6
  21. data/lib/vagrant-libvirt/driver.rb +108 -46
  22. data/lib/vagrant-libvirt/errors.rb +23 -3
  23. data/lib/vagrant-libvirt/plugin.rb +7 -3
  24. data/lib/vagrant-libvirt/provider.rb +1 -1
  25. data/lib/vagrant-libvirt/templates/domain.xml.erb +30 -4
  26. data/lib/vagrant-libvirt/util/byte_number.rb +0 -1
  27. data/lib/vagrant-libvirt/util/compat.rb +23 -0
  28. data/lib/vagrant-libvirt/util/unindent.rb +7 -0
  29. data/lib/vagrant-libvirt/version +1 -1
  30. data/locales/en.yml +24 -2
  31. data/spec/acceptance/additional_storage_spec.rb +32 -0
  32. data/spec/acceptance/package_domain_spec.rb +90 -0
  33. data/spec/acceptance/provider_settings_spec.rb +54 -0
  34. data/spec/acceptance/simple_vm_provision_via_shell_spec.rb +31 -0
  35. data/spec/acceptance/snapshots_spec.rb +41 -0
  36. data/spec/acceptance/support-skeletons/package_complex/Vagrantfile.testbox +14 -0
  37. data/spec/acceptance/support-skeletons/package_complex/scripts/sysprep.sh +32 -0
  38. data/spec/acceptance/support-skeletons/package_simple/Vagrantfile.testbox +10 -0
  39. data/spec/acceptance/two_disks_spec.rb +29 -0
  40. data/spec/acceptance/use_qemu_agent_for_connectivity_spec.rb +35 -0
  41. data/spec/spec_helper.rb +3 -0
  42. data/spec/support/acceptance/configuration.rb +21 -0
  43. data/spec/support/acceptance/context.rb +70 -0
  44. data/spec/support/acceptance/isolated_environment.rb +41 -0
  45. data/spec/support/libvirt_acceptance_context.rb +64 -0
  46. data/spec/support/sharedcontext.rb +1 -0
  47. data/spec/unit/action/create_domain_spec/sysinfo.xml +66 -0
  48. data/spec/unit/action/create_domain_spec/sysinfo_only_required.xml +49 -0
  49. data/spec/unit/action/create_domain_spec.rb +82 -0
  50. data/spec/unit/action/forward_ports_spec.rb +0 -1
  51. data/spec/unit/action/handle_box_image_spec.rb +18 -1
  52. data/spec/unit/action/remove_libvirt_image_spec.rb +43 -0
  53. data/spec/unit/action/resolve_disk_settings_spec.rb +24 -0
  54. data/spec/unit/action/start_domain_spec/clock_timer_removed.xml +38 -0
  55. data/spec/unit/action/start_domain_spec/clock_timer_rtc_tsc.xml +39 -0
  56. data/spec/unit/action/start_domain_spec/nvram_domain_other_setting.xml +2 -2
  57. data/spec/unit/action/start_domain_spec.rb +72 -30
  58. data/spec/unit/action_spec.rb +88 -0
  59. data/spec/unit/cap/synced_folder_9p_spec.rb +120 -0
  60. data/spec/unit/cap/synced_folder_virtiofs_spec.rb +120 -0
  61. data/spec/unit/config_spec.rb +133 -6
  62. data/spec/unit/driver_spec.rb +1 -1
  63. data/spec/unit/plugin_spec.rb +42 -0
  64. data/spec/unit/templates/domain_all_settings.xml +13 -4
  65. data/spec/unit/templates/domain_scsi_bus_storage.xml +44 -0
  66. data/spec/unit/templates/domain_scsi_device_storage.xml +44 -0
  67. data/spec/unit/templates/domain_scsi_multiple_controllers_storage.xml +130 -0
  68. data/spec/unit/templates/domain_spec.rb +105 -21
  69. data/spec/unit/util/byte_number_spec.rb +1 -1
  70. metadata +155 -87
  71. 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 supercede most other options if provided
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
- @disk_bus = 'virtio' if @disk_bus == UNSET_VALUE
869
- @disk_device = 'vda' if @disk_device == UNSET_VALUE
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 optain domain ip configuration, at least
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.each do |_type, opts|
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
- conn_attr[:libvirt_ip_command] = ip_command
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::open_read_only(config.system_uri)
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
- if e.libvirt_code == ProviderLibvirt::Util::ErrorCodes::VIR_ERR_NO_DOMAIN
73
- @logger.debug("machine #{machine.name} domain not found #{e}.")
74
- return nil
75
- else
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 @machine.provider_config.qemu_use_agent == true
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 @machine.provider_config.qemu_use_session
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('Timeout at waiting for an ip address for machine %s' % machine.name)
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('No arp table entry found for machine %s' % machine.name)
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
- return state
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.sort_by { |lse| lse["expirytime"] }.last["ipaddr"] if !leases.empty?
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=10)
176
- @logger.debug("Got Response from qemu agent")
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
- @logger.debug("Unable to receive IP via qemu agent: [%s]" % e.message)
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["return"].each{ |interface|
185
- if domain.mac.downcase == interface["hardware-address"].downcase
186
- @logger.debug("Found mathing interface: [%s]" % interface["name"])
187
- if interface.has_key?("ip-addresses")
188
- interface["ip-addresses"].each{ |ip|
189
- # returning ipv6 addresses might break windows guests because
190
- # winrm cant handle connection, winrm fails with "invalid uri"
191
- if ip["ip-address-type"] == "ipv4"
192
- ip_address = ip["ip-address"]
193
- @logger.debug("Return IP: [%s]" % ip_address)
194
- break
195
- end
196
- }
197
- end
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 |type, ip|
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 if ip[0] != nil
260
+ ip_address = ip[0].split("\n").first unless ip[0].nil?
211
261
  end
212
262
 
213
- ip_address != nil
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(:fog_create_server_error)
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 DeleteSnapshotError < VagrantLibvirtError
190
- error_key(:delete_snapshot_error)
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
- # compatibility fix to define constant not available Vagrant <1.6
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 modifing @machine.id or accessing @machine.state is not
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
- <acceleration accel3d='yes'/>
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
- <vendor id='<%= usb[:vendor] %>'/>
279
+ <vendor id='<%= usb[:vendor] %>'/>
254
280
  <%- end -%>
255
281
  <%- if usb[:product] -%>
256
- <product id='<%= usb[:product] %>'/>
282
+ <product id='<%= usb[:product] %>'/>
257
283
  <%- end -%>
258
284
  <%- if usb[:bus] && usb[:device] -%>
259
- <address bus='<%= usb[:bus] %>' device='<%= usb[:device] %>'/>
285
+ <address bus='<%= usb[:bus] %>' device='<%= usb[:device] %>'/>
260
286
  <%- end -%>
261
287
  </source>
262
288
  </hostdev>
@@ -68,4 +68,3 @@ class ByteNumber < Numeric
68
68
  (to_f/(1024 ** n)).ceil
69
69
  end
70
70
  end
71
-
@@ -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
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class String
4
+ def unindent
5
+ gsub(/^#{scan(/^\s*/).min_by{|l|l.length}}/, "")
6
+ end
7
+ end
@@ -1 +1 @@
1
- 0.9.0
1
+ 0.10.0