vagrant-vmware-desktop 0.0.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/lib/vagrant-vmware-desktop.rb +190 -0
  3. data/lib/vagrant-vmware-desktop/action.rb +442 -0
  4. data/lib/vagrant-vmware-desktop/action/base_mac_to_ip.rb +55 -0
  5. data/lib/vagrant-vmware-desktop/action/boot.rb +26 -0
  6. data/lib/vagrant-vmware-desktop/action/check_existing_network.rb +35 -0
  7. data/lib/vagrant-vmware-desktop/action/check_vmware.rb +28 -0
  8. data/lib/vagrant-vmware-desktop/action/checkpoint.rb +86 -0
  9. data/lib/vagrant-vmware-desktop/action/clear_shared_folders.rb +25 -0
  10. data/lib/vagrant-vmware-desktop/action/common.rb +16 -0
  11. data/lib/vagrant-vmware-desktop/action/compatibility.rb +36 -0
  12. data/lib/vagrant-vmware-desktop/action/created.rb +20 -0
  13. data/lib/vagrant-vmware-desktop/action/destroy.rb +32 -0
  14. data/lib/vagrant-vmware-desktop/action/discard_suspended_state.rb +32 -0
  15. data/lib/vagrant-vmware-desktop/action/export.rb +29 -0
  16. data/lib/vagrant-vmware-desktop/action/fix_old_machine_id.rb +29 -0
  17. data/lib/vagrant-vmware-desktop/action/forward_ports.rb +110 -0
  18. data/lib/vagrant-vmware-desktop/action/halt.rb +27 -0
  19. data/lib/vagrant-vmware-desktop/action/import.rb +138 -0
  20. data/lib/vagrant-vmware-desktop/action/machine_lock.rb +26 -0
  21. data/lib/vagrant-vmware-desktop/action/message_already_running.rb +18 -0
  22. data/lib/vagrant-vmware-desktop/action/message_not_created.rb +18 -0
  23. data/lib/vagrant-vmware-desktop/action/message_not_running.rb +18 -0
  24. data/lib/vagrant-vmware-desktop/action/network.rb +339 -0
  25. data/lib/vagrant-vmware-desktop/action/package_vagrantfile.rb +46 -0
  26. data/lib/vagrant-vmware-desktop/action/prepare_forwarded_port_collision_params.rb +28 -0
  27. data/lib/vagrant-vmware-desktop/action/prepare_nfs_settings.rb +43 -0
  28. data/lib/vagrant-vmware-desktop/action/prepare_synced_folder_cleanup.rb +19 -0
  29. data/lib/vagrant-vmware-desktop/action/prune_forwarded_ports.rb +30 -0
  30. data/lib/vagrant-vmware-desktop/action/prune_nfs_exports.rb +22 -0
  31. data/lib/vagrant-vmware-desktop/action/running.rb +20 -0
  32. data/lib/vagrant-vmware-desktop/action/set_display_name.rb +37 -0
  33. data/lib/vagrant-vmware-desktop/action/share_folders.rb +97 -0
  34. data/lib/vagrant-vmware-desktop/action/snapshot_delete.rb +26 -0
  35. data/lib/vagrant-vmware-desktop/action/snapshot_restore.rb +26 -0
  36. data/lib/vagrant-vmware-desktop/action/snapshot_save.rb +26 -0
  37. data/lib/vagrant-vmware-desktop/action/suspend.rb +26 -0
  38. data/lib/vagrant-vmware-desktop/action/suspended.rb +24 -0
  39. data/lib/vagrant-vmware-desktop/action/vmx_modify.rb +39 -0
  40. data/lib/vagrant-vmware-desktop/action/wait_for_address.rb +31 -0
  41. data/lib/vagrant-vmware-desktop/action/wait_for_communicator_compat.rb +32 -0
  42. data/lib/vagrant-vmware-desktop/action/wait_for_vmx_halt.rb +35 -0
  43. data/lib/vagrant-vmware-desktop/cap/disk.rb +287 -0
  44. data/lib/vagrant-vmware-desktop/cap/provider.rb +37 -0
  45. data/lib/vagrant-vmware-desktop/cap/snapshot.rb +41 -0
  46. data/lib/vagrant-vmware-desktop/checkpoint_client.rb +203 -0
  47. data/lib/vagrant-vmware-desktop/config.rb +377 -0
  48. data/lib/vagrant-vmware-desktop/constants.rb +16 -0
  49. data/lib/vagrant-vmware-desktop/driver.rb +15 -0
  50. data/lib/vagrant-vmware-desktop/driver/base.rb +1356 -0
  51. data/lib/vagrant-vmware-desktop/errors.rb +342 -0
  52. data/lib/vagrant-vmware-desktop/guest_cap/linux/mount_vmware_shared_folder.rb +158 -0
  53. data/lib/vagrant-vmware-desktop/guest_cap/linux/verify_vmware_hgfs.rb +27 -0
  54. data/lib/vagrant-vmware-desktop/helper/lock.rb +26 -0
  55. data/lib/vagrant-vmware-desktop/helper/routing_table.rb +182 -0
  56. data/lib/vagrant-vmware-desktop/helper/vagrant_utility.rb +185 -0
  57. data/lib/vagrant-vmware-desktop/plugin.rb +148 -0
  58. data/lib/vagrant-vmware-desktop/provider.rb +96 -0
  59. data/lib/vagrant-vmware-desktop/setup_plugin.rb +24 -0
  60. data/lib/vagrant-vmware-desktop/synced_folder.rb +93 -0
  61. data/locales/en.yml +634 -0
  62. metadata +71 -17
