vagrant-libvirt 0.6.2 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +65 -13
  3. data/lib/vagrant-libvirt/action/cleanup_on_failure.rb +76 -0
  4. data/lib/vagrant-libvirt/action/create_domain.rb +56 -10
  5. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +5 -1
  6. data/lib/vagrant-libvirt/action/create_networks.rb +24 -0
  7. data/lib/vagrant-libvirt/action/destroy_domain.rb +106 -21
  8. data/lib/vagrant-libvirt/action/destroy_networks.rb +1 -1
  9. data/lib/vagrant-libvirt/action/forward_ports.rb +12 -11
  10. data/lib/vagrant-libvirt/action/handle_box_image.rb +19 -10
  11. data/lib/vagrant-libvirt/action/prepare_nfs_settings.rb +1 -1
  12. data/lib/vagrant-libvirt/action/start_domain.rb +36 -0
  13. data/lib/vagrant-libvirt/action/wait_till_up.rb +6 -32
  14. data/lib/vagrant-libvirt/action.rb +67 -80
  15. data/lib/vagrant-libvirt/config.rb +85 -30
  16. data/lib/vagrant-libvirt/driver.rb +11 -9
  17. data/lib/vagrant-libvirt/errors.rb +12 -0
  18. data/lib/vagrant-libvirt/templates/domain.xml.erb +228 -218
  19. data/lib/vagrant-libvirt/templates/private_network.xml.erb +4 -1
  20. data/lib/vagrant-libvirt/util/network_util.rb +15 -3
  21. data/lib/vagrant-libvirt/util/nfs.rb +2 -0
  22. data/lib/vagrant-libvirt/util/resolvers.rb +80 -0
  23. data/lib/vagrant-libvirt/version +1 -1
  24. data/locales/en.yml +21 -0
  25. data/spec/spec_helper.rb +36 -23
  26. data/spec/support/libvirt_context.rb +7 -4
  27. data/spec/support/sharedcontext.rb +1 -1
  28. data/spec/unit/action/cleanup_on_failure_spec.rb +131 -0
  29. data/spec/unit/action/create_domain_spec/additional_disks_domain.xml +6 -18
  30. data/spec/unit/action/create_domain_spec/custom_disk_settings.xml +43 -0
  31. data/spec/unit/action/create_domain_spec/default_domain.xml +6 -18
  32. data/spec/unit/action/create_domain_spec/two_disk_settings.xml +49 -0
  33. data/spec/unit/action/create_domain_spec.rb +51 -7
  34. data/spec/unit/action/create_domain_volume_spec.rb +5 -3
  35. data/spec/unit/action/destroy_domain_spec/additional_disks_domain.xml +47 -0
  36. data/spec/unit/action/destroy_domain_spec/box_multiple_disks.xml +55 -0
  37. data/spec/unit/action/destroy_domain_spec/box_multiple_disks_and_additional_and_custom_disks.xml +72 -0
  38. data/spec/unit/action/destroy_domain_spec/box_multiple_disks_and_additional_and_custom_disks_no_aliases.xml +67 -0
  39. data/spec/unit/action/destroy_domain_spec/box_multiple_disks_and_additional_disks.xml +67 -0
  40. data/spec/unit/action/destroy_domain_spec/cdrom_domain.xml +48 -0
  41. data/spec/unit/action/destroy_domain_spec.rb +134 -30
  42. data/spec/unit/action/forward_ports_spec.rb +10 -2
  43. data/spec/unit/action/handle_box_image_spec.rb +30 -0
  44. data/spec/unit/action/prepare_nfs_settings_spec.rb +59 -0
  45. data/spec/unit/action/shutdown_domain_spec.rb +1 -1
  46. data/spec/unit/action/start_domain_spec/clock_timer_rtc.xml +6 -18
  47. data/spec/unit/action/start_domain_spec/default.xml +6 -18
  48. data/spec/unit/action/start_domain_spec/default_added_tpm_path.xml +6 -18
  49. data/spec/unit/action/start_domain_spec/default_added_tpm_version.xml +6 -18
  50. data/spec/unit/action/start_domain_spec/existing.xml +1 -1
  51. data/spec/unit/action/wait_till_up_spec.rb +4 -43
  52. data/spec/unit/action_spec.rb +2 -0
  53. data/spec/unit/config_spec.rb +133 -26
  54. data/spec/unit/driver_spec.rb +154 -10
  55. data/spec/unit/provider_spec.rb +11 -0
  56. data/spec/unit/templates/domain_all_settings.xml +56 -77
  57. data/spec/unit/templates/domain_cpu_mode_passthrough.xml +39 -0
  58. data/spec/unit/templates/domain_custom_cpu_model.xml +6 -18
  59. data/spec/unit/templates/domain_defaults.xml +6 -18
  60. data/spec/unit/templates/domain_spec.rb +39 -13
  61. data/spec/unit/templates/tpm/version_1.2.xml +6 -18
  62. data/spec/unit/templates/tpm/version_2.0.xml +6 -18
  63. data/spec/unit/util/resolvers_spec.rb +116 -0
  64. metadata +65 -64
