priteau-vizir 0.1.2 → 0.2.0

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/README.rdoc CHANGED
@@ -7,21 +7,23 @@ Ever been disconnected from Grid'5000 machines with a message like this, losing
7
7
  Vizir is a simple Ruby script that monitors your interactive jobs on Grid'5000[http://www.grid5000.fr/].
8
8
  It triggers Growl[http://growl.info/] notifications when your reservations are going to terminate, allowing you to save your work and/or your deployed environments.
9
9
 
10
- Vizir only supports Mac OS X for now.
10
+ Vizir only supports Mac OS X.
11
11
 
12
12
  == Getting Started
13
13
 
14
14
  Run the following if you haven't already:
15
+
15
16
  $ gem sources -a http://gems.github.com
16
17
 
17
18
  Install the gem:
19
+
18
20
  $ sudo gem install priteau-vizir
19
21
 
20
- Configure Growl to accept notifications. Go to the Growl preference panel, and in the Network options enable "Listen for incoming notifications" and "Allow remote application registration". Don't forget to setup a password.
22
+ Vizir uses HotCocoa to trigger Growl notifications. HotCocoa is shipped with Mac OS X 10.5, so it should work out of the box on Leopard.
21
23
 
22
- Run it in the background, using the <tt>--login</tt> switch with your Grid'5000 login name and the <tt>--password</tt> switch with your Growl password.
24
+ Run Vizir in the background, using the <tt>--login</tt> switch with your Grid'5000 login name.
23
25
 
24
- $ vizir --login priteau --password mygrowlpassword &
26
+ $ vizir --login priteau &
25
27
 
26
28
  == Getting the source
27
29
 
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.add_dependency "eventmachine"
12
13
  gem.add_dependency "json"
13
14
  gem.add_dependency "net-ssh-gateway"
14
15
  gem.add_dependency "rest-client"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.2.0
data/bin/vizir CHANGED
@@ -1,16 +1,22 @@
1
- #!/usr/bin/env ruby -w
1
+ #!/usr/bin/env ruby
2
2
 
3
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
4
+
5
+ require 'eventmachine'
6
+ require 'growl'
3
7
  require 'json'
4
8
  require 'net/ssh/gateway'
5
9
  require 'optparse'
6
10
  require 'rest_client'
7
- require 'ruby-growl'
11
+ require 'vizir'
8
12
 
9
- ALERT_TIME = 600
13
+ FIRST_ALERT_TIME = 600
14
+ ALERT_PERIOD = 60
15
+ REFRESH_TIME = 3600
10
16
  IGNORE_SITES = ['grenoble-exp', 'grenoble-ext', 'grenoble-obs', 'luxembourg', 'portoalegre']
11
17
 
12
18
  def usage
13
- puts 'usage: vizir [ -h | --help ] [ -l | --login login_name ] [ -p | --password mygrowlpassword ]'
19
+ puts 'usage: vizir [ -h | --help ] [ -l | --login login_name ]'
14
20
  exit 1
15
21
  end
16
22
 
@@ -38,63 +44,50 @@ def apiuri(port)
38
44
  return "https://localhost:#{port}/oargridapi"
39
45
  end
40
46
 
41
- def notify_via_growl(jobid, site_name, time, time_unit)
42
- g = Growl.new("localhost", "Vizir", ["Job ending soon"], nil, $password)
43
- g.notify("Job ending soon", "OAR job terminating soon", "Job #{jobid} in #{site_name} ending in #{time} #{time_unit}.")
47
+ def setup_growl
48
+ $growl = Growl::Notifier.sharedInstance
49
+ $growl.register('Vizir', ['Job ending soon'])
44
50
  end
45
51
 
46
- def get_remaining_time(starttime, walltime)
47
- remaining_sec = (Time.at(starttime + walltime) - Time.now).round
52
+ def notify_via_growl(jobid, site_name, time, time_unit)
53
+ $growl.notify('Job ending soon', 'OAR job terminating soon', "Job #{jobid} in #{site_name} ending in #{time} #{time_unit}.")
48
54
  end
49
55
 
50
- def humanize_time(time)
51
- if time > 60 then
52
- remaining_time = time / 60
53
- remaining_time_unit = "minutes"
54
- else
55
- remaining_time = time
56
- remaining_time_unit = "seconds"
57
- end
58
- return remaining_time, remaining_time_unit
56
+ def get_remaining_time(time)
57
+ return (time - Time.now).round
59
58
  end
60
59
 
61
60
  $login = nil
62
- $password = nil
63
61
  opts = OptionParser.new
64
62
  opts.on('-h', '--help') { usage }
65
63
  opts.on('-l', '--login STRING', String) { |str| $login = str }
66
- opts.on('-p', '--password STRING', String) { |str| $password = str }
67
64
  opts.parse(ARGV)
68
65
 
69
- if $login == nil or $password == nil
66
+ if $login == nil
70
67
  usage
71
68
  end
72
69
 
73
70
  gateway, port = setup_ssh_tunnel
74
71
  api = RestClient::Resource.new(apiuri(port))
72
+ setup_growl
75
73
 
76
- sites = get(api, '/sites')
77
- if sites == nil then
78
- exit 1
79
- end
80
- sites.each do |site|
81
- site_name = site['site']
82
- unless IGNORE_SITES.include?(site_name)
83
- jobs = get(api, "#{site['uri']}/jobs")
84
- if jobs == nil then
85
- break
86
- end
87
- jobs.each do |job|
88
- if job['owner'] == $login then
89
- job_details = get(api, "#{job['uri']}")
90
- if job_details == nil then
91
- break
92
- end
93
- if job_details['jobType'] == 'INTERACTIVE' then
94
- remaining_sec = get_remaining_time(Integer(job_details['startTime']), Integer(job_details['walltime']))
95
- if remaining_sec < ALERT_TIME then
96
- remaining_time, remaining_time_unit = humanize_time(remaining_sec)
97
- notify_via_growl(job_details['Job_Id'], site_name.capitalize, remaining_time, remaining_time_unit)
74
+ def learn_new_jobs(api)
75
+ $sites.each do |site|
76
+ site_name = site['site']
77
+ unless IGNORE_SITES.include?(site_name)
78
+ jobs = get(api, "#{site['uri']}/jobs")
79
+ break if jobs == nil
80
+ jobs.each do |job|
81
+ if job['owner'] == $login
82
+ job_details = get(api, "#{job['uri']}")
83
+ break if job_details == nil
84
+ if job_details['jobType'] == 'INTERACTIVE'
85
+ jobid = job_details['Job_Id']
86
+
87
+ # If we don't yet know the job, record it in $jobs
88
+ if $jobs[jobid].nil?
89
+ $jobs[jobid] = Vizir::Job.new(jobid, Time.at(Integer(job_details['startTime']) + Integer(job_details['walltime'])), site_name.capitalize)
90
+ end
98
91
  end
99
92
  end
100
93
  end
@@ -102,4 +95,42 @@ sites.each do |site|
102
95
  end
103
96
  end
104
97
 
98
+ def first_ending_job
99
+ $jobs.sort{|a,b| a[1].end_time <=> b[1].end_time}.first
100
+ end
101
+
102
+ def alert_jobs(api)
103
+ $jobs.each do |jobid, job|
104
+ remaining_sec = get_remaining_time(job.end_time)
105
+ if remaining_sec < FIRST_ALERT_TIME
106
+ # Check if the job still exists before sending a notification
107
+ updatedjob = get(api, "/sites/#{job.site_name.downcase}/jobs/#{job.id}")
108
+ if updatedjob['state'] != 'Running'
109
+ # Job is not running anymore, remove it from the hash
110
+ $jobs.delete(jobid)
111
+ next
112
+ end
113
+ if remaining_sec < 0
114
+ $stderr.puts "Error: negative time"
115
+ next
116
+ end
117
+ remaining_time, remaining_time_unit = Vizir.humanize_time(remaining_sec)
118
+ notify_via_growl(jobid, job.site_name, remaining_time, remaining_time_unit)
119
+ end
120
+ end
121
+ end
122
+
123
+ # Learn the Grid'5000 sites
124
+ $jobs = Hash.new
125
+ $sites = get(api, '/sites')
126
+ exit 1 if $sites == nil
127
+
128
+ learn_new_jobs(api)
129
+ alert_jobs(api)
130
+
131
+ EventMachine::run {
132
+ EventMachine::PeriodicTimer.new(REFRESH_TIME) { learn_new_jobs(api) }
133
+ EventMachine::PeriodicTimer.new(ALERT_PERIOD) { alert_jobs(api) }
134
+ }
135
+
105
136
  gateway.shutdown!
data/lib/vizir.rb CHANGED
@@ -0,0 +1,29 @@
1
+ module Vizir
2
+ def Vizir.humanize_time(time)
3
+ fail "Can't humanize negative period" if time < 0
4
+
5
+ if time >= 60
6
+ remaining_time = time / 60
7
+ remaining_time_unit = "minute"
8
+ else
9
+ remaining_time = time
10
+ remaining_time_unit = "second"
11
+ end
12
+
13
+ if remaining_time > 1
14
+ remaining_time_unit += "s"
15
+ end
16
+
17
+ return remaining_time, remaining_time_unit
18
+ end
19
+
20
+ class Job
21
+ attr_reader :id, :end_time, :site_name
22
+
23
+ def initialize(id, end_time, site_name)
24
+ @id = id
25
+ @end_time = end_time
26
+ @site_name = site_name
27
+ end
28
+ end
29
+ end
data/test/test_helper.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require 'rubygems'
2
2
  require 'test/unit'
3
- require 'shoulda'
4
3
 
5
4
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
5
  $LOAD_PATH.unshift(File.dirname(__FILE__))
data/test/vizir_test.rb CHANGED
@@ -1,7 +1,17 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class VizirTest < Test::Unit::TestCase
4
- should "probably rename this file and start testing for real" do
5
- flunk "hey buddy, you should probably rename this file and start testing for real"
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) }
6
16
  end
