vagrant-libvirt 0.0.32 → 0.0.33

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/Gemfile +4 -0
  4. data/README.md +146 -22
  5. data/lib/vagrant-libvirt/action/create_domain.rb +35 -0
  6. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +1 -0
  7. data/lib/vagrant-libvirt/action/create_networks.rb +2 -0
  8. data/lib/vagrant-libvirt/action/forward_ports.rb +2 -2
  9. data/lib/vagrant-libvirt/action/handle_box_image.rb +3 -1
  10. data/lib/vagrant-libvirt/action/prepare_nfs_settings.rb +9 -9
  11. data/lib/vagrant-libvirt/action/set_name_of_domain.rb +6 -4
  12. data/lib/vagrant-libvirt/action/start_domain.rb +136 -30
  13. data/lib/vagrant-libvirt/action/wait_till_up.rb +22 -14
  14. data/lib/vagrant-libvirt/cap/nic_mac_addresses.rb +7 -1
  15. data/lib/vagrant-libvirt/cap/synced_folder.rb +6 -3
  16. data/lib/vagrant-libvirt/config.rb +109 -0
  17. data/lib/vagrant-libvirt/plugin.rb +3 -0
  18. data/lib/vagrant-libvirt/templates/domain.xml.erb +57 -7
  19. data/lib/vagrant-libvirt/templates/interface.xml.erb +5 -1
  20. data/lib/vagrant-libvirt/templates/private_network.xml.erb +1 -1
  21. data/lib/vagrant-libvirt/templates/tunnel_interface.xml.erb +6 -0
  22. data/lib/vagrant-libvirt/util/network_util.rb +2 -0
  23. data/lib/vagrant-libvirt/version.rb +1 -1
  24. data/locales/en.yml +1 -1
  25. data/spec/spec_helper.rb +1 -0
  26. data/spec/support/libvirt_context.rb +28 -0
  27. data/spec/support/sharedcontext.rb +34 -0
  28. data/spec/{vagrant-libvirt → unit}/action/set_name_of_domain_spec.rb +0 -0
  29. data/spec/unit/action/wait_till_up_spec.rb +128 -0
  30. data/tools/create_box.sh +3 -1
  31. data/vagrant-libvirt.gemspec +4 -4
  32. metadata +21 -15
@@ -67,7 +67,9 @@ module VagrantPlugins
67
67
  env[:ui].info(I18n.t('vagrant_libvirt.uploading_volume'))
68
68
 
69
69
  # Create new volume in storage pool
70
- raise Errors::BoxNotFound if !File.exists?(box_image_file)
70
+ unless File.exists?(box_image_file)
71
+ raise Vagrant::Errors::BoxNotFound.new(name: env[:machine].box.name)
72
+ end
71
73
  box_image_size = File.size(box_image_file) # B
72
74
  message = "Creating volume #{env[:box_volume_name]}"
73
75
  message << " in storage pool #{config.storage_pool_name}."
@@ -40,15 +40,15 @@ module VagrantPlugins
40
40
  # @param [Machine] machine
41
41
  # @return [String]
42
42
  def read_host_ip(ip)
43
- UDPSocket.open do |s|
44
- if(ip.kind_of?(Array))
45
- s.connect(ip.last, 1)
46
- else
47
- s.connect(ip, 1)
43
+ UDPSocket.open do |s|
44
+ if(ip.kind_of?(Array))
45
+ s.connect(ip.last, 1)
46
+ else
47
+ s.connect(ip, 1)
48
+ end
49
+ s.addr.last
50
+ end
48
51
  end
49
- s.addr.last
50
- end
51
- end
52
52
  # Returns the IP address of the guest
53
53
  #
54
54
  # @param [Machine] machine
@@ -65,7 +65,7 @@ module VagrantPlugins
65
65
  result << data if type == :stdout
66
66
  end
67
67
 
68
- ips = result.chomp.split("\n")
68
+ ips = result.chomp.split("\n").uniq
69
69
  @logger.info("guest IPs: #{ips.join(', ')}")
70
70
  ips.each do |ip|
71
71
  next if ip == ssh_host
@@ -46,13 +46,15 @@ module VagrantPlugins
46
46
  config = env[:machine].provider_config
47
47
  domain_name =
48
48
  if config.default_prefix.nil?
49
- env[:root_path].basename.to_s.dup
49
+ env[:root_path].basename.to_s.dup.concat("_")
50
+ elsif config.default_prefix.empty?
51
+ # don't have any prefix, not even "_"
52
+ ""
50
53
  else