@@ -4,15 +4,8 @@ require 'cgi'
4
4
 
5
5
  require 'vagrant'
6
6
 
7
- class Numeric
8
- Alphabet = ('a'..'z').to_a
9
- def vdev
10
- s = String.new
11
- q = self
12
- (q, r = (q - 1).divmod(26)) && s.prepend(Alphabet[r]) until q.zero?
13
- "vd#{s}"
14
- end
15
- end
7
+ require 'vagrant-libvirt/errors'
8
+ require 'vagrant-libvirt/util/resolvers'
16
9
 
17
10
  module VagrantPlugins
18
11
  module ProviderLibvirt
@@ -69,6 +62,7 @@ module VagrantPlugins
69
62
  attr_accessor :management_network_pci_slot
70
63
  attr_accessor :management_network_domain
71
64
  attr_accessor :management_network_mtu
65
+ attr_accessor :management_network_keep
72
66
 
73
67
  # System connection information
74
68
  attr_accessor :system_uri
@@ -119,8 +113,10 @@ module VagrantPlugins
119
113
  attr_accessor :graphics_port
120
114
  attr_accessor :graphics_passwd
121
115
  attr_accessor :graphics_ip
116
+ attr_accessor :graphics_gl
122
117
  attr_accessor :video_type
123
118
  attr_accessor :video_vram
119
+ attr_accessor :video_accel3d
124
120
  attr_accessor :keymap
125
121
  attr_accessor :kvm_hidden
126
122
  attr_accessor :sound_type
@@ -196,6 +192,9 @@ module VagrantPlugins
196
192
  # Use QEMU Agent to get ip address
197
193
  attr_accessor :qemu_use_agent
198
194
 
195
+ # serial consoles
196
+ attr_accessor :serials
197
+
199
198
  def initialize
200
199
  @uri = UNSET_VALUE
201
200
  @driver = UNSET_VALUE
@@ -222,6 +221,7 @@ module VagrantPlugins
222
221
  @management_network_pci_bus = UNSET_VALUE
223
222
  @management_network_domain = UNSET_VALUE
224
223
  @management_network_mtu = UNSET_VALUE
224
+ @management_network_keep = UNSET_VALUE
225
225
 
226
226
  # System connection information
227
227
  @system_uri = UNSET_VALUE
@@ -267,8 +267,10 @@ module VagrantPlugins
267
267
  @graphics_port = UNSET_VALUE
268
268
  @graphics_ip = UNSET_VALUE
269
269
  @graphics_passwd = UNSET_VALUE
270
+ @graphics_gl = UNSET_VALUE
270
271
  @video_type = UNSET_VALUE
271
272
  @video_vram = UNSET_VALUE
273
+ @video_accel3d = UNSET_VALUE
272
274
  @sound_type = UNSET_VALUE
273
275
  @keymap = UNSET_VALUE
274
276
  @kvm_hidden = UNSET_VALUE
@@ -338,23 +340,14 @@ module VagrantPlugins
338
340
 
339
341
  # Use Qemu agent to get ip address
340
342
  @qemu_use_agent = UNSET_VALUE
343
+
344
+ @serials = UNSET_VALUE
341
345
  end
342
346
 
343
347
  def boot(device)
344
348
  @boot_order << device # append
345
349
  end
346
350
 
