td-client 0.8.68 → 0.8.69
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 +4 -4
- data/lib/td/client.rb +250 -57
- data/lib/td/client/api.rb +125 -7
- data/lib/td/client/api/access_control.rb +14 -2
- data/lib/td/client/api/account.rb +4 -0
- data/lib/td/client/api/bulk_import.rb +41 -11
- data/lib/td/client/api/bulk_load.rb +205 -0
- data/lib/td/client/api/database.rb +6 -3
- data/lib/td/client/api/export.rb +5 -0
- data/lib/td/client/api/import.rb +7 -1
- data/lib/td/client/api/job.rb +49 -5
- data/lib/td/client/api/partial_delete.rb +6 -0
- data/lib/td/client/api/result.rb +7 -2
- data/lib/td/client/api/schedule.rb +17 -3
- data/lib/td/client/api/server_status.rb +1 -0
- data/lib/td/client/api/table.rb +41 -6
- data/lib/td/client/api/to_hash_struct.rb +82 -0
- data/lib/td/client/api/user.rb +27 -10
- data/lib/td/client/compat_gzip_reader.rb +3 -0
- data/lib/td/client/model.rb +209 -0
- data/lib/td/client/version.rb +1 -1
- data/spec/spec_helper.rb +14 -6
- data/spec/td/client/bulk_load_spec.rb +358 -0
- data/spec/td/client/job_api_spec.rb +10 -8
- data/spec/td/client_sched_spec.rb +1 -1
- metadata +96 -35
@@ -0,0 +1,205 @@
|
|
1
|
+
require 'td/client/api/to_hash_struct'
|
2
|
+
|
3
|
+
class TreasureData::API
|
4
|
+
module BulkLoad
|
5
|
+
|
6
|
+
####
|
7
|
+
## BulkLoad (Server-side Bulk loader) API
|
8
|
+
##
|
9
|
+
|
10
|
+
# 1. POST /v3/bulk_loads/guess - stateless non REST API to return guess result as BulkLoadSession [NEW]
|
11
|
+
# 2. POST /v3/bulk_loads/preview - stateless non REST API to return preview result as BulkLoadSession [NEW]
|
12
|
+
#
|
13
|
+
# 3. POST /v3/job/issue/:type/:database - create a job resource to run BulkLoadSession [EXTENDED]
|
14
|
+
# 4. POST /v3/job/kill/:id - kill the job [ALREADY EXISTS]
|
15
|
+
# 5. GET /v3/job/show/:id - get status of the job [ALREADY EXISTS]
|
16
|
+
# 6. GET /v3/job/result/:id - get result of the job [NOT NEEDED IN Q4] ... because backend feature is not yet implemented
|
17
|
+
#
|
18
|
+
# 7. GET /v3/bulk_loads - list BulkLoadSession resources [NEW]
|
19
|
+
# 8. POST /v3/bulk_loads - create BulkLoadSession [NEW]
|
20
|
+
# 9. GET /v3/bulk_loads/:name - get BulkLoadSession [NEW]
|
21
|
+
# 10. PUT /v3/bulk_loads/:name - update BulkLoadSession [NEW]
|
22
|
+
# 11. DELETE /v3/bulk_loads/:name - delete BulkLoadSession [NEW]
|
23
|
+
# 12. GET /v3/bulk_loads/:name/jobs - list BulkLoadSession job history [NEW]
|
24
|
+
# 13. POST /v3/bulk_loads/:name/jobs - run BulkLoadSession [NEW]
|
25
|
+
|
26
|
+
# The 'BulkLoadSession' resource in td-api is as follows;
|
27
|
+
# {
|
28
|
+
# "config": {
|
29
|
+
# "type": "s3",
|
30
|
+
# "access_key_id": s3 access key id,
|
31
|
+
# "secret_access_key": s3 secret key,
|
32
|
+
# "endpoint": s3 endpoint name,
|
33
|
+
# "bucket": s3 bucket name,
|
34
|
+
# "path_prefix": "a/prefix/of/files",
|
35
|
+
# "decoders": []
|
36
|
+
# },
|
37
|
+
# "name": account_wide_unique_name,
|
38
|
+
# "cron": cron_string,
|
39
|
+
# "timezone": timezone_string,
|
40
|
+
# "delay": delay_seconds,
|
41
|
+
# "database": database_name,
|
42
|
+
# "table": table_name
|
43
|
+
# }
|
44
|
+
|
45
|
+
## Resource definitions
|
46
|
+
|
47
|
+
class BulkLoad < ToHashStruct.new(:config, :name, :cron, :timezone, :delay, :time_column, :database, :table)
|
48
|
+
class BulkLoadSessionConfig < ToHashStruct.new(:type, :access_key_id, :secret_access_key, :endpoint, :bucket, :path_prefix, :parser, :decoders)
|
49
|
+
def validate_self
|
50
|
+
validate_presence_of :type
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
model_property :config, BulkLoadSessionConfig
|
55
|
+
|
56
|
+
def validate_self
|
57
|
+
validate_presence_of :config
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class BulkLoadPreview < ToHashStruct.new(:schema, :records)
|
62
|
+
end
|
63
|
+
|
64
|
+
class Job < ToHashStruct.new(:job_id, :account_id, :type, :status, :cpu_time, :config, :records, :schema, :database, :table, :priority, :created_at, :updated_at, :start_at, :end_at)
|
65
|
+
model_property :config, BulkLoad::BulkLoadSessionConfig
|
66
|
+
end
|
67
|
+
|
68
|
+
## API definitions
|
69
|
+
|
70
|
+
LIST = '/v3/bulk_loads'
|
71
|
+
SESSION = LIST + '/%s'
|
72
|
+
JOB = SESSION + '/jobs'
|
73
|
+
|
74
|
+
# job: BulkLoad -> BulkLoad
|
75
|
+
def bulk_load_guess(job)
|
76
|
+
# retry_request = true
|
77
|
+
path = LIST + '/guess'
|
78
|
+
res = api { post(path, job.validate.to_json) }
|
79
|
+
unless res.ok?
|
80
|
+
raise_error('BulkLoad configuration guess failed', res)
|
81
|
+
end
|
82
|
+
BulkLoad.from_json(res.body)
|
83
|
+
end
|
84
|
+
|
85
|
+
# job: BulkLoad -> BulkLoadPreview
|
86
|
+
def bulk_load_preview(job)
|
87
|
+
# retry_request = true
|
88
|
+
path = LIST + '/preview'
|
89
|
+
res = api { post(path, job.validate.to_json) }
|
90
|
+
unless res.ok?
|
91
|
+
raise_error('BulkLoad job preview failed', res)
|
92
|
+
end
|
93
|
+
BulkLoadPreview.from_json(res.body)
|
94
|
+
end
|
95
|
+
|
96
|
+
# job: BulkLoad -> String (job_id)
|
97
|
+
def bulk_load_issue(database, table, job)
|
98
|
+
type = 'bulkload'
|
99
|
+
job = job.dup
|
100
|
+
job['database'] = database
|
101
|
+
job['table'] = table
|
102
|
+
path = "/v3/job/issue/#{e type}/#{e database}"
|
103
|
+
res = api { post(path, job.validate.to_json) }
|
104
|
+
unless res.ok?
|
105
|
+
raise_error('BulkLoad job issuing failed', res)
|
106
|
+
end
|
107
|
+
js = checked_json(res.body)
|
108
|
+
js['job_id'].to_s
|
109
|
+
end
|
110
|
+
|
111
|
+
# nil -> [BulkLoad]
|
112
|
+
def bulk_load_list
|
113
|
+
res = api { get(LIST) }
|
114
|
+
unless res.ok?
|
115
|
+
raise_error("BulkLoadSession list retrieve failed", res)
|
116
|
+
end
|
117
|
+
to_ary(res, BulkLoad)
|
118
|
+
end
|
119
|
+
|
120
|
+
# name: String, database: String, table: String, job: BulkLoad -> BulkLoad
|
121
|
+
def bulk_load_create(name, database, table, job, opts = {})
|
122
|
+
job = job.dup
|
123
|
+
job['name'] = name
|
124
|
+
[:cron, :timezone, :delay, :time_column].each do |prop|
|
125
|
+
job[prop.to_s] = opts[prop] if opts.key?(prop)
|
126
|
+
end
|
127
|
+
job['database'] = database
|
128
|
+
job['table'] = table
|
129
|
+
res = api { post(LIST, job.validate.to_json) }
|
130
|
+
unless res.ok?
|
131
|
+
raise_error("BulkLoadSession: #{name} create failed", res)
|
132
|
+
end
|
133
|
+
BulkLoad.from_json(res.body)
|
134
|
+
end
|
135
|
+
|
136
|
+
# name: String -> BulkLoad
|
137
|
+
def bulk_load_show(name)
|
138
|
+
path = session_path(name)
|
139
|
+
res = api { get(path) }
|
140
|
+
unless res.ok?
|
141
|
+
raise_error("BulkLoadSession: #{name} retrieve failed", res)
|
142
|
+
end
|
143
|
+
BulkLoad.from_json(res.body)
|
144
|
+
end
|
145
|
+
|
146
|
+
# name: String, job: BulkLoad -> BulkLoad
|
147
|
+
def bulk_load_update(name, job)
|
148
|
+
path = session_path(name)
|
149
|
+
res = api { put(path, job.validate.to_json) }
|
150
|
+
unless res.ok?
|
151
|
+
raise_error("BulkLoadSession: #{name} update failed", res)
|
152
|
+
end
|
153
|
+
BulkLoad.from_json(res.body)
|
154
|
+
end
|
155
|
+
|
156
|
+
# name: String -> BulkLoad
|
157
|
+
def bulk_load_delete(name)
|
158
|
+
path = session_path(name)
|
159
|
+
res = api { delete(path) }
|
160
|
+
unless res.ok?
|
161
|
+
raise_error("BulkLoadSession: #{name} delete failed", res)
|
162
|
+
end
|
163
|
+
BulkLoad.from_json(res.body)
|
164
|
+
end
|
165
|
+
|
166
|
+
# name: String -> [Job]
|
167
|
+
def bulk_load_history(name)
|
168
|
+
path = job_path(name)
|
169
|
+
res = api { get(path) }
|
170
|
+
unless res.ok?
|
171
|
+
raise_error("history of BulkLoadSession: #{name} retrieve failed", res)
|
172
|
+
end
|
173
|
+
to_ary(res, Job)
|
174
|
+
end
|
175
|
+
|
176
|
+
def bulk_load_run(name, scheduled_time = nil)
|
177
|
+
path = job_path(name)
|
178
|
+
opts = {}
|
179
|
+
opts[:scheduled_time] = scheduled_time unless scheduled_time.nil?
|
180
|
+
res = api { post(path, opts) }
|
181
|
+
unless res.ok?
|
182
|
+
raise_error("BulkLoadSession: #{name} job create failed", res)
|
183
|
+
end
|
184
|
+
js = checked_json(res.body)
|
185
|
+
js['job_id'].to_s
|
186
|
+
end
|
187
|
+
|
188
|
+
private
|
189
|
+
|
190
|
+
def session_path(name)
|
191
|
+
SESSION % e(name)
|
192
|
+
end
|
193
|
+
|
194
|
+
def job_path(name)
|
195
|
+
JOB % e(name)
|
196
|
+
end
|
197
|
+
|
198
|
+
def to_ary(res, klass)
|
199
|
+
JSON.parse(res.body).map { |bulk_load|
|
200
|
+
klass.from_hash(bulk_load)
|
201
|
+
}
|
202
|
+
end
|
203
|
+
|
204
|
+
end
|
205
|
+
end
|
@@ -5,7 +5,7 @@ module Database
|
|
5
5
|
## Database API
|
6
6
|
##
|
7
7
|
|
8
|
-
#
|
8
|
+
# @return [Array<String>] names as array
|
9
9
|
def list_databases
|
10
10
|
code, body, res = get("/v3/database/list")
|
11
11
|
if code != "200"
|
@@ -24,7 +24,8 @@ module Database
|
|
24
24
|
return result
|
25
25
|
end
|
26
26
|
|
27
|
-
#
|
27
|
+
# @param [String] db
|
28
|
+
# @return [true]
|
28
29
|
def delete_database(db)
|
29
30
|
code, body, res = post("/v3/database/delete/#{e db}")
|
30
31
|
if code != "200"
|
@@ -33,7 +34,9 @@ module Database
|
|
33
34
|
return true
|
34
35
|
end
|
35
36
|
|
36
|
-
#
|
37
|
+
# @param [String] db
|
38
|
+
# @param [Hash] opts
|
39
|
+
# @return [true]
|
37
40
|
def create_database(db, opts={})
|
38
41
|
params = opts.dup
|
39
42
|
code, body, res = post("/v3/database/create/#{e db}", params)
|
data/lib/td/client/api/export.rb
CHANGED
@@ -6,6 +6,11 @@ module Export
|
|
6
6
|
##
|
7
7
|
|
8
8
|
# => jobId:String
|
9
|
+
# @param [String] db
|
10
|
+
# @param [String] table
|
11
|
+
# @param [String] storage_type
|
12
|
+
# @param [Hash] opts
|
13
|
+
# @return [String] job_id
|
9
14
|
def export(db, table, storage_type, opts={})
|
10
15
|
params = opts.dup
|
11
16
|
params['storage_type'] = storage_type
|
data/lib/td/client/api/import.rb
CHANGED
@@ -5,7 +5,13 @@ module Import
|
|
5
5
|
## Import API
|
6
6
|
##
|
7
7
|
|
8
|
-
#
|
8
|
+
# @param [String] db
|
9
|
+
# @param [String] table
|
10
|
+
# @param [String] format
|
11
|
+
# @param [String, StringIO] stream
|
12
|
+
# @param [Fixnum] size
|
13
|
+
# @param [String] unique_id
|
14
|
+
# @return [Float] elapsed time
|
9
15
|
def import(db, table, format, stream, size, unique_id=nil)
|
10
16
|
if unique_id
|
11
17
|
path = "/v3/table/import_with_id/#{e db}/#{e table}/#{unique_id}/#{format}"
|
data/lib/td/client/api/job.rb
CHANGED
@@ -5,7 +5,11 @@ module Job
|
|
5
5
|
## Job API
|
6
6
|
##
|
7
7
|
|
8
|
-
#
|
8
|
+
# @param [Fixnum] from
|
9
|
+
# @param [Fixnum] to
|
10
|
+
# @param [String] status
|
11
|
+
# @param [Hash] conditions
|
12
|
+
# @return [Array]
|
9
13
|
def list_jobs(from=0, to=nil, status=nil, conditions=nil)
|
10
14
|
params = {}
|
11
15
|
params['from'] = from.to_s if from
|
@@ -37,7 +41,8 @@ module Job
|
|
37
41
|
return result
|
38
42
|
end
|
39
43
|
|
40
|
-
#
|
44
|
+
# @param [String] job_id
|
45
|
+
# @return [Array]
|
41
46
|
def show_job(job_id)
|
42
47
|
# use v3/job/status instead of v3/job/show to poll finish of a job
|
43
48
|
code, body, res = get("/v3/job/show/#{e job_id}")
|
@@ -93,6 +98,8 @@ module Job
|
|
93
98
|
result_size, result, hive_result_schema, priority, retry_limit, nil, database]
|
94
99
|
end
|
95
100
|
|
101
|
+
# @param [String] job_id
|
102
|
+
# @return [String] HTTP status
|
96
103
|
def job_status(job_id)
|
97
104
|
code, body, res = get("/v3/job/status/#{e job_id}")
|
98
105
|
if code != "200"
|
@@ -103,6 +110,8 @@ module Job
|
|
103
110
|
return js['status']
|
104
111
|
end
|
105
112
|
|
113
|
+
# @param [String] job_id
|
114
|
+
# @return [Array]
|
106
115
|
def job_result(job_id)
|
107
116
|
code, body, res = get("/v3/job/result/#{e job_id}", {'format'=>'msgpack'})
|
108
117
|
if code != "200"
|
@@ -116,6 +125,12 @@ module Job
|
|
116
125
|
end
|
117
126
|
|
118
127
|
# block is optional and must accept 1 parameter
|
128
|
+
#
|
129
|
+
# @param [String] job_id
|
130
|
+
# @param [String] format
|
131
|
+
# @param [IO] io
|
132
|
+
# @param [Proc] block
|
133
|
+
# @return [nil, String]
|
119
134
|
def job_result_format(job_id, format, io=nil, &block)
|
120
135
|
if io
|
121
136
|
code, body, res = get("/v3/job/result/#{e job_id}", {'format'=>format}) {|res|
|
@@ -159,6 +174,10 @@ module Job
|
|
159
174
|
end
|
160
175
|
|
161
176
|
# block is optional and must accept 1 argument
|
177
|
+
#
|
178
|
+
# @param [String] job_id
|
179
|
+
# @param [Proc] block
|
180
|
+
# @return [nil]
|
162
181
|
def job_result_each(job_id, &block)
|
163
182
|
get("/v3/job/result/#{e job_id}", {'format'=>'msgpack'}) {|res|
|
164
183
|
if res.code != "200"
|
@@ -177,6 +196,10 @@ module Job
|
|
177
196
|
end
|
178
197
|
|
179
198
|
# block is optional and must accept 1 argument
|
199
|
+
#
|
200
|
+
# @param [String] job_id
|
201
|
+
# @param [Proc] block
|
202
|
+
# @return [nil]
|
180
203
|
def job_result_each_with_compr_size(job_id, &block)
|
181
204
|
get("/v3/job/result/#{e job_id}", {'format'=>'msgpack'}) {|res|
|
182
205
|
if res.code != "200"
|
@@ -205,6 +228,9 @@ module Job
|
|
205
228
|
nil
|
206
229
|
end
|
207
230
|
|
231
|
+
# @param [String] job_id
|
232
|
+
# @param [String] format
|
233
|
+
# @return [String]
|
208
234
|
def job_result_raw(job_id, format)
|
209
235
|
code, body, res = get("/v3/job/result/#{e job_id}", {'format'=>format})
|
210
236
|
if code != "200"
|
@@ -213,6 +239,8 @@ module Job
|
|
213
239
|
return body
|
214
240
|
end
|
215
241
|
|
242
|
+
# @param [String] job_id
|
243
|
+
# @return [String]
|
216
244
|
def kill(job_id)
|
217
245
|
code, body, res = post("/v3/job/kill/#{e job_id}")
|
218
246
|
if code != "200"
|
@@ -223,17 +251,33 @@ module Job
|
|
223
251
|
return former_status
|
224
252
|
end
|
225
253
|
|
226
|
-
#
|
254
|
+
# @param [String] q
|
255
|
+
# @param [String] db
|
256
|
+
# @param [String] result_url
|
257
|
+
# @param [Fixnum] priority
|
258
|
+
# @param [Hash] opts
|
259
|
+
# @return [String] job_id
|
227
260
|
def hive_query(q, db=nil, result_url=nil, priority=nil, retry_limit=nil, opts={})
|
228
261
|
query(q, :hive, db, result_url, priority, retry_limit, opts)
|
229
262
|
end
|
230
263
|
|
231
|
-
#
|
264
|
+
# @param [String] q
|
265
|
+
# @param [String] db
|
266
|
+
# @param [String] result_url
|
267
|
+
# @param [Fixnum] priority
|
268
|
+
# @param [Hash] opts
|
269
|
+
# @return [String] job_id
|
232
270
|
def pig_query(q, db=nil, result_url=nil, priority=nil, retry_limit=nil, opts={})
|
233
271
|
query(q, :pig, db, result_url, priority, retry_limit, opts)
|
234
272
|
end
|
235
273
|
|
236
|
-
#
|
274
|
+
# @param [String] q
|
275
|
+
# @param [Symbol] type
|
276
|
+
# @param [String] db
|
277
|
+
# @param [String] result_url
|
278
|
+
# @param [Fixnum] priority
|
279
|
+
# @param [Hash] opts
|
280
|
+
# @return [String] job_id
|
237
281
|
def query(q, type=:hive, db=nil, result_url=nil, priority=nil, retry_limit=nil, opts={})
|
238
282
|
params = {'query' => q}.merge(opts)
|
239
283
|
params['result'] = result_url if result_url
|
@@ -5,6 +5,12 @@ module PartialDelete
|
|
5
5
|
## Partial delete API
|
6
6
|
##
|
7
7
|
|
8
|
+
# @param [String] db
|
9
|
+
# @param [String] table
|
10
|
+
# @param [Fixnum] to
|
11
|
+
# @param [Fixnum] from
|
12
|
+
# @param [Hash] opts
|
13
|
+
# @return [String]
|
8
14
|
def partial_delete(db, table, to, from, opts={})
|
9
15
|
params = opts.dup
|
10
16
|
params['to'] = to.to_s
|
data/lib/td/client/api/result.rb
CHANGED
@@ -5,6 +5,7 @@ module Result
|
|
5
5
|
## Result API
|
6
6
|
##
|
7
7
|
|
8
|
+
# @return [Array<String>]
|
8
9
|
def list_result
|
9
10
|
code, body, res = get("/v3/result/list")
|
10
11
|
if code != "200"
|
@@ -18,7 +19,10 @@ module Result
|
|
18
19
|
return result
|
19
20
|
end
|
20
21
|
|
21
|
-
#
|
22
|
+
# @param [String] name
|
23
|
+
# @param [String] url
|
24
|
+
# @param [Hash] opts
|
25
|
+
# @return [true]
|
22
26
|
def create_result(name, url, opts={})
|
23
27
|
params = {'url'=>url}.merge(opts)
|
24
28
|
code, body, res = post("/v3/result/create/#{e name}", params)
|
@@ -28,7 +32,8 @@ module Result
|
|
28
32
|
return true
|
29
33
|
end
|
30
34
|
|
31
|
-
#
|
35
|
+
# @param [String] name
|
36
|
+
# @return [true]
|
32
37
|
def delete_result(name)
|
33
38
|
code, body, res = post("/v3/result/delete/#{e name}")
|
34
39
|
if code != "200"
|
@@ -5,7 +5,9 @@ module Schedule
|
|
5
5
|
## Schedule API
|
6
6
|
##
|
7
7
|
|
8
|
-
#
|
8
|
+
# @param [String] name
|
9
|
+
# @param [Hash] opts
|
10
|
+
# @return [String]
|
9
11
|
def create_schedule(name, opts)
|
10
12
|
params = opts.update({:type=> opts[:type] || opts['type'] || 'hive'})
|
11
13
|
code, body, res = post("/v3/schedule/create/#{e name}", params)
|
@@ -16,7 +18,8 @@ module Schedule
|
|
16
18
|
return js['start']
|
17
19
|
end
|
18
20
|
|
19
|
-
#
|
21
|
+
# @param [String] name
|
22
|
+
# @return [Array]
|
20
23
|
def delete_schedule(name)
|
21
24
|
code, body, res = post("/v3/schedule/delete/#{e name}")
|
22
25
|
if code != "200"
|
@@ -26,7 +29,7 @@ module Schedule
|
|
26
29
|
return js['cron'], js["query"]
|
27
30
|
end
|
28
31
|
|
29
|
-
#
|
32
|
+
# @return [Array]
|
30
33
|
def list_schedules
|
31
34
|
code, body, res = get("/v3/schedule/list")
|
32
35
|
if code != "200"
|
@@ -50,6 +53,9 @@ module Schedule
|
|
50
53
|
return result
|
51
54
|
end
|
52
55
|
|
56
|
+
# @param [String] name
|
57
|
+
# @param [Hash] params
|
58
|
+
# @return [nil]
|
53
59
|
def update_schedule(name, params)
|
54
60
|
code, body, res = post("/v3/schedule/update/#{e name}", params)
|
55
61
|
if code != "200"
|
@@ -58,6 +64,10 @@ module Schedule
|
|
58
64
|
return nil
|
59
65
|
end
|
60
66
|
|
67
|
+
# @param [String] name
|
68
|
+
# @param [Fixnum] from
|
69
|
+
# @param [Fixnum] to
|
70
|
+
# @return [Array]
|
61
71
|
def history(name, from=0, to=nil)
|
62
72
|
params = {}
|
63
73
|
params['from'] = from.to_s if from
|
@@ -84,6 +94,10 @@ module Schedule
|
|
84
94
|
return result
|
85
95
|
end
|
86
96
|
|
97
|
+
# @param [String] name
|
98
|
+
# @param [String] time
|
99
|
+
# @param [Fixnum] num
|
100
|
+
# @return [Array]
|
87
101
|
def run_schedule(name, time, num)
|
88
102
|
params = {}
|
89
103
|
params = {'num' => num} if num
|