sshexpect 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. data/README +2 -0
  2. data/lib/sshexpect.rb +219 -0
  3. metadata +54 -0
data/README ADDED
@@ -0,0 +1,2 @@
1
+ This is a module for using expect and ssh for automation.
2
+ It contains a simple wrapper class for now that will take an expect sequence as input and return the output.
data/lib/sshexpect.rb ADDED
@@ -0,0 +1,219 @@
1
+ require 'expect'
2
+ require 'pty'
3
+
4
+ module SshExpect
5
+ #Signal.trap( 'CHLD', 'IGNORE')
6
+
7
+ # A class for interacting with ssh through pty and expect.
8
+ # Useful for when sshv2 isnt supported or extended login prompts are used.
9
+ class Client
10
+
11
+ attr_reader :hostname, :timeout, :command, :ignore, :quiet, :port, :cipher, :username, :output, :error
12
+
13
+ #==============================================================================#
14
+ # initialize()
15
+ #==============================================================================#
16
+
17
+ #===Synopsis
18
+ #Create a new SshExpect::Single object.
19
+ #
20
+ #===Usage
21
+ # SshExpect.new(options)
22
+ #
23
+ #===Arguments
24
+ #Hash with the following fields:
25
+ # :hostname => [String] -- ip/hostname the device.
26
+ # :username => [String] -- username to connect with.
27
+ # :verbose => [TrueClass|FalseClass] -- Suppress output and warnings if set True.
28
+ # :noverify => [TrueClass|FalseClass] -- Ignore changed host keys if set True.
29
+ # :timeout => [Integer] -- timeout for device to respond on any given sequence step.
30
+ # :port => [Integer] -- TCP port to connect with.
31
+ # :cipher => [String] -- encryption cipher.
32
+ # :command => [String] -- full path to ssh including the binary.
33
+
34
+ def initialize(options)
35
+
36
+ @hostname = nil
37
+ @username = nil
38
+ @verbose = true
39
+ @noverify = true
40
+ @timeout = 30
41
+ @port = 22
42
+ @cipher = "des"
43
+ @command = "/usr/bin/ssh"
44
+ @cmd = nil
45
+ @output = Array.new
46
+ @error = nil
47
+
48
+
49
+ if (!options.kind_of?(Hash))
50
+ raise ArgumentError, "Expected Hash, but #{options.class} provided."
51
+ end
52
+
53
+ if (options.has_key?(:hostname))
54
+ @hostname = options[:hostname]
55
+ if (!@hostname.kind_of?(String))
56
+ raise ArgumentError, "Expected String for :hostname, but #{@server.class} provided."
57
+ end
58
+ else
59
+ raise ArgumentError, "Missing argument :hostname."
60
+ end
61
+
62
+ if (options.has_key?(:username))
63
+ @username = options[:username]
64
+ if (!@username.kind_of?(String))
65
+ raise ArgumentError, "Expected String for :username, but #{@server.class} provided."
66
+ end
67
+ else
68
+ raise ArgumentError, "Missing argument :username."
69
+ end
70
+
71
+ if (options.has_key?(:verbose))
72
+ @verbose = options[:verbose]
73
+ if (!@verbose.kind_of?(TrueClass) && !@verbose.kind_of?(FalseClass))
74
+ raise ArgumentError, "Expected True or False for :verbose, but was #{@verbose.class}"
75
+ end
76
+ end
77
+
78
+ if (options.has_key?(:noverify))
79
+ @noverify = options[:noverify]
80
+ if (!@noverify.kind_of?(TrueClass) && !@noverify.kind_of?(FalseClass))
81
+ raise ArgumentError, "Expected True or False for :noverify, but was #{@ignore.class}"
82
+ end
83
+ end
84
+
85
+ if (options.has_key?(:timeout))
86
+ @timeout = options[:timeout]
87
+ if (!@timeout.kind_of?(Integer))
88
+ raise ArgumentError, "Expected Integer for :timeout, but #{@timeout.class} provided."
89
+ end
90
+ end
91
+
92
+ if (options.has_key?(:port))
93
+ @port = options[:port]
94
+ if (!@port.kind_of?(Integer))
95
+ raise ArgumentError, "Expected Integer for :port, but #{@port.class} provided."
96
+ end
97
+ if (@port >= 2**16)
98
+ raise ArgumentError, "#{@port} is not a valid TCP port."
99
+ end
100
+ end
101
+
102
+ #Build the command line for PTY
103
+ @cmd = @command + " #{@username}@#{@hostname} -p #{@port}"
104
+
105
+ if(@verbose)
106
+ @cmd = @cmd + " -q"
107
+ end
108
+
109
+ if(@noverify)
110
+ @cmd = @cmd + " -o StrictHostKeyChecking=no"
111
+ end
112
+
113
+ end
114
+
115
+ #==============================================================================#
116
+ # exec()
117
+ #==============================================================================#
118
+
119
+ #===Synopsis
120
+ #Iterate through a sequence of send/expect statements.
121
+ #
122
+ #===Usage
123
+ # SshExpect.exec(sequence)
124
+ #
125
+ #===Arguments
126
+ #Array of Hashes with the following format:
127
+ #sequence = []
128
+ #sequence[0] = {}
129
+ #sequence[0]["expect"] = "word:"
130
+ #sequence[0]["send"] = "mypassword\n"
131
+ #sequence[1] = {}
132
+ #sequence[1]["expect"] = ">"
133
+ #sequence[1]["send"] = "en\n"
134
+ #sequence[2] = {}
135
+ #sequence[2]["expect"] = "word:"
136
+ #sequence[2]["send"] = "enable\n"
137
+ #sequence[3] = {}
138
+ #sequence[3]["expect"] = "#"
139
+ #sequence[3]["send"] = "conf t\n"
140
+ #sequence[4] = {}
141
+ #sequence[4]["expect"] = "#"
142
+ #sequence[4]["send"] = "no pager\n sho run\n"
143
+ #sequence[5] = {}
144
+ #sequence[5]["expect"] = "#"
145
+ #sequence[5]["send"] = "exit\n"
146
+ #sequence[6] = {}
147
+ #sequence[6]["expect"] = "#"
148
+ #sequence[6]["send"] = "exit\n"
149
+
150
+
151
+ def exec(sequence)
152
+
153
+ reader = nil
154
+ writer = nil
155
+ pid = nil
156
+
157
+ begin
158
+ PTY.spawn(@cmd) do |reader,writer,pid|
159
+
160
+ sleep 0.1
161
+
162
+ PTY.protect_signal do
163
+
164
+ $expect_verbose = @verbose
165
+ sequence.each do |step|
166
+ exp = step["expect"]
167
+ snd = step["send"]
168
+
169
+ begin
170
+ reader.expect(exp,@timeout) do |receive|
171
+ if receive == nil then
172
+ @output.push("Exception: Timeout talking to device")
173
+
174
+ writer.close
175
+ reader.close
176
+ return @output
177
+ else
178
+ writer.puts(snd)
179
+ @output.push(receive)
180
+ end
181
+ end
182
+
183
+ rescue Exception => ee
184
+ @output.push "Exception trying to handle IO #{ee.to_s}\n"
185
+ return @output
186
+ end
187
+ end
188
+
189
+ writer.close
190
+ reader.close
191
+
192
+ begin
193
+ Process.kill(9,@pid)
194
+ rescue Exception => ee
195
+ @output.push "Exception trying to kill process #{@pid} #{ee.to_s} \n"
196
+ return @output
197
+ end
198
+ end
199
+ end
200
+ return @output
201
+
202
+
203
+ rescue PTY::ChildExited => ee
204
+ @output.push "Exception child died early #{ee.to_s}\n"
205
+ return @output
206
+
207
+ rescue Errno::EIO => ee
208
+ @output.push "Exception connection closed early #{ee.to_s}\n"
209
+ return @output
210
+
211
+ rescue Exception => ee
212
+ @output.push "Exception #{ee.to_s}\n"
213
+ return @output
214
+ end
215
+
216
+ end
217
+ end
218
+
219
+ end
metadata ADDED
@@ -0,0 +1,54 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sshexpect
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - David Lister
8
+ autorequire: sshexpect
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-25 00:00:00 -06:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: david @nospam@ lister.ch
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ files:
25
+ - lib/sshexpect.rb
26
+ - README
27
+ has_rdoc: true
28
+ homepage:
29
+ post_install_message:
30
+ rdoc_options: []
31
+
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: "0"
39
+ version:
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: "0"
45
+ version:
46
+ requirements: []
47
+
48
+ rubyforge_project:
49
+ rubygems_version: 1.0.1
50
+ signing_key:
51
+ specification_version: 2
52
+ summary: This is a module for using expect and ssh for automation.
53
+ test_files: []
54
+