347
- def _get_device(disks)
348
- # skip existing devices and also the first one (vda)
349
- exist = disks.collect { |x| x[:device] } + [1.vdev.to_s]
350
- skip = 1 # we're 1 based, not 0 based...
351
- loop do
352
- dev = skip.vdev # get lettered device
353
- return dev unless exist.include?(dev)
354
- skip += 1
355
- end
356
- end
357
-
358
351
  def _get_cdrom_dev(cdroms)
359
352
  exist = Hash[cdroms.collect { |x| [x[:dev], true] }]
360
353
  # hda - hdc
@@ -507,7 +500,9 @@ module VagrantPlugins
507
500
  target_address: options[:target_address],
508
501
  target_name: options[:target_name],
509
502
  target_port: options[:target_port],
510
- target_type: options[:target_type])
503
+ target_type: options[:target_type],
504
+ disabled: options[:disabled],
505
+ )
511
506
  end
512
507
 
513
508
  def random(options = {})
@@ -705,6 +700,22 @@ module VagrantPlugins
705
700
  @qemu_env.merge!(options)
706
701
  end
707
702
 
703
+ def serial(options={})
704
+ @serials = [] if @serials == UNSET_VALUE
705
+
706
+ options = {
707
+ :type => "pty",
708
+ :source => nil,
709
+ }.merge(options)
710
+
711
+ serial = {
712
+ :type => options[:type],
713
+ :source => options[:source],
714
+ }
715
+
716
+ @serials << serial
717
+ end
718
+
708
719
  def _default_uri
709
720
  # Determine if any settings except driver provided explicitly, if not
710
721
  # and the LIBVIRT_DEFAULT_URI var is set, use that.
@@ -817,7 +828,7 @@ module VagrantPlugins
817
828
  @management_network_pci_slot = nil if @management_network_pci_slot == UNSET_VALUE
818
829
  @management_network_domain = nil if @management_network_domain == UNSET_VALUE
819
830
  @management_network_mtu = nil if @management_network_mtu == UNSET_VALUE
820
- @system_uri = 'qemu:///system' if @system_uri == UNSET_VALUE
831
+ @management_network_keep = false if @management_network_keep == UNSET_VALUE
821
832
 
822
833
  # Domain specific settings.
823
834
  @title = '' if @title == UNSET_VALUE
@@ -870,7 +881,9 @@ module VagrantPlugins
870
881
  @graphics_port = -1 if @graphics_port == UNSET_VALUE
871
882
  @graphics_ip = '127.0.0.1' if @graphics_ip == UNSET_VALUE
872
883
  @video_type = 'cirrus' if @video_type == UNSET_VALUE
873
- @video_vram = 9216 if @video_vram == UNSET_VALUE
884
+ @video_vram = 16384 if @video_vram == UNSET_VALUE
885
+ @video_accel3d = false if @video_accel3d == UNSET_VALUE
886
+ @graphics_gl = @video_accel3d if @graphics_gl == UNSET_VALUE
874
887
  @sound_type = nil if @sound_type == UNSET_VALUE
875
888
  @keymap = 'en-us' if @keymap == UNSET_VALUE
876
889
  @kvm_hidden = false if @kvm_hidden == UNSET_VALUE
@@ -890,10 +903,6 @@ module VagrantPlugins
890
903
 
891
904
  # Storage
892
905
  @disks = [] if @disks == UNSET_VALUE
893
- @disks.map! do |disk|
894
- disk[:device] = _get_device(@disks) if disk[:device].nil?
895
- disk
896
- end
897
906
  @cdroms = [] if @cdroms == UNSET_VALUE
898
907
  @cdroms.map! do |cdrom|
899
908
  cdrom[:dev] = _get_cdrom_dev(@cdroms) if cdrom[:dev].nil?
@@ -904,7 +913,18 @@ module VagrantPlugins
904
913
  @inputs = [{ type: 'mouse', bus: 'ps2' }] if @inputs == UNSET_VALUE
905
914
 
906
915
  # Channels
907
- @channels = [] if @channels == UNSET_VALUE
916
+ if @channels == UNSET_VALUE
917
+ @channels = []
918
+ if @qemu_use_agent == true
919
+ if @channels.all? { |channel| !channel.fetch(:target_name, '').start_with?('org.qemu.guest_agent.') }
920
+ channel(:type => 'unix', :target_name => 'org.qemu.guest_agent.0', :target_type => 'virtio')
921
+ end
922
+ end
923
+ end
924
+
925
+ # filter channels of anything explicitly disabled so it's possible to inject an entry to
926
+ # avoid the automatic addition of the guest_agent above, and disable it from subsequent use.
927
+ @channels = @channels.reject { |channel| channel[:disabled] }.tap {|channel| channel.delete(:disabled) }
908
928
 
