impala 0.4.3 → 0.5.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 488007beb7a8a2ecc5e1663356305ea2d2a705d1
4
+ data.tar.gz: 4e7276e73ee5d17e790116fc38f59938e00d5e15
5
+ SHA512:
6
+ metadata.gz: 6e903365b98beb2a78e2a2a4bea721035ca58344b54e196ba67ae15ac814a20024ef79565d019dc390a58529ff80cc760f254d67080833e21fdb44f90f164eeb
7
+ data.tar.gz: 0d43d9e6442237bd7ecc27ff9770bc3e51058d166a847200c1830b5466bb3c51250be848b8563922618dc10199c716f487bd01d3e5c40ba97188205d137375e4
@@ -1,4 +1,4 @@
1
+ sudo: false
1
2
  language: ruby
2
3
  rvm:
3
- - 1.9.3
4
- - 2.1.2
4
+ - 2.2
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # impala-ruby
2
2
 
3
- ![build](https://travis-ci.org/colinmarc/impala-ruby.svg?branch=master)   [![rubygems](https://badge.fury.io/rb/impala.svg)](http://rubygems.org/gems/impala)
3
+ [![build](https://travis-ci.org/colinmarc/impala-ruby.svg?branch=master)](https://travis-ci.org/colinmarc/impala-ruby)   [![rubygems](https://badge.fury.io/rb/impala.svg)](http://rubygems.org/gems/impala)
4
4
 
5
5
  This is a ruby client for [Cloudera Impala][1]. You use it like this:
6
6
 
@@ -13,9 +13,8 @@ Gem::Specification.new do |gem|
13
13
  gem.homepage = "https://github.com/colinmarc/impala-ruby"
14
14
  gem.license = 'MIT'
15
15
 
16
- gem.add_dependency('thrift', '~> 0.9.1')
17
- gem.add_dependency('rack')
18
- gem.add_dependency('thin')
16
+ gem.add_dependency('thrift', '~> 0.9')
17
+ gem.add_dependency('gssapi', '~> 1.2')
19
18
 
20
19
  gem.add_development_dependency('rake')
21
20
  gem.add_development_dependency('pry')
@@ -10,6 +10,7 @@ require 'impala/version'
10
10
  require 'thrift'
11
11
  require 'time'
12
12
  require 'impala/protocol'
13
+ require 'impala/sasl_transport'
13
14
  require 'impala/cursor'
14
15
  require 'impala/connection'
15
16
 
@@ -22,15 +23,26 @@ module Impala
22
23
  class ParsingError < StandardError; end
23
24
 
24
25
  # Connect to an Impala server. If a block is given, it will close the
25
- # connection after yielding the connection to the block.
26
+ # connection after yielding the connection to the block.
26
27
  # @param [String] host the hostname or IP address of the Impala server
27
28
  # @param [int] port the port that the Impala server is listening on
29
+ # @param [Hash] options connection options
30
+ # @option options [int] :timeout the timeout in seconds to use when connecting
31
+ # @option options [Hash] :sasl if present, used to connect with SASL PLAIN
32
+ # authentication. Should have two properties:
33
+ # - *:username* (String)
34
+ # - *:password* (String)
35
+ # @option options [Hash] :kerberos if present, used to connect with SASL
36
+ # GSSAPI authentication using whatever context is available. Should have two
37
+ # properties:
38
+ # - *:host* (String)
39
+ # - *:provider* (String)
28
40
  # @yieldparam [Connection] conn the open connection. Will be closed once the block
29
41
  # finishes
30
42
  # @return [Connection] the open connection, or, if a block is
31
43
  # passed, the return value of the block
32
- def self.connect(host=DEFAULT_HOST, port=DEFAULT_PORT)
33
- connection = Connection.new(host, port)
44
+ def self.connect(host=DEFAULT_HOST, port=DEFAULT_PORT, options={})
45
+ connection = Connection.new(host, port, options)
34
46
 
35
47
  if block_given?
36
48
  begin
@@ -5,9 +5,10 @@ module Impala
5
5
  LOG_CONTEXT_ID = "impala-ruby"
6
6
 
7
7
  # Don't instantiate Connections directly; instead, use {Impala.connect}.
8
- def initialize(host, port)
8
+ def initialize(host, port, options={})
9
9
  @host = host
10
10
  @port = port
11
+ @options = options
11
12
  @connected = false
12
13
  open
13
14
  end
@@ -20,9 +21,16 @@ module Impala
20
21
  def open
21
22
  return if @connected
22
23
 
23
- socket = Thrift::Socket.new(@host, @port)
24
+ socket = Thrift::Socket.new(@host, @port, @options[:timeout])
25
+
26
+ if @options[:kerberos]
27
+ @transport = SASLTransport.new(socket, :GSSAPI, @options[:kerberos])
28
+ elsif @options[:sasl]
29
+ @transport = SASLTransport.new(socket, :PLAIN, @options[:sasl])
30
+ else
31
+ @transport = Thrift::BufferedTransport.new(socket)
32
+ end
24
33
 
25
- @transport = Thrift::BufferedTransport.new(socket)
26
34
  @transport.open
27
35
 
28
36
  proto = Thrift::BinaryProtocol.new(@transport)
@@ -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[:host], @options[: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
@@ -1,3 +1,3 @@
1
1
  module Impala
2
- VERSION = "0.4.3"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -4,7 +4,7 @@ require 'mocha/setup'
4
4
 
5
5
  describe 'Impala.connect' do
6
6
  before do
7
- Thrift::Socket.expects(:new).with('host', 12345)
7
+ Thrift::Socket.expects(:new).with('host', 12345, nil)
8
8
  Thrift::BufferedTransport.expects(:new).once.returns(stub(:open => nil))
9
9
  Thrift::BinaryProtocol.expects(:new).once
10
10
  Impala::Protocol::ImpalaService::Client.expects(:new).once
metadata CHANGED
@@ -1,174 +1,139 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: impala
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
5
- prerelease:
4
+ version: 0.5.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Colin Marc
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2014-09-04 00:00:00.000000000 Z
11
+ date: 2016-09-25 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: thrift
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ~>
17
+ - - "~>"
20
18
  - !ruby/object:Gem::Version
21
- version: 0.9.1
19
+ version: '0.9'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ~>
24
+ - - "~>"
28
25
  - !ruby/object:Gem::Version
29
- version: 0.9.1
26
+ version: '0.9'
30
27
  - !ruby/object:Gem::Dependency
31
- name: rack
28
+ name: gssapi
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - "~>"
36
32
  - !ruby/object:Gem::Version
37
- version: '0'
33
+ version: '1.2'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - "~>"
44
39
  - !ruby/object:Gem::Version
45
- version: '0'
46
- - !ruby/object:Gem::Dependency
47
- name: thin
48
- requirement: !ruby/object:Gem::Requirement
49
- none: false
50
- requirements:
51
- - - ! '>='
52
- - !ruby/object:Gem::Version
53
- version: '0'
54
- type: :runtime
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
- requirements:
59
- - - ! '>='
60
- - !ruby/object:Gem::Version
61
- version: '0'
40
+ version: '1.2'
62
41
  - !ruby/object:Gem::Dependency
63
42
  name: rake
64
43
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
44
  requirements:
67
- - - ! '>='
45
+ - - ">="
68
46
  - !ruby/object:Gem::Version
69
47
  version: '0'
70
48
  type: :development
71
49
  prerelease: false
72
50
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
51
  requirements:
75
- - - ! '>='
52
+ - - ">="
76
53
  - !ruby/object:Gem::Version
77
54
  version: '0'
78
55
  - !ruby/object:Gem::Dependency
79
56
  name: pry
80
57
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
58
  requirements:
83
- - - ! '>='
59
+ - - ">="
84
60
  - !ruby/object:Gem::Version
85
61
  version: '0'
86
62
  type: :development
87
63
  prerelease: false
88
64
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
65
  requirements:
91
- - - ! '>='
66
+ - - ">="
92
67
  - !ruby/object:Gem::Version
93
68
  version: '0'
94
69
  - !ruby/object:Gem::Dependency
95
70
  name: minitest
96
71
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
72
  requirements:
99
- - - ! '>='
73
+ - - ">="
100
74
  - !ruby/object:Gem::Version
101
75
  version: '0'
102
76
  type: :development
103
77
  prerelease: false
104
78
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
79
  requirements:
107
- - - ! '>='
80
+ - - ">="
108
81
  - !ruby/object:Gem::Version
109
82
  version: '0'
110
83
  - !ruby/object:Gem::Dependency
111
84
  name: mocha
112
85
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
86
  requirements:
115
- - - ! '>='
87
+ - - ">="
116
88
  - !ruby/object:Gem::Version
117
89
  version: '0'
118
90
  type: :development
119
91
  prerelease: false
120
92
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
93
  requirements:
123
- - - ! '>='
94
+ - - ">="
124
95
  - !ruby/object:Gem::Version
125
96
  version: '0'
126
97
  - !ruby/object:Gem::Dependency
127
98
  name: yard
128
99
  requirement: !ruby/object:Gem::Requirement
129
- none: false
130
100
  requirements:
131
- - - ! '>='
101
+ - - ">="
132
102
  - !ruby/object:Gem::Version
133
103
  version: '0'
134
104
  type: :development
135
105
  prerelease: false
136
106
  version_requirements: !ruby/object:Gem::Requirement
137
- none: false
138
107
  requirements:
139
- - - ! '>='
108
+ - - ">="
140
109
  - !ruby/object:Gem::Version
141
110
  version: '0'
142
111
  - !ruby/object:Gem::Dependency
143
112
  name: redcarpet
144
113
  requirement: !ruby/object:Gem::Requirement
145
- none: false
146
114
  requirements:
147
- - - ! '>='
115
+ - - ">="
148
116
  - !ruby/object:Gem::Version
149
117
  version: '0'
150
118
  type: :development
151
119
  prerelease: false
152
120
  version_requirements: !ruby/object:Gem::Requirement
153
- none: false
154
121
  requirements:
155
- - - ! '>='
122
+ - - ">="
156
123
  - !ruby/object:Gem::Version
157
124
  version: '0'
158
125
  - !ruby/object:Gem::Dependency
159
126
  name: github-markup
160
127
  requirement: !ruby/object:Gem::Requirement
161
- none: false
162
128
  requirements:
163
- - - ! '>='
129
+ - - ">="
164
130
  - !ruby/object:Gem::Version
165
131
  version: '0'
166
132
  type: :development
167
133
  prerelease: false
168
134
  version_requirements: !ruby/object:Gem::Requirement
169
- none: false
170
135
  requirements:
171
- - - ! '>='
136
+ - - ">="
172
137
  - !ruby/object:Gem::Version
173
138
  version: '0'
174
139
  description: A ruby client for Cloudera's Impala
@@ -178,8 +143,8 @@ executables: []
178
143
  extensions: []
179
144
  extra_rdoc_files: []
180
145
  files:
181
- - .gitignore
182
- - .travis.yml
146
+ - ".gitignore"
147
+ - ".travis.yml"
183
148
  - Gemfile
184
149
  - LICENSE.txt
185
150
  - README.md
@@ -207,6 +172,7 @@ files:
207
172
  - lib/impala/protocol/status_types.rb
208
173
  - lib/impala/protocol/t_c_l_i_service.rb
209
174
  - lib/impala/protocol/thrift_hive_metastore.rb
175
+ - lib/impala/sasl_transport.rb
210
176
  - lib/impala/version.rb
211
177
  - test/test_impala.rb
212
178
  - test/test_impala_connected.rb
@@ -219,29 +185,27 @@ files:
219
185
  homepage: https://github.com/colinmarc/impala-ruby
220
186
  licenses:
221
187
  - MIT
188
+ metadata: {}
222
189
  post_install_message:
223
190
  rdoc_options: []
224
191
  require_paths:
225
192
  - lib
226
193
  required_ruby_version: !ruby/object:Gem::Requirement
227
- none: false
228
194
  requirements:
229
- - - ! '>='
195
+ - - ">="
230
196
  - !ruby/object:Gem::Version
231
197
  version: '0'
232
198
  required_rubygems_version: !ruby/object:Gem::Requirement
233
- none: false
234
199
  requirements:
235
- - - ! '>='
200
+ - - ">="
236
201
  - !ruby/object:Gem::Version
237
202
  version: '0'
238
203
  requirements: []
239
204
  rubyforge_project:
240
- rubygems_version: 1.8.23
205
+ rubygems_version: 2.4.5.1
241
206
  signing_key:
242
- specification_version: 3
207
+ specification_version: 4
243
208
  summary: A ruby client for Cloudera's Impala
244
209
  test_files:
245
210
  - test/test_impala.rb
246
211
  - test/test_impala_connected.rb
247
- has_rdoc: