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

Returns the value of attribute buf.



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

def buf
  @buf
end

#channelObject

Returns the value of attribute channel.



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

def channel
  @channel
end

#sshObject

Returns the value of attribute ssh.



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
75
76
77
78
# File 'lib/puppet/util/network_device/transport/ssh.rb', line 70

def close
  begin
    @channel.close if @channel
    @channel = nil
    @ssh.close if @ssh
  rescue IOError
    Puppet.debug "device terminated ssh session impolitely"
  end
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}") % { host: host, user: user }, $!.backtrace
  rescue Net::SSH::Exception
    raise Puppet::Error, _("SSH connection failure to %{host}") % { host: 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 { |_,data| @buf << data }
      ch.on_extended_data { |_,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

Returns:

  • (Boolean)


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

def eof?
  !! @eof
end

#expect(prompt) ⇒ Object



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
107
108
109
110
# File 'lib/puppet/util/network_device/transport/ssh.rb', line 80

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

Returns:

  • (Boolean)


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

def handles_login?
  true
end

#process_sshObject



117
118
119
120
121
122
123
124
125
# File 'lib/puppet/util/network_device/transport/ssh.rb', line 117

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

#send(line) ⇒ Object



112
113
114
115
# File 'lib/puppet/util/network_device/transport/ssh.rb', line 112

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