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,53 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            module Cnvrg
         
     | 
| 
      
 3 
     | 
    
         
            +
              module Downloader
         
     | 
| 
      
 4 
     | 
    
         
            +
                OLD_SERVER_VERSION_MESSAGE = "Your server version is not relevant for this cli version please contact support for further help."
         
     | 
| 
      
 5 
     | 
    
         
            +
                attr_accessor :bucket, :client
         
     | 
| 
      
 6 
     | 
    
         
            +
                class Client
         
     | 
| 
      
 7 
     | 
    
         
            +
                  def initialize(params)
         
     | 
| 
      
 8 
     | 
    
         
            +
                    @key = ''
         
     | 
| 
      
 9 
     | 
    
         
            +
                    @iv = ''
         
     | 
| 
      
 10 
     | 
    
         
            +
                    @client = ''
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @bucket = ''
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def extract_key_iv(sts_path)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    sts = open(sts_path).read rescue nil
         
     | 
| 
      
 16 
     | 
    
         
            +
                    raise StandardError.new("Cant open sts") if sts.blank?
         
     | 
| 
      
 17 
     | 
    
         
            +
                    sts.split("\n")
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  def download(storage_path, local_path)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    ### need to be implemented..
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  def upload(storage_path, local_path)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    ### need to be implemented..
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  def mkdir(path, recursive: false)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    recursive ? FileUtils.mkdir_p(path) : FileUtils.mkdir(path)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  def prepare_download(local_path)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    mkdir(File.dirname(local_path), recursive: true)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  def decrypt(str)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    Cnvrg::Helpers.decrypt(@key, @iv, str)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  def self.factory(params)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    params = params.as_json
         
     | 
| 
      
 42 
     | 
    
         
            +
                    case params["storage"]
         
     | 
| 
      
 43 
     | 
    
         
            +
                    when 's3', 'minio'
         
     | 
| 
      
 44 
     | 
    
         
            +
                      return Cnvrg::Downloader::Clients::S3Client.new(sts_path: params["path_sts"], access_key: params["sts_a"], secret: params["sts_s"], session_token: params["sts_st"], region: params["region"], bucket: params["bucket"], encryption: params["encryption"], endpoint: params["endpoint"], storage: params["storage"])
         
     | 
| 
      
 45 
     | 
    
         
            +
                    when 'azure'
         
     | 
| 
      
 46 
     | 
    
         
            +
                      return Cnvrg::Downloader::Clients::AzureDownloader.new(params)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    when 'gcp'
         
     | 
| 
      
 48 
     | 
    
         
            +
                      return Cnvrg::Downloader::Clients::GcpClient.new(project_id: params["project_id"], credentials: params["credentials"], bucket_name: params["bucket_name"], sts: params["sts"])
         
     | 
| 
      
 49 
     | 
    
         
            +
                    end
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Cnvrg
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Downloader
         
     | 
| 
      
 3 
     | 
    
         
            +
                module Clients
         
     | 
| 
      
 4 
     | 
    
         
            +
                  class AzureClient < Client
         
     | 
| 
      
 5 
     | 
    
         
            +
                    def initialize(storage: nil, account_name: nil, access_key: nil, container: nil, sts_path: nil)
         
     | 
| 
      
 6 
     | 
    
         
            +
                      @key, @iv = extract_key_iv(sts_path)
         
     | 
| 
      
 7 
     | 
    
         
            +
                      @account_name = Cnvrg::Helpers.decrypt(@key, @iv, account_name)
         
     | 
| 
      
 8 
     | 
    
         
            +
                      @access_key = Cnvrg::Helpers.decrypt(@key, @iv, access_key)
         
     | 
| 
      
 9 
     | 
    
         
            +
                      @container = Cnvrg::Helpers.decrypt(@key, @iv, container)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    def download(storage_path, local_path)
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                    end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                    def upload(storage_path, local_path)
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,46 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "google/cloud/storage"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Cnvrg
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Downloader
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Clients
         
     | 
| 
      
 6 
     | 
    
         
            +
                  class GcpClient < Client
         
     | 
| 
      
 7 
     | 
    
         
            +
                    def initialize(project_id: nil, credentials: nil, bucket_name: nil, sts: nil)
         
     | 
| 
      
 8 
     | 
    
         
            +
                      @key, @iv = extract_key_iv(sts)
         
     | 
| 
      
 9 
     | 
    
         
            +
                      @project_id = Cnvrg::Helpers.decrypt(@key, @iv, project_id)
         
     | 
| 
      
 10 
     | 
    
         
            +
                      @credentials_path = Cnvrg::Helpers.decrypt(@key, @iv, credentials)
         
     | 
| 
      
 11 
     | 
    
         
            +
                      @tempfile = nil
         
     | 
