vagrant-libvirt 0.0.30 → 0.0.31

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +20 -0
  3. data/Gemfile +6 -1
  4. data/README.md +146 -6
  5. data/example_box/Vagrantfile +1 -1
  6. data/example_box/metadata.json +1 -1
  7. data/lib/vagrant-libvirt.rb +3 -15
  8. data/lib/vagrant-libvirt/action.rb +59 -73
  9. data/lib/vagrant-libvirt/action/create_domain.rb +47 -19
  10. data/lib/vagrant-libvirt/action/create_domain_volume.rb +5 -5
  11. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +82 -36
  12. data/lib/vagrant-libvirt/action/create_networks.rb +99 -54
  13. data/lib/vagrant-libvirt/action/destroy_domain.rb +4 -4
  14. data/lib/vagrant-libvirt/action/destroy_networks.rb +2 -2
  15. data/lib/vagrant-libvirt/action/halt_domain.rb +1 -1
  16. data/lib/vagrant-libvirt/action/handle_box_image.rb +25 -5
  17. data/lib/vagrant-libvirt/action/handle_storage_pool.rb +9 -7
  18. data/lib/vagrant-libvirt/action/is_running.rb +1 -1
  19. data/lib/vagrant-libvirt/action/is_suspended.rb +1 -1
  20. data/lib/vagrant-libvirt/action/package_domain.rb +3 -3
  21. data/lib/vagrant-libvirt/action/prepare_nfs_settings.rb +8 -5
  22. data/lib/vagrant-libvirt/action/prepare_nfs_valid_ids.rb +1 -1
  23. data/lib/vagrant-libvirt/action/prune_nfs_exports.rb +1 -1
  24. data/lib/vagrant-libvirt/action/read_mac_addresses.rb +1 -1
  25. data/lib/vagrant-libvirt/action/remove_libvirt_image.rb +1 -1
  26. data/lib/vagrant-libvirt/action/remove_stale_volume.rb +2 -2
  27. data/lib/vagrant-libvirt/action/resume_domain.rb +1 -1
  28. data/lib/vagrant-libvirt/action/set_boot_order.rb +66 -0
  29. data/lib/vagrant-libvirt/action/set_name_of_domain.rb +3 -2
  30. data/lib/vagrant-libvirt/action/start_domain.rb +1 -1
  31. data/lib/vagrant-libvirt/action/suspend_domain.rb +1 -1
  32. data/lib/vagrant-libvirt/action/wait_till_up.rb +1 -1
  33. data/lib/vagrant-libvirt/cap/mount_p9.rb +2 -1
  34. data/lib/vagrant-libvirt/cap/synced_folder.rb +11 -5
  35. data/lib/vagrant-libvirt/config.rb +44 -5
  36. data/lib/vagrant-libvirt/driver.rb +121 -0
  37. data/lib/vagrant-libvirt/errors.rb +4 -0
  38. data/lib/vagrant-libvirt/plugin.rb +7 -5
  39. data/lib/vagrant-libvirt/provider.rb +54 -12
  40. data/lib/vagrant-libvirt/templates/domain.xml.erb +18 -12
  41. data/lib/vagrant-libvirt/templates/filesystem.xml.erb +1 -1
  42. data/lib/vagrant-libvirt/templates/tunnel_interface.xml.erb +11 -0
  43. data/lib/vagrant-libvirt/util/network_util.rb +11 -1
  44. data/lib/vagrant-libvirt/version.rb +1 -1
  45. data/locales/en.yml +24 -15
  46. data/spec/support/environment_helper.rb +1 -1
  47. data/tools/prepare_redhat_for_box.sh +1 -2
  48. metadata +6 -5
  49. data/lib/vagrant-libvirt/action/connect_libvirt.rb +0 -51
  50. data/lib/vagrant-libvirt/action/read_ssh_info.rb +0 -68
  51. data/lib/vagrant-libvirt/action/read_state.rb +0 -60
@@ -6,7 +6,7 @@ module VagrantPlugins
6
6
  class CreateDomain
