sshexpect 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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
+