condor-job 1.3.13

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.
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ vendor/bundle
19
+ cinput*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in condor-job.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jonatan Hejzlar
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Condor::Job
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'condor-job'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install condor-job
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs = ["lib/condor"]
7
+ t.warning = true
8
+ t.verbose = true
9
+ t.test_files = FileList['test/test_*.rb']
10
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'condor-job/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "condor-job"
8
+ spec.version = Condor::VERSION
9
+ spec.authors = ["Jonatan Hejzlar"]
10
+ spec.email = ["hea@ujv.cz"]
11
+ spec.description = "Gem for condor execution of bash jobs"
12
+ spec.summary = "Gem for condor execution of bash jobs"
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_runtime_dependency "nokogiri"
24
+ spec.add_runtime_dependency "activesupport"
25
+ end
@@ -0,0 +1,134 @@
1
+ require_relative "version"
2
+
3
+ module Condor
4
+
5
+ class Job
6
+
7
+ attr_reader :priority, :id, :cmd, :dir, :job_data
8
+ attr_reader :finished
9
+
10
+ def initialize(cmd = nil, options = {})
11
+ options ||= {}
12
+ @priority = options.delete(:priority)
13
+ @avoid_finalize = !!options.delete(:no_finalizer)
14
+ @home = `echo $HOME`.strip
15
+ @home = nil if (@home || '').empty?
16
+ @dir = options.delete(:directory) || Dir.pwd
17
+ @id = options.delete(:id)
18
+ @finished = false
19
+ @job_data = nil
20
+ @base_name = options.delete(:base_name) || "#{@dir}/cinput"
21
+ @suppress_numbering = options.delete(:simple)
22
+
23
+ options.empty? or raise "Unknown options: #{options.keys.inspect}"
24
+
25
+ if @id
26
+ @cmd = nil
27
+ update
28
+ else
29
+ @id = nil
30
+ @cmd = []
31
+ @cmd << "#!/bin/bash"
32
+ @cmd << "# encoding: UTF-8"
33
+ @cmd << "source /etc/profile"
34
+ @cmd << "source #{@home}/.profile" if @home and File.exist?("#{@home}/.profile")
35
+ @cmd << "source #{@home}/.rvm/scripts/rvm" if @home and File.exist?("#{@home}/.rvm/scripts/rvm")
36
+ @cmd += [cmd].flatten
37
+ end
38
+
39
+ ObjectSpace.define_finalizer(self, proc { finalize_job }) unless @avoid_finalize
40
+ end
41
+
42
+ def run(set_dir = nil)
43
+ @dir = set_dir || @dir
44
+ name = if @suppress_numbering
45
+ "#{@base_name}"
46
+ else
47
+ # get condor input file number
48
+ num = (Dir["#{@base_name}*"].map{|x| File.basename(x).sub(@base_name,'').to_i}.max or 0) + 1
49
+ "#{@base_name}#{num}"
50
+ end
51
+
52
+ @input, @log, @error, @output, @bash = ['.inp','.log','.error','.output',''].map{|x| "#{name}#{x}"}
53
+
54
+ # create bash executable file to run
55
+ File.open(@bash,'w'){|f| f.puts @cmd * "\n"}
56
+ `chmod +x #{@bash}`
57
+
58
+ input = []
59
+ input << "Executable = #{@bash}"
60
+ input << "Universe = vanilla"
61
+ input << "Log = #{name}.log"
62
+ input << "Error = #{name}.error"
63
+ input << "Environment = HOME=#{@home}" if @home
64
+ input << "Initialdir = #{@dir}"
65
+ input << "Output = #{@output}"
66
+ input << "Requirements = OpSys == \"LINUX\""
67
+ input << "Queue"
68
+
69
+ File.open(@input, 'w'){|f| f.puts input * "\n"}
70
+ if submit_output = `condor_submit #{@input}`.strip.split.last
71
+ @id = submit_output + '0'
72
+ set_priority
73
+ update(true)
74
+ @executed = true
75
+ else
76
+ @id = nil
77
+ @executed = false
78
+ @job_data = nil
79
+ end
80
+ end
81
+
82
+ def cleanup
83
+ [@input, @log, @error, @output, @bash].each{|x| `rm #{x}` if x and File.exists?(x)} if @id
84
+ end
85
+
86
+ def priority=(val)
87
+ @priority = val
88
+ set_priority
89
+ end
90
+
91
+ def done?; @finished; end
92
+ def running?; @job_data ? (@job_data.job_status == '2') : false; end
93
+ def idle?; @job_data ? (@job_data.job_status == '1') : false; end
94
+ def held?; @job_data ? (@job_data.job_status == '5') : false; end
95
+ def runtime; @job_data ? Time.at(@job_data.server_time.to_f - @job_data.job_start_date.to_f).utc.strftime("%H:%M:%S") : nil; end
96
+ def alive?; @id and !@finished; end
97
+
98
+ def error; IO.read(@error); end
99
+ def input; IO.read(@input); end
100
+ def log; IO.read(@log); end
101
+ def output; IO.read(@output); end
102
+ def bash; IO.read(@bash); end
103
+
104
+ # update job information
105
+ def update(force = false)
106
+ Condor::Queue.load(force)
107
+ return nil if !@id
108
+ if @job_data = Condor::Queue[@id]
109
+ return self
110
+ else
111
+ @finished = true
112
+ return nil
113
+ end
114
+ end
115
+
116
+ def remove
117
+ `condor_rm #{@id}` if @id
118
+ end
119
+
120
+ def finalize_job
121
+ unless @avoid_finalize
122
+ remove if !done?
123
+ cleanup
124
+ end
125
+ end
126
+
127
+ private
128
+
129
+ def set_priority
130
+ `condor_prio -p #{@priority} #{@id}` if alive?
131
+ end
132
+
133
+ end
134
+ end
@@ -0,0 +1,51 @@
1
+ module Condor
2
+ class Pool
3
+ attr_reader :jobs
4
+ attr_reader :waiting
5
+
6
+ def initialize
7
+ @jobs = []
8
+ @waiting = {}
9
+ end
10
+
11
+ # run command, given job dependencies
12
+ def add(cmd, dep = nil, priority = nil, dir = nil)
13
+ return if !cmd or cmd.empty?
14
+ c = Job.new(cmd, :priority => priority, :directory => dir)
15
+ if [dep].flatten.compact.empty?
16
+ c.run
17
+ else
18
+ @waiting[c] = [dep].flatten.compact
19
+ end
20
+ @jobs << c
21
+ update
22
+ return c
23
+ end
24
+
25
+ def update
26
+ Condor::Queue.load(true)
27
+ @jobs.each do |j|
28
+ j.update
29
+ next if !(deps = @waiting[j])
30
+ if deps.all?(&:done?)
31
+ j.run
32
+ @waiting.delete(j)
33
+ end
34
+ end
35
+ end
36
+
37
+ def finalize
38
+ while alive?
39
+ sleep 2
40
+ update
41
+ end
42
+ @jobs.each{|x| x.cleanup}
43
+ @jobs = []
44
+ end
45
+
46
+ def alive?
47
+ return true if !@waiting.empty?
48
+ @jobs.any?(&:done?)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,65 @@
1
+ require 'nokogiri'
2
+ require 'active_support/inflector'
3
+ require 'singleton'
4
+ require 'ostruct'
5
+
6
+ module Condor
7
+
8
+ class Queue
9
+
10
+ include Singleton
11
+
12
+ def self.load(force = false)
13
+ instance.load(force)
14
+ end
15
+
16
+ def self.[](job_id)
17
+ instance[job_id]
18
+ end
19
+
20
+ def [](job_id)
21
+ @queue.detect{|job| job_id == job.global_job_id.split('#')[1]}
22
+ end
23
+
24
+ def initialize
25
+ load
26
+ end
27
+
28
+ def load(force = false)
29
+ @queue = nil if force
30
+ @queue ||= begin
31
+ queue = []
32
+
33
+ data = `condor_q -global -xml 2>&1`
34
+ n_retries = 0
35
+ while data.include?("condor_collector") # retry!
36
+ data = `condor_q -global -xml 2>&1`
37
+ sleep rand
38
+ (n_retries += 1) < 10 or raise "Could not retrieve the queue!"
39
+ end
40
+
41
+ xml = Nokogiri::XML("<condor>#{data}</condor>")
42
+ xml.root.css("c").each do |e|
43
+ job = {}
44
+ e.css("a").each do |ee|
45
+ key = ee.attributes["n"].to_s
46
+ if ee.children.first
47
+ val = ee.children.first.text
48
+ job[key.underscore] = val
49
+ end
50
+ end
51
+
52
+ queue << QueueEntry.new(job)
53
+ end
54
+ @queue = queue
55
+ end
56
+ @queue
57
+ end
58
+
59
+ end
60
+
61
+ class QueueEntry < OpenStruct
62
+
63
+ end
64
+
65
+ end
@@ -0,0 +1,3 @@
1
+ module Condor
2
+ VERSION = "1.3.13"
3
+ end
data/lib/condor-job.rb ADDED
@@ -0,0 +1,3 @@
1
+ require_relative 'condor-job/queue.rb'
2
+ require_relative 'condor-job/pool.rb'
3
+ require_relative 'condor-job/job.rb'
@@ -0,0 +1,42 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/unit'
3
+ require 'minitest/pride'
4
+
5
+ require 'rubygems'
6
+ require 'bundler/setup'
7
+ require_relative '../lib/condor-job'
8
+
9
+ class TestBasic < MiniTest::Unit::TestCase
10
+
11
+ def test_simple_run
12
+ puts "Running a simple job"
13
+ j = Condor::Job.new 'echo "hello"'
14
+ j.run
15
+ while !j.done?
16
+ j.update
17
+ sleep 2
18
+ if j.running?
19
+ puts "running #{j.runtime} @ #{j.job_data.remote_host}"
20
+ elsif j.held?
21
+ puts "held : #{j.job_data.hold_reason}"
22
+ #break
23
+ elsif j.idle?
24
+ puts "idle"
25
+ end
26
+ end
27
+
28
+ puts "output: #{j.output}, error: #{j.error}"
29
+ end
30
+
31
+ def test_pool
32
+ puts "Pool test"
33
+ c = Condor::Pool.new
34
+ job = c.add ['echo "hi there"', 'sleep 2']
35
+ job1 = c.add 'echo "reply"', job
36
+ job2 = c.add 'echo "priority reply"', job, 1
37
+ c.add 'echo "wait for all reply"', [job1, job2]
38
+ puts "Waiting for the pool"
39
+ c.finalize
40
+ end
41
+
42
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: condor-job
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.3.13
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jonatan Hejzlar
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-01-01 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: nokogiri
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: activesupport
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: Gem for condor execution of bash jobs
79
+ email:
80
+ - hea@ujv.cz
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - Gemfile
87
+ - LICENSE.txt
88
+ - README.md
89
+ - Rakefile
90
+ - condor-job.gemspec
91
+ - lib/condor-job.rb
92
+ - lib/condor-job/job.rb
93
+ - lib/condor-job/pool.rb
94
+ - lib/condor-job/queue.rb
95
+ - lib/condor-job/version.rb
96
+ - test/test_basic.rb
97
+ homepage: ''
98
+ licenses:
99
+ - MIT
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ! '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubyforge_project:
118
+ rubygems_version: 1.8.28
119
+ signing_key:
120
+ specification_version: 3
121
+ summary: Gem for condor execution of bash jobs
122
+ test_files:
123
+ - test/test_basic.rb