sequel-impala 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +45 -0
  3. data/lib/impala.rb +14 -6
  4. data/lib/impala/connection.rb +46 -23
  5. data/lib/impala/cursor.rb +48 -4
  6. data/lib/impala/progress_reporter.rb +40 -0
  7. data/lib/impala/protocol/beeswax_constants.rb +1 -1
  8. data/lib/impala/protocol/beeswax_service.rb +1 -20
  9. data/lib/impala/protocol/beeswax_types.rb +1 -1
  10. data/lib/impala/protocol/exec_stats_constants.rb +13 -0
  11. data/lib/impala/protocol/exec_stats_types.rb +133 -0
  12. data/lib/impala/protocol/facebook_service.rb +3 -3
  13. data/lib/impala/protocol/fb303_constants.rb +1 -1
  14. data/lib/impala/protocol/fb303_types.rb +1 -1
  15. data/lib/impala/protocol/hive_metastore_constants.rb +1 -1
  16. data/lib/impala/protocol/hive_metastore_types.rb +1 -1
  17. data/lib/impala/protocol/impala_hive_server2_service.rb +111 -3
  18. data/lib/impala/protocol/impala_service.rb +67 -1
  19. data/lib/impala/protocol/impala_service_constants.rb +1 -1
  20. data/lib/impala/protocol/impala_service_types.rb +109 -7
  21. data/lib/impala/protocol/status_constants.rb +1 -1
  22. data/lib/impala/protocol/status_types.rb +1 -1
  23. data/lib/impala/protocol/t_c_l_i_service.rb +884 -724
  24. data/lib/impala/protocol/t_c_l_i_service_constants.rb +72 -0
  25. data/lib/impala/protocol/t_c_l_i_service_types.rb +1799 -0
  26. data/lib/impala/protocol/thrift_hive_metastore.rb +1 -1
  27. data/lib/impala/protocol/types_constants.rb +13 -0
  28. data/lib/impala/protocol/types_types.rb +332 -0
  29. data/lib/impala/sasl_transport.rb +117 -0
  30. data/lib/impala/thrift_patch.rb +42 -0
  31. data/lib/rbhive/connection.rb +25 -25
  32. data/lib/rbhive/explain_result.rb +9 -9
  33. data/lib/rbhive/schema_definition.rb +12 -12
  34. data/lib/rbhive/t_c_l_i_connection.rb +28 -26
  35. data/lib/rbhive/t_c_l_i_schema_definition.rb +1 -1
  36. data/lib/rbhive/table_schema.rb +1 -1
  37. data/lib/sequel/adapters/impala.rb +63 -6
  38. data/lib/sequel/adapters/jdbc/hive2.rb +1 -1
  39. data/lib/sequel/adapters/rbhive.rb +3 -2
  40. data/lib/sequel/adapters/shared/impala.rb +133 -25
  41. data/lib/thrift/sasl_client_transport.rb +2 -2
  42. data/lib/thrift/thrift_hive.rb +2 -2
  43. data/lib/thrift/thrift_hive_metastore.rb +2 -2
  44. data/spec/dataset_test.rb +85 -85
  45. data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +1 -1
  46. data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +1 -1
  47. data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +1 -1
  48. data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +1 -1
  49. data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +1 -1
  50. data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +1 -1
  51. data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +1 -1
  52. data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +1 -1
  53. data/spec/files/integer_migrations/001_create_sessions.rb +1 -1
  54. data/spec/files/integer_migrations/002_create_nodes.rb +1 -1
  55. data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +1 -1
  56. data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +1 -1
  57. data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +1 -1
  58. data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +1 -1
  59. data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +1 -1
  60. data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +1 -1
  61. data/spec/migrator_test.rb +2 -2
  62. data/spec/prepared_statement_test.rb +12 -12
  63. data/spec/schema_test.rb +6 -6
  64. data/spec/type_test.rb +8 -8
  65. metadata +30 -11
  66. data/CHANGELOG +0 -19
  67. data/lib/impala/protocol/cli_service_constants.rb +0 -60
  68. data/lib/impala/protocol/cli_service_types.rb +0 -1452
@@ -1,5 +1,5 @@
1
1
  #