51
- config.default_prefix.to_s
54
+ config.default_prefix.to_s.concat("_")
52
55
  end
53
- domain_name << '_'
54
56
  domain_name << env[:machine].name.to_s
55
- domain_name.gsub!(/[^-a-z0-9_]/i, '')
57
+ domain_name.gsub!(/[^-a-z0-9_\.]/i, '')
56
58
  domain_name << "_#{Time.now.utc.to_i}_#{SecureRandom.hex(10)}" if config.random_hostname
57
59
  domain_name
58
60
  end
@@ -23,8 +23,8 @@ module VagrantPlugins
23
23
 
24
24
  libvirt_domain = env[:machine].provider.driver.connection.client.lookup_domain_by_uuid(env[:machine].id)
25
25
 
26
- if config.memory*1024 != libvirt_domain.max_memory
27
- libvirt_domain.max_memory = config.memory*1024
26
+ if config.memory.to_i*1024 != libvirt_domain.max_memory
27
+ libvirt_domain.max_memory = config.memory.to_i*1024
28
28
  libvirt_domain.memory = libvirt_domain.max_memory
29
29
  end
30
30
  begin
@@ -88,7 +88,16 @@ module VagrantPlugins
88
88
  descr_changed = true
89
89
  cpu_model = REXML::Element.new('model', REXML::XPath.first(xml_descr,'/domain/cpu'))
90
90
  cpu_model.attributes['fallback'] = 'allow'
91
- cpu_model.text = 'qemu64'
91
+ cpu_model.text = config.cpu_model
92
+ else
93
+ if cpu_model.text != config.cpu_model
94
+ descr_changed = true
95
+ cpu_model.text = config.cpu_model
96
+ end
97
+ if cpu_model.attributes['fallback'] != config.cpu_fallback
98
+ descr_changed = true
99
+ cpu_model.attributes['fallback'] = config.cpu_fallback
100
+ end
92
101
  end
93
102
  vmx_feature = REXML::XPath.first(xml_descr,'/domain/cpu/feature[@name="vmx"]')
94
103
  svm_feature = REXML::XPath.first(xml_descr,'/domain/cpu/feature[@name="svm"]')
@@ -126,42 +135,137 @@ module VagrantPlugins
126
135
 
127
136
  # Graphics
128
137
  graphics = REXML::XPath.first(xml_descr,'/domain/devices/graphics')
129
- if graphics.attributes['type'] != config.graphics_type
130
- descr_changed = true
131
- graphics.attributes['type'] = config.graphics_type
132
- end
133
- if graphics.attributes['listen'] != config.graphics_ip
134
- descr_changed = true
135
- graphics.attributes['listen'] = config.graphics_ip
136
- graphics.delete_element('//listen')
138
+ if config.graphics_type != 'none'
139
+ if graphics.nil?
140
+ descr_changed = true
141
+ graphics = REXML::Element.new('graphics', REXML::XPath.first(xml_descr,'/domain/devices'))
142
+ end
143
+ if graphics.attributes['type'] != config.graphics_type
144
+ descr_changed = true
145
+ graphics.attributes['type'] = config.graphics_type
146
+ end
147
+ if graphics.attributes['listen'] != config.graphics_ip
148
+ descr_changed = true
149
+ graphics.attributes['listen'] = config.graphics_ip
150
+ graphics.delete_element('//listen')
151
+ end
152
+ if graphics.attributes['autoport'] != config.graphics_autoport
153
+ descr_changed = true
154
+ graphics.attributes['autoport'] = config.graphics_autoport
155
+ if config.graphics_autoport == 'no'
156
+ graphics.attributes['port'] = config.graphics_port
157
+ end
158
+ end
159
+ if graphics.attributes['keymap'] != config.keymap
160
+ descr_changed = true
161
+ graphics.attributes['keymap'] = config.keymap
162
+ end
163
+ if graphics.attributes['passwd'] != config.graphics_passwd
164
+ descr_changed = true
165
+ if config.graphics_passwd.nil?
166
+ graphics.attributes.delete 'passwd'
167
+ else
168
+ graphics.attributes['passwd'] = config.graphics_passwd
169
+ end
170
+ end
171
+ else
172
+ # graphics_type = none, remove entire element
173
+ if !graphics.nil?
174
+ graphics.parent.delete_element(graphics)
175
+ end
137
176
  end
