sequel-impala 1.0.0 → 1.0.1

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +16 -0
  3. data/LICENSE +2 -1
  4. data/README.md +45 -0
  5. data/lib/rbhive.rb +8 -0
  6. data/lib/rbhive/connection.rb +150 -0
  7. data/lib/rbhive/explain_result.rb +46 -0
  8. data/lib/rbhive/result_set.rb +37 -0
  9. data/lib/rbhive/schema_definition.rb +86 -0
  10. data/lib/rbhive/t_c_l_i_connection.rb +464 -0
  11. data/lib/rbhive/t_c_l_i_result_set.rb +3 -0
  12. data/lib/rbhive/t_c_l_i_schema_definition.rb +87 -0
  13. data/lib/rbhive/table_schema.rb +122 -0
  14. data/lib/rbhive/version.rb +3 -0
  15. data/lib/sequel/adapters/impala.rb +13 -1
  16. data/lib/sequel/adapters/rbhive.rb +174 -0
  17. data/lib/sequel/adapters/shared/impala.rb +11 -3
  18. data/lib/sequel/extensions/csv_to_parquet.rb +68 -14
  19. data/lib/thrift/facebook_service.rb +700 -0
  20. data/lib/thrift/fb303_constants.rb +9 -0
  21. data/lib/thrift/fb303_types.rb +19 -0
  22. data/lib/thrift/hive_metastore_constants.rb +41 -0
  23. data/lib/thrift/hive_metastore_types.rb +630 -0
  24. data/lib/thrift/hive_service_constants.rb +13 -0
  25. data/lib/thrift/hive_service_types.rb +72 -0
  26. data/lib/thrift/queryplan_constants.rb +13 -0
  27. data/lib/thrift/queryplan_types.rb +261 -0
  28. data/lib/thrift/sasl_client_transport.rb +161 -0
  29. data/lib/thrift/serde_constants.rb +92 -0
  30. data/lib/thrift/serde_types.rb +7 -0
  31. data/lib/thrift/t_c_l_i_service.rb +1054 -0
  32. data/lib/thrift/t_c_l_i_service_constants.rb +72 -0
  33. data/lib/thrift/t_c_l_i_service_types.rb +1768 -0
  34. data/lib/thrift/thrift_hive.rb +508 -0
  35. data/lib/thrift/thrift_hive_metastore.rb +3856 -0
  36. data/spec/impala_test.rb +6 -1
  37. metadata +53 -25
  38. data/README.rdoc +0 -39
