td-client 1.0.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/data/ca-bundle.crt +3448 -0
- data/lib/td-client.rb +1 -0
- data/lib/td/client.rb +606 -0
- data/lib/td/client/api.rb +707 -0
- data/lib/td/client/api/access_control.rb +74 -0
- data/lib/td/client/api/account.rb +45 -0
- data/lib/td/client/api/bulk_import.rb +184 -0
- data/lib/td/client/api/bulk_load.rb +172 -0
- data/lib/td/client/api/database.rb +50 -0
- data/lib/td/client/api/export.rb +38 -0
- data/lib/td/client/api/import.rb +38 -0
- data/lib/td/client/api/job.rb +390 -0
- data/lib/td/client/api/partial_delete.rb +27 -0
- data/lib/td/client/api/result.rb +46 -0
- data/lib/td/client/api/schedule.rb +120 -0
- data/lib/td/client/api/server_status.rb +21 -0
- data/lib/td/client/api/table.rb +132 -0
- data/lib/td/client/api/user.rb +134 -0
- data/lib/td/client/api_error.rb +37 -0
- data/lib/td/client/compat_gzip_reader.rb +22 -0
- data/lib/td/client/model.rb +816 -0
- data/lib/td/client/version.rb +5 -0
- data/lib/td/core_ext/openssl/ssl/sslcontext/set_params.rb +18 -0
- data/spec/spec_helper.rb +63 -0
- 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_error_spec.rb +77 -0
- data/spec/td/client/api_spec.rb +269 -0
- data/spec/td/client/api_ssl_connection_spec.rb +109 -0
- data/spec/td/client/bulk_import_spec.rb +199 -0
- data/spec/td/client/bulk_load_spec.rb +401 -0
- data/spec/td/client/db_api_spec.rb +123 -0
- data/spec/td/client/export_api_spec.rb +51 -0
- data/spec/td/client/import_api_spec.rb +148 -0
- data/spec/td/client/job_api_spec.rb +833 -0
- data/spec/td/client/model_job_spec.rb +136 -0
- data/spec/td/client/model_schedule_spec.rb +26 -0
- data/spec/td/client/model_schema_spec.rb +134 -0
- data/spec/td/client/partial_delete_api_spec.rb +58 -0
- data/spec/td/client/result_api_spec.rb +77 -0
- data/spec/td/client/sched_api_spec.rb +109 -0
- data/spec/td/client/server_status_api_spec.rb +25 -0
- data/spec/td/client/spec_resources.rb +99 -0
- data/spec/td/client/table_api_spec.rb +226 -0
- data/spec/td/client/user_api_spec.rb +118 -0
- data/spec/td/client_sched_spec.rb +79 -0
- data/spec/td/client_spec.rb +46 -0
- metadata +271 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
module TreasureData
|
2
|
+
|
3
|
+
class ParameterValidationError < StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
# Generic API error
|
7
|
+
class APIError < StandardError
|
8
|
+
attr_reader :api_backtrace
|
9
|
+
|
10
|
+
def initialize(error_message = nil, api_backtrace = nil)
|
11
|
+
super(error_message)
|
12
|
+
@api_backtrace = api_backtrace == '' ? nil : api_backtrace
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# 401 API errors
|
17
|
+
class AuthError < APIError
|
18
|
+
end
|
19
|
+
|
20
|
+
# 403 API errors, used for database permissions
|
21
|
+
class ForbiddenError < APIError
|
22
|
+
end
|
23
|
+
|
24
|
+
# 409 API errors
|
25
|
+
class AlreadyExistsError < APIError
|
26
|
+
attr_reader :conflicts_with
|
27
|
+
def initialize(error_message = nil, api_backtrace = nil, conflicts_with=nil)
|
28
|
+
super(error_message, api_backtrace)
|
29
|
+
@conflicts_with = conflicts_with
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# 404 API errors
|
34
|
+
class NotFoundError < APIError
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
methods = Zlib::GzipReader.public_instance_methods
|
3
|
+
if !methods.include?(:readpartial) && !methods.include?('readpartial')
|
4
|
+
class Zlib::GzipReader
|
5
|
+
# @param [Fixnum] size
|
6
|
+
# @param [IO] out
|
7
|
+
# @return [String]
|
8
|
+
def readpartial(size, out=nil)
|
9
|
+
o = read(size)
|
10
|
+
if o
|
11
|
+
if out
|
12
|
+
out.replace(o)
|
13
|
+
return out
|
14
|
+
else
|
15
|
+
return o
|
16
|
+
end
|
17
|
+
end
|
18
|
+
raise EOFError, "end of file reached"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,816 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
|
3
|
+
module TreasureData
|
4
|
+
|
5
|
+
class Model
|
6
|
+
# @param [TreasureData::Client] client
|
7
|
+
def initialize(client)
|
8
|
+
@client = client
|
9
|
+
end
|
10
|
+
|
11
|
+
# @!attribute [r] client
|
12
|
+
# @return [TreasureData::Client] client
|
13
|
+
attr_reader :client
|
14
|
+
end
|
15
|
+
|
16
|
+
class Account < Model
|
17
|
+
# @param [TreasureData::Client] client
|
18
|
+
# @param [String] account_id
|
19
|
+
# @param [Fixnum] plan
|
20
|
+
# @param [Fixnum] storage_size
|
21
|
+
# @param [Fixnum] guaranteed_cores
|
22
|
+
# @param [Fixnum] maximum_cores
|
23
|
+
# @param [String] created_at
|
24
|
+
def initialize(client, account_id, plan, storage_size=nil, guaranteed_cores=nil, maximum_cores=nil, created_at=nil)
|
25
|
+
super(client)
|
26
|
+
@account_id = account_id
|
27
|
+
@plan = plan
|
28
|
+
@storage_size = storage_size
|
29
|
+
@guaranteed_cores = guaranteed_cores
|
30
|
+
@maximum_cores = maximum_cores
|
31
|
+
@created_at = created_at
|
32
|
+
end
|
33
|
+
|
34
|
+
# @!attribute [r] account_id
|
35
|
+
# @!attribute [r] plan
|
36
|
+
# @!attribute [r] storage_size
|
37
|
+
# @!attribute [r] guaranteed_cores
|
38
|
+
# @!attribute [r] maximum_cores
|
39
|
+
attr_reader :account_id, :plan, :storage_size, :guaranteed_cores, :maximum_cores
|
40
|
+
|
41
|
+
# @return <Time, nil>
|
42
|
+
def created_at
|
43
|
+
@created_at && !@created_at.empty? ? Time.parse(@created_at) : nil
|
44
|
+
end
|
45
|
+
|
46
|
+
# @return <String>
|
47
|
+
def storage_size_string
|
48
|
+
if @storage_size <= 1024 * 1024
|
49
|
+
return "0.0 GB"
|
50
|
+
elsif @storage_size <= 60 * 1024 * 1024
|
51
|
+
return "0.01 GB"
|
52
|
+
elsif @storage_size <= 60 * 1024 * 1024 * 1024
|
53
|
+
"%.1f GB" % (@storage_size.to_f / (1024 * 1024 * 1024))
|
54
|
+
else
|
55
|
+
"%d GB" % (@storage_size.to_f / (1024 * 1024 * 1024)).to_i
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class Database < Model
|
61
|
+
PERMISSIONS = [:administrator, :full_access, :import_only, :query_only]
|
62
|
+
PERMISSION_LIST_TABLES = [:administrator, :full_access]
|
63
|
+
|
64
|
+
# @param [TreasureData::Client] client
|
65
|
+
# @param [String] db_name
|
66
|
+
# @param [Array<Table>] tables
|
67
|
+
# @param [Fixnum] count
|
68
|
+
# @param [String] created_at
|
69
|
+
# @param [String] updated_at
|
70
|
+
# @param [String] org_name
|
71
|
+
# @param [String] permission
|
72
|
+
def initialize(client, db_name, tables=nil, count=nil, created_at=nil, updated_at=nil, org_name=nil, permission=nil)
|
73
|
+
super(client)
|
74
|
+
@db_name = db_name
|
75
|
+
@tables = tables
|
76
|
+
@count = count
|
77
|
+
@created_at = created_at
|
78
|
+
@updated_at = updated_at
|
79
|
+
@permission = permission.to_sym
|
80
|
+
end
|
81
|
+
|
82
|
+
# @!attribute [r] org_name
|
83
|
+
# @!attribute [r] permission
|
84
|
+
# @!attribute [r] count
|
85
|
+
attr_reader :org_name, :permission, :count
|
86
|
+
|
87
|
+
# @return [String] db_name
|
88
|
+
def name
|
89
|
+
@db_name
|
90
|
+
end
|
91
|
+
|
92
|
+
# @return [Array<Table>]
|
93
|
+
def tables
|
94
|
+
update_tables! unless @tables
|
95
|
+
@tables
|
96
|
+
end
|
97
|
+
|
98
|
+
# @param [String] name
|
99
|
+
# @return [true]
|
100
|
+
def create_log_table(name)
|
101
|
+
@client.create_log_table(@db_name, name)
|
102
|
+
end
|
103
|
+
|
104
|
+
# @param [String] table_name
|
105
|
+
# @return [Table]
|
106
|
+
def table(table_name)
|
107
|
+
@client.table(@db_name, table_name)
|
108
|
+
end
|
109
|
+
|
110
|
+
# @return [Symbol]
|
111
|
+
def delete
|
112
|
+
@client.delete_database(@db_name)
|
113
|
+
end
|
114
|
+
|
115
|
+
# @param [String] q
|
116
|
+
# @return [Job]
|
117
|
+
def query(q)
|
118
|
+
@client.query(@db_name, q)
|
119
|
+
end
|
120
|
+
|
121
|
+
# @return [Time, nil]
|
122
|
+
def created_at
|
123
|
+
@created_at && !@created_at.empty? ? Time.parse(@created_at) : nil
|
124
|
+
end
|
125
|
+
|
126
|
+
# @return [Time, nil]
|
127
|
+
def updated_at
|
128
|
+
@updated_at && !@updated_at.empty? ? Time.parse(@updated_at) : nil
|
129
|
+
end
|
130
|
+
|
131
|
+
# @return [nil]
|
132
|
+
def update_tables!
|
133
|
+
@tables = @client.tables(@db_name)
|
134
|
+
# provide Table objects with a reference to the parent Database to avoid
|
135
|
+
# requesting the Database information (such as permission) every time
|
136
|
+
@tables.each {|table|
|
137
|
+
table.database = self
|
138
|
+
}
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
class Table < Model
|
144
|
+
# @param [TreasureData::Client] client
|
145
|
+
# @param [String] db_name
|
146
|
+
# @param [String] table_name
|
147
|
+
# @param [String] type
|
148
|
+
# @param [String] schema
|
149
|
+
# @param [Fixnum] count
|
150
|
+
# @param [String] created_at
|
151
|
+
# @param [String] updated_at
|
152
|
+
# @param [Fixnum] estimated_storage_size
|
153
|
+
# @param [String] last_import
|
154
|
+
# @param [String] last_log_timestamp
|
155
|
+
# @param [Fixnum, String] expire_days
|
156
|
+
def initialize(client, db_name, table_name, type, schema, count, created_at=nil, updated_at=nil, estimated_storage_size=nil, last_import=nil, last_log_timestamp=nil, expire_days=nil)
|
157
|
+
super(client)
|
158
|
+
@database = nil
|
159
|
+
@db_name = db_name
|
160
|
+
@table_name = table_name
|
161
|
+
@type = type
|
162
|
+
@schema = schema
|
163
|
+
@count = count
|
164
|
+
@created_at = created_at
|
165
|
+
@updated_at = updated_at
|
166
|
+
@estimated_storage_size = estimated_storage_size
|
167
|
+
@last_import = last_import
|
168
|
+
@last_log_timestamp = last_log_timestamp
|
169
|
+
@expire_days = expire_days
|
170
|
+
end
|
171
|
+
|
172
|
+
# @!attribute [r] type
|
173
|
+
# @!attribute [r] db_name
|
174
|
+
# @!attribute [r] table_name
|
175
|
+
# @!attribute [r] schema
|
176
|
+
# @!attribute [r] count
|
177
|
+
# @!attribute [r] estimated_storage_size
|
178
|
+
attr_reader :type, :db_name, :table_name, :schema, :count, :estimated_storage_size
|
179
|
+
|
180
|
+
alias database_name db_name
|
181
|
+
alias name table_name
|
182
|
+
|
183
|
+
# @param [String] database
|
184
|
+
def database=(database)
|
185
|
+
@database = database if database.instance_of?(Database)
|
186
|
+
end
|
187
|
+
|
188
|
+
# @return [Time, nil]
|
189
|
+
def created_at
|
190
|
+
@created_at && !@created_at.empty? ? Time.parse(@created_at) : nil
|
191
|
+
end
|
192
|
+
|
193
|
+
# @return [Time, nil]
|
194
|
+
def updated_at
|
195
|
+
@updated_at && !@updated_at.empty? ? Time.parse(@updated_at) : nil
|
196
|
+
end
|
197
|
+
|
198
|
+
# @return [Time, nil]
|
199
|
+
def last_import
|
200
|
+
@last_import && !@last_import.empty? ? Time.parse(@last_import) : nil
|
201
|
+
end
|
202
|
+
|
203
|
+
# @return [Time, nil]
|
204
|
+
def last_log_timestamp
|
205
|
+
@last_log_timestamp && !@last_log_timestamp.empty? ? Time.parse(@last_log_timestamp) : nil
|
206
|
+
end
|
207
|
+
|
208
|
+
# @return [Fixnum, nil]
|
209
|
+
def expire_days
|
210
|
+
@expire_days ? @expire_days.to_i : nil
|
211
|
+
end
|
212
|
+
|
213
|
+
# @return [Database]
|
214
|
+
def database
|
215
|
+
update_database! unless @database
|
216
|
+
@database
|
217
|
+
end
|
218
|
+
|
219
|
+
# get the database's permission as if they were the table's
|
220
|
+
# @return [String]
|
221
|
+
def permission
|
222
|
+
database.permission
|
223
|
+
end
|
224
|
+
|
225
|
+
# @return [String]
|
226
|
+
def identifier
|
227
|
+
"#{@db_name}.#{@table_name}"
|
228
|
+
end
|
229
|
+
|
230
|
+
# @return [Symbol]
|
231
|
+
def delete
|
232
|
+
@client.delete_table(@db_name, @table_name)
|
233
|
+
end
|
234
|
+
|
235
|
+
# @param [Fixnum] count
|
236
|
+
# @return [Array, nil]
|
237
|
+
def tail(count)
|
238
|
+
@client.tail(@db_name, @table_name, count)
|
239
|
+
end
|
240
|
+
|
241
|
+
# @param [String] format
|
242
|
+
# @param [String, StringIO] stream
|
243
|
+
# @param [Fixnum] size
|
244
|
+
# @return [Float]
|
245
|
+
def import(format, stream, size)
|
246
|
+
@client.import(@db_name, @table_name, format, stream, size)
|
247
|
+
end
|
248
|
+
|
249
|
+
# @param [String] storage_type
|
250
|
+
# @param [Hash] opts
|
251
|
+
# @return [Job]
|
252
|
+
def export(storage_type, opts={})
|
253
|
+
@client.export(@db_name, @table_name, storage_type, opts)
|
254
|
+
end
|
255
|
+
|
256
|
+
# @return [String]
|
257
|
+
def estimated_storage_size_string
|
258
|
+
if @estimated_storage_size <= 1024*1024
|
259
|
+
return "0.0 GB"
|
260
|
+
elsif @estimated_storage_size <= 60*1024*1024
|
261
|
+
return "0.01 GB"
|
262
|
+
elsif @estimated_storage_size <= 60*1024*1024*1024
|
263
|
+
"%.1f GB" % (@estimated_storage_size.to_f / (1024*1024*1024))
|
264
|
+
else
|
265
|
+
"%d GB" % (@estimated_storage_size.to_f / (1024*1024*1024)).to_i
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def update_database!
|
270
|
+
@database = @client.database(@db_name)
|
271
|
+
end
|
272
|
+
|
273
|
+
# @return [String]
|
274
|
+
def inspect
|
275
|
+
%[#<%s:%#0#{1.size*2}x @db_name="%s" @table_name="%s">] %
|
276
|
+
[self.class.name, self.__id__*2, @db_name, @table_name]
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
class Schema
|
281
|
+
class Field
|
282
|
+
# @param [String] name
|
283
|
+
# @param [String] type
|
284
|
+
# @param [String] sql_alias
|
285
|
+
def initialize(name, type, sql_alias=nil)
|
286
|
+
if name == 'v' || name == 'time'
|
287
|
+
raise ParameterValidationError, "Column name '#{name}' is reserved."
|
288
|
+
end
|
289
|
+
API.validate_column_name(name)
|
290
|
+
API.validate_sql_alias_name(sql_alias) if sql_alias
|
291
|
+
@name = name
|
292
|
+
@type = type
|
293
|
+
@sql_alias = sql_alias
|
294
|
+
end
|
295
|
+
|
296
|
+
# @!attribute [r] name
|
297
|
+
# @!attribute [r] type
|
298
|
+
attr_reader :name
|
299
|
+
attr_reader :type
|
300
|
+
attr_reader :sql_alias
|
301
|
+
end
|
302
|
+
|
303
|
+
# @param [String] columns
|
304
|
+
# @return [Schema]
|
305
|
+
def self.parse(columns)
|
306
|
+
schema = Schema.new
|
307
|
+
columns.each {|column|
|
308
|
+
unless /\A(?<name>.*)(?::(?<type>[^:@]+))(?:@(?<sql_alias>[^:@]+))?\z/ =~ column
|
309
|
+
raise ParameterValidationError, "type must be specified"
|
310
|
+
end
|
311
|
+
schema.add_field(name, type, sql_alias)
|
312
|
+
}
|
313
|
+
schema
|
314
|
+
end
|
315
|
+
|
316
|
+
# @param [Array] fields
|
317
|
+
def initialize(fields=[])
|
318
|
+
@fields = fields
|
319
|
+
@names = {}
|
320
|
+
@fields.each do |f|
|
321
|
+
raise ArgumentError, "Column name '#{f.name}' is duplicated." if @names.key?(f.name)
|
322
|
+
@names[f.name] = true
|
323
|
+
if f.sql_alias
|
324
|
+
raise ArgumentError, "SQL Column alias '#{f.sql_alias}' is duplicated." if @names.key?(f.sql_alias)
|
325
|
+
@names[f.sql_alias] = true
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
# @!attribute [r] fields
|
331
|
+
attr_reader :fields
|
332
|
+
|
333
|
+
# @param [String] name
|
334
|
+
# @param [String] type
|
335
|
+
# @return [Array]
|
336
|
+
def add_field(name, type, sql_alias=nil)
|
337
|
+
if @names.key?(name)
|
338
|
+
raise ParameterValidationError, "Column name '#{name}' is duplicated."
|
339
|
+
end
|
340
|
+
@names[name] = true
|
341
|
+
if sql_alias && @names.key?(sql_alias)
|
342
|
+
raise ParameterValidationError, "SQL Column alias '#{sql_alias}' is duplicated."
|
343
|
+
end
|
344
|
+
@names[sql_alias] = true
|
345
|
+
@fields << Field.new(name, type, sql_alias)
|
346
|
+
end
|
347
|
+
|
348
|
+
# @param [Schema] schema
|
349
|
+
# @return [Schema]
|
350
|
+
def merge(schema)
|
351
|
+
nf = @fields.dup
|
352
|
+
schema.fields.each {|f|
|
353
|
+
if i = nf.find_index {|sf| sf.name == f.name }
|
354
|
+
nf[i] = f
|
355
|
+
else
|
356
|
+
nf << f
|
357
|
+
end
|
358
|
+
}
|
359
|
+
Schema.new(nf)
|
360
|
+
end
|
361
|
+
|
362
|
+
# @return [Array<Field>]
|
363
|
+
def to_json(*args)
|
364
|
+
@fields.map {|f| f.sql_alias ? [f.name, f.type, f.sql_alias] : [f.name, f.type] }.to_json(*args)
|
365
|
+
end
|
366
|
+
|
367
|
+
# @param [Object] obj
|
368
|
+
# @return [self]
|
369
|
+
def from_json(obj)
|
370
|
+
@fields = obj.map {|f|
|
371
|
+
Field.new(*f)
|
372
|
+
}
|
373
|
+
self
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
class Job < Model
|
378
|
+
STATUS_QUEUED = "queued"
|
379
|
+
STATUS_BOOTING = "booting"
|
380
|
+
STATUS_RUNNING = "running"
|
381
|
+
STATUS_SUCCESS = "success"
|
382
|
+
STATUS_ERROR = "error"
|
383
|
+
STATUS_KILLED = "killed"
|
384
|
+
FINISHED_STATUS = [STATUS_SUCCESS, STATUS_ERROR, STATUS_KILLED]
|
385
|
+
|
386
|
+
# @param [TreasureData::Client] client
|
387
|
+
# @param [String] job_id
|
388
|
+
# @param [String] type
|
389
|
+
# @param [String] query
|
390
|
+
# @param [Fixnum] status
|
391
|
+
# @param [String] url
|
392
|
+
# @param [Boolean] debug
|
393
|
+
# @param [String] start_at
|
394
|
+
# @param [String] end_at
|
395
|
+
# @param [String] cpu_time
|
396
|
+
# @param [String] result_size
|
397
|
+
# @param [Array] result
|
398
|
+
# @param [String] result_url
|
399
|
+
# @param [Array] hive_result_schema
|
400
|
+
# @param [Fixnum] priority
|
401
|
+
# @param [Fixnum] retry_limit
|
402
|
+
# @param [String] org_name
|
403
|
+
# @param [String] db_name
|
404
|
+
# @param [Fixnum] duration
|
405
|
+
# @param [Fixnum] num_records
|
406
|
+
def initialize(client, job_id, type, query, status=nil, url=nil, debug=nil, start_at=nil, end_at=nil, cpu_time=nil,
|
407
|
+
result_size=nil, result=nil, result_url=nil, hive_result_schema=nil, priority=nil, retry_limit=nil,
|
408
|
+
org_name=nil, db_name=nil, duration=nil, num_records=nil)
|
409
|
+
super(client)
|
410
|
+
@job_id = job_id
|
411
|
+
@type = type
|
412
|
+
@url = url
|
413
|
+
@query = query
|
414
|
+
@status = status
|
415
|
+
@debug = debug
|
416
|
+
@start_at = start_at
|
417
|
+
@end_at = end_at
|
418
|
+
@cpu_time = cpu_time
|
419
|
+
@result_size = result_size
|
420
|
+
@result = result
|
421
|
+
@result_url = result_url
|
422
|
+
@hive_result_schema = hive_result_schema
|
423
|
+
@priority = priority
|
424
|
+
@retry_limit = retry_limit
|
425
|
+
@db_name = db_name
|
426
|
+
@duration = duration
|
427
|
+
@num_records = num_records
|
428
|
+
end
|
429
|
+
|
430
|
+
# @!attribute [r] job_id
|
431
|
+
# @!attribute [r] type
|
432
|
+
# @!attribute [r] result_url
|
433
|
+
# @!attribute [r] priority
|
434
|
+
# @!attribute [r] retry_limit
|
435
|
+
# @!attribute [r] org_name
|
436
|
+
# @!attribute [r] db_name
|
437
|
+
# @!attribute [r] duration
|
438
|
+
# @!attribute [r] num_records
|
439
|
+
attr_reader :job_id, :type, :result_url
|
440
|
+
attr_reader :priority, :retry_limit, :org_name, :db_name
|
441
|
+
attr_reader :duration, :num_records
|
442
|
+
|
443
|
+
# @option timeout [Integer,nil] timeout in second
|
444
|
+
# @option wait_interval [Integer,nil] interval in second of polling the job status
|
445
|
+
# @param detail [Boolean] update job detail or not
|
446
|
+
# @param verbose [Boolean] out retry log to stderr or not
|
447
|
+
def wait(*args)
|
448
|
+
opthash = Hash.try_convert(args.last)
|
449
|
+
if opthash
|
450
|
+
args.pop
|
451
|
+
detail = opthash.fetch(:detail, false)
|
452
|
+
verbose = opthash.fetch(:verbose, ENV['TD_CLIENT_DEBUG'])
|
453
|
+
end
|
454
|
+
timeout = args[0]
|
455
|
+
wait_interval = args[1] || 2
|
456
|
+
deadline = monotonic_clock + timeout if timeout
|
457
|
+
timeout_klass = Class.new(Exception)
|
458
|
+
begin
|
459
|
+
if timeout
|
460
|
+
if deadline <= monotonic_clock
|
461
|
+
raise timeout_klass, "timeout (#{timeout}) exceeded wait_interval=#{wait_interval}"
|
462
|
+
end
|
463
|
+
end
|
464
|
+
sleep wait_interval
|
465
|
+
detail ? update_status! : update_progress!
|
466
|
+
yield self if block_given?
|
467
|
+
rescue timeout_klass
|
468
|
+
raise Timeout::Error, $!.message
|
469
|
+
rescue Timeout::Error, SystemCallError, EOFError, SocketError, HTTPClient::ConnectTimeoutError
|
470
|
+
$stderr.puts "ignore network error (#{$!}); retry..." if verbose
|
471
|
+
end until finished?
|
472
|
+
end
|
473
|
+
|
474
|
+
def kill!
|
475
|
+
# TODO
|
476
|
+
end
|
477
|
+
|
478
|
+
# @return [String]
|
479
|
+
def query
|
480
|
+
update_status! unless @query || finished?
|
481
|
+
@query
|
482
|
+
end
|
483
|
+
|
484
|
+
# @return [String]
|
485
|
+
def status
|
486
|
+
update_status! unless @status || finished?
|
487
|
+
@status
|
488
|
+
end
|
489
|
+
|
490
|
+
# @return [String]
|
491
|
+
def url
|
492
|
+
update_status! unless @url || finished?
|
493
|
+
@url
|
494
|
+
end
|
495
|
+
|
496
|
+
# @return [Boolean]
|
497
|
+
def debug
|
498
|
+
update_status! unless @debug || finished?
|
499
|
+
@debug
|
500
|
+
end
|
501
|
+
|
502
|
+
# @return [Time, nil]
|
503
|
+
def start_at
|
504
|
+
update_status! unless @start_at || finished?
|
505
|
+
@start_at && !@start_at.empty? ? Time.parse(@start_at) : nil
|
506
|
+
end
|
507
|
+
|
508
|
+
# @return [Time, nil]
|
509
|
+
def end_at
|
510
|
+
update_status! unless @end_at || finished?
|
511
|
+
@end_at && !@end_at.empty? ? Time.parse(@end_at) : nil
|
512
|
+
end
|
513
|
+
|
514
|
+
# @return [String]
|
515
|
+
def cpu_time
|
516
|
+
update_status! unless @cpu_time || finished?
|
517
|
+
@cpu_time
|
518
|
+
end
|
519
|
+
|
520
|
+
# @return [Array]
|
521
|
+
def hive_result_schema
|
522
|
+
update_status! unless @hive_result_schema.instance_of? Array || finished?
|
523
|
+
@hive_result_schema
|
524
|
+
end
|
525
|
+
|
526
|
+
# @return [String]
|
527
|
+
def result_size
|
528
|
+
update_status! unless @result_size || finished?
|
529
|
+
@result_size
|
530
|
+
end
|
531
|
+
|
532
|
+
# @return [Array]
|
533
|
+
def result
|
534
|
+
unless @result
|
535
|
+
return nil unless finished?
|
536
|
+
@result = @client.job_result(@job_id)
|
537
|
+
end
|
538
|
+
@result
|
539
|
+
end
|
540
|
+
|
541
|
+
# @param [String] format
|
542
|
+
# @param [IO] io
|
543
|
+
# @param [Proc] block
|
544
|
+
# @return [nil, String]
|
545
|
+
def result_format(format, io=nil, &block)
|
546
|
+
return nil unless finished?
|
547
|
+
@client.job_result_format(@job_id, format, io, &block)
|
548
|
+
end
|
549
|
+
|
550
|
+
def result_raw(format, io=nil, &block)
|
551
|
+
return nil unless finished?
|
552
|
+
@client.job_result_raw(@job_id, format, io, &block)
|
553
|
+
end
|
554
|
+
|
555
|
+
# @yield [result]
|
556
|
+
# @return [nil]
|
557
|
+
def result_each_with_compr_size(&block)
|
558
|
+
if @result
|
559
|
+
@result.each(&block)
|
560
|
+
else
|
561
|
+
@client.job_result_each_with_compr_size(@job_id, &block)
|
562
|
+
end
|
563
|
+
nil
|
564
|
+
end
|
565
|
+
|
566
|
+
# @yield [result]
|
567
|
+
# @return [nil]
|
568
|
+
def result_each(&block)
|
569
|
+
if @result
|
570
|
+
@result.each(&block)
|
571
|
+
else
|
572
|
+
@client.job_result_each(@job_id, &block)
|
573
|
+
end
|
574
|
+
nil
|
575
|
+
end
|
576
|
+
|
577
|
+
# @return [Boolean]
|
578
|
+
def finished?
|
579
|
+
update_progress! unless @status
|
580
|
+
FINISHED_STATUS.include?(@status)
|
581
|
+
end
|
582
|
+
|
583
|
+
# @return [Boolean]
|
584
|
+
def success?
|
585
|
+
update_progress! unless @status
|
586
|
+
@status == STATUS_SUCCESS
|
587
|
+
end
|
588
|
+
|
589
|
+
# @return [Boolean]
|
590
|
+
def error?
|
591
|
+
update_progress! unless @status
|
592
|
+
@status == STATUS_ERROR
|
593
|
+
end
|
594
|
+
|
595
|
+
# @return [Boolean]
|
596
|
+
def killed?
|
597
|
+
update_progress! unless @status
|
598
|
+
@status == STATUS_KILLED
|
599
|
+
end
|
600
|
+
|
601
|
+
# @return [Boolean]
|
602
|
+
def queued?
|
603
|
+
update_progress! unless @status
|
604
|
+
@status == STATUS_QUEUED
|
605
|
+
end
|
606
|
+
|
607
|
+
# @return [Boolean]
|
608
|
+
def running?
|
609
|
+
update_progress! unless @status
|
610
|
+
@status == STATUS_RUNNING
|
611
|
+
end
|
612
|
+
|
613
|
+
def update_progress!
|
614
|
+
@status = @client.job_status(@job_id)
|
615
|
+
end
|
616
|
+
|
617
|
+
def update_status!
|
618
|
+
type, query, status, url, debug, start_at, end_at, cpu_time,
|
619
|
+
result_size, result_url, hive_result_schema, priority, retry_limit,
|
620
|
+
org_name, db_name , duration, num_records = @client.api.show_job(@job_id)
|
621
|
+
@query = query
|
622
|
+
@status = status
|
623
|
+
@url = url
|
624
|
+
@debug = debug
|
625
|
+
@start_at = start_at
|
626
|
+
@end_at = end_at
|
627
|
+
@cpu_time = cpu_time
|
628
|
+
@result_size = result_size
|
629
|
+
@result_url = result_url
|
630
|
+
@hive_result_schema = hive_result_schema
|
631
|
+
@priority = priority
|
632
|
+
@retry_limit = retry_limit
|
633
|
+
@db_name = db_name
|
634
|
+
@duration = duration
|
635
|
+
@num_records = num_records
|
636
|
+
self
|
637
|
+
end
|
638
|
+
|
639
|
+
private
|
640
|
+
def monotonic_clock
|
641
|
+
if defined?(Process.clock_gettime)
|
642
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
643
|
+
else
|
644
|
+
Time.now.to_i
|
645
|
+
end
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|
649
|
+
|
650
|
+
class ScheduledJob < Job
|
651
|
+
attr_reader :scheduled_at
|
652
|
+
|
653
|
+
# @param [TreasureData::Client] client
|
654
|
+
# @param [String] scheduled_at
|
655
|
+
# @param [...] super_args for Job#initialize
|
656
|
+
def initialize(client, scheduled_at, *super_args)
|
657
|
+
super(client, *super_args)
|
658
|
+
if scheduled_at.to_s.empty?
|
659
|
+
@scheduled_at = nil
|
660
|
+
else
|
661
|
+
@scheduled_at = Time.parse(scheduled_at) rescue nil
|
662
|
+
end
|
663
|
+
end
|
664
|
+
end
|
665
|
+
|
666
|
+
|
667
|
+
class Schedule < Model
|
668
|
+
# @param [TreasureData::Client] client
|
669
|
+
# @param [String] name
|
670
|
+
# @param [String] cron
|
671
|
+
# @param [String] query
|
672
|
+
# @param [Fixnum] database
|
673
|
+
# @param [String] result_url
|
674
|
+
# @param [String] timezone
|
675
|
+
# @param [String] delay
|
676
|
+
# @param [String] next_time
|
677
|
+
# @param [String] priority
|
678
|
+
# @param [String] retry_limit
|
679
|
+
# @param [String] org_name
|
680
|
+
def initialize(client, name, cron, query, database=nil, result_url=nil, timezone=nil, delay=nil, next_time=nil,
|
681
|
+
priority=nil, retry_limit=nil, org_name=nil)
|
682
|
+
super(client)
|
683
|
+
@name = name
|
684
|
+
@cron = cron
|
685
|
+
@query = query
|
686
|
+
@database = database
|
687
|
+
@result_url = result_url
|
688
|
+
@timezone = timezone
|
689
|
+
@delay = delay
|
690
|
+
@next_time = next_time
|
691
|
+
@priority = priority
|
692
|
+
@retry_limit = retry_limit
|
693
|
+
end
|
694
|
+
|
695
|
+
# @!attribute [r] name
|
696
|
+
# @!attribute [r] cron
|
697
|
+
# @!attribute [r] query
|
698
|
+
# @!attribute [r] database
|
699
|
+
# @!attribute [r] result_url
|
700
|
+
# @!attribute [r] delay
|
701
|
+
# @!attribute [r] priority
|
702
|
+
# @!attribute [r] retry_limit
|
703
|
+
# @!attribute [r] org_name
|
704
|
+
attr_reader :name, :cron, :query, :database, :result_url, :timezone, :delay, :priority, :retry_limit, :org_name
|
705
|
+
|
706
|
+
# @return [Time, nil]
|
707
|
+
def next_time
|
708
|
+
@next_time ? Time.parse(@next_time) : nil
|
709
|
+
end
|
710
|
+
|
711
|
+
# @param [String] time
|
712
|
+
# @param [Fixnum] num
|
713
|
+
# @return [Array]
|
714
|
+
def run(time, num)
|
715
|
+
@client.run_schedule(@name, time, num)
|
716
|
+
end
|
717
|
+
end
|
718
|
+
|
719
|
+
|
720
|
+
class Result < Model
|
721
|
+
# @param [TreasureData::Client] client
|
722
|
+
# @param [String] name
|
723
|
+
# @param [String] url
|
724
|
+
# @param [String] org_name
|
725
|
+
def initialize(client, name, url, org_name)
|
726
|
+
super(client)
|
727
|
+
@name = name
|
728
|
+
@url = url
|
729
|
+
end
|
730
|
+
|
731
|
+
# @!attribute [r] name
|
732
|
+
# @!attribute [r] url
|
733
|
+
# @!attribute [r] org_name
|
734
|
+
attr_reader :name, :url, :org_name
|
735
|
+
end
|
736
|
+
|
737
|
+
|
738
|
+
class BulkImport < Model
|
739
|
+
# @param [TreasureData::Client] client
|
740
|
+
# @param [Hash] data
|
741
|
+
def initialize(client, data={})
|
742
|
+
super(client)
|
743
|
+
@name = data['name']
|
744
|
+
@database = data['database']
|
745
|
+
@table = data['table']
|
746
|
+
@status = data['status']
|
747
|
+
@upload_frozen = data['upload_frozen']
|
748
|
+
@job_id = data['job_id']
|
749
|
+
@valid_records = data['valid_records']
|
750
|
+
@error_records = data['error_records']
|
751
|
+
@valid_parts = data['valid_parts']
|
752
|
+
@error_parts = data['error_parts']
|
753
|
+
end
|
754
|
+
|
755
|
+
# @!attribute [r] name
|
756
|
+
# @!attribute [r] database
|
757
|
+
# @!attribute [r] table
|
758
|
+
# @!attribute [r] status
|
759
|
+
# @!attribute [r] job_id
|
760
|
+
# @!attribute [r] valid_records
|
761
|
+
# @!attribute [r] error_records
|
762
|
+
# @!attribute [r] valid_parts
|
763
|
+
# @!attribute [r] error_parts
|
764
|
+
# @!attribute [r] org_name
|
765
|
+
attr_reader :name
|
766
|
+
attr_reader :database
|
767
|
+
attr_reader :table
|
768
|
+
attr_reader :status
|
769
|
+
attr_reader :job_id
|
770
|
+
attr_reader :valid_records
|
771
|
+
attr_reader :error_records
|
772
|
+
attr_reader :valid_parts
|
773
|
+
attr_reader :error_parts
|
774
|
+
attr_reader :org_name
|
775
|
+
|
776
|
+
# @return [Boolean]
|
777
|
+
def upload_frozen?
|
778
|
+
@upload_frozen
|
779
|
+
end
|
780
|
+
end
|
781
|
+
|
782
|
+
|
783
|
+
class User < Model
|
784
|
+
def initialize(client, name, org_name, role_names, email)
|
785
|
+
super(client)
|
786
|
+
@name = name
|
787
|
+
@email = email
|
788
|
+
end
|
789
|
+
|
790
|
+
attr_reader :client, :name, :org_name, :role_names, :email
|
791
|
+
end
|
792
|
+
|
793
|
+
|
794
|
+
class AccessControl < Model
|
795
|
+
# @param [TreasureData::Client] client
|
796
|
+
# @param [String] subject
|
797
|
+
# @param [String] action
|
798
|
+
# @param [String] scope
|
799
|
+
# @param [Array] grant_option
|
800
|
+
def initialize(client, subject, action, scope, grant_option)
|
801
|
+
super(client)
|
802
|
+
@subject = subject
|
803
|
+
@action = action
|
804
|
+
@scope = scope
|
805
|
+
@grant_option = grant_option
|
806
|
+
end
|
807
|
+
|
808
|
+
# @!attribute [r] subject
|
809
|
+
# @!attribute [r] action
|
810
|
+
# @!attribute [r] scope
|
811
|
+
# @!attribute [r] grant_option
|
812
|
+
attr_reader :subject, :action, :scope, :grant_option
|
813
|
+
end
|
814
|
+
|
815
|
+
|
816
|
+
end
|