summaryrefslogtreecommitdiffstats
path: root/lib/puppet
diff options
context:
space:
mode:
authorBrice Figureau <brice-puppet@daysofwonder.com>2011-01-03 19:50:20 +0100
committerJames Turnbull <james@lovedthanlost.net>2011-04-08 18:19:53 +1000
commit6560da52674dfce10a622b633a9ed511f75b0a89 (patch)
tree77243f514700d857f66113a7349f611844b1a29e /lib/puppet
parent358245a823c1e2ed6fa2351130cf98678bd02e0d (diff)
downloadpuppet-6560da52674dfce10a622b633a9ed511f75b0a89.tar.gz
puppet-6560da52674dfce10a622b633a9ed511f75b0a89.tar.xz
puppet-6560da52674dfce10a622b633a9ed511f75b0a89.zip
Ssh transport for network device management
It is an adapatation of net-ssh-telnet, so that net-ssh conforms to a saner interface for consumer. Signed-off-by: Brice Figureau <brice-puppet@daysofwonder.com>
Diffstat (limited to 'lib/puppet')
-rw-r--r--lib/puppet/feature/ssh.rb4
-rw-r--r--lib/puppet/util/network_device/transport/ssh.rb115
2 files changed, 119 insertions, 0 deletions
diff --git a/lib/puppet/feature/ssh.rb b/lib/puppet/feature/ssh.rb
new file mode 100644
index 000000000..82fe19882
--- /dev/null
+++ b/lib/puppet/feature/ssh.rb
@@ -0,0 +1,4 @@
+require 'puppet/util/feature'
+
+Puppet.features.rubygems?
+Puppet.features.add(:ssh, :libs => %{net/ssh})
diff --git a/lib/puppet/util/network_device/transport/ssh.rb b/lib/puppet/util/network_device/transport/ssh.rb
new file mode 100644
index 000000000..b3cf51b8a
--- /dev/null
+++ b/lib/puppet/util/network_device/transport/ssh.rb
@@ -0,0 +1,115 @@
+
+require 'puppet/util/network_device'
+require 'puppet/util/network_device/transport'
+require 'puppet/util/network_device/transport/base'
+require 'net/ssh'
+
+# This is an adaptation/simplification of gem net-ssh-telnet, which aims to have
+# a sane interface to Net::SSH. Credits goes to net-ssh-telnet authors
+class Puppet::Util::NetworkDevice::Transport::Ssh < Puppet::Util::NetworkDevice::Transport::Base
+
+ attr_accessor :buf, :ssh, :channel, :verbose
+
+ def initialize
+ super
+ end
+
+ def handles_login?
+ true
+ end
+
+ def eof?
+ !! @eof
+ end
+
+ def connect(&block)
+ @output = []
+ @channel_data = ""
+
+ begin
+ Puppet.debug("connecting to #{host} as #{user}")
+ @ssh = Net::SSH.start(host, user, :port => port, :password => password, :timeout => timeout)
+ rescue TimeoutError
+ raise TimeoutError, "timed out while opening an ssh connection to the host"
+ end
+
+ @buf = ""
+ @eof = false
+ @channel = nil
+ @ssh.open_channel do |channel|
+ channel.request_pty { |ch,success| raise "failed to open pty" unless success }
+
+ channel.send_channel_request("shell") do |ch, success|
+ raise "failed to open ssh shell channel" unless success
+
+ ch.on_data { |ch,data| @buf << data }
+ ch.on_extended_data { |ch,type,data| @buf << data if type == 1 }
+ ch.on_close { @eof = true }
+
+ @channel = ch
+ expect(default_prompt, &block)
+ # this is a little bit unorthodox, we're trying to escape
+ # the ssh loop there while still having the ssh connection up
+ # otherwise we wouldn't be able to return ssh stdout/stderr
+ # for a given call of command.
+ return
+ end
+
+ end
+ @ssh.loop
+
+ end
+
+ def close
+ @channel.close if @channel
+ @channel = nil
+ @ssh.close if @ssh
+ end
+
+ def expect(prompt)
+ line = ''
+ sock = @ssh.transport.socket
+
+ while not @eof
+ break if line =~ prompt and @buf == ''
+ break if sock.closed?
+
+ IO::select([sock], [sock], nil, nil)
+
+ process_ssh
+
+ # at this point we have accumulated some data in @buf
+ # or the channel has been closed
+ if @buf != ""
+ line += @buf.gsub(/\r\n/no, "\n")
+ @buf = ''
+ yield line if block_given?
+ elsif @eof
+ # channel has been closed
+ break if line =~ prompt
+ if line == ''
+ line = nil
+ yield nil if block_given?
+ end
+ break
+ end
+ end
+ Puppet.debug("ssh: expected #{line}") if @verbose
+ line
+ end
+
+ def send(line)
+ Puppet.debug("ssh: send #{line}") if @verbose
+ @channel.send_data(line + "\n")
+ end
+
+ def process_ssh
+ while @buf == "" and not eof?
+ begin
+ @channel.connection.process(0.1)
+ rescue IOError
+ @eof = true
+ end
+ end
+ end
+end \ No newline at end of file