| 
      
 12 
     | 
    
         
            +
                      @bucket_name = Cnvrg::Helpers.decrypt(@key, @iv, bucket_name)
         
     | 
| 
      
 13 
     | 
    
         
            +
                      init_gcp_credentials
         
     | 
| 
      
 14 
     | 
    
         
            +
                      @storage = Google::Cloud::Storage.new(project_id: @project_id, credentials: @credentials)
         
     | 
| 
      
 15 
     | 
    
         
            +
                      @bucket = @storage.bucket(@bucket_name)
         
     | 
| 
      
 16 
     | 
    
         
            +
                      @bucket.name
         
     | 
| 
      
 17 
     | 
    
         
            +
                    rescue => e
         
     | 
| 
      
 18 
     | 
    
         
            +
                      Cnvrg::Logger.log_error(e)
         
     | 
| 
      
 19 
     | 
    
         
            +
                      Cnvrg::Logger.log_info("Tried to init gcp client without success.")
         
     | 
| 
      
 20 
     | 
    
         
            +
                      Cnvrg::CLI.log_message("Cannot init client. please contact support to check your bucket credentials.")
         
     | 
| 
      
 21 
     | 
    
         
            +
                      exit(1)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                    def init_gcp_credentials
         
     | 
| 
      
 25 
     | 
    
         
            +
                      t = Tempfile.new
         
     | 
| 
      
 26 
     | 
    
         
            +
                      f = open(@credentials_path).read
         
     | 
| 
      
 27 
     | 
    
         
            +
                      t.binmode
         
     | 
| 
      
 28 
     | 
    
         
            +
                      t.write(f)
         
     | 
| 
      
 29 
     | 
    
         
            +
                      t.rewind
         
     | 
| 
      
 30 
     | 
    
         
            +
                      @credentials = t.path
         
     | 
| 
      
 31 
     | 
    
         
            +
                      @tempfile = t
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                    def download(storage_path, local_path)
         
     | 
| 
      
 35 
     | 
    
         
            +
                      prepare_download(local_path)
         
     | 
| 
      
 36 
     | 
    
         
            +
                      file = @bucket.file(decrypt(storage_path))
         
     | 
| 
      
 37 
     | 
    
         
            +
                      file.download local_path
         
     | 
| 
      
 38 
     | 
    
         
            +
                    end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                    def upload(storage_path, local_path)
         
     | 
| 
      
 41 
     | 
    
         
            +
                      @bucket.create_file(local_path, storage_path)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    end
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
              end
         
     | 
| 
      
 46 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,51 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Cnvrg
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Downloader
         
     | 
| 
      
 3 
     | 
    
         
            +
                module Clients
         
     | 
| 
      
 4 
     | 
    
         
            +
                  class S3Client < Client
         
     | 
| 
      
 5 
     | 
    
         
            +
                    def initialize(sts_path: nil, access_key: nil, secret: nil, session_token: nil, region: nil, bucket: nil, encryption: nil, endpoint: nil, storage: nil)
         
     | 
| 
      
 6 
     | 
    
         
            +
                      @key, @iv = extract_key_iv(sts_path)
         
     | 
| 
      
 7 
     | 
    
         
            +
                      @access_key = Cnvrg::Helpers.decrypt(@key, @iv, access_key)
         
     | 
| 
      
 8 
     | 
    
         
            +
                      @secret = Cnvrg::Helpers.decrypt(@key, @iv, secret)
         
     | 
| 
      
 9 
     | 
    
         
            +
                      @session_token = Cnvrg::Helpers.decrypt(@key, @iv, session_token)
         
     | 
| 
      
 10 
     | 
    
         
            +
                      @region = Cnvrg::Helpers.decrypt(@key, @iv, region)
         
     | 
| 
      
 11 
     | 
    
         
            +
                      @bucket_name = Cnvrg::Helpers.decrypt(@key, @iv, bucket)
         
     | 
| 
      
 12 
     | 
    
         
            +
                      @endpoint = Cnvrg::Helpers.decrypt(@key, @iv, endpoint)
         
     | 
| 
      
 13 
     | 
    
         
            +
                      options = {
         
     | 
| 
      
 14 
     | 
    
         
            +
                          :access_key_id => @access_key,
         
     | 
| 
      
 15 
     | 
    
         
            +
                          :secret_access_key => @secret,
         
     | 
| 
      
 16 
     | 
    
         
            +
                          :session_token => @session_token,
         
     | 
| 
      
 17 
     | 
    
         
            +
                          :region => @region,
         
     | 
| 
      
 18 
     | 
    
         
            +
                          :http_open_timeout => 60, :retry_limit => 20
         
     | 
| 
      
 19 
     | 
    
         
            +
                      }
         
     | 
