SSH class converted to instance methods. now loads on the environment
This commit is contained in:
parent
689f69bd4c
commit
260b099dba
|
@ -28,27 +28,27 @@ module Vagrant
|
||||||
# useful information such as whether or not the environment is created
|
# useful information such as whether or not the environment is created
|
||||||
# and if its running, suspended, etc.
|
# and if its running, suspended, etc.
|
||||||
def status
|
def status
|
||||||
Env.load!
|
env = Environment.load!
|
||||||
|
|
||||||
wrap_output do
|
wrap_output do
|
||||||
if !Env.persisted_vm
|
if !env.vm
|
||||||
puts <<-msg
|
puts <<-msg
|
||||||
The environment has not yet been created. Run `vagrant up` to create the
|
The environment has not yet been created. Run `vagrant up` to create the
|
||||||
environment.
|
environment.
|
||||||
msg
|
msg
|
||||||
else
|
else
|
||||||
additional_msg = ""
|
additional_msg = ""
|
||||||
if Env.persisted_vm.vm.running?
|
if env.vm.vm.running?
|
||||||
additional_msg = <<-msg
|
additional_msg = <<-msg
|
||||||
To stop this VM, you can run `vagrant halt` to shut it down forcefully,
|
To stop this VM, you can run `vagrant halt` to shut it down forcefully,
|
||||||
or you can run `vagrant suspend` to simply suspend the virtual machine.
|
or you can run `vagrant suspend` to simply suspend the virtual machine.
|
||||||
In either case, to restart it again, simply run a `vagrant up`.
|
In either case, to restart it again, simply run a `vagrant up`.
|
||||||
msg
|
msg
|
||||||
elsif Env.persisted_vm.vm.saved?
|
elsif env.vm.vm.saved?
|
||||||
additional_msg = <<-msg
|
additional_msg = <<-msg
|
||||||
To resume this VM, simply run `vagrant up`.
|
To resume this VM, simply run `vagrant up`.
|
||||||
msg
|
msg
|
||||||
elsif Env.persisted_vm.vm.powered_off?
|
elsif env.vm.vm.powered_off?
|
||||||
additional_msg = <<-msg
|
additional_msg = <<-msg
|
||||||
To restart this VM, simply run `vagrant up`.
|
To restart this VM, simply run `vagrant up`.
|
||||||
msg
|
msg
|
||||||
|
@ -61,7 +61,7 @@ msg
|
||||||
|
|
||||||
puts <<-msg
|
puts <<-msg
|
||||||
The environment has been created. The status of the current environment's
|
The environment has been created. The status of the current environment's
|
||||||
virtual machine is: "#{Env.persisted_vm.vm.state}."#{additional_msg}
|
virtual machine is: "#{env.vm.vm.state}."#{additional_msg}
|
||||||
msg
|
msg
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,6 +13,7 @@ module Vagrant
|
||||||
attr_reader :config
|
attr_reader :config
|
||||||
attr_reader :box
|
attr_reader :box
|
||||||
attr_reader :vm
|
attr_reader :vm
|
||||||
|
attr_reader :ssh
|
||||||
|
|
||||||
#---------------------------------------------------------------
|
#---------------------------------------------------------------
|
||||||
# Class Methods
|
# Class Methods
|
||||||
|
@ -84,6 +85,7 @@ module Vagrant
|
||||||
load_config!
|
load_config!
|
||||||
self.class.check_virtualbox!
|
self.class.check_virtualbox!
|
||||||
load_vm!
|
load_vm!
|
||||||
|
load_ssh!
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -167,6 +169,11 @@ module Vagrant
|
||||||
@vm = nil
|
@vm = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Loads/initializes the SSH object
|
||||||
|
def load_ssh!
|
||||||
|
@ssh = SSH.new(self)
|
||||||
|
end
|
||||||
|
|
||||||
#---------------------------------------------------------------
|
#---------------------------------------------------------------
|
||||||
# Methods to manage VM
|
# Methods to manage VM
|
||||||
#---------------------------------------------------------------
|
#---------------------------------------------------------------
|
||||||
|
|
|
@ -1,54 +1,77 @@
|
||||||
module Vagrant
|
module Vagrant
|
||||||
|
# Manages SSH access to a specific environment. Allows an environment to
|
||||||
|
# replace the process with SSH itself, run a specific set of commands,
|
||||||
|
# upload files, or even check if a host is up.
|
||||||
class SSH
|
class SSH
|
||||||
include Vagrant::Util
|
include Vagrant::Util
|
||||||
|
|
||||||
class << self
|
# Reference back up to the environment which this SSH object belongs
|
||||||
def connect(opts={})
|
# to
|
||||||
options = {}
|
attr_accessor :env
|
||||||
[:host, :username, :private_key_path].each do |param|
|
|
||||||
options[param] = opts[param] || Vagrant.config.ssh.send(param)
|
|
||||||
end
|
|
||||||
|
|
||||||
Kernel.exec "ssh -p #{port(opts)} -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i #{options[:private_key_path]} #{options[:username]}@#{options[:host]}".strip
|
def initialize(environment)
|
||||||
|
@env = environment
|
||||||
|
end
|
||||||
|
|
||||||
|
# Connects to the environment's virtual machine, replacing the ruby
|
||||||
|
# process with an SSH process. This method optionally takes a hash
|
||||||
|
# of options which override the configuration values.
|
||||||
|
def connect(opts={})
|
||||||
|
options = {}
|
||||||
|
[:host, :username, :private_key_path].each do |param|
|
||||||
|
options[param] = opts[param] || env.config.ssh.send(param)
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute(opts={})
|
Kernel.exec "ssh -p #{port(opts)} -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i #{options[:private_key_path]} #{options[:username]}@#{options[:host]}".strip
|
||||||
Net::SSH.start(Vagrant.config.ssh.host,
|
end
|
||||||
Vagrant.config[:ssh][:username],
|
|
||||||
opts.merge( :port => port,
|
|
||||||
:keys => [Vagrant.config.ssh.private_key_path])) do |ssh|
|
|
||||||
yield ssh
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def upload!(from, to)
|
# Opens an SSH connection to this environment's virtual machine and yields
|
||||||
execute do |ssh|
|
# a Net::SSH object which can be used to execute remote commands.
|
||||||
scp = Net::SCP.new(ssh)
|
def execute(opts={})
|
||||||
scp.upload!(from, to)
|
Net::SSH.start(env.config.ssh.host,
|
||||||
end
|
env.config[:ssh][:username],
|
||||||
|
opts.merge( :port => port,
|
||||||
|
:keys => [env.config.ssh.private_key_path])) do |ssh|
|
||||||
|
yield ssh
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def up?
|
# Uploads a file from `from` to `to`. `from` is expected to be a filename
|
||||||
check_thread = Thread.new do
|
# or StringIO, and `to` is expected to be a path. This method simply forwards
|
||||||
begin
|
# the arguments to `Net::SCP#upload!` so view that for more information.
|
||||||
Thread.current[:result] = false
|
def upload!(from, to)
|
||||||
execute(:timeout => Vagrant.config.ssh.timeout) do |ssh|
|
execute do |ssh|
|
||||||
Thread.current[:result] = true
|
scp = Net::SCP.new(ssh)
|
||||||
end
|
scp.upload!(from, to)
|
||||||
rescue Errno::ECONNREFUSED, Net::SSH::Disconnect
|
end
|
||||||
# False, its defaulted above
|
end
|
||||||
|
|
||||||
|
# Checks if this environment's machine is up (i.e. responding to SSH).
|
||||||
|
#
|
||||||
|
# @return [Boolean]
|
||||||
|
def up?
|
||||||
|
check_thread = Thread.new do
|
||||||
|
begin
|
||||||
|
Thread.current[:result] = false
|
||||||
|
execute(:timeout => env.config.ssh.timeout) do |ssh|
|
||||||
|
Thread.current[:result] = true
|
||||||
end
|
end
|
||||||
|
rescue Errno::ECONNREFUSED, Net::SSH::Disconnect
|
||||||
|
# False, its defaulted above
|
||||||
end
|
end
|
||||||
|
|
||||||
check_thread.join(Vagrant.config.ssh.timeout)
|
|
||||||
return check_thread[:result]
|
|
||||||
rescue Net::SSH::AuthenticationFailed
|
|
||||||
error_and_exit(:vm_ssh_auth_failed)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def port(opts={})
|
check_thread.join(env.config.ssh.timeout)
|
||||||
opts[:port] || Vagrant.config.vm.forwarded_ports[Vagrant.config.ssh.forwarded_port_key][:hostport]
|
return check_thread[:result]
|
||||||
end
|
rescue Net::SSH::AuthenticationFailed
|
||||||
|
error_and_exit(:vm_ssh_auth_failed)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns the port which is either given in the options hash or taken from
|
||||||
|
# the config by finding it in the forwarded ports hash based on the
|
||||||
|
# `config.ssh.forwarded_port_key`
|
||||||
|
def port(opts={})
|
||||||
|
opts[:port] || env.config.vm.forwarded_ports[env.config.ssh.forwarded_port_key][:hostport]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -128,6 +128,7 @@ class EnvironmentTest < Test::Unit::TestCase
|
||||||
@env.expects(:load_config!).once.in_sequence(call_seq)
|
@env.expects(:load_config!).once.in_sequence(call_seq)
|
||||||
Vagrant::Environment.expects(:check_virtualbox!).once.in_sequence(call_seq)
|
Vagrant::Environment.expects(:check_virtualbox!).once.in_sequence(call_seq)
|
||||||
@env.expects(:load_vm!).once.in_sequence(call_seq)
|
@env.expects(:load_vm!).once.in_sequence(call_seq)
|
||||||
|
@env.expects(:load_ssh!).once.in_sequence(call_seq)
|
||||||
assert_equal @env, @env.load!
|
assert_equal @env, @env.load!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -368,6 +369,19 @@ class EnvironmentTest < Test::Unit::TestCase
|
||||||
assert_nil @env.vm
|
assert_nil @env.vm
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "loading SSH" do
|
||||||
|
setup do
|
||||||
|
@env = mock_environment
|
||||||
|
end
|
||||||
|
|
||||||
|
should "initialize the SSH object with the given environment" do
|
||||||
|
ssh = mock("ssh")
|
||||||
|
Vagrant::SSH.expects(:new).with(@env).returns(ssh)
|
||||||
|
@env.load_ssh!
|
||||||
|
assert_equal ssh, @env.ssh
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "requiring properties" do
|
context "requiring properties" do
|
||||||
|
|
|
@ -5,24 +5,35 @@ class SshTest < Test::Unit::TestCase
|
||||||
mock_config
|
mock_config
|
||||||
end
|
end
|
||||||
|
|
||||||
context "connecting to SSH" do
|
def mock_ssh
|
||||||
test "should call exec with defaults when no options are supplied" do
|
@env = mock_environment do |config|
|
||||||
ssh = Vagrant.config.ssh
|
yield config if block_given?
|
||||||
ssh_exec_expect(Vagrant::SSH.port,
|
|
||||||
Vagrant.config.ssh.private_key_path,
|
|
||||||
Vagrant.config.ssh.username,
|
|
||||||
Vagrant.config.ssh.host)
|
|
||||||
Vagrant::SSH.connect
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "should call exec with supplied params" do
|
@ssh = Vagrant::SSH.new(@env)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "connecting to external SSH" do
|
||||||
|
setup do
|
||||||
|
mock_ssh
|
||||||
|
end
|
||||||
|
|
||||||
|
should "call exec with defaults when no options are supplied" do
|
||||||
|
ssh_exec_expect(@ssh.port,
|
||||||
|
@env.config.ssh.private_key_path,
|
||||||
|
@env.config.ssh.username,
|
||||||
|
@env.config.ssh.host)
|
||||||
|
@ssh.connect
|
||||||
|
end
|
||||||
|
|
||||||
|
should "call exec with supplied params" do
|
||||||
args = {:username => 'bar', :private_key_path => 'baz', :host => 'bak', :port => 'bag'}
|
args = {:username => 'bar', :private_key_path => 'baz', :host => 'bak', :port => 'bag'}
|
||||||
ssh_exec_expect(args[:port], args[:private_key_path], args[:username], args[:host])
|
ssh_exec_expect(args[:port], args[:private_key_path], args[:username], args[:host])
|
||||||
Vagrant::SSH.connect(args)
|
@ssh.connect(args)
|
||||||
end
|
end
|
||||||
|
|
||||||
def ssh_exec_expect(port, key_path, uname, host)
|
def ssh_exec_expect(port, key_path, uname, host)
|
||||||
Kernel.expects(:exec).with() do |arg|
|
Kernel.expects(:exec).with() do |arg|
|
||||||
assert arg =~ /^ssh/
|
assert arg =~ /^ssh/
|
||||||
assert arg =~ /-p #{port}/
|
assert arg =~ /-p #{port}/
|
||||||
assert arg =~ /-i #{key_path}/
|
assert arg =~ /-i #{key_path}/
|
||||||
|
@ -34,91 +45,103 @@ class SshTest < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
context "executing ssh commands" do
|
context "executing ssh commands" do
|
||||||
|
setup do
|
||||||
|
mock_ssh
|
||||||
|
end
|
||||||
|
|
||||||
should "call net::ssh.start with the proper names" do
|
should "call net::ssh.start with the proper names" do
|
||||||
Net::SSH.expects(:start).once.with() do |host, username, opts|
|
Net::SSH.expects(:start).once.with() do |host, username, opts|
|
||||||
assert_equal Vagrant.config.ssh.host, host
|
assert_equal @env.config.ssh.host, host
|
||||||
assert_equal Vagrant.config.ssh.username, username
|
assert_equal @env.config.ssh.username, username
|
||||||
assert_equal Vagrant::SSH.port, opts[:port]
|
assert_equal @ssh.port, opts[:port]
|
||||||
assert_equal [Vagrant.config.ssh.private_key_path], opts[:keys]
|
assert_equal [@env.config.ssh.private_key_path], opts[:keys]
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
Vagrant::SSH.execute
|
@ssh.execute
|
||||||
end
|
end
|
||||||
|
|
||||||
should "use custom host if set" do
|
should "use custom host if set" do
|
||||||
Vagrant.config.ssh.host = "foo"
|
@env.config.ssh.host = "foo"
|
||||||
Net::SSH.expects(:start).with(Vagrant.config.ssh.host, Vagrant.config.ssh.username, anything).once
|
Net::SSH.expects(:start).with(@env.config.ssh.host, @env.config.ssh.username, anything).once
|
||||||
Vagrant::SSH.execute
|
@ssh.execute
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "SCPing files to the remote host" do
|
context "SCPing files to the remote host" do
|
||||||
|
setup do
|
||||||
|
mock_ssh
|
||||||
|
end
|
||||||
|
|
||||||
should "use Vagrant::SSH execute to setup an SCP connection and upload" do
|
should "use Vagrant::SSH execute to setup an SCP connection and upload" do
|
||||||
scp = mock("scp")
|
scp = mock("scp")
|
||||||
ssh = mock("ssh")
|
ssh = mock("ssh")
|
||||||
scp.expects(:upload!).with("foo", "bar").once
|
scp.expects(:upload!).with("foo", "bar").once
|
||||||
Net::SCP.expects(:new).with(ssh).returns(scp).once
|
Net::SCP.expects(:new).with(ssh).returns(scp).once
|
||||||
Vagrant::SSH.expects(:execute).yields(ssh).once
|
@ssh.expects(:execute).yields(ssh).once
|
||||||
Vagrant::SSH.upload!("foo", "bar")
|
@ssh.upload!("foo", "bar")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "checking if host is up" do
|
context "checking if host is up" do
|
||||||
setup do
|
setup do
|
||||||
mock_config
|
mock_ssh
|
||||||
end
|
end
|
||||||
|
|
||||||
should "return true if SSH connection works" do
|
should "return true if SSH connection works" do
|
||||||
Net::SSH.expects(:start).yields("success")
|
Net::SSH.expects(:start).yields("success")
|
||||||
assert Vagrant::SSH.up?
|
assert @ssh.up?
|
||||||
end
|
end
|
||||||
|
|
||||||
should "return false if SSH connection times out" do
|
should "return false if SSH connection times out" do
|
||||||
Net::SSH.expects(:start)
|
Net::SSH.expects(:start)
|
||||||
assert !Vagrant::SSH.up?
|
assert !@ssh.up?
|
||||||
end
|
end
|
||||||
|
|
||||||
should "allow the thread the configured timeout time" do
|
should "allow the thread the configured timeout time" do
|
||||||
@thread = mock("thread")
|
@thread = mock("thread")
|
||||||
@thread.stubs(:[])
|
@thread.stubs(:[])
|
||||||
Thread.expects(:new).returns(@thread)
|
Thread.expects(:new).returns(@thread)
|
||||||
@thread.expects(:join).with(Vagrant.config.ssh.timeout).once
|
@thread.expects(:join).with(@env.config.ssh.timeout).once
|
||||||
Vagrant::SSH.up?
|
@ssh.up?
|
||||||
end
|
end
|
||||||
|
|
||||||
should "return false if the connection is refused" do
|
should "return false if the connection is refused" do
|
||||||
Net::SSH.expects(:start).raises(Errno::ECONNREFUSED)
|
Net::SSH.expects(:start).raises(Errno::ECONNREFUSED)
|
||||||
assert_nothing_raised {
|
assert_nothing_raised {
|
||||||
assert !Vagrant::SSH.up?
|
assert !@ssh.up?
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
should "return false if the connection is dropped" do
|
should "return false if the connection is dropped" do
|
||||||
Net::SSH.expects(:start).raises(Net::SSH::Disconnect)
|
Net::SSH.expects(:start).raises(Net::SSH::Disconnect)
|
||||||
assert_nothing_raised {
|
assert_nothing_raised {
|
||||||
assert !Vagrant::SSH.up?
|
assert !@ssh.up?
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
should "specifity the timeout as an option to execute" do
|
should "specifity the timeout as an option to execute" do
|
||||||
Vagrant::SSH.expects(:execute).with(:timeout => Vagrant.config.ssh.timeout).yields(true)
|
@ssh.expects(:execute).with(:timeout => @env.config.ssh.timeout).yields(true)
|
||||||
assert Vagrant::SSH.up?
|
assert @ssh.up?
|
||||||
end
|
end
|
||||||
|
|
||||||
should "error and exit if a Net::SSH::AuthenticationFailed is raised" do
|
should "error and exit if a Net::SSH::AuthenticationFailed is raised" do
|
||||||
Vagrant::SSH.expects(:execute).raises(Net::SSH::AuthenticationFailed)
|
@ssh.expects(:execute).raises(Net::SSH::AuthenticationFailed)
|
||||||
Vagrant::SSH.expects(:error_and_exit).with(:vm_ssh_auth_failed).once
|
@ssh.expects(:error_and_exit).with(:vm_ssh_auth_failed).once
|
||||||
Vagrant::SSH.up?
|
@ssh.up?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "getting the ssh port" do
|
context "getting the ssh port" do
|
||||||
|
setup do
|
||||||
|
mock_ssh
|
||||||
|
end
|
||||||
|
|
||||||
should "return the configured port by default" do
|
should "return the configured port by default" do
|
||||||
assert_equal Vagrant.config.vm.forwarded_ports[Vagrant.config.ssh.forwarded_port_key][:hostport], Vagrant::SSH.port
|
assert_equal @env.config.vm.forwarded_ports[@env.config.ssh.forwarded_port_key][:hostport], @ssh.port
|
||||||
end
|
end
|
||||||
|
|
||||||
should "return the port given in options if it exists" do
|
should "return the port given in options if it exists" do
|
||||||
assert_equal "47", Vagrant::SSH.port({ :port => "47" })
|
assert_equal "47", @ssh.port({ :port => "47" })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue