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.
- checksums.yaml +4 -4
- data/lib/vagrant-vmware-desktop.rb +190 -0
- data/lib/vagrant-vmware-desktop/action.rb +442 -0
- data/lib/vagrant-vmware-desktop/action/base_mac_to_ip.rb +55 -0
- data/lib/vagrant-vmware-desktop/action/boot.rb +26 -0
- data/lib/vagrant-vmware-desktop/action/check_existing_network.rb +35 -0
- data/lib/vagrant-vmware-desktop/action/check_vmware.rb +28 -0
- data/lib/vagrant-vmware-desktop/action/checkpoint.rb +86 -0
- data/lib/vagrant-vmware-desktop/action/clear_shared_folders.rb +25 -0
- data/lib/vagrant-vmware-desktop/action/common.rb +16 -0
- data/lib/vagrant-vmware-desktop/action/compatibility.rb +36 -0
- data/lib/vagrant-vmware-desktop/action/created.rb +20 -0
- data/lib/vagrant-vmware-desktop/action/destroy.rb +32 -0
- data/lib/vagrant-vmware-desktop/action/discard_suspended_state.rb +32 -0
- data/lib/vagrant-vmware-desktop/action/export.rb +29 -0
- data/lib/vagrant-vmware-desktop/action/fix_old_machine_id.rb +29 -0
- data/lib/vagrant-vmware-desktop/action/forward_ports.rb +110 -0
- data/lib/vagrant-vmware-desktop/action/halt.rb +27 -0
- data/lib/vagrant-vmware-desktop/action/import.rb +138 -0
- data/lib/vagrant-vmware-desktop/action/machine_lock.rb +26 -0
- data/lib/vagrant-vmware-desktop/action/message_already_running.rb +18 -0
- data/lib/vagrant-vmware-desktop/action/message_not_created.rb +18 -0
- data/lib/vagrant-vmware-desktop/action/message_not_running.rb +18 -0
- data/lib/vagrant-vmware-desktop/action/network.rb +339 -0
- data/lib/vagrant-vmware-desktop/action/package_vagrantfile.rb +46 -0
- data/lib/vagrant-vmware-desktop/action/prepare_forwarded_port_collision_params.rb +28 -0
- data/lib/vagrant-vmware-desktop/action/prepare_nfs_settings.rb +43 -0
- data/lib/vagrant-vmware-desktop/action/prepare_synced_folder_cleanup.rb +19 -0
- data/lib/vagrant-vmware-desktop/action/prune_forwarded_ports.rb +30 -0
- data/lib/vagrant-vmware-desktop/action/prune_nfs_exports.rb +22 -0
- data/lib/vagrant-vmware-desktop/action/running.rb +20 -0
- data/lib/vagrant-vmware-desktop/action/set_display_name.rb +37 -0
- data/lib/vagrant-vmware-desktop/action/share_folders.rb +97 -0
- data/lib/vagrant-vmware-desktop/action/snapshot_delete.rb +26 -0
- data/lib/vagrant-vmware-desktop/action/snapshot_restore.rb +26 -0
- data/lib/vagrant-vmware-desktop/action/snapshot_save.rb +26 -0
- data/lib/vagrant-vmware-desktop/action/suspend.rb +26 -0
- data/lib/vagrant-vmware-desktop/action/suspended.rb +24 -0
- data/lib/vagrant-vmware-desktop/action/vmx_modify.rb +39 -0
- data/lib/vagrant-vmware-desktop/action/wait_for_address.rb +31 -0
- data/lib/vagrant-vmware-desktop/action/wait_for_communicator_compat.rb +32 -0
- data/lib/vagrant-vmware-desktop/action/wait_for_vmx_halt.rb +35 -0
- data/lib/vagrant-vmware-desktop/cap/disk.rb +287 -0
- data/lib/vagrant-vmware-desktop/cap/provider.rb +37 -0
- data/lib/vagrant-vmware-desktop/cap/snapshot.rb +41 -0
- data/lib/vagrant-vmware-desktop/checkpoint_client.rb +203 -0
- data/lib/vagrant-vmware-desktop/config.rb +377 -0
- data/lib/vagrant-vmware-desktop/constants.rb +16 -0
- data/lib/vagrant-vmware-desktop/driver.rb +15 -0
- data/lib/vagrant-vmware-desktop/driver/base.rb +1356 -0
- data/lib/vagrant-vmware-desktop/errors.rb +342 -0
- data/lib/vagrant-vmware-desktop/guest_cap/linux/mount_vmware_shared_folder.rb +158 -0
- data/lib/vagrant-vmware-desktop/guest_cap/linux/verify_vmware_hgfs.rb +27 -0
- data/lib/vagrant-vmware-desktop/helper/lock.rb +26 -0
- data/lib/vagrant-vmware-desktop/helper/routing_table.rb +182 -0
- data/lib/vagrant-vmware-desktop/helper/vagrant_utility.rb +185 -0
- data/lib/vagrant-vmware-desktop/plugin.rb +148 -0
- data/lib/vagrant-vmware-desktop/provider.rb +96 -0
- data/lib/vagrant-vmware-desktop/setup_plugin.rb +24 -0
- data/lib/vagrant-vmware-desktop/synced_folder.rb +93 -0
- data/locales/en.yml +634 -0
- 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
|