7
17
  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.1.2"
5
+ s.version = "0.2.0"
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-05-29}
9
+ s.date = %q{2009-06-01}
10
10
  s.default_executable = %q{vizir}
11
11
  s.email = %q{pierre.riteau@gmail.com}
12
12
  s.executables = ["vizir"]
@@ -43,17 +43,20 @@ Gem::Specification.new do |s|
43
43
  s.specification_version = 2
44
44
 
45
45
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
46
+ s.add_runtime_dependency(%q<eventmachine>, [">= 0"])
46
47
  s.add_runtime_dependency(%q<json>, [">= 0"])
47
48
  s.add_runtime_dependency(%q<net-ssh-gateway>, [">= 0"])
48
49
  s.add_runtime_dependency(%q<rest-client>, [">= 0"])
49
50
  s.add_runtime_dependency(%q<ruby-growl>, [">= 0"])
50
51
  else
52
+ s.add_dependency(%q<eventmachine>, [">= 0"])
51
53
  s.add_dependency(%q<json>, [">= 0"])
52
54
  s.add_dependency(%q<net-ssh-gateway>, [">= 0"])
53
55
  s.add_dependency(%q<rest-client>, [">= 0"])
54
56
  s.add_dependency(%q<ruby-growl>, [">= 0"])
55
57
  end
56
58
  else
59
+ s.add_dependency(%q<eventmachine>, [">= 0"])
57
60
  s.add_dependency(%q<json>, [">= 0"])
58
61
  s.add_dependency(%q<net-ssh-gateway>, [">= 0"])
59
62
  s.add_dependency(%q<rest-client>, [">= 0"])
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.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pierre Riteau
@@ -9,9 +9,19 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-05-29 00:00:00 -07:00
12
+ date: 2009-06-01 00:00:00 -07:00
13
13
  default_executable: vizir
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: eventmachine
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
15
25
  - !ruby/object:Gem::Dependency
16
26
  name: json
17
27
  type: :runtime