priteau-vizir 0.2.2 → 0.2.3

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/Rakefile CHANGED
@@ -9,6 +9,7 @@ begin
9
9
  gem.email = "pierre.riteau@gmail.com"
10
10
  gem.homepage = "http://github.com/priteau/vizir"
11
11
  gem.authors = ["Pierre Riteau"]
12
+ gem.rubyforge_project = "vizir"
12
13
  gem.add_dependency "eventmachine"
13
14
  gem.add_dependency "growlnotifier"
14
15
  gem.add_dependency "json"
@@ -17,6 +18,7 @@ begin
17
18
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
19
  end
19
20
 
21
+ Jeweler::RubyforgeTasks.new
20
22
  rescue LoadError
21
23
  puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
22
24
  end
@@ -24,7 +26,7 @@ end
24
26
  require 'rake/testtask'
25
27
  Rake::TestTask.new(:test) do |test|
26
28
  test.libs << 'lib' << 'test'
27
- test.pattern = 'test/**/*_test.rb'
29
+ test.pattern = 'test/**/test_*.rb'
28
30
  test.verbose = true
29
31
  end
30
32
 
@@ -32,7 +34,7 @@ begin
32
34
  require 'rcov/rcovtask'
33
35
  Rcov::RcovTask.new do |test|
34
36
  test.libs << 'test'
35
- test.pattern = 'test/**/*_test.rb'
37
+ test.pattern = 'test/**/test_*.rb'
36
38
  test.verbose = true
37
39
  end
38
40
  rescue LoadError
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.2
1
+ 0.2.3
data/bin/vizir CHANGED
@@ -4,43 +4,13 @@ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
4
4
 
5
5
  require 'eventmachine'
6
6
  require 'growl'
7
- require 'json'
8
7
  require 'net/ssh/gateway'
9
8
  require 'optparse'
10
9
  require 'rest_client'
11
10
  require 'vizir'
12
11
 
13
- FIRST_ALERT_TIME = 600
14
- ALERT_PERIOD = 60
15
- REFRESH_TIME = 3600
16
- IGNORE_SITES = ['grenoble-exp', 'grenoble-ext', 'grenoble-obs', 'luxembourg', 'portoalegre']
17
-
18
- def usage
19
- puts 'usage: vizir [ -h | --help ] [ -l | --login login_name ]'
20
- exit 1
21
- end
22
-
23
- def get(api, uri)
24
- begin
25
- return JSON.parse(api[uri + '?structure=simple'].get(:accept => 'application/json'))
26
- rescue RestClient::RequestTimeout => e
27
- # This should really be elsewhere, but will do for now
28
- # Were we querying a specific site? If yes, remove it from $sites
29
- if uri =~ /\/sites\/(\w+)/
30
- $sites.delete_if { |site| site['site'] == "#{$1}" }
31
- else
32
- raise e
33
- end
34
- rescue => e
35
- if e.respond_to?('http_code')
36
- puts "Error: #{e.http_code}:\n #{e.response.body}"
37
- return nil
38
- else
39
- puts e.inspect
40
- exit 1
41
- end
42
- end
43
- end
12
+ $alert_period = 60
13
+ $refresh_period = 3600
44
14
 
45
15
  def setup_ssh_tunnel
46
16
  gateway = Net::SSH::Gateway.new('access.grenoble.grid5000.fr', $login)
@@ -58,87 +28,47 @@ def setup_growl
58
28
  end
59
29
 
60
30
  def notify_via_growl(jobid, site_name, time, time_unit)
61
- $growl.notify('Job ending soon', 'OAR job terminating soon', "Job #{jobid} in #{site_name} ending in #{time} #{time_unit}.")
62
- end
63
-
64
- def get_remaining_time(time)
65
- return (time - Time.now).round
31
+ $growl.notify('Job ending soon', 'OAR job terminating soon', "Job #{jobid} in #{site_name} ending in #{time} #{time_unit}.", :sticky => true)
66
32
  end
67
33
 
68
34
  $login = nil
69
- opts = OptionParser.new
70
- opts.on('-h', '--help') { usage }
71
- opts.on('-l', '--login STRING', String) { |str| $login = str }
72
- opts.parse(ARGV)
73
-
74
- if $login == nil
75
- usage
76
- end
77
35
 
