auser-poolparty 1.3.4 → 1.3.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. data/VERSION.yml +1 -1
  2. data/bin/cloud-bootstrap +1 -0
  3. data/bin/cloud-configure +1 -0
  4. data/bin/cloud-contract +1 -0
  5. data/bin/poolparty-setup +36 -0
  6. data/examples/vmware.rb +18 -0
  7. data/lib/cloud_providers/cloud_provider_instance.rb +1 -1
  8. data/lib/core/object.rb +2 -2
  9. data/lib/dependency_resolvers/chef.rb +2 -2
  10. data/lib/mixins/askable.rb +16 -7
  11. data/lib/poolparty/base.rb +9 -7
  12. data/lib/poolparty/cloud.rb +57 -2
  13. data/lib/poolparty/installer.rb +8 -4
  14. data/lib/poolparty/installers/ec2.rb +75 -5
  15. data/lib/poolparty/installers/vmware.rb +17 -5
  16. data/lib/poolparty/plugins/apache.rb +3 -2
  17. data/lib/poolparty/plugins/apache2/base.conf.erb +2 -2
  18. data/lib/poolparty/plugins/apache2/browser_fixes.conf.erb +1 -1
  19. data/lib/poolparty/plugins/apache2/passenger_site.rb +2 -2
  20. data/lib/poolparty/pool.rb +9 -2
  21. data/lib/poolparty/resource.rb +20 -7
  22. data/lib/poolparty/resources/directory.rb +5 -1
  23. data/lib/poolparty/resources/exec.rb +2 -2
  24. data/lib/poolparty/resources/file.rb +8 -2
  25. data/lib/poolparty/resources/gem_package.rb +2 -2
  26. data/lib/poolparty/resources/line.rb +23 -6
  27. data/lib/poolparty/resources/mount.rb +2 -2
  28. data/lib/poolparty/resources/package.rb +2 -2
  29. data/lib/poolparty/resources/service.rb +2 -2
  30. data/lib/poolparty/resources/user.rb +2 -2
  31. data/lib/poolparty.rb +2 -2
  32. data/test/lib/poolparty/base_test.rb +13 -0
  33. data/test/lib/poolparty/resources/line_test.rb +3 -3
  34. data/test/lib/poolparty/resources/service_test.rb +1 -1
  35. data/vendor/gems/net-ssh/CHANGELOG.rdoc +127 -0
  36. data/vendor/gems/net-ssh/Manifest +104 -0
  37. data/vendor/gems/net-ssh/README.rdoc +110 -0
  38. data/vendor/gems/net-ssh/Rakefile +26 -0
  39. data/vendor/gems/net-ssh/THANKS.rdoc +16 -0
  40. data/vendor/gems/net-ssh/lib/net/ssh/authentication/agent.rb +176 -0
  41. data/vendor/gems/net-ssh/lib/net/ssh/authentication/constants.rb +18 -0
  42. data/vendor/gems/net-ssh/lib/net/ssh/authentication/key_manager.rb +193 -0
  43. data/vendor/gems/net-ssh/lib/net/ssh/authentication/methods/abstract.rb +60 -0
  44. data/vendor/gems/net-ssh/lib/net/ssh/authentication/methods/hostbased.rb +71 -0
  45. data/vendor/gems/net-ssh/lib/net/ssh/authentication/methods/keyboard_interactive.rb +66 -0
  46. data/vendor/gems/net-ssh/lib/net/ssh/authentication/methods/password.rb +39 -0
  47. data/vendor/gems/net-ssh/lib/net/ssh/authentication/methods/publickey.rb +92 -0
  48. data/vendor/gems/net-ssh/lib/net/ssh/authentication/pageant.rb +183 -0
  49. data/vendor/gems/net-ssh/lib/net/ssh/authentication/session.rb +134 -0
  50. data/vendor/gems/net-ssh/lib/net/ssh/buffer.rb +340 -0
  51. data/vendor/gems/net-ssh/lib/net/ssh/buffered_io.rb +149 -0
  52. data/vendor/gems/net-ssh/lib/net/ssh/config.rb +181 -0
  53. data/vendor/gems/net-ssh/lib/net/ssh/connection/channel.rb +625 -0
  54. data/vendor/gems/net-ssh/lib/net/ssh/connection/constants.rb +33 -0
  55. data/vendor/gems/net-ssh/lib/net/ssh/connection/session.rb +596 -0
  56. data/vendor/gems/net-ssh/lib/net/ssh/connection/term.rb +178 -0
  57. data/vendor/gems/net-ssh/lib/net/ssh/errors.rb +85 -0
  58. data/vendor/gems/net-ssh/lib/net/ssh/key_factory.rb +102 -0
  59. data/vendor/gems/net-ssh/lib/net/ssh/known_hosts.rb +129 -0
  60. data/vendor/gems/net-ssh/lib/net/ssh/loggable.rb +61 -0
  61. data/vendor/gems/net-ssh/lib/net/ssh/packet.rb +102 -0
  62. data/vendor/gems/net-ssh/lib/net/ssh/prompt.rb +93 -0
  63. data/vendor/gems/net-ssh/lib/net/ssh/proxy/errors.rb +14 -0
  64. data/vendor/gems/net-ssh/lib/net/ssh/proxy/http.rb +94 -0
  65. data/vendor/gems/net-ssh/lib/net/ssh/proxy/socks4.rb +70 -0
  66. data/vendor/gems/net-ssh/lib/net/ssh/proxy/socks5.rb +129 -0
  67. data/vendor/gems/net-ssh/lib/net/ssh/ruby_compat.rb +7 -0
  68. data/vendor/gems/net-ssh/lib/net/ssh/service/forward.rb +267 -0
  69. data/vendor/gems/net-ssh/lib/net/ssh/test/channel.rb +129 -0
  70. data/vendor/gems/net-ssh/lib/net/ssh/test/extensions.rb +152 -0
  71. data/vendor/gems/net-ssh/lib/net/ssh/test/kex.rb +44 -0
  72. data/vendor/gems/net-ssh/lib/net/ssh/test/local_packet.rb +51 -0
  73. data/vendor/gems/net-ssh/lib/net/ssh/test/packet.rb +81 -0
  74. data/vendor/gems/net-ssh/lib/net/ssh/test/remote_packet.rb +38 -0
  75. data/vendor/gems/net-ssh/lib/net/ssh/test/script.rb +157 -0
  76. data/vendor/gems/net-ssh/lib/net/ssh/test/socket.rb +59 -0
  77. data/vendor/gems/net-ssh/lib/net/ssh/test.rb +89 -0
  78. data/vendor/gems/net-ssh/lib/net/ssh/transport/algorithms.rb +384 -0
  79. data/vendor/gems/net-ssh/lib/net/ssh/transport/cipher_factory.rb +80 -0
  80. data/vendor/gems/net-ssh/lib/net/ssh/transport/constants.rb +30 -0
  81. data/vendor/gems/net-ssh/lib/net/ssh/transport/hmac/abstract.rb +78 -0
  82. data/vendor/gems/net-ssh/lib/net/ssh/transport/hmac/md5.rb +12 -0
  83. data/vendor/gems/net-ssh/lib/net/ssh/transport/hmac/md5_96.rb +11 -0
  84. data/vendor/gems/net-ssh/lib/net/ssh/transport/hmac/none.rb +15 -0
  85. data/vendor/gems/net-ssh/lib/net/ssh/transport/hmac/sha1.rb +13 -0
  86. data/vendor/gems/net-ssh/lib/net/ssh/transport/hmac/sha1_96.rb +11 -0
  87. data/vendor/gems/net-ssh/lib/net/ssh/transport/hmac.rb +31 -0
  88. data/vendor/gems/net-ssh/lib/net/ssh/transport/identity_cipher.rb +55 -0
  89. data/vendor/gems/net-ssh/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +208 -0
  90. data/vendor/gems/net-ssh/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +77 -0
  91. data/vendor/gems/net-ssh/lib/net/ssh/transport/kex.rb +13 -0
  92. data/vendor/gems/net-ssh/lib/net/ssh/transport/openssl.rb +128 -0
  93. data/vendor/gems/net-ssh/lib/net/ssh/transport/packet_stream.rb +230 -0
  94. data/vendor/gems/net-ssh/lib/net/ssh/transport/server_version.rb +60 -0
  95. data/vendor/gems/net-ssh/lib/net/ssh/transport/session.rb +276 -0
  96. data/vendor/gems/net-ssh/lib/net/ssh/transport/state.rb +201 -0
  97. data/vendor/gems/net-ssh/lib/net/ssh/verifiers/lenient.rb +30 -0
  98. data/vendor/gems/net-ssh/lib/net/ssh/verifiers/null.rb +12 -0
  99. data/vendor/gems/net-ssh/lib/net/ssh/verifiers/strict.rb +53 -0
  100. data/vendor/gems/net-ssh/lib/net/ssh/version.rb +62 -0
  101. data/vendor/gems/net-ssh/lib/net/ssh.rb +215 -0
  102. data/vendor/gems/net-ssh/net-ssh.gemspec +33 -0
  103. data/vendor/gems/net-ssh/setup.rb +1585 -0
  104. data/vendor/gems/net-ssh/test/authentication/methods/common.rb +28 -0
  105. data/vendor/gems/net-ssh/test/authentication/methods/test_abstract.rb +51 -0
  106. data/vendor/gems/net-ssh/test/authentication/methods/test_hostbased.rb +114 -0
  107. data/vendor/gems/net-ssh/test/authentication/methods/test_keyboard_interactive.rb +98 -0
  108. data/vendor/gems/net-ssh/test/authentication/methods/test_password.rb +50 -0
  109. data/vendor/gems/net-ssh/test/authentication/methods/test_publickey.rb +127 -0
  110. data/vendor/gems/net-ssh/test/authentication/test_agent.rb +205 -0
  111. data/vendor/gems/net-ssh/test/authentication/test_key_manager.rb +105 -0
  112. data/vendor/gems/net-ssh/test/authentication/test_session.rb +93 -0
  113. data/vendor/gems/net-ssh/test/common.rb +106 -0
  114. data/vendor/gems/net-ssh/test/configs/eqsign +3 -0
  115. data/vendor/gems/net-ssh/test/configs/exact_match +8 -0
  116. data/vendor/gems/net-ssh/test/configs/wild_cards +14 -0
  117. data/vendor/gems/net-ssh/test/connection/test_channel.rb +452 -0
  118. data/vendor/gems/net-ssh/test/connection/test_session.rb +488 -0
  119. data/vendor/gems/net-ssh/test/test_all.rb +6 -0
  120. data/vendor/gems/net-ssh/test/test_buffer.rb +336 -0
  121. data/vendor/gems/net-ssh/test/test_buffered_io.rb +63 -0
  122. data/vendor/gems/net-ssh/test/test_config.rb +84 -0
  123. data/vendor/gems/net-ssh/test/test_key_factory.rb +67 -0
  124. data/vendor/gems/net-ssh/test/transport/hmac/test_md5.rb +39 -0
  125. data/vendor/gems/net-ssh/test/transport/hmac/test_md5_96.rb +25 -0
  126. data/vendor/gems/net-ssh/test/transport/hmac/test_none.rb +34 -0
  127. data/vendor/gems/net-ssh/test/transport/hmac/test_sha1.rb +34 -0
  128. data/vendor/gems/net-ssh/test/transport/hmac/test_sha1_96.rb +25 -0
  129. data/vendor/gems/net-ssh/test/transport/kex/test_diffie_hellman_group1_sha1.rb +146 -0
  130. data/vendor/gems/net-ssh/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +92 -0
  131. data/vendor/gems/net-ssh/test/transport/test_algorithms.rb +302 -0
  132. data/vendor/gems/net-ssh/test/transport/test_cipher_factory.rb +171 -0
  133. data/vendor/gems/net-ssh/test/transport/test_hmac.rb +34 -0
  134. data/vendor/gems/net-ssh/test/transport/test_identity_cipher.rb +40 -0
  135. data/vendor/gems/net-ssh/test/transport/test_packet_stream.rb +435 -0
  136. data/vendor/gems/net-ssh/test/transport/test_server_version.rb +57 -0
  137. data/vendor/gems/net-ssh/test/transport/test_session.rb +315 -0
  138. data/vendor/gems/net-ssh/test/transport/test_state.rb +173 -0
  139. metadata +109 -4
  140. data/bin/install-poolparty +0 -20