909
929
  # PCI device passthrough
910
930
  @pcis = [] if @pcis == UNSET_VALUE
@@ -945,12 +965,19 @@ module VagrantPlugins
945
965
  # Additional QEMU commandline environment variables
946
966
  @qemu_env = {} if @qemu_env == UNSET_VALUE
947
967
 
948
- @qemu_use_agent = true if @qemu_use_agent != UNSET_VALUE
968
+ @qemu_use_agent = false if @qemu_use_agent == UNSET_VALUE
969
+
970
+ @serials = [{:type => 'pty', :source => nil}] if @serials == UNSET_VALUE
949
971
  end
950
972
 
951
973
  def validate(machine)
952
974
  errors = _detected_errors
953
975
 
976
+ # technically this shouldn't occur, but ensure that if somehow it does, it gets rejected.
977
+ if @cpu_mode == 'host-passthrough' && @cpu_model != ''
978
+ errors << "cannot set cpu_model with cpu_mode of 'host-passthrough'. leave model unset or switch mode."
979
+ end
980
+
954
981
  # The @uri and @qemu_use_session should not conflict
955
982
  uri = _parse_uri(@uri)
956
983
  if (uri.scheme.start_with? "qemu") && (uri.path.include? "session")
@@ -959,6 +986,9 @@ module VagrantPlugins
959
986
  end
960
987
  end
961
988
 
989
+ unless @qemu_use_agent == true || @qemu_use_agent == false
990
+ errors << "libvirt.qemu_use_agent must be a boolean."
991
+ end
962
992
 
963
993
  if @qemu_use_agent == true
964
994
  # if qemu agent is used to optain domain ip configuration, at least
@@ -969,13 +999,28 @@ module VagrantPlugins
969
999
  end
970
1000
  end
971
1001
 
972
-
973
1002
  machine.provider_config.disks.each do |disk|
974
1003
  if disk[:path] && (disk[:path][0] == '/')
975
1004
  errors << "absolute volume paths like '#{disk[:path]}' not yet supported"
976
1005
  end
977
1006
  end
978
1007
 
1008
+ machine.provider_config.serials.each do |serial|
1009
+ if serial[:source] and serial[:source][:path].nil?
1010
+ errors << "serial :source requires :path to be defined"
1011
+ end
1012
+ end
1013
+
1014
+ # this won't be able to fully resolve the disks until the box has
1015
+ # been downloaded and any devices that need to be assigned to the
1016
+ # disks contained have been allocated
1017
+ disk_resolver = ::VagrantPlugins::ProviderLibvirt::Util::DiskDeviceResolver.new
1018
+ begin
1019
+ disk_resolver.resolve(machine.provider_config.disks)
1020
+ rescue Errors::VagrantLibvirtError => e
1021
+ errors << "#{e}"
1022
+ end
1023
+
979
1024
  machine.config.vm.networks.each do |_type, opts|
980
1025
  if opts[:mac]
981
1026
  if opts[:mac] =~ /\A([0-9a-fA-F]{12})\z/
@@ -1017,6 +1062,12 @@ module VagrantPlugins
1017
1062
  c = qemu_env != UNSET_VALUE ? qemu_env.dup : {}
1018
1063
  c.merge!(other.qemu_env) if other.qemu_env != UNSET_VALUE
1019
1064
  result.qemu_env = c
1065
+
1066
+ if serials != UNSET_VALUE
1067
+ s = serials.dup
1068
+ s += other.serials
1069
+ result.serials = s
1070
+ end
1020
1071
  end
1021
1072
  end
1022
1073
 
@@ -1026,6 +1077,10 @@ module VagrantPlugins
1026
1077
  # Parse uri to extract individual components
1027
1078
  uri = _parse_uri(@uri)
1028
1079
 
1080
+ system_uri = uri.dup
1081
+ system_uri.path = '/system'
1082
+ @system_uri = system_uri.to_s if @system_uri == UNSET_VALUE
1083
+
1029
1084
  # only set @connect_via_ssh if not explicitly to avoid overriding
