Merge pull request #6591 from mitchellh/sethvargo/ports
Add `vagrant port` command
This commit is contained in:
commit
c24a44a7c6
|
@ -0,0 +1,90 @@
|
||||||
|
require "vagrant/util/presence"
|
||||||
|
|
||||||
|
require "optparse"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandPort
|
||||||
|
class Command < Vagrant.plugin("2", :command)
|
||||||
|
include Vagrant::Util::Presence
|
||||||
|
|
||||||
|
def self.synopsis
|
||||||
|
"displays information about guest port mappings"
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant port [options] [name]"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
|
||||||
|
o.on("--guest PORT", "Output the host port that maps to the given guest port") do |port|
|
||||||
|
options[:guest] = port
|
||||||
|
end
|
||||||
|
|
||||||
|
o.on("--machine-readable", "Display machine-readable output")
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
|
||||||
|
with_target_vms(argv, single_target: true) do |vm|
|
||||||
|
vm.action_raw(:config_validate,
|
||||||
|
Vagrant::Action::Builtin::ConfigValidate)
|
||||||
|
|
||||||
|
if !vm.provider.capability?(:forwarded_ports)
|
||||||
|
@env.ui.error(I18n.t("port_command.missing_capability",
|
||||||
|
provider: vm.provider_name,
|
||||||
|
))
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
ports = vm.provider.capability(:forwarded_ports)
|
||||||
|
|
||||||
|
if !present?(ports)
|
||||||
|
@env.ui.info(I18n.t("port_command.empty_ports"))
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
if present?(options[:guest])
|
||||||
|
return print_single(vm, ports, options[:guest])
|
||||||
|
else
|
||||||
|
return print_all(vm, ports)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Print all the guest <=> host port mappings.
|
||||||
|
# @return [0] the exit code
|
||||||
|
def print_all(vm, ports)
|
||||||
|
@env.ui.info(I18n.t("port_command.details"))
|
||||||
|
@env.ui.info("")
|
||||||
|
ports.each do |host, guest|
|
||||||
|
@env.ui.info("#{guest.to_s.rjust(6)} (guest) => #{host} (host)")
|
||||||
|
@env.ui.machine("forwarded_port", guest, host, target: vm.name.to_s)
|
||||||
|
end
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
# Print the host mapping that matches the given guest target.
|
||||||
|
# @return [0,1] the exit code
|
||||||
|
def print_single(vm, ports, target)
|
||||||
|
map = ports.find { |_, guest| "#{guest}" == "#{target}" }
|
||||||
|
if !present?(map)
|
||||||
|
@env.ui.error(I18n.t("port_command.no_matching_port",
|
||||||
|
port: target,
|
||||||
|
))
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
@env.ui.info("#{map[0]}")
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,20 @@
|
||||||
|
en:
|
||||||
|
port_command:
|
||||||
|
details: |-
|
||||||
|
The forwarded ports for the machine are listed below. Please note that
|
||||||
|
these values may differ from values configured in the Vagrantfile if the
|
||||||
|
provider supports automatic port collision detection and resolution.
|
||||||
|
empty_ports: |-
|
||||||
|
The provider reported there are no forwarded ports for this virtual
|
||||||
|
machine. This can be caused if there are no ports specified in the
|
||||||
|
Vagrantfile or if the virtual machine is not currently running. Please
|
||||||
|
check that the virtual machine is running and try again.
|
||||||
|
missing_capability: |-
|
||||||
|
The %{provider} provider does not support listing forwarded ports. This is
|
||||||
|
most likely a limitation of the provider and not a bug in Vagrant. If you
|
||||||
|
believe this is a bug in Vagrant, please search existing issues before
|
||||||
|
opening a new one.
|
||||||
|
no_matching_port: |-
|
||||||
|
The guest is not currently mapping port %{port} to the host machine. Is
|
||||||
|
the port configured in the Vagrantfile? You may need to run `vagrant reload`
|
||||||
|
if changes were made to the port configuration in the Vagrantfile.
|
|
@ -0,0 +1,27 @@
|
||||||
|
require "vagrant"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandPort
|
||||||
|
class Plugin < Vagrant.plugin("2")
|
||||||
|
name "port command"
|
||||||
|
description <<-DESC
|
||||||
|
The `port` command displays guest port mappings.
|
||||||
|
DESC
|
||||||
|
|
||||||
|
command("port") do
|
||||||
|
require_relative "command"
|
||||||
|
self.init!
|
||||||
|
Command
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def self.init!
|
||||||
|
return if defined?(@_init)
|
||||||
|
I18n.load_path << File.expand_path("../locales/en.yml", __FILE__)
|
||||||
|
I18n.reload!
|
||||||
|
@_init = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -9,6 +9,8 @@ module VagrantPlugins
|
||||||
#
|
#
|
||||||
# @return [Hash<Integer, Integer>] Host => Guest port mappings.
|
# @return [Hash<Integer, Integer>] Host => Guest port mappings.
|
||||||
def self.forwarded_ports(machine)
|
def self.forwarded_ports(machine)
|
||||||
|
return nil if machine.state.id != :running
|
||||||
|
|
||||||
{}.tap do |result|
|
{}.tap do |result|
|
||||||
machine.provider.driver.read_forwarded_ports.each do |_, _, h, g|
|
machine.provider.driver.read_forwarded_ports.each do |_, _, h, g|
|
||||||
result[h] = g
|
result[h] = g
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
require File.expand_path("../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/port/command")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CommandPort::Command do
|
||||||
|
include_context "unit"
|
||||||
|
include_context "command plugin helpers"
|
||||||
|
|
||||||
|
let(:iso_env) { isolated_environment }
|
||||||
|
let(:env) do
|
||||||
|
iso_env.vagrantfile(<<-VF)
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.vm.box = "hashicorp/precise64"
|
||||||
|
end
|
||||||
|
VF
|
||||||
|
iso_env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:state) { double(:state, id: :running) }
|
||||||
|
|
||||||
|
let(:machine) { env.machine(env.machine_names[0], :dummy) }
|
||||||
|
|
||||||
|
before(:all) do
|
||||||
|
I18n.load_path << Vagrant.source_root.join("plugins/commands/port/locales/en.yml")
|
||||||
|
I18n.reload!
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { described_class.new([], env) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(machine).to receive(:state).and_return(state)
|
||||||
|
allow(subject).to receive(:with_target_vms) { |&block| block.call(machine) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#execute" do
|
||||||
|
it "validates the configuration" do
|
||||||
|
iso_env.vagrantfile <<-EOH
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.vm.box = "hashicorp/precise64"
|
||||||
|
|
||||||
|
config.push.define "noop" do |push|
|
||||||
|
push.bad = "ham"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
EOH
|
||||||
|
|
||||||
|
subject = described_class.new([], iso_env.create_vagrant_env)
|
||||||
|
|
||||||
|
expect { subject.execute }.to raise_error(Vagrant::Errors::ConfigInvalid) { |err|
|
||||||
|
expect(err.message).to include("The following settings shouldn't exist: bad")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it "ensures the vm is running" do
|
||||||
|
allow(state).to receive(:id).and_return(:stopped)
|
||||||
|
expect(env.ui).to receive(:error).with { |message, _|
|
||||||
|
expect(message).to include("does not support listing forwarded ports")
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "shows a friendly error when the capability is not supported" do
|
||||||
|
allow(machine.provider).to receive(:capability?).and_return(false)
|
||||||
|
expect(env.ui).to receive(:error).with { |message, _|
|
||||||
|
expect(message).to include("does not support listing forwarded ports")
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a friendly message when there are no forwarded ports" do
|
||||||
|
allow(machine.provider).to receive(:capability?).and_return(true)
|
||||||
|
allow(machine.provider).to receive(:capability).with(:forwarded_ports)
|
||||||
|
.and_return([])
|
||||||
|
|
||||||
|
expect(env.ui).to receive(:info).with { |message, _|
|
||||||
|
expect(message).to include("there are no forwarded ports")
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the list of ports" do
|
||||||
|
allow(machine.provider).to receive(:capability?).and_return(true)
|
||||||
|
allow(machine.provider).to receive(:capability).with(:forwarded_ports)
|
||||||
|
.and_return([[2222,22], [1111,11]])
|
||||||
|
|
||||||
|
output = ""
|
||||||
|
allow(env.ui).to receive(:info) do |data|
|
||||||
|
output << data
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
|
||||||
|
expect(output).to include("forwarded ports for the machine")
|
||||||
|
expect(output).to include("22 (guest) => 2222 (host)")
|
||||||
|
expect(output).to include("11 (guest) => 1111 (host)")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints the matching host port when --guest is given" do
|
||||||
|
argv = ["--guest", "22"]
|
||||||
|
subject = described_class.new(argv, env)
|
||||||
|
|
||||||
|
allow(machine.provider).to receive(:capability?).and_return(true)
|
||||||
|
allow(machine.provider).to receive(:capability).with(:forwarded_ports)
|
||||||
|
.and_return([[2222,22]])
|
||||||
|
|
||||||
|
output = ""
|
||||||
|
allow(env.ui).to receive(:info) do |data|
|
||||||
|
output << data
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
|
||||||
|
expect(output).to eq("2222")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns an error with no port is mapped to the --guest option" do
|
||||||
|
argv = ["--guest", "80"]
|
||||||
|
subject = described_class.new(argv, env)
|
||||||
|
|
||||||
|
allow(machine.provider).to receive(:capability?).and_return(true)
|
||||||
|
allow(machine.provider).to receive(:capability).with(:forwarded_ports)
|
||||||
|
.and_return([[2222,22]])
|
||||||
|
|
||||||
|
output = ""
|
||||||
|
allow(env.ui).to receive(:error) do |data|
|
||||||
|
output << data
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(subject.execute).to_not eq(0)
|
||||||
|
|
||||||
|
expect(output).to include("not currently mapping port 80")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -15,14 +15,16 @@ describe VagrantPlugins::ProviderVirtualBox::Cap do
|
||||||
let(:machine) do
|
let(:machine) do
|
||||||
iso_env.machine(iso_env.machine_names[0], :dummy).tap do |m|
|
iso_env.machine(iso_env.machine_names[0], :dummy).tap do |m|
|
||||||
m.provider.stub(driver: driver)
|
m.provider.stub(driver: driver)
|
||||||
|
m.stub(state: state)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:driver) { double("driver") }
|
let(:driver) { double("driver") }
|
||||||
|
let(:state) { double("state", id: :running) }
|
||||||
|
|
||||||
describe "#forwarded_ports" do
|
describe "#forwarded_ports" do
|
||||||
it "returns all the forwarded ports" do
|
it "returns all the forwarded ports" do
|
||||||
expect(driver).to receive(:read_forwarded_ports).and_return([
|
allow(driver).to receive(:read_forwarded_ports).and_return([
|
||||||
[nil, nil, 123, 456],
|
[nil, nil, 123, 456],
|
||||||
[nil, nil, 245, 245],
|
[nil, nil, 245, 245],
|
||||||
])
|
])
|
||||||
|
@ -32,5 +34,10 @@ describe VagrantPlugins::ProviderVirtualBox::Cap do
|
||||||
245 => 245,
|
245 => 245,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "returns nil when the machine is not running" do
|
||||||
|
allow(machine).to receive(:state).and_return(double(:state, id: :stopped))
|
||||||
|
expect(described_class.forwarded_ports(machine)).to be(nil)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -104,6 +104,7 @@
|
||||||
<li<%= sidebar_current("cli-login") %>><a href="/v2/cli/login.html">login</a></li>
|
<li<%= sidebar_current("cli-login") %>><a href="/v2/cli/login.html">login</a></li>
|
||||||
<li<%= sidebar_current("cli-package") %>><a href="/v2/cli/package.html">package</a></li>
|
<li<%= sidebar_current("cli-package") %>><a href="/v2/cli/package.html">package</a></li>
|
||||||
<li<%= sidebar_current("cli-plugin") %>><a href="/v2/cli/plugin.html">plugin</a></li>
|
<li<%= sidebar_current("cli-plugin") %>><a href="/v2/cli/plugin.html">plugin</a></li>
|
||||||
|
<li<%= sidebar_current("cli-port") %>><a href="/v2/cli/port.html">port</a></li>
|
||||||
<li<%= sidebar_current("cli-powershell") %>><a href="/v2/cli/powershell.html">powershell</a></li>
|
<li<%= sidebar_current("cli-powershell") %>><a href="/v2/cli/powershell.html">powershell</a></li>
|
||||||
<li<%= sidebar_current("cli-provision") %>><a href="/v2/cli/provision.html">provision</a></li>
|
<li<%= sidebar_current("cli-provision") %>><a href="/v2/cli/provision.html">provision</a></li>
|
||||||
<li<%= sidebar_current("cli-rdp") %>><a href="/v2/cli/rdp.html">rdp</a></li>
|
<li<%= sidebar_current("cli-rdp") %>><a href="/v2/cli/rdp.html">rdp</a></li>
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
---
|
||||||
|
page_title: "vagrant port - Command-Line Interface"
|
||||||
|
sidebar_current: "cli-port"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Port
|
||||||
|
|
||||||
|
**Command: `vagrant port`**
|
||||||
|
|
||||||
|
The port command displays the full list of guest ports mapped to the host
|
||||||
|
machine ports:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ vagrant port
|
||||||
|
22 (guest) => 2222 (host)
|
||||||
|
80 (guest) => 8080 (host)
|
||||||
|
```
|
||||||
|
|
||||||
|
In a multi-machine Vagrantfile, the name of the machine must be specified:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ vagrant port my-machine
|
||||||
|
```
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
* `--guest PORT` - This displays just the host port that corresponds to the
|
||||||
|
given guest port. If the guest is not forwarding that port, an error is
|
||||||
|
returned. This is useful for quick scripting, for example:
|
||||||
|
|
||||||
|
$ ssh -p $(vagrant port --guest 22)
|
||||||
|
|
||||||
|
* `--machine-readable` - This tells Vagrant to display machine-readable output
|
||||||
|
instead of the human-friendly output. More information is available in the
|
||||||
|
[machine-readable output](/v2/cli/machine-readable.html) documentation.
|
Loading…
Reference in New Issue