7
7
  include VagrantPlugins::ProviderLibvirt::Util::ErbTemplate
8
8
 
9
- def initialize(app, env)
9
+ def initialize(app, _env)
10
10
  @logger = Log4r::Logger.new('vagrant_libvirt::action::create_domain')
11
11
  @app = app
12
12
  end
@@ -17,7 +17,7 @@ module VagrantPlugins
17
17
 
18
18
  def _disks_print(disks)
19
19
  disks.collect do |x|
20
- x[:device] + '(' + x[:type] + ',' + x[:size] + ')'
20
+ "#{x[:device]}(#{x[:type]},#{x[:size]})"
21
21
  end.join(', ')
22
22
  end
23
23
 
@@ -33,11 +33,13 @@ module VagrantPlugins
33
33
  @name = env[:domain_name]
34
34
  @cpus = config.cpus.to_i
35
35
  @cpu_mode = config.cpu_mode
36
+ @loader = config.loader
36
37
  @machine_type = config.machine_type
37
38
  @machine_arch = config.machine_arch
38
39
  @disk_bus = config.disk_bus
39
40
  @nested = config.nested
40
41
  @memory_size = config.memory.to_i * 1024
42
+ @management_network_mac = config.management_network_mac
41
43
  @domain_volume_cache = config.volume_cache
42
44
  @kernel = config.kernel
43
45
  @cmd_line = config.cmd_line
@@ -49,12 +51,12 @@ module VagrantPlugins
49
51
  @graphics_passwd = if config.graphics_passwd.to_s.empty?
50
52
  ''
51
53
  else
52
- "passwd='#{config.graphics_passwd.to_s}'"
54
+ "passwd='#{config.graphics_passwd}'"
53
55
  end
54
56
  @video_type = config.video_type
55
57
  @video_vram = config.video_vram
56
58
  @keymap = config.keymap
57
-
59
+
58
60
  # Boot order
59
61
  @boot_order = config.boot_order
60
62
 
@@ -63,19 +65,37 @@ module VagrantPlugins
63
65
  @disks = config.disks
64
66
  @cdroms = config.cdroms
65
67
 
68
+ # Input
69
+ @inputs = config.inputs
70
+
66
71
  config = env[:machine].provider_config
67
72
  @domain_type = config.driver
68
73
 
69
74
  @os_type = 'hvm'
70
75
 
71
- # Get path to domain image.
72
- domain_volume = ProviderLibvirt::Util::Collection.find_matching(
73
- env[:libvirt_compute].volumes.all, "#{@name}.img")
74
- raise Errors::DomainVolumeExists if domain_volume.nil?
75
- @domain_volume_path = domain_volume.path
76
+ # Get path to domain image from the storage pool selected if we have a box.
77
+ if env[:machine].box
78
+ actual_volumes =
79
+ env[:machine].provider.driver.connection.volumes.all.select do |x|
80
+ x.pool_name == @storage_pool_name
81
+ end
82
+ domain_volume = ProviderLibvirt::Util::Collection.find_matching(
83
+ actual_volumes,"#{@name}.img")
84
+ raise Errors::DomainVolumeExists if domain_volume.nil?
85
+ @domain_volume_path = domain_volume.path
86
+ end
76
87
 
88
+ # If we have a box, take the path from the domain volume and set our storage_prefix.
89
+ # If not, we dump the storage pool xml to get its defined path.
77
90
  # the default storage prefix is typically: /var/lib/libvirt/images/
78
- storage_prefix = File.dirname(@domain_volume_path) + '/' # steal
91
+ if env[:machine].box
92
+ storage_prefix = File.dirname(@domain_volume_path) + '/' # steal
93
+ else
94
+ storage_pool = env[:machine].provider.driver.connection.client.lookup_storage_pool_by_name(@storage_pool_name)
95
+ raise Errors::NoStoragePool if storage_pool.nil?
96
+ xml = Nokogiri::XML(storage_pool.xml_desc)
97
+ storage_prefix = xml.xpath("/pool/target/path").inner_text.to_s + '/'
98
+ end
79
99
 
