drill-sergeant 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a9a45ee9fd9196539d55c04641748ea43915edc39b2de7a57acc066ec829a493
4
- data.tar.gz: d38d61d15324267e96a19d93284cece7fdf37a035dccdc5eb7f3a73e0872c9fa
3
+ metadata.gz: 4a3ea03aaaf7870b45a5fcf70d42a3dc471f8475daef5322ea988f253ed85f30
4
+ data.tar.gz: 1f1400fceea93d5a2f17c0ca39df950dc2d0db7fa4048821d9b89e9ac675e088
5
5
  SHA512:
6
- metadata.gz: 7bd8f5dc9e71be3bb905f092794ea5d91effae2dd80420f11d998382d5cee12d2945b856d06ae1f8248f27b7fbae4261a5280a72d53ea6c5501c479bdd538799
7
- data.tar.gz: f4fc88b864649e84dbb3115e15703897bd24e50f0eefc9c956b4163fbe6da8bb4c20a89f5008b06a915ad611f0a5539c35ba1096d314305c6c1d19190471c043
6
+ metadata.gz: feaa39c2ca86d34d7468a229f8371396b4f26dc560584181975d8fa28d36d8ab3d19456493d9fb92f6953b8f8c4741a66e4922472f62f94c30188017c57ab417
7
+ data.tar.gz: 486ea96149e0b3cfe321797fd1f0083e6ba83f19afed099476d1eae4d1f54e053c985b6c0963f66d932aad90cfaef2070ef4eb71d1a6ea255cce631352da8ce9
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 0.2.0 (2022-08-28)
2
+
3
+ - Added support for basic authentication
4
+ - Added `update_storage` and `delete_storage` methods
5
+ - Added `enable_storage` and `disable_storage` methods
6
+ - Added `cancel_query` method
7
+ - Dropped support for Ruby < 2.7
8
+
1
9
  ## 0.1.4 (2022-01-16)
2
10
 
3
11
  - Added `server_version` method
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2017-2020 Andrew Kane
1
+ Copyright (c) 2017-2022 Andrew Kane
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,12 +1,12 @@
1
- # Drill Sergeant
1
+ # Drill Ruby
2
2
 
3
3
  Ruby client for Apache Drill
4
4
 