78
- gateway, port = setup_ssh_tunnel
79
- api = RestClient::Resource.new(apiuri(port))
80
- setup_growl
36
+ opts = OptionParser.new do |opts|
37
+ opts.banner = "Usage: vizir [options]"
38
+ opts.separator("")
81
39
 
82
- def learn_new_jobs(api)
83
- $sites.each do |site|
84
- site_name = site['site']
85
- unless IGNORE_SITES.include?(site_name)
86
- jobs = get(api, "#{site['uri']}/jobs")
87
- break if jobs == nil
88
- jobs.each do |job|
89
- if job['owner'] == $login
90
- job_details = get(api, "#{job['uri']}")
91
- break if job_details == nil
92
- if job_details['jobType'] == 'INTERACTIVE'
93
- jobid = job_details['Job_Id']
94
-
95
- # If we don't yet know the job, record it in $jobs
96
- if $jobs[jobid].nil?
97
- $jobs[jobid] = Vizir::Job.new(jobid, Time.at(Integer(job_details['startTime']) + Integer(job_details['walltime'])), site_name.capitalize)
98
- end
99
- end
100
- end
101
- end
102
- end
40
+ opts.separator("Options:")
41
+ opts.on('-a', '--alert-period TIME', Integer, "Job alert period (seconds), default: #{$alert_period}") { |t| $alert_period = t }
42
+ opts.on('-h', '--help', 'Print help') do
43
+ puts opts
44
+ exit
103
45
  end
46
+ opts.on('-l', '--login LOGIN', String, "User login on Grid\'5000") { |str| $login = str }
47
+ opts.on('-m', '--min-job-time TIME', Integer, "Minimum job time (seconds), default: #{$refresh_period}") { |t| $refresh_period = t }
104
48
  end
105
49
 
106
- def first_ending_job
107
- $jobs.sort{|a,b| a[1].end_time <=> b[1].end_time}.first
108
- end
50
+ opts.parse!(ARGV)
109
51
 
110
- def alert_jobs(api)
111
- $jobs.each do |jobid, job|
112
- remaining_sec = get_remaining_time(job.end_time)
113
- if remaining_sec < FIRST_ALERT_TIME
114
- # Check if the job still exists before sending a notification
115
- updatedjob = get(api, "/sites/#{job.site_name.downcase}/jobs/#{job.id}")
116
- if updatedjob['state'] != 'Running'
117
- # Job is not running anymore, remove it from the hash
118
- $jobs.delete(jobid)
119
- next
120
- end
121
- if remaining_sec < 0
122
- $stderr.puts "Error: negative time"
123
- next
124
- end
125
- remaining_time, remaining_time_unit = Vizir.humanize_time(remaining_sec)
126
- notify_via_growl(jobid, job.site_name, remaining_time, remaining_time_unit)
127
- end
128
- end
52
+ if $login == nil
53
+ puts opts
54
+ exit
129
55
  end
130
56
 
57
+ gateway, port = setup_ssh_tunnel
58
+ api = Vizir.get_api(apiuri(port))
59
+ setup_growl
60
+
131
61
  # Learn the Grid'5000 sites
132
62
  $jobs = Hash.new
133
- $sites = get(api, '/sites')
63
+ $sites = Vizir.learn_sites(api, Vizir::IGNORED_SITES)
134
64
  exit 1 if $sites == nil
135
65
 
136
- learn_new_jobs(api)
137
- alert_jobs(api)
66
+ Vizir.learn_new_jobs(api)
67
+ Vizir.alert_jobs(api)
138
68
 
139
69
  EventMachine::run {
140
- EventMachine::PeriodicTimer.new(REFRESH_TIME) { learn_new_jobs(api) }
141
- EventMachine::PeriodicTimer.new(ALERT_PERIOD) { alert_jobs(api) }
70
+ EventMachine::PeriodicTimer.new($refresh_period) { Vizir.learn_new_jobs(api) }
71
+ EventMachine::PeriodicTimer.new($alert_period) { Vizir.alert_jobs(api) }
142
72
  }