| 
      
 20 
     | 
    
         
            +
                      if storage == 'minio'
         
     | 
| 
      
 21 
     | 
    
         
            +
                        options[:endpoint] = @endpoint
         
     | 
| 
      
 22 
     | 
    
         
            +
                      end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                      @client = Aws::S3::Client.new(options)
         
     | 
| 
      
 25 
     | 
    
         
            +
                      @bucket = Aws::S3::Resource.new(client: @client).bucket(@bucket_name)
         
     | 
| 
      
 26 
     | 
    
         
            +
                      @upload_options = {:use_accelerate_endpoint => storage == 's3'}
         
     | 
| 
      
 27 
     | 
    
         
            +
                      if encryption.present?
         
     | 
| 
      
 28 
     | 
    
         
            +
                        @upload_options[:server_side_encryption] = encryption
         
     | 
| 
      
 29 
     | 
    
         
            +
                      end
         
     | 
| 
      
 30 
     | 
    
         
            +
                    end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                    def download(storage_path, local_path)
         
     | 
| 
      
 33 
     | 
    
         
            +
                      prepare_download(local_path)
         
     | 
| 
      
 34 
     | 
    
         
            +
                      storage_path = Cnvrg::Helpers.decrypt(@key, @iv, storage_path)
         
     | 
| 
      
 35 
     | 
    
         
            +
                      File.open(local_path, 'w+') do |file|
         
     | 
| 
      
 36 
     | 
    
         
            +
                        resp = @client.get_object({bucket: @bucket_name,
         
     | 
| 
      
 37 
     | 
    
         
            +
                                            key: storage_path}, target: file)
         
     | 
| 
      
 38 
     | 
    
         
            +
                      end
         
     | 
| 
      
 39 
     | 
    
         
            +
                      resp
         
     | 
| 
      
 40 
     | 
    
         
            +
                    end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                    def upload(storage_path, local_path)
         
     | 
| 
      
 43 
     | 
    
         
            +
                      ### storage path is the path inside s3 (after the bucket)
         
     | 
| 
      
 44 
     | 
    
         
            +
                      # local path is fullpath for the file /home/ubuntu/user.../hazilim.py
         
     | 
| 
      
 45 
     | 
    
         
            +
                      o = @bucket.object(storage_path)
         
     | 
| 
      
 46 
     | 
    
         
            +
                      o.upload_file(local_path, @upload_options)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    end
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/cnvrg/files.rb
    CHANGED
    
    | 
         @@ -18,6 +18,10 @@ module Cnvrg 
     | 
|
| 
       18 
18 
     | 
    
         
             
                  @base_resource = "users/#{owner}/projects/#{project_slug}/"
         
     | 
| 
       19 
19 
     | 
    
         
             
                  @project_home = project_home.presence || Cnvrg::CLI.get_project_home
         
     | 
| 
       20 
20 
     | 
    
         
             
                  @project = project
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @client = nil
         
     | 
| 
      
 22 
     | 
    
         
            +
                  if @project.present?
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @client = @project.get_storage_client
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
       21 
25 
     | 
    
         
             
                  @progressbar = progressbar
         
     | 
| 
       22 
26 
     | 
    
         
             
                  @custom_progess = false
         
     | 
| 
       23 
27 
     | 
    
         
             
                  @cli = cli
         
     | 
| 
         @@ -84,16 +88,10 @@ module Cnvrg 
     | 
|
| 
       84 
88 
     | 
    
         
             
                  # resolve bucket
         
     | 
| 
       85 
89 
     | 
    
         
             
                  res = resp['result']
         
     | 
| 
       86 
90 
     | 
    
         
             
                  files = res['files']
         
     | 
| 
       87 
     | 
    
         
            -
                  props = Cnvrg::Helpers.get_s3_props(res)
         
     | 
| 
       88 
     | 
    
         
            -
                  client = props[:client]
         
     | 
| 
       89 
     | 
    
         
            -
                  bucket = props[:bucket]
         
     | 
| 
       90 
     | 
    
         
            -
                  upload_options = props[:upload_options]
         
     | 
| 
       91 
     | 
    
         
            -
                  s3_bucket = Aws::S3::Resource.new(client: client).bucket(bucket)
         
     | 
| 
       92 
     | 
    
         
            -
             
     | 
| 
       93 
91 
     | 
    
         
             
                  #upload files
         
     | 
| 
       94 
92 
     | 
    
         
             
                  # files.keys.map do |file|
         
     | 
| 
       95 
93 
     | 
    
         
             
                  Parallel.map(files.keys, self.get_upload_options) do |file|
         
     | 
