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,29 @@
1
+ require 'fileutils'
2
+ module Cnvrg
3
+ class Result
4
+ attr_reader :msg, :msg_color, :e_msg, :e_msg_backtrace
5
+
6
+ def initialize(success, msg, e_msg = "", e_backtrace = "")
7
+ begin
8
+ @success = success
9
+ @msg = msg
10
+ @e_msg = e_msg
11
+ @e_msg_backtrace = e_backtrace
12
+ if !@success
13
+ @msg_color = Thor::Shell::Color::RED
14
+ else
15
+ @msg_color = Thor::Shell::Color::GREEN
16
+
17
+ end
18
+ rescue => e
19
+ end
20
+
21
+ end
22
+ def is_success?
23
+ return @success
24
+ end
25
+
26
+ end
27
+
28
+
29
+ end
@@ -0,0 +1,49 @@
1
+ require 'cnvrg'
2
+
3
+ module Cnvrg
4
+ class Runner
5
+ # Allow everything fun to be injected from the outside while defaulting to normal implementations.
6
+ def initialize(argv, stdin = STDIN, stdout = STDOUT, stderr = STDERR, kernel = Kernel)
7
+ @argv, @stdin, @stdout, @stderr, @kernel = argv, stdin, stdout, stderr, kernel
8
+ end
9
+
10
+ def execute!
11
+ exit_code = begin
12
+ # Thor accesses these streams directly rather than letting them be injected, so we replace them...
13
+ $stderr = @stderr
14
+ $stdin = @stdin
15
+ $stdout = @stdout
16
+
17
+ # Run our normal Thor app the way we know and love.
18
+ Cnvrg::CLI.start(@argv)
19
+
20
+ # Thor::Base#start does not have a return value, assume success if no exception is raised.
21
+ 0
22
+ rescue StandardError => e
23
+ # The ruby interpreter would pipe this to STDERR and exit 1 in the case of an unhandled exception
24
+ b = e.backtrace
25
+ @stderr.puts("#{b.shift}: #{e.message} (#{e.class})")
26
+ @stderr.puts(b.map{|s| "\tfrom #{s}"}.join("\n"))
27
+ 1
28
+ rescue SystemExit => e
29
+ e.status
30
+ ensure
31
+ # TODO: reset your app here, free up resources, etc.
32
+ # Examples:
33
+ # MyApp.logger.flush
34
+ # MyApp.logger.close
35
+ # MyApp.logger = nil
36
+ #
37
+ # MyApp.reset_singleton_instance_variables
38
+
39
+ # ...then we put the streams back.
40
+ $stderr = STDERR
41
+ $stdin = STDIN
42
+ $stdout = STDOUT
43
+ end
44
+
45
+ # Proxy our exit code back to the injected kernel.
46
+ @kernel.exit(exit_code)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,94 @@
1
+ require 'fileutils'
2
+ require 'cnvrg/files'
3
+ require 'net/ssh'
4
+
5
+
6
+ module Cnvrg
7
+ class Ssh
8
+ attr_reader :is_ssh
9
+
10
+
11
+ def initialize(resp)
12
+ begin
13
+ @is_ssh = false
14
+ sts_path = resp["result"]["sts_path"]
15
+
16
+ uri = URI.parse(sts_path)
17
+
18
+ http_object = Net::HTTP.new(uri.host, uri.port)
19
+ http_object.use_ssl = true if uri.scheme == 'https'
20
+ request = Net::HTTP::Get.new(sts_path)
21
+
22
+ body = ""
23
+ http_object.start do |http|
24
+ response = http.request request
25
+ body = response.read_body
26
+ end
27
+
28
+ URLcrypt::key = [body].pack('H*')
29
+ ip = URLcrypt.decrypt(resp["result"]["machine_i"])
30
+
31
+ @user = URLcrypt.decrypt(resp["result"]["machine_u"])
32
+ key = URLcrypt.decrypt(resp["result"]["machine_k"])
33
+ @container = URLcrypt.decrypt(resp["result"]["machine_c"])
34
+
35
+ tempssh = Tempfile.new "sshkey"
36
+ tempssh.write open(key).read
37
+ tempssh.rewind
38
+ key_path = tempssh.path
39
+ count = 0
40
+ while count < 5
41
+
42
+ begin
43
+ @ssh = Net::SSH.start(ip, user=@user, :keys => key_path, :timeout => 10)
44
+ if !@ssh.nil?
45
+ @is_ssh = true
46
+ return
47
+ else
48
+ count+=1
49
+ sleep(2)
50
+
51
+ end
52
+ rescue
53
+ count+=1
54
+ sleep(2)
55
+
56
+
57
+ end
58
+ end
59
+ if tempssh
60
+ tempssh.close
61
+ tempssh.unlink
62
+ end
63
+ return false
64
+ rescue => e
65
+
66
+ puts e
67
+ end
68
+ end
69
+
70
+
71
+
72
+ def exec_command(command)
73
+ exec_command = "sudo -i -u #{@user} cnvrg exec_container #{@container} \"#{command}\" "
74
+ return @ssh.exec!(exec_command)
75
+ end
76
+
77
+
78
+ def close_ssh()
79
+
80
+
81
+ begin
82
+
83
+ @ssh.close
84
+ rescue => e
85
+
86
+ end
87
+
88
+
89
+ end
90
+ end
91
+
92
+
93
+
94
+ end
@@ -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
@@ -0,0 +1,165 @@
1
+ module Cnvrg
2
+ class Task
3
+ attr_accessor :title, :path, :source
4
+ def initialize(project_path, path: nil, content: {})
5
+ @path = path
6
+ @content = content
7
+ @source = 'flow' if @content.present?
8
+ @source = 'file' if @path.present?
9
+ @project = Cnvrg::Project.new(project_path)
10
+ @project_path = project_path
11
+ #generic
12
+ @type = nil #type can be exec, data, library, deploy
13
+ @compute = 'medium'
14
+ @title = nil
15
+ @uid = nil
16
+ @params = {}
17
+
18
+ #exec
19
+ @cmd = nil
20
+ @params_path = nil
21
+
22
+ #library
23
+ @library = nil
24
+
25
+ #dataset
26
+ @dataset = nil
27
+ @query = nil
28
+
29
+ #deploy
30
+ @function = nil
31
+
32
+
33
+ @base_resource = @project.base_resource + "/tasks"
34
+
35
+ self.reload_task
36
+ end
37
+
38
+ def save
39
+ path = @path || gen_path
40
+ File.open(path, 'w'){|f| f.write(get_content.to_yaml)}
41
+ end
42
+
43
+ def reload_task
44
+ task_raw = get_content
45
+ @title = task_raw[:title]
46
+ @type = task_raw[:type]
47
+ @uid = task_raw[:uid]
48
+ @title = task_raw[:title] || @uid
49
+ @compute = task_raw[:compute] || @compute
50
+
51
+ case @type
52
+ when 'exec'
53
+ @cmd = task_raw[:cmd]
54
+ init_params(task_raw)
55
+ when 'library'
56
+ @library = task_raw[:library]
57
+ init_params(task_raw)
58
+ when 'data'
59
+ @dataset = task_raw[:dataset]
60
+ @query = task_raw[:query]
61
+ when 'deploy'
62
+ @cmd = task_raw[:cmd]
63
+ @function = task_raw[:function]
64
+ else
65
+ error("Cant parse task of type #{@type}")
66
+ end
67
+ end
68
+
69
+ def verify_task
70
+ case @type
71
+ when 'exec'
72
+ verify_exec
73
+ when 'data'
74
+ verify_data
75
+ when 'deploy'
76
+ verify_deploy
77
+ when 'library'
78
+ verify_library
79
+ else
80
+ error("Cant parse task of type #{@type}")
81
+ end
82
+ end
83
+
84
+
85
+ def to_api
86
+ get_content.merge(params: @params)
87
+ end
88
+
89
+ def run
90
+ verify_task
91
+ if @type == 'data'
92
+ raise StandardError.new("Data Tasks are not runnable")
93
+ end
94
+ resp = Cnvrg::API.request(@base_resource, "POST", {task: to_api})
95
+ Cnvrg::CLI.is_response_success(resp, true)
96
+ Cnvrg::Helpers.remote_url + resp['result']['url']
97
+ end
98
+
99
+ private
100
+ def verify_compute
101
+ unless @project.check_machine(@compute)
102
+ raise StandardError.new("Cant find #{@compute} machine in project.")
103
+ end
104
+ end
105
+
106
+ def init_params(task_raw)
107
+ @params_path = task_raw[:params_path].presence
108
+ @params = task_raw[:params] || @params
109
+ if @params_path.present?
110
+ @hyper = Cnvrg::Hyper.new(@project_path, @params_path)
111
+ @params = @hyper.resolve_params
112
+ end
113
+ end
114
+
115
+ def verify_exec
116
+ if @cmd.blank?
117
+ error("Cant find command")
118
+ end
119
+ verify_compute
120
+ end
121
+
122
+ def verify_data
123
+ if @dataset.blank?
124
+ error("Cant find dataset slug")
125
+ end
126
+ end
127
+
128
+ def verify_deploy
129
+ error("Cant find command") if @cmd.blank?
130
+ error("Cant find function") if @function.blank?
131
+ verify_compute
132
+ end
133
+
134
+ def verify_library
135
+ error("Cant find library") if @library.blank?
136
+ end
137
+
138
+ def get_content
139
+ return @content if @source == 'flow'
140
+ unless File.exists? @path
141
+ raise StandardError.new("Cant find task in #{@path}")
142
+ end
143
+ YAML.load_file(@path)
144
+ end
145
+
146
+ def gen_path
147
+ @title ||= "#{@type.capitalize}Task"
148
+ unless File.exists? @title
149
+ @path = "#{@title}.task.yaml"
150
+ return @path
151
+ end
152
+ i = 0
153
+ while File.exists? "#{@title}_#{i}.task.yaml"
154
+ i += 1
155
+ end
156
+ @path = "#{@title}.task.yaml"
157
+ return @path
158
+ end
159
+
160
+ def error(msg)
161
+ raise StandardError.new("task: #{@uid} - #{msg}")
162
+ end
163
+
164
+ end
165
+ end