143
73
 
144
74
  gateway.shutdown!
data/lib/vizir.rb CHANGED
@@ -1,4 +1,11 @@
1
+ require 'json'
2
+ require 'restclient'
3
+
1
4
  module Vizir
5
+ APIURL = "https://localhost:8080/oargridapi"
6
+ IGNORED_SITES = ['grenoble-exp', 'grenoble-ext', 'grenoble-obs', 'luxembourg', 'portoalegre']
7
+ FIRST_ALERT_TIME = 600
8
+
2
9
  def Vizir.humanize_time(time)
3
10
  fail "Can't humanize negative period" if time < 0
4
11
 
@@ -17,6 +24,90 @@ module Vizir
17
24
  return remaining_time, remaining_time_unit
18
25
  end
19
26
 
27
+ def Vizir.get_remaining_time(end_time, now)
28
+ return (end_time - now).round
29
+ end
30
+
31
+ def Vizir.get(api, uri)
32
+ begin
33
+ return JSON.parse(api[uri + '?structure=simple'].get(:accept => 'application/json'))
34
+ rescue RestClient::RequestTimeout => e
35
+ # This should really be elsewhere, but will do for now
36
+ # Were we querying a specific site? If yes, remove it from $sites
37
+ if uri =~ /\/sites\/(\w+)/
38
+ $sites.delete_if { |site| site['site'] == "#{$1}" }
39
+ return nil
40
+ else
41
+ raise e
42
+ end
43
+ rescue => e
44
+ if e.respond_to?('http_code')
45
+ puts "Error: #{e.http_code}:\n #{e.response.body}"
46
+ return nil
47
+ else
48
+ puts e.inspect
49
+ exit 1
50
+ end
51
+ end
52
+ end
53
+
54
+ def Vizir.learn_sites(api, ignored_sites)
55
+ return get(api, '/sites').delete_if { |hash| ignored_sites.include?(hash["site"]) }
56
+ end
57
+
58
+ def Vizir.get_api(uri)
59
+ return RestClient::Resource.new(uri, :timeout => 15)
60
+ end
61
+
62
+ def Vizir.learn_new_jobs_on_site(api, site)
63
+ site_name = site['site']
64
+ jobs = Vizir.get(api, "#{site['uri']}/jobs")
65
+ return if jobs.nil?
66
+ jobs.each do |job|
67
+ if job['owner'] == $login
68
+ job_details = Vizir.get(api, "#{job['uri']}")
69
+ break if job_details == nil
70
+ if job_details['jobType'] == 'INTERACTIVE'
71
+ jobid = job_details['Job_Id']
72
+ # If we don't yet know the job, record it in $jobs
73
+ if $jobs[jobid].nil?
74
+ $jobs[jobid] = Vizir::Job.new(jobid, Time.at(Integer(job_details['startTime']) + Integer(job_details['walltime'])), site_name.capitalize)
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ def Vizir.learn_new_jobs(api)
82
+ $sites.each do |site|
83
+ Vizir.learn_new_jobs_on_site(api, site)
84
+ end
85
+ end
86
+
87
+ def Vizir.first_ending_job
88
+ $jobs.sort{|a,b| a[1].end_time <=> b[1].end_time}.first
89
+ end
90
+
91
+ def Vizir.alert_jobs(api)
92
+ $jobs.each do |jobid, job|
93
+ if job.should_be_ending?
94
+ # Check if the job still exists before sending a notification
95
+ if job.is_ended?(api)
96
+ # Job is not running anymore, remove it from the hash
97
+ $jobs.delete(jobid)
98
+ next
99
+ end
100
+ remaining_sec = Vizir.get_remaining_time(job.end_time, Time.now)
101
+ if remaining_sec < 0
102
+ $stderr.puts "Error: negative time"
103
+ next
104
+ end
105
+ remaining_time, remaining_time_unit = Vizir.humanize_time(remaining_sec)
106
+ notify_via_growl(jobid, job.site_name, remaining_time, remaining_time_unit)
107
+ end
108
+ end
109
+ end
110
+
20
111
  class Job
21
112
  attr_reader :id, :end_time, :site_name