2
- # Autogenerated by Thrift Compiler (0.9.1)
2
+ # Autogenerated by Thrift Compiler (0.9.3)
3
3
  #
4
4
  # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
5
  #
@@ -0,0 +1,13 @@
1
+ #
2
+ # Autogenerated by Thrift Compiler (0.9.3)
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+ require 'thrift'
8
+ require 'types_types'
9
+
10
+ module Impala
11
+ module Protocol
12
+ end
13
+ end
@@ -0,0 +1,332 @@
1
+ #
2
+ # Autogenerated by Thrift Compiler (0.9.3)
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+ require 'thrift'
8
+
9
+ module Impala
10
+ module Protocol
11
+ module TPrimitiveType
12
+ INVALID_TYPE = 0
13
+ NULL_TYPE = 1
14
+ BOOLEAN = 2
15
+ TINYINT = 3
16
+ SMALLINT = 4
17
+ INT = 5
18
+ BIGINT = 6
19
+ FLOAT = 7
20
+ DOUBLE = 8
21
+ DATE = 9
22
+ DATETIME = 10
23
+ TIMESTAMP = 11
24
+ STRING = 12
25
+ BINARY = 13
26
+ DECIMAL = 14
27
+ CHAR = 15
28
+ VARCHAR = 16
29
+ VALUE_MAP = {0 => "INVALID_TYPE", 1 => "NULL_TYPE", 2 => "BOOLEAN", 3 => "TINYINT", 4 => "SMALLINT", 5 => "INT", 6 => "BIGINT", 7 => "FLOAT", 8 => "DOUBLE", 9 => "DATE", 10 => "DATETIME", 11 => "TIMESTAMP", 12 => "STRING", 13 => "BINARY", 14 => "DECIMAL", 15 => "CHAR", 16 => "VARCHAR"}
30
+ VALID_VALUES = Set.new([INVALID_TYPE, NULL_TYPE, BOOLEAN, TINYINT, SMALLINT, INT, BIGINT, FLOAT, DOUBLE, DATE, DATETIME, TIMESTAMP, STRING, BINARY, DECIMAL, CHAR, VARCHAR]).freeze
31
+ end
32
+
33
+ module TTypeNodeType
34
+ SCALAR = 0
35
+ ARRAY = 1
36
+ MAP = 2
37
+ STRUCT = 3
38
+ VALUE_MAP = {0 => "SCALAR", 1 => "ARRAY", 2 => "MAP", 3 => "STRUCT"}
39
+ VALID_VALUES = Set.new([SCALAR, ARRAY, MAP, STRUCT]).freeze
40
+ end
41
+
42
+ module TStmtType
43
+ QUERY = 0
44
+ DDL = 1
45
+ DML = 2
46
+ EXPLAIN = 3
47
+ LOAD = 4
48
+ SET = 5
49
+ VALUE_MAP = {0 => "QUERY", 1 => "DDL", 2 => "DML", 3 => "EXPLAIN", 4 => "LOAD", 5 => "SET"}
50
+ VALID_VALUES = Set.new([QUERY, DDL, DML, EXPLAIN, LOAD, SET]).freeze
51
+ end
52
+
53
+ module TExplainLevel
54
+ MINIMAL = 0
55
+ STANDARD = 1
56
+ EXTENDED = 2
57
+ VERBOSE = 3
58
+ VALUE_MAP = {0 => "MINIMAL", 1 => "STANDARD", 2 => "EXTENDED", 3 => "VERBOSE"}
59
+ VALID_VALUES = Set.new([MINIMAL, STANDARD, EXTENDED, VERBOSE]).freeze
60
+ end
61
+
62
+ module TRuntimeFilterMode
63
+ OFF = 0
64
+ LOCAL = 1
65
+ GLOBAL = 2
66
+ VALUE_MAP = {0 => "OFF", 1 => "LOCAL", 2 => "GLOBAL"}
67
+ VALID_VALUES = Set.new([OFF, LOCAL, GLOBAL]).freeze
68
+ end
69
+
70
+ module TFunctionCategory
71
+ SCALAR = 0
72
+ AGGREGATE = 1
73
+ ANALYTIC = 2
74
+ VALUE_MAP = {0 => "SCALAR", 1 => "AGGREGATE", 2 => "ANALYTIC"}
75
+ VALID_VALUES = Set.new([SCALAR, AGGREGATE, ANALYTIC]).freeze
76
+ end
77
+
78
+ module TFunctionBinaryType
79
+ BUILTIN = 0
80
+ JAVA = 1
81
+ NATIVE = 2
82
+ IR = 3
83
+ VALUE_MAP = {0 => "BUILTIN", 1 => "JAVA", 2 => "NATIVE", 3 => "IR"}
84
+ VALID_VALUES = Set.new([BUILTIN, JAVA, NATIVE, IR]).freeze
85
+ end
86
+
87
+ class TScalarType
88
+ include ::Thrift::Struct, ::Thrift::Struct_Union
89
+ TYPE = 1
90
+ LEN = 2
91
+ PRECISION = 3
92
+ SCALE = 4
93
+
94
+ FIELDS = {
95
+ TYPE => {:type => ::Thrift::Types::I32, :name => 'type', :enum_class => ::Impala::Protocol::TPrimitiveType},
96
+ LEN => {:type => ::Thrift::Types::I32, :name => 'len', :optional => true},
97
+ PRECISION => {:type => ::Thrift::Types::I32, :name => 'precision', :optional => true},
98
+ SCALE => {:type => ::Thrift::Types::I32, :name => 'scale', :optional => true}
99
+ }
100
+
101
+ def struct_fields; FIELDS; end
102
+
103
+ def validate
104
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field type is unset!') unless @type
105
+ unless @type.nil? || ::Impala::Protocol::TPrimitiveType::VALID_VALUES.include?(@type)
106
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field type!')
107
+ end
108
+ end
109
+
110
+ ::Thrift::Struct.generate_accessors self
111
+ end
112
+
113
+ class TStructField
114
+ include ::Thrift::Struct, ::Thrift::Struct_Union
115
+ NAME = 1
116
+ COMMENT = 2
117
+
118
+ FIELDS = {
119
+ NAME => {:type => ::Thrift::Types::STRING, :name => 'name'},
120
+ COMMENT => {:type => ::Thrift::Types::STRING, :name => 'comment', :optional => true}
121
+ }
122
+
123
+ def struct_fields; FIELDS; end
124
+
125
+ def validate
126
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field name is unset!') unless @name
127
+ end
128
+
129
+ ::Thrift::Struct.generate_accessors self
130
+ end
131
+
132
+ class TTypeNode
133
+ include ::Thrift::Struct, ::Thrift::Struct_Union
134
+ TYPE = 1
135
+ SCALAR_TYPE = 2
136
+ STRUCT_FIELDS = 3
137
+
138
+ FIELDS = {
139
+ TYPE => {:type => ::Thrift::Types::I32, :name => 'type', :enum_class => ::Impala::Protocol::TTypeNodeType},
140
+ SCALAR_TYPE => {:type => ::Thrift::Types::STRUCT, :name => 'scalar_type', :class => ::Impala::Protocol::TScalarType, :optional => true},
141
+ STRUCT_FIELDS => {:type => ::Thrift::Types::LIST, :name => 'struct_fields', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Impala::Protocol::TStructField}, :optional => true}
142
+ }
143
+
144
+ def struct_fields; FIELDS; end
145
+
146
+ def validate
147
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field type is unset!') unless @type
148
+ unless @type.nil? || ::Impala::Protocol::TTypeNodeType::VALID_VALUES.include?(@type)
149
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field type!')
150
+ end
151
+ end
152
+
153
+ ::Thrift::Struct.generate_accessors self
154
+ end
155
+
156
+ class TColumnType
157
+ include ::Thrift::Struct, ::Thrift::Struct_Union
158
+ TYPES = 1
159
+
160
+ FIELDS = {
161
+ TYPES => {:type => ::Thrift::Types::LIST, :name => 'types', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Impala::Protocol::TTypeNode}}
162
+ }
163
+
164
+ def struct_fields; FIELDS; end
165
+
166
+ def validate
167
+ end
168
+
169
+ ::Thrift::Struct.generate_accessors self
170
+ end
171
+
172
+ class TNetworkAddress
173
+ include ::Thrift::Struct, ::Thrift::Struct_Union
174
+ HOSTNAME = 1
175
+ PORT = 2
176
+
177
+ FIELDS = {
178
+ HOSTNAME => {:type => ::Thrift::Types::STRING, :name => 'hostname'},
179
+ PORT => {:type => ::Thrift::Types::I32, :name => 'port'}
180
+ }
181
+
182
+ def struct_fields; FIELDS; end
183
+
184
+ def validate
185
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field hostname is unset!') unless @hostname
186
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field port is unset!') unless @port
187
+ end
188
+
189
+ ::Thrift::Struct.generate_accessors self
190
+ end
191
+
192
+ class TUniqueId
193
+ include ::Thrift::Struct, ::Thrift::Struct_Union
194
+ HI = 1
195
+ LO = 2
196
+
197
+ FIELDS = {
198
+ HI => {:type => ::Thrift::Types::I64, :name => 'hi'},
199
+ LO => {:type => ::Thrift::Types::I64, :name => 'lo'}
200
+ }
201
+
202
+ def struct_fields; FIELDS; end
203
+
204
+ def validate
205
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field hi is unset!') unless @hi
206
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field lo is unset!') unless @lo
207
+ end
208
+
209
+ ::Thrift::Struct.generate_accessors self
210
+ end
211
+
212
+ class TFunctionName
213
+ include ::Thrift::Struct, ::Thrift::Struct_Union
214
+ DB_NAME = 1
215
+ FUNCTION_NAME = 2
216
+
217
+ FIELDS = {
218
+ DB_NAME => {:type => ::Thrift::Types::STRING, :name => 'db_name', :optional => true},
219
+ FUNCTION_NAME => {:type => ::Thrift::Types::STRING, :name => 'function_name'}
220
+ }
221
+
222
+ def struct_fields; FIELDS; end
223
+
224
+ def validate
225
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field function_name is unset!') unless @function_name
226
+ end
227
+
228
+ ::Thrift::Struct.generate_accessors self
229
+ end
230
+
231
+ class TScalarFunction
232
+ include ::Thrift::Struct, ::Thrift::Struct_Union
233
+ SYMBOL = 1
234
+ PREPARE_FN_SYMBOL = 2
235
+ CLOSE_FN_SYMBOL = 3
236
+
237
+ FIELDS = {
238
+ SYMBOL => {:type => ::Thrift::Types::STRING, :name => 'symbol'},
239
+ PREPARE_FN_SYMBOL => {:type => ::Thrift::Types::STRING, :name => 'prepare_fn_symbol', :optional => true},
240
+ CLOSE_FN_SYMBOL => {:type => ::Thrift::Types::STRING, :name => 'close_fn_symbol', :optional => true}
241
+ }
242
+
243
+ def struct_fields; FIELDS; end
244
+
245
+ def validate
246
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field symbol is unset!') unless @symbol
247
+ end
248
+
249
+ ::Thrift::Struct.generate_accessors self
250
+ end
251
+
252
+ class TAggregateFunction
253
+ include ::Thrift::Struct, ::Thrift::Struct_Union
254
+ INTERMEDIATE_TYPE = 1
255
+ UPDATE_FN_SYMBOL = 2
256
+ INIT_FN_SYMBOL = 3
257
+ SERIALIZE_FN_SYMBOL = 4
258
+ MERGE_FN_SYMBOL = 5
259
+ FINALIZE_FN_SYMBOL = 6
260
+ GET_VALUE_FN_SYMBOL = 8
261
+ REMOVE_FN_SYMBOL = 9
262
+ IGNORES_DISTINCT = 7
263
+
264
+ FIELDS = {
265
+ INTERMEDIATE_TYPE => {:type => ::Thrift::Types::STRUCT, :name => 'intermediate_type', :class => ::Impala::Protocol::TColumnType},
266
+ UPDATE_FN_SYMBOL => {:type => ::Thrift::Types::STRING, :name => 'update_fn_symbol'},
267
+ INIT_FN_SYMBOL => {:type => ::Thrift::Types::STRING, :name => 'init_fn_symbol'},
268
+ SERIALIZE_FN_SYMBOL => {:type => ::Thrift::Types::STRING, :name => 'serialize_fn_symbol', :optional => true},
269
+ MERGE_FN_SYMBOL => {:type => ::Thrift::Types::STRING, :name => 'merge_fn_symbol', :optional => true},
270
+ FINALIZE_FN_SYMBOL => {:type => ::Thrift::Types::STRING, :name => 'finalize_fn_symbol', :optional => true},
271
+ GET_VALUE_FN_SYMBOL => {:type => ::Thrift::Types::STRING, :name => 'get_value_fn_symbol', :optional => true},
272
+ REMOVE_FN_SYMBOL => {:type => ::Thrift::Types::STRING, :name => 'remove_fn_symbol', :optional => true},
273
+ IGNORES_DISTINCT => {:type => ::Thrift::Types::BOOL, :name => 'ignores_distinct', :optional => true}
274
+ }
275
+
276
+ def struct_fields; FIELDS; end
277
+
278
+ def validate
279
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field intermediate_type is unset!') unless @intermediate_type
280
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field update_fn_symbol is unset!') unless @update_fn_symbol
281
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field init_fn_symbol is unset!') unless @init_fn_symbol
282
+ end
283
+
284
+ ::Thrift::Struct.generate_accessors self
285
+ end
286
+
287
+ class TFunction
288
+ include ::Thrift::Struct, ::Thrift::Struct_Union
289
+ NAME = 1
290
+ BINARY_TYPE = 2
291
+ ARG_TYPES = 3
292
+ RET_TYPE = 4
293
+ HAS_VAR_ARGS = 5
294
+ COMMENT = 6
295
+ SIGNATURE = 7
296
+ HDFS_LOCATION = 8
297
+ SCALAR_FN = 9
298
+ AGGREGATE_FN = 10
299
+ IS_PERSISTENT = 11
300
+
301
+ FIELDS = {
302
+ NAME => {:type => ::Thrift::Types::STRUCT, :name => 'name', :class => ::Impala::Protocol::TFunctionName},
303
+ BINARY_TYPE => {:type => ::Thrift::Types::I32, :name => 'binary_type', :enum_class => ::Impala::Protocol::TFunctionBinaryType},
304
+ ARG_TYPES => {:type => ::Thrift::Types::LIST, :name => 'arg_types', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Impala::Protocol::TColumnType}},
305
+ RET_TYPE => {:type => ::Thrift::Types::STRUCT, :name => 'ret_type', :class => ::Impala::Protocol::TColumnType},
306
+ HAS_VAR_ARGS => {:type => ::Thrift::Types::BOOL, :name => 'has_var_args'},
307
+ COMMENT => {:type => ::Thrift::Types::STRING, :name => 'comment', :optional => true},
308
+ SIGNATURE => {:type => ::Thrift::Types::STRING, :name => 'signature', :optional => true},
309
+ HDFS_LOCATION => {:type => ::Thrift::Types::STRING, :name => 'hdfs_location', :optional => true},
310
+ SCALAR_FN => {:type => ::Thrift::Types::STRUCT, :name => 'scalar_fn', :class => ::Impala::Protocol::TScalarFunction, :optional => true},
311
+ AGGREGATE_FN => {:type => ::Thrift::Types::STRUCT, :name => 'aggregate_fn', :class => ::Impala::Protocol::TAggregateFunction, :optional => true},
312
+ IS_PERSISTENT => {:type => ::Thrift::Types::BOOL, :name => 'is_persistent', :optional => true}
313
+ }
314
+
315
+ def struct_fields; FIELDS; end
316
+
317
+ def validate
318
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field name is unset!') unless @name
319
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field binary_type is unset!') unless @binary_type
320
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field arg_types is unset!') unless @arg_types
321
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field ret_type is unset!') unless @ret_type
322
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field has_var_args is unset!') if @has_var_args.nil?
323
+ unless @binary_type.nil? || ::Impala::Protocol::TFunctionBinaryType::VALID_VALUES.include?(@binary_type)
324
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field binary_type!')
325
+ end
326
+ end
327
+
328
+ ::Thrift::Struct.generate_accessors self
329
+ end
330
+
331
+ end
332
+ end
@@ -0,0 +1,117 @@
1
+ require 'gssapi'
2
+
3
+ module Impala
4
+ class SASLTransport < Thrift::FramedTransport
5
+ STATUS_BYTES = 1
6
+ PAYLOAD_LENGTH_BYTES = 4
7
+ NEGOTIATION_STATUS = {
8
+ START: 0x01,
9
+ OK: 0x02,
10
+ BAD: 0x03,
11
+ ERROR: 0x04,
12
+ COMPLETE: 0x05
13
+ }
14
+
15
+ def initialize(transport, mechanism, options={})
16
+ super(transport)
17
+ @mechanism = mechanism.to_sym
18
+ @options = options
19
+
20
+ unless [:PLAIN, :GSSAPI].include? @mechanism
21
+ raise "Unknown SASL mechanism: #{@mechanism}"
22
+ end
23
+
24
+ if @mechanism == :GSSAPI
25
+ @gsscli = GSSAPI::Simple.new(@options[:remote_host], @options[:remote_principal])
26
+ end
27
+ end
28
+
29
+ def open
30
+ super
31
+
32
+ case @mechanism
33
+ when :PLAIN
34
+ handshake_plain!
35
+ when :GSSAPI
36
+ handshake_gssapi!
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def handshake_plain!
43
+ username = @options.fetch(:username, 'anonymous')
44
+ password = @options.fetch(:password, 'anonymous')
45
+
46
+ token = "[PLAIN]\u0000#{username}\u0000#{password}"
47
+ write_handshake_message(NEGOTIATION_STATUS[:START], 'PLAIN')
48
+ write_handshake_message(NEGOTIATION_STATUS[:OK], token)
49
+
50
+ status, _ = read_handshake_message
51
+ case status
52
+ when NEGOTIATION_STATUS[:COMPLETE]
53
+ @open = true
54
+ when NEGOTIATION_STATUS[:OK]
55
+ raise "Failed to complete challenge exchange: only NONE supported currently"
56
+ end
57
+ end
58
+
59
+ def handshake_gssapi!
60
+ token = @gsscli.init_context
61
+ write_handshake_message(NEGOTIATION_STATUS[:START], 'GSSAPI')
62
+ write_handshake_message(NEGOTIATION_STATUS[:OK], token)
63
+
64
+ status, msg = read_handshake_message
65
+ case status
66
+ when NEGOTIATION_STATUS[:COMPLETE]
67
+ raise "Unexpected COMPLETE from server"
68
+ when NEGOTIATION_STATUS[:OK]
69
+ unless @gsscli.init_context(msg)
70
+ raise "GSSAPI: challenge provided by server could not be verified"
71
+ end
72
+
73
+ write_handshake_message(NEGOTIATION_STATUS[:OK], "")
74
+
75
+ status, msg = read_handshake_message
76
+ case status
77
+ when NEGOTIATION_STATUS[:COMPLETE]
78
+ raise "Unexpected COMPLETE from server"
79
+ when NEGOTIATION_STATUS[:OK]
80
+ unwrapped = @gsscli.unwrap_message(msg)
81
+ rewrapped = @gsscli.wrap_message(unwrapped)
82
+
83
+ write_handshake_message(NEGOTIATION_STATUS[:COMPLETE], rewrapped)
84
+
85
+ status, msg = read_handshake_message
86
+ case status
87
+ when NEGOTIATION_STATUS[:COMPLETE]
88
+ @open = true
89
+ when NEGOTIATION_STATUS[:OK]
90
+ raise "Failed to complete GSS challenge exchange"
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ def read_handshake_message
97
+ status, len = @transport.read(STATUS_BYTES + PAYLOAD_LENGTH_BYTES).unpack('cl>')
98
+ body = @transport.to_io.read(len)
99
+ if [NEGOTIATION_STATUS[:BAD], NEGOTIATION_STATUS[:ERROR]].include?(status)
100
+ raise "Exception from server: #{body}"
101
+ end
102
+
103
+ [status, body]
104
+ end
105
+
106
+ def write_handshake_message(status, message)
107
+ header = [status, message.length].pack('cl>')
108
+ @transport.write(header + message)
109
+ end
110
+ end
111
+
112
+ class SASLTransportFactory < Thrift::BaseTransportFactory
113
+ def get_transport(transport)
114
+ return SASLTransport.new(transport)
115
+ end
116
+ end
117
+ end