cnvrg 1.2.7 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/cnvrg.gemspec +3 -2
- data/lib/cnvrg/api.rb +2 -2
- data/lib/cnvrg/cli.rb +51 -36
- data/lib/cnvrg/data.rb +14 -3
- data/lib/cnvrg/datafiles.rb +20 -62
- data/lib/cnvrg/dataset.rb +198 -144
- data/lib/cnvrg/downloader/client.rb +53 -0
- data/lib/cnvrg/downloader/clients/azure_client.rb +22 -0
- data/lib/cnvrg/downloader/clients/gcp_client.rb +46 -0
- data/lib/cnvrg/downloader/clients/s3_client.rb +51 -0
- data/lib/cnvrg/files.rb +17 -44
- data/lib/cnvrg/helpers/executer.rb +171 -0
- data/lib/cnvrg/job_cli.rb +33 -0
- data/lib/cnvrg/project.rb +45 -6
- data/lib/cnvrg/storage.rb +128 -0
- data/lib/cnvrg/version.rb +1 -1
- metadata +28 -7
- data/lib/cnvrg/job.rb +0 -40
@@ -0,0 +1,33 @@
|
|
1
|
+
module Cnvrg
|
2
|
+
class JobCli < SubCommandBase
|
3
|
+
|
4
|
+
desc 'log', description: '', hide: true
|
5
|
+
method_option :level, :type => :string, :aliases => ["-l", "--level"], :default => 'info'
|
6
|
+
method_option :step, :type => :string, :aliases => ["-s", "--step"], :default => nil
|
7
|
+
def log(*logs)
|
8
|
+
Cnvrg::CLI.new.log_start(__method__, args, options)
|
9
|
+
@project = Project.new(owner: ENV['CNVRG_OWNER'], slug: ENV['CNVRG_PROJECT'])
|
10
|
+
@project.job_log(logs, level: options['level'], step: options['step'])
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
desc 'start', description: '', hide: true
|
15
|
+
def start(*logs)
|
16
|
+
cli = Cnvrg::CLI.new
|
17
|
+
cli.log_start(__method__, args, options)
|
18
|
+
@project = Project.new(nil, owner: ENV['CNVRG_OWNER'], slug: ENV['CNVRG_PROJECT'])
|
19
|
+
@executer = Helpers::Executer.new(project: @project, job_type: ENV['CNVRG_JOB_TYPE'], job_id: ENV['CNVRG_JOB_ID'])
|
20
|
+
commands = @executer.fetch_commands
|
21
|
+
@executer.execute_cmds(commands)
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'requirements', description: '', hide: true
|
25
|
+
def requirements
|
26
|
+
cli = Cnvrg::CLI.new
|
27
|
+
cli.log_start(__method__, args, options)
|
28
|
+
project_dir = cli.get_project_home
|
29
|
+
@project = Project.new(project_dir, owner: ENV['CNVRG_OWNER'], slug: ENV['CNVRG_PROJECT'])
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
data/lib/cnvrg/project.rb
CHANGED
@@ -7,11 +7,11 @@ module Cnvrg
|
|
7
7
|
IDXParallelThreads ||= Cnvrg::Helpers.parallel_threads
|
8
8
|
|
9
9
|
|
10
|
-
def initialize(project_home)
|
10
|
+
def initialize(project_home=nil, slug: nil, owner: nil)
|
11
11
|
begin
|
12
12
|
@local_path = project_home
|
13
13
|
@working_dir = project_home
|
14
|
-
config = YAML.load_file(project_home + "/.cnvrg/config.yml")
|
14
|
+
config = YAML.load_file(project_home + "/.cnvrg/config.yml") rescue {owner: owner, project_slug: slug}
|
15
15
|
@title = config[:project_name]
|
16
16
|
@slug = config[:project_slug]
|
17
17
|
@owner = config[:owner]
|
@@ -126,7 +126,7 @@ module Cnvrg
|
|
126
126
|
|
127
127
|
# Create project
|
128
128
|
|
129
|
-
def self.create(project_name, clean, with_docker = false)
|
129
|
+
def self.create(project_name, clean, with_docker = false, bucket: nil)
|
130
130
|
if clean
|
131
131
|
list_dirs = [project_name, project_name + "/.cnvrg"]
|
132
132
|
else
|
@@ -154,7 +154,7 @@ module Cnvrg
|
|
154
154
|
begin
|
155
155
|
|
156
156
|
owner = Cnvrg::CLI.get_owner()
|
157
|
-
response = Cnvrg::API.request("cli/create_project", 'POST', {title: project_name, owner: owner, is_docker: with_docker})
|
157
|
+
response = Cnvrg::API.request("cli/create_project", 'POST', {title: project_name, owner: owner, is_docker: with_docker, bucket: bucket})
|
158
158
|
Cnvrg::CLI.is_response_success(response)
|
159
159
|
response = JSON.parse response["result"]
|
160
160
|
project_slug = response["slug"]
|
@@ -177,7 +177,7 @@ module Cnvrg
|
|
177
177
|
return true
|
178
178
|
end
|
179
179
|
|
180
|
-
def self.link(owner, project_name, docker = false, git = false)
|
180
|
+
def self.link(owner, project_name, docker = false, git = false, bucket: nil)
|
181
181
|
ignore_exits = File.exist? ".cnvrgignore"
|
182
182
|
list_dirs = [".cnvrg"
|
183
183
|
]
|
@@ -192,7 +192,7 @@ module Cnvrg
|
|
192
192
|
cnvrgreadme = Helpers.readme_content
|
193
193
|
cnvrgignore = Helpers.cnvrgignore_content
|
194
194
|
begin
|
195
|
-
response = Cnvrg::API.request("cli/create_project", 'POST', {title: project_name, owner: owner, is_docker: docker})
|
195
|
+
response = Cnvrg::API.request("cli/create_project", 'POST', {title: project_name, owner: owner, is_docker: docker, bucket: bucket})
|
196
196
|
Cnvrg::CLI.is_response_success(response)
|
197
197
|
response = JSON.parse response["result"]
|
198
198
|
project_slug = response["slug"]
|
@@ -324,6 +324,30 @@ module Cnvrg
|
|
324
324
|
YAML.load_file(@working_dir + "/.cnvrg/config.yml") rescue {}
|
325
325
|
end
|
326
326
|
|
327
|
+
def get_storage_client
|
328
|
+
response = Cnvrg::API.request("users/#{@owner}/projects/#{@slug}/client", 'GET')
|
329
|
+
if Cnvrg::CLI.is_response_success(response, false)
|
330
|
+
client_params = response['client']
|
331
|
+
else
|
332
|
+
client_params = get_storage_client_fallback
|
333
|
+
end
|
334
|
+
Cnvrg::Downloader::Client.factory(client_params)
|
335
|
+
end
|
336
|
+
|
337
|
+
def get_storage_client_fallback
|
338
|
+
response = Cnvrg::API.request("users/#{@owner}/projects/#{@slug}/download_files", "POST", {files: [], commit: get_latest_commit})
|
339
|
+
raise StandardError.new("Can't find project credentials") unless Cnvrg::CLI.is_response_success(response, false)
|
340
|
+
files = response['result']
|
341
|
+
storage = files['is_s3'] ? 's3' : 'minio'
|
342
|
+
files['storage'] = storage
|
343
|
+
files
|
344
|
+
end
|
345
|
+
|
346
|
+
def get_latest_commit
|
347
|
+
resp = clone(0, '')
|
348
|
+
resp['result']['commit']
|
349
|
+
end
|
350
|
+
|
327
351
|
def set_config(config)
|
328
352
|
slug = config[:project_slug] rescue nil
|
329
353
|
owner = config[:owner] rescue nil
|
@@ -631,6 +655,21 @@ module Cnvrg
|
|
631
655
|
self.set_config(config)
|
632
656
|
end
|
633
657
|
|
658
|
+
def job_log(logs, level: 'info', step: nil, job_type: nil, job_id: nil)
|
659
|
+
job_type ||= ENV['CNVRG_JOB_TYPE']
|
660
|
+
job_id ||= ENV['CNVRG_JOB_ID']
|
661
|
+
logs = [logs].flatten
|
662
|
+
if job_type.blank? or job_id.blank?
|
663
|
+
raise StandardError.new("Cant find job env variables")
|
664
|
+
end
|
665
|
+
Cnvrg::API.request("users/#{@owner}/projects/#{@slug}/jobs/#{job_type.underscore}/#{job_id}/log", "POST", {job_type: job_type, job_id: job_id, logs: logs, log_level: level, step: step, timestamp: Time.now})
|
666
|
+
end
|
667
|
+
|
668
|
+
|
669
|
+
def job_commands
|
670
|
+
job_type, job_id = ENV['CNVRG_JOB_TYPE'], ENV['CNVRG_JOB_ID']
|
671
|
+
resp = Cnvrg::API.request("users/#{@owner}/projects/#{@slug}/jobs/#{job_type.underscore}/#{job_id}/commands", "GET")
|
672
|
+
end
|
634
673
|
|
635
674
|
def spot_will_terminate
|
636
675
|
restart = false
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module Cnvrg
|
2
|
+
class Storage
|
3
|
+
def initialize(dataset: nil, project: nil, root_path: nil)
|
4
|
+
@element = dataset || project
|
5
|
+
@root_path = root_path
|
6
|
+
@client = @element.get_storage_client
|
7
|
+
end
|
8
|
+
|
9
|
+
def log_error(action: nil, error: '')
|
10
|
+
"[#{Time.now}] (#{action || 'default'}) #{error}"
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def get_chunks_size
|
15
|
+
(ENV['CNVRG_STORAGE_CHUNK_SIZE'] || 10).to_i
|
16
|
+
end
|
17
|
+
|
18
|
+
def init_progress_bar(size: nil, title: "Download Progress")
|
19
|
+
@progressbar = ProgressBar.create(:title => title,
|
20
|
+
:progress_mark => '=',
|
21
|
+
:format => "%b>>%i| %p%% %t",
|
22
|
+
:starting_at => 0,
|
23
|
+
:total => size,
|
24
|
+
:autofinish => true)
|
25
|
+
end
|
26
|
+
|
27
|
+
def make_progress(size: 1)
|
28
|
+
@progressbar.progress += size
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def clone(commit: nil)
|
33
|
+
files_generator = Proc.new do |params|
|
34
|
+
@element.get_clone_chunk(commit: commit, chunk_size: params[:limit], offset: params[:offset])
|
35
|
+
end
|
36
|
+
action = Proc.new do |storage, local|
|
37
|
+
@client.download(storage, local)
|
38
|
+
end
|
39
|
+
|
40
|
+
@stats = @element.get_stats
|
41
|
+
progress = {size: @stats['commit_size'], title: "Clone Progress"}
|
42
|
+
|
43
|
+
storage_action(files_generator: files_generator, action: action, progress: progress)
|
44
|
+
end
|
45
|
+
|
46
|
+
def upload_files(commit: nil)
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
def upload_files(files_generator, progress: {size: 0, title: ''})
|
51
|
+
init_progress_bar(progress)
|
52
|
+
@storage_errors = []
|
53
|
+
@finished = false
|
54
|
+
@files = Queue.new
|
55
|
+
t = Thread.new{file_gen_thread(files_generator)}
|
56
|
+
do_parallel{|file| self.upload_files_thread(file); self.make_progress(size: file['size'])}
|
57
|
+
t.join
|
58
|
+
handle_errors
|
59
|
+
end
|
60
|
+
|
61
|
+
def file_gen_upload_thread(files_generator)
|
62
|
+
while true
|
63
|
+
files = files_generator
|
64
|
+
files.each{|f| @files.push(f)}
|
65
|
+
break if files.blank?
|
66
|
+
end
|
67
|
+
@finished = true
|
68
|
+
end
|
69
|
+
|
70
|
+
def storage_action(files_generator: nil, action: nil, progress: {size: 0, title: ''})
|
71
|
+
### the generator files should have {path (encrypted), name, size}
|
72
|
+
init_progress_bar(progress)
|
73
|
+
@storage_errors = []
|
74
|
+
@finished = false
|
75
|
+
@files = Queue.new
|
76
|
+
t = Thread.new{file_gen_thread(files_generator)}
|
77
|
+
do_parallel do |file|
|
78
|
+
self.download_file_thread(file) do |local, storage|
|
79
|
+
action.call(local, storage)
|
80
|
+
end
|
81
|
+
self.make_progress(size: file['size'])
|
82
|
+
end
|
83
|
+
t.join
|
84
|
+
handle_errors
|
85
|
+
end
|
86
|
+
|
87
|
+
def file_gen_thread(file_gen)
|
88
|
+
offset = 0
|
89
|
+
chunk_size = get_chunks_size
|
90
|
+
while true
|
91
|
+
files = file_gen.call(limit: chunk_size, offset: offset)
|
92
|
+
break if files.blank?
|
93
|
+
files.each{|f| @files.push(f)}
|
94
|
+
offset += files.size
|
95
|
+
end
|
96
|
+
@finished = true
|
97
|
+
end
|
98
|
+
|
99
|
+
def handle_errors
|
100
|
+
if @storage_errors.present?
|
101
|
+
File.open(@element.working_dir + "/.cnvrg/errors.yml", "w+"){|f| f.write @storage_errors.to_yaml}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def do_parallel
|
106
|
+
Parallel.each( -> { @files.empty? ? (@finished ? Parallel::Stop : sleep(1)) : @files.pop }, in_threads: get_chunks_size) do |file|
|
107
|
+
if file == 1
|
108
|
+
next
|
109
|
+
end
|
110
|
+
yield(file)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def download_file_thread(file)
|
115
|
+
return if file.blank?
|
116
|
+
local_path = file['name']
|
117
|
+
storage_path = file['path']
|
118
|
+
(0..5).each do
|
119
|
+
begin
|
120
|
+
# @client.download(storage_path, "#{@root_path}/#{local_path}")
|
121
|
+
break
|
122
|
+
rescue => e
|
123
|
+
log_error(action: "download #{local_path}", error: e.message)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
data/lib/cnvrg/version.rb
CHANGED
metadata
CHANGED
@@ -1,30 +1,31 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cnvrg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2
|
4
|
+
version: 1.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yochay Ettun
|
8
8
|
- Leah Kolben
|
9
|
+
- Omer Shacham
|
9
10
|
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date: 2019-
|
13
|
+
date: 2019-05-05 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: bundler
|
16
17
|
requirement: !ruby/object:Gem::Requirement
|
17
18
|
requirements:
|
18
|
-
- - "
|
19
|
+
- - ">="
|
19
20
|
- !ruby/object:Gem::Version
|
20
|
-
version: '
|
21
|
+
version: '0'
|
21
22
|
type: :development
|
22
23
|
prerelease: false
|
23
24
|
version_requirements: !ruby/object:Gem::Requirement
|
24
25
|
requirements:
|
25
|
-
- - "
|
26
|
+
- - ">="
|
26
27
|
- !ruby/object:Gem::Version
|
27
|
-
version: '
|
28
|
+
version: '0'
|
28
29
|
- !ruby/object:Gem::Dependency
|
29
30
|
name: rake
|
30
31
|
requirement: !ruby/object:Gem::Requirement
|
@@ -217,6 +218,20 @@ dependencies:
|
|
217
218
|
- - "~>"
|
218
219
|
- !ruby/object:Gem::Version
|
219
220
|
version: '2'
|
221
|
+
- !ruby/object:Gem::Dependency
|
222
|
+
name: google-cloud-storage
|
223
|
+
requirement: !ruby/object:Gem::Requirement
|
224
|
+
requirements:
|
225
|
+
- - "~>"
|
226
|
+
- !ruby/object:Gem::Version
|
227
|
+
version: '1.16'
|
228
|
+
type: :runtime
|
229
|
+
prerelease: false
|
230
|
+
version_requirements: !ruby/object:Gem::Requirement
|
231
|
+
requirements:
|
232
|
+
- - "~>"
|
233
|
+
- !ruby/object:Gem::Version
|
234
|
+
version: '1.16'
|
220
235
|
- !ruby/object:Gem::Dependency
|
221
236
|
name: sucker_punch
|
222
237
|
requirement: !ruby/object:Gem::Requirement
|
@@ -379,18 +394,24 @@ files:
|
|
379
394
|
- lib/cnvrg/data.rb
|
380
395
|
- lib/cnvrg/datafiles.rb
|
381
396
|
- lib/cnvrg/dataset.rb
|
397
|
+
- lib/cnvrg/downloader/client.rb
|
398
|
+
- lib/cnvrg/downloader/clients/azure_client.rb
|
399
|
+
- lib/cnvrg/downloader/clients/gcp_client.rb
|
400
|
+
- lib/cnvrg/downloader/clients/s3_client.rb
|
382
401
|
- lib/cnvrg/experiment.rb
|
383
402
|
- lib/cnvrg/files.rb
|
384
403
|
- lib/cnvrg/flow.rb
|
385
404
|
- lib/cnvrg/helpers.rb
|
405
|
+
- lib/cnvrg/helpers/executer.rb
|
386
406
|
- lib/cnvrg/hyper.rb
|
387
|
-
- lib/cnvrg/
|
407
|
+
- lib/cnvrg/job_cli.rb
|
388
408
|
- lib/cnvrg/logger.rb
|
389
409
|
- lib/cnvrg/org_helpers.rb
|
390
410
|
- lib/cnvrg/project.rb
|
391
411
|
- lib/cnvrg/result.rb
|
392
412
|
- lib/cnvrg/runner.rb
|
393
413
|
- lib/cnvrg/ssh.rb
|
414
|
+
- lib/cnvrg/storage.rb
|
394
415
|
- lib/cnvrg/task.rb
|
395
416
|
- lib/cnvrg/version.rb
|
396
417
|
homepage: https://cnvrg.io
|
data/lib/cnvrg/job.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
require 'mimemagic'
|
2
|
-
require 'aws-sdk'
|
3
|
-
require 'URLcrypt'
|
4
|
-
|
5
|
-
require 'sucker_punch'
|
6
|
-
module Cnvrg
|
7
|
-
|
8
|
-
class LogJob
|
9
|
-
include SuckerPunch::Job
|
10
|
-
|
11
|
-
def perform(upload_resp, file_path)
|
12
|
-
begin
|
13
|
-
sts_path = upload_resp["result"]["path_sts"]
|
14
|
-
uri = URI.parse(sts_path)
|
15
|
-
http_object = Net::HTTP.new(uri.host, uri.port)
|
16
|
-
http_object.use_ssl = true if uri.scheme == 'https'
|
17
|
-
request = Net::HTTP::Get.new(sts_path)
|
18
|
-
body = ""
|
19
|
-
http_object.start do |http|
|
20
|
-
response = http.request request
|
21
|
-
body = response.read_body
|
22
|
-
end
|
23
|
-
URLcrypt::key = [body].pack('H*')
|
24
|
-
s3 = Aws::S3::Resource.new(
|
25
|
-
:access_key_id => URLcrypt.decrypt(upload_resp["result"]["sts_a"]),
|
26
|
-
:secret_access_key => URLcrypt.decrypt(upload_resp["result"]["sts_s"]),
|
27
|
-
:session_token => URLcrypt.decrypt(upload_resp["result"]["sts_st"]),
|
28
|
-
:region => URLcrypt.decrypt(upload_resp["result"]["region"]))
|
29
|
-
resp = s3.bucket(URLcrypt.decrypt(upload_resp["result"]["bucket"])).
|
30
|
-
object(upload_resp["result"]["path"]+"/"+File.basename(file_path)).
|
31
|
-
upload_file(file_path)
|
32
|
-
return resp
|
33
|
-
rescue =>e
|
34
|
-
return false
|
35
|
-
|
36
|
-
end
|
37
|
-
return true
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|