22
113
 
@@ -25,5 +116,23 @@ module Vizir
25
116
  @end_time = end_time
26
117
  @site_name = site_name
27
118
  end
119
+
120
+ def Job.create_from_json(json, site_name)
121
+ return Job.new(json['Job_Id'], Time.at(Integer(json['startTime']) + Integer(json['walltime'])), site_name.capitalize)
122
+ end
123
+
124
+ def fetch_details(api)
125
+ return Vizir.get(api, "/sites/#{@site_name.downcase}/jobs/#{@id}")
126
+ end
127
+
128
+ def should_be_ending?(time=Time.now())
129
+ return Vizir.get_remaining_time(self.end_time, time) <= Vizir::FIRST_ALERT_TIME
130
+ end
131
+
132
+ def is_ended?(api)
133
+ updatedjob = self.fetch_details(api)
134
+ return updatedjob['state'] != 'Running'
135
+ end
136
+
28
137
  end
29
138
  end
data/test/test_helper.rb CHANGED
@@ -1,8 +1,11 @@
1
1
  require 'rubygems'
2
2
  require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ require 'fakeweb'
3
6
 
4
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
5
7
  $LOAD_PATH.unshift(File.dirname(__FILE__))
8
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
9
  require 'vizir'
7
10
 
8
11
  class Test::Unit::TestCase
@@ -0,0 +1,99 @@
1
+ require 'test_helper'
2
+
3
+ class VizirTest < Test::Unit::TestCase
4
+ TIMES = [
5
+ [0, [0, "second"]],
6
+ [1, [1, "second"]],
7
+ [30, [30, "seconds"]],
8
+ [59, [59, "seconds"]],
9
+ [60, [1, "minute"]],
10
+ [119, [1, "minute"]],
11
+ [120, [2, "minutes"]]
12
+ ]
13
+ def test_humanize_time
14
+ TIMES.each do |seconds, result|
15
+ assert_equal(result, Vizir.humanize_time(seconds))
16
+ end
17
+ e = assert_raise(RuntimeError) { Vizir.humanize_time(-1) }
18
+ assert_equal("Can't humanize negative period", e.message)
19
+ end
20
+
21
+ def test_learn_sites
22
+ FakeWeb.allow_net_connect = false
23
+ o = [
24
+ {
25
+ "site" => "nancy",
26
+ "uri" => "/sites/nancy"
27
+ },
28
+ {
29
+ "site" => "rennes",
30
+ "uri" => "/sites/rennes"
31
+ },
32
+ {
33
+ "site" => "luxembourg",
34
+ "uri" => "/sites/luxembourg"
35
+ }]
36
+ json = JSON.generate(o)
37
+ FakeWeb.register_uri(:get, "#{Vizir::APIURL}/sites?structure=simple", :string => json)
38
+ api = Vizir.get_api(Vizir::APIURL)
39
+ sites = o.delete_if { |hash| hash["site"] == "luxembourg" }
40
+ ignored_sites = ["luxembourg", "portoalegre"]
41
+ assert_equal(sites, Vizir.learn_sites(api, ignored_sites))
42
+ end
43
+
44
+ context "A Job instance" do
45
+ setup do
46
+ @job_endtime = Time.at(123456789)
47
+ @job = Vizir::Job.new('1234', @job_endtime, 'Rennes')
48
+ end
49
+
50
+ context 'ending in FIRST_ALERT_TIME seconds' do
51
+ setup do
52
+ @now = Time.at(Integer(@job_endtime) - Integer(Vizir::FIRST_ALERT_TIME))
53
+ end
54
+
55
+ should 'be considered as ending soon' do
56
+ assert_equal true, @job.should_be_ending?(@now)
57
+ end
58
+ end
59
+
60
+ context 'ending in more than FIRST_ALERT_TIME seconds' do
61
+ setup do
62
+ @now = Time.at(Integer(@job_endtime) - Integer(Vizir::FIRST_ALERT_TIME + 1))
63
+ end
64
+
65
+ should 'not be considered as ending soon' do
66
+ assert_equal false, @job.should_be_ending?(@now)
67
+ end
68
+ end
69
+ end
70
+
71
+ context 'A site-specific query' do
72
+ setup do
73
+ @uri = "#{Vizir::APIURL}/sites/rennes/jobs?structure=simple"
74
+ end
75
+
76
+ context 'which timeouts' do
77
+ setup do
78
+ FakeWeb.register_uri(:get, @uri, :exception => Timeout::Error)
79
+ @api = Vizir.get_api(Vizir::APIURL)
80
+ end
81
+
82
+ should 'remove the site from the sites list' do
83
+ $sites = [
84
+ {
85
+ "site" => "nancy",
86
+ "uri" => "/sites/nancy"
87
+ },
88
+ {
89
+ "site" => "rennes",
90
+ "uri" => "/sites/rennes"
91
+ }
92
+ ]
93
+ Vizir.learn_new_jobs_on_site(@api, $sites[1])
94
+ assert_equal [{ "site" => "nancy", "uri" => "/sites/nancy" }], $sites
95
+ end
96
+ end
97
+ end
98
+
99
+ end
data/vizir.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{vizir}
5
- s.version = "0.2.2"
5
+ s.version = "0.2.3"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Pierre Riteau"]
9
- s.date = %q{2009-06-02}
9
+ s.date = %q{2009-06-18}
10
10
  s.default_executable = %q{vizir}