138
- if graphics.attributes['autoport'] != config.graphics_autoport
139
- descr_changed = true
140
- graphics.attributes['autoport'] = config.graphics_autoport
141
- if config.graphics_autoport == 'no'
142
- graphics.attributes['port'] = config.graphics_port
177
+
178
+ #TPM
179
+ if config.tpm_path
180
+ raise Errors::FogCreateServerError, "The TPM Path must be fully qualified" unless config.tpm_path[0].chr == '/'
181
+
182
+ tpm = REXML::XPath.first(xml_descr,'/domain/devices/tpm')
183
+ if tpm.nil?
184
+ descr_changed = true
185
+ tpm = REXML::Element.new('tpm', REXML::XPath.first(xml_descr,'/domain/devices/tpm/model'))
186
+ tpm.attributes['model'] = config.tpm_model
187
+ tpm_backend_type = tpm.add_element('backend')
188
+ tpm_backend_type.attributes['type'] = config.tpm_type
189
+ tpm_device_path = tpm_backend_type.add_element('device')
190
+ tpm_device_path.attributes['path'] = config.tpm_path
191
+ else
192
+ if tpm.attributes['model'] != config.tpm_model
193
+ descr_changed = true
194
+ tpm.attributes['model'] = config.tpm_model
195
+ end
196
+ if tpm.elements['backend'].attributes['type'] != config.tpm_type
197
+ descr_changed = true
198
+ tpm.elements['backend'].attributes['type'] = config.tpm_type
199
+ end
200
+ if tpm.elements['backend'].elements['device'].attributes['path'] != config.tpm_path
201
+ descr_changed = true
202
+ tpm.elements['backend'].elements['device'].attributes['path'] = config.tpm_path
203
+ end
143
204
  end
144
205
  end
145
- if graphics.attributes['keymap'] != config.keymap
206
+
207
+ # Video device
208
+ video = REXML::XPath.first(xml_descr,'/domain/devices/video')
209
+ if !video.nil? and config.graphics_type == 'none'
210
+ # graphics_type = none, video devices are removed since there is no possible output
146
211
  descr_changed = true
147
- graphics.attributes['keymap'] = config.keymap
212
+ video.parent.delete_element(video)
213
+ else
214
+ video_model = REXML::XPath.first(xml_descr,'/domain/devices/video/model')
215
+ if video_model.nil?
216
+ video_model = REXML::Element.new('model', REXML::XPath.first(xml_descr,'/domain/devices/video'))
217
+ video_model.attributes['type'] = config.video_type
218
+ video_model.attributes['vram'] = config.video_vram
219
+ else
220
+ if video_model.attributes['type'] != config.video_type || video_model.attributes['vram'] != config.video_vram
221
+ descr_changed = true
222
+ video_model.attributes['type'] = config.video_type
223
+ video_model.attributes['vram'] = config.video_vram
224
+ end
225
+ end
148
226
  end
149
- if graphics.attributes['passwd'] != config.graphics_passwd
150
- descr_changed = true
151
- if config.graphics_passwd.nil?
152
- graphics.attributes.delete 'passwd'
227
+
228
+ # dtb
229
+ if config.dtb
230
+ dtb = REXML::XPath.first(xml_descr,'/domain/os/dtb')
231
+ if dtb.nil?
232
+ descr_changed = true
233
+ dtb = REXML::Element.new('dtb', REXML::XPath.first(xml_descr,'/domain/os'))
234
+ dtb.text = config.dtb
153
235
  else
154
- graphics.attributes['passwd'] = config.graphics_passwd
236
+ if dtb.text != config.dtb
237
+ descr_changed = true
238
+ dtb.text = config.dtb
239
+ end
155
240
  end
156
241
  end
157
242
 
