cnvrg 1.9.9.9.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/bin/cnvrg +9 -0
  3. data/cnvrg.gemspec +47 -0
  4. data/lib/cnvrg.rb +7 -0
  5. data/lib/cnvrg/Images.rb +351 -0
  6. data/lib/cnvrg/api.rb +247 -0
  7. data/lib/cnvrg/api_v2.rb +14 -0
  8. data/lib/cnvrg/auth.rb +79 -0
  9. data/lib/cnvrg/cli.rb +5715 -0
  10. data/lib/cnvrg/cli/flow.rb +166 -0
  11. data/lib/cnvrg/cli/library_cli.rb +33 -0
  12. data/lib/cnvrg/cli/subcommand.rb +28 -0
  13. data/lib/cnvrg/cli/task.rb +116 -0
  14. data/lib/cnvrg/colors.rb +8 -0
  15. data/lib/cnvrg/connect_job_ssh.rb +31 -0
  16. data/lib/cnvrg/data.rb +335 -0
  17. data/lib/cnvrg/datafiles.rb +1325 -0
  18. data/lib/cnvrg/dataset.rb +892 -0
  19. data/lib/cnvrg/downloader/client.rb +101 -0
  20. data/lib/cnvrg/downloader/clients/azure_client.rb +45 -0
  21. data/lib/cnvrg/downloader/clients/gcp_client.rb +50 -0
  22. data/lib/cnvrg/downloader/clients/s3_client.rb +78 -0
  23. data/lib/cnvrg/experiment.rb +209 -0
  24. data/lib/cnvrg/files.rb +1047 -0
  25. data/lib/cnvrg/flow.rb +137 -0
  26. data/lib/cnvrg/helpers.rb +422 -0
  27. data/lib/cnvrg/helpers/agent.rb +188 -0
  28. data/lib/cnvrg/helpers/executer.rb +213 -0
  29. data/lib/cnvrg/hyper.rb +21 -0
  30. data/lib/cnvrg/image.rb +113 -0
  31. data/lib/cnvrg/image_cli.rb +25 -0
  32. data/lib/cnvrg/job_cli.rb +73 -0
  33. data/lib/cnvrg/job_ssh.rb +48 -0
  34. data/lib/cnvrg/logger.rb +111 -0
  35. data/lib/cnvrg/org_helpers.rb +5 -0
  36. data/lib/cnvrg/project.rb +822 -0
  37. data/lib/cnvrg/result.rb +29 -0
  38. data/lib/cnvrg/runner.rb +49 -0
  39. data/lib/cnvrg/ssh.rb +94 -0
  40. data/lib/cnvrg/storage.rb +128 -0
  41. data/lib/cnvrg/task.rb +165 -0
  42. data/lib/cnvrg/version.rb +3 -0
  43. metadata +460 -0