11
11
  s.email = %q{pierre.riteau@gmail.com}
12
12
  s.executables = ["vizir"]
@@ -24,18 +24,19 @@ Gem::Specification.new do |s|
24
24
  "bin/vizir",
25
25
  "lib/vizir.rb",
26
26
  "test/test_helper.rb",
27
- "test/vizir_test.rb",
27
+ "test/test_vizir.rb",
28
28
  "vizir.gemspec"
29
29
  ]
30
30
  s.has_rdoc = true
31
31
  s.homepage = %q{http://github.com/priteau/vizir}
32
32
  s.rdoc_options = ["--charset=UTF-8"]
33
33
  s.require_paths = ["lib"]
34
+ s.rubyforge_project = %q{vizir}
34
35
  s.rubygems_version = %q{1.3.1}
35
36
  s.summary = %q{Growl notifications for Grid'5000 jobs}
36
37
  s.test_files = [
37
38
  "test/test_helper.rb",
38
- "test/vizir_test.rb"
39
+ "test/test_vizir.rb"
39
40
  ]
40
41
 
41
42
  if s.respond_to? :specification_version then
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: priteau-vizir
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pierre Riteau
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-02 00:00:00 -07:00
12
+ date: 2009-06-18 00:00:00 -07:00
13
13
  default_executable: vizir
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -81,7 +81,7 @@ files:
81
81
  - bin/vizir
82
82
  - lib/vizir.rb
83
83
  - test/test_helper.rb
84
- - test/vizir_test.rb
84
+ - test/test_vizir.rb
85
85
  - vizir.gemspec
86
86
  has_rdoc: true
87
87
  homepage: http://github.com/priteau/vizir
@@ -104,11 +104,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
104
  version:
105
105
  requirements: []
106
106
 
107
- rubyforge_project:
107
+ rubyforge_project: vizir
108
108
  rubygems_version: 1.2.0
109
109
  signing_key:
110
110
  specification_version: 2
111
111
  summary: Growl notifications for Grid'5000 jobs
112
112
  test_files:
113
113
  - test/test_helper.rb
114
- - test/vizir_test.rb
114
+ - test/test_vizir.rb
data/test/vizir_test.rb DELETED
@@ -1,17 +0,0 @@
1
- require 'test_helper'
2
-
3
- class VizirTest < Test::Unit::TestCase
4
- TIMES = [
5
- [1, [1, "second"]],
6
- [30, [30, "seconds"]],
7
- [59, [59, "seconds"]],
8
- [60, [1, "minute"]],
9
- [120, [2, "minutes"]]
10
- ]
11
- def test_humanize_time
12
- TIMES.each do |seconds, result|
13
- assert_equal(result, Vizir.humanize_time(seconds))
14
- end
15
- assert_raise(RuntimeError) { Vizir.humanize_time(-1) }
16
- end
17
- end