drill-sergeant 0.1.4 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a9a45ee9fd9196539d55c04641748ea43915edc39b2de7a57acc066ec829a493
4
- data.tar.gz: d38d61d15324267e96a19d93284cece7fdf37a035dccdc5eb7f3a73e0872c9fa
3
+ metadata.gz: 5f879931453d91603853f983a38e6ccbed7d15f6a3c4f4d83d0a92fa1b1bedf7
4
+ data.tar.gz: a9baa8c79b3edd26cc57836540129b591a789c4accbb8cb2881a8d2930a877fd
5
5
  SHA512:
6
- metadata.gz: 7bd8f5dc9e71be3bb905f092794ea5d91effae2dd80420f11d998382d5cee12d2945b856d06ae1f8248f27b7fbae4261a5280a72d53ea6c5501c479bdd538799
7
- data.tar.gz: f4fc88b864649e84dbb3115e15703897bd24e50f0eefc9c956b4163fbe6da8bb4c20a89f5008b06a915ad611f0a5539c35ba1096d314305c6c1d19190471c043
6
+ metadata.gz: ed5aa7562167c1fef98d29a72b805064180c9ad12296a75e66e6346dc71abc27c4cf4173e508c2c5510c73c39958ec9b278c64bc1885b012a64360c19105398f
7
+ data.tar.gz: d84e6181c5282c2f10a948d71f07169a8dfcb9f99c3d68f2edbbe8cc2bc3882af78ecb5ea82c4d99268fb7dac14f311608f34cf8cb1e926d2a76c7a1218de639
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## 0.3.0 (2024-10-22)
2
+
3
+ - Dropped support for Ruby < 3.1
4
+
5
+ ## 0.2.0 (2022-08-28)
6
+
7
+ - Added support for basic authentication
8
+ - Added `update_storage` and `delete_storage` methods
9
+ - Added `enable_storage` and `disable_storage` methods
10
+ - Added `cancel_query` method
11
+ - Dropped support for Ruby < 2.7
12
+
1
13
  ## 0.1.4 (2022-01-16)
2
14
 
3
15
  - 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/actions/workflows/build.yml/badge.svg)](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.3.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/version"
7
+ require_relative "drill/client"
8
+ require_relative "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.3.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: 2024-10-23 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: '3.1'
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.5.16
86
45
  signing_key:
87
46
  specification_version: 4
88
47
  summary: Ruby client for Apache Drill