80
100
  @disks.each do |disk|
81
101
  disk[:path] ||= _disk_name(@name, disk)
@@ -88,11 +108,13 @@ module VagrantPlugins
88
108
 
89
109
  disk[:absolute_path] = storage_prefix + disk[:path]
90
110
 
91
- if env[:libvirt_compute].volumes.all.select {|x| x.name == disk[:name] }.empty?
111
+ if env[:machine].provider.driver.connection.volumes.select do |x|
112
+ x.name == disk[:name] && x.pool_name == @storage_pool_name
113
+ end.empty?
92
114
  # make the disk. equivalent to:
93
115
  # qemu-img create -f qcow2 <path> 5g
94
116
  begin
95
- env[:libvirt_compute].volumes.create(
117
+ env[:machine].provider.driver.connection.volumes.create(
96
118
  name: disk[:name],
97
119
  format_type: disk[:type],
98
120
  path: disk[:absolute_path],
@@ -114,9 +136,13 @@ module VagrantPlugins
114
136
  env[:ui].info(" -- Domain type: #{@domain_type}")
115
137
  env[:ui].info(" -- Cpus: #{@cpus}")
116
138
  env[:ui].info(" -- Memory: #{@memory_size / 1024}M")
117
- env[:ui].info(" -- Base box: #{env[:machine].box.name}")
139
+ env[:ui].info(" -- Management MAC: #{@management_network_mac}")
140
+ env[:ui].info(" -- Loader: #{@loader}")
141
+ if env[:machine].box
142
+ env[:ui].info(" -- Base box: #{env[:machine].box.name}")
143
+ end
118
144
  env[:ui].info(" -- Storage pool: #{@storage_pool_name}")
119
- env[:ui].info(" -- Image: #{@domain_volume_path}")
145
+ env[:ui].info(" -- Image: #{@domain_volume_path} (#{env[:box_virtual_size]}G)")
120
146
  env[:ui].info(" -- Volume Cache: #{@domain_volume_cache}")
121
147
  env[:ui].info(" -- Kernel: #{@kernel}")
122
148
  env[:ui].info(" -- Initrd: #{@initrd}")
@@ -127,7 +153,7 @@ module VagrantPlugins
127
153
  env[:ui].info(" -- Video Type: #{@video_type}")
128
154
  env[:ui].info(" -- Video VRAM: #{@video_vram}")
129
155
  env[:ui].info(" -- Keymap: #{@keymap}")
130
-
156
+
131
157
  @boot_order.each do |device|
132
158
  env[:ui].info(" -- Boot device: #{device}")
133
159
  end
@@ -138,8 +164,8 @@ module VagrantPlugins
138
164
 
139
165
  @disks.each do |disk|
140
166
  msg = " -- Disk(#{disk[:device]}): #{disk[:absolute_path]}"
141
- msg += " (shared. Remove only manualy)" if disk[:allow_existing]
142
- msg += " Not created - using existed." if disk[:preexisting]
167
+ msg += ' (shared. Remove only manually)' if disk[:allow_existing]
168
+ msg += ' Not created - using existed.' if disk[:preexisting]
143
169
  env[:ui].info(msg)
144
170
  end
145
171
 
@@ -150,14 +176,16 @@ module VagrantPlugins
150
176
  @cdroms.each do |cdrom|
151
177
  env[:ui].info(" -- CDROM(#{cdrom[:dev]}): #{cdrom[:path]}")
152
178
  end
153
-
179
+ @inputs.each do |input|
180
+ env[:ui].info(" -- INPUT : type=#{input[:type]}, bus=#{input[:bus]}")
181
+ end
154
182
  env[:ui].info(" -- Command line : #{@cmd_line}")
155
183
 
156
184
  # Create libvirt domain.
157
185
  # Is there a way to tell fog to create new domain with already
158
186
  # existing volume? Use domain creation from template..
159
187
  begin
160
- server = env[:libvirt_compute].servers.create(
188
+ server = env[:machine].provider.driver.connection.servers.create(
161
189
  xml: to_xml('domain'))
162
190
  rescue Fog::Errors::Error => e
163
191
  raise Errors::FogCreateServerError, error_message: e.message
@@ -26,21 +26,21 @@ module VagrantPlugins
26
26
 
27
27
  # Verify the volume doesn't exist already.
28
28
  domain_volume = ProviderLibvirt::Util::Collection.find_matching(
29
- env[:libvirt_compute].volumes.all, @name)
29
+ env[:machine].provider.driver.connection.volumes.all, @name)
30
30
  raise Errors::DomainVolumeExists if domain_volume
31
31
 
32
32
  # Get path to backing image - box volume.
33
33
  box_volume = ProviderLibvirt::Util::Collection.find_matching(
34
- env[:libvirt_compute].volumes.all, env[:box_volume_name])
34
+ env[:machine].provider.driver.connection.volumes.all, env[:box_volume_name])
35
35
  @backing_file = box_volume.path
36
36
 
37
- # Virtual size of image. Same as box image size.
38
- @capacity = env[:machine].box.metadata['virtual_size'] #G
37
+ # Virtual size of image. Take value worked out by HandleBoxImage
38
+ @capacity = env[:box_virtual_size] #G
39
39
 
40
40
  # Create new volume from xml template. Fog currently doesn't support
41
41
  # volume snapshots directly.
42
42
  begin
43
- domain_volume = env[:libvirt_compute].volumes.create(
43
+ domain_volume = env[:machine].provider.driver.connection.volumes.create(
44
44
  :xml => to_xml('volume_snapshot'),
45
45
  :pool_name => config.storage_pool_name)
46
46
  rescue Fog::Errors::Error => e
@@ -19,13 +19,14 @@ module VagrantPlugins
19
19
  @management_network_name = env[:machine].provider_config.management_network_name
20
20
  config = env[:machine].provider_config
21
21
  @nic_model_type = config.nic_model_type
22
+ @nic_adapter_count = config.nic_adapter_count
22
23
  @app = app
23
24
  end
24
25
 
25
26
  def call(env)
26
27
  # Get domain first.
27
28
  begin
28
- domain = env[:libvirt_compute].client.lookup_domain_by_uuid(
29
+ domain = env[:machine].provider.driver.connection.client.lookup_domain_by_uuid(
29
30
  env[:machine].id.to_s)
30
31
  rescue => e
31
32
  raise Errors::NoDomainError,
@@ -36,7 +37,6 @@ module VagrantPlugins
36
37
  adapters = []
37
38
 
38
39
  # Vagrant gives you adapter 0 by default
39
-
40
40
  # Assign interfaces to slots.
41
41
  configured_networks(env, @logger).each do |options|
42
42
 
@@ -60,7 +60,7 @@ module VagrantPlugins
60
60
  # We have slot for interface, fill it with interface configuration.
61
61
  adapters[free_slot] = options
62
62
  adapters[free_slot][:network_name] = interface_network(
63
- env[:libvirt_compute].client, adapters[free_slot])
63
+ env[:machine].provider.driver.connection.client, adapters[free_slot])
64
64
  end
65
65
 
66
66
  # Create each interface as new domain device.
@@ -70,7 +70,6 @@ module VagrantPlugins
70
70
  @mac = iface_configuration.fetch(:mac, false)
71
71
  @model_type = iface_configuration.fetch(:model_type, @nic_model_type)
72
72
  template_name = 'interface'
73
-
74
73
  # Configuration for public interfaces which use the macvtap driver
75
74
  if iface_configuration[:iface_type] == :public_network
76
75
  @device = iface_configuration.fetch(:dev, 'eth0')
@@ -80,8 +79,30 @@ module VagrantPlugins
80
79
  template_name = 'public_interface'
81
80
  @logger.info("Setting up public interface using device #{@device} in mode #{@mode}")
82
81
  @ovs = iface_configuration.fetch(:ovs, false)
82
+ # configuration for udp or tcp tunnel interfaces (p2p conn btwn guest OSes)
83
+ elsif iface_configuration.fetch(:tunnel_type, nil)
84
+ @type = iface_configuration.fetch(:tunnel_type)
85
+ @tunnel_port = iface_configuration.fetch(:tunnel_port, nil)
86
+ raise Errors::TunnelPortNotDefined if @tunnel_port.nil?
87
+ if @type == 'udp'
88
+ # default udp tunnel source to 127.0.0.1
89
+ @udp_tunnel_local_ip = iface_configuration.fetch(:tunnel_local_ip, '127.0.0.1')
90
+ @udp_tunnel_local_port = iface_configuration.fetch(:tunnel_local_port)
91
+ end
92
+ # default mcast tunnel to 239.255.1.1. Web search says this
93
+ # 239.255.x.x is a safe range to use for general use mcast
94
+ if @type == 'mcast'
95
+ default_ip = '239.255.1.1'
96
+ else
97
+ default_ip = '127.0.0.1'
98
+ end
99
+ @tunnel_ip = iface_configuration.fetch(:tunnel_address, default_ip)
100
+ @model_type = iface_configuration.fetch(:model_type, @nic_model_type)
101
+ template_name = 'tunnel_interface'
102
+ @logger.info("Setting up #{@type} tunnel interface using #{@tunnel_ip} port #{@tunnel_port}")
83
103
  end
84
104
 
105
+
85
106
  message = "Creating network interface eth#{@iface_number}"
86
107
  message << " connected to network #{@network_name}."
87
108
  if @mac
@@ -96,58 +117,83 @@ module VagrantPlugins
96
117
  raise Errors::AttachDeviceError,
97
118
  :error_message => e.message
98
119
  end
120
+
121
+ # Re-read the network configuration and grab the MAC address
122
+ unless @mac
123
+ xml = Nokogiri::XML(domain.xml_desc)
124
+ if iface_configuration[:iface_type] == :public_network
125
+ if @type == 'direct'
126
+ @mac = xml.xpath("/domain/devices/interface[source[@dev='#{@device}']]/mac/@address")
127
+ else
128
+ @mac = xml.xpath("/domain/devices/interface[source[@bridge='#{@device}']]/mac/@address")
129
+ end
130
+ else
131
+ @mac = xml.xpath("/domain/devices/interface[source[@network='#{@network_name}']]/mac/@address")
132
+ end
133
+ iface_configuration[:mac] = @mac.to_s
134
+ end
99
135
  end
100
136
 
101
137
  # Continue the middleware chain.
102
138
  @app.call(env)
103
139
 
104
- # Configure interfaces that user requested. Machine should be up and
105
- # running now.
106
- networks_to_configure = []
107
-
108
- adapters.each_with_index do |options, slot_number|
109
- # Skip configuring the management network, which is on the first interface.
110
- # It's used for provisioning and it has to be available during provisioning,
111
- # ifdown command is not acceptable here.
112
- next if slot_number == 0
113
- next if options[:auto_config] === false
114
- @logger.debug "Configuring interface slot_number #{slot_number} options #{options}"
115
-
116
- network = {
117
- :interface => slot_number,
118
- :use_dhcp_assigned_default_route => options[:use_dhcp_assigned_default_route],
119
- #:mac => ...,
120
- }
121
-
122
- if options[:ip]
140
+
141
+ if env[:machine].box
142
+ # Configure interfaces that user requested. Machine should be up and
143
+ # running now.
144
+ networks_to_configure = []
145
+
146
+ adapters.each_with_index do |options, slot_number|
147
+ # Skip configuring the management network, which is on the first interface.
148
+ # It's used for provisioning and it has to be available during provisioning,
149
+ # ifdown command is not acceptable here.
150
+ next if slot_number == 0
151
+ next if options[:auto_config] === false
152
+ @logger.debug "Configuring interface slot_number #{slot_number} options #{options}"
153
+
123
154
  network = {
124
- :type => :static,
125
- :ip => options[:ip],
126
- :netmask => options[:netmask],
127
- }.merge(network)
128
- else
129
- network[:type] = :dhcp
155
+ :interface => slot_number,
156
+ :use_dhcp_assigned_default_route => options[:use_dhcp_assigned_default_route],
157
+ :mac_address => options[:mac],
158
+ }
159
+
160
+ if options[:ip]
161
+ network = {
162
+ :type => :static,
163
+ :ip => options[:ip],
164
+ :netmask => options[:netmask],
165
+ }.merge(network)
166
+ else
167
+ network[:type] = :dhcp
168
+ end
169
+
170
+ # do not run configure_networks for tcp tunnel interfaces
171
+ next if options.fetch(:tunnel_type, nil)
172
+
173
+ networks_to_configure << network
130
174
  end
131
175
 
132
- networks_to_configure << network
133
- end
176
+ env[:ui].info I18n.t('vagrant.actions.vm.network.configuring')
177
+ env[:machine].guest.capability(
178
+ :configure_networks, networks_to_configure)
134
179
 
135
- env[:ui].info I18n.t('vagrant.actions.vm.network.configuring')
136
- env[:machine].guest.capability(
137
- :configure_networks, networks_to_configure)
180
+ end
138
181
  end
139
182
 
140
183
  private
141
184
 
142
- def find_empty(array, start=0, stop=8)
185
+ def find_empty(array, start=0, stop=@nic_adapter_count)
143
186
  (start..stop).each do |i|
144
- return i if !array[i]
187
+ return i unless array[i]
145
188
  end
146
189
  return nil
147
190
  end
148
191
 
149
192
  # Return network name according to interface options.
150
193
  def interface_network(libvirt_client, options)
194
+ # no need to get interface network for tcp tunnel config
195
+ return 'tunnel_interface' if options.fetch(:tunnel_type, nil)
196
+
151
197
  if options[:network_name]
152
198
  @logger.debug "Found network by name"
153
199
  return options[:network_name]
@@ -23,7 +23,7 @@ module VagrantPlugins
23
23
 
24
24
  @available_networks = []
25
25
  @options = {}
26
- @libvirt_client = env[:libvirt_compute].client
26
+ @libvirt_client = env[:machine].provider.driver.connection.client
27
27
  end
28
28
 
29
29
  def call(env)
@@ -35,7 +35,8 @@ module VagrantPlugins
35
35
  # available, create it if possible. Otherwise raise an error.
36
36
  configured_networks(env, @logger).each do |options|
37
37
  # Only need to create private networks
38
- next if options[:iface_type] != :private_network
38
+ next if options[:iface_type] != :private_network ||
39
+ options.fetch(:tunnel_type, nil)
39
40
  @logger.debug "Searching for network with options #{options}"
40
41
 
41
42
  # should fix other methods so this doesn't have to be instance var
@@ -45,7 +46,7 @@ module VagrantPlugins
45
46
  # list is used throughout this class and should be easier to
46
47
  # process than libvirt API calls.
47
48
  @available_networks = libvirt_networks(
48
- env[:libvirt_compute].client)
49
+ env[:machine].provider.driver.connection.client)
49
50
 