158
- # Video device
159
- video = REXML::XPath.first(xml_descr,'/domain/devices/video/model')
160
- if video.attributes['type'] != config.video_type || video.attributes['vram'] != config.video_vram
161
- descr_changed = true
162
- video.attributes.each_attribute {|attr| video.attributes.delete attr}
163
- video.attributes['type'] = config.video_type
164
- video.attributes['vram'] = config.video_vram
243
+ # kernel and initrd
244
+ if config.kernel
245
+ kernel= REXML::XPath.first(xml_descr,'/domain/os/kernel')
246
+ if kernel.nil?
247
+ descr_changed = true
248
+ kernel = REXML::Element.new('kernel', REXML::XPath.first(xml_descr,'/domain/os'))
249
+ kernel.text = config.kernel
250
+ else
251
+ if kernel.text != config.kernel
252
+ descr_changed = true
253
+ kernel.text = config.kernel
254
+ end
255
+ end
256
+ end
257
+ if config.initrd
258
+ initrd = REXML::XPath.first(xml_descr,'/domain/os/initrd')
259
+ if initrd.nil?
260
+ descr_changed = true
261
+ initrd = REXML::Element.new('initrd', REXML::XPath.first(xml_descr,'/domain/os'))
262
+ initrd.text = config.initrd
263
+ else
264
+ if initrd.text != config.initrd
265
+ descr_changed = true
266
+ initrd.text = config.initrd
267
+ end
268
+ end
165
269
  end
166
270
 
167
271
  # Apply
@@ -179,6 +283,8 @@ module VagrantPlugins
179
283
  rescue => e
180
284
  env[:ui].error("Error when updating domain settings: #{e.message}")
181
285
  end
286
+ # Autostart with host if enabled in Vagrantfile
287
+ libvirt_domain.autostart = config.autostart
182
288
  # Actually start the domain
183
289
  domain.start
184
290
  rescue => e
@@ -1,4 +1,5 @@
1
1
  require 'log4r'
2
+ require 'vagrant-libvirt/errors'
2
3
  require 'vagrant-libvirt/util/timer'
3
4
  require 'vagrant/util/retryable'
4
5
 
@@ -21,18 +22,22 @@ module VagrantPlugins
21
22
  env[:metrics] ||= {}
22
23
 
23
24
  # Get domain object
24
- domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
25
- raise NoDomainError if domain == nil
25
+ domain = env[:machine].provider.driver.get_domain(env[:machine].id.to_s)
26
+ if domain == nil
27
+ raise Errors::NoDomainError,
28
+ :error_message => "Domain #{env[:machine].id} not found"
29
+ end
26
30
 
27
31
  # Wait for domain to obtain an ip address. Ip address is searched
28
32
  # from arp table, either localy or remotely via ssh, if libvirt
29
33
  # connection was done via ssh.
30
34
  env[:ip_address] = nil
31
35
  env[:metrics]["instance_ip_time"] = Util::Timer.time do
36
+ @logger.debug("Searching for IP for MAC address: #{domain.mac}")
32
37
  env[:ui].info(I18n.t("vagrant_libvirt.waiting_for_ip"))
33
38
  retryable(:on => Fog::Errors::TimeoutError, :tries => 300) do
34
39
  # If we're interrupted don't worry about waiting
35
- next if env[:interrupted]
40
+ return terminate(env) if env[:interrupted]
36
41
 
37
42
  # Wait for domain to obtain an ip address
38
43
  domain.wait_for(2) {
@@ -43,7 +48,6 @@ module VagrantPlugins
43
48
  }
44
49
  end
45
50
  end
46
- terminate(env) if env[:interrupted]
47
51
  @logger.info("Got IP address #{env[:ip_address]}")
48
52
  @logger.info("Time for getting IP: #{env[:metrics]["instance_ip_time"]}")
49
53
 
@@ -64,7 +68,8 @@ module VagrantPlugins
64
68
  end
65
69
  end
66
70
  end
67
- terminate(env) if env[:interrupted]
71
+ # if interrupted above, just terminate immediately
72
+ return terminate(env) if env[:interrupted]
68
73
  @logger.info("Time for SSH ready: #{env[:metrics]["instance_ssh_time"]}")
69
74
 
70
75
  # Booted and ready for use.
@@ -76,18 +81,21 @@ module VagrantPlugins
76
81
  def recover(env)
77
82
  return if env["vagrant.error"].is_a?(Vagrant::Errors::VagrantError)
78
83
 
79
- if env[:machine].provider.state.id != :not_created
80
- # Undo the import
81
- terminate(env)
82
- end
84
+ # Undo the import
85
+ terminate(env)
83
86
  end
84
87
 
85
88
  def terminate(env)
