vagrant-hypervnet 0.1.1
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 +7 -0
- data/Gemfile +16 -0
- data/README.md +54 -0
- data/Rakefile +8 -0
- data/Vagrantfile +104 -0
- data/lib/vagrant-hypervnet/action/disable_builtin_network_configure.rb +39 -0
- data/lib/vagrant-hypervnet/action/network.rb +328 -0
- data/lib/vagrant-hypervnet/action/ssh_server.rb +28 -0
- data/lib/vagrant-hypervnet/action.rb +31 -0
- data/lib/vagrant-hypervnet/cap/linux/nic_mac_addresses.rb +71 -0
- data/lib/vagrant-hypervnet/cap/linux/pre_configure_networks.rb +31 -0
- data/lib/vagrant-hypervnet/cap/vyos/post_configure_networks.rb +45 -0
- data/lib/vagrant-hypervnet/cap/windows/rsync.rb +60 -0
- data/lib/vagrant-hypervnet/cap/windows/sshd.rb +151 -0
- data/lib/vagrant-hypervnet/cap.rb +15 -0
- data/lib/vagrant-hypervnet/config.rb +36 -0
- data/lib/vagrant-hypervnet/driver.rb +197 -0
- data/lib/vagrant-hypervnet/errors.rb +34 -0
- data/lib/vagrant-hypervnet/scripts/add_vm_adapter.ps1 +15 -0
- data/lib/vagrant-hypervnet/scripts/connect_vm_adapter.ps1 +12 -0
- data/lib/vagrant-hypervnet/scripts/get_switch_by_address.ps1 +22 -0
- data/lib/vagrant-hypervnet/scripts/get_switch_by_name.ps1 +17 -0
- data/lib/vagrant-hypervnet/scripts/get_vm_adapters.ps1 +11 -0
- data/lib/vagrant-hypervnet/scripts/new_switch.ps1 +26 -0
- data/lib/vagrant-hypervnet/scripts/remove_vm_adapter.ps1 +9 -0
- data/lib/vagrant-hypervnet/scripts/utils/VagrantMessages/VagrantMessages.psm1 +27 -0
- data/lib/vagrant-hypervnet/version.rb +7 -0
- data/lib/vagrant-hypervnet.rb +89 -0
- data/locales/en.yml +69 -0
- data/sig/vagrant/hypervnet.rbs +6 -0
- data/vagrant-hypervnet.gemspec +26 -0
- metadata +73 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module HyperVNet
|
5
|
+
module Cap
|
6
|
+
module Linux
|
7
|
+
class PreConfigureNetworks
|
8
|
+
extend Vagrant::Util::GuestInspection::Linux
|
9
|
+
|
10
|
+
def self.pre_configure_networks(machine)
|
11
|
+
if netplan?(machine.communicate)
|
12
|
+
yaml = ""
|
13
|
+
machine.communicate.sudo("netplan get 'ethernets'") do |type, data|
|
14
|
+
yaml << data if type == :stdout
|
15
|
+
end
|
16
|
+
ethernets = YAML.load(yaml)
|
17
|
+
ethernets_to_fix = ethernets.select {|k,v| (v["dhcp4"] || v["dhcp6"]) && !v["critical"]}
|
18
|
+
if !ethernets_to_fix.empty?
|
19
|
+
ethernets_to_fix.each do |k,v|
|
20
|
+
machine.communicate.sudo("netplan set 'ethernets.#{k}.critical=true'")
|
21
|
+
end
|
22
|
+
machine.communicate.sudo("netplan apply &")
|
23
|
+
machine.communicate.reset!
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module HyperVNet
|
5
|
+
module Cap
|
6
|
+
module Vyos
|
7
|
+
class PostConfigureNetworks
|
8
|
+
|
9
|
+
@@logger = Log4r::Logger.new("vagrant::hypervnet::guest::vyos::post_configure_networks")
|
10
|
+
|
11
|
+
def self.post_configure_networks(machine)
|
12
|
+
nic_mac_addresses = machine.guest.capability(:nic_mac_addresses)
|
13
|
+
machine.communicate.tap do |comm|
|
14
|
+
commands = "#!/bin/vbash\n"
|
15
|
+
commands << "if [ \"$(id -g -n)\" != 'vyattacfg' ] ; then\n"
|
16
|
+
commands << " exec sg vyattacfg -c \"/bin/vbash $(readlink -f $0) $@\"\n"
|
17
|
+
commands << "fi\n"
|
18
|
+
commands << "source /opt/vyatta/etc/functions/script-template\n"
|
19
|
+
commands << "configure\n"
|
20
|
+
|
21
|
+
nic_mac_addresses.each do |nic|
|
22
|
+
commands << "set interfaces ethernet #{nic[:name]} hw-id '#{nic[:mac_address]}' \n"
|
23
|
+
end
|
24
|
+
|
25
|
+
commands << "commit\n"
|
26
|
+
commands << "save\n"
|
27
|
+
commands << "exit\n"
|
28
|
+
|
29
|
+
@@logger.debug("Commands: \n#{commands}")
|
30
|
+
|
31
|
+
temp = Tempfile.new("vagrant")
|
32
|
+
temp.binmode
|
33
|
+
temp.write(commands)
|
34
|
+
temp.close
|
35
|
+
|
36
|
+
comm.upload(temp.path, "/tmp/vagrant-configure-network")
|
37
|
+
comm.execute("bash /tmp/vagrant-configure-network")
|
38
|
+
comm.execute("rm -f /tmp/vagrant-configure-network")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module HyperVNet
|
6
|
+
module Cap
|
7
|
+
module Windows
|
8
|
+
class RSync
|
9
|
+
|
10
|
+
def self.rsync_installed(machine)
|
11
|
+
machine.communicate.test("rsync -V")
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.rsync_install(machine)
|
15
|
+
if machine.config.hypervnet.install_rsync
|
16
|
+
machine.ui.detail(I18n.t("vagrant_hypervnet.rsync.install"))
|
17
|
+
|
18
|
+
msys2_base_url = "https://repo.msys2.org/distrib/x86_64/"
|
19
|
+
path_registry_key = "Registry::HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\Environment"
|
20
|
+
msys2_url = Net::HTTP.get(URI.parse(msys2_base_url)).scan(/msys2-x86_64-\d+\.exe/)
|
21
|
+
.sort.map{|url| URI.join(msys2_base_url, url)}.last.to_s
|
22
|
+
|
23
|
+
cmds = []
|
24
|
+
cmds += [
|
25
|
+
"Invoke-WebRequest -Uri '#{msys2_url}' -OutFile C:\\msys2.exe",
|
26
|
+
"C:\\msys2.exe install --root 'C:\\MSYS2' --confirm-command",
|
27
|
+
"C:\\msys2\\usr\\bin\\pacman -S rsync --noconfirm",
|
28
|
+
"remove-item 'C:\\msys2.exe'"
|
29
|
+
]
|
30
|
+
cmd = "$path = (Get-ItemProperty -Path '#{path_registry_key}' -Name path).path; "
|
31
|
+
cmd << "$path = \"$path;C:\\MSYS2\\usr\\bin\"; "
|
32
|
+
cmd << "Set-ItemProperty -Path '#{path_registry_key}' -Name path -Value $path"
|
33
|
+
cmds << cmd
|
34
|
+
|
35
|
+
machine.communicate.tap do |comm|
|
36
|
+
cmds.each do |cmd|
|
37
|
+
comm.execute(cmd, shell: :powershell)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
if machine.guest.capability?(:sshd_reload)
|
42
|
+
machine.guest.capability(:sshd_reload)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.rsync_scrub_guestpath( machine, opts )
|
48
|
+
if opts[:guestpath] =~ /^([a-zA-Z]):/
|
49
|
+
opts[:guestpath].gsub( /^([a-zA-Z]):/, '/c/\1' )
|
50
|
+
elsif opts[:guestpath] !~ /^[\/\\][a-zA-Z][\/\\]/
|
51
|
+
"/c/#{opts[:guestpath]}"
|
52
|
+
else
|
53
|
+
opts[:guestpath]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
|
2
|
+
require 'vagrant/util/keypair'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module HyperVNet
|
6
|
+
module Cap
|
7
|
+
module Windows
|
8
|
+
class Sshd
|
9
|
+
|
10
|
+
def self.sshd_installed(machine)
|
11
|
+
machine.communicate.test("Get-Service -Name sshd")
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.sshd_install(machine)
|
15
|
+
machine.ui.detail(I18n.t("vagrant_hypervnet.ssh.install"))
|
16
|
+
|
17
|
+
machine.communicate.sudo("Get-WindowsCapability -Online | ? Name -like 'OpenSSH.Server*' | Add-WindowsCapability -Online",
|
18
|
+
shell: :powershell, elevated: true)
|
19
|
+
|
20
|
+
if machine.config.ssh.insert_key
|
21
|
+
insert = false
|
22
|
+
ssh_info = machine.ssh_info
|
23
|
+
if !ssh_info.nil?
|
24
|
+
insert = ssh_info[:password] && ssh_info[:private_key_path].empty?
|
25
|
+
ssh_info[:private_key_path].each do |pk|
|
26
|
+
if insecure_key?(pk)
|
27
|
+
insert = true
|
28
|
+
machine.ui.detail("\n"+I18n.t("vagrant_hypervnet.ssh.inserting_insecure_detected"))
|
29
|
+
break
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
if insert
|
35
|
+
_pub, priv, openssh = Vagrant::Util::Keypair.create
|
36
|
+
machine.ui.detail("\n"+I18n.t("vagrant_hypervnet.ssh.inserting_random_key"))
|
37
|
+
insert_public_key(machine, openssh)
|
38
|
+
|
39
|
+
# Write out the private key in the data dir so that the
|
40
|
+
# machine automatically picks it up.
|
41
|
+
machine.data_dir.join("private_key").open("w+") do |f|
|
42
|
+
f.write(priv)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Adjust private key file permissions if host provides capability
|
46
|
+
if machine.env.host.capability?(:set_ssh_key_permissions)
|
47
|
+
machine.env.host.capability(:set_ssh_key_permissions, machine.data_dir.join("private_key"))
|
48
|
+
end
|
49
|
+
|
50
|
+
# Remove the old key if it exists
|
51
|
+
machine.ui.detail(I18n.t("vagrant_hypervnet.ssh.inserting_remove_key"))
|
52
|
+
remove_public_key(machine, Vagrant.source_root.join("keys", "vagrant.pub").read.chomp)
|
53
|
+
|
54
|
+
machine.ui.detail(I18n.t("vagrant_hypervnet.ssh.inserted_key"))
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
cmds = []
|
59
|
+
cmds += [
|
60
|
+
'Start-Service -Name sshd',
|
61
|
+
'Set-Service -Name sshd -StartupType "Automatic"'
|
62
|
+
]
|
63
|
+
|
64
|
+
machine.communicate.tap do |comm|
|
65
|
+
cmds.each do |cmd|
|
66
|
+
comm.execute(cmd, shell: :powershell)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.sshd_reload(machine)
|
73
|
+
machine.ui.detail(I18n.t("vagrant_hypervnet.ssh.reload"))
|
74
|
+
machine.communicate.execute('Restart-Service -Name sshd', shell: :powershell)
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.insecure_key?(path)
|
78
|
+
return false if !path
|
79
|
+
return false if !File.file?(path)
|
80
|
+
source_path = Vagrant.source_root.join("keys", "vagrant")
|
81
|
+
return File.read(path).chomp == source_path.read.chomp
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.insert_public_key(machine, contents)
|
85
|
+
contents = contents.strip
|
86
|
+
winssh_modify_authorized_keys machine do |keys|
|
87
|
+
if !keys.include?(contents)
|
88
|
+
keys << contents
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.remove_public_key(machine, contents)
|
94
|
+
winssh_modify_authorized_keys machine do |keys|
|
95
|
+
keys.delete(contents)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.winssh_modify_authorized_keys(machine)
|
100
|
+
comm = machine.communicate
|
101
|
+
directories = fetch_guest_paths(comm)
|
102
|
+
data_dir = directories[:data]
|
103
|
+
temp_dir = directories[:temp]
|
104
|
+
|
105
|
+
remote_ssh_dir = "#{data_dir}\\ssh"
|
106
|
+
comm.execute("New-Item -Path '#{remote_ssh_dir}' -ItemType directory -Force", shell: "powershell")
|
107
|
+
remote_upload_path = "#{temp_dir}\\vagrant-insert-pubkey-#{Time.now.to_i}"
|
108
|
+
remote_authkeys_path = "#{remote_ssh_dir}\\administrators_authorized_keys"
|
109
|
+
|
110
|
+
keys_file = Tempfile.new("vagrant-windows-insert-public-key")
|
111
|
+
keys_file.close
|
112
|
+
# Check if an authorized_keys file already exists
|
113
|
+
result = comm.execute("dir \"#{remote_authkeys_path}\"", shell: "cmd", error_check: false)
|
114
|
+
if result == 0
|
115
|
+
comm.download(remote_authkeys_path, keys_file.path)
|
116
|
+
keys = File.read(keys_file.path).split(/[\r\n]+/)
|
117
|
+
else
|
118
|
+
keys = []
|
119
|
+
end
|
120
|
+
yield keys
|
121
|
+
File.write(keys_file.path, keys.join("\r\n") + "\r\n")
|
122
|
+
comm.upload(keys_file.path, remote_upload_path)
|
123
|
+
keys_file.delete
|
124
|
+
comm.execute(<<-EOC.gsub(/^\s*/, ""), shell: "powershell")
|
125
|
+
Set-Acl "#{remote_upload_path}" (Get-Acl "#{remote_authkeys_path}")
|
126
|
+
Move-Item -Force "#{remote_upload_path}" "#{remote_authkeys_path}"
|
127
|
+
EOC
|
128
|
+
end
|
129
|
+
|
130
|
+
# Fetch user's temporary and data directory paths from the Windows guest
|
131
|
+
#
|
132
|
+
# @param [Communicator]
|
133
|
+
# @return [Hash] {:temp, :data}
|
134
|
+
def self.fetch_guest_paths(communicator)
|
135
|
+
output = ""
|
136
|
+
communicator.execute("Write-Output $env:TEMP\nWrite-Output $env:ProgramData", shell: "powershell") do |type, data|
|
137
|
+
if type == :stdout
|
138
|
+
output << data
|
139
|
+
end
|
140
|
+
end
|
141
|
+
temp_dir, data_dir = output.strip.split(/[\r\n]+/)
|
142
|
+
if temp_dir.nil? || data_dir.nil?
|
143
|
+
raise Errors::PublicKeyDirectoryFailure
|
144
|
+
end
|
145
|
+
{temp: temp_dir, data: data_dir}
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative 'driver'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module HyperVNet
|
5
|
+
module Cap
|
6
|
+
# Reads the network interface card MAC addresses and returns them.
|
7
|
+
#
|
8
|
+
# @return [Hash<String, String>] Adapter => MAC address
|
9
|
+
def self.nic_mac_addresses(machine)
|
10
|
+
driver = Driver.new(machine.id)
|
11
|
+
driver.read_vm_mac_addresses
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "vagrant"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module HyperVNet
|
5
|
+
class Config < Vagrant.plugin("2", :config)
|
6
|
+
|
7
|
+
attr_reader :network_adapters
|
8
|
+
|
9
|
+
attr_accessor :install_ssh_server
|
10
|
+
attr_accessor :install_rsync
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@network_adapters = []
|
14
|
+
@install_ssh_server = UNSET_VALUE
|
15
|
+
@install_rsync = UNSET_VALUE
|
16
|
+
|
17
|
+
network_adapter(:nat)
|
18
|
+
end
|
19
|
+
|
20
|
+
def network_adapter(type, **opts)
|
21
|
+
@network_adapters << [type, opts]
|
22
|
+
end
|
23
|
+
|
24
|
+
def finalize!
|
25
|
+
@install_ssh_server = true if @install_ssh_server == UNSET_VALUE
|
26
|
+
@install_rsync = true if @install_rsync == UNSET_VALUE
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate(machine)
|
30
|
+
errors = _detected_errors
|
31
|
+
|
32
|
+
{"Hyper-V network" => errors}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
require "json"
|
2
|
+
require "vagrant/util/powershell"
|
3
|
+
|
4
|
+
require_relative "errors"
|
5
|
+
|
6
|
+
module VagrantPlugins
|
7
|
+
module HyperVNet
|
8
|
+
class Driver
|
9
|
+
ERROR_REGEXP = /===Begin-Error===(.+?)===End-Error===/m
|
10
|
+
OUTPUT_REGEXP = /===Begin-Output===(.+?)===End-Output===/m
|
11
|
+
|
12
|
+
# @return [String] VM Id
|
13
|
+
attr_reader :vmId
|
14
|
+
|
15
|
+
def initialize(id)
|
16
|
+
@vmId = id
|
17
|
+
@logger = Log4r::Logger.new("vagrant::hypervnet::driver")
|
18
|
+
end
|
19
|
+
|
20
|
+
# Execute a PowerShell command and process the results
|
21
|
+
#
|
22
|
+
# @param [String] path Path to PowerShell script
|
23
|
+
# @param [Hash] options Options to pass to command
|
24
|
+
#
|
25
|
+
# @return [Object, nil] If the command returned JSON content
|
26
|
+
# it will be parsed and returned, otherwise
|
27
|
+
# nil will be returned
|
28
|
+
def execute(path, options={})
|
29
|
+
if path.is_a?(Symbol)
|
30
|
+
path = "#{path}.ps1"
|
31
|
+
end
|
32
|
+
r = execute_powershell(path, options)
|
33
|
+
|
34
|
+
# We only want unix-style line endings within Vagrant
|
35
|
+
r.stdout.gsub!("\r\n", "\n")
|
36
|
+
r.stderr.gsub!("\r\n", "\n")
|
37
|
+
|
38
|
+
error_match = ERROR_REGEXP.match(r.stdout)
|
39
|
+
output_match = OUTPUT_REGEXP.match(r.stdout)
|
40
|
+
|
41
|
+
if error_match
|
42
|
+
data = JSON.parse(error_match[1])
|
43
|
+
|
44
|
+
@logger.info("Error in #{path}: #{data["error"]}")
|
45
|
+
# We have some error data.
|
46
|
+
raise Errors::PowerShellError,
|
47
|
+
script: path,
|
48
|
+
stderr: data["error"]
|
49
|
+
end
|
50
|
+
|
51
|
+
if r.exit_code != 0
|
52
|
+
@logger.info("Error in #{path}: #{r.stderr}")
|
53
|
+
raise Errors::PowerShellError,
|
54
|
+
script: path,
|
55
|
+
stderr: r.stderr
|
56
|
+
end
|
57
|
+
|
58
|
+
# Nothing
|
59
|
+
return nil if !output_match
|
60
|
+
return JSON.parse(output_match[1])
|
61
|
+
end
|
62
|
+
|
63
|
+
def find_switch_by_name(name)
|
64
|
+
data = execute(:get_switch_by_name, Name: name)
|
65
|
+
if data && data.kind_of?(Array)
|
66
|
+
data = data[0]
|
67
|
+
end
|
68
|
+
|
69
|
+
if data
|
70
|
+
switch = {}
|
71
|
+
switch[:name] = data["Name"]
|
72
|
+
switch[:type] = data["SwitchType"]
|
73
|
+
end
|
74
|
+
|
75
|
+
switch
|
76
|
+
end
|
77
|
+
|
78
|
+
def find_switch_by_address(ip_address, prefix_length)
|
79
|
+
data = execute(:get_switch_by_address, DestinationPrefix: "#{ip_address}/#{prefix_length}")
|
80
|
+
if data && data.kind_of?(Array)
|
81
|
+
data = data[0]
|
82
|
+
end
|
83
|
+
|
84
|
+
if data
|
85
|
+
switch = {}
|
86
|
+
switch[:name] = data["Name"]
|
87
|
+
switch[:type] = data["SwitchType"]
|
88
|
+
end
|
89
|
+
|
90
|
+
switch
|
91
|
+
end
|
92
|
+
|
93
|
+
def read_vm_mac_addresses
|
94
|
+
adapters = {}
|
95
|
+
|
96
|
+
data = execute(:get_vm_adapters, VmId: @vmId)
|
97
|
+
if data
|
98
|
+
if data.kind_of?(Hash)
|
99
|
+
data = [] << data
|
100
|
+
end
|
101
|
+
|
102
|
+
data.each.with_index(1) do |value, index|
|
103
|
+
adapters[index] = value["MacAddress"]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
adapters
|
108
|
+
end
|
109
|
+
|
110
|
+
def read_vm_network_adapters
|
111
|
+
adapters = []
|
112
|
+
|
113
|
+
data = execute(:get_vm_adapters, VmId: @vmId)
|
114
|
+
if data
|
115
|
+
if data.kind_of?(Hash)
|
116
|
+
data = [] << data
|
117
|
+
end
|
118
|
+
data.each do |value|
|
119
|
+
adapter = {}
|
120
|
+
adapter[:id] = value["Id"]
|
121
|
+
adapter[:name] = value["Name"]
|
122
|
+
adapter[:switch] = value["SwitchName"]
|
123
|
+
adapter[:mac_address] = value["MacAddress"]
|
124
|
+
adapters << adapter
|
125
|
+
end
|
126
|
+
end
|
127
|
+
adapters
|
128
|
+
end
|
129
|
+
|
130
|
+
def create_switch(type, name, ip_address = nil, prefix_length = nil)
|
131
|
+
case type
|
132
|
+
when :internal
|
133
|
+
data = execute(:new_switch, Name: name, SwitchType: "Internal", IPAddress: ip_address, PrefixLength: prefix_length)
|
134
|
+
when :private
|
135
|
+
data = execute(:new_switch, Name: name, SwitchType: "Private")
|
136
|
+
end
|
137
|
+
|
138
|
+
if data
|
139
|
+
switch = {}
|
140
|
+
switch[:name] = data["Name"]
|
141
|
+
switch[:type] = data["SwitchType"]
|
142
|
+
end
|
143
|
+
|
144
|
+
switch
|
145
|
+
end
|
146
|
+
|
147
|
+
def add_vm_adapter(switch)
|
148
|
+
data = execute(:add_vm_adapter, VmId: @vmId, SwitchName: switch)
|
149
|
+
|
150
|
+
adapter = {}
|
151
|
+
adapter[:id] = data["Id"]
|
152
|
+
adapter[:name] = data["Name"]
|
153
|
+
adapter[:switch] = data["SwitchName"]
|
154
|
+
adapter[:mac_address] = data["MacAddress"]
|
155
|
+
|
156
|
+
adapter
|
157
|
+
end
|
158
|
+
|
159
|
+
def remove_vm_adapter(id)
|
160
|
+
execute(:remove_vm_adapter, VmId: @vmId, Id: id)
|
161
|
+
end
|
162
|
+
|
163
|
+
def connect_vm_adapter(id, switch)
|
164
|
+
execute(:connect_vm_adapter, VmId: @vmId, Id: id, SwitchName: switch)
|
165
|
+
end
|
166
|
+
|
167
|
+
protected
|
168
|
+
|
169
|
+
def execute_powershell(path, options, &block)
|
170
|
+
lib_path = Pathname.new(File.expand_path("../scripts", __FILE__))
|
171
|
+
mod_path = Vagrant::Util::Platform.wsl_to_windows_path(lib_path.join("utils")).to_s.gsub("/", "\\")
|
172
|
+
path = Vagrant::Util::Platform.wsl_to_windows_path(lib_path.join(path)).to_s.gsub("/", "\\")
|
173
|
+
options = options || {}
|
174
|
+
ps_options = []
|
175
|
+
options.each do |key, value|
|
176
|
+
next if !value || value.to_s.empty?
|
177
|
+
next if value == false
|
178
|
+
ps_options << "-#{key}"
|
179
|
+
# If the value is a TrueClass assume switch
|
180
|
+
next if value == true
|
181
|
+
ps_options << "'#{value}'"
|
182
|
+
end
|
183
|
+
|
184
|
+
# Always have a stop error action for failures
|
185
|
+
ps_options << "-ErrorAction" << "Stop"
|
186
|
+
|
187
|
+
# Include our module path so we can nicely load helper modules
|
188
|
+
opts = {
|
189
|
+
notify: [:stdout, :stderr, :stdin],
|
190
|
+
module_path: mod_path
|
191
|
+
}
|
192
|
+
|
193
|
+
Vagrant::Util::PowerShell.execute(path, *ps_options, **opts, &block)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module HyperVNet
|
3
|
+
module Errors
|
4
|
+
# A convenient superclass for all our errors.
|
5
|
+
class HyperVNetError < Vagrant::Errors::VagrantError
|
6
|
+
error_namespace("vagrant_hypervnet.errors")
|
7
|
+
end
|
8
|
+
|
9
|
+
class BridgeUndefinedInPublicNetwork < HyperVNetError
|
10
|
+
error_key(:bridge_undefined_in_public_network)
|
11
|
+
end
|
12
|
+
|
13
|
+
class IpUndefinedInPrivateNetwork < HyperVNetError
|
14
|
+
error_key(:ip_undefined_in_private_network)
|
15
|
+
end
|
16
|
+
|
17
|
+
class PowerShellError < HyperVNetError
|
18
|
+
error_key(:powershell_error)
|
19
|
+
end
|
20
|
+
|
21
|
+
class NetworkAddressInvalid < HyperVNetError
|
22
|
+
error_key(:network_address_invalid)
|
23
|
+
end
|
24
|
+
|
25
|
+
class NetworkNotFound < HyperVNetError
|
26
|
+
error_key(:network_not_found)
|
27
|
+
end
|
28
|
+
|
29
|
+
class NetworkTypeNotSupported < HyperVNetError
|
30
|
+
error_key(:network_type_not_supported)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#Requires -Modules VagrantMessages
|
2
|
+
|
3
|
+
param (
|
4
|
+
[parameter (Mandatory=$true)]
|
5
|
+
[string]$VmId,
|
6
|
+
[parameter (Mandatory=$true)]
|
7
|
+
[string]$SwitchName
|
8
|
+
|
9
|
+
)
|
10
|
+
|
11
|
+
$vm = Get-VM -Id $VmId
|
12
|
+
$adapter = Add-VMNetworkAdapter -PassThru -VM $vm -SwitchName $SwitchName |
|
13
|
+
Select-Object -Property "Name", "Id", "SwitchName", "MacAddress"
|
14
|
+
|
15
|
+
Write-OutputMessage $(ConvertTo-JSON $adapter)
|
@@ -0,0 +1,12 @@
|
|
1
|
+
param (
|
2
|
+
[parameter (Mandatory=$true)]
|
3
|
+
[string]$VmId,
|
4
|
+
[parameter (Mandatory=$true)]
|
5
|
+
[string]$Id,
|
6
|
+
[parameter (Mandatory=$true)]
|
7
|
+
[string]$SwitchName
|
8
|
+
|
9
|
+
)
|
10
|
+
|
11
|
+
$vm = Get-VM -Id $VmId
|
12
|
+
Get-VMNetworkAdapter -VM $vm | Where-Object -Property Id -EQ -Value $Id | Connect-VMNetworkAdapter -SwitchName $SwitchName
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#Requires -Modules VagrantMessages
|
2
|
+
|
3
|
+
param (
|
4
|
+
[parameter (Mandatory=$true)]
|
5
|
+
[string]$DestinationPrefix
|
6
|
+
)
|
7
|
+
|
8
|
+
$switches = @()
|
9
|
+
|
10
|
+
foreach($route in Get-NetRoute | Where-Object -Property DestinationPrefix -EQ -Value $DestinationPrefix) {
|
11
|
+
foreach($adapter in Get-NetAdapter -InterfaceIndex $route.ifIndex) {
|
12
|
+
foreach($vmAdapter in Get-VMNetworkAdapter -ManagementOS | Where-Object -Property DeviceId -EQ -Value $adapter.DeviceId) {
|
13
|
+
foreach($switch in Get-VMSwitch -Name $vmAdapter.SwitchName |
|
14
|
+
Select-Object -Property Name,
|
15
|
+
@{Name='SwitchType';Expression={"$($_.SwitchType)"}},
|
16
|
+
@{Name='NetAdapter';Expression={$switch_adapter[$_.Name]}}) {
|
17
|
+
$switches += $switch
|
18
|
+
}
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
22
|
+
Write-OutputMessage $(ConvertTo-JSON $switches)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#Requires -Modules VagrantMessages
|
2
|
+
|
3
|
+
param (
|
4
|
+
[parameter (Mandatory=$true)]
|
5
|
+
[string]$Name
|
6
|
+
)
|
7
|
+
|
8
|
+
$switches = @()
|
9
|
+
|
10
|
+
foreach($switch in Get-VMSwitch | Where-Object -Property Name -EQ -Value $Name |
|
11
|
+
Select-Object -Property Name,
|
12
|
+
@{Name='SwitchType';Expression={"$($_.SwitchType)"}},
|
13
|
+
@{Name='NetAdapter';Expression={$switch_adapter[$_.Name]}}) {
|
14
|
+
$switches += $switch
|
15
|
+
}
|
16
|
+
|
17
|
+
Write-OutputMessage $(ConvertTo-JSON $switches)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
#Requires -Modules VagrantMessages
|
2
|
+
|
3
|
+
param (
|
4
|
+
[parameter (Mandatory=$true)]
|
5
|
+
[string]$VmId
|
6
|
+
)
|
7
|
+
$vm = Get-VM -Id $VmId
|
8
|
+
$adapters = Get-VMNetworkAdapter -VM $vm |
|
9
|
+
Select-Object -Property "Name", "Id", "SwitchName", "MacAddress"
|
10
|
+
|
11
|
+
Write-OutputMessage $(ConvertTo-JSON $adapters)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#Requires -Modules VagrantMessages
|
2
|
+
|
3
|
+
param (
|
4
|
+
[parameter (Mandatory=$true)]
|
5
|
+
[string]$Name,
|
6
|
+
[parameter (Mandatory=$true)]
|
7
|
+
[string]$SwitchType,
|
8
|
+
[parameter (Mandatory=$false)]
|
9
|
+
[string]$IPAddress,
|
10
|
+
[parameter (Mandatory=$false)]
|
11
|
+
[string]$PrefixLength
|
12
|
+
|
13
|
+
)
|
14
|
+
|
15
|
+
$switch = New-VMSwitch -Name $Name -SwitchType $SwitchType
|
16
|
+
|
17
|
+
if($IPAddress) {
|
18
|
+
$vmAdapter = Get-VMNetworkAdapter -ManagementOS -SwitchName $switch.Name
|
19
|
+
$adapter = Get-NetAdapter | Where-Object -Property DeviceId -EQ -Value $vmAdapter.DeviceId
|
20
|
+
New-NetIPAddress -IPAddress $IPAddress -PrefixLength $PrefixLength -InterfaceIndex $adapter.ifIndex
|
21
|
+
}
|
22
|
+
|
23
|
+
Write-OutputMessage $($switch | Select-Object -Property Name,
|
24
|
+
@{Name='SwitchType';Expression={"$($_.SwitchType)"}},
|
25
|
+
@{Name='NetAdapter';Expression={$switch_adapter[$_.Name]}} |
|
26
|
+
ConvertTo-JSON)
|