1030
1085
  # and allow an error to occur if the @uri and @connect_via_ssh disagree
1031
1086
  @connect_via_ssh = uri.scheme.include? "ssh" if @connect_via_ssh == UNSET_VALUE
@@ -61,7 +61,7 @@ module VagrantPlugins
61
61
 
62
62
  config = @machine.provider_config
63
63
 
64
- @system_connection = Libvirt::open(config.system_uri)
64
+ @system_connection = Libvirt::open_read_only(config.system_uri)
65
65
  @system_connection
66
66
  end
67
67
 
@@ -98,16 +98,16 @@ module VagrantPlugins
98
98
  end
99
99
 
100
100
  def get_domain_ipaddress(machine, domain)
101
- if @machine.provider_config.qemu_use_session
102
- return get_ipaddress_from_system domain.mac
103
- end
104
-
105
101
  # attempt to get ip address from qemu agent
106
102
  if @machine.provider_config.qemu_use_agent == true
107
103
  @logger.info('Get IP via qemu agent')
108
104
  return get_ipaddress_from_qemu_agent(domain, machine.id)
109
105
  end
110
106
 
107
+ if @machine.provider_config.qemu_use_session
108
+ return get_ipaddress_from_system domain.mac
109
+ end
110
+
111
111
  # Get IP address from dhcp leases table
112
112
  begin
113
113
  ip_address = get_ipaddress_from_domain(domain)
@@ -135,7 +135,9 @@ module VagrantPlugins
135
135
  end
136
136
 
137
137
  # TODO: terminated no longer appears to be a valid fog state, remove?
138
- return :not_created if domain.nil? || domain.state.to_sym == :terminated
138
+ return :not_created if domain.nil?
139
+ return :unknown if domain.state.nil?
140
+ return :not_created if domain.state.to_sym == :terminated
139
141
 
140
142
  state = domain.state.tr('-', '_').to_sym
141
143
  if state == :running
@@ -168,9 +170,9 @@ module VagrantPlugins
168
170
  def get_ipaddress_from_qemu_agent(domain, machine_id)
169
171
  ip_address = nil
170
172
  addresses = nil
171
- dom = system_connection.lookup_domain_by_uuid(machine_id)
173
+ libvirt_domain = connection.client.lookup_domain_by_uuid(machine_id)
172
174
  begin
173
- response = dom.qemu_agent_command('{"execute":"guest-network-get-interfaces"}', timeout=10)
175
+ response = libvirt_domain.qemu_agent_command('{"execute":"guest-network-get-interfaces"}', timeout=10)
174
176
  @logger.debug("Got Response from qemu agent")
175
177
  @logger.debug(response)
176
178
  addresses = JSON.parse(response)
@@ -180,7 +182,7 @@ module VagrantPlugins
180
182
 
181
183
  unless addresses.nil?
182
184
  addresses["return"].each{ |interface|
183
- if domain.mac == interface["hardware-address"]
185
+ if domain.mac.downcase == interface["hardware-address"].downcase
184
186
  @logger.debug("Found mathing interface: [%s]" % interface["name"])
185
187
  if interface.has_key?("ip-addresses")
186
188
  interface["ip-addresses"].each{ |ip|
@@ -18,6 +18,14 @@ module VagrantPlugins
18
18
  error_key(:package_not_supported)
19
19
  end
20
20
 
21
+ class DuplicateDiskDevice < VagrantLibvirtError
22
+ error_key(:duplicate_disk_device)
23
+ end
24
+
25
+ class NoDiskDeviceAvailable < VagrantLibvirtError
26
+ error_key(:no_disk_device_available)
27
+ end
28
+
21
29
  # Storage pools and volumes exceptions
22
30
  class NoStoragePool < VagrantLibvirtError
23
31
  error_key(:no_storage_pool)
@@ -181,6 +189,10 @@ module VagrantPlugins
181
189
  class DeleteSnapshotError < VagrantLibvirtError
182
190
  error_key(:delete_snapshot_error)
183
191
  end
192
+
193
+ class SerialCannotCreatePathError < VagrantLibvirtError
194
+ error_key(:serial_cannot_create_path_error)
195
+ end
184
196
  end
185
197
  end
186
198
  end