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.
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