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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6f024899cc74a4e7385cd03355e8bef3b435890225cff8b0a6148d25b52a86f9
|
4
|
+
data.tar.gz: 1e00433fbdc4d9c3a134eb154c185b186cf8c1188816dd38f80d7af8db92adb7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 57d673018b5faef0970e51671bd53033908c914e5af64d526ff2c41115552686988067d905b347c005ffc1edd9794e70f77be3865784c952e6be517412c7d7d4
|
7
|
+
data.tar.gz: e58247102736397f56cc419b56d3df1940f2f6704c2c7c81cdbb6211b533c98ce9c5710ec2e30818a1798b06bc5b0e0c71e8cc6cc2a67be1d26bbb5d1a54eed6
|
data/Gemfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in vagrant-hypervnet.gemspec
|
6
|
+
#gemspec
|
7
|
+
|
8
|
+
#gem "debug", ">= 1.0.0"
|
9
|
+
|
10
|
+
group :development do
|
11
|
+
gem "vagrant", git: "https://github.com/hashicorp/vagrant.git", tag: 'v2.3.4'
|
12
|
+
end
|
13
|
+
|
14
|
+
group :plugins do
|
15
|
+
gem "vagrant-hypervnet", path: "."
|
16
|
+
end
|
data/README.md
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# vagrant-hypervnet
|
2
|
+
|
3
|
+
*vagrant-hypervnet* is a [Vagrant](http://vagrantup.com) plugin which extends Hyper-V provider implementing networks creation and
|
4
|
+
configuration.
|
5
|
+
|
6
|
+
[](https://badge.fury.io/rb/vagrant-hypervnet)
|
7
|
+
[](https://rubygems.org/gems/vagrant-hypervnet)
|
8
|
+
|
9
|
+
## Features
|
10
|
+
|
11
|
+
* Create Hyper-V switches.
|
12
|
+
* Add an host IP address for each private network
|
13
|
+
* Add a and configure a guest network adapter for each configured public or private network
|
14
|
+
* Optionally install and configure SSH server in windows guests.
|
15
|
+
* Optionally install and configure rsync ([MSYS2](https://www.msys2.org/)) in windows guests.
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
```
|
20
|
+
$ vagrant plugin install vagrant-hypervnet
|
21
|
+
```
|
22
|
+
|
23
|
+
## Configuration
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
Vagrant.configure("2") do |config|
|
27
|
+
|
28
|
+
# install OpenSSH Server (Windows Capability) and insert vagrant ssh key on windows guests
|
29
|
+
config.hypervnet.install_ssh_server = true
|
30
|
+
|
31
|
+
# install MSYS2 and rsync on windows guests
|
32
|
+
config.hypervnet.install_rsync = true
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
### Config options
|
37
|
+
|
38
|
+
* `install_ssh_server` (Boolean, default: `true`): install OpenSSH Server (Windows Capability) and insert vagrant ssh key on windows guests.
|
39
|
+
* `install_rsync` (Boolean, default: `true`): install MSYS2 and rsync on windows guests.
|
40
|
+
|
41
|
+
## Usage
|
42
|
+
|
43
|
+
```
|
44
|
+
$ vagrant init
|
45
|
+
$ vagrant up --provider=hyperv
|
46
|
+
```
|
47
|
+
|
48
|
+
## Contributing
|
49
|
+
|
50
|
+
1. Fork it
|
51
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
52
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
53
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
54
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/Vagrantfile
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
vms = []
|
2
|
+
|
3
|
+
windows = {}
|
4
|
+
windows["box"] = "StefanScherer/windows_2019"
|
5
|
+
windows["hostname"] = "test-windows"
|
6
|
+
windows["network"] = []
|
7
|
+
windowsNet1 = {}
|
8
|
+
windowsNet1["ip"] = "10.42.201.101"
|
9
|
+
windowsNet1["netmask"] = "255.255.255.0"
|
10
|
+
windows["network"].push(windowsNet1)
|
11
|
+
windowsNet2 = {}
|
12
|
+
windowsNet2["ip"] = "10.42.202.101"
|
13
|
+
windowsNet2["netmask"] = "255.255.255.0"
|
14
|
+
windows["network"].push(windowsNet2)
|
15
|
+
windowsNet3 = {}
|
16
|
+
windowsNet3["ip"] = "10.42.203.101"
|
17
|
+
windowsNet3["netmask"] = "255.255.255.0"
|
18
|
+
windows["network"].push(windowsNet3)
|
19
|
+
windows["synced_folder"] = []
|
20
|
+
windowsSyncFolder1 = {}
|
21
|
+
windowsSyncFolder1["src"] = "."
|
22
|
+
windowsSyncFolder1["dst"] = "/c/vagrant"
|
23
|
+
windowsSyncFolder1["exclude"] = ".git/"
|
24
|
+
windows["synced_folder"].push(windowsSyncFolder1)
|
25
|
+
vms.push(windows)
|
26
|
+
|
27
|
+
ubuntu = {}
|
28
|
+
ubuntu["box"] = "generic/ubuntu2004"
|
29
|
+
ubuntu["hostname"] = "test-ubuntu"
|
30
|
+
ubuntu["network"] = []
|
31
|
+
ubuntuNet1 = {}
|
32
|
+
ubuntuNet1["ip"] = "10.42.201.102"
|
33
|
+
ubuntuNet1["netmask"] = "255.255.255.0"
|
34
|
+
ubuntu["network"].push(ubuntuNet1)
|
35
|
+
ubuntuNet2 = {}
|
36
|
+
ubuntuNet2["ip"] = "10.42.202.102"
|
37
|
+
ubuntuNet2["netmask"] = "255.255.255.0"
|
38
|
+
ubuntu["network"].push(ubuntuNet2)
|
39
|
+
ubuntuNet3 = {}
|
40
|
+
ubuntuNet3["ip"] = "10.42.203.102"
|
41
|
+
ubuntuNet3["netmask"] = "255.255.255.0"
|
42
|
+
ubuntu["network"].push(ubuntuNet3)
|
43
|
+
ubuntu["synced_folder"] = []
|
44
|
+
ubuntuSyncFolder1 = {}
|
45
|
+
ubuntuSyncFolder1["src"] = "."
|
46
|
+
ubuntuSyncFolder1["dst"] = "/vagrant"
|
47
|
+
ubuntuSyncFolder1["exclude"] = ".git/"
|
48
|
+
ubuntu["synced_folder"].push(ubuntuSyncFolder1)
|
49
|
+
vms.push(ubuntu)
|
50
|
+
|
51
|
+
centos = {}
|
52
|
+
centos["box"] = "generic/centos7"
|
53
|
+
centos["hostname"] = "test-centos"
|
54
|
+
centos["network"] = []
|
55
|
+
centosNet1 = {}
|
56
|
+
centosNet1["ip"] = "10.42.201.103"
|
57
|
+
centosNet1["netmask"] = "255.255.255.0"
|
58
|
+
centos["network"].push(centosNet1)
|
59
|
+
centosNet2 = {}
|
60
|
+
centosNet2["ip"] = "10.42.202.103"
|
61
|
+
centosNet2["netmask"] = "255.255.255.0"
|
62
|
+
centos["network"].push(centosNet2)
|
63
|
+
centosNet3 = {}
|
64
|
+
centosNet3["ip"] = "10.42.203.103"
|
65
|
+
centosNet3["netmask"] = "255.255.255.0"
|
66
|
+
centos["network"].push(centosNet3)
|
67
|
+
centos["synced_folder"] = []
|
68
|
+
centosSyncFolder1 = {}
|
69
|
+
centosSyncFolder1["src"] = "."
|
70
|
+
centosSyncFolder1["dst"] = "/vagrant"
|
71
|
+
centosSyncFolder1["exclude"] = ".git/"
|
72
|
+
centos["synced_folder"].push(centosSyncFolder1)
|
73
|
+
vms.push(centos)
|
74
|
+
|
75
|
+
Vagrant.configure("2") do |config|
|
76
|
+
vms.each do |node|
|
77
|
+
config.vm.define node["hostname"] do |node_config|
|
78
|
+
node_config.vm.box = node["box"]
|
79
|
+
node_config.vm.hostname = node["hostname"]
|
80
|
+
|
81
|
+
node["network"].each do |network|
|
82
|
+
node_config.vm.network :private_network, ip: network["ip"], netmask: network["netmask"]
|
83
|
+
end
|
84
|
+
|
85
|
+
node["synced_folder"].each do |folder|
|
86
|
+
node_config.vm.synced_folder folder["src"], folder["dst"], type: "rsync", rsync__exclude: folder["exclude"]
|
87
|
+
end
|
88
|
+
|
89
|
+
node_config.vm.provider "hyperv" do |p|
|
90
|
+
p.linked_clone = true
|
91
|
+
p.vmname = node["hostname"]
|
92
|
+
p.cpus = 2
|
93
|
+
p.maxmemory = 4096
|
94
|
+
p.vm_integration_services = {
|
95
|
+
guest_service_interface: true,
|
96
|
+
time_synchronization: true,
|
97
|
+
shutdown: true,
|
98
|
+
heartbeat: true,
|
99
|
+
vss: true
|
100
|
+
}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module HyperVNet
|
5
|
+
module Action
|
6
|
+
class DisableBuiltinNetworkConfigure
|
7
|
+
|
8
|
+
def initialize(app, env)
|
9
|
+
@app = app
|
10
|
+
@logger = Log4r::Logger.new("vagrant::hypervnet::disable_builtin_network_configure")
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
@logger.info("Disabling built-in Hyper-V provider network configure...")
|
15
|
+
|
16
|
+
|
17
|
+
env[:machine].config.vm.networks.each do |type, options|
|
18
|
+
if options.key?(:bridge)
|
19
|
+
bridge = options.delete(:bridge)
|
20
|
+
options[:hyperv__bridge] = bridge
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
sentinel = env[:machine].data_dir.join("action_configure")
|
25
|
+
|
26
|
+
# Create the sentinel
|
27
|
+
if !sentinel.file?
|
28
|
+
sentinel.open("w") do |f|
|
29
|
+
f.write(Time.now.to_i.to_s)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Continue the middleware chain.
|
34
|
+
@app.call(env)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,328 @@
|
|
1
|
+
require "ipaddr"
|
2
|
+
require "log4r"
|
3
|
+
|
4
|
+
require "vagrant/util/scoped_hash_override"
|
5
|
+
|
6
|
+
require_relative "../driver"
|
7
|
+
require_relative "../errors"
|
8
|
+
|
9
|
+
module VagrantPlugins
|
10
|
+
module HyperVNet
|
11
|
+
module Action
|
12
|
+
class Network
|
13
|
+
|
14
|
+
include Vagrant::Util::ScopedHashOverride
|
15
|
+
|
16
|
+
def initialize(app, env)
|
17
|
+
@app = app
|
18
|
+
@logger = Log4r::Logger.new("vagrant::hypervnet::network")
|
19
|
+
end
|
20
|
+
|
21
|
+
def call(env)
|
22
|
+
@env = env
|
23
|
+
@driver = Driver.new(env[:machine].id)
|
24
|
+
|
25
|
+
network_adapters_config = env[:machine].config.hypervnet.network_adapters.dup
|
26
|
+
|
27
|
+
@logger.info("Determining network adapters required for high-level configuration...")
|
28
|
+
env[:machine].config.vm.networks.each do |type, options|
|
29
|
+
next if type != :private_network && type != :public_network
|
30
|
+
|
31
|
+
options = scoped_hash_override(options, :hyperv)
|
32
|
+
|
33
|
+
if !options.key?(:type) && options.key?(:ip)
|
34
|
+
begin
|
35
|
+
addr = IPAddr.new(options[:ip])
|
36
|
+
options[:type] = if addr.ipv4?
|
37
|
+
:static
|
38
|
+
else
|
39
|
+
:static6
|
40
|
+
end
|
41
|
+
rescue IPAddr::Error => err
|
42
|
+
raise Errors::NetworkAddressInvalid,
|
43
|
+
address: options[:ip], mask: options[:netmask],
|
44
|
+
error: err.message
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
data = nil
|
49
|
+
if type == :private_network
|
50
|
+
if options[:private]
|
51
|
+
data = [:private, options]
|
52
|
+
else
|
53
|
+
data = [:internal, options]
|
54
|
+
end
|
55
|
+
elsif type == :public_network
|
56
|
+
data = [:external, options]
|
57
|
+
end
|
58
|
+
|
59
|
+
@logger.info(" -- Slot #{network_adapters_config.length}: #{data[0]}")
|
60
|
+
network_adapters_config << data
|
61
|
+
end
|
62
|
+
|
63
|
+
@logger.info("Determining adapters and compiling network configuration...")
|
64
|
+
adapters = []
|
65
|
+
networks = []
|
66
|
+
network_adapters_config.each.with_index(0) do |data, index|
|
67
|
+
type = data[0]
|
68
|
+
options = data[1]
|
69
|
+
|
70
|
+
@logger.info("Network #{index}. Type: #{type}.")
|
71
|
+
|
72
|
+
config = send("#{type}_config", options)
|
73
|
+
@logger.debug("Normalized configuration: #{config.inspect}")
|
74
|
+
|
75
|
+
adapter = send("#{type}_adapter", config)
|
76
|
+
adapters << adapter
|
77
|
+
@logger.debug("Adapter configuration: #{adapter.inspect}")
|
78
|
+
|
79
|
+
network = send("#{type}_network_config", config)
|
80
|
+
network[:auto_config] = config[:auto_config]
|
81
|
+
networks << network
|
82
|
+
end
|
83
|
+
|
84
|
+
if !adapters.empty?
|
85
|
+
@logger.info("Enabling adapters...")
|
86
|
+
env[:ui].output(I18n.t("vagrant_hypervnet.network.preparing"))
|
87
|
+
adapters.each.with_index(0) do |adapter, index|
|
88
|
+
@logger.info(adapter.inspect)
|
89
|
+
env[:ui].detail(I18n.t(
|
90
|
+
"vagrant_hypervnet.network_adapter",
|
91
|
+
adapter: index.to_s,
|
92
|
+
type: adapter[:type].to_s,
|
93
|
+
switch: adapter[:switch].to_s
|
94
|
+
))
|
95
|
+
end
|
96
|
+
|
97
|
+
enable_adapters(adapters)
|
98
|
+
end
|
99
|
+
|
100
|
+
@app.call(env)
|
101
|
+
|
102
|
+
if !adapters.empty? && !networks.empty?
|
103
|
+
|
104
|
+
guest_adapters = {}
|
105
|
+
if env[:machine].guest.capability?(:nic_mac_addresses)
|
106
|
+
nic_mac_addresses = env[:machine].guest.capability(:nic_mac_addresses)
|
107
|
+
@logger.info("Guest NIC MAC-addresses: #{nic_mac_addresses.inspect}")
|
108
|
+
nic_mac_addresses.each.with_index(0) do |iface, index|
|
109
|
+
mac_address = iface[:mac_address].upcase.delete(':')
|
110
|
+
guest_adapters[mac_address] = index
|
111
|
+
end
|
112
|
+
@logger.info("Guest Adapters map: #{guest_adapters.inspect}")
|
113
|
+
end
|
114
|
+
|
115
|
+
assign_interface_numbers(networks, adapters, guest_adapters)
|
116
|
+
|
117
|
+
networks_to_configure = networks.select { |n| n[:auto_config] }
|
118
|
+
if !networks_to_configure.empty?
|
119
|
+
env[:ui].info I18n.t("vagrant_hypervnet.network.configuring")
|
120
|
+
|
121
|
+
networks_to_configure.each.with_index(0) do |network, index|
|
122
|
+
@logger.info(network.inspect)
|
123
|
+
env[:ui].detail(I18n.t(
|
124
|
+
"vagrant_hypervnet.network_config",
|
125
|
+
network: index.to_s,
|
126
|
+
interface: network[:interface].to_s,
|
127
|
+
type: network[:type].to_s,
|
128
|
+
ip: network[:ip].to_s,
|
129
|
+
netmask: network[:netmask].to_s
|
130
|
+
))
|
131
|
+
end
|
132
|
+
if env[:machine].guest.capability?(:pre_configure_networks)
|
133
|
+
env[:machine].guest.capability(:pre_configure_networks)
|
134
|
+
end
|
135
|
+
env[:machine].guest.capability(:configure_networks, networks_to_configure)
|
136
|
+
if env[:machine].guest.capability?(:post_configure_networks)
|
137
|
+
env[:machine].guest.capability(:post_configure_networks)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def external_config(options)
|
144
|
+
return {
|
145
|
+
auto_config: true,
|
146
|
+
bridge: nil,
|
147
|
+
netmask: "255.255.255.0",
|
148
|
+
type: :static
|
149
|
+
}.merge(options || {})
|
150
|
+
end
|
151
|
+
|
152
|
+
def external_adapter(config)
|
153
|
+
if config[:bridge]
|
154
|
+
@logger.debug("Searching for bridge #{config[:bridge]}")
|
155
|
+
|
156
|
+
switch = @driver.find_switch_by_name(config[:bridge])
|
157
|
+
if switch
|
158
|
+
@logger.info("Bridging adapter to #{switch[:name]}")
|
159
|
+
|
160
|
+
return {
|
161
|
+
type: :external,
|
162
|
+
switch: switch[:name],
|
163
|
+
}
|
164
|
+
else
|
165
|
+
raise Errors::NetworkNotFound, name: config[:bridge]
|
166
|
+
end
|
167
|
+
else
|
168
|
+
raise Errors::BridgeUndefinedInPublicNetwork
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def external_network_config(config)
|
173
|
+
return {
|
174
|
+
type: config[:type],
|
175
|
+
ip: config[:ip],
|
176
|
+
netmask: config[:netmask]
|
177
|
+
}
|
178
|
+
end
|
179
|
+
|
180
|
+
def internal_config(options)
|
181
|
+
return {
|
182
|
+
auto_config: true,
|
183
|
+
bridge: nil,
|
184
|
+
netmask: "255.255.255.0",
|
185
|
+
type: :static,
|
186
|
+
}.merge(options || {})
|
187
|
+
end
|
188
|
+
|
189
|
+
def internal_adapter(config)
|
190
|
+
if config[:type].to_sym != :static
|
191
|
+
raise Errors::NetworkTypeNotSupported, type: config[:type]
|
192
|
+
elsif !config[:ip]
|
193
|
+
raise Errors::IpUndefinedInPrivateNetwork
|
194
|
+
end
|
195
|
+
|
196
|
+
switch = nil
|
197
|
+
netaddr = IPAddr.new(config[:ip]).mask(config[:netmask])
|
198
|
+
if config[:bridge]
|
199
|
+
@logger.debug("Searching for switch #{config[:bridge]}")
|
200
|
+
switch = @driver.find_switch_by_name(config[:bridge])
|
201
|
+
else
|
202
|
+
@logger.info("Searching for matching switch: #{netaddr.to_s}")
|
203
|
+
switch = @driver.find_switch_by_address(netaddr.to_s, netaddr.prefix)
|
204
|
+
end
|
205
|
+
|
206
|
+
if !switch
|
207
|
+
@logger.info("Switch not found. Creating if we can.")
|
208
|
+
if !config[:bridge]
|
209
|
+
config[:bridge] = netaddr.to_s
|
210
|
+
end
|
211
|
+
|
212
|
+
# Create a new switch
|
213
|
+
switch = @driver.create_switch(:internal, config[:bridge], netaddr.succ.to_s, netaddr.prefix)
|
214
|
+
@logger.info("Created switch: #{switch[:name]}")
|
215
|
+
end
|
216
|
+
|
217
|
+
return {
|
218
|
+
switch: switch[:name],
|
219
|
+
type: :internal
|
220
|
+
}
|
221
|
+
end
|
222
|
+
|
223
|
+
def internal_network_config(config)
|
224
|
+
return {
|
225
|
+
type: config[:type],
|
226
|
+
ip: config[:ip],
|
227
|
+
netmask: config[:netmask]
|
228
|
+
}
|
229
|
+
end
|
230
|
+
|
231
|
+
def private_config(options)
|
232
|
+
return {
|
233
|
+
auto_config: true,
|
234
|
+
bridge: options[:private],
|
235
|
+
netmask: "255.255.255.0",
|
236
|
+
type: :static,
|
237
|
+
}.merge(options || {})
|
238
|
+
end
|
239
|
+
|
240
|
+
def private_adapter(config)
|
241
|
+
switch = nil
|
242
|
+
if config[:bridge]
|
243
|
+
@logger.debug("Searching for switch #{config[:bridge]}")
|
244
|
+
switch = @driver.find_switch_by_name(config[:bridge])
|
245
|
+
end
|
246
|
+
|
247
|
+
if !switch
|
248
|
+
@logger.info("Switch not found. Creating if we can.")
|
249
|
+
|
250
|
+
# Create a new switch
|
251
|
+
switch = @driver.create_switch(:private, config[:bridge])
|
252
|
+
@logger.info("Created switch: #{switch[:name]}")
|
253
|
+
end
|
254
|
+
|
255
|
+
return {
|
256
|
+
type: :private,
|
257
|
+
switch: switch[:name],
|
258
|
+
}
|
259
|
+
end
|
260
|
+
|
261
|
+
def private_network_config(config)
|
262
|
+
return {
|
263
|
+
type: config[:type],
|
264
|
+
ip: config[:ip],
|
265
|
+
netmask: config[:netmask]
|
266
|
+
}
|
267
|
+
end
|
268
|
+
|
269
|
+
def nat_config(options)
|
270
|
+
return options.merge(
|
271
|
+
auto_config: false
|
272
|
+
)
|
273
|
+
end
|
274
|
+
|
275
|
+
def nat_adapter(config)
|
276
|
+
return {
|
277
|
+
type: :nat,
|
278
|
+
switch: "Default Switch"
|
279
|
+
}
|
280
|
+
end
|
281
|
+
|
282
|
+
def nat_network_config(config)
|
283
|
+
return {}
|
284
|
+
end
|
285
|
+
|
286
|
+
#-----------------------------------------------------------------
|
287
|
+
# Misc. helpers
|
288
|
+
#-----------------------------------------------------------------
|
289
|
+
|
290
|
+
def enable_adapters(adapters)
|
291
|
+
vm_adapters = @driver.read_vm_network_adapters
|
292
|
+
adapters.each.with_index(0) do |adapter, index|
|
293
|
+
if index < vm_adapters.length
|
294
|
+
vm_adapter = vm_adapters[index]
|
295
|
+
@logger.info("Connecting adapter #{vm_adapter.inspect} to switch #{adapter[:switch]}")
|
296
|
+
@driver.connect_vm_adapter(vm_adapter[:id], adapter[:switch])
|
297
|
+
else
|
298
|
+
vm_adapter = @driver.add_vm_adapter(adapter[:switch])
|
299
|
+
@logger.info("Created adapter: #{vm_adapter.inspect}")
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
if vm_adapters.length > adapters.length
|
304
|
+
for index in adapters.length .. vm_adapters.length-1
|
305
|
+
vm_adapter = vm_adapters[index]
|
306
|
+
@logger.info("Removing adapter: #{vm_adapter.inspect}")
|
307
|
+
@driver.remove_vm_adapter(vm_adapter[:id])
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
def assign_interface_numbers(networks, adapters, guest_adapters)
|
313
|
+
vm_adapters = @driver.read_vm_network_adapters
|
314
|
+
vm_adapters.each.with_index(0) do |vm_adapter, index|
|
315
|
+
if guest_adapters && guest_adapters.key?(vm_adapter[:mac_address])
|
316
|
+
@logger.info("Found guest adapter #{vm_adapter[:mac_address]}")
|
317
|
+
networks[index][:interface] = guest_adapters[vm_adapter[:mac_address]]
|
318
|
+
else
|
319
|
+
@logger.info("Guest adapter #{vm_adapter[:mac_address]} not found")
|
320
|
+
networks[index][:interface] = index
|
321
|
+
end
|
322
|
+
@logger.info("Mapping vm adapter #{index} to guest adapter #{networks[index][:interface]}")
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module HyperVNet
|
5
|
+
module Action
|
6
|
+
class SshServer
|
7
|
+
|
8
|
+
def initialize(app, env)
|
9
|
+
@app = app
|
10
|
+
@logger = Log4r::Logger.new("vagrant::hypervnet::ssh_server")
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
machine = env[:machine]
|
15
|
+
if(machine.config.hypervnet.install_ssh_server)
|
16
|
+
if machine.guest.capability?(:sshd_installed) && !machine.guest.capability(:sshd_installed)
|
17
|
+
@logger.info("Installing OpenSSH server...")
|
18
|
+
machine.guest.capability(:sshd_install)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Continue the middleware chain.
|
23
|
+
@app.call(env)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative 'action/disable_builtin_network_configure'
|
2
|
+
require_relative 'action/network'
|
3
|
+
require_relative 'action/ssh_server'
|
4
|
+
|
5
|
+
module VagrantPlugins
|
6
|
+
module HyperVNet
|
7
|
+
module Action
|
8
|
+
include Vagrant::Action::Builtin
|
9
|
+
|
10
|
+
def self.disable_builtin_network_configure
|
11
|
+
Vagrant::Action::Builder.new.tap do |builder|
|
12
|
+
builder.use DisableBuiltinNetworkConfigure
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.network
|
17
|
+
Vagrant::Action::Builder.new.tap do |builder|
|
18
|
+
builder.use ConfigValidate
|
19
|
+
builder.use Network
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.ssh_server
|
24
|
+
Vagrant::Action::Builder.new.tap do |builder|
|
25
|
+
builder.use ConfigValidate
|
26
|
+
builder.use SshServer
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module HyperVNet
|
5
|
+
module Cap
|
6
|
+
module Linux
|
7
|
+
class NicMacAddresses
|
8
|
+
|
9
|
+
POSSIBLE_ETHERNET_PREFIXES = ["eth".freeze, "en".freeze].freeze
|
10
|
+
|
11
|
+
@@logger = Log4r::Logger.new("vagrant::hypervnet::guest::linux::nic_mac_addresses")
|
12
|
+
|
13
|
+
def self.nic_mac_addresses(machine)
|
14
|
+
s = ""
|
15
|
+
machine.communicate.execute("ip -o link | grep -v LOOPBACK | awk '{print $2 \"|\" $17}' | sed 's/://'") do |type, data|
|
16
|
+
s << data if type == :stdout
|
17
|
+
end
|
18
|
+
|
19
|
+
ifaces = s.split("\n").map { |line|
|
20
|
+
parts = line.split("|")
|
21
|
+
iface = {}
|
22
|
+
iface[:name] = parts[0]
|
23
|
+
iface[:mac_address] = parts[1]
|
24
|
+
iface[:parts] = iface[:name].scan(/(.+?)(\d+)?/).flatten.map do |name_part|
|
25
|
+
if name_part.to_i.to_s == name_part
|
26
|
+
name_part.to_i
|
27
|
+
else
|
28
|
+
name_part
|
29
|
+
end
|
30
|
+
end
|
31
|
+
iface
|
32
|
+
}
|
33
|
+
|
34
|
+
@@logger.debug("Unsorted list: #{ifaces.inspect}")
|
35
|
+
|
36
|
+
ifaces = ifaces.uniq.sort do |lhs, rhs|
|
37
|
+
result = 0
|
38
|
+
slice_length = [rhs[:parts].size, lhs[:parts].size].min
|
39
|
+
slice_length.times do |idx|
|
40
|
+
if(lhs[:parts][idx].is_a?(rhs[:parts][idx].class))
|
41
|
+
result = lhs[:parts][idx] <=> rhs[:parts][idx]
|
42
|
+
elsif(lhs[:parts][idx].is_a?(String))
|
43
|
+
result = 1
|
44
|
+
else
|
45
|
+
result = -1
|
46
|
+
end
|
47
|
+
break if result != 0
|
48
|
+
end
|
49
|
+
result
|
50
|
+
end
|
51
|
+
@@logger.debug("Sorted list: #{ifaces.inspect}")
|
52
|
+
|
53
|
+
ifaces.each do |iface|
|
54
|
+
iface.delete(:parts)
|
55
|
+
end
|
56
|
+
|
57
|
+
resorted_ifaces = []
|
58
|
+
resorted_ifaces += ifaces.find_all do |iface|
|
59
|
+
POSSIBLE_ETHERNET_PREFIXES.any?{|prefix| iface[:name].start_with?(prefix)} &&
|
60
|
+
iface[:name].match(/^[a-zA-Z0-9]+$/)
|
61
|
+
end
|
62
|
+
resorted_ifaces += ifaces - resorted_ifaces
|
63
|
+
ifaces = resorted_ifaces
|
64
|
+
@@logger.debug("Ethernet preferred sorted list: #{ifaces.inspect}")
|
65
|
+
ifaces
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|