rye 0.9.7 → 0.9.8

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.
@@ -0,0 +1,278 @@
1
+ require 'net/ssh'
2
+
3
+ #
4
+ # For channel requests, see SSH_MSG_CHANNEL_REQUEST messages
5
+ # in http://www.snailbook.com/docs/connection.txt
6
+ DEBUG = true
7
+
8
+ module Rye
9
+ class Box
10
+ def debug(state, msg='')
11
+ return unless DEBUG
12
+ puts " ------ %s: %s" % [state, msg]
13
+ end
14
+
15
+ def start_session_state(channel)
16
+ debug :start_session, channel[:handler]
17
+ channel.send_data("unset PS1; stty -echo\n")
18
+ channel[:state] = :ignore_response
19
+ end
20
+
21
+ def ignore_response_state(channel)
22
+ debug :ignore_response, channel[:handler]
23
+ @ignore_response_counter ||= 0
24
+ if channel[:buffer].available > 0
25
+ @await_response_counter = 0
26
+ channel[:buffer].read
27
+ channel[:state] = :process
28
+ elsif @ignore_response_counter > 2
29
+ @await_response_counter = 0
30
+ channel[:state] = :process
31
+ end
32
+ @ignore_response_counter += 1
33
+ end
34
+
35
+ def process_state(channel)
36
+ debug :process, channel[:handler]
37
+ if channel[:block]
38
+ channel[:state] = :run_block
39
+ else
40
+ channel[:state] = :await_input
41
+ end
42
+ end
43
+
44
+ def send_data_state(channel)
45
+ debug :send_data, channel[:handler]
46
+ #if channel[:stack].empty?
47
+ # channel[:state] = :await_input
48
+ #else
49
+ cmd = channel[:stack].shift
50
+ #return if cmd.strip.empty?
51
+ debug :send_data, "calling #{cmd.inspect}"
52
+ channel[:state] = :await_response
53
+ channel.send_data("#{cmd}\n") unless channel.eof?
54
+ #channel.exec("#{cmd}\n", &create_channel)
55
+ #end
56
+ end
57
+
58
+ def await_input_state(channel)
59
+ debug :await_input, channel[:handler]
60
+
61
+ if channel[:buffer].available > 0
62
+ channel[:state] = :read_input
63
+ else
64
+ ret = STDIN.gets
65
+ if ret.nil?
66
+ channel.eof!
67
+ channel[:state] = :exit
68
+ else
69
+ channel[:stack] << ret.chomp
70
+ channel[:state] = :send_data
71
+ end
72
+ end
73
+
74
+ end
75
+
76
+ def check_interactive_state(channel)
77
+ debug :read_input, channel[:handler]
78
+ channel.send_data("x")
79
+ end
80
+
81
+ def read_input_state(channel)
82
+ debug :read_input, channel[:handler]
83
+ if channel[:buffer].available > 0
84
+ print channel[:buffer].read
85
+
86
+ if channel[:stack].empty?
87
+ channel[:state] = :await_input
88
+ elsif channel[:buffer].available > 0
89
+ channel[:state] = :read_input
90
+ else
91
+ channel[:state] = :send_data
92
+ end
93
+ else
94
+ channel[:state] = :await_response
95
+ end
96
+ end
97
+
98
+ def exit_state(channel)
99
+ debug :exit_state, channel[:exit_status]
100
+ puts
101
+ channel.eof!
102
+ end
103
+
104
+ def handle_error_state(channel)
105
+ debug :handle_error, channel[:handler]
106
+ channel.eof!
107
+ end
108
+
109
+
110
+ def await_response_state(channel)
111
+ debug :await_response, channel[:handler]
112
+ @await_response_counter ||= 0
113
+ if channel[:buffer].available > 0
114
+ channel[:state] = :read_input
115
+ elsif @await_response_counter > 20
116
+ @await_response_counter = 0
117
+ channel[:state] = :await_input
118
+ end
119
+ @await_response_counter += 1
120
+ end
121
+
122
+ def run_block_state(channel)
123
+ debug :run_block, channel[:handler]
124
+ channel[:state] = nil
125
+ blk = channel[:block]
126
+ channel[:block] = nil
127
+ instance_eval &blk
128
+ channel[:state] = :exit
129
+ end
130
+
131
+ def command(name,*args, &blk)
132
+ debug :command, channel[:handler]
133
+ return if @channel.eof?
134
+ cmd = "%s %s" % [name, args.join(' ')]
135
+ debug :command, "Running: #{cmd}"
136
+ if self.pty && channel[:buffer].available
137
+ prompt = channel[:buffer].read
138
+ end
139
+ channel.send_data("#{cmd}\n")
140
+ channel.connection.loop do
141
+ break if channel[:buffer].available > 0
142
+ p :loop
143
+ channel.active?
144
+ end
145
+ ret = channel[:buffer].read
146
+ ret
147
+
148
+ end
149
+
150
+ def wait_for_command_state(channel)
151
+ debug :wait_for_command, channel[:handler]
152
+ end
153
+
154
+ def ls(*args) command(:ls, *args) end
155
+ def cat(*args) command(:cat, *args) end
156
+ def echo(*args) command(:echo, *args) end
157
+ def sudo(*args) command(:sudo, *args) end
158
+ def date(*args) command(:date, *args) end
159
+ def uname(*args) command(:uname, *args) end
160
+ def chroot(*args) command(:chroot, *args) end
161
+ def bash(*args, &blk) command(:bash, *args, &blk) end
162
+ def exit(*args, &blk) command(:exit, *args, &blk) end
163
+
164
+ attr_reader :session, :channel
165
+ attr_accessor :running, :pty
166
+
167
+ def connect(host, user, opts={})
168
+ opts = {
169
+ :auth_methods => %w[keyboard-interactive]
170
+ }.merge(opts)
171
+ opts[:auth_methods].unshift 'publickey' unless opts[:keys].nil?
172
+ opts[:auth_methods].unshift 'password' unless opts[:password].nil?
173
+ @sessions ||= []
174
+ @session = Net::SSH.start(host, user, opts)
175
+ end
176
+
177
+ def run(shell, &blk)
178
+
179
+ puts "Running #{shell}"
180
+ @channel = @session.open_channel do |channel|
181
+ #if blk.nil?
182
+ channel.request_pty do |ch,success|
183
+ self.pty = success
184
+ raise "pty request denied" unless success
185
+ end
186
+ #end
187
+ channel.exec shell, &create_channel
188
+ end
189
+
190
+ channel[:block] = blk
191
+
192
+ @session.loop(0.5) do
193
+ break if !@channel.active?
194
+ !@channel.eof? # otherwise keep returning true
195
+ end
196
+
197
+ end
198
+
199
+ def stop
200
+ @control.join if @control
201
+ @ssh.running = false
202
+ @ssh.close
203
+ end
204
+
205
+ private
206
+ def busy_proc
207
+ Proc.new { |s| !s.busy? }
208
+ end
209
+
210
+ def create_channel
211
+ Proc.new do |channel,success|
212
+ channel[:callback] = Proc.new { p :callback }
213
+ channel[:buffer ] = Net::SSH::Buffer.new
214
+ #channel[:batch ] = blk
215
+ channel[:stderr ] = Net::SSH::Buffer.new
216
+ channel[:state ] = "start_session"
217
+ @channel[:stack] ||= []
218
+ channel.on_close { |ch|
219
+ channel[:handler] = ":on_close"
220
+ }
221
+ channel.on_data { |ch, data|
222
+ channel[:handler] = ":on_data"
223
+ channel[:buffer].append(data)
224
+ }
225
+ channel.on_extended_data { |ch, type, data|
226
+ channel[:handler] = ":on_extended_data"
227
+ channel[:stderr].append(data)
228
+ channel[:state] = :handle_error
229
+ }
230
+ channel.on_request("exit-status") { |ch, data|
231
+ channel[:handler] = ":on_request (exit-status)"
232
+ channel[:exit] = data.read_long
233
+ }
234
+ channel.on_request("exit-signal") do |ch, data|
235
+ channel[:handler] = ":on_request (exit-signal)"
236
+ # This should be the POSIX SIGNAL that ended the process
237
+ channel[:exit_signal] = data.read_long
238
+ end
239
+ channel.on_process {
240
+ channel[:handler] = :on_process
241
+ print channel[:stderr].read if channel[:stderr].available > 0
242
+ begin
243
+ send("#{channel[:state]}_state", channel) unless channel[:state].nil?
244
+ rescue Interrupt
245
+ debug :await_input_interrupt
246
+ channel[:state] = :exit
247
+ end
248
+ }
249
+ end
250
+ end
251
+ end
252
+ end
253
+
254
+ begin
255
+ puts $$
256
+ rbox = Rye::Box.new
257
+ rbox.connect 'ec2-184-72-169-231.compute-1.amazonaws.com', 'ubuntu', :verbose => :fatal, :keys => ['~/.ssh/key-us-east-1b-build-arch']
258
+ #rbox.run 'bash'
259
+ rbox.run 'bash' do
260
+ puts command("date")
261
+ p cat("/etc/issue")
262
+ command("SUDO_PS1=''")
263
+ puts sudo( 'chroot', '/mnt/archlinux-x86_64')
264
+ command("unset PS1;")
265
+ p cat("/etc/issue")
266
+ end
267
+ puts rbox.channel[:stderr] if rbox.channel[:stderr]
268
+ end
269
+
270
+
271
+ __END__
272
+ http://tldp.org/LDP/abs/html/intandnonint.html
273
+ case $- in
274
+ *i*) # interactive shell
275
+ ;;
276
+ *) # non-interactive shell
277
+ ;;
278
+ # (Courtesy of "UNIX F.A.Q.," 1993)
@@ -0,0 +1,280 @@
1
+ require 'net/ssh'
2
+
3
+ #
4
+ # For channel requests, see SSH_MSG_CHANNEL_REQUEST messages
5
+ # in http://www.snailbook.com/docs/connection.txt
6
+ DEBUG = true
7
+
8
+ module Rye
9
+ class Box
10
+ def debug(state, msg='')
11
+ return unless DEBUG
12
+ puts " ------ %s: %s" % [state, msg]
13
+ end
14
+
15
+ def start_session_state(channel)
16
+ debug :start_session, channel[:handler]
17
+ #channel.send_data("stty -echo\n")
18
+ #channel[:state] = :ignore_response
19
+ channel[:state] = :await_response
20
+ end
21
+
22
+ def await_response_state(channel)
23
+ debug :await_response, channel[:handler]
24
+ @await_response_counter ||= 0
25
+ if channel[:buffer].available > 0
26
+ channel[:state] = :read_input
27
+ elsif @await_response_counter > 10
28
+ @await_response_counter = 0
29
+ channel[:state] = :await_input
30
+ end
31
+ @await_response_counter += 1
32
+ end
33
+
34
+ def read_input_state(channel)
35
+ debug :read_input, channel[:handler]
36
+ if channel[:buffer].available > 0
37
+ print channel[:buffer].read
38
+
39
+ if channel[:stack].empty?
40
+ channel[:state] = :await_input
41
+ elsif channel[:buffer].available > 0
42
+ channel[:state] = :read_input
43
+ else
44
+ channel[:state] = :send_data
45
+ end
46
+ else
47
+ channel[:state] = :await_response
48
+ end
49
+ end
50
+
51
+ def send_data_state(channel)
52
+ debug :send_data, channel[:handler]
53
+ #if channel[:stack].empty?
54
+ # channel[:state] = :await_input
55
+ #else
56
+ cmd = channel[:stack].shift
57
+ #return if cmd.strip.empty?
58
+ debug :send_data, "calling #{cmd.inspect}"
59
+ channel[:state] = :await_response
60
+ channel.send_data("#{cmd}\n") unless channel.eof?
61
+ #channel.exec("#{cmd}\n", &create_channel)
62
+ #end
63
+ end
64
+
65
+ def await_input_state(channel)
66
+ debug :await_input, channel[:handler]
67
+
68
+ if channel[:buffer].available > 0
69
+ channel[:state] = :read_input
70
+ else
71
+ ret = STDIN.gets
72
+ if ret.nil?
73
+ channel.eof!
74
+ channel[:state] = :exit
75
+ else
76
+ channel[:stack] << ret.chomp
77
+ channel[:state] = :send_data
78
+ end
79
+ end
80
+
81
+ end
82
+
83
+ def check_interactive_state(channel)
84
+ debug :read_input, channel[:handler]
85
+ channel.send_data("x")
86
+ end
87
+
88
+ def exit_state(channel)
89
+ debug :exit_state, channel[:exit_status]
90
+ puts
91
+ channel.eof!
92
+ end
93
+
94
+ def handle_error_state(channel)
95
+ debug :handle_error, channel[:handler]
96
+ channel.eof!
97
+ end
98
+
99
+ def ignore_response_state(channel)
100
+ debug :ignore_response, channel[:handler]
101
+ @ignore_response_counter ||= 0
102
+ if channel[:buffer].available > 0
103
+ @await_response_counter = 0
104
+ channel[:buffer].read
105
+ channel[:state] = :await_input
106
+ elsif @ignore_response_counter > 2
107
+ @await_response_counter = 0
108
+ channel[:state] = :await_input
109
+ end
110
+ @ignore_response_counter += 1
111
+ end
112
+
113
+
114
+ def run_block_state(channel)
115
+ instance_eval &channel[:block]
116
+ channel[:block] = nil
117
+ channel[:state] = :await_response
118
+ end
119
+
120
+ def command(name,*args, &blk)
121
+ return if @channel.eof?
122
+ channel[:block] = blk
123
+ cmd = "%s %s" % [name, args.join(' ')]
124
+ channel.send_data("#{cmd}\n")
125
+ #channel.wait
126
+ channel[:state] = :await_response
127
+
128
+ #@channel[:buffer]
129
+ # channel.exec "ls -l /home" do |ch, success|
130
+ # if success
131
+ # puts "command has begun executing..."
132
+ # # this is a good place to hang callbacks like #on_data...
133
+ # else
134
+ # puts "alas! the command could not be invoked!"
135
+ # end
136
+ # end
137
+ end
138
+
139
+ def ls(*args) command(:ls, *args) end
140
+ def date(*args) command(:date, *args) end
141
+ def bash(*args, &blk) command(:bash, *args, &blk) end
142
+ def exit(*args, &blk) command(:exit, *args, &blk) end
143
+
144
+ attr_reader :session, :channel
145
+ attr_accessor :running
146
+
147
+ def connect(host, user, opts={})
148
+ opts = {
149
+ :auth_methods => %w[keyboard-interactive]
150
+ }.merge(opts)
151
+ opts[:auth_methods].unshift 'publickey' unless opts[:keys].nil?
152
+ opts[:auth_methods].unshift 'password' unless opts[:password].nil?
153
+ @sessions ||= []
154
+ @session = Net::SSH.start(host, user, opts)
155
+ end
156
+
157
+ def run(shell, &blk)
158
+
159
+ #@session.process(0.1, &busy_proc)
160
+
161
+ #result = nil
162
+ #@channel = @session.open_channel do |ch|
163
+ # ch.exec("irb") do |c, success|
164
+ # ch.on_data { |c, data| puts data }
165
+ # ch.on_extended_data { |c, type, data| puts data }
166
+ # ch.on_close { |c| c.close }
167
+ # end
168
+ #end
169
+
170
+ @channel = @session.open_channel do |channel|
171
+ channel.request_pty do |ch,success|
172
+ if success
173
+
174
+ else
175
+ raise "pty request denied"
176
+ end
177
+ end
178
+ channel.exec shell, &create_channel
179
+ end
180
+
181
+
182
+ @channel[:stack] ||= []
183
+ #@channel[:stack] << "require 'gibbler'"
184
+ #@channel[:stack] << "{}.gibbler"
185
+
186
+ #trap("INT") {
187
+ # p [:INT, @session.closed?, @channel.eof?]
188
+ # #if channel[:state] == :await_input
189
+ # @channel.eof!
190
+ # @session.close unless @session.closed?
191
+ #}
192
+ #trap("INT") {
193
+ #@channel.eof! unless @channel.eof?
194
+ #@session.close unless @session.closed?
195
+ # @channel[:state] = :exit
196
+ #}
197
+
198
+ @session.loop(0.1) do
199
+ break if !@channel.active?
200
+ !@channel.eof? # otherwise keep returning true
201
+ end
202
+
203
+ #puts @channel[:stderr], @channel[:exit_status]
204
+
205
+ end
206
+
207
+ def stop
208
+ @control.join if @control
209
+ @ssh.running = false
210
+ @ssh.close
211
+ end
212
+
213
+ private
214
+ def busy_proc
215
+ Proc.new { |s| !s.busy? }
216
+ end
217
+
218
+ def create_channel
219
+ Proc.new do |channel,success|
220
+ channel[:callback] = Proc.new { p :callback }
221
+ channel[:buffer ] = Net::SSH::Buffer.new
222
+ #channel[:batch ] = blk
223
+ channel[:stderr ] = Net::SSH::Buffer.new
224
+ channel[:state ] = "start_session"
225
+ @channel[:stack] ||= []
226
+ channel.on_close { |ch|
227
+ channel[:handler] = ":on_close"
228
+ }
229
+ channel.on_data { |ch, data|
230
+ channel[:handler] = ":on_data"
231
+ channel[:buffer].append(data)
232
+ }
233
+ channel.on_extended_data { |ch, type, data|
234
+ channel[:handler] = ":on_extended_data"
235
+ channel[:stderr].append(data)
236
+ channel[:state] = :handle_error
237
+ }
238
+ channel.on_request("exit-status") { |ch, data|
239
+ channel[:handler] = ":on_request (exit-status)"
240
+ channel[:exit] = data.read_long
241
+ }
242
+ channel.on_request("exit-signal") do |ch, data|
243
+ channel[:handler] = ":on_request (exit-signal)"
244
+ # This should be the POSIX SIGNAL that ended the process
245
+ channel[:exit_signal] = data.read_long
246
+ end
247
+ channel.on_process {
248
+ channel[:handler] = :on_process
249
+ print channel[:stderr].read if channel[:stderr].available > 0
250
+ begin
251
+ send("#{channel[:state]}_state", channel)
252
+ rescue Interrupt
253
+ debug :await_input_interrupt
254
+ channel[:state] = :exit
255
+ end
256
+ }
257
+ end
258
+ end
259
+ end
260
+ end
261
+
262
+ begin
263
+ puts $$
264
+ rbox = Rye::Box.new
265
+ rbox.connect 'localhost', 'delano', :keys => []
266
+ rbox.run 'bash'
267
+
268
+ #p rbox.channel[:exit], rbox.channel[:exit_signal]
269
+
270
+ end
271
+
272
+
273
+ __END__
274
+ http://tldp.org/LDP/abs/html/intandnonint.html
275
+ case $- in
276
+ *i*) # interactive shell
277
+ ;;
278
+ *) # non-interactive shell
279
+ ;;
280
+ # (Courtesy of "UNIX F.A.Q.," 1993)