poolparty 1.3.4 → 1.3.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (174) hide show
  1. data/Rakefile +2 -2
  2. data/VERSION.yml +1 -1
  3. data/bin/cloud-bootstrap +1 -0
  4. data/bin/cloud-configure +1 -0
  5. data/bin/cloud-contract +1 -0
  6. data/bin/cloud-misc +34 -0
  7. data/bin/cloud-setup +36 -0
  8. data/bin/cloud-ssh +4 -1
  9. data/config/jeweler.rb +4 -3
  10. data/examples/monitored_cloud.rb +1 -1
  11. data/examples/thrift/thrift_example.rb +5 -3
  12. data/examples/vmware.rb +28 -0
  13. data/lib/cloud_providers/cloud_provider_instance.rb +14 -5
  14. data/lib/cloud_providers/connections.rb +1 -1
  15. data/lib/core/file.rb +12 -0
  16. data/lib/core/object.rb +2 -2
  17. data/lib/dependency_resolvers/base.rb +1 -1
  18. data/lib/dependency_resolvers/chef.rb +9 -7
  19. data/lib/dependency_resolvers/proxy_object.rb +11 -3
  20. data/lib/mixins/askable.rb +16 -7
  21. data/lib/poolparty/base.rb +8 -7
  22. data/lib/poolparty/cloud.rb +77 -7
  23. data/lib/poolparty/default.rb +1 -0
  24. data/lib/poolparty/installer.rb +8 -4
  25. data/lib/poolparty/installers/ec2.rb +75 -5
  26. data/lib/poolparty/installers/vmware.rb +17 -5
  27. data/lib/poolparty/plugin.rb +1 -5
  28. data/lib/poolparty/plugins/apache.rb +10 -7
  29. data/lib/poolparty/plugins/apache2/base.conf.erb +2 -2
  30. data/lib/poolparty/plugins/apache2/browser_fixes.conf.erb +1 -1
  31. data/lib/poolparty/plugins/apache2/passenger_site.rb +2 -2
  32. data/lib/poolparty/plugins/collectd/templates/collectd.conf.erb +369 -0
  33. data/lib/poolparty/plugins/collectd.rb +24 -0
  34. data/lib/poolparty/plugins/hermes.rb +89 -0
  35. data/lib/poolparty/pool.rb +33 -3
  36. data/lib/poolparty/resource.rb +32 -18
  37. data/lib/poolparty/resources/directory.rb +5 -1
  38. data/lib/poolparty/resources/exec.rb +2 -2
  39. data/lib/poolparty/resources/file.rb +8 -2
  40. data/lib/poolparty/resources/gem_package.rb +2 -2
  41. data/lib/poolparty/resources/line.rb +23 -6
  42. data/lib/poolparty/resources/mount.rb +2 -2
  43. data/lib/poolparty/resources/package.rb +2 -2
  44. data/lib/poolparty/resources/service.rb +2 -2
  45. data/lib/poolparty/resources/user.rb +2 -2
  46. data/lib/poolparty/resources/variable.rb +4 -3
  47. data/lib/poolparty.rb +5 -3
  48. data/lib/proto/command_interface_handler.rb +17 -1
  49. data/lib/proto/gen-py/cloudthrift/CommandInterface.pyc +0 -0
  50. data/lib/proto/gen-py/cloudthrift/__init__.pyc +0 -0
  51. data/lib/proto/gen-py/cloudthrift/constants.pyc +0 -0
  52. data/lib/proto/gen-py/cloudthrift/ttypes.pyc +0 -0
  53. data/lib/proto/gen-py/thrift/Thrift.pyc +0 -0
  54. data/lib/proto/gen-py/thrift/__init__.pyc +0 -0
  55. data/lib/proto/gen-py/thrift/protocol/TBinaryProtocol.pyc +0 -0
  56. data/lib/proto/gen-py/thrift/protocol/TProtocol.pyc +0 -0
  57. data/lib/proto/gen-py/thrift/protocol/__init__.pyc +0 -0
  58. data/lib/proto/gen-py/thrift/transport/TSocket.pyc +0 -0
  59. data/lib/proto/gen-py/thrift/transport/TTransport.pyc +0 -0
  60. data/lib/proto/gen-py/thrift/transport/__init__.pyc +0 -0
  61. data/test/lib/dependency_resolvers/chef_test.rb +92 -100
  62. data/test/lib/poolparty/base_test.rb +13 -0
  63. data/test/lib/poolparty/cloud_test.rb +50 -2
  64. data/test/lib/poolparty/monitor_test.rb +2 -2
  65. data/test/lib/poolparty/resource_test.rb +5 -0
  66. data/test/lib/poolparty/resources/line_test.rb +3 -3
  67. data/test/lib/poolparty/resources/service_test.rb +1 -1
  68. data/test/lib/poolparty/resources/variable_test.rb +33 -10
  69. data/vendor/gems/net-ssh/CHANGELOG.rdoc +127 -0
  70. data/vendor/gems/net-ssh/Manifest +104 -0
  71. data/vendor/gems/net-ssh/README.rdoc +110 -0
  72. data/vendor/gems/net-ssh/Rakefile +26 -0
  73. data/vendor/gems/net-ssh/THANKS.rdoc +16 -0
  74. data/vendor/gems/net-ssh/lib/net/ssh/authentication/agent.rb +176 -0
  75. data/vendor/gems/net-ssh/lib/net/ssh/authentication/constants.rb +18 -0
  76. data/vendor/gems/net-ssh/lib/net/ssh/authentication/key_manager.rb +193 -0
  77. data/vendor/gems/net-ssh/lib/net/ssh/authentication/methods/abstract.rb +60 -0
  78. data/vendor/gems/net-ssh/lib/net/ssh/authentication/methods/hostbased.rb +71 -0
  79. data/vendor/gems/net-ssh/lib/net/ssh/authentication/methods/keyboard_interactive.rb +66 -0
  80. data/vendor/gems/net-ssh/lib/net/ssh/authentication/methods/password.rb +39 -0
  81. data/vendor/gems/net-ssh/lib/net/ssh/authentication/methods/publickey.rb +92 -0
  82. data/vendor/gems/net-ssh/lib/net/ssh/authentication/pageant.rb +183 -0
  83. data/vendor/gems/net-ssh/lib/net/ssh/authentication/session.rb +134 -0
  84. data/vendor/gems/net-ssh/lib/net/ssh/buffer.rb +340 -0
  85. data/vendor/gems/net-ssh/lib/net/ssh/buffered_io.rb +149 -0
  86. data/vendor/gems/net-ssh/lib/net/ssh/config.rb +181 -0
  87. data/vendor/gems/net-ssh/lib/net/ssh/connection/channel.rb +625 -0
  88. data/vendor/gems/net-ssh/lib/net/ssh/connection/constants.rb +33 -0
  89. data/vendor/gems/net-ssh/lib/net/ssh/connection/session.rb +596 -0
  90. data/vendor/gems/net-ssh/lib/net/ssh/connection/term.rb +178 -0
  91. data/vendor/gems/net-ssh/lib/net/ssh/errors.rb +85 -0
  92. data/vendor/gems/net-ssh/lib/net/ssh/key_factory.rb +102 -0
  93. data/vendor/gems/net-ssh/lib/net/ssh/known_hosts.rb +129 -0
  94. data/vendor/gems/net-ssh/lib/net/ssh/loggable.rb +61 -0
  95. data/vendor/gems/net-ssh/lib/net/ssh/packet.rb +102 -0
  96. data/vendor/gems/net-ssh/lib/net/ssh/prompt.rb +93 -0
  97. data/vendor/gems/net-ssh/lib/net/ssh/proxy/errors.rb +14 -0
  98. data/vendor/gems/net-ssh/lib/net/ssh/proxy/http.rb +94 -0
  99. data/vendor/gems/net-ssh/lib/net/ssh/proxy/socks4.rb +70 -0
  100. data/vendor/gems/net-ssh/lib/net/ssh/proxy/socks5.rb +129 -0
  101. data/vendor/gems/net-ssh/lib/net/ssh/ruby_compat.rb +7 -0
  102. data/vendor/gems/net-ssh/lib/net/ssh/service/forward.rb +267 -0
  103. data/vendor/gems/net-ssh/lib/net/ssh/test/channel.rb +129 -0
  104. data/vendor/gems/net-ssh/lib/net/ssh/test/extensions.rb +152 -0
  105. data/vendor/gems/net-ssh/lib/net/ssh/test/kex.rb +44 -0
  106. data/vendor/gems/net-ssh/lib/net/ssh/test/local_packet.rb +51 -0
  107. data/vendor/gems/net-ssh/lib/net/ssh/test/packet.rb +81 -0
  108. data/vendor/gems/net-ssh/lib/net/ssh/test/remote_packet.rb +38 -0
  109. data/vendor/gems/net-ssh/lib/net/ssh/test/script.rb +157 -0
  110. data/vendor/gems/net-ssh/lib/net/ssh/test/socket.rb +59 -0
  111. data/vendor/gems/net-ssh/lib/net/ssh/test.rb +89 -0
  112. data/vendor/gems/net-ssh/lib/net/ssh/transport/algorithms.rb +384 -0
  113. data/vendor/gems/net-ssh/lib/net/ssh/transport/cipher_factory.rb +80 -0
  114. data/vendor/gems/net-ssh/lib/net/ssh/transport/constants.rb +30 -0
  115. data/vendor/gems/net-ssh/lib/net/ssh/transport/hmac/abstract.rb +78 -0
  116. data/vendor/gems/net-ssh/lib/net/ssh/transport/hmac/md5.rb +12 -0
  117. data/vendor/gems/net-ssh/lib/net/ssh/transport/hmac/md5_96.rb +11 -0
  118. data/vendor/gems/net-ssh/lib/net/ssh/transport/hmac/none.rb +15 -0
  119. data/vendor/gems/net-ssh/lib/net/ssh/transport/hmac/sha1.rb +13 -0
  120. data/vendor/gems/net-ssh/lib/net/ssh/transport/hmac/sha1_96.rb +11 -0
  121. data/vendor/gems/net-ssh/lib/net/ssh/transport/hmac.rb +31 -0
  122. data/vendor/gems/net-ssh/lib/net/ssh/transport/identity_cipher.rb +55 -0
  123. data/vendor/gems/net-ssh/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +208 -0
  124. data/vendor/gems/net-ssh/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +77 -0
  125. data/vendor/gems/net-ssh/lib/net/ssh/transport/kex.rb +13 -0
  126. data/vendor/gems/net-ssh/lib/net/ssh/transport/openssl.rb +128 -0
  127. data/vendor/gems/net-ssh/lib/net/ssh/transport/packet_stream.rb +230 -0
  128. data/vendor/gems/net-ssh/lib/net/ssh/transport/server_version.rb +60 -0
  129. data/vendor/gems/net-ssh/lib/net/ssh/transport/session.rb +276 -0
  130. data/vendor/gems/net-ssh/lib/net/ssh/transport/state.rb +201 -0
  131. data/vendor/gems/net-ssh/lib/net/ssh/verifiers/lenient.rb +30 -0
  132. data/vendor/gems/net-ssh/lib/net/ssh/verifiers/null.rb +12 -0
  133. data/vendor/gems/net-ssh/lib/net/ssh/verifiers/strict.rb +53 -0
  134. data/vendor/gems/net-ssh/lib/net/ssh/version.rb +62 -0
  135. data/vendor/gems/net-ssh/lib/net/ssh.rb +215 -0
  136. data/vendor/gems/net-ssh/net-ssh.gemspec +33 -0
  137. data/vendor/gems/net-ssh/setup.rb +1585 -0
  138. data/vendor/gems/net-ssh/test/authentication/methods/common.rb +28 -0
  139. data/vendor/gems/net-ssh/test/authentication/methods/test_abstract.rb +51 -0
  140. data/vendor/gems/net-ssh/test/authentication/methods/test_hostbased.rb +114 -0
  141. data/vendor/gems/net-ssh/test/authentication/methods/test_keyboard_interactive.rb +98 -0
  142. data/vendor/gems/net-ssh/test/authentication/methods/test_password.rb +50 -0
  143. data/vendor/gems/net-ssh/test/authentication/methods/test_publickey.rb +127 -0
  144. data/vendor/gems/net-ssh/test/authentication/test_agent.rb +205 -0
  145. data/vendor/gems/net-ssh/test/authentication/test_key_manager.rb +105 -0
  146. data/vendor/gems/net-ssh/test/authentication/test_session.rb +93 -0
  147. data/vendor/gems/net-ssh/test/common.rb +106 -0
  148. data/vendor/gems/net-ssh/test/configs/eqsign +3 -0
  149. data/vendor/gems/net-ssh/test/configs/exact_match +8 -0
  150. data/vendor/gems/net-ssh/test/configs/wild_cards +14 -0
  151. data/vendor/gems/net-ssh/test/connection/test_channel.rb +452 -0
  152. data/vendor/gems/net-ssh/test/connection/test_session.rb +488 -0
  153. data/vendor/gems/net-ssh/test/test_all.rb +6 -0
  154. data/vendor/gems/net-ssh/test/test_buffer.rb +336 -0
  155. data/vendor/gems/net-ssh/test/test_buffered_io.rb +63 -0
  156. data/vendor/gems/net-ssh/test/test_config.rb +84 -0
  157. data/vendor/gems/net-ssh/test/test_key_factory.rb +67 -0
  158. data/vendor/gems/net-ssh/test/transport/hmac/test_md5.rb +39 -0
  159. data/vendor/gems/net-ssh/test/transport/hmac/test_md5_96.rb +25 -0
  160. data/vendor/gems/net-ssh/test/transport/hmac/test_none.rb +34 -0
  161. data/vendor/gems/net-ssh/test/transport/hmac/test_sha1.rb +34 -0
  162. data/vendor/gems/net-ssh/test/transport/hmac/test_sha1_96.rb +25 -0
  163. data/vendor/gems/net-ssh/test/transport/kex/test_diffie_hellman_group1_sha1.rb +146 -0
  164. data/vendor/gems/net-ssh/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +92 -0
  165. data/vendor/gems/net-ssh/test/transport/test_algorithms.rb +302 -0
  166. data/vendor/gems/net-ssh/test/transport/test_cipher_factory.rb +171 -0
  167. data/vendor/gems/net-ssh/test/transport/test_hmac.rb +34 -0
  168. data/vendor/gems/net-ssh/test/transport/test_identity_cipher.rb +40 -0
  169. data/vendor/gems/net-ssh/test/transport/test_packet_stream.rb +435 -0
  170. data/vendor/gems/net-ssh/test/transport/test_server_version.rb +57 -0
  171. data/vendor/gems/net-ssh/test/transport/test_session.rb +315 -0
  172. data/vendor/gems/net-ssh/test/transport/test_state.rb +173 -0
  173. metadata +116 -4
  174. data/bin/install-poolparty +0 -20