50
51
  # Prepare a hash describing network for this specific interface.
51
52
  @interface_network = {
@@ -62,15 +63,16 @@ module VagrantPlugins
62
63
 
63
64
  if @options[:ip]
64
65
  handle_ip_option(env)
65
- # in vagrant 1.2.3 and later it is not possible to take this branch
66
- # because cannot have name without ip
67
- # https://github.com/mitchellh/vagrant/commit/cf2f6da4dbcb4f57c9cdb3b94dcd0bba62c5f5fd
66
+ elsif @options[:type].to_s == 'dhcp'
67
+ handle_dhcp_private_network(env)
68
68
  elsif @options[:network_name]
69
- handle_network_name_option
69
+ handle_network_name_option(env)
70
+ else
71
+ raise Errors::CreateNetworkError, error_message: @options
70
72
  end
71
73
 
72
- autostart_network if !@interface_network[:autostart]
73
- activate_network if !@interface_network[:active]
74
+ autostart_network if @interface_network[:autostart]
75
+ activate_network unless @interface_network[:active]
74
76
  end
75
77
  end
76
78
 
@@ -79,22 +81,21 @@ module VagrantPlugins
79
81
 
80
82
  private
81
83
 
84
+ def lookup_network_by_ip(ip)
85
+ @logger.debug "looking up network with ip == #{ip}"
86
+ @available_networks.find { |network| network[:network_address] == ip }
87
+ end
88
+
82
89
  # Return hash of network for specified name, or nil if not found.
83
90
  def lookup_network_by_name(network_name)
84
91
  @logger.debug "looking up network named #{network_name}"
85
- @available_networks.each do |network|
86
- return network if network[:name] == network_name
87
- end
88
- nil
92
+ @available_networks.find { |network| network[:name] == network_name }
89
93
  end
90
94
 
91
95
  # Return hash of network for specified bridge, or nil if not found.
92
96
  def lookup_bridge_by_name(bridge_name)
93
97
  @logger.debug "looking up bridge named #{bridge_name}"
94
- @available_networks.each do |network|
95
- return network if network[:bridge_name] == bridge_name
96
- end
97
- nil
98
+ @available_networks.find { |network| network[:bridge_name] == bridge_name }
98
99
  end
99
100
 
100
101
  # Throw an error if dhcp setting for an existing network does not
@@ -114,28 +115,30 @@ module VagrantPlugins
114
115
  # Handle only situations, when ip is specified. Variables @options and
115
116
  # @available_networks should be filled before calling this function.
116
117
  def handle_ip_option(env)
117
- return if !@options[:ip]
118
+ return unless @options[:ip]
119
+ net_address = nil
120
+ unless @options[:forward_mode] == 'veryisolated'
121
+ net_address = network_address(@options[:ip], @options[:netmask])
122
+
123
+ # Set IP address of network (actually bridge). It will be used as
124
+ # gateway address for machines connected to this network.
125
+ @interface_network[:ip_address] = get_host_ip_addr(net_address)
126
+ end
118
127
 
119
- net_address = network_address(@options[:ip], @options[:netmask])
120
128
  @interface_network[:network_address] = net_address
121
129
 
122
- # Set IP address of network (actually bridge). It will be used as
123
- # gateway address for machines connected to this network.
124
- net = IPAddr.new(net_address)
125
- # Default to first address (after network name)
126
- @interface_network[:ip_address] = @options[:host_ip].nil? ? net.to_range.begin.succ : IPAddr.new(@options[:host_ip])
127
-
128
- # Is there an available network matching to configured ip
129
- # address?
130
- @available_networks.each do |available_network|
131
- if available_network[:network_address] == \
132
- @interface_network[:network_address]
133
- @interface_network = available_network
134
- @logger.debug "found existing network by ip, values are"
135
- @logger.debug @interface_network
136
- break
137
- end
130
+ # if network is veryisolated, search by name
131
+ if @options[:libvirt__forward_mode] == "veryisolated"
132
+ network = lookup_network_by_name(@options[:network_name])
133
+ elsif net_address
134
+ # otherwise, search by ip (if set)
135
+ network = lookup_network_by_ip(net_address)
136
+ else
137
+ # leaving this here to mimic prior behavior. If we get
138
+ # here, something's probably broken.
139
+ network = lookup_network_by_name(@options[:network_name])
138
140
  end
141
+ @interface_network = network if network
139
142
 
140
143
  if @interface_network[:created]
141
144
  verify_dhcp
@@ -167,7 +170,7 @@ module VagrantPlugins
167
170
  end
168
171
 
169
172
  # Do we need to create new network?
170
- if !@interface_network[:created]
173
+ unless @interface_network[:created]
171
174
 
172
175
  # TODO: stop after some loops. Don't create infinite loops.
173
176
 
@@ -188,17 +191,7 @@ module VagrantPlugins
188
191
  end
189
192
 
190
193
  # Generate a unique name for network bridge.
191
- count = 0
192
- while @interface_network[:bridge_name].nil?
193
- @logger.debug "generating name for bridge"
194
- bridge_name = 'virbr'
195
- bridge_name << count.to_s
196
- count += 1
197
-
198
- next if lookup_bridge_by_name(bridge_name)
199
-
200
- @interface_network[:bridge_name] = bridge_name
201
- end
194
+ @interface_network[:bridge_name] = generate_bridge_name
202
195
 
203
196
  # Create a private network.
204
197
  create_private_network(env)
@@ -208,16 +201,68 @@ module VagrantPlugins
208
201
  # Handle network_name option, if ip was not specified. Variables
209
202
  # @options and @available_networks should be filled before calling this
210
203
  # function.
211
- def handle_network_name_option
212
- return if @options[:ip] || !@options[:network_name]
204
+ def handle_network_name_option(env)
205
+ return if @options[:ip] || \
206
+ !@options[:network_name] || \
207
+ !@options[:libvirt__forward_mode] == "veryisolated"
208
+
209
+ network = lookup_network_by_name(@options[:network_name])
210
+ @interface_network = network if network
213
211
 
214
- @interface_network = lookup_network_by_name(@options[:network_name])
215
- if !@interface_network
212
+ # if this interface has a network address, something's wrong.
213
+ if @interface_network[:network_address]
216
214
  raise Errors::NetworkNotAvailableError,
217
215
  network_name: @options[:network_name]
218
- else
219
- verify_dhcp
220
216
  end
217
+
218
+ # Do we need to create new network?
219
+ unless @interface_network[:created]
220
+ @interface_network[:name] = @options[:network_name]
221
+
222
+ # Generate a unique name for network bridge.
223
+ @interface_network[:bridge_name] = generate_bridge_name
224
+
225
+ # Create a private network.
226
+ create_private_network(env)
227
+ end
228
+ end
229
+
230
+ def handle_dhcp_private_network(env)
231
+ net_address = '172.28.128.0'
232
+ network = lookup_network_by_ip(net_address)
233
+ @interface_network = network if network
234
+
235
+ # Do we need to create new network?
236
+ unless @interface_network[:created]
237
+ @interface_network[:name] = 'vagrant-private-dhcp'
238
+ @interface_network[:network_address] = net_address
239
+
240
+ # Set IP address of network (actually bridge). It will be used as
241
+ # gateway address for machines connected to this network.
242
+ @interface_network[:ip_address] = get_host_ip_addr(net_address)
243
+
244
+ # Generate a unique name for network bridge.
245
+ @interface_network[:bridge_name] = generate_bridge_name
246
+
247
+ # Create a private network.
248
+ create_private_network(env)
249
+ end
250
+ end
251
+
252
+ # Return provided address or first address of network otherwise
253
+ def get_host_ip_addr(network)
254
+ @options[:host_ip] ? IPAddr.new(@options[:host_ip]) : IPAddr.new(network).succ
255
+ end
256
+
257
+ # Return the first available virbr interface name
258
+ def generate_bridge_name
259
+ @logger.debug "generating name for bridge"
260
+ count = 0
261
+ while lookup_bridge_by_name(bridge_name = "virbr#{count}")
262
+ count += 1
263
+ end
264
+ @logger.debug "found available bridge name #{bridge_name}"
265
+ bridge_name
221
266
  end
222
267
 
223
268
  def create_private_network(env)
@@ -235,7 +280,7 @@ module VagrantPlugins
235
280
  # Find out DHCP addresses pool range.
236
281
  network_address = "#{@interface_network[:network_address]}/"
237
282
  network_address << "#{@interface_network[:netmask]}"
238
- net = IPAddr.new(network_address)
283
+ net = @interface_network[:network_address] ? IPAddr.new(network_address) : nil
239
284
 
240
285
  # First is address of network, second is gateway (by default).
241
286
  # So start the range two addresses after network address by default.