@@ -0,0 +1,1047 @@
1
+ require 'mimemagic'
2
+ require 'aws-sdk-s3'
3
+ require 'URLcrypt'
4
+ require 'tempfile'
5
+ require 'net/http'
6
+ require 'cnvrg/result'
7
+ module Cnvrg
8
+ class Files
9
+ ParallelThreads = Cnvrg::Helpers.parallel_threads
10
+ VALID_FILE_NAME = /[\x00\\\*\?\"<>\|]/
11
+ LARGE_FILE=1024*1024*5
12
+ MULTIPART_SPLIT=10000000
13
+
14
+ attr_reader :base_resource
15
+
16
+ def initialize(owner, project_slug, project_home: '', project: nil, progressbar: nil, cli: nil, options: {})
17
+ @project_slug = project_slug
18
+ @owner = owner
19
+ @base_resource = "users/#{owner}/projects/#{project_slug}/"
20
+ @project_home = project_home.presence || Cnvrg::CLI.get_project_home
21
+ @project = project
22
+ @client = nil
23
+ if @project.present?
24
+ @client = @project.get_storage_client
25
+ end
26
+ @progressbar = progressbar
27
+ @custom_progess = false
28
+ @cli = cli
29
+ @options = options
30
+ @token_issue_time = Time.current
31
+ end
32
+
33
+ def refresh_storage_token
34
+ current_time = Time.current
35
+ if current_time - @token_issue_time > 3.hours
36
+ @client = @project.get_storage_client
37
+ @token_issue_time = Time.current
38
+ end
39
+ end
40
+
41
+ def self.valid_file_name?(fullpath)
42
+ VALID_FILE_NAME.match(fullpath).blank?
43
+ end
44
+
45
+
46
+ def download_commit(sha1)
47
+ response = @project.clone(false, sha1)
48
+ log_error("Cant download commit #{sha1}") unless Cnvrg::CLI.is_response_success response, false
49
+ commit_sha1 = response["result"]["commit"]
50
+ files = response["result"]["tree"].keys
51
+ log_progress("Downloading #{files.size} Files")
52
+ idx = {commit: commit_sha1, tree: response["result"]["tree"]}
53
+ @progressbar ||= create_progressbar(files.size, "Download Progress")
54
+ download_files(files, commit_sha1, progress: @progressbar)
55
+ @progressbar.finish if @custom_progess
56
+ Project.verify_cnvrgignore_exist(@project_slug, false)
57
+ @project.set_idx(idx)
58
+ log("Done")
59
+ log("Downloaded #{files.size} files")
60
+ end
61
+
62
+ def get_upload_options(number_of_items: 0, progress: false)
63
+ options = {
64
+ in_processes: Cnvrg::CLI::ParallelProcesses,
65
+ in_thread: Cnvrg::CLI::ParallelThreads,
66
+ isolation: true
67
+ }
68
+ if progress
69
+ options[:progress] = {
70
+ :title => "Upload Progress",
71
+ :progress_mark => '=',
72
+ :format => "%b>>%i| %p%% %t",
73
+ :starting_at => 0,
74
+ :total => number_of_items,
75
+ :autofinish => true
76
+ }
77
+ end
78
+ options
79
+ end
80
+
81
+ def upload_files_old(files_list, commit_sha1, progress: nil)
82
+ # Parallel.map(files_list) do |file|
83
+ files_list.each do |file|
84
+ Cnvrg::Helpers.try_until_success{self.upload_old("#{@project_home}/#{file}", file, commit_sha1)}
85
+ progress.progress += 1
86
+ end
87
+ end
88
+
89
+ def upload_multiple_files(files_list, commit_sha1, progress: nil, suppress_exceptions: false, chunk_size: 100)
90
+ #open files on the server.
91
+ Cnvrg::Logger.log_info("Uploading project files")
92
+ return if files_list.blank?
93
+ if Cnvrg::Helpers.server_version < 1
94
+ Cnvrg::Logger.log_info("Upload files to older server..")
95
+ return self.upload_files_old(files_list, commit_sha1, progress: progress)
96
+ end
97
+
98
+ blob_ids = []
99
+ buffered_errors = {}
100
+ files_list.each_slice(chunk_size).each do |chunk_of_files|
101
+ Cnvrg::Logger.log_info("Upload chunk")
102
+ parsed_chunk_of_files = chunk_of_files.map{|x| [x, self.parse_file(x)] if self.parse_file(x)}.compact.to_h
103
+
104
+ resp = Cnvrg::API.request(@base_resource + "upload_files", 'POST', {
105
+ files: parsed_chunk_of_files,
106
+ commit: commit_sha1
107
+ })
108
+ unless Cnvrg::CLI.is_response_success(resp, false)
109
+ raise SignalException.new("Cant upload files to the server.")
110
+ end
111
+ # resolve bucket
112
+ res = resp['result']
113
+ files = res['files']
114
+
115
+ #upload files
116
+ blob_id_chunk = Parallel.map(files.keys, in_threads: ParallelThreads) do |file|
117
+ begin
118
+ Cnvrg::Helpers.try_until_success{self.upload_single_file(files[file].merge(parsed_chunk_of_files[file]))}
119
+ rescue => e
120
+ Cnvrg::CLI.log_message("Failed to upload #{file}: #{e.message}", 'red') unless suppress_exceptions
121
+ Cnvrg::Logger.log_error(e)
122
+ Cnvrg::Logger.log_method(bind: binding)
123
+
124
+ buffered_errors[file] = "Failed to upload #{file}: #{e.message}" if suppress_exceptions
125
+
126
+ raise e unless suppress_exceptions
127
+ end
128
+ progress.progress += 1 if progress.present?
129
+
130
+ unless buffered_errors.key?(file)
131
+ files[file]["bv_id"]
132
+ else
133
+ nil
134
+ end
135
+ end
136
+
137
+
138
+ blob_ids.concat blob_id_chunk
139
+ end
140
+
141
+ # remove nil files (failed files) from blob_ids
142
+ blob_ids.compact!
143
+
144
+ #save files on the server.
145
+ resp = Cnvrg::API.request(@base_resource + "upload_files_save", 'POST', {blob_ids: blob_ids, commit: commit_sha1})
146
+ unless Cnvrg::CLI.is_response_success(resp, false)
147
+ raise SignalException.new("Cant save uploaded files to the server.")
148
+ end
149
+
150
+ return buffered_errors
151
+ end
152
+
153
+
154
+
155
+ def delete_files_from_server_old(files, commit_sha1)
156
+ #files are absolute path here.
157
+ files.each do |file|
158
+ if file.ends_with? '/'
159
+ #dir
160
+ self.delete_dir(file, commit_sha1)
161
+ else
162
+ #file
163
+ self.delete_file(file, commit_sha1)
164
+ end
165
+ end
166
+ end
167
+
168
+ def delete_files_from_server(files, commit_sha1, suppress_exceptions: false)
169
+ #files are absolute path files here. ^^
170
+ if Cnvrg::Helpers.server_version < 1
171
+ return self.delete_files_from_server_old(files, commit_sha1)
172
+ end
173
+ #convert files to relative path
174
+ files = files.map{|file| file.gsub(/^#{@project_home + "/"}/, "")}
175
+ return if files.blank?
176
+ resp = Cnvrg::API.request(@base_resource + "delete_files", 'DELETE', {files: files, commit: commit_sha1})
177
+ unless Cnvrg::CLI.is_response_success(resp, false)
178
+ raise SignalException.new("Cant delete the following files from the server.") unless suppress_exceptions
179
+ Cnvrg::Logger.log_error_message("Cant delete the following files from the server: ")
180
+ Cnvrg::Logger.log_error_message(files.to_s)
181
+ end
182
+ rescue => e
183
+ Cnvrg::Logger.log_error_message("An exception raised in delete_files_from_server: ")
184
+ Cnvrg::Logger.log_error(e)
185
+ raise e unless suppress_exceptions
186
+ end
187
+
188
+ def upload_single_file(file)
189
+ path = file['path']
190
+ absolute_path = file[:absolute_path]
191
+ @client.upload(path, absolute_path)
192
+ end
193
+
194
+ def parse_file(file)
195
+ abs_path = "#{@project_home}/#{file}"
196
+ return {relative_path: file, absolute_path: abs_path} if file.ends_with? '/'
197
+ file_name = File.basename(file)
198
+ file_size = File.size abs_path
199
+ mime_type = MimeMagic.by_path(abs_path)
200
+ content_type = !(mime_type.nil? or mime_type.text?) ? mime_type.type : "text/plain"
201
+ sha1 = OpenSSL::Digest::SHA1.file(abs_path).hexdigest
202
+
203
+ {relative_path: file, absolute_path: abs_path, file_name: file_name, file_size: file_size, content_type: content_type, sha1: sha1}
204
+ rescue => e
205
+ return false
206
+ end
207
+
208
+ def upload_old(absolute_path, relative_path, commit_sha1)
209
+ if relative_path.ends_with? '/'
210
+ self.create_dir(absolute_path, relative_path, commit_sha1)
211
+ else
212
+ self.upload_file(absolute_path, relative_path, commit_sha1)
213
+ end
214
+ end
215
+
216
+ def upload_file(absolute_path, relative_path, commit_sha1)
217
+ file_name = File.basename relative_path
218
+ file_size = File.size(absolute_path).to_f
219
+ mime_type = MimeMagic.by_path(absolute_path)
220
+ content_type = !(mime_type.nil? or mime_type.text?) ? mime_type.type : "text/plain"
221
+ sha1 = OpenSSL::Digest::SHA1.file(absolute_path).hexdigest
222
+ upload_resp = Cnvrg::API.request(@base_resource + "upload_file", 'POST_FILE', {absolute_path: absolute_path, relative_path: relative_path,
223
+ commit_sha1: commit_sha1, file_name: file_name,
224
+ file_size: file_size, file_content_type: content_type, sha1: sha1,
225
+ new_version:true,only_large:true})
226
+
227
+ if Cnvrg::CLI.is_response_success(upload_resp, false)
228
+ s3_res = upload_large_files_s3(upload_resp, absolute_path)
229
+ return s3_res
230
+ end
231
+ return false
232
+
233
+ end
234
+
235
+ def upload_log_file(absolute_path, relative_path, log_date)
236
+ file_name = File.basename relative_path
237
+ file_size = File.size(absolute_path).to_f
238
+ content_type = "text/x-log"
239
+ upload_resp = Cnvrg::API.request("/users/#{@owner}/" + "upload_cli_log", 'POST_FILE', {absolute_path: absolute_path, relative_path: relative_path,
240
+ file_name: file_name, log_date: log_date,
241
+ file_size: file_size, file_content_type: content_type})
242
+ path, client = upload_resp["path"], upload_resp["client"]
243
+ @client = Cnvrg::Downloader::Client.factory(client)
244
+ @client.upload(path, absolute_path)
245
+ end
246
+
247
+ def upload_exec_file(absolute_path, image_name, commit_id)
248
+ file_name = File.basename absolute_path
249
+ file_size = File.size(absolute_path).to_f
250
+ content_type = "application/zip"
251
+ begin
252
+ upload_resp = Cnvrg::API.request("users/#{@owner}/images/" + "upload_config", 'POST_FILE', {relative_path: absolute_path,
253
+ file_name: file_name,
254
+ image_name: image_name,
255
+ file_size: file_size,
256
+ file_content_type: content_type,
257
+ project_slug: @project_slug,
258
+ commit_id: commit_id})
259
+ # puts upload_resp
260
+ if Cnvrg::CLI.is_response_success(upload_resp, false)
261
+ if upload_resp["result"]["image"] == -1
262
+ return -1
263
+ end
264
+ path = upload_resp["result"]["path"]
265
+ s3_res = upload_small_files_s3(path, absolute_path, content_type)
266
+
267
+ end
268
+ if s3_res
269
+ return upload_resp["result"]["id"]
270
+ end
271
+ return false
272
+ rescue SignalException
273
+
274
+ say "\nAborting"
275
+ exit(1)
276
+ end
277
+
278
+ end
279
+
280
+
281
+ def upload_image(absolute_path, image_name, owner, is_public, is_base, dpkg, libraries, bash, message, commit_id)
282
+ file_name = File.basename absolute_path
283
+ file_size = File.size(absolute_path).to_f
284
+ if is_base
285
+
286
+ content_type = "application/zip"
287
+ else
288
+ content_type = "application/gzip"
289
+ end
290
+ begin
291
+ upload_resp = Cnvrg::API.request("users/#{owner}/images/" + "upload_cnvrg", 'POST_FILE', {relative_path: absolute_path,
292
+ file_name: file_name,
293
+ image_name: image_name,
294
+ file_size: file_size,
295
+ file_content_type: content_type,
296
+ is_public: is_public,
297
+ project_slug: @project_slug,
298
+ commit_id: commit_id,
299
+ dpkg: dpkg,
300
+ py2: libraries,
301
+ py3: libraries,
302
+
303
+ bash_history: bash,
304
+ commit_message: message,
305
+ is_base: is_base})
306
+ # puts upload_resp
307
+ if Cnvrg::CLI.is_response_success(upload_resp, false)
308
+ s3_res = upload_large_files_s3(upload_resp, absolute_path)
309
+ if s3_res
310
+ commit_resp = Cnvrg::API.request("users/#{owner}/images/#{upload_resp["result"]["id"]}/" + "commit", 'GET')
311
+ if Cnvrg::CLI.is_response_success(commit_resp, false)
312
+ return commit_resp["result"]["image"]
313
+ else
314
+ return false
315
+ end
316
+
317
+ end
318
+ end
319
+ return false
320
+ rescue => e
321
+ end
322
+
323
+ end
324
+
325
+ def upload_cnvrg_image(absolute_path, image_name,secret)
326
+ file_name = File.basename absolute_path
327
+ file_size = File.size(absolute_path).to_f
328
+ content_type = MimeMagic.by_path(absolute_path)
329
+ begin
330
+ upload_resp = Cnvrg::API.request("images/#{image_name}/upload", 'POST_FILE', {relative_path: absolute_path,
331
+ file_name: file_name,
332
+ file_size: file_size,
333
+ file_content_type: content_type,
334
+ secret:secret
335
+ })
336
+ # puts upload_resp
337
+ if Cnvrg::CLI.is_response_success(upload_resp, false)
338
+ path = upload_resp["result"]["path"]
339
+ s3_res = upload_large_files_s3(upload_resp, absolute_path)
340
+ if s3_res
341
+ return true
342
+ else
343
+ return false
344
+ end
345
+
346
+ end
347
+ rescue => e
348
+ return false
349
+ end
350
+ return false
351
+
352
+
353
+ end
354
+
355
+ def download_image(file_path_to_store, image_slug, owner)
356
+
357
+
358
+ download_resp = Cnvrg::API.request("users/#{owner}/images/#{image_slug}/" + "download", 'GET')
359
+ path = download_resp["result"]["path"]
360
+
361
+ if Cnvrg::CLI.is_response_success(download_resp, false)
362
+ begin
363
+ open(file_path_to_store, 'wb') do |file|
364
+ file << open(path).read
365
+ end
366
+
367
+ return true
368
+ rescue => e
369
+ return false
370
+ end
371
+
372
+ return true
373
+ else
374
+ return false
375
+ end
376
+
377
+
378
+ end
379
+ def download_cnvrg_image(image_name, secret)
380
+ res =Cnvrg::API.request("images/#{image_name}/" + "download", 'POST', {secret:secret},true)
381
+ Cnvrg::CLI.is_response_success(res, true)
382
+ if res["result"]
383
+ download_resp = res
384
+ sts_path = download_resp["result"]["path_sts"]
385
+ uri = URI.parse(sts_path)
386
+ http_object = Net::HTTP.new(uri.host, uri.port)
387
+ http_object.use_ssl = true if uri.scheme == 'https'
388
+ request = Net::HTTP::Get.new(sts_path)
389
+ body = ""
390
+ http_object.start do |http|
391
+ response = http.request request
392
+ body = response.read_body
393
+ end
394
+ split = body.split("\n")
395
+ key = split[0]
396
+ iv = split[1]
397
+
398
+ access = Cnvrg::Helpers.decrypt(key, iv, download_resp["result"]["sts_a"])
399
+
400
+ secret = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["sts_s"])
401
+
402
+ session = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["sts_st"])
403
+ region = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["region"])
404
+
405
+ bucket = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["bucket"])
406
+ key = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["key"])
407
+
408
+ client = Aws::S3::Client.new(
409
+ :access_key_id =>access,
410
+ :secret_access_key => secret,
411
+ :session_token => session,
412
+ :region => region,
413
+ :http_open_timeout => 60, :retry_limit => 20
414
+ )
415
+
416
+ File.open("/tmp/#{image_name}.tar", 'w+') do |file|
417
+ resp = client.get_object({bucket:bucket,
418
+ key:key}, target: file)
419
+ end
420
+ return true
421
+ end
422
+
423
+ rescue => e
424
+ Cnvrg::Logger.log_error(e)
425
+ return false
426
+ end
427
+
428
+ def resolve_bucket(response)
429
+ begin
430
+ sts_path = response["path_sts"]
431
+ sts_body = self.download_and_read(sts_path)
432
+ split = sts_body.split("\n")
433
+ key = split[0]
434
+ iv = split[1]
435
+ access = Cnvrg::Helpers.decrypt(key, iv, response["sts_a"])
436
+
437
+ secret = Cnvrg::Helpers.decrypt(key, iv, response["sts_s"])
438
+
439
+ session = Cnvrg::Helpers.decrypt(key, iv, response["sts_st"])
440
+ region = Cnvrg::Helpers.decrypt(key, iv, response["region"])
441
+
442
+ bucket = Cnvrg::Helpers.decrypt(key, iv, response["bucket"])
443
+ Cnvrg::Logger.log_info("Resolving bucket #{bucket}, region: #{region}")
444
+ is_s3 = response["is_s3"]
445
+ if is_s3 or is_s3.nil?
446
+ client = Aws::S3::Client.new(
447
+ :access_key_id => access,
448
+ :secret_access_key => secret,
449
+ :session_token => session,
450
+ :region => region,
451
+ :use_accelerate_endpoint => true,
452
+ :http_open_timeout => 60, :retry_limit => 20)
453
+ else
454
+ endpoint = Cnvrg::Helpers.decrypt(key, iv, response["endpoint"])
455
+ client = Aws::S3::Client.new(
456
+ :access_key_id => access,
457
+ :secret_access_key => secret,
458
+ :region => region,
459
+ :endpoint => endpoint, :force_path_style => true, :ssl_verify_peer => false,
460
+ :use_accelerate_endpoint => false,
461
+ :server_side_encryption => 'AES256',
462
+ :http_open_timeout => 60, :retry_limit => 20)
463
+ end
464
+
465
+ s3 = Aws::S3::Resource.new(client: client)
466
+ s3.bucket(bucket)
467
+ rescue => e
468
+ Cnvrg::Logger.log_error(e)
469
+ Cnvrg::Logger.log_method(bind: binding)
470
+ end
471
+ end
472
+
473
+ def download_and_read(path)
474
+ body = nil
475
+ retries = 0
476
+ success= false
477
+ while !success and retries < 20
478
+ begin
479
+ if !Helpers.is_verify_ssl
480
+ body = open(path, {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE}).read
481
+ else
482
+ body = open(path).read
483
+ end
484
+ success = true
485
+ rescue => e
486
+ retries +=1
487
+ sleep(1)
488
+ end
489
+ end
490
+ body
491
+ end
492
+
493
+ def upload_large_files_s3(upload_resp, file_path)
494
+ begin
495
+ return true if upload_resp['result']['already_exists'].present?
496
+ sts_path = upload_resp["result"]["path_sts"]
497
+ retries = 0
498
+ success= false
499
+ while !success and retries < 20
500
+ begin
501
+ if !Helpers.is_verify_ssl
502
+ body = open(sts_path, {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE}).read
503
+ else
504
+ body = open(sts_path).read
505
+ end
506
+ success = true
507
+ rescue => e
508
+ retries +=1
509
+ sleep(5)
510
+
511
+ end
512
+ end
513
+ if !success
514
+ return false
515
+ end
516
+ split = body.split("\n")
517
+ key = split[0]
518
+ iv = split[1]
519
+
520
+ access = Cnvrg::Helpers.decrypt(key, iv, upload_resp["result"]["sts_a"])
521
+
522
+ secret = Cnvrg::Helpers.decrypt(key,iv, upload_resp["result"]["sts_s"])
523
+
524
+ session = Cnvrg::Helpers.decrypt(key,iv, upload_resp["result"]["sts_st"])
525
+ region = Cnvrg::Helpers.decrypt(key,iv, upload_resp["result"]["region"])
526
+
527
+ bucket = Cnvrg::Helpers.decrypt(key,iv, upload_resp["result"]["bucket"])
528
+ is_s3 = upload_resp["result"]["is_s3"]
529
+ server_side_encryption =upload_resp["result"]["server_side_encryption"]
530
+ use_accelerate_endpoint = false
531
+
532
+ if is_s3 or is_s3.nil?
533
+ use_accelerate_endpoint =true
534
+ client = Aws::S3::Client.new(
535
+ :access_key_id =>access,
536
+ :secret_access_key => secret,
537
+ :session_token => session,
538
+ :region => region,
539
+ :http_open_timeout => 60, :retry_limit => 20)
540
+ else
541
+ endpoint = Cnvrg::Helpers.decrypt(key,iv, upload_resp["result"]["endpoint"])
542
+ client = Aws::S3::Client.new(
543
+ :access_key_id =>access,
544
+ :secret_access_key => secret,
545
+ :region => region,
546
+ :endpoint=> endpoint,:force_path_style=> true,:ssl_verify_peer=>false,
547
+ :http_open_timeout => 60, :retry_limit => 20)
548
+ end
549
+
550
+ if !server_side_encryption
551
+ options = {:use_accelerate_endpoint => use_accelerate_endpoint}
552
+ else
553
+ options = {:use_accelerate_endpoint => use_accelerate_endpoint, :server_side_encryption => server_side_encryption}
554
+ end
555
+ s3 = Aws::S3::Resource.new(client: client)
556
+ resp = s3.bucket(bucket).
557
+ object(upload_resp["result"]["path"]+"/"+File.basename(file_path)).
558
+ upload_file(file_path, options)
559
+
560
+ return resp
561
+
562
+ rescue => e
563
+ puts e
564
+ return false
565
+ rescue SignalException
566
+ return false
567
+
568
+ end
569
+ return true
570
+
571
+ end
572
+
573
+
574
+ def upload_small_files_s3(url_path, file_path, content_type)
575
+ url = URI.parse(url_path)
576
+ file = File.open(file_path, "rb")
577
+ body = file.read
578
+ begin
579
+ Net::HTTP.start(url.host) do |http|
580
+ if !Helpers.is_verify_ssl
581
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
582
+ end
583
+ http.send_request("PUT", url.request_uri, body, {
584
+ "content-type" => content_type,
585
+ })
586
+ end
587
+ return true
588
+ rescue Interrupt
589
+ return false
590
+ rescue => e
591
+ puts e
592
+ return false
593
+ end
594
+ end
595
+
596
+ def upload_url(file_path)
597
+ response = Cnvrg::API.request(@base_resource + "upload_url", 'POST', {file_s3_path: file_path})
598
+ if Cnvrg::CLI.is_response_success(response, false)
599
+ return response
600
+ else
601
+ return nil
602
+ end
603
+
604
+ end
605
+
606
+ def delete_file(relative_path, commit_sha1)
607
+ response = Cnvrg::API.request(@base_resource + "delete_file", 'DELETE', {relative_path: relative_path, commit_sha1: commit_sha1})
608
+ return Cnvrg::CLI.is_response_success(response, false)
609
+ end
610
+
611
+ def delete_dir(relative_path, commit_sha1)
612
+ response = Cnvrg::API.request(@base_resource + "delete_dir", 'DELETE', {relative_path: relative_path, commit_sha1: commit_sha1})
613
+ return Cnvrg::CLI.is_response_success(response, false)
614
+ end
615
+
616
+ def create_dir(absolute_path, relative_path, commit_sha1)
617
+ response = Cnvrg::API.request(@base_resource + "create_dir", 'POST', {absolute_path: absolute_path, relative_path: relative_path, commit_sha1: commit_sha1})
618
+ return Cnvrg::CLI.is_response_success(response, false)
619
+ end
620
+
621
+
622
+ def calculate_sha1(files_list)
623
+ files_list = files_list.map{|file| "#{@project_home}/#{file}"}
624
+ files_list = files_list.select{|file| !file.ends_with? '/'}
625
+ #TODO: parallel
626
+ files_list.map do |file|
627
+ next [file, nil] unless File.exists? file
628
+ next [file, nil] if File.directory? file
629
+ sha1 = OpenSSL::Digest::SHA1.file(file).hexdigest
630
+ [file.gsub("#{@project_home}/", ""), sha1]
631
+ end.to_h
632
+ end
633
+
634
+
635
+ def download_file_s3(relative_path, commit_sha1=nil, postfix: '')
636
+ begin
637
+ res = Cnvrg::API.request(@base_resource + "download_file", 'POST', {relative_path: relative_path,
638
+ commit_sha1: commit_sha1,new_version:true})
639
+
640
+ Cnvrg::CLI.is_response_success(res, false)
641
+ if res["result"]
642
+ download_resp = res
643
+ filename = download_resp["result"]["filename"]
644
+ sts_path = download_resp["result"]["path_sts"]
645
+ retries = 0
646
+ success= false
647
+ while !success and retries < 20
648
+ begin
649
+ if !Helpers.is_verify_ssl
650
+ body = open(sts_path, {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE}).read
651
+ else
652
+ body = open(sts_path).read
653
+ end
654
+ success = true
655
+ rescue => e
656
+ retries +=1
657
+ sleep(5)
658
+
659
+ end
660
+ end
661
+ if !success
662
+ puts "error in sts"
663
+ return false
664
+ end
665
+
666
+ split = body.split("\n")
667
+ key = split[0]
668
+ iv = split[1]
669
+
670
+ access = Cnvrg::Helpers.decrypt(key, iv, download_resp["result"]["sts_a"])
671
+
672
+ secret = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["sts_s"])
673
+
674
+ session = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["sts_st"])
675
+ region = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["region"])
676
+
677
+ bucket = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["bucket"])
678
+ file_key = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["key"])
679
+
680
+
681
+ is_s3 = download_resp["result"]["is_s3"]
682
+ if is_s3 or is_s3.nil?
683
+ client = Aws::S3::Client.new(
684
+ :access_key_id =>access,
685
+ :secret_access_key => secret,
686
+ :session_token => session,
687
+ :region => region,
688
+ :http_open_timeout => 60, :retry_limit => 20)
689
+ else
690
+ endpoint = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["endpoint"])
691
+ client = Aws::S3::Client.new(
692
+ :access_key_id =>access,
693
+ :secret_access_key => secret,
694
+ :region => region,
695
+ :endpoint=> endpoint,:force_path_style=> true,:ssl_verify_peer=>false,
696
+ :http_open_timeout => 60, :retry_limit => 20)
697
+ end
698
+ absolute_path = "#{@project_home}/#{relative_path}#{postfix}"
699
+ File.open(absolute_path, 'w+') do |file|
700
+ resp = client.get_object({bucket:bucket,
701
+ key:file_key}, target: file)
702
+ end
703
+ return true
704
+ end
705
+
706
+ rescue => e
707
+ puts "error in aws"
708
+
709
+ puts e.message
710
+ return false
711
+
712
+ end
713
+ end
714
+
715
+ def create_progressbar(length = 10, title = 'Progress')
716
+ @progressbar = ProgressBar.create(:title => title,
717
+ :progress_mark => '=',
718
+ :format => "%b>>%i| %p%% %t",
719
+ :starting_at => 0,
720
+ :total => length,
721
+ :autofinish => true)
722
+ @custom_progess = true
723
+ @progressbar
724
+ end
725
+
726
+ def download_files(files, commit, postfix: '', progress: nil)
727
+ return if files.blank?
728
+ if Cnvrg::Helpers.server_version < 1
729
+ Cnvrg::Logger.log_info("Download files from older server.")
730
+ return self.download_files_old(files, commit, progress: progress, postfix: postfix)
731
+ end
732
+ res = Cnvrg::API.request(@base_resource + "download_files", 'POST', {files: files, commit: commit})
733
+ unless Cnvrg::CLI.is_response_success(res, false)
734
+ raise SignalException.new("Cant download files from the server.")
735
+ end
736
+ self.download_multpile_files_s3(res['result'], @project_home, postfix: postfix, progress: progress)
737
+ end
738
+
739
+
740
+ def download_files_old(files, commit, postfix: '', progress: nil)
741
+ files.each do |file|
742
+ self.download_file_s3(file, commit, postfix: postfix)
743
+ progress.progress += 1 if progress.present?
744
+ end
745
+ end
746
+
747
+ def delete_files_local(deleted, conflicted: [], progress: nil)
748
+ deleted -= conflicted
749
+ deleted.each{|file| self.delete(file); progress.progress += 1 if progress.present?}
750
+ conflicted.each{|file| self.delete_conflict(file); progress.progress += 1 if progress.present?}
751
+ end
752
+
753
+ def download_multpile_files_s3(files, project_home, postfix: '', progress: nil)
754
+ begin
755
+ props = {}
756
+ client = props[:client]
757
+ iv = props[:iv]
758
+ key = props[:key]
759
+ bucket = props[:bucket]
760
+ download_succ_count = 0
761
+ parallel_options = {
762
+ in_threads: Cnvrg::Helpers.parallel_threads,
763
+ isolation: true
764
+ }
765
+
766
+ token_mutex = Mutex.new
767
+
768
+ Parallel.map(files["keys"], parallel_options) do |f|
769
+
770
+ token_mutex.synchronize {
771
+ refresh_storage_token
772
+ }
773
+
774
+ file_path = f["name"]
775
+ if file_path.end_with? "/"
776
+ # dir
777
+ if download_dir(file_path, file_path, project_home)
778
+ download_succ_count += 1
779
+ else
780
+ return Cnvrg::Result.new(false,"Could not create directory: #{file_path}")
781
+ raise Parallel::Kill
782
+ end
783
+ else
784
+ file_path += postfix
785
+ # blob
786
+ begin
787
+ if not File.exists?(project_home+"/"+File.dirname(file_path))
788
+ FileUtils.makedirs(project_home+"/"+File.dirname(file_path))
789
+ end
790
+ local_path = project_home+"/"+file_path
791
+ storage_path = f["path"]
792
+ @client.download(storage_path, local_path)
793
+ progress.progress += 1 if progress.present?
794
+ download_succ_count += 1
795
+ rescue => e
796
+ return Cnvrg::Result.new(false,"Could not create file: #{file_path}", e.message, e.backtrace)
797
+ raise Parallel::Kill
798
+ end
799
+
800
+
801
+
802
+ end
803
+ end
804
+ if download_succ_count == files["keys"].size
805
+ return Cnvrg::Result.new(true,"Done.\nDownloaded #{download_succ_count} files")
806
+ end
807
+ rescue => e
808
+ return Cnvrg::Result.new(false,"Could not download some files", e.message, e.backtrace)
809
+ end
810
+
811
+
812
+
813
+
814
+ end
815
+ def download_file(absolute_path, relative_path, project_home, conflict=false)
816
+ res = Cnvrg::API.request(@base_resource + "download_file", 'POST', {absolute_path: absolute_path, relative_path: relative_path})
817
+ Cnvrg::CLI.is_response_success(res, false)
818
+ if res["result"]
819
+ res = res["result"]
820
+ return false if res["link"].empty? or res["filename"].empty?
821
+ filename = res["filename"]
822
+ file_location = absolute_path.gsub(/#{filename}\/?$/, "")
823
+
824
+ FileUtils.mkdir_p project_home + "/" + file_location
825
+ filename += ".conflict" if conflict
826
+
827
+ File.open("#{project_home}/#{file_location}/#{filename}", "wb") do |file|
828
+ file.write open(res["link"]).read
829
+ end
830
+ else
831
+ return false
832
+ end
833
+ return true
834
+ end
835
+
836
+ def show_file_s3(relative_path, commit_sha1=nil)
837
+ begin
838
+ res = Cnvrg::API.request(@base_resource + "download_file", 'POST', { absolute_path: '', relative_path: relative_path, commit_sha1: commit_sha1, new_version:true })
839
+
840
+ Cnvrg::CLI.is_response_success(res, false)
841
+ if res["result"]
842
+ download_resp = res
843
+ filename = download_resp["result"]["filename"]
844
+
845
+ #absolute_path += ".conflict" if conflict
846
+ sts_path = download_resp["result"]["path_sts"]
847
+ uri = URI.parse(sts_path)
848
+ http_object = Net::HTTP.new(uri.host, uri.port)
849
+ http_object.use_ssl = true if uri.scheme == 'https'
850
+ request = Net::HTTP::Get.new(sts_path)
851
+
852
+ body = ""
853
+ http_object.start do |http|
854
+ response = http.request request
855
+ body = response.read_body
856
+ end
857
+ split = body.split("\n")
858
+ key = split[0]
859
+ iv = split[1]
860
+
861
+ access = Cnvrg::Helpers.decrypt(key, iv, download_resp["result"]["sts_a"])
862
+
863
+ secret = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["sts_s"])
864
+
865
+ session = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["sts_st"])
866
+ region = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["region"])
867
+
868
+ bucket = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["bucket"])
869
+ key = Cnvrg::Helpers.decrypt(key,iv, download_resp["result"]["key"])
870
+
871
+ client = Aws::S3::Client.new(
872
+ :access_key_id =>access,
873
+ :secret_access_key => secret,
874
+ :session_token => session,
875
+ :region => region,
876
+ :http_open_timeout => 60, :retry_limit => 20
877
+ )
878
+ resp = client.get_object({bucket:bucket,
879
+ key:key})
880
+ return resp.body.string
881
+ end
882
+
883
+ rescue => e
884
+ puts e
885
+ return false
886
+
887
+ end
888
+ end
889
+
890
+ def download_dir(absolute_path, relative_path, project_home)
891
+ FileUtils.mkdir_p("#{project_home}/#{absolute_path}")
892
+ end
893
+
894
+ def revoke_download_dir(absolute_path, relative_path, project_home)
895
+ puts FileUtils.rmtree("#{absolute_path}")
896
+ end
897
+
898
+ def revoke_download_file(project_home, absolute_path, filename, conflict=false)
899
+ begin
900
+ file_location = absolute_path.gsub(/#{filename}\/?$/, "")
901
+
902
+ filename += ".conflict" if conflict
903
+ FileUtils.remove("#{file_location}/#{filename}")
904
+ return true
905
+ rescue
906
+ return false
907
+ end
908
+ end
909
+ def revoke_download(conflicted_changes,downloaded_changes)
910
+ begin
911
+ if !conflicted_changes.nil? and !conflicted_changes.empty?
912
+ conflicted_changes.each do |c|
913
+ # FileUtils.rm_rf(c+".conflict")
914
+ end
915
+ end
916
+ # FileUtils.rm_rf(downloaded_changes) unless (downloaded_changes.nil? or downloaded_changes.empty?)
917
+ rescue => e
918
+ return false
919
+ end
920
+
921
+ return true
922
+
923
+ end
924
+ def revoke_clone(project_home)
925
+ begin
926
+ FileUtils.rm_rf(project_home)
927
+ rescue
928
+ end
929
+
930
+ end
931
+
932
+ def delete_commit_files_local(deleted)
933
+ begin
934
+ FileUtils.rm_rf(deleted) unless (deleted.nil? or deleted.empty?)
935
+ return true
936
+ rescue => e
937
+ return false
938
+ end
939
+ end
940
+
941
+ def start_commit(new_branch,force:false, exp_start_commit:nil, job_slug: nil, job_type: nil, start_commit: nil, message: nil, debug_mode: false)
942
+ response = Cnvrg::API.request(
943
+ "#{base_resource}/commit/start",
944
+ 'POST',
945
+ {
946
+ project_slug: @project_slug, username: @owner,
947
+ new_branch: new_branch, force:force,
948
+ exp_start_commit:exp_start_commit, start_commit: start_commit,
949
+ job_slug: job_slug, job_type: job_type, message: message,
950
+ debug_mode: debug_mode
951
+ }
952
+ )
953
+
954
+ Cnvrg::CLI.is_response_success(response,false)
955
+ return response
956
+ end
957
+
958
+ def end_commit(commit_sha1,force:false,message:"")
959
+ response = Cnvrg::API.request("#{base_resource}/commit/end", 'POST', {commit_sha1: commit_sha1,force:force,message:message})
960
+ return response
961
+ end
962
+
963
+ def download_file(file_path: '', key: '', iv: '', bucket: '', path: '', client: nil)
964
+ local_path = @project_home+"/"+file_path
965
+ @client.download(path, local_path)
966
+ end
967
+
968
+ def delete(file)
969
+ file = "#{@project_home}/#{file}" unless File.exists? file
970
+ return unless File.exists? file
971
+ FileUtils.rm_rf(file)
972
+ end
973
+
974
+ def delete_conflict(file)
975
+ file = "#{@project_home}/#{file}" unless File.exists? file
976
+ return unless File.exists? file
977
+ File.rename(file, "#{file}.deleted")
978
+ end
979
+
980
+ def handle_compare_idx(compared, resolver: {})
981
+ begin
982
+ all_files = compared.values.flatten.uniq
983
+ props = {}
984
+ files = resolver['keys'].map{|f| [f['name'], f]}.to_h
985
+ client = props[:client]
986
+ iv = props[:iv]
987
+ key = props[:key]
988
+ bucket = props[:bucket]
989
+ parallel_options = {
990
+ :progress => {
991
+ :title => "Jump Progress",
992
+ :progress_mark => '=',
993
+ :format => "%b>>%i| %p%% %t",
994
+ :starting_at => 0,
995
+ :total => all_files.size,
996
+ :autofinish => true
997
+ },
998
+ in_processes: Cnvrg::CLI::ParallelProcesses,
999
+ in_thread: Cnvrg::CLI::ParallelThreads
1000
+ }
1001
+ Parallel.map(all_files, parallel_options) do |file|
1002
+ Cnvrg::CLI.log_message("Trying #{file}")
1003
+ if compared['conflicts'].include? file
1004
+ self.download_file(file_path: "#{file}.conflict", key: key, iv: iv, bucket: bucket, path: files[file]['path'], client: client)
1005
+ next
1006
+ end
1007
+ if compared['updated_on_server'].include? file
1008
+ self.download_file(file_path: file, key: key, iv: iv, bucket: bucket, path: files[file]['path'], client: client)
1009
+ next
1010
+ end
1011
+ if compared['deleted'].include? file
1012
+ self.delete(file)
1013
+ next
1014
+ end
1015
+ Cnvrg::CLI.log_message("Failed #{file}")
1016
+ end
1017
+ rescue => e
1018
+ Cnvrg::Logger.log_error(e)
1019
+ raise SignalException.new("Cant upload files")
1020
+ end
1021
+ end
1022
+ def rollback_commit(commit_sha1)
1023
+ response = Cnvrg::API.request("#{base_resource}/commit/rollback", 'POST', {commit_sha1: commit_sha1})
1024
+ Cnvrg::CLI.is_response_success(response, false)
1025
+ end
1026
+ private
1027
+ def log(msgs, type: Thor::Shell::Color::GREEN)
1028
+ return false if @cli.blank?
1029
+ msgs = [msgs].flatten
1030
+ msgs.each do |msg|
1031
+ @cli.log_message(msg, type)
1032
+ end
1033
+ end
1034
+
1035
+
1036
+ def log_error(msgs)
1037
+ @cli.log_error(msgs) if @cli.present?
1038
+ log(msgs, type: Thor::Shell::Color::RED)
1039
+ end
1040
+
1041
+ def log_progress(msgs)
1042
+ log(msgs, type: Thor::Shell::Color::BLUE)
1043
+ end
1044
+ end
1045
+
1046
+
1047
+ end