5
- [![Build Status](https://github.com/ankane/drill-sergeant/workflows/build/badge.svg?branch=master)](https://github.com/ankane/drill-sergeant/actions)
5
+ [![Build Status](https://github.com/ankane/drill-ruby/workflows/build/badge.svg?branch=master)](https://github.com/ankane/drill-ruby/actions)
6
6
 
7
7
  ## Installation
8
8
 
9
- First, [install Apache Drill](https://drill.apache.org/docs/installing-drill-on-linux-and-mac-os-x/). For Homebrew, use:
9
+ First, [install Apache Drill](https://drill.apache.org/docs/install-drill-introduction/). For Homebrew, use:
10
10
 
11
11
  ```sh
12
12
  brew install apache-drill
@@ -19,12 +19,12 @@ And add this line to your application’s Gemfile:
19
19
  gem "drill-sergeant"
20
20
  ```
21
21
 
22
- ## How to Use
22
+ ## Getting Started
23
23
 
24
24
  Create a client
25
25
 
26
26
  ```ruby
27
- drill = Drill.new(url: "http://localhost:8047")
27
+ drill = Drill::Client.new(url: "http://localhost:8047")
28
28
  ```
29
29
 
30
30
  And query away
@@ -37,30 +37,86 @@ drill.query("SELECT * FROM dfs.`/path/to/some/file.csvh`")
37
37
 
38
38
  [API docs](https://drill.apache.org/docs/rest-api-introduction/)
39
39
 
40
- Get profiles
40
+ ### Query
41
+
42
+ Run a query
43
+
44
+ ```ruby
45
+ drill.query(
46
+ query,
47
+ limit: nil,
48
+ default_schema: nil,
49
+ username: nil
50
+ )
51
+ ```
52
+
53
+ ### Profiles
54
+
55
+ Get profiles of running and completed queries
41
56
 
42
57
  ```ruby
43
58
  drill.profiles
44
59
  ```
45
60
 
46
- Get profile by query id
61
+ Get the profile of a query
47
62
 
48
63
  ```ruby
49
64
  drill.profiles(query_id)
50
65
  ```
51
66
 
52
- Get storage
67
+ Cancel a query
68
+
69
+ ```ruby
70
+ drill.cancel_query(query_id)
71
+ ```
72
+
73
+ ### Storage
74
+
75
+ List storage plugins
53
76
 
54
77
  ```ruby
55
78
  drill.storage
56
79
  ```
57
80
 
58
- Get storage by name
81
+ Get a storage plugin by name
59
82
 
60
83
  ```ruby
61
84
  drill.storage(name)
62
85
  ```
63
86
 
87
+ Enable a storage plugin
88
+
89
+ ```ruby
90
+ drill.enable_storage(name)
91
+ ```
92
+
93
+ Disable a storage plugin
94
+
95
+ ```ruby
96
+ drill.disable_storage(name)
97
+ ```
98
+
99
+ Create or update a storage plugin
100
+
101
+ ```ruby
102
+ drill.update_storage(
103
+ name,
104
+ type: nil,
105
+ enabled: nil,
106
+ connection: nil,
107
+ workspaces: nil,
108
+ formats: nil
109
+ )
110
+ ```
111
+
112
+ Delete a storage plugin
113
+
114
+ ```ruby
115
+ drill.delete_storage(name)
116
+ ```
117
+
118
+ ### Info
119
+
64
120
  Get cluster info
65
121
 
66
122
  ```ruby
@@ -84,27 +140,27 @@ drill.options
84
140
  Set timeouts
85
141
 
86
142
  ```ruby
87
- Drill.new(open_timeout: 5, read_timeout: 120)
143
+ Drill::Client.new(open_timeout: 5, read_timeout: 120)
88
144
  ```
89
145
 
90
146
  ## History
91
147
 
92
- View the [changelog](https://github.com/ankane/drill-sergeant/blob/master/CHANGELOG.md)
148
+ View the [changelog](CHANGELOG.md)
93
149
 
94
150
  ## Contributing
95
151
 
96
152
  Everyone is encouraged to help improve this project. Here are a few ways you can help:
97
153
 
98
- - [Report bugs](https://github.com/ankane/drill-sergeant/issues)
99
- - Fix bugs and [submit pull requests](https://github.com/ankane/drill-sergeant/pulls)
154
+ - [Report bugs](https://github.com/ankane/drill-ruby/issues)
155
+ - Fix bugs and [submit pull requests](https://github.com/ankane/drill-ruby/pulls)
100
156
  - Write, clarify, or fix documentation
101
157
  - Suggest or add new features
102
158
 
103
159
  To get started with development:
104
160
 
105
161
  ```sh
106
- git clone https://github.com/ankane/drill-sergeant.git
107
- cd drill-sergeant
162
+ git clone https://github.com/ankane/drill-ruby.git
163
+ cd drill-ruby
108
164
  bundle install
109
165
  bundle exec rake test
110
166
  ```
@@ -0,0 +1,164 @@
1
+ module Drill
2
+ class Client
3
+ HEADERS = {
4
+ "Content-Type" => "application/json",
5
+ "Accept" => "application/json"
6
+ }
7
+
8
+ def initialize(url: nil, open_timeout: 3, read_timeout: nil)
9
+ url ||= ENV["DRILL_URL"] || "http://localhost:8047"
10
+ # remove trailing slash
11
+ @uri = URI.parse(url.chomp("/"))
12
+ @http = Net::HTTP.new(@uri.host, @uri.port)
13
+ @http.use_ssl = true if @uri.scheme == "https"
14
+ @http.open_timeout = open_timeout if open_timeout
15
+ @http.read_timeout = read_timeout if read_timeout
16
+ end
17
+
18
+ def query(statement, limit: nil, default_schema: nil, username: nil)
19
+ options = {}
20
+ if Gem::Version.new(server_version) >= Gem::Version.new("1.19.0")
21
+ options["drill.exec.http.rest.errors.verbose"] = true
22
+ end
23
+
24
+ data = {
25
+ query: statement,
26
+ options: options
27
+ }
28
+ data[:autoLimit] = limit if limit
29
+ data[:defaultSchema] = default_schema if default_schema
30
+ data[:userName] = username if username
31
+
32
+ run_query(data)
33
+ end
34
+
35
+ def profiles(query_id = nil)
36
+ path = query_id ? "profiles/#{escape_path(query_id)}.json" : "profiles.json"
37
+ get(path)
38
+ end
39
+
40
+ def cancel_query(query_id)
41
+ get("profiles/cancel/#{escape_path(query_id)}")
42
+ end
43
+
44
+ def storage(name = nil)
45
+ path = name ? "storage/#{escape_path(name)}.json" : "storage.json"
46
+ get(path)
47
+ end
48
+
49
+ def enable_storage(name)
50
+ get("storage/#{escape_path(name)}/enable/true")
51
+ end
52
+
53
+ def disable_storage(name)
54
+ get("storage/#{escape_path(name)}/enable/false")
55
+ end
56
+
57
+ def update_storage(name, type:, enabled:, connection:, workspaces:, formats:)
58
+ data = {
59
+ name: name,
60
+ config: {
61
+ type: type,
62
+ enabled: enabled,
63
+ connection: connection,
64
+ workspaces: workspaces,
65
+ formats: formats
66
+ }
67
+ }
68
+ post("storage/#{escape_path(name)}.json", data)
69
+ end
70
+
71
+ def delete_storage(name)
72
+ delete("storage/#{escape_path(name)}.json")
73
+ end
74
+
75
+ def cluster
76
+ get("cluster.json")
77
+ end
78
+
79
+ # status does not return json
80
+
81
+ def metrics
82
+ # no .json suffix
83
+ get("status/metrics")
84
+ end
85
+
86
+ # threads does not return json
87
+
88
+ def options
89
+ get("options.json")
90
+ end
91
+
92
+ def server_version
93
+ @server_version ||= run_query({query: "SELECT version FROM sys.version"})[0]["version"]
94
+ end
95
+
96
+ # @uri may contain sensitive info
97
+ def inspect
98
+ to_s
99
+ end
100
+
101
+ private
102
+
103
+ def run_query(data)
104
+ data[:queryType] ||= "sql"
105
+
106
+ body = post("query.json", data)
107
+
108
+ # errors return 200 with Drill 1.19+
109
+ if body["queryState"] != "COMPLETED"
110
+ raise Error, body["errorMessage"] || "Bad state: #{body["queryState"]}"
111
+ end
112
+
113
+ # return columns in order
114
+ result = []
115
+ columns = body["columns"]
116
+ body["rows"].each do |row|
117
+ result << columns.each_with_object({}) { |c, memo| memo[c] = row[c] }
118
+ end
119
+ result
120
+ end
121
+
122
+ def get(path)
123
+ handle_response do
124
+ Net::HTTP::Get.new("#{@uri.request_uri}#{path}", HEADERS)
125
+ end
126
+ end
127
+
128
+ def post(path, data)
129
+ handle_response do
130
+ req = Net::HTTP::Post.new("#{@uri.request_uri}#{path}", HEADERS)
131
+ req.body = data.to_json
132
+ req
133
+ end
134
+ end
135
+
136
+ def delete(path)
137
+ handle_response do
138
+ Net::HTTP::Delete.new("#{@uri.request_uri}#{path}", HEADERS)
139
+ end
140
+ end
141
+
142
+ def handle_response
143
+ begin
144
+ req = yield
145
+ req.basic_auth(@uri.user, @uri.password) if @uri.user || @uri.password
146
+ response = @http.request(req)
147
+ rescue Errno::ECONNREFUSED => e
148
+ raise Error, e.message
149
+ end
150
+
151
+ unless response.kind_of?(Net::HTTPSuccess)
152
+ body = JSON.parse(response.body) rescue {}
153
+ message = body["errorMessage"] || "Bad response: #{response.code}"
154
+ raise Error, message
155
+ end
156
+
157
+ JSON.parse(response.body)
158
+ end
159
+
160
+ def escape_path(path)
161
+ CGI.escape(path).gsub("+", "%20")
162
+ end
163
+ end
164
+ end
data/lib/drill/version.rb CHANGED
@@ -1,3 +1,3 @@
1
- class Drill
2
- VERSION = "0.1.4"
1
+ module Drill
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,119 +1,16 @@
1
- # dependencies
1
+ # stdlib
2
2
  require "cgi"
3
3
  require "json"
4
4
  require "net/http"
5
5
 
6
6
  # modules
7
+ require "drill/client"
7
8
  require "drill/version"
8
9
 
9
- # TODO make module and move to client
10
- class Drill
10
+ module Drill
11
11
  class Error < StandardError; end
12
12
 
13
- HEADERS = {
14
- "Content-Type" => "application/json",
15
- "Accept" => "application/json"
16
- }
17
-
18
- def initialize(url: nil, open_timeout: 3, read_timeout: nil)
19
- url ||= ENV["DRILL_URL"] || "http://localhost:8047"
20
- # remove trailing slash
21
- @uri = URI.parse(url.chomp("/"))
22
- @http = Net::HTTP.new(@uri.host, @uri.port)
23
- @http.use_ssl = true if @uri.scheme == "https"
24
- @http.open_timeout = open_timeout if open_timeout
25
- @http.read_timeout = read_timeout if read_timeout
26
- end
27
-
28
- def query(statement)
29
- options = {}
30
- if Gem::Version.new(server_version) >= Gem::Version.new("1.19.0")
31
- options["drill.exec.http.rest.errors.verbose"] = true
32
- end
33
- run_query(statement, options)
34
- end
35
-
36
- def profiles(query_id = nil)
37
- path = query_id ? "profiles/#{escape_path(query_id)}.json" : "profiles.json"
38
- get(path)
39
- end
40
-
41
- def storage(name = nil)
42
- path = name ? "storage/#{escape_path(name)}.json" : "storage.json"
43
- get(path)
44
- end
45
-
46
- def cluster
47
- get("cluster.json")
48
- end
49
-
50
- def metrics
51
- # no .json suffix
52
- get("status/metrics")
53
- end
54
-
55
- def options
56
- get("options.json")
57
- end
58
-
59
- def server_version
60
- @server_version ||= run_query("SELECT version FROM sys.version", {})[0]["version"]
61
- end
62
-
63
- private
64
-
65
- def run_query(statement, options)
66
- data = {
67
- queryType: "sql",
68
- query: statement,
69
- options: options
70
- }
71
-
72
- body = post("query.json", data)
73
-
74
- # errors return 200 with Drill 1.19+
75
- if body["queryState"] != "COMPLETED"
76
- raise Error, body["errorMessage"] || "Bad state: #{body["queryState"]}"
77
- end
78
-
79
- # return columns in order
80
- result = []
81
- columns = body["columns"]
82
- body["rows"].each do |row|
83
- result << columns.each_with_object({}) { |c, memo| memo[c] = row[c] }
84
- end
85
- result
86
- end
87
-
88
- def get(path)
89
- handle_response do
90
- @http.get("#{@uri.request_uri}#{path}", HEADERS)
91
- end
92
- end
93
-
94
- def post(path, data)
95
- handle_response do
96
- @http.post("#{@uri.request_uri}#{path}", data.to_json, HEADERS)
97
- end
98
- end
99
-
100
- def handle_response
101
- begin
102
- response = yield
103
- rescue Errno::ECONNREFUSED => e
104
- raise Error, e.message
105
- end
106
-
107
- unless response.kind_of?(Net::HTTPSuccess)
108
- body = JSON.parse(response.body) rescue {}
109
- message = body["errorMessage"] || "Bad response: #{response.code}"
110
- raise Error, message
111
- end
112
-
113
- JSON.parse(response.body)
114
- end
115
-
116
- def escape_path(path)
117
- CGI.escape(path).gsub("+", "%20")
13
+ def self.new(**options)
14
+ Client.new(**options)
118
15
  end
119
16
  end
metadata CHANGED
@@ -1,59 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: drill-sergeant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-16 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: rake
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: minitest
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
11
+ date: 2022-08-29 00:00:00.000000000 Z
12
+ dependencies: []
55
13
  description:
56
- email: andrew@chartkick.com
14
+ email: andrew@ankane.org
57
15
  executables: []
58
16
  extensions: []
59
17
  extra_rdoc_files: []
@@ -62,8 +20,9 @@ files:
62
20
  - LICENSE.txt
63
21
  - README.md
64
22
  - lib/drill-sergeant.rb
23
+ - lib/drill/client.rb
65
24
  - lib/drill/version.rb
66
- homepage: https://github.com/ankane/drill-sergeant
25
+ homepage: https://github.com/ankane/drill-ruby
67
26
  licenses:
68
27
  - MIT
69
28
  metadata: {}
@@ -75,14 +34,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
75
34
  requirements:
76
35
  - - ">="
77
36
  - !ruby/object:Gem::Version
78
- version: '2.4'
37
+ version: '2.7'
79
38
  required_rubygems_version: !ruby/object:Gem::Requirement
80
39
  requirements:
81
40
  - - ">="
82
41
  - !ruby/object:Gem::Version
83
42
  version: '0'
84
43
  requirements: []
85
- rubygems_version: 3.3.3
44
+ rubygems_version: 3.3.7
86
45
  signing_key:
87
46
  specification_version: 4
88
47
  summary: Ruby client for Apache Drill