vagrant-vmware-desktop 0.0.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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