| 
       96 
     | 
    
         
            -
                    resp = Cnvrg::Helpers.try_until_success{self.upload_single_file(files[file].merge(files_list[file]) 
     | 
| 
      
 94 
     | 
    
         
            +
                    resp = Cnvrg::Helpers.try_until_success{self.upload_single_file(files[file].merge(files_list[file]))}
         
     | 
| 
       97 
95 
     | 
    
         
             
                    raise SignalException.new("Cant upload #{file}") unless resp
         
     | 
| 
       98 
96 
     | 
    
         
             
                    progress.progress += 1 if progress.present?
         
     | 
| 
       99 
97 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -134,16 +132,10 @@ module Cnvrg 
     | 
|
| 
       134 
132 
     | 
    
         
             
                  end
         
     | 
| 
       135 
133 
     | 
    
         
             
                end
         
     | 
| 
       136 
134 
     | 
    
         | 
| 
       137 
     | 
    
         
            -
                def upload_single_file(file 
     | 
| 
      
 135 
     | 
    
         
            +
                def upload_single_file(file)
         
     | 
| 
       138 
136 
     | 
    
         
             
                  path = file['path']
         
     | 
| 
       139 
137 
     | 
    
         
             
                  absolute_path = file[:absolute_path]
         
     | 
| 
       140 
     | 
    
         
            -
             
     | 
| 
       141 
     | 
    
         
            -
                  resp = bucket.object(path).
         
     | 
| 
       142 
     | 
    
         
            -
                      upload_file(absolute_path, options)
         
     | 
| 
       143 
     | 
    
         
            -
                  unless resp
         
     | 
| 
       144 
     | 
    
         
            -
                    raise SignalException.new("Cant upload #{absolute_path}")
         
     | 
| 
       145 
     | 
    
         
            -
                  end
         
     | 
| 
       146 
     | 
    
         
            -
                  resp
         
     | 
| 
      
 138 
     | 
    
         
            +
                  @client.upload(path, absolute_path)
         
     | 
| 
       147 
139 
     | 
    
         
             
                end
         
     | 
| 
       148 
140 
     | 
    
         | 
| 
       149 
141 
     | 
    
         
             
                def parse_file(file)
         
     | 
| 
         @@ -192,15 +184,9 @@ module Cnvrg 
     | 
|
| 
       192 
184 
     | 
    
         
             
                  upload_resp = Cnvrg::API.request("/users/#{@owner}/" + "upload_cli_log", 'POST_FILE', {absolute_path: absolute_path, relative_path: relative_path,
         
     | 
| 
       193 
185 
     | 
    
         
             
                                                                                                         file_name: file_name, log_date: log_date,
         
     | 
| 
       194 
186 
     | 
    
         
             
                                                                                                         file_size: file_size, file_content_type: content_type})
         
     | 
| 
       195 
     | 
    
         
            -
                   
     | 
| 
       196 
     | 
    
         
            -
             
     | 
| 
       197 
     | 
    
         
            -
             
     | 
| 
       198 
     | 
    
         
            -
                  end
         
     | 
| 
       199 
     | 
    
         
            -
                  if s3_res
         
     | 
| 
       200 
     | 
    
         
            -
                    return true
         
     | 
| 
       201 
     | 
    
         
            -
                  end
         
     | 
| 
       202 
     | 
    
         
            -
                  return false
         
     | 
| 
       203 
     | 
    
         
            -
             
     | 
| 
      
 187 
     | 
    
         
            +
                  path, client = upload_resp["path"], upload_resp["client"]
         
     | 
| 
      
 188 
     | 
    
         
            +
                  @client = Cnvrg::Downloader::Client.factory(client)
         
     | 
| 
      
 189 
     | 
    
         
            +
                  @client.upload(path, absolute_path)
         
     | 
| 
       204 
190 
     | 
    
         
             
                end
         
     | 
| 
       205 
191 
     | 
    
         | 
| 
       206 
192 
     | 
    
         
             
                def upload_exec_file(absolute_path, image_name, commit_id)
         
     | 
| 
         @@ -711,7 +697,7 @@ module Cnvrg 
     | 
|
| 
       711 
697 
     | 
    
         | 
| 
       712 
698 
     | 
    
         
             
                def download_multpile_files_s3(files, project_home, postfix: '', progress: nil)
         
     | 
| 
       713 
699 
     | 
    
         
             
                  begin
         
     | 
| 
       714 
     | 
    
         
            -
                    props =  
     | 
| 
      
 700 
     | 
    
         
            +
                    props = {}
         
     | 
| 
       715 
701 
     | 
    
         
             
                    client = props[:client]
         
     | 
| 
       716 
702 
     | 
    
         
             
                    iv = props[:iv]
         
     | 
| 
       717 
703 
     | 
    
         
             
                    key = props[:key]
         
     | 
| 
         @@ -739,20 +725,11 @@ module Cnvrg 
     | 
|
| 
       739 
725 
     | 
    
         
             
                          if not File.exists?(project_home+"/"+File.dirname(file_path))
         
     | 
| 
       740 
726 
     | 
    
         
             
                            FileUtils.makedirs(project_home+"/"+File.dirname(file_path))
         
     | 
| 
       741 
727 
     | 
    
         
             
                          end
         
     | 
| 
       742 
     | 
    
         
            -
             
     | 
| 
       743 
     | 
    
         
            -
                           
     | 
| 
       744 
     | 
    
         
            -
                           
     | 
| 
       745 
     | 
    
         
            -
                          Cnvrg::Helpers.try_until_success(tries: 10) {
         
     | 
| 
       746 
     | 
    
         
            -
                            File.open(project_home+"/"+file_path, 'w+') do |file|
         
     | 
| 
       747 
     | 
    
         
            -
                              resp = client.get_object({bucket:bucket,
         
     | 
| 
       748 
     | 
    
         
            -
                                                      key:file_key}, target: file)
         
     | 
| 
       749 
     | 
    
         
            -
                            end
         
     | 
| 
       750 
     | 
    
         
            -
                          }
         
     | 
| 
      
 728 
     | 
    
         
            +
                          local_path = project_home+"/"+file_path
         
     | 
| 
      
 729 
     | 
    
         
            +
                          storage_path = f["path"]
         
     | 
| 
      
 730 
     | 
    
         
            +
                          @client.download(storage_path, local_path)
         
     | 
| 
       751 
731 
     | 
    
         
             
                          progress.progress += 1 if progress.present?
         
     | 
| 
       752 
732 
     | 
    
         
             
                          download_succ_count += 1
         
     | 
| 
       753 
     | 
    
         
            -
             
     | 
| 
       754 
     | 
    
         
            -
             
     | 
| 
       755 
     | 
    
         
            -
             
     | 
| 
       756 
733 
     | 
    
         
             
                        rescue => e
         
     | 
| 
       757 
734 
     | 
    
         
             
                          return Cnvrg::Result.new(false,"Could not create file: #{file_path}", e.message, e.backtrace)
         
     | 
| 
       758 
735 
     | 
    
         
             
                          raise Parallel::Kill
         
     | 
| 
         @@ -913,12 +890,8 @@ module Cnvrg 
     | 
|
| 
       913 
890 
     | 
    
         
             
                end
         
     | 
| 
       914 
891 
     | 
    
         | 
| 
       915 
892 
     | 
    
         
             
                def download_file(file_path: '', key: '', iv: '', bucket: '', path: '', client: nil)
         
     | 
| 
       916 
     | 
    
         
            -
                   
     | 
| 
       917 
     | 
    
         
            -
                   
     | 
| 
       918 
     | 
    
         
            -
                  File.open(@project_home+"/"+file_path, 'w+') do |file|
         
     | 
| 
       919 
     | 
    
         
            -
                    resp = client.get_object({bucket:bucket,
         
     | 
| 
       920 
     | 
    
         
            -
                                              key:file_key}, target: file)
         
     | 
| 
       921 
     | 
    
         
            -
                  end
         
     | 
| 
      
 893 
     | 
    
         
            +
                  local_path = @project_home+"/"+file_path
         
     | 
| 
      
 894 
     | 
    
         
            +
                  @client.download(path, local_path)
         
     | 
| 
       922 
895 
     | 
    
         
             
                end
         
     | 
| 
       923 
896 
     | 
    
         | 
| 
       924 
897 
     | 
    
         
             
                def delete(file)
         
     | 
| 
         @@ -936,7 +909,7 @@ module Cnvrg 
     | 
|
| 
       936 
909 
     | 
    
         
             
                def handle_compare_idx(compared, resolver: {})
         
     | 
| 
       937 
910 
     | 
    
         
             
                  begin
         
     | 
| 
       938 
911 
     | 
    
         
             
                    all_files = compared.values.flatten.uniq
         
     | 
| 
       939 
     | 
    
         
            -
                    props =  
     | 
| 
      
 912 
     | 
    
         
            +
                    props = {}
         
     | 
| 
       940 
913 
     | 
    
         
             
                    files = resolver['keys'].map{|f| [f['name'], f]}.to_h
         
     | 
| 
       941 
914 
     | 
    
         
             
                    client = props[:client]
         
     | 
| 
       942 
915 
     | 
    
         
             
                    iv = props[:iv]
         
     | 
| 
         @@ -0,0 +1,171 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Cnvrg::Helpers::Executer
         
     | 
| 
      
 2 
     | 
    
         
            +
              def initialize(project: nil, job_type: nil, job_id: nil)
         
     | 
| 
      
 3 
     | 
    
         
            +
                @project = project
         
     | 
| 
      
 4 
     | 
    
         
            +
                @job_type = job_type
         
     | 
| 
      
 5 
     | 
    
         
            +
                @job_id = job_id
         
     | 
| 
      
 6 
     | 
    
         
            +
                if job_id.blank?
         
     | 
| 
      
 7 
     | 
    
         
            +
                  Cnvrg::CLI.log_message("Cant find job, exiting.", 'red')
         
     | 
| 
      
 8 
     | 
    
         
            +
                  exit(1)
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              def fetch_commands(block: nil, key: nil)
         
     | 
| 
      
 13 
     | 
    
         
            +
                resp = Cnvrg::API.request("#{base_url}/commands", "GET", {block: block})
         
     | 
| 
      
 14 
     | 
    
         
            +
                commands = decrypt_commands(resp["commands"], resp["key"], resp["iv"])
         
     | 
| 
      
 15 
     | 
    
         
            +
                commands.map{|k| k.with_indifferent_access}
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              def decrypt_commands(text,key,iv)
         
     | 
| 
      
 19 
     | 
    
         
            +
                text, key, iv = [text,key,iv].map{|x| x.unpack('m')[0]}
         
     | 
| 
      
 20 
     | 
    
         
            +
                decipher = OpenSSL::Cipher::AES256.new :CBC
         
     | 
| 
      
 21 
     | 
    
         
            +
                decipher.decrypt
         
     | 
| 
      
 22 
     | 
    
         
            +
                decipher.key = key
         
     | 
| 
      
 23 
     | 
    
         
            +
                decipher.iv = iv
         
     | 
| 
      
 24 
     | 
    
         
            +
                commands = decipher.update(text) + decipher.final
         
     | 
| 
      
 25 
     | 
    
         
            +
                JSON.parse(commands)
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              def execute(cmd)
         
     | 
| 
      
 29 
     | 
    
         
            +
                ## execute the command for running
         
     | 
| 
      
 30 
     | 
    
         
            +
                # cmd will have to following fields
         
     | 
| 
      
 31 
     | 
    
         
            +
                #
         
     | 
| 
      
 32 
     | 
    
         
            +
                # :command => the command to execute
         
     | 
| 
      
 33 
     | 
    
         
            +
                # :type => the command type, 'notify' or nil
         
     | 
| 
      
 34 
     | 
    
         
            +
                # :timeout => the timeout for the command in seconds (default is 60 hours)
         
     | 
| 
      
 35 
     | 
    
         
            +
                # :retries => integer, default 1
         
     | 
| 
      
 36 
     | 
    
         
            +
                #
         
     | 
| 
      
 37 
     | 
    
         
            +
                # when type == 'file_exists'
         
     | 
| 
      
 38 
     | 
    
         
            +
                #  'file' => string => file to check (fullpath)
         
     | 
| 
      
 39 
     | 
    
         
            +
                #  'exists_commands' => list of commands in case file exists
         
     | 
| 
      
 40 
     | 
    
         
            +
                #   'non_exists_commands' => list of commands in case file doesnt exists
         
     | 
| 
      
 41 
     | 
    
         
            +
                # when type == 'notify'
         
     | 
| 
      
 42 
     | 
    
         
            +
                # :before_execute_log => log to be logged before execution
         
     | 
| 
      
 43 
     | 
    
         
            +
                # :logs => boolean => add the execution logs to the job logs
         
     | 
| 
      
 44 
     | 
    
         
            +
                # :title => command title, can replace the on_error, on_success fields
         
     | 
| 
      
 45 
     | 
    
         
            +
                # :on_error_log => log to be logged on exit_code != 0
         
     | 
| 
      
 46 
     | 
    
         
            +
                # :on_success_log => log to be logged on exit_code == 0
         
     | 
| 
      
 47 
     | 
    
         
            +
                #
         
     | 
| 
      
 48 
     | 
    
         
            +
                retries = cmd[:retries] || 1
         
     | 
| 
      
 49 
     | 
    
         
            +
                resp = []
         
     | 
| 
      
 50 
     | 
    
         
            +
                retries.times.each do
         
     | 
| 
      
 51 
     | 
    
         
            +
                  resp = execute_helper(cmd)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  exit_status, _, _, _, _ = resp
         
     | 
| 
      
 53 
     | 
    
         
            +
                  return resp if exit_status == 0
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
                return resp
         
     | 
| 
      
 56 
     | 
    
         
            +
              end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
              def execute_cmds(cmds)
         
     | 
| 
      
 59 
     | 
    
         
            +
                cmds.each do |command|
         
     | 
| 
      
 60 
     | 
    
         
            +
                  puts "===================="
         
     | 
| 
      
 61 
     | 
    
         
            +
                  puts "Execute #{command[:command]}"
         
     | 
| 
      
 62 
     | 
    
         
            +
                  execute(command)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  puts "===================="
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
              private
         
     | 
| 
      
 69 
     | 
    
         
            +
              def execute_helper(cmd)
         
     | 
| 
      
 70 
     | 
    
         
            +
                case cmd[:type]
         
     | 
| 
      
 71 
     | 
    
         
            +
                when 'notify'
         
     | 
| 
      
 72 
     | 
    
         
            +
                  return run_and_notify(cmd)
         
     | 
| 
      
 73 
     | 
    
         
            +
                when 'file_exists'
         
     | 
| 
      
 74 
     | 
    
         
            +
                  if File.exists? cmd[:file]
         
     | 
| 
      
 75 
     | 
    
         
            +
                    return execute_cmds(cmd[:exists_commands]) if cmd[:exists_commands].present?
         
     | 
| 
      
 76 
     | 
    
         
            +
                  else
         
     | 
| 
      
 77 
     | 
    
         
            +
                    return execute_cmds(cmd[:non_exists_commands]) if cmd[:non_exists_commands].present?
         
     | 
| 
      
 78 
     | 
    
         
            +
                  end
         
     | 
| 
      
 79 
     | 
    
         
            +
                when 'create_file'
         
     | 
| 
      
 80 
     | 
    
         
            +
                  return create_file(cmd)
         
     | 
| 
      
 81 
     | 
    
         
            +
                else
         
     | 
| 
      
 82 
     | 
    
         
            +
                  return regular_command(cmd)
         
     | 
| 
      
 83 
     | 
    
         
            +
                end
         
     | 
| 
      
 84 
     | 
    
         
            +
              end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
              def run_and_notify(cmd)
         
     | 
| 
      
 87 
     | 
    
         
            +
                with_logs = cmd[:logs]
         
     | 
| 
      
 88 
     | 
    
         
            +
                cmd = init_cmd_logs(cmd)
         
     | 
| 
      
 89 
     | 
    
         
            +
                job_log(cmd[:before_execute_log]) if cmd[:before_execute_log].present?
         
     | 
| 
      
 90 
     | 
    
         
            +
                exit_status, output, errors, start_time, end_time = regular_command(cmd)
         
     | 
| 
      
 91 
     | 
    
         
            +
                logs = []
         
     | 
| 
      
 92 
     | 
    
         
            +
                if exit_status == 0
         
     | 
| 
      
 93 
     | 
    
         
            +
                  logs = output.map{|log| log[:logs]} if with_logs
         
     | 
| 
      
 94 
     | 
    
         
            +
                  job_log(logs + cmd[:on_success_log])
         
     | 
| 
      
 95 
     | 
    
         
            +
                else
         
     | 
| 
      
 96 
     | 
    
         
            +
                  logs = output + errors
         
     | 
| 
      
 97 
     | 
    
         
            +
                  logs = logs.sort_by{|x| x[:timestamp]}.map{|x| x[:logs]} if with_logs
         
     | 
| 
      
 98 
     | 
    
         
            +
                  job_log(logs + cmd[:on_error_log], level: 'error')
         
     | 
| 
      
 99 
     | 
    
         
            +
                end
         
     | 
| 
      
 100 
     | 
    
         
            +
                return [exit_status, output, errors, start_time, end_time]
         
     | 
| 
      
 101 
     | 
    
         
            +
              end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
              def merge_log_block(logs)
         
     | 
| 
      
 104 
     | 
    
         
            +
                logs.group_by {|log| log[:timestamp].to_s}
         
     | 
| 
      
 105 
     | 
    
         
            +
                    .map {|ts, logz| {timestamp: ts, logs: logz.map {|l| l[:log]}.join("\n")}}
         
     | 
| 
      
 106 
     | 
    
         
            +
              end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
              def regular_command(cmd = {})
         
     | 
| 
      
 110 
     | 
    
         
            +
                errors = []
         
     | 
| 
      
 111 
     | 
    
         
            +
                output = []
         
     | 
| 
      
 112 
     | 
    
         
            +
                start_time = Time.now
         
     | 
| 
      
 113 
     | 
    
         
            +
                timeout = cmd[:timeout] || 60*60*60
         
     | 
| 
      
 114 
     | 
    
         
            +
                t = Thread.new do
         
     | 
| 
      
 115 
     | 
    
         
            +
                  PTY.spawn(cmd[:command]) do |stdout, stdin, pid, stderr|
         
     | 
| 
      
 116 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 117 
     | 
    
         
            +
                      stdout.each do |line|
         
     | 
| 
      
 118 
     | 
    
         
            +
                        puts line
         
     | 
| 
      
 119 
     | 
    
         
            +
                        output << {log: line.strip, timestamp: Time.now}
         
     | 
| 
      
 120 
     | 
    
         
            +
                      end
         
     | 
| 
      
 121 
     | 
    
         
            +
                      if stderr.present?
         
     | 
| 
      
 122 
     | 
    
         
            +
                        stderr.each do |line|
         
     | 
| 
      
 123 
     | 
    
         
            +
                          errors << {log: line.strip, timestamp: Time.now}
         
     | 
| 
      
 124 
     | 
    
         
            +
                        end
         
     | 
| 
      
 125 
     | 
    
         
            +
                      end
         
     | 
| 
      
 126 
     | 
    
         
            +
                    rescue => e
         
     | 
| 
      
 127 
     | 
    
         
            +
                      errors << {log: e.message, timestamp: Time.now}
         
     | 
| 
      
 128 
     | 
    
         
            +
                    end
         
     | 
| 
      
 129 
     | 
    
         
            +
                    ::Process.wait pid
         
     | 
| 
      
 130 
     | 
    
         
            +
                  end
         
     | 
| 
      
 131 
     | 
    
         
            +
                end
         
     | 
| 
      
 132 
     | 
    
         
            +
                while t.status
         
     | 
| 
      
 133 
     | 
    
         
            +
                  if Time.now - start_time > timeout
         
     | 
| 
      
 134 
     | 
    
         
            +
                    puts "Kill thread because of timeout..."
         
     | 
| 
      
 135 
     | 
    
         
            +
                    errors << {log: "Timeout", timestamp: Time.now}
         
     | 
| 
      
 136 
     | 
    
         
            +
                    Thread.kill(t)
         
     | 
| 
      
 137 
     | 
    
         
            +
                  end
         
     | 
| 
      
 138 
     | 
    
         
            +
                  sleep 1
         
     | 
| 
      
 139 
     | 
    
         
            +
                end
         
     | 
| 
      
 140 
     | 
    
         
            +
                exit_status = $?.exitstatus
         
     | 
| 
      
 141 
     | 
    
         
            +
                end_time = Time.now
         
     | 
| 
      
 142 
     | 
    
         
            +
                [exit_status, merge_log_block(output), merge_log_block(errors), start_time, end_time]
         
     | 
| 
      
 143 
     | 
    
         
            +
              end
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
              def create_file(cmd)
         
     | 
| 
      
 146 
     | 
    
         
            +
                cmd = init_cmd_logs(cmd)
         
     | 
| 
      
 147 
     | 
    
         
            +
                File.open(cmd[:path], "w+"){|f| f.write(cmd[:content])}
         
     | 
| 
      
 148 
     | 
    
         
            +
              end
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
              def init_cmd_logs(cmd)
         
     | 
| 
      
 151 
     | 
    
         
            +
                if cmd[:title]
         
     | 
| 
      
 152 
     | 
    
         
            +
                  cmd[:before_execute_log] ||= ["Running #{cmd[:title]}"]
         
     | 
| 
      
 153 
     | 
    
         
            +
                  cmd[:on_error_log] ||= ["#{cmd[:title]} was failed during running"]
         
     | 
| 
      
 154 
     | 
    
         
            +
                  cmd[:on_success_log] ||= ["#{cmd[:title]} executed successfully"]
         
     | 
| 
      
 155 
     | 
    
         
            +
                end
         
     | 
| 
      
 156 
     | 
    
         
            +
                cmd[:on_success_log] ||= []
         
     | 
| 
      
 157 
     | 
    
         
            +
                cmd[:on_error_log] ||= []
         
     | 
| 
      
 158 
     | 
    
         
            +
                [:before_execute_log, :on_success_log, :on_error_log].each{|x| cmd[x] = [cmd[x]].flatten}
         
     | 
| 
      
 159 
     | 
    
         
            +
                cmd
         
     | 
| 
      
 160 
     | 
    
         
            +
              end
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
              def base_url
         
     | 
| 
      
 163 
     | 
    
         
            +
                "users/#{@project.owner}/projects/#{@project.slug}/jobs/#{@job_type.underscore}/#{@job_id}"
         
     | 
| 
      
 164 
     | 
    
         
            +
              end
         
     | 
| 
      
 165 
     | 
    
         
            +
             
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
              def job_log(logs, level: 'info', step: nil)
         
     | 
| 
      
 168 
     | 
    
         
            +
                @project.job_log(logs, level: level, step: step, job_type: @job_type, job_id: @job_id)
         
     | 
| 
      
 169 
     | 
    
         
            +
              end
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
            end
         
     |