vagrant-veertu 0.0.12

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 (60) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +11 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +31 -0
  5. data/Rakefile +5 -0
  6. data/lib/vagrant-veertu.rb +18 -0
  7. data/lib/vagrant-veertu/action.rb +330 -0
  8. data/lib/vagrant-veertu/action/boot.rb +21 -0
  9. data/lib/vagrant-veertu/action/check_accessible.rb +22 -0
  10. data/lib/vagrant-veertu/action/check_created.rb +21 -0
  11. data/lib/vagrant-veertu/action/check_running.rb +21 -0
  12. data/lib/vagrant-veertu/action/check_veertu.rb +22 -0
  13. data/lib/vagrant-veertu/action/clear_forwarded_ports.rb +20 -0
  14. data/lib/vagrant-veertu/action/clear_network_interfaces.rb +31 -0
  15. data/lib/vagrant-veertu/action/created.rb +20 -0
  16. data/lib/vagrant-veertu/action/customize.rb +44 -0
  17. data/lib/vagrant-veertu/action/destroy.rb +19 -0
  18. data/lib/vagrant-veertu/action/discard_state.rb +20 -0
  19. data/lib/vagrant-veertu/action/export.rb +41 -0
  20. data/lib/vagrant-veertu/action/forced_halt.rb +25 -0
  21. data/lib/vagrant-veertu/action/forward_ports.rb +91 -0
  22. data/lib/vagrant-veertu/action/import.rb +96 -0
  23. data/lib/vagrant-veertu/action/is_paused.rb +20 -0
  24. data/lib/vagrant-veertu/action/is_running.rb +20 -0
  25. data/lib/vagrant-veertu/action/is_saved.rb +20 -0
  26. data/lib/vagrant-veertu/action/message_already_running.rb +16 -0
  27. data/lib/vagrant-veertu/action/message_not_created.rb +16 -0
  28. data/lib/vagrant-veertu/action/message_not_running.rb +16 -0
  29. data/lib/vagrant-veertu/action/message_will_not_destroy.rb +17 -0
  30. data/lib/vagrant-veertu/action/network.rb +556 -0
  31. data/lib/vagrant-veertu/action/network_fix_ipv6.rb +81 -0
  32. data/lib/vagrant-veertu/action/package.rb +44 -0
  33. data/lib/vagrant-veertu/action/package_vagrantfile.rb +33 -0
  34. data/lib/vagrant-veertu/action/prepare_forwarded_port_collision_params.rb +35 -0
  35. data/lib/vagrant-veertu/action/prepare_nfs_settings.rb +119 -0
  36. data/lib/vagrant-veertu/action/prepare_nfs_valid_ids.rb +17 -0
  37. data/lib/vagrant-veertu/action/resume.rb +21 -0
  38. data/lib/vagrant-veertu/action/sane_defaults.rb +89 -0
  39. data/lib/vagrant-veertu/action/set_name.rb +55 -0
  40. data/lib/vagrant-veertu/action/setup_package_files.rb +51 -0
  41. data/lib/vagrant-veertu/action/snapshot_delete.rb +32 -0
  42. data/lib/vagrant-veertu/action/snapshot_restore.rb +28 -0
  43. data/lib/vagrant-veertu/action/snapshot_save.rb +25 -0
  44. data/lib/vagrant-veertu/action/suspend.rb +20 -0
  45. data/lib/vagrant-veertu/cap.rb +23 -0
  46. data/lib/vagrant-veertu/cap/public_address.rb +15 -0
  47. data/lib/vagrant-veertu/config.rb +199 -0
  48. data/lib/vagrant-veertu/driver/base.rb +240 -0
  49. data/lib/vagrant-veertu/driver/meta.rb +143 -0
  50. data/lib/vagrant-veertu/driver/version_5_0.rb +284 -0
  51. data/lib/vagrant-veertu/errors.rb +18 -0
  52. data/lib/vagrant-veertu/model/forwarded_port.rb +70 -0
  53. data/lib/vagrant-veertu/plugin.rb +76 -0
  54. data/lib/vagrant-veertu/provider.rb +121 -0
  55. data/lib/vagrant-veertu/synced_folder.rb +120 -0
  56. data/lib/vagrant-veertu/util/compile_forwarded_ports.rb +35 -0
  57. data/lib/vagrant-veertu/version.rb +5 -0
  58. data/locales/en.yml +19 -0
  59. data/vagrant-veertu.gemspec +22 -0
  60. metadata +130 -0
