vagrant-skytap 0.2.10 → 0.3.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/CHANGELOG.md +7 -0
- data/lib/vagrant-skytap/action/check_created.rb +43 -0
- data/lib/vagrant-skytap/action/check_running.rb +43 -0
- data/lib/vagrant-skytap/action/get_host_vm.rb +52 -0
- data/lib/vagrant-skytap/action/prepare_nfs_settings.rb +22 -5
- data/lib/vagrant-skytap/action.rb +11 -18
- data/lib/vagrant-skytap/api/connectable.rb +50 -0
- data/lib/vagrant-skytap/api/environment.rb +10 -5
- data/lib/vagrant-skytap/api/interface.rb +9 -0
- data/lib/vagrant-skytap/api/network.rb +60 -1
- data/lib/vagrant-skytap/api/public_ip.rb +7 -75
- data/lib/vagrant-skytap/api/publish_set.rb +4 -0
- data/lib/vagrant-skytap/api/published_service.rb +7 -71
- data/lib/vagrant-skytap/api/resource.rb +25 -3
- data/lib/vagrant-skytap/api/tunnel.rb +69 -0
- data/lib/vagrant-skytap/api/vm.rb +10 -2
- data/lib/vagrant-skytap/api/vpn.rb +2 -106
- data/lib/vagrant-skytap/cap/host_metadata.rb +45 -0
- data/lib/vagrant-skytap/connection/public_ip_choice.rb +94 -0
- data/lib/vagrant-skytap/connection/published_service_choice.rb +100 -0
- data/lib/vagrant-skytap/connection/tunnel_choice.rb +118 -0
- data/lib/vagrant-skytap/connection/vpn_choice.rb +132 -0
- data/lib/vagrant-skytap/connection.rb +123 -0
- data/lib/vagrant-skytap/errors.rb +4 -0
- data/lib/vagrant-skytap/plugin.rb +5 -0
- data/lib/vagrant-skytap/setup_helper.rb +34 -8
- data/lib/vagrant-skytap/version.rb +1 -1
- data/locales/en.yml +46 -0
- data/spec/unit/actions/prepare_nfs_settings_spec.rb +63 -16
- data/spec/unit/cap/host_metadata_spec.rb +43 -0
- data/spec/unit/connections/public_ip_choice_spec.rb +57 -0
- data/spec/unit/connections/published_service_choice_spec.rb +79 -0
- data/spec/unit/connections/tunnel_choice_spec.rb +124 -0
- data/spec/unit/connections/vpn_choice_spec.rb +109 -0
- data/spec/unit/interface_spec.rb +53 -0
- data/spec/unit/network_spec.rb +123 -0
- data/spec/unit/setup_helper_spec.rb +59 -19
- data/spec/unit/support/api_responses/tunnel1.json +7 -0
- data/spec/unit/support/api_responses/vm1.json +12 -1
- data/spec/unit/support/shared/rest_api_context.rb +1 -0
- data/spec/unit/tunnel_spec.rb +62 -0
- data/spec/unit/vm_spec.rb +53 -60
- metadata +22 -2
@@ -0,0 +1,118 @@
|
|
1
|
+
# Copyright (c) 2014-2016 Skytap, Inc.
|
2
|
+
#
|
3
|
+
# The MIT License (MIT)
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
20
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
21
|
+
# DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
require 'vagrant-skytap/connection'
|
24
|
+
|
25
|
+
# An ICNR tunnel connects networks in two different Skytap environments.
|
26
|
+
# In the case where the host is a Skytap VM, a tunnel is the most convenient
|
27
|
+
# way of establishing communication with the guest VM.
|
28
|
+
|
29
|
+
module VagrantPlugins
|
30
|
+
module Skytap
|
31
|
+
module Connection
|
32
|
+
class TunnelChoice < Choice
|
33
|
+
attr_reader :host_network, :guest_network
|
34
|
+
|
35
|
+
def initialize(env, host_network, iface)
|
36
|
+
@env = env
|
37
|
+
@iface = iface
|
38
|
+
@host_network = host_network
|
39
|
+
@guest_network = iface.network
|
40
|
+
@execution = TunnelExecution.make(env, iface, host_network)
|
41
|
+
end
|
42
|
+
|
43
|
+
def choose
|
44
|
+
execution.execute
|
45
|
+
@iface = iface.vm.reload.get_interface_by_id(iface.id)
|
46
|
+
@host_network = host_network.environment.reload.networks.find{|n| n.id == host_network.id}
|
47
|
+
nat_address = iface.nat_address_for_network(host_network)
|
48
|
+
[nat_address, DEFAULT_PORT]
|
49
|
+
end
|
50
|
+
|
51
|
+
def valid?
|
52
|
+
@validation_error_message = nil
|
53
|
+
|
54
|
+
unless host_network.tunnelable?
|
55
|
+
@validation_error_message = I18n.t("vagrant_skytap.connections.tunnel.errors.host_network_not_tunnelable")
|
56
|
+
return false
|
57
|
+
end
|
58
|
+
|
59
|
+
unless host_network.nat_enabled?
|
60
|
+
@validation_error_message = I18n.t("vagrant_skytap.connections.tunnel.errors.host_network_nat_disabled")
|
61
|
+
return false
|
62
|
+
end
|
63
|
+
|
64
|
+
unless guest_network.nat_enabled?
|
65
|
+
if guest_network.subnet.overlaps?(host_network.subnet)
|
66
|
+
@validation_error_message = I18n.t("vagrant_skytap.connections.tunnel.errors.guest_network_overlaps")
|
67
|
+
return false
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
true
|
72
|
+
end
|
73
|
+
|
74
|
+
class TunnelExecution < Execution
|
75
|
+
attr_reader :host_network, :guest_network
|
76
|
+
|
77
|
+
def self.make(env, iface, host_network)
|
78
|
+
if host_network.try(:connected_to_network?, iface.network)
|
79
|
+
UseExecution.new(env, iface, host_network)
|
80
|
+
else
|
81
|
+
CreateAndUseExecution.new(env, iface, host_network)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def initialize(env, iface, host_network)
|
86
|
+
super
|
87
|
+
@host_network = host_network
|
88
|
+
@guest_network = iface.network
|
89
|
+
end
|
90
|
+
|
91
|
+
def message
|
92
|
+
"#{verb}: #{host_network.name}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class UseExecution < TunnelExecution
|
97
|
+
def verb
|
98
|
+
I18n.t("vagrant_skytap.connections.tunnel.verb_use")
|
99
|
+
end
|
100
|
+
|
101
|
+
def execute
|
102
|
+
# No-op
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class CreateAndUseExecution < TunnelExecution
|
107
|
+
def verb
|
108
|
+
I18n.t("vagrant_skytap.connections.tunnel.verb_create_and_use")
|
109
|
+
end
|
110
|
+
|
111
|
+
def execute
|
112
|
+
guest_network.connect_to_network(host_network)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# Copyright (c) 2014-2016 Skytap, Inc.
|
2
|
+
#
|
3
|
+
# The MIT License (MIT)
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
20
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
21
|
+
# DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
require 'vagrant-skytap/connection'
|
24
|
+
require 'vagrant-skytap/api/vpn_attachment'
|
25
|
+
|
26
|
+
module VagrantPlugins
|
27
|
+
module Skytap
|
28
|
+
module Connection
|
29
|
+
class VpnChoice < Choice
|
30
|
+
attr_reader :vm, :vpn, :attachment
|
31
|
+
|
32
|
+
def initialize(env, vpn, vm)
|
33
|
+
@env = env
|
34
|
+
@vpn = vpn
|
35
|
+
@vm = vm
|
36
|
+
@iface = select_interface(vm, vpn)
|
37
|
+
@execution = VPNAttachmentExecution.make(env, iface, vpn)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Finds an interface on the guest VM which is connected to a network
|
41
|
+
# which lies inside the VPN's subnet. If the VPN is NAT enabled, this
|
42
|
+
# method simply returns the first interface.
|
43
|
+
#
|
44
|
+
# @param [API::Vm] vm The guest VM
|
45
|
+
# @param [API::Vpn] vpn The VPN this VpnChoice will connect to
|
46
|
+
# @return [API::Interface] An interface connected to a suitable network
|
47
|
+
def select_interface(vm, vpn)
|
48
|
+
vm.interfaces.select(&:network).tap do |ifaces|
|
49
|
+
unless vpn.nat_enabled?
|
50
|
+
ifaces.select! {|i| vpn.subsumes?(i.network) }
|
51
|
+
end
|
52
|
+
end.first
|
53
|
+
end
|
54
|
+
|
55
|
+
def choose
|
56
|
+
execution.execute
|
57
|
+
@iface = vm.reload.get_interface_by_id(iface.id)
|
58
|
+
host = iface.address_for(vpn)
|
59
|
+
[host, DEFAULT_PORT]
|
60
|
+
end
|
61
|
+
|
62
|
+
# To communicate with the guest VM over a VPN, the guest's network
|
63
|
+
# must be both attached and connected to the VPN. The various
|
64
|
+
# subclasses perform different REST calls depending on which of these
|
65
|
+
# conditions are already met.
|
66
|
+
class VPNAttachmentExecution < Execution
|
67
|
+
attr_reader :vpn, :attachment
|
68
|
+
|
69
|
+
def self.make(env, iface, vpn)
|
70
|
+
attachment = iface.attachment_for(vpn)
|
71
|
+
|
72
|
+
if attachment.try(:connected?)
|
73
|
+
UseExecution.new(env, iface, vpn, attachment)
|
74
|
+
elsif attachment
|
75
|
+
ConnectAndUseExecution.new(env, iface, vpn, attachment)
|
76
|
+
else
|
77
|
+
AttachConnectAndUseExecution.new(env, iface, vpn)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def initialize(env, iface, vpn, attachment=nil)
|
82
|
+
super
|
83
|
+
@vpn = vpn
|
84
|
+
@attachment = attachment
|
85
|
+
end
|
86
|
+
|
87
|
+
def message
|
88
|
+
"#{verb}: #{vpn.name}".tap do |ret|
|
89
|
+
if vpn.nat_enabled?
|
90
|
+
ret << " " << I18n.t("vagrant_skytap.connections.vpn_attachment.nat_enabled")
|
91
|
+
else
|
92
|
+
ret << " " << I18n.t("vagrant_skytap.connections.vpn_attachment.local_subnet",
|
93
|
+
local_subnet: vpn.local_subnet)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class UseExecution < VPNAttachmentExecution
|
100
|
+
def verb
|
101
|
+
I18n.t("vagrant_skytap.connections.vpn_attachment.verb_use")
|
102
|
+
end
|
103
|
+
|
104
|
+
def execute
|
105
|
+
# No-op
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
class ConnectAndUseExecution < VPNAttachmentExecution
|
110
|
+
def verb
|
111
|
+
I18n.t("vagrant_skytap.connections.vpn_attachment.verb_connect")
|
112
|
+
end
|
113
|
+
|
114
|
+
def execute
|
115
|
+
attachment.connect!
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class AttachConnectAndUseExecution < VPNAttachmentExecution
|
120
|
+
def verb
|
121
|
+
I18n.t("vagrant_skytap.connections.vpn_attachment.verb_attach")
|
122
|
+
end
|
123
|
+
|
124
|
+
def execute
|
125
|
+
@attachment = API::VpnAttachment.create(iface.network, vpn, env)
|
126
|
+
@attachment.connect!
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# Copyright (c) 2014-2016 Skytap, Inc.
|
2
|
+
#
|
3
|
+
# The MIT License (MIT)
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
20
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
21
|
+
# DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
require 'net/ssh/transport/session'
|
24
|
+
|
25
|
+
# Encapsulates a chooseable option for establishing communication with the
|
26
|
+
# guest VM over SSH/WinRM. All valid options (e.g. using specific VPNs,
|
27
|
+
# creating a published service, etc.) are collected as Choices and
|
28
|
+
# presented to the user.
|
29
|
+
|
30
|
+
module VagrantPlugins
|
31
|
+
module Skytap
|
32
|
+
module Connection
|
33
|
+
DEFAULT_PORT = Net::SSH::Transport::Session::DEFAULT_PORT
|
34
|
+
|
35
|
+
# A Choice represents the potential for establishing a connection to the
|
36
|
+
# guest VM via a specific resource.
|
37
|
+
class Choice
|
38
|
+
attr_reader :env, :iface, :execution, :validation_error_message
|
39
|
+
|
40
|
+
# Thia method should be overridden to call #make on the
|
41
|
+
# [Connection::Execution] subclass for this particular resource type.
|
42
|
+
# The execution holds all the information needed to establish the
|
43
|
+
# connection.
|
44
|
+
def initialize(*args)
|
45
|
+
@env = args.first
|
46
|
+
end
|
47
|
+
|
48
|
+
# Invokes the execution, and determines the IP address and port for
|
49
|
+
# communicating with the guest VM.
|
50
|
+
#
|
51
|
+
# @return [Array] Tuple of [String], [Integer] The IP address and port
|
52
|
+
# for communicating with the guest VM.
|
53
|
+
def choose
|
54
|
+
raise NotImplementedError.new('Must override')
|
55
|
+
end
|
56
|
+
|
57
|
+
# Override this method to add any validation logic needed by a specific
|
58
|
+
# resource type. For example, [Connection::TunnelChoice] must check for
|
59
|
+
# subnet overlaps. If this method returns false, this particular choice
|
60
|
+
# should not be offered to the user. For some resource types, it may
|
61
|
+
# be useful to set @validation_error_message on this choice when
|
62
|
+
# returning false.
|
63
|
+
#
|
64
|
+
# @return [Boolean]
|
65
|
+
def valid?
|
66
|
+
true
|
67
|
+
end
|
68
|
+
|
69
|
+
def to_s
|
70
|
+
execution.message
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# An Execution implements a strategy for establishing a connection
|
75
|
+
# to the guest VM using a given resource. A resource may have more
|
76
|
+
# than one strategy, depending on the initial state of the connection.
|
77
|
+
# (When the guest VM is first created, no connection will exist.)
|
78
|
+
class Execution
|
79
|
+
attr_reader :env, :iface
|
80
|
+
|
81
|
+
def initialize(*args)
|
82
|
+
@env, @iface, _ = args
|
83
|
+
end
|
84
|
+
|
85
|
+
# Creates an execution object which will perform the correct actions
|
86
|
+
# to establish a connection via a specific connectable resource. This
|
87
|
+
# method should be overridden to return an object of the correct
|
88
|
+
# execution subclass given the resource's initial state. For example,
|
89
|
+
# if the guest's network is already attached to this VPN, but
|
90
|
+
# disconnected, this method would return a ConnectAndUseExecution.
|
91
|
+
#
|
92
|
+
# @return [Connection::Execution]
|
93
|
+
def make(*args)
|
94
|
+
raise NotImplementedError.new('Must override')
|
95
|
+
end
|
96
|
+
|
97
|
+
# Performs the API calls which establish the connection for
|
98
|
+
# communicating with the guest VM. If the connection is already
|
99
|
+
# established, as in the case of a guest VM which already exists,
|
100
|
+
# this may be a no-op.
|
101
|
+
def execute
|
102
|
+
raise NotImplementedError.new('Must override')
|
103
|
+
end
|
104
|
+
|
105
|
+
# The name of the action(s) performed by this execution subclass,
|
106
|
+
# e.g. "Connect and use".
|
107
|
+
#
|
108
|
+
# @return [String]
|
109
|
+
def verb
|
110
|
+
raise NotImplementedError.new('Must override')
|
111
|
+
end
|
112
|
+
|
113
|
+
# The description of the actions to be taken when this choice is
|
114
|
+
# executed, e.g. "Connect to and use VPN 1".
|
115
|
+
#
|
116
|
+
# @return [String]
|
117
|
+
def message
|
118
|
+
verb
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -89,6 +89,10 @@ module VagrantPlugins
|
|
89
89
|
error_key(:no_connection_options)
|
90
90
|
end
|
91
91
|
|
92
|
+
class NoSkytapConnectionOptions < VagrantSkytapError
|
93
|
+
error_key(:no_skytap_connection_options)
|
94
|
+
end
|
95
|
+
|
92
96
|
class FeatureNotSupportedForHostOs < VagrantSkytapError
|
93
97
|
error_key(:feature_not_supported_for_host_os)
|
94
98
|
end
|
@@ -71,6 +71,11 @@ module VagrantPlugins
|
|
71
71
|
Cap::PublicAddress
|
72
72
|
end
|
73
73
|
|
74
|
+
provider_capability(:skytap, :host_metadata) do
|
75
|
+
require_relative "cap/host_metadata"
|
76
|
+
Cap::HostMetadata
|
77
|
+
end
|
78
|
+
|
74
79
|
%w[start_ssh_tunnel kill_ssh_tunnel clear_forwarded_ports read_forwarded_ports read_used_ports].each do |cap|
|
75
80
|
host_capability("bsd", cap) do
|
76
81
|
require_relative "hosts/bsd/cap/ssh_tunnel"
|
@@ -29,7 +29,7 @@ require 'net/ssh/transport/session'
|
|
29
29
|
module VagrantPlugins
|
30
30
|
module Skytap
|
31
31
|
class SetupHelper
|
32
|
-
attr_reader :env, :environment, :machine, :provider_config
|
32
|
+
attr_reader :env, :environment, :host_vm, :machine, :provider_config
|
33
33
|
attr_reader :username, :password, :host, :port
|
34
34
|
|
35
35
|
def self.run!(env, environment)
|
@@ -40,6 +40,7 @@ module VagrantPlugins
|
|
40
40
|
@env = env
|
41
41
|
@logger = Log4r::Logger.new("vagrant_skytap::setup_helper")
|
42
42
|
@environment = environment
|
43
|
+
@host_vm = env[:vagrant_host_vm]
|
43
44
|
@machine = env[:machine]
|
44
45
|
@provider_config = env[:machine].provider_config
|
45
46
|
@username = @machine.config.ssh.username
|
@@ -54,6 +55,10 @@ module VagrantPlugins
|
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
58
|
+
def running_in_skytap_vm?
|
59
|
+
!!host_vm
|
60
|
+
end
|
61
|
+
|
57
62
|
def run!
|
58
63
|
ask_routing
|
59
64
|
ask_credentials
|
@@ -94,30 +99,46 @@ module VagrantPlugins
|
|
94
99
|
end
|
95
100
|
|
96
101
|
def ask_routing
|
97
|
-
@logger.debug("ask_routing")
|
98
102
|
unless host && port
|
99
103
|
iface = current_vm.interfaces.first
|
100
|
-
choices = connection_choices(iface)
|
104
|
+
choices = connection_choices(iface)
|
105
|
+
|
106
|
+
if running_in_skytap_vm?
|
107
|
+
unless choices.any?(&:valid?)
|
108
|
+
raise Errors::NoSkytapConnectionOptions, message: choices.collect(&:validation_error_message).first
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
choices.select!(&:valid?)
|
101
113
|
raise Errors::NoConnectionOptions unless choices.present?
|
102
114
|
|
103
|
-
|
115
|
+
choice = nil
|
116
|
+
if !running_in_skytap_vm? && vpn_url = @provider_config.vpn_url
|
104
117
|
choice = choices.detect do |choice|
|
105
118
|
choice.vpn && vpn_url.include?(choice.vpn.id)
|
106
119
|
end
|
107
120
|
raise Errors::DoesNotExist, object_name: vpn_url unless choice
|
108
|
-
|
121
|
+
elsif choices.count == 1
|
122
|
+
choice = choices.first
|
123
|
+
env[:ui].info("Using only available connection option: #{choice}")
|
109
124
|
else
|
110
125
|
question = "How do you want to connect to machine '#{@machine.name}'?"
|
111
|
-
ask_from_list(question, choices, 0) do |i,
|
112
|
-
|
126
|
+
ask_from_list(question, choices, 0) do |i, _choice|
|
127
|
+
choice = _choice
|
113
128
|
end
|
114
129
|
end
|
130
|
+
@host, @port = choice.choose
|
115
131
|
end
|
132
|
+
@logger.debug("ask_routing returning guest VM address and port: #{@host}:#{@port}")
|
116
133
|
[@host, @port]
|
117
134
|
end
|
118
135
|
|
119
136
|
def connection_choices(iface)
|
120
|
-
|
137
|
+
if running_in_skytap_vm?
|
138
|
+
tunnel_choices(iface)
|
139
|
+
else
|
140
|
+
vpn_choices(iface)
|
141
|
+
end
|
121
142
|
end
|
122
143
|
|
123
144
|
def vpn_choices(iface)
|
@@ -137,6 +158,11 @@ module VagrantPlugins
|
|
137
158
|
iface.published_service_choices
|
138
159
|
end
|
139
160
|
|
161
|
+
def tunnel_choices(guest_iface)
|
162
|
+
candidates = host_vm.interfaces.collect(&:network)
|
163
|
+
candidates.collect {|network| network.choice_for_setup(guest_iface) }
|
164
|
+
end
|
165
|
+
|
140
166
|
def vpns
|
141
167
|
VagrantPlugins::Skytap::API::Vpn.all(env, query: {region: environment.region})
|
142
168
|
end
|
data/locales/en.yml
CHANGED
@@ -100,6 +100,11 @@ en:
|
|
100
100
|
There were no available options for connecting to the VM.
|
101
101
|
Currently, the provider supports connections over VPN only.
|
102
102
|
|
103
|
+
no_skytap_connection_options: |-
|
104
|
+
Could not establish a connection between the host and guest VMs.
|
105
|
+
%{message}
|
106
|
+
Please correct the problem and try again.
|
107
|
+
|
103
108
|
bad_vm_url: |-
|
104
109
|
The specified vm_url was invalid: %{url}
|
105
110
|
|
@@ -143,6 +148,47 @@ en:
|
|
143
148
|
long_busy: |-
|
144
149
|
The Skytap instance is busy. Wait for the current operation to complete.
|
145
150
|
|
151
|
+
connections:
|
152
|
+
vpn_attachment:
|
153
|
+
verb_use: |-
|
154
|
+
Use VPN
|
155
|
+
verb_connect: |-
|
156
|
+
Connect to and use VPN
|
157
|
+
verb_attach: |-
|
158
|
+
Attach to and use VPN
|
159
|
+
nat_enabled: |-
|
160
|
+
(NAT-enabled)
|
161
|
+
local_subnet: |-
|
162
|
+
(local subnet: %{local_subnet})
|
163
|
+
published_service:
|
164
|
+
verb_use: |-
|
165
|
+
Use published service
|
166
|
+
verb_create_and_use: |-
|
167
|
+
Create and use published service
|
168
|
+
public_ip:
|
169
|
+
verb_use: |-
|
170
|
+
Use public IP
|
171
|
+
verb_attach: |-
|
172
|
+
Attach and use public IP
|
173
|
+
deployed: |-
|
174
|
+
(attached and deployed to another VM)
|
175
|
+
attached: |-
|
176
|
+
(attached to another VM)
|
177
|
+
tunnel:
|
178
|
+
verb_use: |-
|
179
|
+
Use existing tunnel to host network
|
180
|
+
verb_create_and_use: |-
|
181
|
+
Create and use tunnel to host network
|
182
|
+
errors:
|
183
|
+
host_network_not_tunnelable: |-
|
184
|
+
The host's network must be tunnelable.
|
185
|
+
host_network_nat_disabled: |-
|
186
|
+
The host's network must have NAT enabled.
|
187
|
+
guest_network_overlaps: |-
|
188
|
+
The guest's network subnet overlaps with the host's network.
|
189
|
+
(This can be resolved by changing network subnets, or by
|
190
|
+
enabling NAT on the guest network.)
|
191
|
+
|
146
192
|
commands:
|
147
193
|
publish_urls:
|
148
194
|
list: |-
|
@@ -26,8 +26,12 @@ require "vagrant-skytap/action/prepare_nfs_settings"
|
|
26
26
|
describe VagrantPlugins::Skytap::Action::PrepareNFSSettings do
|
27
27
|
include_context "skytap"
|
28
28
|
|
29
|
-
let(:
|
30
|
-
let(:
|
29
|
+
let(:json_path) { File.join(File.expand_path('..', __FILE__), 'support', 'api_responses') }
|
30
|
+
let(:vm1_attrs) { read_json(json_path, 'vm1.json') }
|
31
|
+
|
32
|
+
let(:app) { lambda { |env| } }
|
33
|
+
let(:host_vm) { nil }
|
34
|
+
let(:env) { { machine: machine, ui: ui, host_vm: host_vm} }
|
31
35
|
|
32
36
|
let(:machine) { double(:machine, config: config, provider_config: provider_config, ssh_info: {host: guest_ip}) }
|
33
37
|
let(:config) { double(:config, vm: vm_config) }
|
@@ -37,21 +41,42 @@ describe VagrantPlugins::Skytap::Action::PrepareNFSSettings do
|
|
37
41
|
let(:guest_ip) { '192.168.0.1' }
|
38
42
|
let(:using_nfs) { false }
|
39
43
|
|
44
|
+
let(:udpsocket) { double("UDPSocket") }
|
45
|
+
let(:addresses) { ["AF_INET", 99999, '127.0.0.1', host_ip] }
|
46
|
+
let(:socket) { double(:socket, connect: nil, addr: addresses) }
|
47
|
+
|
48
|
+
let(:nat_host_ip) { '10.0.4.1' }
|
49
|
+
let(:nat_guest_ip) { '14.0.0.1' }
|
50
|
+
let(:guest_network) { double(:guest_network, id: "2", attrs: {}, :nat_enabled? => false) }
|
51
|
+
let(:guest_iface) { double(:guest_iface, network: guest_network) }
|
52
|
+
let(:guest_vm) { double(:guest_vm, interfaces: [guest_iface]) }
|
53
|
+
|
54
|
+
let(:default_hostpath) {"."}
|
55
|
+
let(:default_disabled) { false }
|
56
|
+
let(:default_type) { nil }
|
40
57
|
let(:default_folder_props) do
|
41
|
-
{guestpath: "/vagrant", hostpath:
|
58
|
+
{guestpath: "/vagrant", hostpath: default_hostpath, disabled: default_disabled, type: default_type}
|
42
59
|
end
|
43
60
|
let(:synced_folders) { { "/vagrant" => default_folder_props } }
|
44
61
|
|
45
|
-
let(:instance)
|
62
|
+
let(:instance) do
|
63
|
+
described_class.new(app, env).tap do |instance|
|
64
|
+
allow(instance).to receive(:machine).and_return(machine)
|
65
|
+
allow(instance).to receive(:host_vm).and_return(host_vm)
|
66
|
+
allow(instance).to receive(:current_vm).and_return(guest_vm)
|
67
|
+
end
|
68
|
+
end
|
46
69
|
|
47
70
|
before do
|
48
|
-
|
49
|
-
allow(
|
50
|
-
allow(subject).to receive(:read_host_ip).and_return(host_ip)
|
71
|
+
stub_const("UDPSocket", udpsocket)
|
72
|
+
allow(udpsocket).to receive(:open).and_yield(socket)
|
51
73
|
end
|
52
74
|
|
53
75
|
describe "#call" do
|
54
76
|
subject {instance}
|
77
|
+
before do
|
78
|
+
allow(subject).to receive(:using_nfs?).and_return(using_nfs)
|
79
|
+
end
|
55
80
|
|
56
81
|
context "when not using nfs" do
|
57
82
|
it "does not set the host and guest ip addresses" do
|
@@ -82,25 +107,47 @@ describe VagrantPlugins::Skytap::Action::PrepareNFSSettings do
|
|
82
107
|
end
|
83
108
|
|
84
109
|
context "when its type is rsync" do
|
85
|
-
let(:
|
86
|
-
{guestpath: "/vagrant", hostpath: ".", disabled: false, type: :rsync}
|
87
|
-
end
|
110
|
+
let(:default_type) { :rsync }
|
88
111
|
it {should be false }
|
89
112
|
end
|
90
113
|
|
91
114
|
context "when its type is nfs" do
|
92
|
-
let(:
|
93
|
-
{guestpath: "/vagrant", hostpath: ".", disabled: false, type: :nfs}
|
94
|
-
end
|
115
|
+
let(:default_type) { :nfs }
|
95
116
|
it {should be true }
|
96
117
|
|
97
118
|
context "when it is disabled" do
|
98
|
-
let(:
|
99
|
-
{guestpath: "/vagrant", hostpath: ".", disabled: true, type: :nfs}
|
100
|
-
end
|
119
|
+
let(:default_disabled) { true }
|
101
120
|
it {should be false }
|
102
121
|
end
|
103
122
|
end
|
104
123
|
end
|
105
124
|
end
|
125
|
+
|
126
|
+
describe "read_host_ip" do
|
127
|
+
subject { instance.read_host_ip }
|
128
|
+
|
129
|
+
context "when not running in a VM" do
|
130
|
+
it { should eq host_ip }
|
131
|
+
end
|
132
|
+
|
133
|
+
context "when running in a VM" do
|
134
|
+
let(:host_iface) { double(:host_iface, nat_address_for_network: nat_host_ip) }
|
135
|
+
let(:host_vm) { double(:host_vm, interfaces: [host_iface]) }
|
136
|
+
|
137
|
+
before do
|
138
|
+
allow(host_vm).to receive(:reload).and_return(host_vm)
|
139
|
+
end
|
140
|
+
|
141
|
+
context "when guest network is not NAT enabled" do
|
142
|
+
it { should eq host_ip }
|
143
|
+
end
|
144
|
+
|
145
|
+
context "when guest network is NAT enabled" do
|
146
|
+
before do
|
147
|
+
allow(guest_network).to receive(:nat_enabled?).and_return(true)
|
148
|
+
end
|
149
|
+
it { should eq nat_host_ip }
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
106
153
|
end
|