86
- destroy_env = env.dup
87
- destroy_env.delete(:interrupted)
88
- destroy_env[:config_validate] = false
89
- destroy_env[:force_confirm_destroy] = true
90
- env[:action_runner].run(Action.action_destroy, destroy_env)
89
+ if env[:machine].provider.state.id != :not_created
90
+ # If we're not supposed to destroy on error then just return
91
+ return if !env[:destroy_on_error]
92
+
93
+ destroy_env = env.dup
94
+ destroy_env.delete(:interrupted)
95
+ destroy_env[:config_validate] = false
96
+ destroy_env[:force_confirm_destroy] = true
97
+ env[:action_runner].run(Action.action_destroy, destroy_env)
98
+ end
91
99
  end
92
100
  end
93
101
  end
@@ -3,7 +3,13 @@ module VagrantPlugins
3
3
  module Cap
4
4
  class NicMacAddresses
5
5
  def self.nic_mac_addresses(machine)
6
- machine.provider.mac_addresses
6
+ # Vagrant expects a Hash with an index starting at 1 as key
7
+ # and the mac as uppercase string without colons as value
8
+ nic_macs = {}
9
+ machine.provider.mac_addresses.each do |index, mac|
10
+ nic_macs[index+1] = mac.upcase.gsub(':','')
11
+ end
12
+ nic_macs
7
13
  end
8
14
  end
9
15
  end
@@ -38,6 +38,7 @@ module VagrantPlugins
38
38
  folders.each do |id, folder_opts|
39
39
  folder_opts.merge!({ target: id,
40
40
  accessmode: 'passthrough',
41
+ mount: true,
41
42
  readonly: nil }) { |_k, ov, _nv| ov }
42
43
 
43
44
  mount_tag = Digest::MD5.new.update(folder_opts[:hostpath]).to_s[0,31]
@@ -63,9 +64,11 @@ module VagrantPlugins
63
64
  # Only mount folders that have a guest path specified.
64
65
  mount_folders = {}
65
66
  folders.each do |id, opts|
66
- mount_folders[id] = opts.dup if opts[:guestpath]
67
- # merge common options if not given
68
- mount_folders[id].merge!(version: '9p2000.L') { |_k, ov, _nv| ov }
67
+ if opts[:mount] && opts[:guestpath] && ! opts[:guestpath].empty?
68
+ mount_folders[id] = opts.dup
69
+ # merge common options if not given
70
+ mount_folders[id].merge!(version: '9p2000.L') { |_k, ov, _nv| ov }
71
+ end
69
72
  end
70
73
  # Mount the actual folder
