td-client 0.8.67 → 0.8.68
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 +12 -2
- data/lib/td/client/api.rb +51 -1040
- data/lib/td/client/api/access_control.rb +62 -0
- data/lib/td/client/api/account.rb +41 -0
- data/lib/td/client/api/bulk_import.rb +154 -0
- data/lib/td/client/api/database.rb +47 -0
- data/lib/td/client/api/export.rb +21 -0
- data/lib/td/client/api/import.rb +31 -0
- data/lib/td/client/api/job.rb +251 -0
- data/lib/td/client/api/partial_delete.rb +21 -0
- data/lib/td/client/api/result.rb +41 -0
- data/lib/td/client/api/schedule.rb +106 -0
- data/lib/td/client/api/server_status.rb +20 -0
- data/lib/td/client/api/table.rb +123 -0
- data/lib/td/client/api/user.rb +117 -0
- data/lib/td/client/api_error.rb +26 -0
- data/lib/td/client/model.rb +7 -5
- data/lib/td/client/version.rb +1 -1
- data/lib/td/core_ext/openssl/ssl/sslcontext/set_params.rb +18 -0
- data/spec/spec_helper.rb +8 -4
- data/spec/td/client/access_control_api_spec.rb +37 -0
- data/spec/td/client/account_api_spec.rb +34 -0
- data/spec/td/client/api_ssl_connection_spec.rb +10 -7
- data/spec/td/client/bulk_import_spec.rb +144 -0
- data/spec/td/client/import_api_spec.rb +73 -0
- data/spec/td/client/job_api_spec.rb +124 -1
- data/spec/td/client/result_api_spec.rb +23 -0
- data/spec/td/client/sched_api_spec.rb +33 -0
- data/spec/td/client/server_status_api_spec.rb +25 -0
- data/spec/td/client/table_api_spec.rb +45 -0
- data/spec/td/client/user_api_spec.rb +118 -0
- data/spec/td/client_sched_spec.rb +54 -0
- metadata +37 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6f4ce3a275f3c038d731feb43dda2ec4cc477e5
|
4
|
+
data.tar.gz: b6affcd7ad8e6430af814d9459cfbabde9ae50f9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3127bd887d7fff303cde39f92932d8d9a263cfb37201e3c299a24e53a3767390a70ce4195fe34ce9003ecd815465a0776e3e094cc1c35d3da37f181bc4273c98
|
7
|
+
data.tar.gz: d002d279379a09a63c10882503cf09f6d25d7e3d12198281c55e82881d8f1ef5a7e2ca2af3cb66856b89d8056667da7003a5172f91d424e87fba8a1c625ddcdf
|
data/lib/td/client.rb
CHANGED
@@ -287,8 +287,18 @@ class Client
|
|
287
287
|
def history(name, from=nil, to=nil)
|
288
288
|
result = @api.history(name, from, to)
|
289
289
|
result.map {|scheduled_at,job_id,type,status,query,start_at,end_at,result_url,priority,database|
|
290
|
-
|
291
|
-
|
290
|
+
job_param = [job_id, type, query, status,
|
291
|
+
nil, nil, # url, debug
|
292
|
+
start_at, end_at,
|
293
|
+
nil, # cpu_time
|
294
|
+
nil, nil, # result_size, result
|
295
|
+
result_url,
|
296
|
+
nil, # hive_result_schema
|
297
|
+
priority,
|
298
|
+
nil, # retry_limit
|
299
|
+
nil, # TODO org_name
|
300
|
+
database]
|
301
|
+
ScheduledJob.new(self, scheduled_at, *job_param)
|
292
302
|
}
|
293
303
|
end
|
294
304
|
|
data/lib/td/client/api.rb
CHANGED
@@ -1,32 +1,39 @@
|
|
1
|
+
require 'td/client/api_error'
|
1
2
|
require 'td/client/version'
|
3
|
+
require 'td/client/api/access_control'
|
4
|
+
require 'td/client/api/account'
|
5
|
+
require 'td/client/api/bulk_import'
|
6
|
+
require 'td/client/api/database'
|
7
|
+
require 'td/client/api/export'
|
8
|
+
require 'td/client/api/import'
|
9
|
+
require 'td/client/api/job'
|
10
|
+
require 'td/client/api/partial_delete'
|
11
|
+
require 'td/client/api/result'
|
12
|
+
require 'td/client/api/schedule'
|
13
|
+
require 'td/client/api/server_status'
|
14
|
+
require 'td/client/api/table'
|
15
|
+
require 'td/client/api/user'
|
16
|
+
|
17
|
+
# For disabling SSLv3 connection in favor of POODLE Attack protection
|
18
|
+
require 'td/core_ext/openssl/ssl/sslcontext/set_params'
|
2
19
|
|
3
20
|
module TreasureData
|
4
21
|
|
5
|
-
class ParameterValidationError < StandardError
|
6
|
-
end
|
7
|
-
|
8
|
-
# Generic API error
|
9
|
-
class APIError < StandardError
|
10
|
-
end
|
11
|
-
|
12
|
-
# 401 API errors
|
13
|
-
class AuthError < APIError
|
14
|
-
end
|
15
|
-
|
16
|
-
# 403 API errors, used for database permissions
|
17
|
-
class ForbiddenError < APIError
|
18
|
-
end
|
19
|
-
|
20
|
-
# 409 API errors
|
21
|
-
class AlreadyExistsError < APIError
|
22
|
-
end
|
23
|
-
|
24
|
-
# 404 API errors
|
25
|
-
class NotFoundError < APIError
|
26
|
-
end
|
27
|
-
|
28
|
-
|
29
22
|
class API
|
23
|
+
include API::AccessControl
|
24
|
+
include API::Account
|
25
|
+
include API::BulkImport
|
26
|
+
include API::Database
|
27
|
+
include API::Export
|
28
|
+
include API::Import
|
29
|
+
include API::Job
|
30
|
+
include API::PartialDelete
|
31
|
+
include API::Result
|
32
|
+
include API::Schedule
|
33
|
+
include API::ServerStatus
|
34
|
+
include API::Table
|
35
|
+
include API::User
|
36
|
+
|
30
37
|
DEFAULT_ENDPOINT = 'api.treasure-data.com'
|
31
38
|
DEFAULT_IMPORT_ENDPOINT = 'api-import.treasure-data.com'
|
32
39
|
|
@@ -42,6 +49,10 @@ class API
|
|
42
49
|
require 'time'
|
43
50
|
#require 'faraday' # faraday doesn't support streaming upload with httpclient yet so now disabled
|
44
51
|
require 'httpclient'
|
52
|
+
require 'zlib'
|
53
|
+
require 'stringio'
|
54
|
+
require 'cgi'
|
55
|
+
require 'msgpack'
|
45
56
|
|
46
57
|
@apikey = apikey
|
47
58
|
@user_agent = "TD-Client-Ruby: #{TreasureData::Client::VERSION}"
|
@@ -195,1006 +206,17 @@ class API
|
|
195
206
|
|
196
207
|
# for fluent-plugin-td / td command to check table existence with import onlt user
|
197
208
|
def self.create_empty_gz_data
|
198
|
-
require 'zlib'
|
199
|
-
require 'stringio'
|
200
|
-
|
201
209
|
io = StringIO.new
|
202
210
|
Zlib::GzipWriter.new(io).close
|
203
211
|
io.string
|
204
212
|
end
|
205
213
|
|
206
|
-
####
|
207
|
-
## Account API
|
208
|
-
##
|
209
|
-
|
210
|
-
def show_account
|
211
|
-
code, body, res = get("/v3/account/show")
|
212
|
-
if code != "200"
|
213
|
-
raise_error("Show account failed", res)
|
214
|
-
end
|
215
|
-
js = checked_json(body, %w[account])
|
216
|
-
a = js["account"]
|
217
|
-
account_id = a['id'].to_i
|
218
|
-
plan = a['plan'].to_i
|
219
|
-
storage_size = a['storage_size'].to_i
|
220
|
-
guaranteed_cores = a['guaranteed_cores'].to_i
|
221
|
-
maximum_cores = a['maximum_cores'].to_i
|
222
|
-
created_at = a['created_at']
|
223
|
-
return [account_id, plan, storage_size, guaranteed_cores, maximum_cores, created_at]
|
224
|
-
end
|
225
|
-
|
226
|
-
def account_core_utilization(from, to)
|
227
|
-
params = { }
|
228
|
-
params['from'] = from.to_s if from
|
229
|
-
params['to'] = to.to_s if to
|
230
|
-
code, body, res = get("/v3/account/core_utilization", params)
|
231
|
-
if code != "200"
|
232
|
-
raise_error("Show account failed", res)
|
233
|
-
end
|
234
|
-
js = checked_json(body, %w[from to interval history])
|
235
|
-
from = Time.parse(js['from']).utc
|
236
|
-
to = Time.parse(js['to']).utc
|
237
|
-
interval = js['interval'].to_i
|
238
|
-
history = js['history']
|
239
|
-
return [from, to, interval, history]
|
240
|
-
end
|
241
|
-
|
242
|
-
|
243
|
-
####
|
244
|
-
## Database API
|
245
|
-
##
|
246
|
-
|
247
|
-
# => [name:String]
|
248
|
-
def list_databases
|
249
|
-
code, body, res = get("/v3/database/list")
|
250
|
-
if code != "200"
|
251
|
-
raise_error("List databases failed", res)
|
252
|
-
end
|
253
|
-
js = checked_json(body, %w[databases])
|
254
|
-
result = {}
|
255
|
-
js["databases"].each {|m|
|
256
|
-
name = m['name']
|
257
|
-
count = m['count']
|
258
|
-
created_at = m['created_at']
|
259
|
-
updated_at = m['updated_at']
|
260
|
-
permission = m['permission']
|
261
|
-
result[name] = [count, created_at, updated_at, nil, permission] # set nil to org for API compatibiilty
|
262
|
-
}
|
263
|
-
return result
|
264
|
-
end
|
265
|
-
|
266
|
-
# => true
|
267
|
-
def delete_database(db)
|
268
|
-
code, body, res = post("/v3/database/delete/#{e db}")
|
269
|
-
if code != "200"
|
270
|
-
raise_error("Delete database failed", res)
|
271
|
-
end
|
272
|
-
return true
|
273
|
-
end
|
274
|
-
|
275
|
-
# => true
|
276
|
-
def create_database(db, opts={})
|
277
|
-
params = opts.dup
|
278
|
-
code, body, res = post("/v3/database/create/#{e db}", params)
|
279
|
-
if code != "200"
|
280
|
-
raise_error("Create database failed", res)
|
281
|
-
end
|
282
|
-
return true
|
283
|
-
end
|
284
|
-
|
285
|
-
|
286
|
-
####
|
287
|
-
## Table API
|
288
|
-
##
|
289
|
-
|
290
|
-
# => {name:String => [type:Symbol, count:Integer]}
|
291
|
-
def list_tables(db)
|
292
|
-
code, body, res = get("/v3/table/list/#{e db}")
|
293
|
-
if code != "200"
|
294
|
-
raise_error("List tables failed", res)
|
295
|
-
end
|
296
|
-
js = checked_json(body, %w[tables])
|
297
|
-
result = {}
|
298
|
-
js["tables"].map {|m|
|
299
|
-
name = m['name']
|
300
|
-
type = (m['type'] || '?').to_sym
|
301
|
-
count = (m['count'] || 0).to_i # TODO?
|
302
|
-
created_at = m['created_at']
|
303
|
-
updated_at = m['updated_at']
|
304
|
-
last_import = m['counter_updated_at']
|
305
|
-
last_log_timestamp = m['last_log_timestamp']
|
306
|
-
estimated_storage_size = m['estimated_storage_size'].to_i
|
307
|
-
schema = JSON.parse(m['schema'] || '[]')
|
308
|
-
expire_days = m['expire_days']
|
309
|
-
primary_key = m['primary_key']
|
310
|
-
primary_key_type = m['primary_key_type']
|
311
|
-
result[name] = [type, schema, count, created_at, updated_at, estimated_storage_size, last_import, last_log_timestamp, expire_days, primary_key, primary_key_type]
|
312
|
-
}
|
313
|
-
return result
|
314
|
-
end
|
315
|
-
|
316
|
-
def create_log_or_item_table(db, table, type)
|
317
|
-
code, body, res = post("/v3/table/create/#{e db}/#{e table}/#{type}")
|
318
|
-
if code != "200"
|
319
|
-
raise_error("Create #{type} table failed", res)
|
320
|
-
end
|
321
|
-
return true
|
322
|
-
end
|
323
|
-
private :create_log_or_item_table
|
324
|
-
|
325
|
-
# => true
|
326
|
-
def create_log_table(db, table)
|
327
|
-
create_table(db, table, :log)
|
328
|
-
end
|
329
|
-
|
330
|
-
# => true
|
331
|
-
def create_item_table(db, table, primary_key, primary_key_type)
|
332
|
-
params = {'primary_key' => primary_key, 'primary_key_type' => primary_key_type}
|
333
|
-
create_table(db, table, :item, params)
|
334
|
-
end
|
335
|
-
|
336
|
-
def create_table(db, table, type, params={})
|
337
|
-
schema = schema.to_s
|
338
|
-
code, body, res = post("/v3/table/create/#{e db}/#{e table}/#{type}", params)
|
339
|
-
if code != "200"
|
340
|
-
raise_error("Create #{type} table failed", res)
|
341
|
-
end
|
342
|
-
return true
|
343
|
-
end
|
344
|
-
private :create_table
|
345
|
-
|
346
|
-
# => true
|
347
|
-
def swap_table(db, table1, table2)
|
348
|
-
code, body, res = post("/v3/table/swap/#{e db}/#{e table1}/#{e table2}")
|
349
|
-
if code != "200"
|
350
|
-
raise_error("Swap tables failed", res)
|
351
|
-
end
|
352
|
-
return true
|
353
|
-
end
|
354
|
-
|
355
|
-
# => true
|
356
|
-
def update_schema(db, table, schema_json)
|
357
|
-
code, body, res = post("/v3/table/update-schema/#{e db}/#{e table}", {'schema'=>schema_json})
|
358
|
-
if code != "200"
|
359
|
-
raise_error("Create schema table failed", res)
|
360
|
-
end
|
361
|
-
return true
|
362
|
-
end
|
363
|
-
|
364
|
-
def update_expire(db, table, expire_days)
|
365
|
-
code, body, res = post("/v3/table/update/#{e db}/#{e table}", {'expire_days'=>expire_days})
|
366
|
-
if code != "200"
|
367
|
-
raise_error("Update table expiration failed", res)
|
368
|
-
end
|
369
|
-
return true
|
370
|
-
end
|
371
|
-
|
372
|
-
# => type:Symbol
|
373
|
-
def delete_table(db, table)
|
374
|
-
code, body, res = post("/v3/table/delete/#{e db}/#{e table}")
|
375
|
-
if code != "200"
|
376
|
-
raise_error("Delete table failed", res)
|
377
|
-
end
|
378
|
-
js = checked_json(body, %w[])
|
379
|
-
type = (js['type'] || '?').to_sym
|
380
|
-
return type
|
381
|
-
end
|
382
|
-
|
383
|
-
def tail(db, table, count, to, from, &block)
|
384
|
-
params = {'format' => 'msgpack'}
|
385
|
-
params['count'] = count.to_s if count
|
386
|
-
params['to'] = to.to_s if to
|
387
|
-
params['from'] = from.to_s if from
|
388
|
-
code, body, res = get("/v3/table/tail/#{e db}/#{e table}", params)
|
389
|
-
if code != "200"
|
390
|
-
raise_error("Tail table failed", res)
|
391
|
-
end
|
392
|
-
require 'msgpack'
|
393
|
-
if block
|
394
|
-
MessagePack::Unpacker.new.feed_each(body, &block)
|
395
|
-
nil
|
396
|
-
else
|
397
|
-
result = []
|
398
|
-
MessagePack::Unpacker.new.feed_each(body) {|row|
|
399
|
-
result << row
|
400
|
-
}
|
401
|
-
return result
|
402
|
-
end
|
403
|
-
end
|
404
|
-
|
405
|
-
|
406
|
-
####
|
407
|
-
## Job API
|
408
|
-
##
|
409
|
-
|
410
|
-
# => [(jobId:String, type:Symbol, status:String, start_at:String, end_at:String, result_url:String)]
|
411
|
-
def list_jobs(from=0, to=nil, status=nil, conditions=nil)
|
412
|
-
params = {}
|
413
|
-
params['from'] = from.to_s if from
|
414
|
-
params['to'] = to.to_s if to
|
415
|
-
params['status'] = status.to_s if status
|
416
|
-
params.merge!(conditions) if conditions
|
417
|
-
code, body, res = get("/v3/job/list", params)
|
418
|
-
if code != "200"
|
419
|
-
raise_error("List jobs failed", res)
|
420
|
-
end
|
421
|
-
js = checked_json(body, %w[jobs])
|
422
|
-
result = []
|
423
|
-
js['jobs'].each {|m|
|
424
|
-
job_id = m['job_id']
|
425
|
-
type = (m['type'] || '?').to_sym
|
426
|
-
database = m['database']
|
427
|
-
status = m['status']
|
428
|
-
query = m['query']
|
429
|
-
start_at = m['start_at']
|
430
|
-
end_at = m['end_at']
|
431
|
-
cpu_time = m['cpu_time']
|
432
|
-
result_size = m['result_size'] # compressed result size in msgpack.gz format
|
433
|
-
result_url = m['result']
|
434
|
-
priority = m['priority']
|
435
|
-
retry_limit = m['retry_limit']
|
436
|
-
result << [job_id, type, status, query, start_at, end_at, cpu_time,
|
437
|
-
result_size, result_url, priority, retry_limit, nil, database]
|
438
|
-
}
|
439
|
-
return result
|
440
|
-
end
|
441
|
-
|
442
|
-
# => (type:Symbol, status:String, result:String, url:String, result:String)
|
443
|
-
def show_job(job_id)
|
444
|
-
# use v3/job/status instead of v3/job/show to poll finish of a job
|
445
|
-
code, body, res = get("/v3/job/show/#{e job_id}")
|
446
|
-
if code != "200"
|
447
|
-
raise_error("Show job failed", res)
|
448
|
-
end
|
449
|
-
js = checked_json(body, %w[status])
|
450
|
-
# TODO debug
|
451
|
-
type = (js['type'] || '?').to_sym # TODO
|
452
|
-
database = js['database']
|
453
|
-
query = js['query']
|
454
|
-
status = js['status']
|
455
|
-
debug = js['debug']
|
456
|
-
url = js['url']
|
457
|
-
start_at = js['start_at']
|
458
|
-
end_at = js['end_at']
|
459
|
-
cpu_time = js['cpu_time']
|
460
|
-
result_size = js['result_size'] # compressed result size in msgpack.gz format
|
461
|
-
result = js['result'] # result target URL
|
462
|
-
hive_result_schema = (js['hive_result_schema'] || '')
|
463
|
-
if hive_result_schema.empty?
|
464
|
-
hive_result_schema = nil
|
465
|
-
else
|
466
|
-
begin
|
467
|
-
hive_result_schema = JSON.parse(hive_result_schema)
|
468
|
-
rescue JSON::ParserError => e
|
469
|
-
# this is a workaround for a Known Limitation in the Pig Engine which does not set a default, auto-generated
|
470
|
-
# column name for anonymous columns (such as the ones that are generated from UDF like COUNT or SUM).
|
471
|
-
# The schema will contain 'nil' for the name of those columns and that breaks the JSON parser since it violates
|
472
|
-
# the JSON syntax standard.
|
473
|
-
if type == :pig and hive_result_schema !~ /[\{\}]/
|
474
|
-
begin
|
475
|
-
# NOTE: this works because a JSON 2 dimensional array is the same as a Ruby one.
|
476
|
-
# Any change in the format for the hive_result_schema output may cause a syntax error, in which case
|
477
|
-
# this lame attempt at fixing the problem will fail and we will be raising the original JSON exception
|
478
|
-
hive_result_schema = eval(hive_result_schema)
|
479
|
-
rescue SyntaxError => ignored_e
|
480
|
-
raise e
|
481
|
-
end
|
482
|
-
hive_result_schema.each_with_index {|col_schema, idx|
|
483
|
-
if col_schema[0].nil?
|
484
|
-
col_schema[0] = "_col#{idx}"
|
485
|
-
end
|
486
|
-
}
|
487
|
-
else
|
488
|
-
raise e
|
489
|
-
end
|
490
|
-
end
|
491
|
-
end
|
492
|
-
priority = js['priority']
|
493
|
-
retry_limit = js['retry_limit']
|
494
|
-
return [type, query, status, url, debug, start_at, end_at, cpu_time,
|
495
|
-
result_size, result, hive_result_schema, priority, retry_limit, nil, database]
|
496
|
-
end
|
497
|
-
|
498
|
-
def job_status(job_id)
|
499
|
-
code, body, res = get("/v3/job/status/#{e job_id}")
|
500
|
-
if code != "200"
|
501
|
-
raise_error("Get job status failed", res)
|
502
|
-
end
|
503
|
-
|
504
|
-
js = checked_json(body, %w[status])
|
505
|
-
return js['status']
|
506
|
-
end
|
507
|
-
|
508
|
-
def job_result(job_id)
|
509
|
-
require 'msgpack'
|
510
|
-
code, body, res = get("/v3/job/result/#{e job_id}", {'format'=>'msgpack'})
|
511
|
-
if code != "200"
|
512
|
-
raise_error("Get job result failed", res)
|
513
|
-
end
|
514
|
-
result = []
|
515
|
-
MessagePack::Unpacker.new.feed_each(body) {|row|
|
516
|
-
result << row
|
517
|
-
}
|
518
|
-
return result
|
519
|
-
end
|
520
|
-
|
521
|
-
# block is optional and must accept 1 parameter
|
522
|
-
def job_result_format(job_id, format, io=nil, &block)
|
523
|
-
if io
|
524
|
-
code, body, res = get("/v3/job/result/#{e job_id}", {'format'=>format}) {|res|
|
525
|
-
if res.code != "200"
|
526
|
-
raise_error("Get job result failed", res)
|
527
|
-
end
|
528
|
-
|
529
|
-
if ce = res.header['Content-Encoding']
|
530
|
-
require 'zlib'
|
531
|
-
res.extend(DeflateReadBodyMixin)
|
532
|
-
res.gzip = true if ce == 'gzip'
|
533
|
-
else
|
534
|
-
res.extend(DirectReadBodyMixin)
|
535
|
-
end
|
536
|
-
|
537
|
-
res.extend(DirectReadBodyMixin)
|
538
|
-
if ce = res.header['Content-Encoding']
|
539
|
-
if ce == 'gzip'
|
540
|
-
infl = Zlib::Inflate.new(Zlib::MAX_WBITS + 16)
|
541
|
-
else
|
542
|
-
infl = Zlib::Inflate.new
|
543
|
-
end
|
544
|
-
end
|
545
|
-
|
546
|
-
total_compr_size = 0
|
547
|
-
res.each_fragment {|fragment|
|
548
|
-
total_compr_size += fragment.size
|
549
|
-
# uncompressed if the 'Content-Enconding' header is set in response
|
550
|
-
fragment = infl.inflate(fragment) if ce
|
551
|
-
io.write(fragment)
|
552
|
-
block.call(total_compr_size) if block_given?
|
553
|
-
}
|
554
|
-
}
|
555
|
-
nil
|
556
|
-
else
|
557
|
-
code, body, res = get("/v3/job/result/#{e job_id}", {'format'=>format})
|
558
|
-
if res.code != "200"
|
559
|
-
raise_error("Get job result failed", res)
|
560
|
-
end
|
561
|
-
body
|
562
|
-
end
|
563
|
-
end
|
564
|
-
|
565
|
-
# block is optional and must accept 1 argument
|
566
|
-
def job_result_each(job_id, &block)
|
567
|
-
require 'msgpack'
|
568
|
-
get("/v3/job/result/#{e job_id}", {'format'=>'msgpack'}) {|res|
|
569
|
-
if res.code != "200"
|
570
|
-
raise_error("Get job result failed", res)
|
571
|
-
end
|
572
|
-
|
573
|
-
# default to decompressing the response since format is fixed to 'msgpack'
|
574
|
-
res.extend(DeflateReadBodyMixin)
|
575
|
-
res.gzip = (res.header['Content-Encoding'] == 'gzip')
|
576
|
-
upkr = MessagePack::Unpacker.new
|
577
|
-
res.each_fragment {|inflated_fragment|
|
578
|
-
upkr.feed_each(inflated_fragment, &block)
|
579
|
-
}
|
580
|
-
}
|
581
|
-
nil
|
582
|
-
end
|
583
|
-
|
584
|
-
# block is optional and must accept 1 argument
|
585
|
-
def job_result_each_with_compr_size(job_id, &block)
|
586
|
-
require 'zlib'
|
587
|
-
require 'msgpack'
|
588
|
-
|
589
|
-
get("/v3/job/result/#{e job_id}", {'format'=>'msgpack'}) {|res|
|
590
|
-
if res.code != "200"
|
591
|
-
raise_error("Get job result failed", res)
|
592
|
-
end
|
593
|
-
|
594
|
-
res.extend(DirectReadBodyMixin)
|
595
|
-
if res.header['Content-Encoding'] == 'gzip'
|
596
|
-
infl = Zlib::Inflate.new(Zlib::MAX_WBITS + 16)
|
597
|
-
else
|
598
|
-
infl = Zlib::Inflate.new
|
599
|
-
end
|
600
|
-
upkr = MessagePack::Unpacker.new
|
601
|
-
begin
|
602
|
-
total_compr_size = 0
|
603
|
-
res.each_fragment {|fragment|
|
604
|
-
total_compr_size += fragment.size
|
605
|
-
upkr.feed_each(infl.inflate(fragment)) {|unpacked|
|
606
|
-
block.call(unpacked, total_compr_size) if block_given?
|
607
|
-
}
|
608
|
-
}
|
609
|
-
ensure
|
610
|
-
infl.close
|
611
|
-
end
|
612
|
-
}
|
613
|
-
nil
|
614
|
-
end
|
615
|
-
|
616
|
-
def job_result_raw(job_id, format)
|
617
|
-
code, body, res = get("/v3/job/result/#{e job_id}", {'format'=>format})
|
618
|
-
if code != "200"
|
619
|
-
raise_error("Get job result failed", res)
|
620
|
-
end
|
621
|
-
return body
|
622
|
-
end
|
623
|
-
|
624
|
-
def kill(job_id)
|
625
|
-
code, body, res = post("/v3/job/kill/#{e job_id}")
|
626
|
-
if code != "200"
|
627
|
-
raise_error("Kill job failed", res)
|
628
|
-
end
|
629
|
-
js = checked_json(body, %w[])
|
630
|
-
former_status = js['former_status']
|
631
|
-
return former_status
|
632
|
-
end
|
633
|
-
|
634
|
-
# => jobId:String
|
635
|
-
def hive_query(q, db=nil, result_url=nil, priority=nil, retry_limit=nil, opts={})
|
636
|
-
query(q, :hive, db, result_url, priority, retry_limit, opts)
|
637
|
-
end
|
638
|
-
|
639
|
-
# => jobId:String
|
640
|
-
def pig_query(q, db=nil, result_url=nil, priority=nil, retry_limit=nil, opts={})
|
641
|
-
query(q, :pig, db, result_url, priority, retry_limit, opts)
|
642
|
-
end
|
643
|
-
|
644
|
-
# => jobId:String
|
645
|
-
def query(q, type=:hive, db=nil, result_url=nil, priority=nil, retry_limit=nil, opts={})
|
646
|
-
params = {'query' => q}.merge(opts)
|
647
|
-
params['result'] = result_url if result_url
|
648
|
-
params['priority'] = priority if priority
|
649
|
-
params['retry_limit'] = retry_limit if retry_limit
|
650
|
-
code, body, res = post("/v3/job/issue/#{type}/#{e db}", params)
|
651
|
-
if code != "200"
|
652
|
-
raise_error("Query failed", res)
|
653
|
-
end
|
654
|
-
js = checked_json(body, %w[job_id])
|
655
|
-
return js['job_id'].to_s
|
656
|
-
end
|
657
|
-
|
658
|
-
####
|
659
|
-
## Export API
|
660
|
-
##
|
661
|
-
|
662
|
-
# => jobId:String
|
663
|
-
def export(db, table, storage_type, opts={})
|
664
|
-
params = opts.dup
|
665
|
-
params['storage_type'] = storage_type
|
666
|
-
code, body, res = post("/v3/export/run/#{e db}/#{e table}", params)
|
667
|
-
if code != "200"
|
668
|
-
raise_error("Export failed", res)
|
669
|
-
end
|
670
|
-
js = checked_json(body, %w[job_id])
|
671
|
-
return js['job_id'].to_s
|
672
|
-
end
|
673
|
-
|
674
|
-
|
675
|
-
####
|
676
|
-
## Partial delete API
|
677
|
-
##
|
678
|
-
|
679
|
-
def partial_delete(db, table, to, from, opts={})
|
680
|
-
params = opts.dup
|
681
|
-
params['to'] = to.to_s
|
682
|
-
params['from'] = from.to_s
|
683
|
-
code, body, res = post("/v3/table/partialdelete/#{e db}/#{e table}", params)
|
684
|
-
if code != "200"
|
685
|
-
raise_error("Partial delete failed", res)
|
686
|
-
end
|
687
|
-
js = checked_json(body, %w[job_id])
|
688
|
-
return js['job_id'].to_s
|
689
|
-
end
|
690
|
-
|
691
|
-
####
|
692
|
-
## Bulk import API
|
693
|
-
##
|
694
|
-
|
695
|
-
# => nil
|
696
|
-
def create_bulk_import(name, db, table, opts={})
|
697
|
-
params = opts.dup
|
698
|
-
code, body, res = post("/v3/bulk_import/create/#{e name}/#{e db}/#{e table}", params)
|
699
|
-
if code != "200"
|
700
|
-
raise_error("Create bulk import failed", res)
|
701
|
-
end
|
702
|
-
return nil
|
703
|
-
end
|
704
|
-
|
705
|
-
# => nil
|
706
|
-
def delete_bulk_import(name, opts={})
|
707
|
-
params = opts.dup
|
708
|
-
code, body, res = post("/v3/bulk_import/delete/#{e name}", params)
|
709
|
-
if code != "200"
|
710
|
-
raise_error("Delete bulk import failed", res)
|
711
|
-
end
|
712
|
-
return nil
|
713
|
-
end
|
714
|
-
|
715
|
-
# => data:Hash
|
716
|
-
def show_bulk_import(name)
|
717
|
-
code, body, res = get("/v3/bulk_import/show/#{name}")
|
718
|
-
if code != "200"
|
719
|
-
raise_error("Show bulk import failed", res)
|
720
|
-
end
|
721
|
-
js = checked_json(body, %w[status])
|
722
|
-
return js
|
723
|
-
end
|
724
|
-
|
725
|
-
# => result:[data:Hash]
|
726
|
-
def list_bulk_imports(opts={})
|
727
|
-
params = opts.dup
|
728
|
-
code, body, res = get("/v3/bulk_import/list", params)
|
729
|
-
if code != "200"
|
730
|
-
raise_error("List bulk imports failed", res)
|
731
|
-
end
|
732
|
-
js = checked_json(body, %w[bulk_imports])
|
733
|
-
return js['bulk_imports']
|
734
|
-
end
|
735
|
-
|
736
|
-
def list_bulk_import_parts(name, opts={})
|
737
|
-
params = opts.dup
|
738
|
-
code, body, res = get("/v3/bulk_import/list_parts/#{e name}", params)
|
739
|
-
if code != "200"
|
740
|
-
raise_error("List bulk import parts failed", res)
|
741
|
-
end
|
742
|
-
js = checked_json(body, %w[parts])
|
743
|
-
return js['parts']
|
744
|
-
end
|
745
|
-
|
746
|
-
# => nil
|
747
|
-
def bulk_import_upload_part(name, part_name, stream, size, opts={})
|
748
|
-
code, body, res = put("/v3/bulk_import/upload_part/#{e name}/#{e part_name}", stream, size)
|
749
|
-
if code[0] != ?2
|
750
|
-
raise_error("Upload a part failed", res)
|
751
|
-
end
|
752
|
-
return nil
|
753
|
-
end
|
754
|
-
|
755
|
-
# => nil
|
756
|
-
def bulk_import_delete_part(name, part_name, opts={})
|
757
|
-
params = opts.dup
|
758
|
-
code, body, res = post("/v3/bulk_import/delete_part/#{e name}/#{e part_name}", params)
|
759
|
-
if code[0] != ?2
|
760
|
-
raise_error("Delete a part failed", res)
|
761
|
-
end
|
762
|
-
return nil
|
763
|
-
end
|
764
|
-
|
765
|
-
# => nil
|
766
|
-
def freeze_bulk_import(name, opts={})
|
767
|
-
params = opts.dup
|
768
|
-
code, body, res = post("/v3/bulk_import/freeze/#{e name}", params)
|
769
|
-
if code != "200"
|
770
|
-
raise_error("Freeze bulk import failed", res)
|
771
|
-
end
|
772
|
-
return nil
|
773
|
-
end
|
774
|
-
|
775
|
-
# => nil
|
776
|
-
def unfreeze_bulk_import(name, opts={})
|
777
|
-
params = opts.dup
|
778
|
-
code, body, res = post("/v3/bulk_import/unfreeze/#{e name}", params)
|
779
|
-
if code != "200"
|
780
|
-
raise_error("Unfreeze bulk import failed", res)
|
781
|
-
end
|
782
|
-
return nil
|
783
|
-
end
|
784
|
-
|
785
|
-
# => jobId:String
|
786
|
-
def perform_bulk_import(name, opts={})
|
787
|
-
params = opts.dup
|
788
|
-
code, body, res = post("/v3/bulk_import/perform/#{e name}", params)
|
789
|
-
if code != "200"
|
790
|
-
raise_error("Perform bulk import failed", res)
|
791
|
-
end
|
792
|
-
js = checked_json(body, %w[job_id])
|
793
|
-
return js['job_id'].to_s
|
794
|
-
end
|
795
|
-
|
796
|
-
# => nil
|
797
|
-
def commit_bulk_import(name, opts={})
|
798
|
-
params = opts.dup
|
799
|
-
code, body, res = post("/v3/bulk_import/commit/#{e name}", params)
|
800
|
-
if code != "200"
|
801
|
-
raise_error("Commit bulk import failed", res)
|
802
|
-
end
|
803
|
-
return nil
|
804
|
-
end
|
805
|
-
|
806
|
-
# => data...
|
807
|
-
def bulk_import_error_records(name, opts={}, &block)
|
808
|
-
params = opts.dup
|
809
|
-
code, body, res = get("/v3/bulk_import/error_records/#{e name}", params)
|
810
|
-
if code != "200"
|
811
|
-
raise_error("Failed to get bulk import error records", res)
|
812
|
-
end
|
813
|
-
if body.empty?
|
814
|
-
if block
|
815
|
-
return nil
|
816
|
-
else
|
817
|
-
return []
|
818
|
-
end
|
819
|
-
end
|
820
|
-
require 'zlib'
|
821
|
-
require 'stringio'
|
822
|
-
require 'msgpack'
|
823
|
-
require File.expand_path('compat_gzip_reader', File.dirname(__FILE__))
|
824
|
-
u = MessagePack::Unpacker.new(Zlib::GzipReader.new(StringIO.new(body)))
|
825
|
-
if block
|
826
|
-
begin
|
827
|
-
u.each(&block)
|
828
|
-
rescue EOFError
|
829
|
-
end
|
830
|
-
nil
|
831
|
-
else
|
832
|
-
result = []
|
833
|
-
begin
|
834
|
-
u.each {|row|
|
835
|
-
result << row
|
836
|
-
}
|
837
|
-
rescue EOFError
|
838
|
-
end
|
839
|
-
return result
|
840
|
-
end
|
841
|
-
end
|
842
|
-
|
843
|
-
####
|
844
|
-
## Schedule API
|
845
|
-
##
|
846
|
-
|
847
|
-
# => start:String
|
848
|
-
def create_schedule(name, opts)
|
849
|
-
params = opts.update({:type=> opts[:type] || opts['type'] || 'hive'})
|
850
|
-
code, body, res = post("/v3/schedule/create/#{e name}", params)
|
851
|
-
if code != "200"
|
852
|
-
raise_error("Create schedule failed", res)
|
853
|
-
end
|
854
|
-
js = checked_json(body, %w[start])
|
855
|
-
return js['start']
|
856
|
-
end
|
857
|
-
|
858
|
-
# => cron:String, query:String
|
859
|
-
def delete_schedule(name)
|
860
|
-
code, body, res = post("/v3/schedule/delete/#{e name}")
|
861
|
-
if code != "200"
|
862
|
-
raise_error("Delete schedule failed", res)
|
863
|
-
end
|
864
|
-
js = checked_json(body, %w[])
|
865
|
-
return js['cron'], js["query"]
|
866
|
-
end
|
867
|
-
|
868
|
-
# => [(name:String, cron:String, query:String, database:String, result_url:String)]
|
869
|
-
def list_schedules
|
870
|
-
code, body, res = get("/v3/schedule/list")
|
871
|
-
if code != "200"
|
872
|
-
raise_error("List schedules failed", res)
|
873
|
-
end
|
874
|
-
js = checked_json(body, %w[schedules])
|
875
|
-
result = []
|
876
|
-
js['schedules'].each {|m|
|
877
|
-
name = m['name']
|
878
|
-
cron = m['cron']
|
879
|
-
query = m['query']
|
880
|
-
database = m['database']
|
881
|
-
result_url = m['result']
|
882
|
-
timezone = m['timezone']
|
883
|
-
delay = m['delay']
|
884
|
-
next_time = m['next_time']
|
885
|
-
priority = m['priority']
|
886
|
-
retry_limit = m['retry_limit']
|
887
|
-
result << [name, cron, query, database, result_url, timezone, delay, next_time, priority, retry_limit, nil] # same as database
|
888
|
-
}
|
889
|
-
return result
|
890
|
-
end
|
891
|
-
|
892
|
-
def update_schedule(name, params)
|
893
|
-
code, body, res = post("/v3/schedule/update/#{e name}", params)
|
894
|
-
if code != "200"
|
895
|
-
raise_error("Update schedule failed", res)
|
896
|
-
end
|
897
|
-
return nil
|
898
|
-
end
|
899
|
-
|
900
|
-
def history(name, from=0, to=nil)
|
901
|
-
params = {}
|
902
|
-
params['from'] = from.to_s if from
|
903
|
-
params['to'] = to.to_s if to
|
904
|
-
code, body, res = get("/v3/schedule/history/#{e name}", params)
|
905
|
-
if code != "200"
|
906
|
-
raise_error("List history failed", res)
|
907
|
-
end
|
908
|
-
js = checked_json(body, %w[history])
|
909
|
-
result = []
|
910
|
-
js['history'].each {|m|
|
911
|
-
job_id = m['job_id']
|
912
|
-
type = (m['type'] || '?').to_sym
|
913
|
-
database = m['database']
|
914
|
-
status = m['status']
|
915
|
-
query = m['query']
|
916
|
-
start_at = m['start_at']
|
917
|
-
end_at = m['end_at']
|
918
|
-
scheduled_at = m['scheduled_at']
|
919
|
-
result_url = m['result']
|
920
|
-
priority = m['priority']
|
921
|
-
result << [scheduled_at, job_id, type, status, query, start_at, end_at, result_url, priority, database]
|
922
|
-
}
|
923
|
-
return result
|
924
|
-
end
|
925
|
-
|
926
|
-
def run_schedule(name, time, num)
|
927
|
-
params = {}
|
928
|
-
params = {'num' => num} if num
|
929
|
-
code, body, res = post("/v3/schedule/run/#{e name}/#{e time}", params)
|
930
|
-
if code != "200"
|
931
|
-
raise_error("Run schedule failed", res)
|
932
|
-
end
|
933
|
-
js = checked_json(body, %w[jobs])
|
934
|
-
result = []
|
935
|
-
js['jobs'].each {|m|
|
936
|
-
job_id = m['job_id']
|
937
|
-
scheduled_at = m['scheduled_at']
|
938
|
-
type = (m['type'] || '?').to_sym
|
939
|
-
result << [job_id, type, scheduled_at]
|
940
|
-
}
|
941
|
-
return result
|
942
|
-
end
|
943
|
-
|
944
|
-
####
|
945
|
-
## Import API
|
946
|
-
##
|
947
|
-
|
948
|
-
# => time:Float
|
949
|
-
def import(db, table, format, stream, size, unique_id=nil)
|
950
|
-
if unique_id
|
951
|
-
path = "/v3/table/import_with_id/#{e db}/#{e table}/#{unique_id}/#{format}"
|
952
|
-
else
|
953
|
-
path = "/v3/table/import/#{e db}/#{e table}/#{format}"
|
954
|
-
end
|
955
|
-
opts = {}
|
956
|
-
if @host == DEFAULT_ENDPOINT
|
957
|
-
opts[:host] = DEFAULT_IMPORT_ENDPOINT
|
958
|
-
elsif @host == NEW_DEFAULT_ENDPOINT
|
959
|
-
opts[:host] = NEW_DEFAULT_IMPORT_ENDPOINT
|
960
|
-
end
|
961
|
-
code, body, res = put(path, stream, size, opts)
|
962
|
-
if code[0] != ?2
|
963
|
-
raise_error("Import failed", res)
|
964
|
-
end
|
965
|
-
js = checked_json(body, %w[])
|
966
|
-
time = js['elapsed_time'].to_f
|
967
|
-
return time
|
968
|
-
end
|
969
|
-
|
970
|
-
|
971
|
-
####
|
972
|
-
## Result API
|
973
|
-
##
|
974
|
-
|
975
|
-
def list_result
|
976
|
-
code, body, res = get("/v3/result/list")
|
977
|
-
if code != "200"
|
978
|
-
raise_error("List result table failed", res)
|
979
|
-
end
|
980
|
-
js = checked_json(body, %w[results])
|
981
|
-
result = []
|
982
|
-
js['results'].map {|m|
|
983
|
-
result << [m['name'], m['url'], nil] # same as database
|
984
|
-
}
|
985
|
-
return result
|
986
|
-
end
|
987
|
-
|
988
|
-
# => true
|
989
|
-
def create_result(name, url, opts={})
|
990
|
-
params = {'url'=>url}.merge(opts)
|
991
|
-
code, body, res = post("/v3/result/create/#{e name}", params)
|
992
|
-
if code != "200"
|
993
|
-
raise_error("Create result table failed", res)
|
994
|
-
end
|
995
|
-
return true
|
996
|
-
end
|
997
|
-
|
998
|
-
# => true
|
999
|
-
def delete_result(name)
|
1000
|
-
code, body, res = post("/v3/result/delete/#{e name}")
|
1001
|
-
if code != "200"
|
1002
|
-
raise_error("Delete result table failed", res)
|
1003
|
-
end
|
1004
|
-
return true
|
1005
|
-
end
|
1006
|
-
|
1007
|
-
|
1008
|
-
####
|
1009
|
-
## User API
|
1010
|
-
##
|
1011
|
-
|
1012
|
-
# apikey:String
|
1013
|
-
def authenticate(user, password)
|
1014
|
-
code, body, res = post("/v3/user/authenticate", {'user'=>user, 'password'=>password})
|
1015
|
-
if code != "200"
|
1016
|
-
if code == "400"
|
1017
|
-
raise_error("Authentication failed", res, AuthError)
|
1018
|
-
else
|
1019
|
-
raise_error("Authentication failed", res)
|
1020
|
-
end
|
1021
|
-
end
|
1022
|
-
js = checked_json(body, %w[apikey])
|
1023
|
-
apikey = js['apikey']
|
1024
|
-
return apikey
|
1025
|
-
end
|
1026
|
-
|
1027
|
-
# => [[name:String,organization:String,[user:String]]
|
1028
|
-
def list_users
|
1029
|
-
code, body, res = get("/v3/user/list")
|
1030
|
-
if code != "200"
|
1031
|
-
raise_error("List users failed", res)
|
1032
|
-
end
|
1033
|
-
js = checked_json(body, %w[users])
|
1034
|
-
result = js["users"].map {|roleinfo|
|
1035
|
-
name = roleinfo['name']
|
1036
|
-
email = roleinfo['email']
|
1037
|
-
[name, nil, nil, email] # set nil to org and role for API compatibility
|
1038
|
-
}
|
1039
|
-
return result
|
1040
|
-
end
|
1041
|
-
|
1042
|
-
# => true
|
1043
|
-
def add_user(name, org, email, password)
|
1044
|
-
params = {'organization'=>org, :email=>email, :password=>password}
|
1045
|
-
code, body, res = post("/v3/user/add/#{e name}", params)
|
1046
|
-
if code != "200"
|
1047
|
-
raise_error("Adding user failed", res)
|
1048
|
-
end
|
1049
|
-
return true
|
1050
|
-
end
|
1051
|
-
|
1052
|
-
# => true
|
1053
|
-
def remove_user(user)
|
1054
|
-
code, body, res = post("/v3/user/remove/#{e user}")
|
1055
|
-
if code != "200"
|
1056
|
-
raise_error("Removing user failed", res)
|
1057
|
-
end
|
1058
|
-
return true
|
1059
|
-
end
|
1060
|
-
|
1061
|
-
# => true
|
1062
|
-
def change_email(user, email)
|
1063
|
-
params = {'email' => email}
|
1064
|
-
code, body, res = post("/v3/user/email/change/#{e user}", params)
|
1065
|
-
if code != "200"
|
1066
|
-
raise_error("Changing email failed", res)
|
1067
|
-
end
|
1068
|
-
return true
|
1069
|
-
end
|
1070
|
-
|
1071
|
-
# => [apikey:String]
|
1072
|
-
def list_apikeys(user)
|
1073
|
-
code, body, res = get("/v3/user/apikey/list/#{e user}")
|
1074
|
-
if code != "200"
|
1075
|
-
raise_error("List API keys failed", res)
|
1076
|
-
end
|
1077
|
-
js = checked_json(body, %w[apikeys])
|
1078
|
-
return js['apikeys']
|
1079
|
-
end
|
1080
|
-
|
1081
|
-
# => true
|
1082
|
-
def add_apikey(user)
|
1083
|
-
code, body, res = post("/v3/user/apikey/add/#{e user}")
|
1084
|
-
if code != "200"
|
1085
|
-
raise_error("Adding API key failed", res)
|
1086
|
-
end
|
1087
|
-
return true
|
1088
|
-
end
|
1089
|
-
|
1090
|
-
# => true
|
1091
|
-
def remove_apikey(user, apikey)
|
1092
|
-
params = {'apikey' => apikey}
|
1093
|
-
code, body, res = post("/v3/user/apikey/remove/#{e user}", params)
|
1094
|
-
if code != "200"
|
1095
|
-
raise_error("Removing API key failed", res)
|
1096
|
-
end
|
1097
|
-
return true
|
1098
|
-
end
|
1099
|
-
|
1100
|
-
# => true
|
1101
|
-
def change_password(user, password)
|
1102
|
-
params = {'password' => password}
|
1103
|
-
code, body, res = post("/v3/user/password/change/#{e user}", params)
|
1104
|
-
if code != "200"
|
1105
|
-
raise_error("Changing password failed", res)
|
1106
|
-
end
|
1107
|
-
return true
|
1108
|
-
end
|
1109
|
-
|
1110
|
-
# => true
|
1111
|
-
def change_my_password(old_password, password)
|
1112
|
-
params = {'old_password' => old_password, 'password' => password}
|
1113
|
-
code, body, res = post("/v3/user/password/change", params)
|
1114
|
-
if code != "200"
|
1115
|
-
raise_error("Changing password failed", res)
|
1116
|
-
end
|
1117
|
-
return true
|
1118
|
-
end
|
1119
|
-
|
1120
|
-
|
1121
|
-
####
|
1122
|
-
## Access Control API
|
1123
|
-
##
|
1124
|
-
|
1125
|
-
def grant_access_control(subject, action, scope, grant_option)
|
1126
|
-
params = {'subject'=>subject, 'action'=>action, 'scope'=>scope, 'grant_option'=>grant_option.to_s}
|
1127
|
-
code, body, res = post("/v3/acl/grant", params)
|
1128
|
-
if code != "200"
|
1129
|
-
raise_error("Granting access control failed", res)
|
1130
|
-
end
|
1131
|
-
return true
|
1132
|
-
end
|
1133
|
-
|
1134
|
-
def revoke_access_control(subject, action, scope)
|
1135
|
-
params = {'subject'=>subject, 'action'=>action, 'scope'=>scope}
|
1136
|
-
code, body, res = post("/v3/acl/revoke", params)
|
1137
|
-
if code != "200"
|
1138
|
-
raise_error("Revoking access control failed", res)
|
1139
|
-
end
|
1140
|
-
return true
|
1141
|
-
end
|
1142
|
-
|
1143
|
-
# [true, [{subject:String,action:String,scope:String}]]
|
1144
|
-
def test_access_control(user, action, scope)
|
1145
|
-
params = {'user'=>user, 'action'=>action, 'scope'=>scope}
|
1146
|
-
code, body, res = get("/v3/acl/test", params)
|
1147
|
-
if code != "200"
|
1148
|
-
raise_error("Testing access control failed", res)
|
1149
|
-
end
|
1150
|
-
js = checked_json(body, %w[permission access_controls])
|
1151
|
-
perm = js["permission"]
|
1152
|
-
acl = js["access_controls"].map {|roleinfo|
|
1153
|
-
subject = roleinfo['subject']
|
1154
|
-
action = roleinfo['action']
|
1155
|
-
scope = roleinfo['scope']
|
1156
|
-
[name, action, scope]
|
1157
|
-
}
|
1158
|
-
return perm, acl
|
1159
|
-
end
|
1160
|
-
|
1161
|
-
# [{subject:String,action:String,scope:String}]
|
1162
|
-
def list_access_controls
|
1163
|
-
code, body, res = get("/v3/acl/list")
|
1164
|
-
if code != "200"
|
1165
|
-
raise_error("Listing access control failed", res)
|
1166
|
-
end
|
1167
|
-
js = checked_json(body, %w[access_controls])
|
1168
|
-
acl = js["access_controls"].map {|roleinfo|
|
1169
|
-
subject = roleinfo['subject']
|
1170
|
-
action = roleinfo['action']
|
1171
|
-
scope = roleinfo['scope']
|
1172
|
-
grant_option = roleinfo['grant_option']
|
1173
|
-
[subject, action, scope, grant_option]
|
1174
|
-
}
|
1175
|
-
return acl
|
1176
|
-
end
|
1177
|
-
|
1178
|
-
####
|
1179
|
-
## Server Status API
|
1180
|
-
##
|
1181
|
-
|
1182
|
-
# => status:String
|
1183
|
-
def server_status
|
1184
|
-
code, body, res = get('/v3/system/server_status')
|
1185
|
-
if code != "200"
|
1186
|
-
return "Server is down (#{code})"
|
1187
|
-
end
|
1188
|
-
js = checked_json(body, %w[status])
|
1189
|
-
status = js['status']
|
1190
|
-
return status
|
1191
|
-
end
|
1192
|
-
|
1193
214
|
def ssl_ca_file=(ssl_ca_file)
|
1194
215
|
@ssl_ca_file = ssl_ca_file
|
1195
216
|
end
|
1196
217
|
|
1197
|
-
|
218
|
+
private
|
219
|
+
|
1198
220
|
module DeflateReadBodyMixin
|
1199
221
|
attr_accessor :gzip
|
1200
222
|
|
@@ -1303,7 +325,6 @@ class API
|
|
1303
325
|
body = response.body
|
1304
326
|
unless block
|
1305
327
|
if ce = response.header['content-encoding']
|
1306
|
-
require 'zlib'
|
1307
328
|
if ce == 'gzip'
|
1308
329
|
infl = Zlib::Inflate.new(Zlib::MAX_WBITS + 16)
|
1309
330
|
begin
|
@@ -1377,7 +398,11 @@ class API
|
|
1377
398
|
retry_delay *= 2
|
1378
399
|
retry
|
1379
400
|
else
|
1380
|
-
|
401
|
+
if @retry_post_requests
|
402
|
+
$stderr.puts "Retrying stopped after #{@max_cumul_retry_delay} seconds."
|
403
|
+
else
|
404
|
+
$stderr.puts ""
|
405
|
+
end
|
1381
406
|
raise e
|
1382
407
|
end
|
1383
408
|
rescue => e
|
@@ -1434,7 +459,7 @@ class API
|
|
1434
459
|
|
1435
460
|
def build_endpoint(url, host)
|
1436
461
|
schema = @ssl ? 'https' : 'http'
|
1437
|
-
"#{schema}://#{host}:#{@port}
|
462
|
+
"#{schema}://#{host}:#{@port}#{@base_path + url}"
|
1438
463
|
end
|
1439
464
|
|
1440
465
|
def guard_no_sslv3
|
@@ -1543,9 +568,14 @@ class API
|
|
1543
568
|
# TODO error
|
1544
569
|
end
|
1545
570
|
|
1546
|
-
|
1547
|
-
|
1548
|
-
|
571
|
+
if ''.respond_to?(:encode)
|
572
|
+
def e(s)
|
573
|
+
CGI.escape(s.to_s.encode("UTF-8"))
|
574
|
+
end
|
575
|
+
else
|
576
|
+
def e(s)
|
577
|
+
CGI.escape(s.to_s)
|
578
|
+
end
|
1549
579
|
end
|
1550
580
|
|
1551
581
|
def checked_json(body, required)
|
@@ -1568,22 +598,3 @@ class API
|
|
1568
598
|
end
|
1569
599
|
|
1570
600
|
end # module TreasureData
|
1571
|
-
|
1572
|
-
require 'openssl'
|
1573
|
-
module OpenSSL
|
1574
|
-
module SSL
|
1575
|
-
class SSLContext
|
1576
|
-
|
1577
|
-
# For disabling SSLv3 connection in favor of POODLE Attack protection
|
1578
|
-
#
|
1579
|
-
# Allow 'options' customize through Thread local storage since
|
1580
|
-
# Net::HTTP does not support 'options' configuration.
|
1581
|
-
#
|
1582
|
-
alias original_set_params set_params
|
1583
|
-
def set_params(params={})
|
1584
|
-
original_set_params(params)
|
1585
|
-
self.options |= OP_NO_SSLv3 if Thread.current[:SET_SSL_OP_NO_SSLv3]
|
1586
|
-
end
|
1587
|
-
end
|
1588
|
-
end
|
1589
|
-
end
|