@@ -0,0 +1,110 @@
1
+ require "json"
2
+ require "set"
3
+
4
+ require "log4r"
5
+
6
+ require "vagrant/util/scoped_hash_override"
7
+
8
+ module HashiCorp
9
+ module VagrantVMwareDesktop
10
+ module Action
11
+ # This does NAT port forwarding on the VMware VM.
12
+ class ForwardPorts
13
+ include Common
14
+ include Vagrant::Util::ScopedHashOverride
15
+
16
+ def initialize(app, env)
17
+ @app = app
18
+ @logger = Log4r::Logger.new("hashicorp::provider::vmware::forward_ports")
19
+ end
20
+
21
+ def call(env)
22
+ # Build the definitions for our driver.
23
+ @logger.debug("Building up ports to forward...")
24
+ definitions = []
25
+ env[:machine].config.vm.networks.each do |type, options|
26
+ # Ignore anything but forwarded ports
27
+ next if type != :forwarded_port
28
+ options = scoped_hash_override(options, :vmware)
29
+
30
+ # Ignore disabled ports
31
+ next if options[:disabled]
32
+
33
+ definitions << {
34
+ device: env[:machine].provider_config.nat_device,
35
+ guest_port: options[:guest],
36
+ host_port: options[:host],
37
+ protocol: options[:protocol],
38
+ }
39
+ end
40
+
41
+ # Make sure we're not conflicting with any of the NAT forwarded
42
+ # ports. Note that port collision detection/handling should fix
43
+ # any collisions at a higher level, so this is more of an ASSERT
44
+ # type statement.
45
+ all_ports = Set.new(env[:machine].provider.driver.all_forwarded_ports)
46
+ all_defined = Set.new(definitions.map { |d| d[:host_port].to_i })
47
+ intersection = all_ports & all_defined
48
+ if !intersection.empty?
49
+ raise Errors::ForwardedPortsCollideWithExistingNAT,
50
+ :ports => intersection.to_a.sort.join(", ")
51
+ end
52
+
53
+ # Set the guest IP on all forwarded ports
54
+ guest_ip = nil
55
+ 5.times do |_|
56
+ guest_ip = env[:machine].provider.driver.read_ip(
57
+ env[:machine].provider_config.enable_vmrun_ip_lookup
58
+ )
59
+ break if guest_ip
60
+ sleep 2
61
+ end
62
+
63
+ if !guest_ip
64
+ raise Errors::ForwardedPortNoGuestIP
65
+ end
66
+
67
+ definitions.each do |fp|
68
+ fp[:guest_ip] = guest_ip
69
+ end
70
+
71
+ # UI
72
+ env[:ui].info(I18n.t("hashicorp.vagrant_vmware_desktop.forwarding_ports"))
73
+ definitions.each do |fp|
74
+ env[:ui].detail(I18n.t(
75
+ "hashicorp.vagrant_vmware_desktop.forward_port_entry",
76
+ :guest_port => fp[:guest_port],
77
+ :host_port => fp[:host_port]))
78
+ end
79
+
80
+ # Forward the ports!
81
+ env[:machine].provider.driver.forward_ports(definitions)
82
+
83
+ # Store the forwarded ports for later
84
+ env[:machine].data_dir.join("forwarded_ports").open("w+") do |f|
85
+ ports = {}
86
+ definitions.each do |fp|
87
+ ports[fp[:host_port].to_i] = fp[:guest_port].to_i
88
+ end
89
+
90
+ f.write(JSON.dump(ports))
91
+ end
92
+
93
+ # Because the network gets restarted when ports are forwarded the
94
+ # guest may see that the network connection has been lost and then
95
+ # regained. NetworkManager will some times see this and drop a
96
+ # current DHCP lease and start the process over again which prevents
97
+ # expected access to the guest. To prevent that, we just wait for a
98
+ # bit until the network is ready.
99
+ port_forward_network_pause = env[:machine].provider_config.port_forward_network_pause.to_i
100
+ if port_forward_network_pause > 0
101
+ env[:ui].info("Pausing for network to stabilize (#{port_forward_network_pause} seconds)")
102
+ sleep(port_forward_network_pause)
103
+ end
104
+
105
+ @app.call(env)
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,27 @@
1
+ require "log4r"
2
+
3
+ module HashiCorp
4
+ module VagrantVMwareDesktop
5
+ module Action
6
+ # This stops the VMware machine.
7
+ class Halt
8
+ include Common
9
+
10
+ def initialize(app, env)
11
+ @app = app
12
+ @logger = Log4r::Logger.new("hashicorp::provider::vmware::halt")
13
+ end
14
+
15
+ def call(env)
16
+ if env[:machine].provider.state.id == :running
17
+ env[:ui].info(I18n.t("hashicorp.vagrant_vmware_desktop.stopping"))
18
+ stop_mode = env[:force_halt] ? "hard" : "soft"
19
+ env[:machine].provider.driver.stop(stop_mode)
20
+ end
21
+
22
+ @app.call(env)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,138 @@
1
+ require "pathname"
2
+ require "securerandom"
3
+
4
+ require "log4r"
5
+
6
+ module HashiCorp
7
+ module VagrantVMwareDesktop
8
+ module Action
9
+ # This class "imports" a VMware machine by copying the proper
10
+ # files over to the VM folder.
11
+ class Import
12
+ include Common
13
+
14
+ def initialize(app, env)
15
+ @app = app
16
+ @logger = Log4r::Logger.new("hashicorp::provider::vmware::import")
17
+ end
18
+
19
+ def call(env)
20
+ # Create the folder to store the VM
21
+ vm_folder = env[:machine].provider_config.clone_directory
22
+ vm_folder ||= env[:machine].data_dir
23
+ if VagrantVMwareDesktop.wsl? && !VagrantVMwareDesktop.wsl_drvfs_path?(vm_folder) # !Vagrant::Util::Platform.wsl_windows_access_bypass?(vm_folder)
24
+ @logger.info("import folder location cannot be used due to file system type (#{vm_folder})")
25
+ vm_folder = File.join(VagrantVMwareDesktop.windows_to_wsl_path(Vagrant::Util::Platform.wsl_windows_appdata_local), "vagrant-vmware-desktop")
26
+ @logger.info("import folder location has been updated to supported location: #{vm_folder}")
27
+ end
28
+ vm_folder = File.expand_path(vm_folder, env[:machine].env.root_path)
29
+ vm_folder = Pathname.new(vm_folder)
30
+ vm_folder.mkpath if !vm_folder.directory?
31
+ vm_folder = vm_folder.realpath
32
+
33
+ # Create a random name for our import. We protect against some
34
+ # weird theoretical realities where this never gets us a unique
35
+ # name.
36
+ found = false
37
+ 10.times do |i|
38
+ temp = vm_folder.join(SecureRandom.uuid)
39
+ if !temp.exist?
40
+ vm_folder = temp
41
+ found = true
42
+ break
43
+ end
44
+ end
45
+ raise Errors::CloneFolderExists if !found
46
+ vm_folder.mkpath
47
+
48
+ # TODO: If cloning, we need to verify the clone machine is not running
49
+
50
+ # Determine the primary VMX file for the box
51
+ vmx_file = nil
52
+ if env[:clone_id]
53
+ vmx_file = Pathname.new(env[:clone_id])
54
+ else
55
+ vmx_file = env[:machine].box.metadata["vmx_file"]
56
+ if vmx_file
57
+ vmx_file = env[:machine].box.directory.join(vmx_file)
58
+ end
59
+
60
+ if !vmx_file
61
+ # Not specified by metadata, attempt to discover VMX file
62
+ @logger.info("VMX file not in metadata, attempting to discover...")
63
+
64
+ env[:machine].box.directory.children(true).each do |child|
65
+ if child.basename.to_s =~ /^(.+?)\.vmx$/
66
+ vmx_file = child
67
+ break
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ # If we don't have a VMX file, it is an error
74
+ raise Errors::BoxVMXFileNotFound if !vmx_file || !vmx_file.file?
75
+
76
+ # Otherwise, log it out and continue
77
+ @logger.debug("Cloning into: #{vm_folder}")
78
+ @logger.info("VMX file: #{vmx_file}")
79
+
80
+ # Clone the VM
81
+ clone_name = nil
82
+ clone_name = env[:machine].config.vm.clone if env[:clone_id]
83
+ clone_name = env[:machine].box.name if !clone_name
84
+ env[:ui].info(I18n.t(
85
+ "hashicorp.vagrant_vmware_desktop.cloning",
86
+ :name => clone_name))
87
+ env[:machine].id = env[:machine].provider.driver.clone(vmx_file, vm_folder, env[:machine].provider_config.linked_clone).to_s
88
+
89
+ # If we were interrupted, then undo this
90
+ destroy_import(env) if env[:interrupted]
91
+
92
+ # Silence!
93
+ env[:machine].provider.driver.suppress_messages
94
+
95
+ # Copy the SSH key from the clone machine if we can
96
+ if env[:clone_machine]
97
+ key_path = env[:clone_machine].data_dir.join("private_key")
98
+ if key_path.file?
99
+ FileUtils.cp(
100
+ key_path,
101
+ env[:machine].data_dir.join("private_key"))
102
+ end
103
+ end
104
+
105
+ @app.call(env)
106
+ end
107
+
108
+ def recover(env)
109
+ if env[:machine].provider.state.id != :not_created
110
+ # Ignore errors that Vagrant knows about.
111
+ return if env["vagrant.error"].is_a?(Vagrant::Errors::VagrantError)
112
+
113
+ # Return if we already tried to destroyimport
114
+ return if env[:import_destroyed]
115
+
116
+ # Return if we're not supposed to destroy
117
+ return if !env[:destroy_on_error]
118
+
119
+ # Note that we already tried to destroy so we don't infinite loop
120
+ env[:import_destroyed] = true
121
+
122
+ # Undo the import
123
+ destroy_import(env)
124
+ end
125
+ end
126
+
127
+ # This undoes the import by destroying it.
128
+ def destroy_import(env)
129
+ destroy_env = env.dup
130
+ destroy_env.delete(:interrupted)
131
+ destroy_env[:config_validate] = false
132
+ destroy_env[:force_confirm_destroy] = true
133
+ env[:action_runner].run(Action.action_destroy, destroy_env)
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,26 @@
1
+ require "vagrant/action/builtin/lock"
2
+
3
+ module HashiCorp
4
+ module VagrantVMwareDesktop
5
+ module Action
6
+ # This class locks a single machine so that operations can only be done
7
+ # on one machine at a time.
8
+ class MachineLock < Vagrant::Action::Builtin::Lock
9
+ include Common
10
+
11
+ def initialize(app, outer_env)
12
+ options = {}
13
+ options[:path] = lambda do |env|
14
+ env[:machine].data_dir.join("lock")
15
+ end
16
+
17
+ options[:exception] = lambda do |env|
18
+ Errors::SingleMachineLock.new(:machine => env[:machine].name)
19
+ end
20
+
21
+ super(app, outer_env, options)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,18 @@
1
+ module HashiCorp
2
+ module VagrantVMwareDesktop
3
+ module Action
4
+ class MessageAlreadyRunning
5
+ include Common
6
+
7
+ def initialize(app, env)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ env[:ui].info(I18n.t("hashicorp.vagrant_vmware_desktop.already_running"))
13
+ @app.call(env)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ module HashiCorp
2
+ module VagrantVMwareDesktop
3
+ module Action
4
+ class MessageNotCreated
5
+ include Common
6
+
7
+ def initialize(app, env)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ env[:ui].info(I18n.t("hashicorp.vagrant_vmware_desktop.not_created"))
13
+ @app.call(env)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ module HashiCorp
2
+ module VagrantVMwareDesktop
3
+ module Action
4
+ class MessageNotRunning
5
+ include Common
6
+
7
+ def initialize(app, env)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ env[:ui].info(I18n.t("hashicorp.vagrant_vmware_desktop.not_running"))
13
+ @app.call(env)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,339 @@
1
+ require "set"
2
+
3
+ require "log4r"
4
+
5
+ require "vagrant/util/network_ip"
6
+ require "vagrant/util/scoped_hash_override"
7
+
8
+ require "vagrant-vmware-desktop/helper/lock"
9
+ require "vagrant-vmware-desktop/helper/routing_table"
10
+
11
+ module HashiCorp
12
+ module VagrantVMwareDesktop
13
+ module Action
14
+ # This action sets up all the network adapters for the machine and
15
+ # also tells the guest to configure the networks.
16
+ class Network
17
+ include Common
18
+
19
+ include Vagrant::Util::NetworkIP
20
+ include Vagrant::Util::ScopedHashOverride
21
+
22
+ DEFAULT_VMNET_NAT = "vmnet8"
23
+
24
+ def initialize(app, env)
25
+ @app = app
26
+ @logger = Log4r::Logger.new("hashicorp::provider::vmware::network")
27
+ end
28
+
29
+ def call(env)
30
+ # Set this to an ivar so that helper methods have access to it
31
+ @env = env
32
+
33
+ # Get the list of network adapters from the configuration
34
+ network_adapters_config = env[:machine].provider_config.network_adapters.dup
35
+
36
+ # Assign the adapter slot for each high-level network
37
+ available_slots = Set.new(1..8)
38
+ network_adapters_config.each do |slot, _data|
39
+ available_slots.delete(slot)
40
+ end
41
+
42
+ @logger.debug("Available slots for high-level adapters: #{available_slots.inspect}")
43
+ @logger.info("Determining network adapters required for high-level configuration...")
44
+ available_slots = available_slots.to_a.sort
45
+ env[:machine].config.vm.networks.each do |type, options|
46
+ # We only handle private and public networks
47
+ next if type != :private_network && type != :public_network
48
+
49
+ scope_key = "vmware_#{PRODUCT_NAME}".to_sym
50
+ options = scoped_hash_override(options, scope_key)
51
+
52
+ # Figure out the slot that this adapter will go into
53
+ slot = options[:adapter]
54
+ if !slot
55
+ if available_slots.empty?
56
+ raise Errors::NetworkingNoSlotsForHighLevel
57
+ end
58
+
59
+ slot = available_slots.shift
60
+ end
61
+
62
+ # Configure it
63
+ data = nil
64
+ if type == :private_network
65
+ # private_network = hostonly
66
+ data = [:hostonly, options]
67
+ elsif type == :public_network
68
+ # public_network = bridged
69
+ data = [:bridged, options]
70
+ end
71
+
72
+ # Store it!
73
+ @logger.info(" -- Slot #{slot}: #{data[0]}")
74
+ network_adapters_config[slot] = data
75
+ end
76
+
77
+ @logger.info("Determining adapters and compiling network configuration...")
78
+ adapters = []
79
+ networks = []
80
+ network_adapters_config.each do |slot, data|
81
+ type = data[0]
82
+ options = data[1]
83
+
84
+ if slot == 0 && env[:machine].provider_config.nat_device != DEFAULT_VMNET_NAT
85
+ # TODO: what's the device name on windows?
86
+ options[:device] = "/dev/#{env[:machine].provider_config.nat_device}"
87
+ end
88
+
89
+ @logger.info("Slot #{slot}. Type: #{type}")
90
+
91
+ # Get normalized configuration so we can add/scrub values
92
+ config = send("#{type}_config", options)
93
+ @logger.debug("Normalized configuration: #{config.inspect}")
94
+
95
+ # Get the adapter configuration for the driver
96
+ adapter = send("#{type}_adapter", config)
97
+ adapter[:slot] = slot
98
+ adapters << adapter
99
+ @logger.debug("Adapter configuration: #{adapter.inspect}")
100
+
101
+ # Get the network configuration for the guest
102
+ network = send("#{type}_network_config", config)
103
+ network[:auto_config] = config[:auto_config]
104
+ networks << network
105
+ @logger.debug("Network configuration: #{network.inspect}")
106
+ end
107
+
108
+ if !adapters.empty?
109
+ # Modify the VM metadata to add adapters
110
+ @logger.info("Enabling #{adapters.length} adapters...")
111
+ Helper::Lock.lock(env[:machine], "vmware-network") do
112
+ env[:ui].info(I18n.t("hashicorp.vagrant_vmware_desktop.enabling_adapters"))
113
+ env[:machine].provider.driver.setup_adapters(adapters, env[:machine].provider_config.allowlist_verified)
114
+ end
115
+ end
116
+
117
+ @app.call(env)
118
+
119
+ if !networks.empty?
120
+ # Assign interface numbers to the networks
121
+ assign_interface_numbers(networks, adapters)
122
+
123
+ networks_to_configure = networks.select { |n| n[:auto_config] }
124
+ env[:ui].info(I18n.t("hashicorp.vagrant_vmware_desktop.configuring_networks"))
125
+ env[:machine].guest.capability(:configure_networks, networks_to_configure)
126
+ end
127
+ end
128
+
129
+ def nat_config(options)
130
+ return {
131
+ :auto_config => true,
132
+ :type => :dhcp
133
+ }.merge(options)
134
+ end
135
+
136
+ def nat_adapter(config)
137
+ {
138
+ type: :nat,
139
+ mac_address: config[:mac_address],
140
+ vnet: config[:device]
141
+ }.compact
142
+ end
143
+
144
+ def nat_network_config(config)
145
+ return {
146
+ :type => :dhcp
147
+ }
148
+ end
149
+
150
+ def hostonly_config(options)
151
+ # Get the default configuration built up
152
+ config = {
153
+ :auto_config => true,
154
+ :netmask => "255.255.255.0",
155
+ :type => :dhcp
156
+ }.merge(options || {})
157
+
158
+ if options[:ip]
159
+ # Check if we are using ipv6, which is not supported
160
+ ip = IPAddr.new(options[:ip])
161
+ if ip.ipv6?
162
+ raise Errors::VMNetNoIPV6
163
+ end
164
+
165
+ # We are using static if we have an IP set
166
+ config[:type] = :static
167
+
168
+ # Get the static IP and use the static IP + subnet mask to
169
+ # determine the subnet IP.
170
+ static_ip = config[:ip]
171
+ subnet_ip = network_address(static_ip, config[:netmask])
172
+ config[:subnet_ip] = subnet_ip
173
+
174
+ # Calculate the actual IP of the adapter itself, which is usually
175
+ # just the network address "+ 1" in the last octet
176
+ ip_parts = subnet_ip.split(".").map { |i| i.to_i }
177
+ adapter_ip = ip_parts.dup
178
+ adapter_ip[3] += 1
179
+ config[:adapter_ip] ||= adapter_ip.join(".")
180
+ end
181
+
182
+ # Make sure the type is a symbol
183
+ config[:type] = config[:type].to_sym
184
+
185
+ return config
186
+ end
187
+
188
+ def hostonly_adapter(config)
189
+ # If we're just doing normal DHCP, then we just connect to the
190
+ # basic default adapter.
191
+ if config[:type] == :dhcp
192
+ return {
193
+ :type => :hostonly
194
+ }
195
+ end
196
+
197
+ # Otherwise we want a static IP. Start by trying to find
198
+ # an existing network that matches our needs.
199
+ vmnet = nil
200
+ @env[:machine].provider.driver.read_vmnet_devices.each do |device|
201
+ if device[:hostonly_subnet] == config[:subnet_ip]
202
+ @logger.info("Found matching vmnet device: #{device[:name]}")
203
+ vmnet = device
204
+ break
205
+ end
206
+ end
207
+
208
+ # Check for collisions by checking for if there is another device
209
+ # that the IP would route to. The basic logic is: if there is
210
+ # a device, and it is NOT the vmnet we care about, then it
211
+ # is an error.
212
+ @logger.info("Checking for hostonly network collisions...")
213
+ device = routing_table.device_for_route(config[:ip])
214
+ if device
215
+ if !vmnet || device != vmnet[:name]
216
+ # There is a collision with some other networking device.
217
+ raise Errors::NetworkingHostOnlyCollision,
218
+ :device => device,
219
+ :ip => config[:ip]
220
+ end
221
+ end
222
+
223
+ if !vmnet
224
+ @logger.info("No collisions detected, creating new vmnet device.")
225
+ vmnet = @env[:machine].provider.driver.create_vmnet_device(
226
+ :netmask => config[:netmask],
227
+ :subnet_ip => config[:subnet_ip])
228
+ end
229
+
230
+ # Determine MAC address of the adapter
231
+ mac_address = config[:mac]
232
+ mac_address = vmware_mac_format(mac_address) if mac_address
233
+
234
+ # Return a more complex configuration to describe what we need
235
+ return {
236
+ :type => :custom,
237
+ :mac_address => mac_address,
238
+ :vnet => vmnet[:name]
239
+ }
240
+ end
241
+
242
+ def hostonly_network_config(config)
243
+ return {
244
+ :type => config[:type],
245
+ :adapter_ip => config[:adapter_ip],
246
+ :ip => config[:ip],
247
+ :netmask => config[:netmask]
248
+ }
249
+ end
250
+
251
+ def bridged_config(options)
252
+ return {
253
+ :auto_config => true,
254
+ :mac => nil,
255
+ :type => :dhcp
256
+ }.merge(options || {})
257
+ end
258
+
259
+ def bridged_adapter(config)
260
+ mac_address = config[:mac]
261
+ mac_address = vmware_mac_format(mac_address) if mac_address
262
+
263
+ return {
264
+ :type => :bridged,
265
+ :mac_address => mac_address
266
+ }
267
+ end
268
+
269
+ def bridged_network_config(config)
270
+ if config[:ip]
271
+ options = {
272
+ auto_config: true,
273
+ mac: nil,
274
+ netmask: "255.255.255.0",
275
+ }.merge(config)
276
+ options[:type] = :static
277
+ return options
278
+ end
279
+
280
+ return {
281
+ :type => :dhcp
282
+ }
283
+ end
284
+
285
+ #-----------------------------------------------------------------
286
+ # Misc. helpers
287
+ #-----------------------------------------------------------------
288
+ # Assigns the actual interface number of a network based on the
289
+ # enabled NICs on the virtual machine.
290
+ #
291
+ # This interface number is used by the guest to configure the
292
+ # NIC on the guest VM.
293
+ #
294
+ # The networks are modified in place by adding an ":interface"
295
+ # field to each.
296
+ def assign_interface_numbers(networks, adapters)
297
+ # First create a mapping of adapter slot to interface number
298
+ # by reading over the existing network adapters.
299
+ slots_in_use = []
300
+ vm_adapters = @env[:machine].provider.driver.read_network_adapters
301
+ vm_adapters.each do |adapter|
302
+ slots_in_use << adapter[:slot].to_i
303
+ end
304
+
305
+ slot_to_interface = {}
306
+ slots_in_use.sort.each_index do |i|
307
+ slot_to_interface[slots_in_use[i]] = i
308
+ end
309
+
310
+ # Make a pass through the adapters to assign the :interface
311
+ # key to each network configuration.
312
+ adapters.each_index do |i|
313
+ adapter = adapters[i]
314
+ network = networks[i]
315
+
316
+ # Figure out the interface number by simple lookup
317
+ network[:interface] = slot_to_interface[adapter[:slot]]
318
+ end
319
+ end
320
+
321
+ # This converts the Vagrant configured MAC address format to
322
+ # a typical MAC address format.
323
+ #
324
+ # @param [String] mac
325
+ # @return [String]
326
+ def vmware_mac_format(mac)
327
+ mac.scan(/.{2}/).join(":")
328
+ end
329
+
330
+ # This is a lazy loaded {Helper::RoutingTable}.
331
+ #
332
+ # @return [Helper::RoutingTable]
333
+ def routing_table
334
+ @routing_table ||= Helper::RoutingTable.new
335
+ end
336
+ end
337
+ end
338
+ end
339
+ end