@@ -0,0 +1,625 @@
1
+ require 'net/ssh/loggable'
2
+ require 'net/ssh/connection/constants'
3
+ require 'net/ssh/connection/term'
4
+
5
+ module Net; module SSH; module Connection
6
+
7
+ # The channel abstraction. Multiple "channels" can be multiplexed onto a
8
+ # single SSH channel, each operating independently and seemingly in parallel.
9
+ # This class represents a single such channel. Most operations performed
10
+ # with the Net::SSH library will involve using one or more channels.
11
+ #
12
+ # Channels are intended to be used asynchronously. You request that one be
13
+ # opened (via Connection::Session#open_channel), and when it is opened, your
14
+ # callback is invoked. Then, you set various other callbacks on the newly
15
+ # opened channel, which are called in response to the corresponding events.
16
+ # Programming with Net::SSH works best if you think of your programs as
17
+ # state machines. Complex programs are best implemented as objects that
18
+ # wrap a channel. See Net::SCP and Net::SFTP for examples of how complex
19
+ # state machines can be built on top of the SSH protocol.
20
+ #
21
+ # ssh.open_channel do |channel|
22
+ # channel.exec("/invoke/some/command") do |ch, success|
23
+ # abort "could not execute command" unless success
24
+ #
25
+ # channel.on_data do |ch, data|
26
+ # puts "got stdout: #{data}"
27
+ # channel.send_data "something for stdin\n"
28
+ # end
29
+ #
30
+ # channel.on_extended_data do |ch, type, data|
31
+ # puts "got stderr: #{data}"
32
+ # end
33
+ #
34
+ # channel.on_close do |ch|
35
+ # puts "channel is closing!"
36
+ # end
37
+ # end
38
+ # end
39
+ #
40
+ # ssh.loop
41
+ #
42
+ # Channels also have a basic hash-like interface, that allows programs to
43
+ # store arbitrary state information on a channel object. This helps simplify
44
+ # the writing of state machines, especially when you may be juggling
45
+ # multiple open channels at the same time.
46
+ #
47
+ # Note that data sent across SSH channels are governed by maximum packet
48
+ # sizes and maximum window sizes. These details are managed internally
49
+ # by Net::SSH::Connection::Channel, so you may remain blissfully ignorant
50
+ # if you so desire, but you can always inspect the current maximums, as
51
+ # well as the remaining window size, using the reader attributes for those
52
+ # values.
53
+ class Channel
54
+ include Constants, Loggable
55
+
56
+ # The local id for this channel, assigned by the Net::SSH::Connection::Session instance.
57
+ attr_reader :local_id
58
+
59
+ # The remote id for this channel, assigned by the remote host.
60
+ attr_reader :remote_id
61
+
62
+ # The type of this channel, usually "session".
63
+ attr_reader :type
64
+
65
+ # The underlying Net::SSH::Connection::Session instance that supports this channel.
66
+ attr_reader :connection
67
+
68
+ # The maximum packet size that the local host can receive.
69
+ attr_reader :local_maximum_packet_size
70
+
71
+ # The maximum amount of data that the local end of this channel can
72
+ # receive. This is a total, not per-packet.
73
+ attr_reader :local_maximum_window_size
74
+
75
+ # The maximum packet size that the remote host can receive.
76
+ attr_reader :remote_maximum_packet_size
77
+
78
+ # The maximum amount of data that the remote end of this channel can
79
+ # receive. This is a total, not per-packet.
80
+ attr_reader :remote_maximum_window_size
81
+
82
+ # This is the remaining window size on the local end of this channel. When
83
+ # this reaches zero, no more data can be received.
84
+ attr_reader :local_window_size
85
+
86
+ # This is the remaining window size on the remote end of this channel. When
87
+ # this reaches zero, no more data can be sent.
88
+ attr_reader :remote_window_size
89
+
90
+ # A hash of properties for this channel. These can be used to store state
91
+ # information about this channel. See also #[] and #[]=.
92
+ attr_reader :properties
93
+
94
+ # The output buffer for this channel. Data written to the channel is
95
+ # enqueued here, to be written as CHANNEL_DATA packets during each pass of
96
+ # the event loop. See Connection::Session#process and #enqueue_pending_output.
97
+ attr_reader :output #:nodoc:
98
+
99
+ # The list of pending requests. Each time a request is sent which requires
100
+ # a reply, the corresponding callback is pushed onto this queue. As responses
101
+ # arrive, they are shifted off the front and handled.
102
+ attr_reader :pending_requests #:nodoc:
103
+
104
+ # Instantiates a new channel on the given connection, of the given type,
105
+ # and with the given id. If a block is given, it will be remembered until
106
+ # the channel is confirmed open by the server, and will be invoked at
107
+ # that time (see #do_open_confirmation).
108
+ #
109
+ # This also sets the default maximum packet size and maximum window size.
110
+ def initialize(connection, type, local_id, &on_confirm_open)
111
+ self.logger = connection.logger
112
+
113
+ @connection = connection
114
+ @type = type
115
+ @local_id = local_id
116
+
117
+ @local_maximum_packet_size = 0x10000
118
+ @local_window_size = @local_maximum_window_size = 0x20000
119
+
120
+ @on_confirm_open = on_confirm_open
121
+
122
+ @output = Buffer.new
123
+
124
+ @properties = {}
125
+
126
+ @pending_requests = []
127
+ @on_open_failed = @on_data = @on_extended_data = @on_process = @on_close = @on_eof = nil
128
+ @on_request = {}
129
+ @closing = @eof = false
130
+ end
131
+
132
+ # A shortcut for accessing properties of the channel (see #properties).
133
+ def [](name)
134
+ @properties[name]
135
+ end
136
+
137
+ # A shortcut for setting properties of the channel (see #properties).
138
+ def []=(name, value)
139
+ @properties[name] = value
140
+ end
141
+
142
+ # Syntactic sugar for executing a command. Sends a channel request asking
143
+ # that the given command be invoked. If the block is given, it will be
144
+ # called when the server responds. The first parameter will be the
145
+ # channel, and the second will be true or false, indicating whether the
146
+ # request succeeded or not. In this case, success means that the command
147
+ # is being executed, not that it has completed, and failure means that the
148
+ # command altogether failed to be executed.
149
+ #
150
+ # channel.exec "ls -l /home" do |ch, success|
151
+ # if success
152
+ # puts "command has begun executing..."
153
+ # # this is a good place to hang callbacks like #on_data...
154
+ # else
155
+ # puts "alas! the command could not be invoked!"
156
+ # end
157
+ # end
158
+ def exec(command, &block)
159
+ send_channel_request("exec", :string, command, &block)
160
+ end
161
+
162
+ # Syntactic sugar for requesting that a subsystem be started. Subsystems
163
+ # are a way for other protocols (like SFTP) to be run, using SSH as
164
+ # the transport. Generally, you'll never need to call this directly unless
165
+ # you are the implementor of something that consumes an SSH subsystem, like
166
+ # SFTP.
167
+ #
168
+ # channel.subsystem("sftp") do |ch, success|
169
+ # if success
170
+ # puts "subsystem successfully started"
171
+ # else
172
+ # puts "subsystem could not be started"
173
+ # end
174
+ # end
175
+ def subsystem(subsystem, &block)
176
+ send_channel_request("subsystem", :string, subsystem, &block)
177
+ end
178
+
179
+ # Syntactic sugar for setting an environment variable in the remote
180
+ # process' environment. Note that for security reasons, the server may
181
+ # refuse to set certain environment variables, or all, at the server's
182
+ # discretion. If you are connecting to an OpenSSH server, you will
183
+ # need to update the AcceptEnv setting in the sshd_config to include the
184
+ # environment variables you want to send.
185
+ #
186
+ # channel.env "PATH", "/usr/local/bin"
187
+ def env(variable_name, variable_value, &block)
188
+ send_channel_request("env", :string, variable_name, :string, variable_value, &block)
189
+ end
190
+
191
+ # A hash of the valid PTY options (see #request_pty).
192
+ VALID_PTY_OPTIONS = { :term => "xterm",
193
+ :chars_wide => 80,
194
+ :chars_high => 24,
195
+ :pixels_wide => 640,
196
+ :pixels_high => 480,
197
+ :modes => {} }
198
+
199
+ # Requests that a pseudo-tty (or "pty") be made available for this channel.
200
+ # This is useful when you want to invoke and interact with some kind of
201
+ # screen-based program (e.g., vim, or some menuing system).
202
+ #
203
+ # Note, that without a pty some programs (e.g. sudo, or subversion) on
204
+ # some systems, will not be able to run interactively, and will error
205
+ # instead of prompt if they ever need some user interaction.
206
+ #
207
+ # Note, too, that when a pty is requested, user's shell configuration
208
+ # scripts (.bashrc and such) are not run by default, whereas they are
209
+ # run when a pty is not present.
210
+ #
211
+ # channel.request_pty do |ch, success|
212
+ # if success
213
+ # puts "pty successfully obtained"
214
+ # else
215
+ # puts "could not obtain pty"
216
+ # end
217
+ # end
218
+ def request_pty(opts={}, &block)
219
+ extra = opts.keys - VALID_PTY_OPTIONS.keys
220
+ raise ArgumentError, "invalid option(s) to request_pty: #{extra.inspect}" if extra.any?
221
+
222
+ opts = VALID_PTY_OPTIONS.merge(opts)
223
+
224
+ modes = opts[:modes].inject(Buffer.new) do |memo, (mode, data)|
225
+ memo.write_byte(mode).write_long(data)
226
+ end
227
+ # mark the end of the mode opcode list with a 0 byte
228
+ modes.write_byte(0)
229
+
230
+ send_channel_request("pty-req", :string, opts[:term],
231
+ :long, opts[:chars_wide], :long, opts[:chars_high],
232
+ :long, opts[:pixels_wide], :long, opts[:pixels_high],
233
+ :string, modes.to_s, &block)
234
+ end
235
+
236
+ # Sends data to the channel's remote endpoint. This usually has the
237
+ # effect of sending the given string to the remote process' stdin stream.
238
+ # Note that it does not immediately send the data across the channel,
239
+ # but instead merely appends the given data to the channel's output buffer,
240
+ # preparatory to being packaged up and sent out the next time the connection
241
+ # is accepting data. (A connection might not be accepting data if, for
242
+ # instance, it has filled its data window and has not yet been resized by
243
+ # the remote end-point.)
244
+ #
245
+ # This will raise an exception if the channel has previously declared
246
+ # that no more data will be sent (see #eof!).
247
+ #
248
+ # channel.send_data("the password\n")
249
+ def send_data(data)
250
+ raise EOFError, "cannot send data if channel has declared eof" if eof?
251
+ output.append(data.to_s)
252
+ end
253
+
254
+ # Returns true if the channel exists in the channel list of the session,
255
+ # and false otherwise. This can be used to determine whether a channel has
256
+ # been closed or not.
257
+ #
258
+ # ssh.loop { channel.active? }
259
+ def active?
260
+ connection.channels.key?(local_id)
261
+ end
262
+
263
+ # Runs the SSH event loop until the channel is no longer active. This is
264
+ # handy for blocking while you wait for some channel to finish.
265
+ #
266
+ # channel.exec("grep ...") { ... }
267
+ # channel.wait
268
+ def wait
269
+ connection.loop { active? }
270
+ end
271
+
272
+ # Returns true if the channel is currently closing, but not actually
273
+ # closed. A channel is closing when, for instance, #close has been
274
+ # invoked, but the server has not yet responded with a CHANNEL_CLOSE
275
+ # packet of its own.
276
+ def closing?
277
+ @closing
278
+ end
279
+
280
+ # Requests that the channel be closed. If the channel is already closing,
281
+ # this does nothing, nor does it do anything if the channel has not yet
282
+ # been confirmed open (see #do_open_confirmation). Otherwise, it sends a
283
+ # CHANNEL_CLOSE message and marks the channel as closing.
284
+ def close
285
+ return if @closing
286
+ if remote_id
287
+ @closing = true
288
+ connection.send_message(Buffer.from(:byte, CHANNEL_CLOSE, :long, remote_id))
289
+ end
290
+ end
291
+
292
+ # Returns true if the local end of the channel has declared that no more
293
+ # data is forthcoming (see #eof!). Trying to send data via #send_data when
294
+ # this is true will result in an exception being raised.
295
+ def eof?
296
+ @eof
297
+ end
298
+
299
+ # Tells the remote end of the channel that no more data is forthcoming
300
+ # from this end of the channel. The remote end may still send data.
301
+ def eof!
302
+ return if eof?
303
+ @eof = true
304
+ connection.send_message(Buffer.from(:byte, CHANNEL_EOF, :long, remote_id))
305
+ end
306
+
307
+ # If an #on_process handler has been set up, this will cause it to be
308
+ # invoked (passing the channel itself as an argument). It also causes all
309
+ # pending output to be enqueued as CHANNEL_DATA packets (see #enqueue_pending_output).
310
+ def process
311
+ @on_process.call(self) if @on_process
312
+ enqueue_pending_output
313
+ end
314
+
315
+ # Registers a callback to be invoked when data packets are received by the
316
+ # channel. The callback is called with the channel as the first argument,
317
+ # and the data as the second.
318
+ #
319
+ # channel.on_data do |ch, data|
320
+ # puts "got data: #{data.inspect}"
321
+ # end
322
+ #
323
+ # Data received this way is typically the data written by the remote
324
+ # process to its +stdout+ stream.
325
+ def on_data(&block)
326
+ old, @on_data = @on_data, block
327
+ old
328
+ end
329
+
330
+ # Registers a callback to be invoked when extended data packets are received
331
+ # by the channel. The callback is called with the channel as the first
332
+ # argument, the data type (as an integer) as the second, and the data as
333
+ # the third. Extended data is almost exclusively used to send +stderr+ data
334
+ # (+type+ == 1). Other extended data types are not defined by the SSH
335
+ # protocol.
336
+ #
337
+ # channel.on_extended_data do |ch, type, data|
338
+ # puts "got stderr: #{data.inspect}"
339
+ # end
340
+ def on_extended_data(&block)
341
+ old, @on_extended_data = @on_extended_data, block
342
+ old
343
+ end
344
+
345
+ # Registers a callback to be invoked for each pass of the event loop for
346
+ # this channel. There are no guarantees on timeliness in the event loop,
347
+ # but it will be called roughly once for each packet received by the
348
+ # connection (not the channel). This callback is invoked with the channel
349
+ # as the sole argument.
350
+ #
351
+ # Here's an example that accumulates the channel data into a variable on
352
+ # the channel itself, and displays individual lines in the input one
353
+ # at a time when the channel is processed:
354
+ #
355
+ # channel[:data] = ""
356
+ #
357
+ # channel.on_data do |ch, data|
358
+ # channel[:data] << data
359
+ # end
360
+ #
361
+ # channel.on_process do |ch|
362
+ # if channel[:data] =~ /^.*?\n/
363
+ # puts $&
364
+ # channel[:data] = $'
365
+ # end
366
+ # end
367
+ def on_process(&block)
368
+ old, @on_process = @on_process, block
369
+ old
370
+ end
371
+
372
+ # Registers a callback to be invoked when the server acknowledges that a
373
+ # channel is closed. This is invoked with the channel as the sole argument.
374
+ #
375
+ # channel.on_close do |ch|
376
+ # puts "remote end is closing!"
377
+ # end
378
+ def on_close(&block)
379
+ old, @on_close = @on_close, block
380
+ old
381
+ end
382
+
383
+ # Registers a callback to be invoked when the server indicates that no more
384
+ # data will be sent to the channel (although the channel can still send
385
+ # data to the server). The channel is the sole argument to the callback.
386
+ #
387
+ # channel.on_eof do |ch|
388
+ # puts "remote end is done sending data"
389
+ # end
390
+ def on_eof(&block)
391
+ old, @on_eof = @on_eof, block
392
+ old
393
+ end
394
+
395
+ # Registers a callback to be invoked when the server was unable to open
396
+ # the requested channel. The channel itself will be passed to the block,
397
+ # along with the integer "reason code" for the failure, and a textual
398
+ # description of the failure from the server.
399
+ #
400
+ # channel = session.open_channel do |ch|
401
+ # # ..
402
+ # end
403
+ #
404
+ # channel.on_open_failed { |ch, code, desc| ... }
405
+ def on_open_failed(&block)
406
+ old, @on_open_failed = @on_open_failed, block
407
+ old
408
+ end
409
+
410
+ # Registers a callback to be invoked when a channel request of the given
411
+ # type is received. The callback will receive the channel as the first
412
+ # argument, and the associated (unparsed) data as the second. The data
413
+ # will be a Net::SSH::Buffer that you will need to parse, yourself,
414
+ # according to the kind of request you are watching.
415
+ #
416
+ # By default, if the request wants a reply, Net::SSH will send a
417
+ # CHANNEL_SUCCESS response for any request that was handled by a registered
418
+ # callback, and CHANNEL_FAILURE for any that wasn't, but if you want your
419
+ # registered callback to result in a CHANNEL_FAILURE response, just raise
420
+ # Net::SSH::ChannelRequestFailed.
421
+ #
422
+ # Some common channel requests that your programs might want to listen
423
+ # for are:
424
+ #
425
+ # * "exit-status" : the exit status of the remote process will be reported
426
+ # as a long integer in the data buffer, which you can grab via
427
+ # data.read_long.
428
+ # * "exit-signal" : if the remote process died as a result of a signal
429
+ # being sent to it, the signal will be reported as a string in the
430
+ # data, via data.read_string. (Not all SSH servers support this channel
431
+ # request type.)
432
+ #
433
+ # channel.on_request "exit-status" do |ch, data|
434
+ # puts "process terminated with exit status: #{data.read_long}"
435
+ # end
436
+ def on_request(type, &block)
437
+ old, @on_request[type] = @on_request[type], block
438
+ old
439
+ end
440
+
441
+ # Sends a new channel request with the given name. The extra +data+
442
+ # parameter must either be empty, or consist of an even number of
443
+ # arguments. See Net::SSH::Buffer.from for a description of their format.
444
+ # If a block is given, it is registered as a callback for a pending
445
+ # request, and the packet will be flagged so that the server knows a
446
+ # reply is required. If no block is given, the server will send no
447
+ # response to this request. Responses, where required, will cause the
448
+ # callback to be invoked with the channel as the first argument, and
449
+ # either true or false as the second, depending on whether the request
450
+ # succeeded or not. The meaning of "success" and "failure" in this context
451
+ # is dependent on the specific request that was sent.
452
+ #
453
+ # channel.send_channel_request "shell" do |ch, success|
454
+ # if success
455
+ # puts "user shell started successfully"
456
+ # else
457
+ # puts "could not start user shell"
458
+ # end
459
+ # end
460
+ #
461
+ # Most channel requests you'll want to send are already wrapped in more
462
+ # convenient helper methods (see #exec and #subsystem).
463
+ def send_channel_request(request_name, *data, &callback)
464
+ info { "sending channel request #{request_name.inspect}" }
465
+ msg = Buffer.from(:byte, CHANNEL_REQUEST,
466
+ :long, remote_id, :string, request_name,
467
+ :bool, !callback.nil?, *data)
468
+ connection.send_message(msg)
469
+ pending_requests << callback if callback
470
+ end
471
+
472
+ public # these methods are public, but for Net::SSH internal use only
473
+
474
+ # Enqueues pending output at the connection as CHANNEL_DATA packets. This
475
+ # does nothing if the channel has not yet been confirmed open (see
476
+ # #do_open_confirmation). This is called automatically by #process, which
477
+ # is called from the event loop (Connection::Session#process). You will
478
+ # generally not need to invoke it directly.
479
+ def enqueue_pending_output #:nodoc:
480
+ return unless remote_id
481
+
482
+ while output.length > 0
483
+ length = output.length
484
+ length = remote_window_size if length > remote_window_size
485
+ length = remote_maximum_packet_size if length > remote_maximum_packet_size
486
+
487
+ if length > 0
488
+ connection.send_message(Buffer.from(:byte, CHANNEL_DATA, :long, remote_id, :string, output.read(length)))
489
+ output.consume!
490
+ @remote_window_size -= length
491
+ else
492
+ break
493
+ end
494
+ end
495
+ end
496
+
497
+ # Invoked when the server confirms that a channel has been opened.
498
+ # The remote_id is the id of the channel as assigned by the remote host,
499
+ # and max_window and max_packet are the maximum window and maximum
500
+ # packet sizes, respectively. If an open-confirmation callback was
501
+ # given when the channel was created, it is invoked at this time with
502
+ # the channel itself as the sole argument.
503
+ def do_open_confirmation(remote_id, max_window, max_packet) #:nodoc:
504
+ @remote_id = remote_id
505
+ @remote_window_size = @remote_maximum_window_size = max_window
506
+ @remote_maximum_packet_size = max_packet
507
+ connection.forward.agent(self) if connection.options[:forward_agent] && type == "session"
508
+ @on_confirm_open.call(self) if @on_confirm_open
509
+ end
510
+
511
+ # Invoked when the server failed to open the channel. If an #on_open_failed
512
+ # callback was specified, it will be invoked with the channel, reason code,
513
+ # and description as arguments. Otherwise, a ChannelOpenFailed exception
514
+ # will be raised.
515
+ def do_open_failed(reason_code, description)
516
+ if @on_open_failed
517
+ @on_open_failed.call(self, reason_code, description)
518
+ else
519
+ raise ChannelOpenFailed.new(reason_code, description)
520
+ end
521
+ end
522
+
523
+ # Invoked when the server sends a CHANNEL_WINDOW_ADJUST packet, and
524
+ # causes the remote window size to be adjusted upwards by the given
525
+ # number of bytes. This has the effect of allowing more data to be sent
526
+ # from the local end to the remote end of the channel.
527
+ def do_window_adjust(bytes) #:nodoc:
528
+ @remote_maximum_window_size += bytes
529
+ @remote_window_size += bytes
530
+ end
531
+
532
+ # Invoked when the server sends a channel request. If any #on_request
533
+ # callback has been registered for the specific type of this request,
534
+ # it is invoked. If +want_reply+ is true, a packet will be sent of
535
+ # either CHANNEL_SUCCESS or CHANNEL_FAILURE type. If there was no callback
536
+ # to handle the request, CHANNEL_FAILURE will be sent. Otherwise,
537
+ # CHANNEL_SUCCESS, unless the callback raised ChannelRequestFailed. The
538
+ # callback should accept the channel as the first argument, and the
539
+ # request-specific data as the second.
540
+ def do_request(request, want_reply, data) #:nodoc:
541
+ result = true
542
+
543
+ begin
544
+ callback = @on_request[request] or raise ChannelRequestFailed
545
+ callback.call(self, data)
546
+ rescue ChannelRequestFailed
547
+ result = false
548
+ end
549
+
550
+ if want_reply
551
+ msg = Buffer.from(:byte, result ? CHANNEL_SUCCESS : CHANNEL_FAILURE, :long, remote_id)
552
+ connection.send_message(msg)
553
+ end
554
+ end
555
+
556
+ # Invokes the #on_data callback when the server sends data to the
557
+ # channel. This will reduce the available window size on the local end,
558
+ # but does not actually throttle requests that come in illegally when
559
+ # the window size is too small. The callback is invoked with the channel
560
+ # as the first argument, and the data as the second.
561
+ def do_data(data) #:nodoc:
562
+ update_local_window_size(data.length)
563
+ @on_data.call(self, data) if @on_data
564
+ end
565
+
566
+ # Invokes the #on_extended_data callback when the server sends
567
+ # extended data to the channel. This will reduce the available window
568
+ # size on the local end. The callback is invoked with the channel,
569
+ # type, and data.
570
+ def do_extended_data(type, data)
571
+ update_local_window_size(data.length)
572
+ @on_extended_data.call(self, type, data) if @on_extended_data
573
+ end
574
+
575
+ # Invokes the #on_eof callback when the server indicates that no
576
+ # further data is forthcoming. The callback is invoked with the channel
577
+ # as the argument.
578
+ def do_eof
579
+ @on_eof.call(self) if @on_eof
580
+ end
581
+
582
+ # Invokes the #on_close callback when the server closes a channel.
583
+ # The channel is the only argument.
584
+ def do_close
585
+ @on_close.call(self) if @on_close
586
+ end
587
+
588
+ # Invokes the next pending request callback with +false+ as the second
589
+ # argument.
590
+ def do_failure
591
+ if callback = pending_requests.shift
592
+ callback.call(self, false)
593
+ else
594
+ error { "channel failure recieved with no pending request to handle it (bug?)" }
595
+ end
596
+ end
597
+
598
+ # Invokes the next pending request callback with +true+ as the second
599
+ # argument.
600
+ def do_success
601
+ if callback = pending_requests.shift
602
+ callback.call(self, true)
603
+ else
604
+ error { "channel success recieved with no pending request to handle it (bug?)" }
605
+ end
606
+ end
607
+
608
+ private
609
+
610
+ # Updates the local window size by the given amount. If the window
611
+ # size drops to less than half of the local maximum (an arbitrary
612
+ # threshold), a CHANNEL_WINDOW_ADJUST message will be sent to the
613
+ # server telling it that the window size has grown.
614
+ def update_local_window_size(size)
615
+ @local_window_size -= size
616
+ if local_window_size < local_maximum_window_size/2
617
+ connection.send_message(Buffer.from(:byte, CHANNEL_WINDOW_ADJUST,
618
+ :long, remote_id, :long, 0x20000))
619
+ @local_window_size += 0x20000
620
+ @local_maximum_window_size += 0x20000
621
+ end
622
+ end
623
+ end
624
+
625
+ end; end; end
@@ -0,0 +1,33 @@
1
+ module Net; module SSH; module Connection
2
+
3
+ # Definitions of constants that are specific to the connection layer of the
4
+ # SSH protocol.
5
+ module Constants
6
+
7
+ #--
8
+ # Connection protocol generic messages
9
+ #++
10
+
11
+ GLOBAL_REQUEST = 80
12
+ REQUEST_SUCCESS = 81
13
+ REQUEST_FAILURE = 82
14
+
15
+ #--
16
+ # Channel related messages
17
+ #++
18
+
19
+ CHANNEL_OPEN = 90
20
+ CHANNEL_OPEN_CONFIRMATION = 91
21
+ CHANNEL_OPEN_FAILURE = 92
22
+ CHANNEL_WINDOW_ADJUST = 93
23
+ CHANNEL_DATA = 94
24
+ CHANNEL_EXTENDED_DATA = 95
25
+ CHANNEL_EOF = 96
26
+ CHANNEL_CLOSE = 97
27
+ CHANNEL_REQUEST = 98
28
+ CHANNEL_SUCCESS = 99
29
+ CHANNEL_FAILURE = 100
30
+
31
+ end
32
+
33
+ end; end end