@@ -0,0 +1,340 @@
1
+ require 'net/ssh/ruby_compat'
2
+ require 'net/ssh/transport/openssl'
3
+
4
+ module Net; module SSH
5
+
6
+ # Net::SSH::Buffer is a flexible class for building and parsing binary
7
+ # data packets. It provides a stream-like interface for sequentially
8
+ # reading data items from the buffer, as well as a useful helper method
9
+ # for building binary packets given a signature.
10
+ #
11
+ # Writing to a buffer always appends to the end, regardless of where the
12
+ # read cursor is. Reading, on the other hand, always begins at the first
13
+ # byte of the buffer and increments the read cursor, with subsequent reads
14
+ # taking up where the last left off.
15
+ #
16
+ # As a consumer of the Net::SSH library, you will rarely come into contact
17
+ # with these buffer objects directly, but it could happen. Also, if you
18
+ # are ever implementing a protocol on top of SSH (e.g. SFTP), this buffer
19
+ # class can be quite handy.
20
+ class Buffer
21
+ # This is a convenience method for creating and populating a new buffer
22
+ # from a single command. The arguments must be even in length, with the
23
+ # first of each pair of arguments being a symbol naming the type of the
24
+ # data that follows. If the type is :raw, the value is written directly
25
+ # to the hash.
26
+ #
27
+ # b = Buffer.from(:byte, 1, :string, "hello", :raw, "\1\2\3\4")
28
+ # #-> "\1\0\0\0\5hello\1\2\3\4"
29
+ #
30
+ # The supported data types are:
31
+ #
32
+ # * :raw => write the next value verbatim (#write)
33
+ # * :int64 => write an 8-byte integer (#write_int64)
34
+ # * :long => write a 4-byte integer (#write_long)
35
+ # * :byte => write a single byte (#write_byte)
36
+ # * :string => write a 4-byte length followed by character data (#write_string)
37
+ # * :bool => write a single byte, interpreted as a boolean (#write_bool)
38
+ # * :bignum => write an SSH-encoded bignum (#write_bignum)
39
+ # * :key => write an SSH-encoded key value (#write_key)
40
+ #
41
+ # Any of these, except for :raw, accepts an Array argument, to make it
42
+ # easier to write multiple values of the same type in a briefer manner.
43
+ def self.from(*args)
44
+ raise ArgumentError, "odd number of arguments given" unless args.length % 2 == 0
45
+
46
+ buffer = new
47
+ 0.step(args.length-1, 2) do |index|
48
+ type = args[index]
49
+ value = args[index+1]
50
+ if type == :raw
51
+ buffer.append(value.to_s)
52
+ elsif Array === value
53
+ buffer.send("write_#{type}", *value)
54
+ else
55
+ buffer.send("write_#{type}", value)
56
+ end
57
+ end
58
+
59
+ buffer
60
+ end
61
+
62
+ # exposes the raw content of the buffer
63
+ attr_reader :content
64
+
65
+ # the current position of the pointer in the buffer
66
+ attr_accessor :position
67
+
68
+ # Creates a new buffer, initialized to the given content. The position
69
+ # is initialized to the beginning of the buffer.
70
+ def initialize(content="")
71
+ @content = content.to_s
72
+ @position = 0
73
+ end
74
+
75
+ # Returns the length of the buffer's content.
76
+ def length
77
+ @content.length
78
+ end
79
+
80
+ # Returns the number of bytes available to be read (e.g., how many bytes
81
+ # remain between the current position and the end of the buffer).
82
+ def available
83
+ length - position
84
+ end
85
+
86
+ # Returns a copy of the buffer's content.
87
+ def to_s
88
+ (@content || "").dup
89
+ end
90
+
91
+ # Compares the contents of the two buffers, returning +true+ only if they
92
+ # are identical in size and content.
93
+ def ==(buffer)
94
+ to_s == buffer.to_s
95
+ end
96
+
97
+ # Returns +true+ if the buffer contains no data (e.g., it is of zero length).
98
+ def empty?
99
+ @content.empty?
100
+ end
101
+
102
+ # Resets the pointer to the start of the buffer. Subsequent reads will
103
+ # begin at position 0.
104
+ def reset!
105
+ @position = 0
106
+ end
107
+
108
+ # Returns true if the pointer is at the end of the buffer. Subsequent
109
+ # reads will return nil, in this case.
110
+ def eof?
111
+ @position >= length
112
+ end
113
+
114
+ # Resets the buffer, making it empty. Also, resets the read position to
115
+ # 0.
116
+ def clear!
117
+ @content = ""
118
+ @position = 0
119
+ end
120
+
121
+ # Consumes n bytes from the buffer, where n is the current position
122
+ # unless otherwise specified. This is useful for removing data from the
123
+ # buffer that has previously been read, when you are expecting more data
124
+ # to be appended. It helps to keep the size of buffers down when they
125
+ # would otherwise tend to grow without bound.
126
+ #
127
+ # Returns the buffer object itself.
128
+ def consume!(n=position)
129
+ if n >= length
130
+ # optimize for a fairly common case
131
+ clear!
132
+ elsif n > 0
133
+ @content = @content[n..-1] || ""
134
+ @position -= n
135
+ @position = 0 if @position < 0
136
+ end
137
+ self
138
+ end
139
+
140
+ # Appends the given text to the end of the buffer. Does not alter the
141
+ # read position. Returns the buffer object itself.
142
+ def append(text)
143
+ @content << text
144
+ self
145
+ end
146
+
147
+ # Returns all text from the current pointer to the end of the buffer as
148
+ # a new Net::SSH::Buffer object.
149
+ def remainder_as_buffer
150
+ Buffer.new(@content[@position..-1])
151
+ end
152
+
153
+ # Reads all data up to and including the given pattern, which may be a
154
+ # String, Fixnum, or Regexp and is interpreted exactly as String#index
155
+ # does. Returns nil if nothing matches. Increments the position to point
156
+ # immediately after the pattern, if it does match. Returns all data up to
157
+ # and including the text that matched the pattern.
158
+ def read_to(pattern)
159
+ index = @content.index(pattern, @position) or return nil
160
+ length = case pattern
161
+ when String then pattern.length
162
+ when Fixnum then 1
163
+ when Regexp then $&.length
164
+ end
165
+ index && read(index+length)
166
+ end
167
+
168
+ # Reads and returns the next +count+ bytes from the buffer, starting from
169
+ # the read position. If +count+ is +nil+, this will return all remaining
170
+ # text in the buffer. This method will increment the pointer.
171
+ def read(count=nil)
172
+ count ||= length
173
+ count = length - @position if @position + count > length
174
+ @position += count
175
+ @content[@position-count, count]
176
+ end
177
+
178
+ # Reads (as #read) and returns the given number of bytes from the buffer,
179
+ # and then consumes (as #consume!) all data up to the new read position.
180
+ def read!(count=nil)
181
+ data = read(count)
182
+ consume!
183
+ data
184
+ end
185
+
186
+ # Return the next 8 bytes as a 64-bit integer (in network byte order).
187
+ # Returns nil if there are less than 8 bytes remaining to be read in the
188
+ # buffer.
189
+ def read_int64
190
+ hi = read_long or return nil
191
+ lo = read_long or return nil
192
+ return (hi << 32) + lo
193
+ end
194
+
195
+ # Return the next four bytes as a long integer (in network byte order).
196
+ # Returns nil if there are less than 4 bytes remaining to be read in the
197
+ # buffer.
198
+ def read_long
199
+ b = read(4) or return nil
200
+ b.unpack("N").first
201
+ end
202
+
203
+ # Read and return the next byte in the buffer. Returns nil if called at
204
+ # the end of the buffer.
205
+ def read_byte
206
+ b = read(1) or return nil
207
+ b.getbyte(0)
208
+ end
209
+
210
+ # Read and return an SSH2-encoded string. The string starts with a long
211
+ # integer that describes the number of bytes remaining in the string.
212
+ # Returns nil if there are not enough bytes to satisfy the request.
213
+ def read_string
214
+ length = read_long or return nil
215
+ read(length)
216
+ end
217
+
218
+ # Read a single byte and convert it into a boolean, using 'C' rules
219
+ # (i.e., zero is false, non-zero is true).
220
+ def read_bool
221
+ b = read_byte or return nil
222
+ b != 0
223
+ end
224
+
225
+ # Read a bignum (OpenSSL::BN) from the buffer, in SSH2 format. It is
226
+ # essentially just a string, which is reinterpreted to be a bignum in
227
+ # binary format.
228
+ def read_bignum
229
+ data = read_string
230
+ return unless data
231
+ OpenSSL::BN.new(data, 2)
232
+ end
233
+
234
+ # Read a key from the buffer. The key will start with a string
235
+ # describing its type. The remainder of the key is defined by the
236
+ # type that was read.
237
+ def read_key
238
+ type = read_string
239
+ return (type ? read_keyblob(type) : nil)
240
+ end
241
+
242
+ # Read a keyblob of the given type from the buffer, and return it as
243
+ # a key. Only RSA and DSA keys are supported.
244
+ def read_keyblob(type)
245
+ case type
246
+ when "ssh-dss"
247
+ key = OpenSSL::PKey::DSA.new
248
+ key.p = read_bignum
249
+ key.q = read_bignum
250
+ key.g = read_bignum
251
+ key.pub_key = read_bignum
252
+
253
+ when "ssh-rsa"
254
+ key = OpenSSL::PKey::RSA.new
255
+ key.e = read_bignum
256
+ key.n = read_bignum
257
+
258
+ else
259
+ raise NotImplementedError, "unsupported key type `#{type}'"
260
+ end
261
+
262
+ return key
263
+ end
264
+
265
+ # Reads the next string from the buffer, and returns a new Buffer
266
+ # object that wraps it.
267
+ def read_buffer
268
+ Buffer.new(read_string)
269
+ end
270
+
271
+ # Writes the given data literally into the string. Does not alter the
272
+ # read position. Returns the buffer object.
273
+ def write(*data)
274
+ data.each { |datum| @content << datum }
275
+ self
276
+ end
277
+
278
+ # Writes each argument to the buffer as a network-byte-order-encoded
279
+ # 64-bit integer (8 bytes). Does not alter the read position. Returns the
280
+ # buffer object.
281
+ def write_int64(*n)
282
+ n.each do |i|
283
+ hi = (i >> 32) & 0xFFFFFFFF
284
+ lo = i & 0xFFFFFFFF
285
+ @content << [hi, lo].pack("N2")
286
+ end
287
+ self
288
+ end
289
+
290
+ # Writes each argument to the buffer as a network-byte-order-encoded
291
+ # long (4-byte) integer. Does not alter the read position. Returns the
292
+ # buffer object.
293
+ def write_long(*n)
294
+ @content << n.pack("N*")
295
+ self
296
+ end
297
+
298
+ # Writes each argument to the buffer as a byte. Does not alter the read
299
+ # position. Returns the buffer object.
300
+ def write_byte(*n)
301
+ n.each { |b| @content << b.chr }
302
+ self
303
+ end
304
+
305
+ # Writes each argument to the buffer as an SSH2-encoded string. Each
306
+ # string is prefixed by its length, encoded as a 4-byte long integer.
307
+ # Does not alter the read position. Returns the buffer object.
308
+ def write_string(*text)
309
+ text.each do |string|
310
+ s = string.to_s
311
+ write_long(s.length)
312
+ write(s)
313
+ end
314
+ self
315
+ end
316
+
317
+ # Writes each argument to the buffer as a (C-style) boolean, with 1
318
+ # meaning true, and 0 meaning false. Does not alter the read position.
319
+ # Returns the buffer object.
320
+ def write_bool(*b)
321
+ b.each { |v| @content << (v ? "\1" : "\0") }
322
+ self
323
+ end
324
+
325
+ # Writes each argument to the buffer as a bignum (SSH2-style). No
326
+ # checking is done to ensure that the arguments are, in fact, bignums.
327
+ # Does not alter the read position. Returns the buffer object.
328
+ def write_bignum(*n)
329
+ @content << n.map { |b| b.to_ssh }.join
330
+ self
331
+ end
332
+
333
+ # Writes the given arguments to the buffer as SSH2-encoded keys. Does not
334
+ # alter the read position. Returns the buffer object.
335
+ def write_key(*key)
336
+ key.each { |k| append(k.to_blob) }
337
+ self
338
+ end
339
+ end
340
+ end; end;
@@ -0,0 +1,149 @@
1
+ require 'net/ssh/buffer'
2
+ require 'net/ssh/loggable'
3
+
4
+ module Net; module SSH
5
+
6
+ # This module is used to extend sockets and other IO objects, to allow
7
+ # them to be buffered for both read and write. This abstraction makes it
8
+ # quite easy to write a select-based event loop
9
+ # (see Net::SSH::Connection::Session#listen_to).
10
+ #
11
+ # The general idea is that instead of calling #read directly on an IO that
12
+ # has been extended with this module, you call #fill (to add pending input
13
+ # to the internal read buffer), and then #read_available (to read from that
14
+ # buffer). Likewise, you don't call #write directly, you call #enqueue to
15
+ # add data to the write buffer, and then #send_pending or #wait_for_pending_sends
16
+ # to actually send the data across the wire.
17
+ #
18
+ # In this way you can easily use the object as an argument to IO.select,
19
+ # calling #fill when it is available for read, or #send_pending when it is
20
+ # available for write, and then call #enqueue and #read_available during
21
+ # the idle times.
22
+ #
23
+ # socket = TCPSocket.new(address, port)
24
+ # socket.extend(Net::SSH::BufferedIo)
25
+ #
26
+ # ssh.listen_to(socket)
27
+ #
28
+ # ssh.loop do
29
+ # if socket.available > 0
30
+ # puts socket.read_available
31
+ # socket.enqueue("response\n")
32
+ # end
33
+ # end
34
+ #
35
+ # Note that this module must be used to extend an instance, and should not
36
+ # be included in a class. If you do want to use it via an include, then you
37
+ # must make sure to invoke the private #initialize_buffered_io method in
38
+ # your class' #initialize method:
39
+ #
40
+ # class Foo < IO
41
+ # include Net::SSH::BufferedIo
42
+ #
43
+ # def initialize
44
+ # initialize_buffered_io
45
+ # # ...
46
+ # end
47
+ # end
48
+ module BufferedIo
49
+ include Loggable
50
+
51
+ # Called when the #extend is called on an object, with this module as the
52
+ # argument. It ensures that the modules instance variables are all properly
53
+ # initialized.
54
+ def self.extended(object) #:nodoc:
55
+ # need to use __send__ because #send is overridden in Socket
56
+ object.__send__(:initialize_buffered_io)
57
+ end
58
+
59
+ # Tries to read up to +n+ bytes of data from the remote end, and appends
60
+ # the data to the input buffer. It returns the number of bytes read, or 0
61
+ # if no data was available to be read.
62
+ def fill(n=8192)
63
+ input.consume!
64
+ data = recv(n)
65
+ debug { "read #{data.length} bytes" }
66
+ input.append(data)
67
+ return data.length
68
+ end
69
+
70
+ # Read up to +length+ bytes from the input buffer. If +length+ is nil,
71
+ # all available data is read from the buffer. (See #available.)
72
+ def read_available(length=nil)
73
+ input.read(length || available)
74
+ end
75
+
76
+ # Returns the number of bytes available to be read from the input buffer.
77
+ # (See #read_available.)
78
+ def available
79
+ input.available
80
+ end
81
+
82
+ # Enqueues data in the output buffer, to be written when #send_pending
83
+ # is called. Note that the data is _not_ sent immediately by this method!
84
+ def enqueue(data)
85
+ output.append(data)
86
+ end
87
+
88
+ # Returns +true+ if there is data waiting in the output buffer, and
89
+ # +false+ otherwise.
90
+ def pending_write?
91
+ output.length > 0
92
+ end
93
+
94
+ # Sends as much of the pending output as possible. Returns +true+ if any
95
+ # data was sent, and +false+ otherwise.
96
+ def send_pending
97
+ if output.length > 0
98
+ sent = send(output.to_s, 0)
99
+ debug { "sent #{sent} bytes" }
100
+ output.consume!(sent)
101
+ return sent > 0
102
+ else
103
+ return false
104
+ end
105
+ end
106
+
107
+ # Calls #send_pending repeatedly, if necessary, blocking until the output
108
+ # buffer is empty.
109
+ def wait_for_pending_sends
110
+ send_pending
111
+ while output.length > 0
112
+ result = IO.select(nil, [self]) or next
113
+ next unless result[1].any?
114
+ send_pending
115
+ end
116
+ end
117
+
118
+ public # these methods are primarily for use in tests
119
+
120
+ def write_buffer #:nodoc:
121
+ output.to_s
122
+ end
123
+
124
+ def read_buffer #:nodoc:
125
+ input.to_s
126
+ end
127
+
128
+ private
129
+
130
+ #--
131
+ # Can't use attr_reader here (after +private+) without incurring the
132
+ # wrath of "ruby -w". We hates it.
133
+ #++
134
+
135
+ def input; @input; end
136
+ def output; @output; end
137
+
138
+ # Initializes the intput and output buffers for this object. This method
139
+ # is called automatically when the module is mixed into an object via
140
+ # Object#extend (see Net::SSH::BufferedIo.extended), but must be called
141
+ # explicitly in the +initialize+ method of any class that uses
142
+ # Module#include to add this module.
143
+ def initialize_buffered_io
144
+ @input = Net::SSH::Buffer.new
145
+ @output = Net::SSH::Buffer.new
146
+ end
147
+ end
148
+
149
+ end; end
@@ -0,0 +1,181 @@
1
+ module Net; module SSH
2
+
3
+ # The Net::SSH::Config class is used to parse OpenSSH configuration files,
4
+ # and translates that syntax into the configuration syntax that Net::SSH
5
+ # understands. This lets Net::SSH scripts read their configuration (to
6
+ # some extent) from OpenSSH configuration files (~/.ssh/config, /etc/ssh_config,
7
+ # and so forth).
8
+ #
9
+ # Only a subset of OpenSSH configuration options are understood:
10
+ #
11
+ # * Ciphers => maps to the :encryption option
12
+ # * Compression => :compression
13
+ # * CompressionLevel => :compression_level
14
+ # * ConnectTimeout => maps to the :timeout option
15
+ # * ForwardAgent => :forward_agent
16
+ # * GlobalKnownHostsFile => :global_known_hosts_file
17
+ # * HostBasedAuthentication => maps to the :auth_methods option
18
+ # * HostKeyAlgorithms => maps to :host_key option
19
+ # * HostKeyAlias => :host_key_alias
20
+ # * HostName => :host_name
21
+ # * IdentityFile => maps to the :keys option
22
+ # * Macs => maps to the :hmac option
23
+ # * PasswordAuthentication => maps to the :auth_methods option
24
+ # * Port => :port
25
+ # * PreferredAuthentications => maps to the :auth_methods option
26
+ # * RekeyLimit => :rekey_limit
27
+ # * User => :user
28
+ # * UserKnownHostsFile => :user_known_hosts_file
29
+ #
30
+ # Note that you will never need to use this class directly--you can control
31
+ # whether the OpenSSH configuration files are read by passing the :config
32
+ # option to Net::SSH.start. (They are, by default.)
33
+ class Config
34
+ class <<self
35
+ @@default_files = %w(~/.ssh/config /etc/ssh_config /etc/ssh/ssh_config)
36
+
37
+ # Returns an array of locations of OpenSSH configuration files
38
+ # to parse by default.
39
+ def default_files
40
+ @@default_files
41
+ end
42
+
43
+ # Loads the configuration data for the given +host+ from all of the
44
+ # given +files+ (defaulting to the list of files returned by
45
+ # #default_files), translates the resulting hash into the options
46
+ # recognized by Net::SSH, and returns them.
47
+ def for(host, files=default_files)
48
+ translate(files.inject({}) { |settings, file| load(file, host, settings) })
49
+ end
50
+
51
+ # Load the OpenSSH configuration settings in the given +file+ for the
52
+ # given +host+. If +settings+ is given, the options are merged into
53
+ # that hash, with existing values taking precedence over newly parsed
54
+ # ones. Returns a hash containing the OpenSSH options. (See
55
+ # #translate for how to convert the OpenSSH options into Net::SSH
56
+ # options.)
57
+ def load(file, host, settings={})
58
+ file = File.expand_path(file)
59
+ return settings unless File.readable?(file)
60
+
61
+ in_match = false
62
+ IO.foreach(file) do |line|
63
+ next if line =~ /^\s*(?:#.*)?$/
64
+
65
+ if line =~ /^\s*(\S+)\s*=(.*)$/
66
+ key, value = $1, $2
67
+ else
68
+ key, value = line.strip.split(/\s+/, 2)
69
+ end
70
+
71
+ # silently ignore malformed entries
72
+ next if value.nil?
73
+
74
+ key.downcase!
75
+ value = $1 if value =~ /^"(.*)"$/
76
+
77
+ value = case value.strip
78
+ when /^\d+$/ then value.to_i
79
+ when /^no$/i then false
80
+ when /^yes$/i then true
81
+ else value
82
+ end
83
+
84
+ if key == 'host'
85
+ in_match = (host =~ pattern2regex(value))
86
+ elsif in_match
87
+ if key == 'identityfile'
88
+ settings[key] ||= []
89
+ settings[key] << value
90
+ else
91
+ settings[key] = value unless settings.key?(key)
92
+ end
93
+ end
94
+ end
95
+
96
+ return settings
97
+ end
98
+
99
+ # Given a hash of OpenSSH configuration options, converts them into
100
+ # a hash of Net::SSH options. Unrecognized options are ignored. The
101
+ # +settings+ hash must have Strings for keys, all downcased, and
102
+ # the returned hash will have Symbols for keys.
103
+ def translate(settings)
104
+ settings.inject({}) do |hash, (key, value)|
105
+ case key
106
+ when 'ciphers' then
107
+ hash[:encryption] = value.split(/,/)
108
+ when 'compression' then
109
+ hash[:compression] = value
110
+ when 'compressionlevel' then
111
+ hash[:compression_level] = value
112
+ when 'connecttimeout' then
113
+ hash[:timeout] = value
114
+ when 'forwardagent' then
115
+ hash[:forward_agent] = value
116
+ when 'globalknownhostsfile'
117
+ hash[:global_known_hosts_file] = value
118
+ when 'hostbasedauthentication' then
119
+ if value
120
+ hash[:auth_methods] ||= []
121
+ hash[:auth_methods] << "hostbased"
122
+ end
123
+ when 'hostkeyalgorithms' then
124
+ hash[:host_key] = value.split(/,/)
125
+ when 'hostkeyalias' then
126
+ hash[:host_key_alias] = value
127
+ when 'hostname' then
128
+ hash[:host_name] = value
129
+ when 'identityfile' then
130
+ hash[:keys] = value
131
+ when 'macs' then
132
+ hash[:hmac] = value.split(/,/)
133
+ when 'passwordauthentication'
134
+ if value
135
+ hash[:auth_methods] ||= []
136
+ hash[:auth_methods] << "password"
137
+ end
138
+ when 'port'
139
+ hash[:port] = value
140
+ when 'preferredauthentications'
141
+ hash[:auth_methods] = value.split(/,/)
142
+ when 'pubkeyauthentication'
143
+ if value
144
+ hash[:auth_methods] ||= []
145
+ hash[:auth_methods] << "publickey"
146
+ end
147
+ when 'rekeylimit'
148
+ hash[:rekey_limit] = interpret_size(value)
149
+ when 'user'
150
+ hash[:user] = value
151
+ when 'userknownhostsfile'
152
+ hash[:user_known_hosts_file] = value
153
+ end
154
+ hash
155
+ end
156
+ end
157
+
158
+ private
159
+
160
+ # Converts an ssh_config pattern into a regex for matching against
161
+ # host names.
162
+ def pattern2regex(pattern)
163
+ pattern = "^" + pattern.to_s.gsub(/\./, "\\.").
164
+ gsub(/\?/, '.').
165
+ gsub(/\*/, '.*') + "$"
166
+ Regexp.new(pattern, true)
167
+ end
168
+
169
+ # Converts the given size into an integer number of bytes.
170
+ def interpret_size(size)
171
+ case size
172
+ when /k$/i then size.to_i * 1024
173
+ when /m$/i then size.to_i * 1024 * 1024
174
+ when /g$/i then size.to_i * 1024 * 1024 * 1024
175
+ else size.to_i
176
+ end
177
+ end
178
+ end
179
+ end
180
+
181
+ end; end