@@ -0,0 +1,13 @@
1
+ #
2
+ # Autogenerated by Thrift Compiler (0.9.0)
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+ require 'thrift'
8
+ require_relative 'hive_service_types'
9
+
10
+ module Hive
11
+ module Thrift
12
+ end
13
+ end
@@ -0,0 +1,72 @@
1
+ #
2
+ # Autogenerated by Thrift Compiler (0.9.0)
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+ require 'thrift'
8
+ require_relative 'fb303_types'
9
+ require_relative 'hive_metastore_types'
10
+ require_relative 'queryplan_types'
11
+
12
+
13
+ module Hive
14
+ module Thrift
15
+ module JobTrackerState
16
+ INITIALIZING = 1
17
+ RUNNING = 2
18
+ VALUE_MAP = {1 => "INITIALIZING", 2 => "RUNNING"}
19
+ VALID_VALUES = Set.new([INITIALIZING, RUNNING]).freeze
20
+ end
21
+
22
+ class HiveClusterStatus
23
+ include ::Thrift::Struct, ::Thrift::Struct_Union
24
+ TASKTRACKERS = 1
25
+ MAPTASKS = 2
26
+ REDUCETASKS = 3
27
+ MAXMAPTASKS = 4
28
+ MAXREDUCETASKS = 5
29
+ STATE = 6
30
+
31
+ FIELDS = {
32
+ TASKTRACKERS => {:type => ::Thrift::Types::I32, :name => 'taskTrackers'},
33
+ MAPTASKS => {:type => ::Thrift::Types::I32, :name => 'mapTasks'},
34
+ REDUCETASKS => {:type => ::Thrift::Types::I32, :name => 'reduceTasks'},
35
+ MAXMAPTASKS => {:type => ::Thrift::Types::I32, :name => 'maxMapTasks'},
36
+ MAXREDUCETASKS => {:type => ::Thrift::Types::I32, :name => 'maxReduceTasks'},
37
+ STATE => {:type => ::Thrift::Types::I32, :name => 'state', :enum_class => ::Hive::Thrift::JobTrackerState}
38
+ }
39
+
40
+ def struct_fields; FIELDS; end
41
+
42
+ def validate
43
+ unless @state.nil? || ::Hive::Thrift::JobTrackerState::VALID_VALUES.include?(@state)
44
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field state!')
45
+ end
46
+ end
47
+
48
+ ::Thrift::Struct.generate_accessors self
49
+ end
50
+
51
+ class HiveServerException < ::Thrift::Exception
52
+ include ::Thrift::Struct, ::Thrift::Struct_Union
53
+ MESSAGE = 1
54
+ ERRORCODE = 2
55
+ SQLSTATE = 3
56
+
57
+ FIELDS = {
58
+ MESSAGE => {:type => ::Thrift::Types::STRING, :name => 'message'},
59
+ ERRORCODE => {:type => ::Thrift::Types::I32, :name => 'errorCode'},
60
+ SQLSTATE => {:type => ::Thrift::Types::STRING, :name => 'SQLState'}
61
+ }
62
+
63
+ def struct_fields; FIELDS; end
64
+
65
+ def validate
66
+ end
67
+
68
+ ::Thrift::Struct.generate_accessors self
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,13 @@
1
+ #
2
+ # Autogenerated by Thrift Compiler (0.9.0)
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+ require 'thrift'
8
+ require_relative 'queryplan_types'
9
+
10
+ module Hive
11
+ module Thrift
12
+ end
13
+ end
@@ -0,0 +1,261 @@
1
+ #
2
+ # Autogenerated by Thrift Compiler (0.9.0)
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+ require 'thrift'
8
+
9
+ module Hive
10
+ module Thrift
11
+ module AdjacencyType
12
+ CONJUNCTIVE = 0
13
+ DISJUNCTIVE = 1
14
+ VALUE_MAP = {0 => "CONJUNCTIVE", 1 => "DISJUNCTIVE"}
15
+ VALID_VALUES = Set.new([CONJUNCTIVE, DISJUNCTIVE]).freeze
16
+ end
17
+
18
+ module NodeType
19
+ OPERATOR = 0
20
+ STAGE = 1
21
+ VALUE_MAP = {0 => "OPERATOR", 1 => "STAGE"}
22
+ VALID_VALUES = Set.new([OPERATOR, STAGE]).freeze
23
+ end
24
+
25
+ module OperatorType
26
+ JOIN = 0
27
+ MAPJOIN = 1
28
+ EXTRACT = 2
29
+ FILTER = 3
30
+ FORWARD = 4
31
+ GROUPBY = 5
32
+ LIMIT = 6
33
+ SCRIPT = 7
34
+ SELECT = 8
35
+ TABLESCAN = 9
36
+ FILESINK = 10
37
+ REDUCESINK = 11
38
+ UNION = 12
39
+ UDTF = 13
40
+ LATERALVIEWJOIN = 14
41
+ LATERALVIEWFORWARD = 15
42
+ HASHTABLESINK = 16
43
+ HASHTABLEDUMMY = 17
44
+ VALUE_MAP = {0 => "JOIN", 1 => "MAPJOIN", 2 => "EXTRACT", 3 => "FILTER", 4 => "FORWARD", 5 => "GROUPBY", 6 => "LIMIT", 7 => "SCRIPT", 8 => "SELECT", 9 => "TABLESCAN", 10 => "FILESINK", 11 => "REDUCESINK", 12 => "UNION", 13 => "UDTF", 14 => "LATERALVIEWJOIN", 15 => "LATERALVIEWFORWARD", 16 => "HASHTABLESINK", 17 => "HASHTABLEDUMMY"}
45
+ VALID_VALUES = Set.new([JOIN, MAPJOIN, EXTRACT, FILTER, FORWARD, GROUPBY, LIMIT, SCRIPT, SELECT, TABLESCAN, FILESINK, REDUCESINK, UNION, UDTF, LATERALVIEWJOIN, LATERALVIEWFORWARD, HASHTABLESINK, HASHTABLEDUMMY]).freeze
46
+ end
47
+
48
+ module TaskType
49
+ MAP = 0
50
+ REDUCE = 1
51
+ OTHER = 2
52
+ VALUE_MAP = {0 => "MAP", 1 => "REDUCE", 2 => "OTHER"}
53
+ VALID_VALUES = Set.new([MAP, REDUCE, OTHER]).freeze
54
+ end
55
+
56
+ module StageType
57
+ CONDITIONAL = 0
58
+ COPY = 1
59
+ DDL = 2
60
+ MAPRED = 3
61
+ EXPLAIN = 4
62
+ FETCH = 5
63
+ FUNC = 6
64
+ MAPREDLOCAL = 7
65
+ MOVE = 8
66
+ STATS = 9
67
+ VALUE_MAP = {0 => "CONDITIONAL", 1 => "COPY", 2 => "DDL", 3 => "MAPRED", 4 => "EXPLAIN", 5 => "FETCH", 6 => "FUNC", 7 => "MAPREDLOCAL", 8 => "MOVE", 9 => "STATS"}
68
+ VALID_VALUES = Set.new([CONDITIONAL, COPY, DDL, MAPRED, EXPLAIN, FETCH, FUNC, MAPREDLOCAL, MOVE, STATS]).freeze
69
+ end
70
+
71
+ class Adjacency
72
+ include ::Thrift::Struct, ::Thrift::Struct_Union
73
+ NODE = 1
74
+ CHILDREN = 2
75
+ ADJACENCYTYPE = 3
76
+
77
+ FIELDS = {
78
+ NODE => {:type => ::Thrift::Types::STRING, :name => 'node'},
79
+ CHILDREN => {:type => ::Thrift::Types::LIST, :name => 'children', :element => {:type => ::Thrift::Types::STRING}},
80
+ ADJACENCYTYPE => {:type => ::Thrift::Types::I32, :name => 'adjacencyType', :enum_class => ::Hive::Thrift::AdjacencyType}
81
+ }
82
+
83
+ def struct_fields; FIELDS; end
84
+
85
+ def validate
86
+ unless @adjacencyType.nil? || ::Hive::Thrift::AdjacencyType::VALID_VALUES.include?(@adjacencyType)
87
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field adjacencyType!')
88
+ end
89
+ end
90
+
91
+ ::Thrift::Struct.generate_accessors self
92
+ end
93
+
94
+ class Graph
95
+ include ::Thrift::Struct, ::Thrift::Struct_Union
96
+ NODETYPE = 1
97
+ ROOTS = 2
98
+ ADJACENCYLIST = 3
99
+
100
+ FIELDS = {
101
+ NODETYPE => {:type => ::Thrift::Types::I32, :name => 'nodeType', :enum_class => ::Hive::Thrift::NodeType},
102
+ ROOTS => {:type => ::Thrift::Types::LIST, :name => 'roots', :element => {:type => ::Thrift::Types::STRING}},
103
+ ADJACENCYLIST => {:type => ::Thrift::Types::LIST, :name => 'adjacencyList', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Hive::Thrift::Adjacency}}
104
+ }
105
+
106
+ def struct_fields; FIELDS; end
107
+
108
+ def validate
109
+ unless @nodeType.nil? || ::Hive::Thrift::NodeType::VALID_VALUES.include?(@nodeType)
110
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field nodeType!')
111
+ end
112
+ end
113
+
114
+ ::Thrift::Struct.generate_accessors self
115
+ end
116
+
117
+ class Operator
118
+ include ::Thrift::Struct, ::Thrift::Struct_Union
119
+ OPERATORID = 1
120
+ OPERATORTYPE = 2
121
+ OPERATORATTRIBUTES = 3
122
+ OPERATORCOUNTERS = 4
123
+ DONE = 5
124
+ STARTED = 6
125
+
126
+ FIELDS = {
127
+ OPERATORID => {:type => ::Thrift::Types::STRING, :name => 'operatorId'},
128
+ OPERATORTYPE => {:type => ::Thrift::Types::I32, :name => 'operatorType', :enum_class => ::Hive::Thrift::OperatorType},
129
+ OPERATORATTRIBUTES => {:type => ::Thrift::Types::MAP, :name => 'operatorAttributes', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::STRING}},
130
+ OPERATORCOUNTERS => {:type => ::Thrift::Types::MAP, :name => 'operatorCounters', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::I64}},
131
+ DONE => {:type => ::Thrift::Types::BOOL, :name => 'done'},
132
+ STARTED => {:type => ::Thrift::Types::BOOL, :name => 'started'}
133
+ }
134
+
135
+ def struct_fields; FIELDS; end
136
+
137
+ def validate
138
+ unless @operatorType.nil? || ::Hive::Thrift::OperatorType::VALID_VALUES.include?(@operatorType)
139
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field operatorType!')
140
+ end
141
+ end
142
+
143
+ ::Thrift::Struct.generate_accessors self
144
+ end
145
+
146
+ class Task
147
+ include ::Thrift::Struct, ::Thrift::Struct_Union
148
+ TASKID = 1
149
+ TASKTYPE = 2
150
+ TASKATTRIBUTES = 3
151
+ TASKCOUNTERS = 4
152
+ OPERATORGRAPH = 5
153
+ OPERATORLIST = 6
154
+ DONE = 7
155
+ STARTED = 8
156
+
157
+ FIELDS = {
158
+ TASKID => {:type => ::Thrift::Types::STRING, :name => 'taskId'},
159
+ TASKTYPE => {:type => ::Thrift::Types::I32, :name => 'taskType', :enum_class => ::Hive::Thrift::TaskType},
160
+ TASKATTRIBUTES => {:type => ::Thrift::Types::MAP, :name => 'taskAttributes', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::STRING}},
161
+ TASKCOUNTERS => {:type => ::Thrift::Types::MAP, :name => 'taskCounters', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::I64}},
162
+ OPERATORGRAPH => {:type => ::Thrift::Types::STRUCT, :name => 'operatorGraph', :class => ::Hive::Thrift::Graph, :optional => true},
163
+ OPERATORLIST => {:type => ::Thrift::Types::LIST, :name => 'operatorList', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Hive::Thrift::Operator}, :optional => true},
164
+ DONE => {:type => ::Thrift::Types::BOOL, :name => 'done'},
165
+ STARTED => {:type => ::Thrift::Types::BOOL, :name => 'started'}
166
+ }
167
+
168
+ def struct_fields; FIELDS; end
169
+
170
+ def validate
171
+ unless @taskType.nil? || ::Hive::Thrift::TaskType::VALID_VALUES.include?(@taskType)
172
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field taskType!')
173
+ end
174
+ end
175
+
176
+ ::Thrift::Struct.generate_accessors self
177
+ end
178
+
179
+ class Stage
180
+ include ::Thrift::Struct, ::Thrift::Struct_Union
181
+ STAGEID = 1
182
+ STAGETYPE = 2
183
+ STAGEATTRIBUTES = 3
184
+ STAGECOUNTERS = 4
185
+ TASKLIST = 5
186
+ DONE = 6
187
+ STARTED = 7
188
+
189
+ FIELDS = {
190
+ STAGEID => {:type => ::Thrift::Types::STRING, :name => 'stageId'},
191
+ STAGETYPE => {:type => ::Thrift::Types::I32, :name => 'stageType', :enum_class => ::Hive::Thrift::StageType},
192
+ STAGEATTRIBUTES => {:type => ::Thrift::Types::MAP, :name => 'stageAttributes', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::STRING}},
193
+ STAGECOUNTERS => {:type => ::Thrift::Types::MAP, :name => 'stageCounters', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::I64}},
194
+ TASKLIST => {:type => ::Thrift::Types::LIST, :name => 'taskList', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Hive::Thrift::Task}},
195
+ DONE => {:type => ::Thrift::Types::BOOL, :name => 'done'},
196
+ STARTED => {:type => ::Thrift::Types::BOOL, :name => 'started'}
197
+ }
198
+
199
+ def struct_fields; FIELDS; end
200
+
201
+ def validate
202
+ unless @stageType.nil? || ::Hive::Thrift::StageType::VALID_VALUES.include?(@stageType)
203
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field stageType!')
204
+ end
205
+ end
206
+
207
+ ::Thrift::Struct.generate_accessors self
208
+ end
209
+
210
+ class Query
211
+ include ::Thrift::Struct, ::Thrift::Struct_Union
212
+ QUERYID = 1
213
+ QUERYTYPE = 2
214
+ QUERYATTRIBUTES = 3
215
+ QUERYCOUNTERS = 4
216
+ STAGEGRAPH = 5
217
+ STAGELIST = 6
218
+ DONE = 7
219
+ STARTED = 8
220
+
221
+ FIELDS = {
222
+ QUERYID => {:type => ::Thrift::Types::STRING, :name => 'queryId'},
223
+ QUERYTYPE => {:type => ::Thrift::Types::STRING, :name => 'queryType'},
224
+ QUERYATTRIBUTES => {:type => ::Thrift::Types::MAP, :name => 'queryAttributes', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::STRING}},
225
+ QUERYCOUNTERS => {:type => ::Thrift::Types::MAP, :name => 'queryCounters', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::I64}},
226
+ STAGEGRAPH => {:type => ::Thrift::Types::STRUCT, :name => 'stageGraph', :class => ::Hive::Thrift::Graph},
227
+ STAGELIST => {:type => ::Thrift::Types::LIST, :name => 'stageList', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Hive::Thrift::Stage}},
228
+ DONE => {:type => ::Thrift::Types::BOOL, :name => 'done'},
229
+ STARTED => {:type => ::Thrift::Types::BOOL, :name => 'started'}
230
+ }
231
+
232
+ def struct_fields; FIELDS; end
233
+
234
+ def validate
235
+ end
236
+
237
+ ::Thrift::Struct.generate_accessors self
238
+ end
239
+
240
+ class QueryPlan
241
+ include ::Thrift::Struct, ::Thrift::Struct_Union
242
+ QUERIES = 1
243
+ DONE = 2
244
+ STARTED = 3
245
+
246
+ FIELDS = {
247
+ QUERIES => {:type => ::Thrift::Types::LIST, :name => 'queries', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Hive::Thrift::Query}},
248
+ DONE => {:type => ::Thrift::Types::BOOL, :name => 'done'},
249
+ STARTED => {:type => ::Thrift::Types::BOOL, :name => 'started'}
250
+ }
251
+
252
+ def struct_fields; FIELDS; end
253
+
254
+ def validate
255
+ end
256
+
257
+ ::Thrift::Struct.generate_accessors self
258
+ end
259
+
260
+ end
261
+ end
@@ -0,0 +1,161 @@
1
+ module Thrift
2
+ class SaslClientTransport < BufferedTransport
3
+ attr_reader :challenge, :sasl_complete
4
+
5
+ STATUS_BYTES = 1
6
+ PAYLOAD_LENGTH_BYTES = 4
7
+ AUTH_MECHANISM = 'PLAIN'
8
+ NEGOTIATION_STATUS = {
9
+ START: 0x01,
10
+ OK: 0x02,
11
+ BAD: 0x03,
12
+ ERROR: 0x04,
13
+ COMPLETE: 0x05
14
+ }
15
+
16
+ def initialize(transport, sasl_params={})
17
+ super(transport)
18
+ @challenge = nil
19
+ @sasl_username = sasl_params.fetch(:username, 'anonymous')
20
+ @sasl_password = sasl_params.fetch(:password, 'anonymous')
21
+ @sasl_mechanism = sasl_params.fetch(:mechanism, 'PLAIN')
22
+ raise 'Unknown SASL mechanism: #{@sasl_mechanism}' unless ['PLAIN', 'GSSAPI'].include? @sasl_mechanism
23
+ if @sasl_mechanism == 'GSSAPI'
24
+ require 'gssapi'
25
+ @sasl_remote_principal = sasl_params[:remote_principal]
26
+ @sasl_remote_host = sasl_params[:remote_host]
27
+ @gsscli = GSSAPI::Simple.new(@sasl_remote_host, @sasl_remote_principal)
28
+ end
29
+ end
30
+
31
+ def read(sz)
32
+ len, = @transport.read(PAYLOAD_LENGTH_BYTES).unpack('l>') if @rbuf.nil?
33
+ sz = len if len && sz > len
34
+ @index += sz
35
+ ret = @rbuf.slice(@index - sz, sz) || Bytes.empty_byte_buffer
36
+ if ret.length < sz
37
+ sz -= ret.length
38
+ read_into_buffer(@rbuf, [sz, len || 0].max)
39
+ @index = sz
40
+ ret += @rbuf.slice(0, sz) || Bytes.empty_byte_buffer
41
+ end
42
+ ret
43
+ end
44
+
45
+ def read_byte
46
+ reset_buffer! if @index >= @rbuf.size
47
+ @index += 1
48
+ Bytes.get_string_byte(@rbuf, @index - 1)
49
+ end
50
+
51
+ def read_into_buffer(buffer, size)
52
+ i = 0
53
+ while i < size
54
+ reset_buffer! if @index >= @rbuf.size
55
+ byte = Bytes.get_string_byte(@rbuf, @index)
56
+ Bytes.set_string_byte(buffer, i, byte)
57
+ @index += 1
58
+ i += 1
59
+ end
60
+ i
61
+ end
62
+
63
+ def write(buf)
64
+ initiate_hand_shake unless sasl_complete
65
+ header = [buf.length].pack('l>')
66
+ @wbuf << (header + Bytes.force_binary_encoding(buf))
67
+ end
68
+
69
+ protected
70
+
71
+ def initiate_hand_shake
72
+ if @sasl_mechanism == 'GSSAPI'
73
+ initiate_hand_shake_gssapi
74
+ else
75
+ initiate_hand_shake_plain
76
+ end
77
+ end
78
+
79
+ def initiate_hand_shake_gssapi
80
+ token = @gsscli.init_context
81
+ header = [NEGOTIATION_STATUS[:START], @sasl_mechanism.length].pack('cl>')
82
+ @transport.write header + @sasl_mechanism
83
+ header = [NEGOTIATION_STATUS[:OK], token.length].pack('cl>')
84
+ @transport.write header + token
85
+ status, len = @transport.read(STATUS_BYTES + PAYLOAD_LENGTH_BYTES).unpack('cl>')
86
+ case status
87
+ when NEGOTIATION_STATUS[:BAD], NEGOTIATION_STATUS[:ERROR]
88
+ raise @transport.to_io.read(len)
89
+ when NEGOTIATION_STATUS[:COMPLETE]
90
+ raise "Not expecting COMPLETE at initial stage"
91
+ when NEGOTIATION_STATUS[:OK]
92
+ challenge = @transport.to_io.read len
93
+ unless @gsscli.init_context(challenge)
94
+ raise "GSSAPI: challenge provided by server could not be verified"
95
+ end
96
+ header = [NEGOTIATION_STATUS[:OK], 0].pack('cl>')
97
+ @transport.write header
98
+ status2, len = @transport.read(STATUS_BYTES + PAYLOAD_LENGTH_BYTES).unpack('cl>')
99
+ case status2
100
+ when NEGOTIATION_STATUS[:BAD], NEGOTIATION_STATUS[:ERROR]
101
+ raise @transport.to_io.read(len)
102
+ when NEGOTIATION_STATUS[:COMPLETE]
103
+ raise "Not expecting COMPLETE at second stage"
104
+ when NEGOTIATION_STATUS[:OK]
105
+ challenge = @transport.to_io.read len
106
+ unwrapped = @gsscli.unwrap_message(challenge)
107
+ rewrapped = @gsscli.wrap_message(unwrapped)
108
+ header = [NEGOTIATION_STATUS[:COMPLETE], rewrapped.length].pack('cl>')
109
+ @transport.write header + rewrapped
110
+ status3, len = @transport.read(STATUS_BYTES + PAYLOAD_LENGTH_BYTES).unpack('cl>')
111
+ case status3
112
+ when NEGOTIATION_STATUS[:BAD], NEGOTIATION_STATUS[:ERROR]
113
+ raise @transport.to_io.read(len)
114
+ when NEGOTIATION_STATUS[:COMPLETE]
115
+ s = @transport.to_io.read len
116
+ @sasl_complete = true
117
+ when NEGOTIATION_STATUS[:OK]
118
+ raise "Failed to complete GSS challenge exchange"
119
+ end
120
+ end
121
+ end
122
+ @sasl_complete = true
123
+ end
124
+
125
+ def initiate_hand_shake_plain
126
+ header = [NEGOTIATION_STATUS[:START], AUTH_MECHANISM.length].pack('cl>')
127
+ @transport.write header + AUTH_MECHANISM
128
+ message = "[#{AUTH_MECHANISM}]\u0000#{@sasl_username}\u0000#{@sasl_password}"
129
+ header = [NEGOTIATION_STATUS[:OK], message.length].pack('cl>')
130
+ @transport.write header + message
131
+ status, len = @transport.read(STATUS_BYTES + PAYLOAD_LENGTH_BYTES).unpack('cl>')
132
+ case status
133
+ when NEGOTIATION_STATUS[:BAD], NEGOTIATION_STATUS[:ERROR]
134
+ raise @transport.to_io.read(len)
135
+ when NEGOTIATION_STATUS[:COMPLETE]
136
+ @challenge = @transport.to_io.read len
137
+ when NEGOTIATION_STATUS[:OK]
138
+ raise "Failed to complete challenge exchange: only NONE supported currently"
139
+ end
140
+ @sasl_complete = true
141
+ end
142
+
143
+ private
144
+
145
+ def reset_buffer!
146
+ len, = @transport.read(PAYLOAD_LENGTH_BYTES).unpack('l>')
147
+ @rbuf = @transport.read(len)
148
+ while @rbuf.size < len
149
+ @rbuf << @transport.read(len - @rbuf.size)
150
+ end
151
+ @index = 0
152
+ end
153
+ end
154
+
155
+ class SaslClientTransportFactory < BaseTransportFactory
156
+ def get_transport(transport)
157
+ return SaslClientTransport.new(transport)
158
+ end
159
+ end
160
+
161
+ end