@@ -0,0 +1,20 @@
1
+ module VagrantPlugins
2
+ module ProviderVeertu
3
+ module Action
4
+ class IsPaused
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ # Set the result to be true if the machine is paused.
11
+ env[:result] = env[:machine].state.id == :paused
12
+
13
+ # Call the next if we have one (but we shouldn't, since this
14
+ # middleware is built to run with the Call-type middlewares)
15
+ @app.call(env)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module VagrantPlugins
2
+ module ProviderVeertu
3
+ module Action
4
+ class IsRunning
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ # Set the result to be true if the machine is running.
11
+ env[:result] = env[:machine].state.id == :running
12
+
13
+ # Call the next if we have one (but we shouldn't, since this
14
+ # middleware is built to run with the Call-type middlewares)
15
+ @app.call(env)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module VagrantPlugins
2
+ module ProviderVeertu
3
+ module Action
4
+ class IsSaved
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ # Set the result to be true if the machine is saved.
11
+ env[:result] = env[:machine].state.id == :paused
12
+
13
+ # Call the next if we have one (but we shouldn't, since this
14
+ # middleware is built to run with the Call-type middlewares)
15
+ @app.call(env)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ module VagrantPlugins
2
+ module ProviderVeertu
3
+ module Action
4
+ class MessageAlreadyRunning
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ env[:ui].info I18n.t("vagrant.commands.common.vm_already_running")
11
+ @app.call(env)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module VagrantPlugins
2
+ module ProviderVeertu
3
+ module Action
4
+ class MessageNotCreated
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ env[:ui].info I18n.t("vagrant.commands.common.vm_not_created")
11
+ @app.call(env)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module VagrantPlugins
2
+ module ProviderVeertu
3
+ module Action
4
+ class MessageNotRunning
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ env[:ui].info I18n.t("vagrant.commands.common.vm_not_running")
11
+ @app.call(env)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ module VagrantPlugins
2
+ module ProviderVeertu
3
+ module Action
4
+ class MessageWillNotDestroy
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ env[:ui].info I18n.t("vagrant.commands.destroy.will_not_destroy",
11
+ name: env[:machine].name)
12
+ @app.call(env)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,556 @@
1
+ require "ipaddr"
2
+ require "set"
3
+
4
+ require "log4r"
5
+
6
+ require "vagrant/util/network_ip"
7
+ require "vagrant/util/scoped_hash_override"
8
+
9
+ module VagrantPlugins
10
+ module ProviderVeertu
11
+ module Action
12
+ # This middleware class sets up all networking for the VirtualBox
13
+ # instance. This includes host only networks, bridged networking,
14
+ # forwarded ports, etc.
15
+ #
16
+ # This handles all the `config.vm.network` configurations.
17
+ class Network
18
+ include Vagrant::Util::NetworkIP
19
+ include Vagrant::Util::ScopedHashOverride
20
+
21
+ def initialize(app, env)
22
+ @logger = Log4r::Logger.new("vagrant::plugins::veertu::network")
23
+ @app = app
24
+ end
25
+
26
+ def call(env)
27
+ # TODO: Validate network configuration prior to anything below
28
+ @env = env
29
+
30
+ # Get the list of network adapters from the configuration
31
+ network_adapters_config = env[:machine].provider_config.network_adapters.dup
32
+
33
+ # Assign the adapter slot for each high-level network
34
+ available_slots = Set.new(1..36)
35
+ network_adapters_config.each do |slot, _data|
36
+ available_slots.delete(slot)
37
+ end
38
+
39
+ @logger.debug("Available slots for high-level adapters: #{available_slots.inspect}")
40
+ @logger.info("Determining network adapters required for high-level configuration...")
41
+ available_slots = available_slots.to_a.sort
42
+ env[:machine].config.vm.networks.each do |type, options|
43
+ # We only handle private and public networks
44
+ next if type != :private_network && type != :public_network
45
+
46
+ options = scoped_hash_override(options, :veertu)
47
+
48
+ # Figure out the slot that this adapter will go into
49
+ slot = options[:adapter]
50
+ if !slot
51
+ if available_slots.empty?
52
+ raise Vagrant::Errors::VirtualBoxNoRoomForHighLevelNetwork
53
+ end
54
+
55
+ slot = available_slots.shift
56
+ end
57
+
58
+ # Internal network is a special type
59
+ if type == :private_network && options[:intnet]
60
+ type = :internal_network
61
+ end
62
+
63
+ # Configure it
64
+ data = nil
65
+ if type == :private_network
66
+ # private_network = hostonly
67
+ data = [:hostonly, options]
68
+ elsif type == :public_network
69
+ # public_network = bridged
70
+ data = [:bridged, options]
71
+ elsif type == :internal_network
72
+ data = [:intnet, options]
73
+ end
74
+
75
+ # Store it!
76
+ @logger.info(" -- Slot #{slot}: #{data[0]}")
77
+ network_adapters_config[slot] = data
78
+ end
79
+
80
+ @logger.info("Determining adapters and compiling network configuration...")
81
+ adapters = []
82
+ networks = []
83
+ network_adapters_config.each do |slot, data|
84
+ type = data[0]
85
+ options = data[1]
86
+
87
+ @logger.info("Network slot #{slot}. Type: #{type}.")
88
+
89
+ # Get the normalized configuration for this type
90
+ config = send("#{type}_config", options)
91
+ config[:adapter] = slot
92
+ @logger.debug("Normalized configuration: #{config.inspect}")
93
+
94
+ # Get the VirtualBox adapter configuration
95
+ adapter = send("#{type}_adapter", config)
96
+ adapters << adapter
97
+ @logger.debug("Adapter configuration: #{adapter.inspect}")
98
+
99
+ # Get the network configuration
100
+ network = send("#{type}_network_config", config)
101
+ network[:auto_config] = config[:auto_config]
102
+ networks << network
103
+ end
104
+
105
+ if !adapters.empty?
106
+ # Enable the adapters
107
+ @logger.info("Enabling adapters...")
108
+ env[:ui].output(I18n.t("vagrant.actions.vm.network.preparing"))
109
+ adapters.each do |adapter|
110
+ env[:ui].detail(I18n.t(
111
+ "vagrant.virtualbox.network_adapter",
112
+ adapter: adapter[:adapter].to_s,
113
+ type: adapter[:type].to_s,
114
+ extra: "",
115
+ ))
116
+ end
117
+
118
+ #env[:machine].provider.driver.enable_adapters(adapters)
119
+ end
120
+
121
+ # Continue the middleware chain.
122
+ @app.call(env)
123
+
124
+ # If we have networks to configure, then we configure it now, since
125
+ # that requires the machine to be up and running.
126
+ if !adapters.empty? && !networks.empty?
127
+ assign_interface_numbers(networks, adapters)
128
+
129
+ # Only configure the networks the user requested us to configure
130
+ networks_to_configure = networks.select { |n| n[:auto_config] }
131
+ if !networks_to_configure.empty?
132
+ env[:ui].info I18n.t("vagrant.actions.vm.network.configuring")
133
+ env[:machine].guest.capability(:configure_networks, networks_to_configure)
134
+ end
135
+ end
136
+ end
137
+
138
+ def bridged_config(options)
139
+ return {
140
+ auto_config: true,
141
+ bridge: nil,
142
+ mac: nil,
143
+ nic_type: nil,
144
+ use_dhcp_assigned_default_route: false
145
+ }.merge(options || {})
146
+ end
147
+
148
+ def bridged_adapter(config)
149
+ # Find the bridged interfaces that are available
150
+ bridgedifs = @env[:machine].provider.driver.read_bridged_interfaces
151
+ bridgedifs.delete_if { |interface| interface[:status] == "Down" || interface[:status] == "Unknown" }
152
+
153
+ # The name of the chosen bridge interface will be assigned to this
154
+ # variable.
155
+ chosen_bridge = nil
156
+
157
+ if config[:bridge]
158
+ @logger.debug("Bridge was directly specified in config, searching for: #{config[:bridge]}")
159
+
160
+ # Search for a matching bridged interface
161
+ Array(config[:bridge]).each do |bridge|
162
+ bridge = bridge.downcase if bridge.respond_to?(:downcase)
163
+ bridgedifs.each do |interface|
164
+ if bridge === interface[:name].downcase
165
+ @logger.debug("Specific bridge found as configured in the Vagrantfile. Using it.")
166
+ chosen_bridge = interface[:name]
167
+ break
168
+ end
169
+ end
170
+ break if chosen_bridge
171
+ end
172
+
173
+ # If one wasn't found, then we notify the user here.
174
+ if !chosen_bridge
175
+ @env[:ui].info I18n.t("vagrant.actions.vm.bridged_networking.specific_not_found",
176
+ bridge: config[:bridge])
177
+ end
178
+ end
179
+
180
+ # If we still don't have a bridge chosen (this means that one wasn't
181
+ # specified in the Vagrantfile, or the bridge specified in the Vagrantfile
182
+ # wasn't found), then we fall back to the normal means of searchign for a
183
+ # bridged network.
184
+ if !chosen_bridge
185
+ if bridgedifs.length == 1
186
+ # One bridgable interface? Just use it.
187
+ chosen_bridge = bridgedifs[0][:name]
188
+ @logger.debug("Only one bridged interface available. Using it by default.")
189
+ else
190
+ # More than one bridgable interface requires a user decision, so
191
+ # show options to choose from.
192
+ @env[:ui].info I18n.t(
193
+ "vagrant.actions.vm.bridged_networking.available",
194
+ prefix: false)
195
+ bridgedifs.each_index do |index|
196
+ interface = bridgedifs[index]
197
+ @env[:ui].info("#{index + 1}) #{interface[:name]}", prefix: false)
198
+ end
199
+ @env[:ui].info(I18n.t(
200
+ "vagrant.actions.vm.bridged_networking.choice_help")+"\n")
201
+
202
+ # The range of valid choices
203
+ valid = Range.new(1, bridgedifs.length)
204
+
205
+ # The choice that the user has chosen as the bridging interface
206
+ choice = nil
207
+ while !valid.include?(choice)
208
+ choice = @env[:ui].ask(
209
+ "Which interface should the network bridge to? ")
210
+ choice = choice.to_i
211
+ end
212
+
213
+ chosen_bridge = bridgedifs[choice - 1][:name]
214
+ end
215
+ end
216
+
217
+ @logger.info("Bridging adapter #{config[:adapter]} to #{chosen_bridge}")
218
+
219
+ # Given the choice we can now define the adapter we're using
220
+ return {
221
+ adapter: config[:adapter],
222
+ type: :bridged,
223
+ bridge: chosen_bridge,
224
+ mac_address: config[:mac],
225
+ nic_type: config[:nic_type]
226
+ }
227
+ end
228
+
229
+ def bridged_network_config(config)
230
+ if config[:ip]
231
+ options = {
232
+ auto_config: true,
233
+ mac: nil,
234
+ netmask: "255.255.255.0",
235
+ type: :static
236
+ }.merge(config)
237
+ options[:type] = options[:type].to_sym
238
+ return options
239
+ end
240
+
241
+ return {
242
+ type: :dhcp,
243
+ use_dhcp_assigned_default_route: config[:use_dhcp_assigned_default_route]
244
+ }
245
+ end
246
+
247
+ def hostonly_config(options)
248
+ options = {
249
+ auto_config: true,
250
+ mac: nil,
251
+ nic_type: nil,
252
+ type: :static,
253
+ }.merge(options)
254
+
255
+ # Make sure the type is a symbol
256
+ options[:type] = options[:type].to_sym
257
+
258
+ # Default IP is in the 20-bit private network block for DHCP based networks
259
+ options[:ip] = "172.28.128.1" if options[:type] == :dhcp && !options[:ip]
260
+
261
+ ip = IPAddr.new(options[:ip])
262
+ if ip.ipv4?
263
+ options[:netmask] ||= "255.255.255.0"
264
+
265
+ # Calculate our network address for the given IP/netmask
266
+ netaddr = network_address(options[:ip], options[:netmask])
267
+
268
+ # Verify that a host-only network subnet would not collide
269
+ # with a bridged networking interface.
270
+ #
271
+ # If the subnets overlap in any way then the host only network
272
+ # will not work because the routing tables will force the
273
+ # traffic onto the real interface rather than the VirtualBox
274
+ # interface.
275
+ @env[:machine].provider.driver.read_bridged_interfaces.each do |interface|
276
+ that_netaddr = network_address(interface[:ip], interface[:netmask])
277
+ raise Vagrant::Errors::NetworkCollision if \
278
+ netaddr == that_netaddr && interface[:status] != "Down"
279
+ end
280
+
281
+ # Split the IP address into its components
282
+ ip_parts = netaddr.split(".").map { |i| i.to_i }
283
+
284
+ # Calculate the adapter IP, which we assume is the IP ".1" at
285
+ # the end usually.
286
+ adapter_ip = ip_parts.dup
287
+ adapter_ip[3] += 1
288
+ options[:adapter_ip] ||= adapter_ip.join(".")
289
+ elsif ip.ipv6?
290
+ # Default subnet prefix length
291
+ options[:netmask] ||= 64
292
+
293
+ # Set adapter IP to <prefix>::1
294
+ options[:adapter_ip] ||= (ip.mask(options[:netmask].to_i) | 1).to_s
295
+
296
+ # Append a 6 to the end of the type
297
+ options[:type] = "#{options[:type]}6".to_sym
298
+ else
299
+ raise "BUG: Unknown IP type: #{ip.inspect}"
300
+ end
301
+
302
+ dhcp_options = {}
303
+ if options[:type] == :dhcp
304
+ # Calculate the DHCP server IP, which is the network address
305
+ # with the final octet + 2. So "172.28.0.0" turns into "172.28.0.2"
306
+ dhcp_ip = ip_parts.dup
307
+ dhcp_ip[3] += 2
308
+ dhcp_options[:dhcp_ip] = options[:dhcp_ip] || dhcp_ip.join(".")
309
+
310
+ # Calculate the lower and upper bound for the DHCP server
311
+ dhcp_lower = ip_parts.dup
312
+ dhcp_lower[3] += 3
313
+ dhcp_options[:dhcp_lower] = options[:dhcp_lower] || dhcp_lower.join(".")
314
+
315
+ dhcp_upper = ip_parts.dup
316
+ dhcp_upper[3] = 254
317
+ dhcp_options[:dhcp_upper] = options[:dhcp_upper] || dhcp_upper.join(".")
318
+ end
319
+
320
+ return {
321
+ adapter_ip: options[:adapter_ip],
322
+ auto_config: options[:auto_config],
323
+ ip: options[:ip],
324
+ mac: options[:mac],
325
+ name: options[:name],
326
+ netmask: options[:netmask],
327
+ nic_type: options[:nic_type],
328
+ type: options[:type]
329
+ }.merge(dhcp_options)
330
+ end
331
+
332
+ def hostonly_adapter(config)
333
+ @logger.info("Searching for matching hostonly network: #{config[:ip]}")
334
+ interface = hostonly_find_matching_network(config)
335
+
336
+ if !interface
337
+ @logger.info("Network not found. Creating if we can.")
338
+
339
+ # It is an error if a specific host only network name was specified
340
+ # but the network wasn't found.
341
+ if config[:name]
342
+ raise Vagrant::Errors::NetworkNotFound, name: config[:name]
343
+ end
344
+
345
+ # Create a new network
346
+ interface = hostonly_create_network(config)
347
+ @logger.info("Created network: #{interface[:name]}")
348
+ end
349
+
350
+ if config[:type] == :dhcp
351
+ create_dhcp_server_if_necessary(interface, config)
352
+ end
353
+
354
+ return {
355
+ adapter: config[:adapter],
356
+ hostonly: interface[:name],
357
+ mac_address: config[:mac],
358
+ nic_type: config[:nic_type],
359
+ type: :hostonly
360
+ }
361
+ end
362
+
363
+ def hostonly_network_config(config)
364
+ return {
365
+ type: config[:type],
366
+ adapter_ip: config[:adapter_ip],
367
+ ip: config[:ip],
368
+ netmask: config[:netmask]
369
+ }
370
+ end
371
+
372
+ def intnet_config(options)
373
+ return {
374
+ type: "static",
375
+ ip: nil,
376
+ netmask: "255.255.255.0",
377
+ adapter: nil,
378
+ mac: nil,
379
+ intnet: nil,
380
+ auto_config: true
381
+ }.merge(options || {})
382
+ end
383
+
384
+ def intnet_adapter(config)
385
+ intnet_name = config[:intnet]
386
+ intnet_name = "intnet" if intnet_name == true
387
+
388
+ return {
389
+ adapter: config[:adapter],
390
+ type: :intnet,
391
+ mac_address: config[:mac],
392
+ nic_type: config[:nic_type],
393
+ intnet: intnet_name,
394
+ }
395
+ end
396
+
397
+ def intnet_network_config(config)
398
+ return {
399
+ type: config[:type],
400
+ ip: config[:ip],
401
+ netmask: config[:netmask]
402
+ }
403
+ end
404
+
405
+ def nat_config(options)
406
+ return {
407
+ auto_config: false
408
+ }
409
+ end
410
+
411
+ def nat_adapter(config)
412
+ return {
413
+ adapter: config[:adapter],
414
+ type: :nat,
415
+ }
416
+ end
417
+
418
+ def nat_network_config(config)
419
+ return {}
420
+ end
421
+
422
+ #-----------------------------------------------------------------
423
+ # Misc. helpers
424
+ #-----------------------------------------------------------------
425
+ # Assigns the actual interface number of a network based on the
426
+ # enabled NICs on the virtual machine.
427
+ #
428
+ # This interface number is used by the guest to configure the
429
+ # NIC on the guest VM.
430
+ #
431
+ # The networks are modified in place by adding an ":interface"
432
+ # field to each.
433
+ def assign_interface_numbers(networks, adapters)
434
+ current = 0
435
+ adapter_to_interface = {}
436
+
437
+ # Make a first pass to assign interface numbers by adapter location
438
+ vm_adapters = @env[:machine].provider.driver.read_network_interfaces
439
+ vm_adapters.sort.each do |number, adapter|
440
+ if adapter[:type] != :none
441
+ # Not used, so assign the interface number and increment
442
+ adapter_to_interface[number] = current
443
+ current += 1
444
+ end
445
+ end
446
+
447
+ # Make a pass through the adapters to assign the :interface
448
+ # key to each network configuration.
449
+ adapters.each_index do |i|
450
+ adapter = adapters[i]
451
+ network = networks[i]
452
+
453
+ # Figure out the interface number by simple lookup
454
+ network[:interface] = adapter_to_interface[adapter[:adapter]]
455
+ end
456
+ end
457
+
458
+ #-----------------------------------------------------------------
459
+ # Hostonly Helper Functions
460
+ #-----------------------------------------------------------------
461
+ # This creates a host only network for the given configuration.
462
+ def hostonly_create_network(config)
463
+ @env[:machine].provider.driver.create_host_only_network(
464
+ adapter_ip: config[:adapter_ip],
465
+ netmask: config[:netmask]
466
+ )
467
+ end
468
+
469
+ # This finds a matching host only network for the given configuration.
470
+ def hostonly_find_matching_network(config)
471
+ this_netaddr = network_address(config[:ip], config[:netmask])
472
+
473
+ @env[:machine].provider.driver.read_host_only_interfaces.each do |interface|
474
+ return interface if config[:name] && config[:name] == interface[:name]
475
+
476
+ if interface[:ip] != ""
477
+ return interface if this_netaddr == \
478
+ network_address(interface[:ip], interface[:netmask])
479
+ end
480
+
481
+ if interface[:ipv6] != ""
482
+ return interface if this_netaddr == \
483
+ network_address(interface[:ipv6], interface[:ipv6_prefix])
484
+ end
485
+ end
486
+
487
+ nil
488
+ end
489
+
490
+ #-----------------------------------------------------------------
491
+ # DHCP Server Helper Functions
492
+ #-----------------------------------------------------------------
493
+
494
+ DEFAULT_DHCP_SERVER_FROM_VBOX_INSTALL = {
495
+ network_name: 'HostInterfaceNetworking-vboxnet0',
496
+ network: 'vboxnet0',
497
+ ip: '192.168.56.100',
498
+ netmask: '255.255.255.0',
499
+ lower: '192.168.56.101',
500
+ upper: '192.168.56.254'
501
+ }.freeze
502
+
503
+ #
504
+ # When a host-only network of type: :dhcp is configured,
505
+ # this handles the potential creation of a vbox dhcpserver to manage
506
+ # it.
507
+ #
508
+ # @param [Hash<String>] interface hash as returned from read_host_only_interfaces
509
+ # @param [Hash<String>] config hash as returned from hostonly_config
510
+ def create_dhcp_server_if_necessary(interface, config)
511
+ existing_dhcp_server = find_matching_dhcp_server(interface)
512
+
513
+ if existing_dhcp_server
514
+ if dhcp_server_matches_config?(existing_dhcp_server, config)
515
+ @logger.debug("DHCP server already properly configured")
516
+ return
517
+ elsif existing_dhcp_server == DEFAULT_DHCP_SERVER_FROM_VBOX_INSTALL
518
+ @env[:ui].info I18n.t("vagrant.actions.vm.network.cleanup_vbox_default_dhcp")
519
+ @env[:machine].provider.driver.remove_dhcp_server(existing_dhcp_server[:network_name])
520
+ else
521
+ # We have an invalid DHCP server that we're not able to
522
+ # automatically clean up, so we need to give up and tell the user
523
+ # to sort out their own vbox dhcpservers and hostonlyifs
524
+ raise Vagrant::Errors::NetworkDHCPAlreadyAttached
525
+ end
526
+ end
527
+
528
+ @logger.debug("Creating a DHCP server...")
529
+ @env[:machine].provider.driver.create_dhcp_server(interface[:name], config)
530
+ end
531
+
532
+ # Detect when an existing DHCP server matches precisely the
533
+ # requested config for a hostonly interface.
534
+ #
535
+ # @param [Hash<String>] dhcp_server as found by read_dhcp_servers
536
+ # @param [Hash<String>] config as returned from hostonly_config
537
+ # @return [Boolean]
538
+ def dhcp_server_matches_config?(dhcp_server, config)
539
+ dhcp_server[:ip] == config[:dhcp_ip] &&
540
+ dhcp_server[:lower] == config[:dhcp_lower] &&
541
+ dhcp_server[:upper] == config[:dhcp_upper]
542
+ end
543
+
544
+ # Returns the existing dhcp server, if any, that is attached to the
545
+ # specified interface.
546
+ #
547
+ # @return [Hash<String>] dhcp_server or nil if not found
548
+ def find_matching_dhcp_server(interface)
549
+ @env[:machine].provider.driver.read_dhcp_servers.detect do |dhcp_server|
550
+ interface[:name] && interface[:name] == dhcp_server[:network]
551
+ end
552
+ end
553
+ end
554
+ end
555
+ end
556
+ end