cnvrg 1.9.9.9.7
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 +7 -0
- data/bin/cnvrg +9 -0
- data/cnvrg.gemspec +47 -0
- data/lib/cnvrg.rb +7 -0
- data/lib/cnvrg/Images.rb +351 -0
- data/lib/cnvrg/api.rb +247 -0
- data/lib/cnvrg/api_v2.rb +14 -0
- data/lib/cnvrg/auth.rb +79 -0
- data/lib/cnvrg/cli.rb +5715 -0
- data/lib/cnvrg/cli/flow.rb +166 -0
- data/lib/cnvrg/cli/library_cli.rb +33 -0
- data/lib/cnvrg/cli/subcommand.rb +28 -0
- data/lib/cnvrg/cli/task.rb +116 -0
- data/lib/cnvrg/colors.rb +8 -0
- data/lib/cnvrg/connect_job_ssh.rb +31 -0
- data/lib/cnvrg/data.rb +335 -0
- data/lib/cnvrg/datafiles.rb +1325 -0
- data/lib/cnvrg/dataset.rb +892 -0
- data/lib/cnvrg/downloader/client.rb +101 -0
- data/lib/cnvrg/downloader/clients/azure_client.rb +45 -0
- data/lib/cnvrg/downloader/clients/gcp_client.rb +50 -0
- data/lib/cnvrg/downloader/clients/s3_client.rb +78 -0
- data/lib/cnvrg/experiment.rb +209 -0
- data/lib/cnvrg/files.rb +1047 -0
- data/lib/cnvrg/flow.rb +137 -0
- data/lib/cnvrg/helpers.rb +422 -0
- data/lib/cnvrg/helpers/agent.rb +188 -0
- data/lib/cnvrg/helpers/executer.rb +213 -0
- data/lib/cnvrg/hyper.rb +21 -0
- data/lib/cnvrg/image.rb +113 -0
- data/lib/cnvrg/image_cli.rb +25 -0
- data/lib/cnvrg/job_cli.rb +73 -0
- data/lib/cnvrg/job_ssh.rb +48 -0
- data/lib/cnvrg/logger.rb +111 -0
- data/lib/cnvrg/org_helpers.rb +5 -0
- data/lib/cnvrg/project.rb +822 -0
- data/lib/cnvrg/result.rb +29 -0
- data/lib/cnvrg/runner.rb +49 -0
- data/lib/cnvrg/ssh.rb +94 -0
- data/lib/cnvrg/storage.rb +128 -0
- data/lib/cnvrg/task.rb +165 -0
- data/lib/cnvrg/version.rb +3 -0
- metadata +460 -0
@@ -0,0 +1,1325 @@
|
|
1
|
+
require 'mimemagic'
|
2
|
+
require 'aws-sdk-s3'
|
3
|
+
require 'URLcrypt'
|
4
|
+
require 'parallel'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
|
8
|
+
module Cnvrg
|
9
|
+
class Datafiles
|
10
|
+
ParallelThreads ||= Cnvrg::Helpers.parallel_threads
|
11
|
+
|
12
|
+
LARGE_FILE=1024*1024*5
|
13
|
+
MULTIPART_SPLIT=10000000
|
14
|
+
|
15
|
+
attr_reader :base_resource
|
16
|
+
|
17
|
+
def initialize(owner, dataset_slug, dataset: nil)
|
18
|
+
@dataset_slug = dataset_slug
|
19
|
+
@owner = owner
|
20
|
+
@dataset = dataset
|
21
|
+
@base_resource = "users/#{owner}/datasets/#{dataset_slug}/"
|
22
|
+
@downloader = @dataset.get_storage_client
|
23
|
+
@token_issue_time = Time.current
|
24
|
+
end
|
25
|
+
|
26
|
+
def refresh_storage_token
|
27
|
+
current_time = Time.current
|
28
|
+
if current_time - @token_issue_time > 1.hours
|
29
|
+
@downloader = @dataset.get_storage_client
|
30
|
+
@token_issue_time = Time.current
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def check_file_sha1(filename, org_sha1, tag: 'conflict')
|
35
|
+
file_loc = "#{Dir.pwd}/#{filename}"
|
36
|
+
sha1 = OpenSSL::Digest::SHA1.file(file_loc).hexdigest
|
37
|
+
return 0 if sha1 == org_sha1
|
38
|
+
FileUtils.cp(file_loc, "#{file_loc}.#{tag}")
|
39
|
+
return 1
|
40
|
+
end
|
41
|
+
|
42
|
+
def verify_files_exists(files)
|
43
|
+
paths = []
|
44
|
+
files.each do |file|
|
45
|
+
if File.exists? file
|
46
|
+
if File.directory? file
|
47
|
+
paths += Dir.glob("#{file}/**/*")
|
48
|
+
else
|
49
|
+
paths << file
|
50
|
+
end
|
51
|
+
next
|
52
|
+
end
|
53
|
+
raise SignalException.new(1, "Cant find file #{file}") unless File.exists? "#{Dir.pwd}/#{file}"
|
54
|
+
end
|
55
|
+
paths.map{|p| p.gsub(/^\.\//, '')}
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_files_and_folders(paths)
|
59
|
+
files_and_folders = {}
|
60
|
+
paths.each do |file|
|
61
|
+
if File.exists? file
|
62
|
+
if File.directory? file
|
63
|
+
Dir.glob("#{file}/**/*").select do |f|
|
64
|
+
files_and_folders["#{f}/"] = "folder" if File.directory? f
|
65
|
+
files_and_folders[f] = "file" if File.file? f
|
66
|
+
end
|
67
|
+
files_and_folders["#{file}/"] = "folder"
|
68
|
+
else
|
69
|
+
files_and_folders[file] = "file"
|
70
|
+
end
|
71
|
+
next
|
72
|
+
end
|
73
|
+
raise SignalException.new(1, "Cant find file #{file}") unless File.exists? "#{Dir.pwd}/#{file}"
|
74
|
+
end
|
75
|
+
return files_and_folders
|
76
|
+
end
|
77
|
+
|
78
|
+
def check_files_sha1(files, resolver, tag)
|
79
|
+
conflicts = 0
|
80
|
+
files.each do |file|
|
81
|
+
next if file.ends_with? '/'
|
82
|
+
sha1 = resolver.fetch(file, {}).fetch("sha1", nil)
|
83
|
+
conflicts += self.check_file_sha1(file, sha1, tag: tag)
|
84
|
+
end
|
85
|
+
conflicts
|
86
|
+
end
|
87
|
+
|
88
|
+
def mark_conflicts(results)
|
89
|
+
begin
|
90
|
+
updated = results["updated_on_server"]
|
91
|
+
deleted = results["deleted"]
|
92
|
+
resolver = results['resolved_files']
|
93
|
+
overall = 0
|
94
|
+
overall += self.check_files_sha1(updated, resolver, "conflict")
|
95
|
+
overall += self.check_files_sha1(deleted, resolver, "deleted")
|
96
|
+
overall
|
97
|
+
rescue => e
|
98
|
+
0
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def cp_ds(relative: false)
|
103
|
+
prefix = @dataset.get_dataset["bucket_prefix"]
|
104
|
+
batch_size = 10000
|
105
|
+
pbar = ProgressBar.create(:title => "Download Progress",
|
106
|
+
:progress_mark => '=',
|
107
|
+
:format => "%b%i| %c Files downloaded",
|
108
|
+
:starting_at => 0,
|
109
|
+
:total => nil,
|
110
|
+
:autofinish => true)
|
111
|
+
parallel_options = {
|
112
|
+
in_threads: ParallelThreads,
|
113
|
+
in_processes: Cnvrg::CLI::ParallelProcesses,
|
114
|
+
isolation: true,
|
115
|
+
finish: ->(*args) { pbar.progress += 1 }
|
116
|
+
}
|
117
|
+
finished = false
|
118
|
+
while not finished
|
119
|
+
current_batch, marker = @downloader.fetch_files(prefix: prefix, marker: marker, limit: batch_size)
|
120
|
+
if marker.blank?
|
121
|
+
finished = true
|
122
|
+
end
|
123
|
+
Parallel.map(current_batch, parallel_options) do |file|
|
124
|
+
next if file.end_with? "/"
|
125
|
+
cutted_key = relative ? @downloader.cut_prefix(prefix, file) : file
|
126
|
+
dest_path = File.join(@dataset.local_path, cutted_key)
|
127
|
+
@downloader.download(file, dest_path, decrypt: false)
|
128
|
+
file
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# This is for backwards compatibility only and should be removed in future versions:
|
134
|
+
def put_commit(commit_sha1)
|
135
|
+
response = Cnvrg::API.request(
|
136
|
+
"#{@base_resource}/commit/latest",
|
137
|
+
'PUT',
|
138
|
+
{
|
139
|
+
commit_sha1: commit_sha1,
|
140
|
+
ignore: true # tells the new server to ignore this api call since its coming from the new CLI
|
141
|
+
}
|
142
|
+
)
|
143
|
+
if response.present?
|
144
|
+
msg = response['result']
|
145
|
+
else
|
146
|
+
msg = "Can't save changes in the dataset"
|
147
|
+
end
|
148
|
+
|
149
|
+
Cnvrg::Result.new(Cnvrg::CLI.is_response_success(response, false), msg)
|
150
|
+
end
|
151
|
+
|
152
|
+
def create_progressbar(title, total)
|
153
|
+
return ProgressBar.create(
|
154
|
+
:title => title,
|
155
|
+
:progress_mark => '=',
|
156
|
+
:format => "%b>>%i| %p%% %t",
|
157
|
+
:starting_at => 0,
|
158
|
+
:total => total,
|
159
|
+
:autofinish => true
|
160
|
+
)
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
def upload_multiple_files(commit_sha1, tree, threads: ParallelThreads, force: false, new_branch: false, prefix: '', partial_commit: nil, total: nil)
|
165
|
+
begin
|
166
|
+
Cnvrg::Logger.log_info("Sending Upload Files request")
|
167
|
+
refresh_storage_token
|
168
|
+
error = nil
|
169
|
+
upload_resp = nil
|
170
|
+
10.times do
|
171
|
+
upload_resp = Cnvrg::API.request(@base_resource + "upload_files", 'POST_JSON', {commit_sha1: commit_sha1, tree: tree, force: force, override: force, is_branch: new_branch, partial_commit: partial_commit})
|
172
|
+
if Cnvrg::CLI.is_response_success(upload_resp, false)
|
173
|
+
error = nil
|
174
|
+
break
|
175
|
+
end
|
176
|
+
error = upload_resp
|
177
|
+
Cnvrg::Logger.log_method(bind: binding)
|
178
|
+
Cnvrg::Logger.log_info("Got an error message from server, #{upload_resp.try(:fetch, "message")}, trying again")
|
179
|
+
end
|
180
|
+
raise Exception.new("Can't upload data files: #{error["message"]}") if error.present?
|
181
|
+
|
182
|
+
Cnvrg::Logger.log_info("Uploading files")
|
183
|
+
results = upload_resp['result'].with_indifferent_access
|
184
|
+
|
185
|
+
if results['files'].blank?
|
186
|
+
return 0, []
|
187
|
+
end
|
188
|
+
|
189
|
+
if @temp_upload_progressbar.blank?
|
190
|
+
@temp_upload_progressbar = ProgressBar.create(:title => "Upload Progress",
|
191
|
+
:progress_mark => '=',
|
192
|
+
:format => "%b>>%i| %p%% %t",
|
193
|
+
:starting_at => 0,
|
194
|
+
:total => total,
|
195
|
+
:autofinish => true)
|
196
|
+
end
|
197
|
+
|
198
|
+
files = results['files']
|
199
|
+
|
200
|
+
progress_semaphore = Mutex.new
|
201
|
+
upload_error_files = []
|
202
|
+
@temp_upload_progressbar.progress += tree.keys.length - files.length if @temp_upload_progressbar.present?
|
203
|
+
Parallel.map((files.keys), in_threads: threads) do |k|
|
204
|
+
o = tree[k].merge(files[k])
|
205
|
+
success = upload_single_file(nil, o)
|
206
|
+
if not success
|
207
|
+
upload_error_files << {absolute_path: o[:absolute_path]}
|
208
|
+
files.except!(k)
|
209
|
+
tree.except!(k)
|
210
|
+
Cnvrg::Logger.log_error_message("Error while upload single file #{o["path"]}")
|
211
|
+
end
|
212
|
+
progress_semaphore.synchronize { @temp_upload_progressbar.progress += 1 if @temp_upload_progressbar.present? }
|
213
|
+
end
|
214
|
+
|
215
|
+
blob_ids = files.values.map {|f| f['bv_id']}
|
216
|
+
if blob_ids.present?
|
217
|
+
dirs = tree.keys.select {|k| tree[k].nil?} || []
|
218
|
+
Cnvrg::Logger.info("Sending Upload files save")
|
219
|
+
upload_resp = Cnvrg::API.request(@base_resource + "upload_files_save", "POST", {commit: commit_sha1, blob_ids: blob_ids, dirs: dirs})
|
220
|
+
unless Cnvrg::CLI.is_response_success(upload_resp, false)
|
221
|
+
Cnvrg::Logger.log_method(bind: binding)
|
222
|
+
raise Exception.new("Got an error message from server, #{upload_resp.try(:fetch, "message")}")
|
223
|
+
end
|
224
|
+
end
|
225
|
+
Cnvrg::Logger.log_info("Upload Success")
|
226
|
+
return files.try(:keys).try(:length), upload_error_files
|
227
|
+
rescue => e
|
228
|
+
Cnvrg::Logger.log_method(bind: binding)
|
229
|
+
Cnvrg::Logger.log_error(e)
|
230
|
+
raise e
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def delete_multiple_files(commit_sha1, regex_list)
|
235
|
+
begin
|
236
|
+
Cnvrg::Logger.log_info("Sending Delete Files request")
|
237
|
+
resp = Cnvrg::API.request(
|
238
|
+
@base_resource + "delete_files",
|
239
|
+
'POST_JSON',
|
240
|
+
{
|
241
|
+
commit_sha1: commit_sha1,
|
242
|
+
regex_list: regex_list,
|
243
|
+
}
|
244
|
+
)
|
245
|
+
unless Cnvrg::CLI.is_response_success(resp, false)
|
246
|
+
Cnvrg::Logger.log_method(bind: binding)
|
247
|
+
raise Exception.new("Got an error message from server, #{resp.try(:fetch, "message")}")
|
248
|
+
end
|
249
|
+
Cnvrg::Logger.log_info("Delete Files request Successful")
|
250
|
+
return resp["files"], resp["folders"], resp["job_id"]
|
251
|
+
rescue => e
|
252
|
+
Cnvrg::Logger.log_method(bind: binding)
|
253
|
+
Cnvrg::Logger.log_error(e)
|
254
|
+
raise e
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def delete_file_chunk(commit_sha1, regex_list, chunk_size, offset)
|
259
|
+
begin
|
260
|
+
resp = Cnvrg::API.request(
|
261
|
+
@base_resource + "delete_files_by_chunk",
|
262
|
+
'POST_JSON',
|
263
|
+
{
|
264
|
+
commit_sha1: commit_sha1,
|
265
|
+
regex_list: regex_list,
|
266
|
+
chunk_size: chunk_size,
|
267
|
+
offset: offset
|
268
|
+
}
|
269
|
+
)
|
270
|
+
unless Cnvrg::CLI.is_response_success(resp, false)
|
271
|
+
Cnvrg::Logger.log_method(bind: binding)
|
272
|
+
raise Exception.new("Got an error message from server, #{resp.try(:fetch, "message")}")
|
273
|
+
end
|
274
|
+
return resp["total_changes"]
|
275
|
+
rescue => e
|
276
|
+
Cnvrg::Logger.log_method(bind: binding)
|
277
|
+
Cnvrg::Logger.log_error(e)
|
278
|
+
raise e
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def get_delete_progress(commit_sha1, job_id)
|
283
|
+
begin
|
284
|
+
resp = Cnvrg::API.request(
|
285
|
+
@base_resource + "get_delete_progress",
|
286
|
+
'POST_JSON',
|
287
|
+
{
|
288
|
+
commit_sha1: commit_sha1,
|
289
|
+
job_id: job_id
|
290
|
+
}
|
291
|
+
)
|
292
|
+
unless Cnvrg::CLI.is_response_success(resp, false)
|
293
|
+
Cnvrg::Logger.log_method(bind: binding)
|
294
|
+
raise Exception.new("Got an error message from server, #{resp.try(:fetch, "message")}")
|
295
|
+
end
|
296
|
+
return resp["total_deleted"]
|
297
|
+
rescue => e
|
298
|
+
Cnvrg::Logger.log_method(bind: binding)
|
299
|
+
Cnvrg::Logger.log_error(e)
|
300
|
+
raise e
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
def request_upload_files(commit_sha1, tree, override, new_branch, partial_commit)
|
305
|
+
retry_count = 0
|
306
|
+
loop do
|
307
|
+
upload_resp = Cnvrg::API.request(@base_resource + "upload_files", 'POST_JSON', {
|
308
|
+
commit_sha1: commit_sha1,
|
309
|
+
tree: tree,
|
310
|
+
override: override,
|
311
|
+
force: override,
|
312
|
+
is_branch: new_branch,
|
313
|
+
partial_commit: partial_commit
|
314
|
+
})
|
315
|
+
if not (Cnvrg::CLI.is_response_success(upload_resp, false))
|
316
|
+
#Cnvrg::Logger.log_method(bind: binding)
|
317
|
+
retry_count += 1
|
318
|
+
|
319
|
+
puts "Failed request upload files: #{Time.current}"
|
320
|
+
puts upload_resp
|
321
|
+
|
322
|
+
if retry_count > 5
|
323
|
+
raise Exception.new("Got an error message from server, #{upload_resp.try(:fetch, "message")}")
|
324
|
+
end
|
325
|
+
sleep 5
|
326
|
+
next
|
327
|
+
end
|
328
|
+
return upload_resp['result'].with_indifferent_access
|
329
|
+
end
|
330
|
+
|
331
|
+
end
|
332
|
+
|
333
|
+
def upload_multiple_files_optimized(files, commit_sha1, threads: 15, chunk_size: 1000, override: false, new_branch: false, prefix: '', partial_commit: nil)
|
334
|
+
cli = CLI.new
|
335
|
+
cli.log_message("Using #{threads} threads with chunk size of #{chunk_size}.", Thor::Shell::Color::GREEN)
|
336
|
+
|
337
|
+
progressbar = create_progressbar("Upload Progress", files.size)
|
338
|
+
cli = CLI.new
|
339
|
+
|
340
|
+
# Vars to handle the parallelism
|
341
|
+
progress_mutex = Mutex.new
|
342
|
+
file_queue = Queue.new
|
343
|
+
progress_queue = Queue.new
|
344
|
+
worker_threads = []
|
345
|
+
|
346
|
+
# Vars to keep track of uploaded files and directories
|
347
|
+
dirs = []
|
348
|
+
uploaded_files = []
|
349
|
+
|
350
|
+
begin
|
351
|
+
# Init working threads that handle the upload of the files:
|
352
|
+
threads.times do |i|
|
353
|
+
worker_threads[i] = Thread.new do
|
354
|
+
# wait for file_queue.close to break the loop
|
355
|
+
while file = file_queue.deq
|
356
|
+
success = upload_single_file(cli, file)
|
357
|
+
file[:success] = success
|
358
|
+
if not success
|
359
|
+
cli.log_message("Error while uploading file: #{file[:absolute_path]}", Thor::Shell::Color::RED)
|
360
|
+
Cnvrg::Logger.log_error_message("Error while upload single file #{file["path"]}")
|
361
|
+
end
|
362
|
+
progress_queue << file
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
# init the thread that handles the file upload progress and saving them in the server
|
368
|
+
progress_thread = Thread.new do
|
369
|
+
loop do
|
370
|
+
file = progress_queue.deq(non_block: true) rescue nil # to prevent deadlocks
|
371
|
+
unless file.nil?
|
372
|
+
progress_mutex.synchronize {
|
373
|
+
progressbar.progress += 1
|
374
|
+
uploaded_files.append(file) if file[:success]
|
375
|
+
}
|
376
|
+
|
377
|
+
if uploaded_files.size == chunk_size or progressbar.finished?
|
378
|
+
refresh_storage_token
|
379
|
+
# puts "progress: #{progress_queue.length}"
|
380
|
+
# puts "files: #{file_queue.length}"
|
381
|
+
Cnvrg::Logger.info("Sending Upload files save")
|
382
|
+
blob_ids = uploaded_files.map {|f| f['bv_id']}
|
383
|
+
upload_resp = Cnvrg::API.request(@base_resource + "upload_files_save", "POST", {commit: commit_sha1, blob_ids: blob_ids, dirs: dirs})
|
384
|
+
unless Cnvrg::CLI.is_response_success(upload_resp, false)
|
385
|
+
Cnvrg::Logger.log_method(bind: binding)
|
386
|
+
raise Exception.new("Got an error message from server, #{upload_resp.try(:fetch, "message")}")
|
387
|
+
end
|
388
|
+
# cli.log_message("Saved file chunk to server", Thor::Shell::Color::GREEN)
|
389
|
+
uploaded_files = []
|
390
|
+
dirs = []
|
391
|
+
end
|
392
|
+
else
|
393
|
+
sleep(0.1)
|
394
|
+
end
|
395
|
+
|
396
|
+
if progressbar.finished?
|
397
|
+
# puts "finished"
|
398
|
+
file_queue.close()
|
399
|
+
progress_queue.close()
|
400
|
+
Thread.exit
|
401
|
+
end
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
file_chunks = files.each_slice(chunk_size).to_a
|
406
|
+
# Fetch the required files from the server:
|
407
|
+
Parallel.map((file_chunks), in_threads: 10) do |files_chunk|
|
408
|
+
|
409
|
+
tree = @dataset.generate_chunked_idx(files_chunk, prefix: prefix, threads: threads)
|
410
|
+
results = request_upload_files(commit_sha1, tree, override, new_branch, partial_commit)
|
411
|
+
|
412
|
+
# puts "Got #{results['files'].size} files to upload from #{files_chunk.size} files"
|
413
|
+
|
414
|
+
if results['files'].blank?
|
415
|
+
progress_mutex.synchronize { progressbar.progress += tree.keys.length }
|
416
|
+
next
|
417
|
+
end
|
418
|
+
|
419
|
+
# Handle directories:
|
420
|
+
new_dirs = tree.keys.select {|k| tree[k].nil?}
|
421
|
+
dirs += new_dirs
|
422
|
+
|
423
|
+
files_to_upload = results['files']
|
424
|
+
progress_mutex.synchronize {
|
425
|
+
progressbar.progress += tree.keys.length - files_to_upload.length
|
426
|
+
}
|
427
|
+
|
428
|
+
files_to_upload.keys.each do |key|
|
429
|
+
while file_queue.size > 5000
|
430
|
+
sleep(0.1)
|
431
|
+
end
|
432
|
+
file_queue.push tree[key].merge(files_to_upload[key])
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
progress_thread.join()
|
437
|
+
worker_threads.each(&:join)
|
438
|
+
|
439
|
+
rescue => e
|
440
|
+
puts e
|
441
|
+
Cnvrg::Logger.log_method(bind: binding)
|
442
|
+
Cnvrg::Logger.log_error(e)
|
443
|
+
raise e
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
def upload_single_file(cli, file)
|
448
|
+
success = false
|
449
|
+
begin
|
450
|
+
file = file.as_json
|
451
|
+
Cnvrg::Logger.log_info("Uploading #{file["absolute_path"]}")
|
452
|
+
@downloader.safe_upload(file["path"], file["absolute_path"])
|
453
|
+
success = true
|
454
|
+
Cnvrg::Logger.log_info("#{file["absolute_path"]} uploaded.")
|
455
|
+
rescue => e
|
456
|
+
Cnvrg::Logger.log_error_message("Error while upload single file #{file["path"]}")
|
457
|
+
Cnvrg::Logger.log_error(e)
|
458
|
+
end
|
459
|
+
success
|
460
|
+
end
|
461
|
+
|
462
|
+
def upload_file(absolute_path, relative_path, commit_sha1)
|
463
|
+
file_name = File.basename relative_path
|
464
|
+
file_size = File.size(absolute_path).to_f
|
465
|
+
mime_type = MimeMagic.by_path(absolute_path)
|
466
|
+
content_type = !(mime_type.nil? or mime_type.text?) ? mime_type.type : "text/plain"
|
467
|
+
sha1 = OpenSSL::Digest::SHA1.file(absolute_path).hexdigest
|
468
|
+
if (absolute_path.include? "_tags.yml" or absolute_path.include? "_tags.yaml")
|
469
|
+
is_valid = false
|
470
|
+
begin
|
471
|
+
content = open(absolute_path).read()
|
472
|
+
hash = YAML.load(open(absolute_path).read())
|
473
|
+
# if level 1 keys count is 1
|
474
|
+
if hash.keys.count == 1
|
475
|
+
if hash["tags"].present?
|
476
|
+
is_valid = true
|
477
|
+
elsif hash[hash.keys.first].class != Hash
|
478
|
+
is_valid = true
|
479
|
+
end
|
480
|
+
# if level 1 keys count is greater than 1
|
481
|
+
elsif hash.keys.count > 1
|
482
|
+
if hash["tags"].present? and hash["tags"].class == Hash
|
483
|
+
is_valid = false
|
484
|
+
else
|
485
|
+
is_valid = true
|
486
|
+
end
|
487
|
+
end
|
488
|
+
rescue
|
489
|
+
is_valid = false
|
490
|
+
end
|
491
|
+
|
492
|
+
if is_valid
|
493
|
+
upload_resp = Cnvrg::API.request(@base_resource + "upload_file", 'POST_FILE', {absolute_path: absolute_path, relative_path: relative_path,
|
494
|
+
commit_sha1: commit_sha1, file_name: file_name,
|
495
|
+
file_size: file_size, file_content_type: content_type, sha1: sha1, content: content})
|
496
|
+
else
|
497
|
+
puts("#{absolute_path} is invalid")
|
498
|
+
puts("Please check yaml structure.")
|
499
|
+
end
|
500
|
+
else
|
501
|
+
upload_resp = Cnvrg::API.request(@base_resource + "upload_file", 'POST_FILE', {absolute_path: absolute_path, relative_path: relative_path,
|
502
|
+
commit_sha1: commit_sha1, file_name: file_name,
|
503
|
+
file_size: file_size, file_content_type: content_type, sha1: sha1})
|
504
|
+
puts upload_resp
|
505
|
+
|
506
|
+
end
|
507
|
+
|
508
|
+
if Cnvrg::CLI.is_response_success(upload_resp, false)
|
509
|
+
s3_res = upload_large_files_s3(upload_resp, absolute_path)
|
510
|
+
|
511
|
+
return s3_res
|
512
|
+
end
|
513
|
+
end
|
514
|
+
def upload_tar_file(absolute_path, relative_path, commit_sha1)
|
515
|
+
begin
|
516
|
+
file_name = File.basename relative_path
|
517
|
+
file_size = File.size(absolute_path).to_f
|
518
|
+
mime_type = MimeMagic.by_path(absolute_path)
|
519
|
+
content_type = !(mime_type.nil? or mime_type.text?) ? mime_type.type : "text/plain"
|
520
|
+
begin
|
521
|
+
chunked_bytes = [100, (file_size*0.01)].min
|
522
|
+
total_yanked = ""
|
523
|
+
open(absolute_path, "rb") do |f|
|
524
|
+
total_yanked = f.read(chunked_bytes)
|
525
|
+
end
|
526
|
+
if !total_yanked.empty?
|
527
|
+
sha1 = OpenSSL::Digest::SHA1.hexdigest(total_yanked)
|
528
|
+
else
|
529
|
+
sha1 = OpenSSL::Digest::SHA1.file(absolute_path).hexdigest
|
530
|
+
end
|
531
|
+
rescue
|
532
|
+
sha1 = OpenSSL::Digest::SHA1.file(absolute_path).hexdigest
|
533
|
+
end
|
534
|
+
|
535
|
+
upload_resp = Cnvrg::API.request(@base_resource + "upload_tar_file", 'POST_FILE', {absolute_path: absolute_path, relative_path: relative_path,
|
536
|
+
commit_sha1: commit_sha1, file_name: file_name,
|
537
|
+
file_size: file_size, file_content_type: content_type, sha1: sha1,
|
538
|
+
new_version:true})
|
539
|
+
if Cnvrg::CLI.is_response_success(upload_resp, false)
|
540
|
+
path = upload_resp["result"]["path"]
|
541
|
+
s3_res = upload_large_files_s3(upload_resp, absolute_path)
|
542
|
+
if s3_res
|
543
|
+
# Cnvrg::API.request(@base_resource + "update_s3", 'POST', {path: path, commit_id: upload_resp["result"]["commit_id"],
|
544
|
+
# blob_id: upload_resp["result"]["id"]})
|
545
|
+
return true
|
546
|
+
end
|
547
|
+
else
|
548
|
+
return false
|
549
|
+
end
|
550
|
+
rescue => e
|
551
|
+
puts e.message
|
552
|
+
return false
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
|
557
|
+
def upload_log_file(absolute_path, relative_path, log_date)
|
558
|
+
file_name = File.basename relative_path
|
559
|
+
file_size = File.size(absolute_path).to_f
|
560
|
+
content_type = "text/x-log"
|
561
|
+
upload_resp = Cnvrg::API.request("/users/#{@owner}/" + "upload_cli_log", 'POST_FILE', {absolute_path: absolute_path, relative_path: relative_path,
|
562
|
+
file_name: file_name, log_date: log_date,
|
563
|
+
file_size: file_size, file_content_type: content_type})
|
564
|
+
if Cnvrg::CLI.is_response_success(upload_resp, false)
|
565
|
+
path = upload_resp["result"]["path"]
|
566
|
+
s3_res = upload_small_files_s3(path, absolute_path, "text/plain")
|
567
|
+
end
|
568
|
+
if s3_res
|
569
|
+
return true
|
570
|
+
end
|
571
|
+
return false
|
572
|
+
|
573
|
+
end
|
574
|
+
def upload_data_log_file(absolute_path, relative_path,data_commit_sha)
|
575
|
+
file_name = File.basename relative_path
|
576
|
+
file_size = File.size(absolute_path).to_f
|
577
|
+
content_type = "text/x-log"
|
578
|
+
upload_resp = Cnvrg::API.request("/users/#{@owner}/" + "upload_data_log", 'POST_FILE', {absolute_path: absolute_path, relative_path: relative_path,
|
579
|
+
file_name: file_name, log_date: Time.now,
|
580
|
+
file_size: file_size, file_content_type: content_type,
|
581
|
+
data_commit_sha1:data_commit_sha})
|
582
|
+
if Cnvrg::CLI.is_response_success(upload_resp, false)
|
583
|
+
path = upload_resp["result"]["path"]
|
584
|
+
s3_res = upload_small_files_s3(path, absolute_path, "text/plain")
|
585
|
+
end
|
586
|
+
if s3_res
|
587
|
+
return true
|
588
|
+
end
|
589
|
+
return false
|
590
|
+
|
591
|
+
end
|
592
|
+
|
593
|
+
|
594
|
+
def upload_exec_file(absolute_path, image_name, commit_id)
|
595
|
+
file_name = File.basename absolute_path
|
596
|
+
file_size = File.size(absolute_path).to_f
|
597
|
+
content_type = "application/zip"
|
598
|
+
begin
|
599
|
+
upload_resp = Cnvrg::API.request("users/#{@owner}/images/" + "upload_config", 'POST_FILE', {relative_path: absolute_path,
|
600
|
+
file_name: file_name,
|
601
|
+
image_name: image_name,
|
602
|
+
file_size: file_size,
|
603
|
+
file_content_type: content_type,
|
604
|
+
project_slug: @project_slug,
|
605
|
+
commit_id: commit_id})
|
606
|
+
# puts upload_resp
|
607
|
+
if Cnvrg::CLI.is_response_success(upload_resp, false)
|
608
|
+
if upload_resp["result"]["image"] == -1
|
609
|
+
return -1
|
610
|
+
end
|
611
|
+
path = upload_resp["result"]["path"]
|
612
|
+
s3_res = upload_small_files_s3(path, absolute_path, content_type)
|
613
|
+
|
614
|
+
end
|
615
|
+
if s3_res
|
616
|
+
return upload_resp["result"]["id"]
|
617
|
+
end
|
618
|
+
return false
|
619
|
+
rescue SignalException
|
620
|
+
|
621
|
+
say "\nAborting"
|
622
|
+
exit(1)
|
623
|
+
end
|
624
|
+
|
625
|
+
end
|
626
|
+
|
627
|
+
|
628
|
+
def upload_image(absolute_path, image_name, owner, is_public, is_base, dpkg, libraries, bash, message, commit_id)
|
629
|
+
file_name = File.basename absolute_path
|
630
|
+
file_size = File.size(absolute_path).to_f
|
631
|
+
if is_base
|
632
|
+
|
633
|
+
content_type = "application/zip"
|
634
|
+
else
|
635
|
+
content_type = "application/gzip"
|
636
|
+
end
|
637
|
+
begin
|
638
|
+
upload_resp = Cnvrg::API.request("users/#{owner}/images/" + "upload_cnvrg", 'POST_FILE', {relative_path: absolute_path,
|
639
|
+
file_name: file_name,
|
640
|
+
image_name: image_name,
|
641
|
+
file_size: file_size,
|
642
|
+
file_content_type: content_type,
|
643
|
+
is_public: is_public,
|
644
|
+
project_slug: @project_slug,
|
645
|
+
commit_id: commit_id,
|
646
|
+
dpkg: dpkg,
|
647
|
+
py2: libraries,
|
648
|
+
py3: libraries,
|
649
|
+
bash_history: bash,
|
650
|
+
commit_message: message,
|
651
|
+
is_base: is_base})
|
652
|
+
# puts upload_resp
|
653
|
+
if Cnvrg::CLI.is_response_success(upload_resp, false)
|
654
|
+
path = upload_resp["result"]["path"]
|
655
|
+
s3_res = upload_small_files_s3(path, absolute_path, content_type)
|
656
|
+
if s3_res
|
657
|
+
commit_resp = Cnvrg::API.request("users/#{owner}/images/#{upload_resp["result"]["id"]}/" + "commit", 'GET')
|
658
|
+
if Cnvrg::CLI.is_response_success(commit_resp, false)
|
659
|
+
return commit_resp["result"]["image"]
|
660
|
+
else
|
661
|
+
return false
|
662
|
+
end
|
663
|
+
|
664
|
+
end
|
665
|
+
end
|
666
|
+
return false
|
667
|
+
rescue => e
|
668
|
+
end
|
669
|
+
|
670
|
+
end
|
671
|
+
|
672
|
+
def upload_cnvrg_image(absolute_path, image_name,secret)
|
673
|
+
file_name = File.basename relative_path
|
674
|
+
file_size = File.size(absolute_path).to_f
|
675
|
+
mime_type = MimeMagic.by_path(absolute_path)
|
676
|
+
content_type = !(mime_type.nil? or mime_type.text?) ? mime_type.type : "text/plain"
|
677
|
+
upload_resp = Cnvrg::API.request("images/#{image_name}/upload_file", 'POST_FILE', {absolute_path: absolute_path, relative_path: absolute_path,
|
678
|
+
file_name: file_name,
|
679
|
+
file_size: file_size, file_content_type: content_type,
|
680
|
+
secret: secret})
|
681
|
+
if Cnvrg::CLI.is_response_success(upload_resp, false)
|
682
|
+
path = upload_resp["result"]["path"]
|
683
|
+
s3_res = upload_large_files_s3(upload_resp, absolute_path)
|
684
|
+
if s3_res
|
685
|
+
Cnvrg::API.request(@base_resource + "update_s3", 'POST', {path: path, commit_id: upload_resp["result"]["commit_id"],
|
686
|
+
blob_id: upload_resp["result"]["id"]})
|
687
|
+
return true
|
688
|
+
end
|
689
|
+
end
|
690
|
+
return false
|
691
|
+
|
692
|
+
end
|
693
|
+
|
694
|
+
def download_image(file_path_to_store, image_slug, owner)
|
695
|
+
|
696
|
+
|
697
|
+
download_resp = Cnvrg::API.request("users/#{owner}/images/#{image_slug}/" + "download", 'GET')
|
698
|
+
path = download_resp["result"]["path"]
|
699
|
+
|
700
|
+
if Cnvrg::CLI.is_response_success(download_resp, false)
|
701
|
+
begin
|
702
|
+
open(file_path_to_store, 'w+') do |file|
|
703
|
+
file << open(path).read
|
704
|
+
end
|
705
|
+
|
706
|
+
return true
|
707
|
+
rescue => e
|
708
|
+
return false
|
709
|
+
end
|
710
|
+
|
711
|
+
return true
|
712
|
+
else
|
713
|
+
return false
|
714
|
+
end
|
715
|
+
|
716
|
+
|
717
|
+
end
|
718
|
+
|
719
|
+
def upload_large_files_s3(upload_resp, file_path)
|
720
|
+
begin
|
721
|
+
sts_path = upload_resp["result"]["path_sts"]
|
722
|
+
|
723
|
+
retries = 0
|
724
|
+
success= false
|
725
|
+
while !success and retries < 20
|
726
|
+
begin
|
727
|
+
if !Helpers.is_verify_ssl
|
728
|
+
body = open(sts_path, {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE}).read
|
729
|
+
else
|
730
|
+
body = open(sts_path).read
|
731
|
+
end
|
732
|
+
success = true
|
733
|
+
rescue => e
|
734
|
+
retries +=1
|
735
|
+
sleep(5)
|
736
|
+
|
737
|
+
end
|
738
|
+
end
|
739
|
+
if !success
|
740
|
+
return false
|
741
|
+
end
|
742
|
+
split = body.split("\n")
|
743
|
+
key = split[0]
|
744
|
+
iv = split[1]
|
745
|
+
is_s3 = upload_resp["result"]["is_s3"]
|
746
|
+
access = Cnvrg::Helpers.decrypt(key, iv, upload_resp["result"]["sts_a"])
|
747
|
+
|
748
|
+
secret = Cnvrg::Helpers.decrypt(key,iv, upload_resp["result"]["sts_s"])
|
749
|
+
|
750
|
+
session = Cnvrg::Helpers.decrypt(key,iv, upload_resp["result"]["sts_st"])
|
751
|
+
region = Cnvrg::Helpers.decrypt(key,iv, upload_resp["result"]["region"])
|
752
|
+
|
753
|
+
bucket = Cnvrg::Helpers.decrypt(key,iv, upload_resp["result"]["bucket"])
|
754
|
+
server_side_encryption =upload_resp["result"]["server_side_encryption"]
|
755
|
+
use_accelerate_endpoint = false
|
756
|
+
if is_s3 or is_s3.nil?
|
757
|
+
|
758
|
+
use_accelerate_endpoint =true
|
759
|
+
client = Aws::S3::Client.new(
|
760
|
+
:access_key_id =>access,
|
761
|
+
:secret_access_key => secret,
|
762
|
+
:session_token => session,
|
763
|
+
:region => region,
|
764
|
+
:http_open_timeout => 60, :retry_limit => 20)
|
765
|
+
else
|
766
|
+
endpoint = Cnvrg::Helpers.decrypt(key,iv, upload_resp["result"]["endpoint"])
|
767
|
+
use_accelerate_endpoint = false
|
768
|
+
client = Aws::S3::Client.new(
|
769
|
+
:access_key_id =>access,
|
770
|
+
:secret_access_key => secret,
|
771
|
+
:region => region,
|
772
|
+
:endpoint=> endpoint,:force_path_style=> true,:ssl_verify_peer=>false,
|
773
|
+
:http_open_timeout => 60, :retry_limit => 20)
|
774
|
+
end
|
775
|
+
|
776
|
+
|
777
|
+
if !server_side_encryption
|
778
|
+
options = {:use_accelerate_endpoint => use_accelerate_endpoint}
|
779
|
+
else
|
780
|
+
options = {:use_accelerate_endpoint => use_accelerate_endpoint, :server_side_encryption => server_side_encryption}
|
781
|
+
end
|
782
|
+
|
783
|
+
|
784
|
+
|
785
|
+
|
786
|
+
s3 = Aws::S3::Resource.new(client: client)
|
787
|
+
|
788
|
+
resp = s3.bucket(bucket).
|
789
|
+
object(upload_resp["result"]["path"]+"/"+File.basename(file_path)).
|
790
|
+
upload_file(file_path,options)
|
791
|
+
|
792
|
+
|
793
|
+
return resp
|
794
|
+
|
795
|
+
rescue => e
|
796
|
+
puts e.message
|
797
|
+
return false
|
798
|
+
|
799
|
+
end
|
800
|
+
return true
|
801
|
+
|
802
|
+
end
|
803
|
+
|
804
|
+
|
805
|
+
def upload_small_files_s3(url_path, file_path, content_type)
|
806
|
+
url = URI.parse(url_path)
|
807
|
+
file = File.open(file_path, "rb")
|
808
|
+
body = file.read
|
809
|
+
begin
|
810
|
+
Net::HTTP.start(url.host) do |http|
|
811
|
+
http.send_request("PUT", url.request_uri, body, {
|
812
|
+
"content-type" => content_type,
|
813
|
+
})
|
814
|
+
end
|
815
|
+
return true
|
816
|
+
rescue Interrupt
|
817
|
+
return false
|
818
|
+
rescue
|
819
|
+
return false
|
820
|
+
end
|
821
|
+
end
|
822
|
+
|
823
|
+
def upload_url(file_path)
|
824
|
+
response = Cnvrg::API.request(@base_resource + "upload_url", 'POST', {file_s3_path: file_path})
|
825
|
+
if Cnvrg::CLI.is_response_success(response, false)
|
826
|
+
return response
|
827
|
+
else
|
828
|
+
return nil
|
829
|
+
end
|
830
|
+
|
831
|
+
end
|
832
|
+
|
833
|
+
def delete_file(absolute_path, relative_path, commit_sha1)
|
834
|
+
response = Cnvrg::API.request(@base_resource + "delete_file", 'DELETE', {absolute_path: absolute_path, relative_path: relative_path, commit_sha1: commit_sha1})
|
835
|
+
return Cnvrg::CLI.is_response_success(response, false)
|
836
|
+
end
|
837
|
+
|
838
|
+
def delete_dir(absolute_path, relative_path, commit_sha1)
|
839
|
+
response = Cnvrg::API.request(@base_resource + "delete_dir", 'DELETE', {absolute_path: absolute_path, relative_path: relative_path, commit_sha1: commit_sha1})
|
840
|
+
return Cnvrg::CLI.is_response_success(response, false)
|
841
|
+
end
|
842
|
+
|
843
|
+
def create_dir(absolute_path, relative_path, commit_sha1)
|
844
|
+
response = Cnvrg::API.request(@base_resource + "create_dir", 'POST', {absolute_path: absolute_path, relative_path: relative_path, commit_sha1: commit_sha1})
|
845
|
+
return Cnvrg::CLI.is_response_success(response, false)
|
846
|
+
end
|
847
|
+
def download_list_files_in_query(response, dataset_home)
|
848
|
+
sts_path = response["path_sts"]
|
849
|
+
if !Helpers.is_verify_ssl
|
850
|
+
body = open(sts_path, {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE}).read
|
851
|
+
else
|
852
|
+
body = open(sts_path).read
|
853
|
+
end
|
854
|
+
split = body.split("\n")
|
855
|
+
key = split[0]
|
856
|
+
iv = split[1]
|
857
|
+
|
858
|
+
access = Cnvrg::Helpers.decrypt(key, iv, response["sts_a"])
|
859
|
+
|
860
|
+
secret = Cnvrg::Helpers.decrypt(key,iv, response["sts_s"])
|
861
|
+
|
862
|
+
session = Cnvrg::Helpers.decrypt(key,iv, response["sts_st"])
|
863
|
+
region = Cnvrg::Helpers.decrypt(key,iv, response["region"])
|
864
|
+
|
865
|
+
bucket = Cnvrg::Helpers.decrypt(key,iv, response["bucket"])
|
866
|
+
is_s3 = response["is_s3"]
|
867
|
+
if is_s3 or is_s3.nil?
|
868
|
+
client = Aws::S3::Client.new(
|
869
|
+
:access_key_id =>access,
|
870
|
+
:secret_access_key => secret,
|
871
|
+
:session_token => session,
|
872
|
+
:region => region,
|
873
|
+
:http_open_timeout => 60, :retry_limit => 20)
|
874
|
+
else
|
875
|
+
endpoint = Cnvrg::Helpers.decrypt(key,iv, response["endpoint_url"])
|
876
|
+
client = Aws::S3::Client.new(
|
877
|
+
:access_key_id =>access,
|
878
|
+
:secret_access_key => secret,
|
879
|
+
:region => region,
|
880
|
+
:endpoint=> endpoint,:force_path_style=> true,:ssl_verify_peer=>false,
|
881
|
+
:http_open_timeout => 60, :retry_limit => 20)
|
882
|
+
end
|
883
|
+
list_files = response["files"]
|
884
|
+
parallel_options = {
|
885
|
+
:progress => {
|
886
|
+
:title => "Download Progress",
|
887
|
+
:progress_mark => '=',
|
888
|
+
:format => "%b>>%i| %p%% %t",
|
889
|
+
:starting_at => 0,
|
890
|
+
:total => list_files.size,
|
891
|
+
:autofinish => true
|
892
|
+
},
|
893
|
+
in_threads: ParallelThreads
|
894
|
+
}
|
895
|
+
download_count = 0
|
896
|
+
Parallel.map((list_files), parallel_options) do |f|
|
897
|
+
file_key = Cnvrg::Helpers.decrypt(key,iv, f["path"])
|
898
|
+
begin
|
899
|
+
begin
|
900
|
+
dir = File.dirname f["fullpath"]
|
901
|
+
FileUtils.mkdir_p(dataset_home+"/"+ dir) unless File.exist? (dataset_home+"/"+ dir)
|
902
|
+
end
|
903
|
+
|
904
|
+
File.open(dataset_home+"/"+f["fullpath"], 'w+') do |file|
|
905
|
+
resp = client.get_object({bucket:bucket,
|
906
|
+
key:file_key}, target: file)
|
907
|
+
end
|
908
|
+
download_count += 1
|
909
|
+
rescue
|
910
|
+
end
|
911
|
+
|
912
|
+
end
|
913
|
+
if download_count == list_files.size
|
914
|
+
return true
|
915
|
+
else
|
916
|
+
return false
|
917
|
+
end
|
918
|
+
|
919
|
+
|
920
|
+
|
921
|
+
|
922
|
+
end
|
923
|
+
|
924
|
+
|
925
|
+
def download_file_s3(absolute_path, relative_path, project_home, conflict=false, commit_sha1=nil, as_link=false)
|
926
|
+
begin
|
927
|
+
res = Cnvrg::API.request(@base_resource + "download_file", 'POST', {absolute_path: absolute_path, relative_path: relative_path, commit_sha1: commit_sha1 ,new_version:true, as_link:as_link})
|
928
|
+
Cnvrg::CLI.is_response_success(res, false)
|
929
|
+
if res["result"]
|
930
|
+
file_url = res["result"]["file_url"]
|
931
|
+
|
932
|
+
if as_link
|
933
|
+
return res["result"]
|
934
|
+
end
|
935
|
+
# begin
|
936
|
+
# if !Helpers.is_verify_ssl
|
937
|
+
# tempfile = Down.download(file_url,open_timeout: 60,ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE )
|
938
|
+
#
|
939
|
+
# else
|
940
|
+
# tempfile = Down.download(file_url,open_timeout: 60)
|
941
|
+
#
|
942
|
+
# end
|
943
|
+
#
|
944
|
+
# FileUtils.move(tempfile.path, project_home+"/"+ absolute_path)
|
945
|
+
# return true
|
946
|
+
# rescue
|
947
|
+
#
|
948
|
+
# end
|
949
|
+
download_resp = res
|
950
|
+
filename = download_resp["result"]["filename"]
|
951
|
+
|
952
|
+
absolute_path += ".conflict" if conflict
|
953
|
+
sts_path = download_resp["result"]["path_sts"]
|
954
|
+
retries = 0
|
955
|
+
success= false
|
956
|
+
while !success and retries < 20
|
957
|
+
begin
|
958
|
+
if !Helpers.is_verify_ssl
|
959
|
+
body = open(sts_path, {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE}).read
|
960
|
+
else
|
961
|
+
body = open(sts_path).read
|
962
|
+
end
|
963
|
+
success = true
|
964
|
+
rescue => e
|
965
|
+
retries +=1
|
966
|
+
sleep(5)
|
967
|
+
|
968
|
+
end
|
969
|
+
end
|
970
|
+
if !success
|
971
|
+
return false
|
972
|
+
end
|
973
|
+
split = body.split("\n")
|
974
|
+
key = split[0]
|
975
|
+
iv = split[1]
|
976
|
+
|
977
|
+
access = Cnvrg::Helpers.decrypt(key, iv, download_resp["result"]["sts_a"])
|
978
|
+
|
979
|
+
secret = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["sts_s"])
|
980
|
+
|
981
|
+
session = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["sts_st"])
|
982
|
+
region = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["region"])
|
983
|
+
|
984
|
+
bucket = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["bucket"])
|
985
|
+
file_key = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["key"])
|
986
|
+
|
987
|
+
is_s3 = download_resp["result"]["is_s3"]
|
988
|
+
if is_s3 or is_s3.nil?
|
989
|
+
client = Aws::S3::Client.new(
|
990
|
+
:access_key_id =>access,
|
991
|
+
:secret_access_key => secret,
|
992
|
+
:session_token => session,
|
993
|
+
:region => region,
|
994
|
+
:http_open_timeout => 60, :retry_limit => 20)
|
995
|
+
else
|
996
|
+
endpoint = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["endpoint_url"])
|
997
|
+
client = Aws::S3::Client.new(
|
998
|
+
:access_key_id =>access,
|
999
|
+
:secret_access_key => secret,
|
1000
|
+
:region => region,
|
1001
|
+
:endpoint=> endpoint,:force_path_style=> true,:ssl_verify_peer=>false,
|
1002
|
+
:http_open_timeout => 60, :retry_limit => 20)
|
1003
|
+
end
|
1004
|
+
|
1005
|
+
File.open(project_home+"/"+absolute_path, 'w+') do |file|
|
1006
|
+
resp = client.get_object({bucket:bucket,
|
1007
|
+
key:file_key}, target: file)
|
1008
|
+
end
|
1009
|
+
return true
|
1010
|
+
end
|
1011
|
+
|
1012
|
+
rescue => e
|
1013
|
+
return false
|
1014
|
+
|
1015
|
+
end
|
1016
|
+
end
|
1017
|
+
|
1018
|
+
def download_data_file(commit_sha1, dataset_home)
|
1019
|
+
begin
|
1020
|
+
res = Cnvrg::API.request(@base_resource + "download_data_file", 'POST', {commit_sha1: commit_sha1,new_version:true})
|
1021
|
+
Cnvrg::CLI.is_response_success(res, false)
|
1022
|
+
if res["result"]
|
1023
|
+
download_resp = res
|
1024
|
+
filename = download_resp["result"]["filename"]
|
1025
|
+
|
1026
|
+
sts_path = download_resp["result"]["path_sts"]
|
1027
|
+
if !Helpers.is_verify_ssl
|
1028
|
+
body = open(sts_path, {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE}).read
|
1029
|
+
else
|
1030
|
+
body = open(sts_path).read
|
1031
|
+
end
|
1032
|
+
split = body.split("\n")
|
1033
|
+
key = split[0]
|
1034
|
+
iv = split[1]
|
1035
|
+
|
1036
|
+
|
1037
|
+
access = Cnvrg::Helpers.decrypt(key, iv, download_resp["result"]["sts_a"])
|
1038
|
+
|
1039
|
+
secret = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["sts_s"])
|
1040
|
+
|
1041
|
+
session = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["sts_st"])
|
1042
|
+
region = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["region"])
|
1043
|
+
|
1044
|
+
bucket = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["bucket"])
|
1045
|
+
file_key = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["key"])
|
1046
|
+
|
1047
|
+
is_s3 = download_resp["result"]["is_s3"]
|
1048
|
+
if is_s3 or is_s3.nil?
|
1049
|
+
client = Aws::S3::Client.new(
|
1050
|
+
:access_key_id =>access,
|
1051
|
+
:secret_access_key => secret,
|
1052
|
+
:session_token => session,
|
1053
|
+
:region => region,
|
1054
|
+
:http_open_timeout => 60, :retry_limit => 20)
|
1055
|
+
else
|
1056
|
+
endpoint = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["endpoint_url"])
|
1057
|
+
client = Aws::S3::Client.new(
|
1058
|
+
:access_key_id =>access,
|
1059
|
+
:secret_access_key => secret,
|
1060
|
+
:region => region,
|
1061
|
+
:endpoint=> endpoint,:force_path_style=> true,:ssl_verify_peer=>false,
|
1062
|
+
:http_open_timeout => 60, :retry_limit => 20)
|
1063
|
+
end
|
1064
|
+
|
1065
|
+
|
1066
|
+
File.open(dataset_home+"/"+filename, 'w+') do |file|
|
1067
|
+
resp = client.get_object({bucket: bucket,
|
1068
|
+
key: file_key }, target: file)
|
1069
|
+
end
|
1070
|
+
return filename
|
1071
|
+
end
|
1072
|
+
|
1073
|
+
rescue => e
|
1074
|
+
return false
|
1075
|
+
|
1076
|
+
end
|
1077
|
+
end
|
1078
|
+
|
1079
|
+
def download_file(absolute_path, relative_path, project_home, conflict=false)
|
1080
|
+
res = Cnvrg::API.request(@base_resource + "download_file", 'POST', {absolute_path: absolute_path, relative_path: relative_path})
|
1081
|
+
Cnvrg::CLI.is_response_success(res, false)
|
1082
|
+
if res["result"]
|
1083
|
+
res = res["result"]
|
1084
|
+
return false if res["link"].empty? or res["filename"].empty?
|
1085
|
+
filename = res["filename"]
|
1086
|
+
file_location = absolute_path.gsub(/#{filename}\/?$/, "")
|
1087
|
+
|
1088
|
+
FileUtils.mkdir_p project_home + "/" + file_location
|
1089
|
+
filename += ".conflict" if conflict
|
1090
|
+
|
1091
|
+
File.open("#{project_home}/#{file_location}/#{filename}", "w+") do |file|
|
1092
|
+
file.write open(res["link"]).read
|
1093
|
+
end
|
1094
|
+
else
|
1095
|
+
return false
|
1096
|
+
end
|
1097
|
+
return true
|
1098
|
+
end
|
1099
|
+
|
1100
|
+
def delete_commit_files_local(deleted)
|
1101
|
+
begin
|
1102
|
+
FileUtils.rm_rf(deleted) unless (deleted.nil? or deleted.empty?)
|
1103
|
+
return Cnvrg::Result.new(true, '')
|
1104
|
+
rescue => e
|
1105
|
+
return Cnvrg::Result.new(false, '')
|
1106
|
+
end
|
1107
|
+
end
|
1108
|
+
|
1109
|
+
def download_dir(dataset_home, absolute_path)
|
1110
|
+
FileUtils.mkdir_p("#{dataset_home}/#{absolute_path}")
|
1111
|
+
end
|
1112
|
+
|
1113
|
+
def revoke_download_dir(absolute_path)
|
1114
|
+
puts FileUtils.rmtree("#{absolute_path}")
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
def revoke_download_file(absolute_path, filename, conflict=false)
|
1118
|
+
begin
|
1119
|
+
file_location = absolute_path.gsub(/#{filename}\/?$/, "")
|
1120
|
+
|
1121
|
+
filename += ".conflict" if conflict
|
1122
|
+
FileUtils.remove("#{file_location}/#{filename}")
|
1123
|
+
return true
|
1124
|
+
rescue
|
1125
|
+
return false
|
1126
|
+
end
|
1127
|
+
end
|
1128
|
+
|
1129
|
+
def revoke_download(tar_files, extracted_files)
|
1130
|
+
begin
|
1131
|
+
FileUtils.rm_rf(tar_files) unless (tar_files.nil? or tar_files.empty?)
|
1132
|
+
FileUtils.rm_rf(extracted_files) unless (extracted_files.nil? or extracted_files.empty?)
|
1133
|
+
rescue => e
|
1134
|
+
return false
|
1135
|
+
end
|
1136
|
+
return true
|
1137
|
+
end
|
1138
|
+
|
1139
|
+
def delete_commit(commit_sha1)
|
1140
|
+
response = Cnvrg::API.request("#{base_resource}/commit/#{commit_sha1}", 'DELETE')
|
1141
|
+
Cnvrg::CLI.is_response_success(response, true)
|
1142
|
+
return response
|
1143
|
+
end
|
1144
|
+
|
1145
|
+
def get_commit(commit_sha1)
|
1146
|
+
response = Cnvrg::API.request("#{base_resource}/commit/#{commit_sha1}", 'GET')
|
1147
|
+
Cnvrg::CLI.is_response_success(response, true)
|
1148
|
+
return response
|
1149
|
+
end
|
1150
|
+
|
1151
|
+
def start_commit(new_branch, force=false, chunks: 0, dataset: @dataset, message:nil)
|
1152
|
+
#if we are pushing with force or to branch we dont need to send current/next commit cause we want to
|
1153
|
+
# create a new commit.
|
1154
|
+
idx = {}
|
1155
|
+
commit = idx[:commit]
|
1156
|
+
next_commit = idx[:next_commit]
|
1157
|
+
response = Cnvrg::API.request(
|
1158
|
+
"#{base_resource}/commit/start",
|
1159
|
+
'POST',
|
1160
|
+
{
|
1161
|
+
dataset_slug: @dataset_slug,
|
1162
|
+
new_branch: new_branch,
|
1163
|
+
force:force,
|
1164
|
+
username: @owner,
|
1165
|
+
current_commit: commit,
|
1166
|
+
next_commit: next_commit,
|
1167
|
+
total_chunks: chunks,
|
1168
|
+
message: message
|
1169
|
+
}
|
1170
|
+
)
|
1171
|
+
Cnvrg::CLI.is_response_success(response, true)
|
1172
|
+
response
|
1173
|
+
rescue => e
|
1174
|
+
false
|
1175
|
+
end
|
1176
|
+
|
1177
|
+
def end_commit(commit_sha1, force, success: true, uploaded_files: 0, commit_type: nil)
|
1178
|
+
begin
|
1179
|
+
response = Cnvrg::API.request(
|
1180
|
+
"#{base_resource}/commit/end",
|
1181
|
+
'POST',
|
1182
|
+
{
|
1183
|
+
commit_sha1: commit_sha1,
|
1184
|
+
force:force,
|
1185
|
+
success: success,
|
1186
|
+
uploaded_files: uploaded_files,
|
1187
|
+
commit_type: commit_type
|
1188
|
+
}
|
1189
|
+
)
|
1190
|
+
Cnvrg::CLI.is_response_success(response, true)
|
1191
|
+
return response
|
1192
|
+
rescue => e
|
1193
|
+
return false
|
1194
|
+
end
|
1195
|
+
end
|
1196
|
+
|
1197
|
+
def end_commit_tar(commit_sha1, cur_idx)
|
1198
|
+
response = Cnvrg::API.request("#{base_resource}/commit/end_tar", 'POST', {commit_sha1: commit_sha1, idx: cur_idx})
|
1199
|
+
return response
|
1200
|
+
end
|
1201
|
+
|
1202
|
+
def rollback_commit(commit_sha1)
|
1203
|
+
response = Cnvrg::API.request("#{base_resource}/commit/rollback", 'POST', {commit_sha1: commit_sha1})
|
1204
|
+
Cnvrg::CLI.is_response_success(response, false)
|
1205
|
+
end
|
1206
|
+
|
1207
|
+
def clone_in_chunks(commit: 'latest', chunk_size: 1000)
|
1208
|
+
begin
|
1209
|
+
|
1210
|
+
end
|
1211
|
+
end
|
1212
|
+
|
1213
|
+
def get_trees(commit: "latest")
|
1214
|
+
response = Cnvrg::API.request("#{@base_resource}/clone_trees", 'POST',{commit: commit})
|
1215
|
+
return nil unless Cnvrg::CLI.is_response_success(response, false)
|
1216
|
+
response['result']['files']
|
1217
|
+
end
|
1218
|
+
|
1219
|
+
def get_clone_chunk(latest_id: nil, chunk_size: 1000, commit: 'latest')
|
1220
|
+
response = Cnvrg::API.request("#{@base_resource}/clone_chunk", 'POST',{commit: commit, chunk_size: chunk_size, latest_id: latest_id})
|
1221
|
+
unless Cnvrg::CLI.is_response_success(response, false)
|
1222
|
+
Cnvrg::Logger.log_info("#{{commit: commit, chunk_size: chunk_size, latest_id: latest_id}}")
|
1223
|
+
return nil
|
1224
|
+
end
|
1225
|
+
response['result']['files']
|
1226
|
+
end
|
1227
|
+
|
1228
|
+
def download_files_in_chunks(files, chunk_size: 1000, conflict: false, commit: 'latest', progress: nil)
|
1229
|
+
begin
|
1230
|
+
files.each_slice(chunk_size).each do |files|
|
1231
|
+
download_files_chunk(files, conflict: conflict, progress: progress)
|
1232
|
+
end
|
1233
|
+
return Cnvrg::Result.new(true, "Download Completed")
|
1234
|
+
rescue Exception => e
|
1235
|
+
return Cnvrg::Result.new(false, "Can`t download files")
|
1236
|
+
end
|
1237
|
+
end
|
1238
|
+
|
1239
|
+
def download_files_chunk(files, conflict: false, progress: nil)
|
1240
|
+
(1..5).each do |i|
|
1241
|
+
response = Cnvrg::API.request("users/#{@owner}/datasets/#{@dataset_slug}/download_multi", 'POST', {files: files})
|
1242
|
+
next unless Cnvrg::CLI.is_response_success(response, false) #trying to api request 5 times.
|
1243
|
+
files_to_download = response['files']
|
1244
|
+
data_home = "#{Dir.pwd}/#{response['name']}"
|
1245
|
+
res = download_multiple_files_s3(files_to_download, data_home, conflict: conflict, read_only: false, progressbar: progress)
|
1246
|
+
next unless res.is_success? #try again..
|
1247
|
+
return files_to_download['keys'].length
|
1248
|
+
end
|
1249
|
+
end
|
1250
|
+
|
1251
|
+
def download_multiple_chunks(commit, chunk_size=1000, progress: nil)
|
1252
|
+
begin
|
1253
|
+
last_chunk_size = chunk_size
|
1254
|
+
q = { commit: commit, chunk_size: chunk_size}
|
1255
|
+
overall = 0
|
1256
|
+
while last_chunk_size > 0
|
1257
|
+
response = Cnvrg::API.request("users/#{@owner}/datasets/#{@dataset_slug}/clone", 'POST', q)
|
1258
|
+
if Cnvrg::CLI.is_response_success(response, false)
|
1259
|
+
files = response['files']
|
1260
|
+
data_home = "#{Dir.pwd}/#{response['name']}"
|
1261
|
+
last_chunk_size = files['keys'].length
|
1262
|
+
break if last_chunk_size == 0
|
1263
|
+
res = download_multiple_files_s3(files, data_home, read_only: false, progressbar: progress)
|
1264
|
+
overall += last_chunk_size
|
1265
|
+
q[:latest] = files['latest']
|
1266
|
+
else
|
1267
|
+
last_chunk_size = 0
|
1268
|
+
end
|
1269
|
+
end
|
1270
|
+
Cnvrg::Result.new(true, "Cloned #{overall} files!")
|
1271
|
+
rescue => e
|
1272
|
+
Cnvrg::Result.new(false, "Cant download chunk", e.message, e.backtrace)
|
1273
|
+
|
1274
|
+
end
|
1275
|
+
end
|
1276
|
+
|
1277
|
+
def last_valid_commit()
|
1278
|
+
begin
|
1279
|
+
response = Cnvrg::API.request("#{base_resource}/last_valid_commit", 'GET')
|
1280
|
+
Cnvrg::CLI.is_response_success(response, true)
|
1281
|
+
return response
|
1282
|
+
rescue => e
|
1283
|
+
return false
|
1284
|
+
end
|
1285
|
+
end
|
1286
|
+
|
1287
|
+
def download_multiple_files_s3(files, project_home, conflict: false, progressbar: nil, read_only:false, flatten: false)
|
1288
|
+
begin
|
1289
|
+
refresh_storage_token
|
1290
|
+
parallel_options = {
|
1291
|
+
in_threads: ParallelThreads,
|
1292
|
+
isolation: true
|
1293
|
+
}
|
1294
|
+
Parallel.map(files["keys"], parallel_options) do |f|
|
1295
|
+
begin
|
1296
|
+
file_path = f['name']
|
1297
|
+
file_path = File.basename(f['name']) if flatten
|
1298
|
+
local_path = @dataset.local_path + '/' + file_path
|
1299
|
+
Cnvrg::Logger.log_info("Downloading #{local_path}")
|
1300
|
+
progressbar.progress += 1 if progressbar.present?
|
1301
|
+
if local_path.end_with? "/"
|
1302
|
+
@downloader.mkdir(local_path, recursive: true)
|
1303
|
+
next
|
1304
|
+
end
|
1305
|
+
# blob
|
1306
|
+
local_path = "#{local_path}.conflict" if conflict
|
1307
|
+
storage_path = f["path"]
|
1308
|
+
# if File.exists? local_path
|
1309
|
+
# Cnvrg::Logger.log_info("Trying to download #{local_path} but its already exists, skipping..")
|
1310
|
+
# next
|
1311
|
+
# end
|
1312
|
+
resp = @downloader.download(storage_path, local_path)
|
1313
|
+
Cnvrg::Logger.log_info("Download #{local_path} success resp: #{resp}")
|
1314
|
+
rescue => e
|
1315
|
+
Cnvrg::Logger.log_error(e)
|
1316
|
+
end
|
1317
|
+
end
|
1318
|
+
return Cnvrg::Result.new(true,"Downloaded successfully")
|
1319
|
+
rescue => e
|
1320
|
+
Cnvrg::Logger.log_error(e)
|
1321
|
+
return Cnvrg::Result.new(false,"Could not download some files", e.message, e.backtrace)
|
1322
|
+
end
|
1323
|
+
end
|
1324
|
+
end
|
1325
|
+
end
|