71
74
  machine.guest.capability(
@@ -48,6 +48,7 @@ module VagrantPlugins
48
48
  attr_accessor :management_network_address
49
49
  attr_accessor :management_network_mode
50
50
  attr_accessor :management_network_mac
51
+ attr_accessor :management_network_guest_ipv6
51
52
 
52
53
  # Default host prefix (alternative to use project folder name)
53
54
  attr_accessor :default_prefix
@@ -57,6 +58,9 @@ module VagrantPlugins
57
58
  attr_accessor :memory
58
59
  attr_accessor :cpus
59
60
  attr_accessor :cpu_mode
61
+ attr_accessor :cpu_model
62
+ attr_accessor :cpu_fallback
63
+ attr_accessor :cpu_features
60
64
  attr_accessor :loader
61
65
  attr_accessor :boot_order
62
66
  attr_accessor :machine_type
@@ -69,6 +73,8 @@ module VagrantPlugins
69
73
  attr_accessor :kernel
70
74
  attr_accessor :cmd_line
71
75
  attr_accessor :initrd
76
+ attr_accessor :dtb
77
+ attr_accessor :emulator_path
72
78
  attr_accessor :graphics_type
73
79
  attr_accessor :graphics_autoport
74
80
  attr_accessor :graphics_port
@@ -77,6 +83,13 @@ module VagrantPlugins
77
83
  attr_accessor :video_type
78
84
  attr_accessor :video_vram
79
85
  attr_accessor :keymap
86
+ attr_accessor :kvm_hidden
87
+
88
+ # Sets the information for connecting to a host TPM device
89
+ # Only supports socket-based TPMs
90
+ attr_accessor :tpm_model
91
+ attr_accessor :tpm_type
92
+ attr_accessor :tpm_path
80
93
 
81
94
  # Sets the max number of NICs that can be created
82
95
  # Default set to 8. Don't change the default unless you know
@@ -90,9 +103,18 @@ module VagrantPlugins
90
103
  # Inputs
91
104
  attr_accessor :inputs
92
105
 
106
+ # PCI device passthrough
107
+ attr_accessor :pcis
108
+
109
+ # USB device passthrough
110
+ attr_accessor :usbs
111
+
93
112
  # Suspend mode
94
113
  attr_accessor :suspend_mode
95
114
 
115
+ # Autostart
116
+ attr_accessor :autostart
117
+
96
118
  def initialize
97
119
  @uri = UNSET_VALUE
98
120
  @driver = UNSET_VALUE
@@ -107,12 +129,16 @@ module VagrantPlugins
107
129
  @management_network_address = UNSET_VALUE
108
130
  @management_network_mode = UNSET_VALUE
109
131
  @management_network_mac = UNSET_VALUE
132
+ @management_network_guest_ipv6 = UNSET_VALUE
110
133
 
111
134
  # Domain specific settings.
112
135
  @uuid = UNSET_VALUE
113
136
  @memory = UNSET_VALUE
114
137
  @cpus = UNSET_VALUE
115
138
  @cpu_mode = UNSET_VALUE
139
+ @cpu_model = UNSET_VALUE
140
+ @cpu_fallback = UNSET_VALUE
141
+ @cpu_features = UNSET_VALUE
116
142
  @loader = UNSET_VALUE
117
143
  @machine_type = UNSET_VALUE
118
144
  @machine_arch = UNSET_VALUE
@@ -123,7 +149,9 @@ module VagrantPlugins
123
149
  @volume_cache = UNSET_VALUE
124
150
  @kernel = UNSET_VALUE
125
151
  @initrd = UNSET_VALUE
152
+ @dtb = UNSET_VALUE
126
153
  @cmd_line = UNSET_VALUE
154
+ @emulator_path = UNSET_VALUE
127
155
  @graphics_type = UNSET_VALUE
128
156
  @graphics_autoport = UNSET_VALUE
129
157
  @graphics_port = UNSET_VALUE
@@ -132,6 +160,11 @@ module VagrantPlugins
132
160
  @video_type = UNSET_VALUE
133
161
  @video_vram = UNSET_VALUE
134
162
  @keymap = UNSET_VALUE
163
+ @kvm_hidden = UNSET_VALUE
164
+
165
+ @tpm_model = UNSET_VALUE
166
+ @tpm_type = UNSET_VALUE
167
+ @tpm_path = UNSET_VALUE
135
168
 
136
169
  @nic_adapter_count = UNSET_VALUE
137
170
 
@@ -144,8 +177,17 @@ module VagrantPlugins
144
177
  # Inputs
145
178
  @inputs = UNSET_VALUE
146
179
 
180
+ # PCI device passthrough
181
+ @pcis = UNSET_VALUE
182
+
183
+ # USB device passthrough
184
+ @usbs = UNSET_VALUE
185
+
147
186
  # Suspend mode
148
187
  @suspend_mode = UNSET_VALUE
188
+
189
+ # Autostart
190
+ @autostart = UNSET_VALUE
149
191
  end
150
192
 
151
193
  def boot(device)
@@ -183,6 +225,21 @@ module VagrantPlugins
183
225
  raise 'Only four cdroms may be attached at a time'
184
226
  end
185
227
 
228
+ def cpu_feature(options={})
229
+ if options[:name].nil? || options[:policy].nil?
230
+ raise 'CPU Feature name AND policy must be specified'
231
+ end
232
+
233
+ if @cpu_features == UNSET_VALUE
234
+ @cpu_features = []
235
+ end
236
+
237
+ @cpu_features.push({
238
+ name: options[:name],
239
+ policy: options[:policy]
240
+ })
241
+ end
242
+
186
243
  def input(options={})
187
244
  if options[:type].nil? || options[:bus].nil?
188
245
  raise 'Input type AND bus must be specified'
@@ -198,6 +255,40 @@ module VagrantPlugins
198
255
  })
199
256
  end
200
257
 
258
+ def pci(options={})
259
+ if options[:bus].nil? || options[:slot].nil? || options[:function].nil?
260
+ raise 'Bus AND slot AND function must be specified. Check `lspci` for that numbers.'
261
+ end
262
+
263
+ if @pcis == UNSET_VALUE
264
+ @pcis = []
265
+ end
266
+
267
+ @pcis.push({
268
+ bus: options[:bus],
269
+ slot: options[:slot],
270
+ function: options[:function]
271
+ })
272
+ end
273
+
274
+ def usb(options={})
275
+ if (options[:bus].nil? || options[:device].nil?) && options[:vendor].nil? && options[:product].nil?
276
+ raise 'Bus and device and/or vendor and/or product must be specified. Check `lsusb` for these.'
277
+ end
278
+
279
+ if @usbs == UNSET_VALUE
280
+ @usbs = []
281
+ end
282
+
283
+ @usbs.push({
284
+ bus: options[:bus],
285
+ device: options[:device],
286
+ vendor: options[:vendor],
287
+ product: options[:product],
288
+ startupPolicy: options[:startupPolicy],
289
+ })
290
+ end
291
+
201
292
  # NOTE: this will run twice for each time it's needed- keep it idempotent
