class Singularity::Runner
Public Class Methods
new(script)
click to toggle source
# File lib/singularity.rb, line 81 def initialize(script) if !File.file?("mesos-deploy.yml") or !File.file?(".mescal.json") puts "Please do this command from a project directory (where mesos-deploy.yml and .mescal.json exist)" end @script = script # read .mescal.json for ssh command, image, release number, cpus, mem @configData = JSON.parse(ERB.new(open(File.join(Dir.pwd, ".mescal.json")).read).result(Request.new.get_binding)) @sshCmd = @configData['sshCmd'] @image = @configData['image'].split(':')[0] @release = @configData['image'].split(':')[1] # read mesos-deploy.yml for singularity url @mesosDeployConfig = YAML.load_file(File.join(Dir.pwd, "mesos-deploy.yml")) @uri = @mesosDeployConfig['singularity_url'] # create request/deploy json data @data = { 'command' => "/sbin/my_init", 'resources' => { 'memoryMb' => @configData['mem'], 'cpus' => @configData['cpus'], 'numPorts' => 1 }, 'env' => { 'APPLICATION_ENV' => "production" }, 'requestType' => "RUN_ONCE", 'containerInfo' => { 'type' => "DOCKER", 'docker' => { 'image' => @configData['image'], 'network' => "BRIDGE", 'portMappings' => [{ 'containerPortType' => "LITERAL", 'containerPort' => 22, 'hostPortType' => "FROM_OFFER", 'hostPort' => 0 }] } } } # either we typed 'singularity ssh' if @script == "ssh" @data['id'] = Dir.pwd.split('/').last + "_SSH" @data['command'] = "#{@sshCmd}" # or we passed a script/commands to 'singularity run' else # if we passed "runx", then skip use of /sbin/my_init if @script[0] == "runx" @data['arguments'] = [] # don't use "--" as first argument @data['command'] = @script[1] #remove "runx" from commands @script.shift @data['id'] = @script.join("-").tr('@/\*?% []#$', '_') @data['id'][0] = '' @script.shift # else join /sbin/my_init with your commands else @data['arguments'] = ["--"] @data['id'] = @script.join("-").tr('@/\*?% []#$', '_') @data['id'][0] = '' end @script.each { |i| @data['arguments'].push i } end end
Public Instance Methods
is_paused()
click to toggle source
# File lib/singularity.rb, line 147 def is_paused begin resp = RestClient.get "#{@uri}/api/requests/request/#{@data['id']}" JSON.parse(resp)['state'] == 'PAUSED' rescue print " Deploying request...".light_green false end end
runner()
click to toggle source
# File lib/singularity.rb, line 157 def runner begin if is_paused() puts " PAUSED, SKIPPING.".yellow return else # create or update the request RestClient.post "#{@uri}/api/requests", @data.to_json, :content_type => :json end # deploy the request @data['requestId'] = @data['id'] @data['id'] = "#{@release}.#{Time.now.to_i}" @deploy = { 'deploy' => @data, 'user' => `whoami`.chomp, 'unpauseOnSuccessfulDeploy' => false } RestClient.post "#{@uri}/api/deploys", @deploy.to_json, :content_type => :json puts " Deploy succeeded.".green # get active tasks until ours shows up so we can get IP/PORT begin @thisTask = '' @tasks = JSON.parse(RestClient.get "#{@uri}/api/tasks/active", :content_type => :json) @tasks.each do |entry| if entry['taskRequest']['request']['id'] == @data['requestId'] @thisTask = entry end end end until @thisTask != '' @ip = @thisTask['offer']['url']['address']['ip'] @port = @thisTask['mesosTask']['container']['docker']['portMappings'][0]['hostPort'] # SSH into the machine if @script == "ssh" # uses "begin end until" because "system" will keep returning "false" unless the command exits with success # this makes sure that the docker image has completely started and the SSH command succeeds where = Dir.pwd.split('/').last puts " Opening a shell to #{where}, please wait a moment...".light_blue begin end until system "ssh -o LogLevel=quiet -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@#{@ip} -p #{@port}" else puts " Deployed and running #{@data['command']} #{@data['arguments']}".light_green print " STDOUT".light_cyan print " and" print " STDERR".light_magenta puts ":" # output STDOUT / STDERR to shell @stdoutOffset = 0 @stderrOffset = 0 begin # get most recent task state # need to wait for "task_running" before we can ask for STDOUT/STDERR @taskState = JSON.parse(RestClient.get "#{@uri}/api/history/task/#{@thisTask['taskId']['id']}") @taskState["taskUpdates"].each do |update| @taskState = update['taskState'] end if @taskState == "TASK_RUNNING" # print stdout @stdout = JSON.parse(RestClient.get "#{@uri}/api/sandbox/#{@thisTask['taskId']['id']}/read", {params: {path: "stdout", length: 30000, offset: @stdoutOffset}})['data'] outLength = @stdout.bytes.to_a.size if @stdout.length > 0 print @stdout.light_cyan @stdoutOffset += outLength end # print stderr @stderr = JSON.parse(RestClient.get "#{@uri}/api/sandbox/#{@thisTask['taskId']['id']}/read", {params: {path: "stderr", length: 30000, offset: @stderrOffset}})['data'] errLength = @stderr.bytes.to_a.size if @stderr.length > 0 print @stderr.light_magenta @stderrOffset += errLength end end end until @taskState == "TASK_FINISHED" end # finally, delete the request (which also deletes the corresponding task) RestClient.delete "#{@uri}/api/requests/request/#{@data['requestId']}" rescue Exception => e puts " #{e.response}".red end end