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.
Files changed (32) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +16 -0
  3. data/README.md +54 -0
  4. data/Rakefile +8 -0
  5. data/Vagrantfile +104 -0
  6. data/lib/vagrant-hypervnet/action/disable_builtin_network_configure.rb +39 -0
  7. data/lib/vagrant-hypervnet/action/network.rb +328 -0
  8. data/lib/vagrant-hypervnet/action/ssh_server.rb +28 -0
  9. data/lib/vagrant-hypervnet/action.rb +31 -0
  10. data/lib/vagrant-hypervnet/cap/linux/nic_mac_addresses.rb +71 -0
  11. data/lib/vagrant-hypervnet/cap/linux/pre_configure_networks.rb +31 -0
  12. data/lib/vagrant-hypervnet/cap/vyos/post_configure_networks.rb +45 -0
  13. data/lib/vagrant-hypervnet/cap/windows/rsync.rb +60 -0
  14. data/lib/vagrant-hypervnet/cap/windows/sshd.rb +151 -0
  15. data/lib/vagrant-hypervnet/cap.rb +15 -0
  16. data/lib/vagrant-hypervnet/config.rb +36 -0
  17. data/lib/vagrant-hypervnet/driver.rb +197 -0
  18. data/lib/vagrant-hypervnet/errors.rb +34 -0
  19. data/lib/vagrant-hypervnet/scripts/add_vm_adapter.ps1 +15 -0
  20. data/lib/vagrant-hypervnet/scripts/connect_vm_adapter.ps1 +12 -0
  21. data/lib/vagrant-hypervnet/scripts/get_switch_by_address.ps1 +22 -0
  22. data/lib/vagrant-hypervnet/scripts/get_switch_by_name.ps1 +17 -0
  23. data/lib/vagrant-hypervnet/scripts/get_vm_adapters.ps1 +11 -0
  24. data/lib/vagrant-hypervnet/scripts/new_switch.ps1 +26 -0
  25. data/lib/vagrant-hypervnet/scripts/remove_vm_adapter.ps1 +9 -0
  26. data/lib/vagrant-hypervnet/scripts/utils/VagrantMessages/VagrantMessages.psm1 +27 -0
  27. data/lib/vagrant-hypervnet/version.rb +7 -0
  28. data/lib/vagrant-hypervnet.rb +89 -0
  29. data/locales/en.yml +69 -0
  30. data/sig/vagrant/hypervnet.rbs +6 -0
  31. data/vagrant-hypervnet.gemspec +26 -0
  32. 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
+ [![Gem Version](https://badge.fury.io/rb/vagrant-hypervnet.svg)](https://badge.fury.io/rb/vagrant-hypervnet)
7
+ [![Downloads](http://ruby-gem-downloads-badge.herokuapp.com/vagrant-hypervnet?type=total&style=flat)](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
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ #require "bundler/gem_tasks"
4
+ #task default: %i[]
5
+
6
+ require "rubygems"
7
+ require "bundler/setup"
8
+ Bundler::GemHelper.install_tasks
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