202
293
  def storage(storage_type, options={})
203
294
  if storage_type == :file
@@ -320,6 +411,7 @@ module VagrantPlugins
320
411
  @management_network_address = '192.168.121.0/24' if @management_network_address == UNSET_VALUE
321
412
  @management_network_mode = 'nat' if @management_network_mode == UNSET_VALUE
322
413
  @management_network_mac = nil if @management_network_mac == UNSET_VALUE
414
+ @management_network_guest_ipv6 = 'yes' if @management_network_guest_ipv6 == UNSET_VALUE
323
415
 
324
416
  # generate a URI if none is supplied
325
417
  @uri = _generate_uri() if @uri == UNSET_VALUE
@@ -329,6 +421,9 @@ module VagrantPlugins
329
421
  @memory = 512 if @memory == UNSET_VALUE
330
422
  @cpus = 1 if @cpus == UNSET_VALUE
331
423
  @cpu_mode = 'host-model' if @cpu_mode == UNSET_VALUE
424
+ @cpu_model = 'qemu64' if @cpu_model == UNSET_VALUE
425
+ @cpu_fallback = 'allow' if @cpu_fallback == UNSET_VALUE
426
+ @cpu_features = [] if @cpu_features == UNSET_VALUE
332
427
  @loader = nil if @loader == UNSET_VALUE
333
428
  @machine_type = nil if @machine_type == UNSET_VALUE
334
429
  @machine_arch = nil if @machine_arch == UNSET_VALUE
@@ -340,6 +435,7 @@ module VagrantPlugins
340
435
  @kernel = nil if @kernel == UNSET_VALUE
341
436
  @cmd_line = '' if @cmd_line == UNSET_VALUE
342
437
  @initrd = '' if @initrd == UNSET_VALUE
438
+ @dtb = nil if @dtb == UNSET_VALUE
343
439
  @graphics_type = 'vnc' if @graphics_type == UNSET_VALUE
344
440
  @graphics_autoport = 'yes' if @graphics_port == UNSET_VALUE
345
441
  @graphics_autoport = 'no' if @graphics_port != UNSET_VALUE
@@ -352,7 +448,12 @@ module VagrantPlugins
352
448
  @video_type = 'cirrus' if @video_type == UNSET_VALUE
353
449
  @video_vram = 9216 if @video_vram == UNSET_VALUE
354
450
  @keymap = 'en-us' if @keymap == UNSET_VALUE
451
+ @kvm_hidden = false if @kvm_hidden == UNSET_VALUE
452
+ @tpm_model = 'tpm-tis' if @tpm_model == UNSET_VALUE
453
+ @tpm_type = 'passthrough' if @tpm_type == UNSET_VALUE
454
+ @tpm_path = nil if @tpm_path == UNSET_VALUE
355
455
  @nic_adapter_count = 8 if @nic_adapter_count == UNSET_VALUE
456
+ @emulator_path = nil if @emulator_path == UNSET_VALUE
356
457
 
357
458
  # Boot order
358
459
  @boot_order = [] if @boot_order == UNSET_VALUE
@@ -364,9 +465,17 @@ module VagrantPlugins
364
465
  # Inputs
365
466
  @inputs = [{:type => "mouse", :bus => "ps2"}] if @inputs == UNSET_VALUE
366
467
 
468
+ # PCI device passthrough
469
+ @pcis = [] if @pcis == UNSET_VALUE
470
+
471
+ # USB device passthrough
472
+ @usbs = [] if @usbs == UNSET_VALUE
473
+
367
474
  # Suspend mode
368
475
  @suspend_mode = "pause" if @suspend_mode == UNSET_VALUE
369
476
 
477
+ # Autostart
478
+ @autostart = false if @autostart == UNSET_VALUE
370
479
  end
371
480
 
372
481
  def validate(machine)