Class: Puppet::Util::NetworkDevice::Transport::Ssh

Inherits:
Base
  • Object
show all
Defined in:
lib/puppet/util/network_device/transport/ssh.rb

Overview

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

Instance Attribute Summary collapse

Attributes inherited from Base

#default_prompt, #host, #password, #port, #timeout, #user

Instance Method Summary collapse

Methods inherited from Base

#command

Constructor Details

#initialize(verbose = false) ⇒ Ssh

Returns a new instance of Ssh.



12
13
14
15
16
17
18
# File 'lib/puppet/util/network_device/transport/ssh.rb', line 12

def initialize(verbose = false)
  super()
  @verbose = verbose
  unless Puppet.features.ssh?
    raise 'Connecting with ssh to a network device requires the \'net/ssh\' ruby library'
  end
end

Instance Attribute Details

#bufObject



10
11
12
# File 'lib/puppet/util/network_device/transport/ssh.rb', line 10

def buf
  @buf
end

#channelObject



10
11
12
# File 'lib/puppet/util/network_device/transport/ssh.rb', line 10

def channel
  @channel
end

#sshObject



10
11
12
# File 'lib/puppet/util/network_device/transport/ssh.rb', line 10

def ssh
  @ssh
end

Instance Method Details

#closeObject



70
71
72
73
74
# File 'lib/puppet/util/network_device/transport/ssh.rb', line 70

def close
  @channel.close if @channel
  @channel = nil
  @ssh.close if @ssh
end

#connect(&block) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/puppet/util/network_device/transport/ssh.rb', line 28

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", $!.backtrace
  rescue Net::SSH::AuthenticationFailed
    raise Puppet::Error, "SSH authentication failure connecting to #{host} as #{user}", $!.backtrace
  rescue Net::SSH::Exception
    raise Puppet::Error, "SSH connection failure to #{host}", $!.backtrace
  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

#eof?Boolean



24
25
26
# File 'lib/puppet/util/network_device/transport/ssh.rb', line 24

def eof?
  !! @eof
end

#expect(prompt) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/puppet/util/network_device/transport/ssh.rb', line 76

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

#handles_login?Boolean



20
21
22
# File 'lib/puppet/util/network_device/transport/ssh.rb', line 20

def handles_login?
  true
end

#process_sshObject



113
114
115
116
117
118
119
120
121
# File 'lib/puppet/util/network_device/transport/ssh.rb', line 113

def process_ssh
  while @buf == "" and not eof?
    begin
      @channel.connection.process(0.1)
    rescue IOError
      @eof = true
    end
  end
end

#send(line) ⇒ Object



108
109
110
111
# File 'lib/puppet/util/network_device/transport/ssh.rb', line 108

def send(line)
  Puppet.debug("ssh: send #{line}") if @verbose
  @channel.send_data(line + "\n")
end