girdle 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +7 -0
- data/Guardfile +15 -0
- data/README.markdown +28 -0
- data/Rakefile +2 -0
- data/girdle.gemspec +27 -0
- data/lib/girdle.rb +86 -0
- data/lib/girdle/controller.rb +32 -0
- data/lib/girdle/grid.rb +33 -0
- data/lib/girdle/job.rb +104 -0
- data/lib/girdle/specification.rb +56 -0
- data/lib/girdle/task.rb +16 -0
- data/lib/girdle/version.rb +3 -0
- data/spec/girdle/controller_spec.rb +67 -0
- data/spec/girdle/grid_spec.rb +57 -0
- data/spec/girdle/job_spec.rb +178 -0
- data/spec/girdle/specification_spec.rb +68 -0
- data/spec/girdle/task_spec.rb +19 -0
- data/spec/girdle_spec.rb +44 -0
- data/spec/spec_helper.rb +7 -0
- metadata +160 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'minitest' do
|
5
|
+
# with Minitest::Unit
|
6
|
+
watch(%r|^test/test_(.*)\.rb|)
|
7
|
+
watch(%r|^lib/(.*)([^/]+)\.rb|) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
|
8
|
+
watch(%r|^test/test_helper\.rb|) { "test" }
|
9
|
+
|
10
|
+
# with Minitest::Spec
|
11
|
+
watch(%r|^spec/(.*)_spec\.rb|)
|
12
|
+
watch(%r|^lib/(.*)\.rb|) { |m| "spec/#{m[1]}_spec.rb" }
|
13
|
+
watch(%r|^lib/girdle/(.*)\.rb|) { |m| "spec/#{m[1]}_spec.rb" }
|
14
|
+
watch(%r|^spec/spec_helper\.rb|) { "spec" }
|
15
|
+
end
|
data/README.markdown
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
Girdle
|
2
|
+
=======
|
3
|
+
|
4
|
+
A client for submitting and managing Xgrid jobs.
|
5
|
+
|
6
|
+
License
|
7
|
+
-------
|
8
|
+
|
9
|
+
Copyright (c) 2011 Jamie Hodge
|
10
|
+
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
12
|
+
a copy of this software and associated documentation files (the
|
13
|
+
"Software"), to deal in the Software without restriction, including
|
14
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
15
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
16
|
+
permit persons to whom the Software is furnished to do so, subject to
|
17
|
+
the following conditions:
|
18
|
+
|
19
|
+
The above copyright notice and this permission notice shall be
|
20
|
+
included in all copies or substantial portions of the Software.
|
21
|
+
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
23
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
24
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
25
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
26
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
27
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
28
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
data/girdle.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/girdle/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Jamie Hodge"]
|
6
|
+
gem.email = ["jamiehodge@me.com"]
|
7
|
+
gem.description = %q{An Xgrid client}
|
8
|
+
gem.summary = %q{A client for submitting and managing Xgrid jobs}
|
9
|
+
gem.homepage = 'http://github.com/jamiehodge/girdle'
|
10
|
+
|
11
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
12
|
+
gem.files = `git ls-files`.split("\n")
|
13
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
14
|
+
gem.name = "girdle"
|
15
|
+
gem.require_paths = ['lib']
|
16
|
+
gem.version = Girdle::VERSION
|
17
|
+
|
18
|
+
gem.add_development_dependency 'bundler'
|
19
|
+
gem.add_development_dependency 'guard'
|
20
|
+
gem.add_development_dependency 'guard-minitest'
|
21
|
+
gem.add_development_dependency 'rb-fsevent'
|
22
|
+
gem.add_development_dependency 'growl_notify'
|
23
|
+
gem.add_development_dependency 'mocha'
|
24
|
+
|
25
|
+
gem.add_dependency 'nokogiri'
|
26
|
+
gem.add_dependency 'nokogiri-plist'
|
27
|
+
end
|
data/lib/girdle.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'nokogiri-plist'
|
4
|
+
|
5
|
+
require_relative 'girdle/version'
|
6
|
+
|
7
|
+
require_relative 'girdle/task'
|
8
|
+
require_relative 'girdle/specification'
|
9
|
+
require_relative 'girdle/job'
|
10
|
+
|
11
|
+
require_relative 'girdle/grid'
|
12
|
+
require_relative 'girdle/controller'
|
13
|
+
|
14
|
+
module Girdle
|
15
|
+
extend self
|
16
|
+
|
17
|
+
attr_writer :xgrid, :hostname, :auth,
|
18
|
+
:password, :format, :failover, :autocopy
|
19
|
+
|
20
|
+
def xgrid
|
21
|
+
@xgrid ||= '/usr/bin/xgrid'
|
22
|
+
end
|
23
|
+
|
24
|
+
def hostname
|
25
|
+
@hostname ||= 'localhost'
|
26
|
+
end
|
27
|
+
|
28
|
+
# None, Password, Kerberos
|
29
|
+
def auth
|
30
|
+
@auth ||= 'None'
|
31
|
+
end
|
32
|
+
|
33
|
+
def password
|
34
|
+
@password ||= ''
|
35
|
+
end
|
36
|
+
|
37
|
+
# plain, xml
|
38
|
+
def format
|
39
|
+
@format ||= 'xml'
|
40
|
+
end
|
41
|
+
|
42
|
+
# YES, NO
|
43
|
+
def failover
|
44
|
+
@failover ||= 'YES'
|
45
|
+
end
|
46
|
+
|
47
|
+
# YES, NO
|
48
|
+
def autocopy
|
49
|
+
@autocopy ||= 'YES'
|
50
|
+
end
|
51
|
+
|
52
|
+
def run(options = {})
|
53
|
+
options = default_options.merge(options)
|
54
|
+
result = `#{xgrid} #{options_format(options)}`
|
55
|
+
parse(result) if $?.to_i == 0
|
56
|
+
end
|
57
|
+
|
58
|
+
def run_batch(xml, options = {})
|
59
|
+
options = default_options.merge(options)
|
60
|
+
result = `#{xml} | #{xgrid} #{options_format(options)} -`
|
61
|
+
parse(result) if $?.to_i == 0
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def options_format(options)
|
67
|
+
options.map { |k,v| k == :cmd ? v : "-#{k} #{v}" }.join(' ')
|
68
|
+
end
|
69
|
+
|
70
|
+
def default_options
|
71
|
+
opts = {
|
72
|
+
hostname: hostname,
|
73
|
+
auth: auth,
|
74
|
+
format: format,
|
75
|
+
failover: failover,
|
76
|
+
autocopy: autocopy
|
77
|
+
}
|
78
|
+
opts[:password] == password if auth == 'Password'
|
79
|
+
opts
|
80
|
+
end
|
81
|
+
|
82
|
+
def parse(xml)
|
83
|
+
Nokogiri::PList(xml)
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Girdle
|
2
|
+
|
3
|
+
class Controller
|
4
|
+
|
5
|
+
attr_reader :id
|
6
|
+
|
7
|
+
def initialize(id)
|
8
|
+
@id = id
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.list
|
12
|
+
Girdle.run(controller: 'list')['controllerList']
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.role
|
16
|
+
Girdle.run(controller: 'role')['controllerRole']
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.promote(role)
|
20
|
+
Girdle.run(
|
21
|
+
controller: 'promote', role: role.to_s.upcase
|
22
|
+
)['controllerRole']
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.autopromote(role)
|
26
|
+
Girdle.run(
|
27
|
+
controller: 'autopromote', role: role.to_s.upcase
|
28
|
+
)['controllerRole']
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
data/lib/girdle/grid.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Girdle
|
2
|
+
|
3
|
+
class Grid
|
4
|
+
|
5
|
+
attr_reader :id
|
6
|
+
|
7
|
+
def initialize(id)
|
8
|
+
@id = id
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.list
|
12
|
+
Girdle.run(grid: 'list')
|
13
|
+
end
|
14
|
+
|
15
|
+
def attributes
|
16
|
+
Girdle.run(grid: 'attributes', gid: id)['gridAttributes']
|
17
|
+
end
|
18
|
+
|
19
|
+
def name
|
20
|
+
attributes['name']
|
21
|
+
end
|
22
|
+
|
23
|
+
def megahertz
|
24
|
+
attributes['gridMegahertz']
|
25
|
+
end
|
26
|
+
|
27
|
+
def is_default?
|
28
|
+
attributes['isDefault'] == 'YES'
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/lib/girdle/job.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
module Girdle
|
2
|
+
|
3
|
+
class Job
|
4
|
+
|
5
|
+
attr_reader :name, :id
|
6
|
+
|
7
|
+
def initialize(id)
|
8
|
+
@id = id
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.list
|
12
|
+
Girdle.run(job: 'list')['jobList']
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.submit(cmd)
|
16
|
+
Girdle.run(job: 'submit', cmd: cmd)['jobIdentifier']
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.run(cmd)
|
20
|
+
Girdle.run(job: 'run', cmd: cmd)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.batch(xml)
|
24
|
+
Girdle.run_batch(xml, job: 'batch')['jobIdentifier']
|
25
|
+
end
|
26
|
+
|
27
|
+
def attributes
|
28
|
+
Girdle.run(job: 'attributes', id: id)['jobAttributes']
|
29
|
+
end
|
30
|
+
|
31
|
+
def active_cpu_power
|
32
|
+
attributes['activeCPUPower'].to_i
|
33
|
+
end
|
34
|
+
|
35
|
+
def date_now
|
36
|
+
attributes['dateNow']
|
37
|
+
end
|
38
|
+
|
39
|
+
def date_started
|
40
|
+
attributes['dateStarted']
|
41
|
+
end
|
42
|
+
|
43
|
+
def date_stopped
|
44
|
+
attributes['dateStopped']
|
45
|
+
end
|
46
|
+
|
47
|
+
def date_submitted
|
48
|
+
attributes['dateSubmitted']
|
49
|
+
end
|
50
|
+
|
51
|
+
def status
|
52
|
+
attributes['jobStatus'].downcase.to_sym
|
53
|
+
end
|
54
|
+
|
55
|
+
def name
|
56
|
+
attributes['name']
|
57
|
+
end
|
58
|
+
|
59
|
+
def percent_done
|
60
|
+
attributes['percentDone']
|
61
|
+
end
|
62
|
+
|
63
|
+
def task_count
|
64
|
+
attributes['taskCount'].to_i
|
65
|
+
end
|
66
|
+
|
67
|
+
def undone_task_count
|
68
|
+
attributes['undoneTaskCount'].to_i
|
69
|
+
end
|
70
|
+
|
71
|
+
def results
|
72
|
+
Girdle.run(job: 'results', id: id)
|
73
|
+
end
|
74
|
+
|
75
|
+
def specification
|
76
|
+
Girdle.run(job: 'specification', id: id)['jobSpecification']
|
77
|
+
end
|
78
|
+
|
79
|
+
def log
|
80
|
+
Girdle.run(job: 'log', id: id)
|
81
|
+
end
|
82
|
+
|
83
|
+
def stop
|
84
|
+
Girdle.run(job: 'stop', id: id)
|
85
|
+
end
|
86
|
+
|
87
|
+
def suspend
|
88
|
+
Girdle.run(job: 'suspend', id: id)
|
89
|
+
end
|
90
|
+
|
91
|
+
def resume
|
92
|
+
Girdle.run(job: 'resume', id: id)
|
93
|
+
end
|
94
|
+
|
95
|
+
def delete
|
96
|
+
Girdle.run(job: 'delete', id: id)
|
97
|
+
end
|
98
|
+
|
99
|
+
def restart
|
100
|
+
Girdle.run(job: 'restart', id: id)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Girdle
|
2
|
+
|
3
|
+
class Specification
|
4
|
+
|
5
|
+
attr_accessor :name, :notification_email, :tasks
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@name = options[:name]
|
9
|
+
@notification_email = options[:notification_email]
|
10
|
+
@tasks = options[:tasks] || []
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_plist
|
14
|
+
Nokogiri::XML::Builder.new do |xml|
|
15
|
+
xml.doc.create_internal_subset(
|
16
|
+
'plist',
|
17
|
+
'-//Apple Computer//DTD PLIST 1.0//EN',
|
18
|
+
'http://www.apple.com/DTDs/PropertyList-1.0.dtd'
|
19
|
+
)
|
20
|
+
xml.plist(:version => '1.0') do
|
21
|
+
xml.array do
|
22
|
+
xml.key 'name'
|
23
|
+
xml.string name
|
24
|
+
xml.key 'notificationEmail'
|
25
|
+
xml.string notification_email
|
26
|
+
xml.key 'taskSpecifications'
|
27
|
+
xml.dict do
|
28
|
+
tasks.each do |task|
|
29
|
+
xml.key 'name'
|
30
|
+
xml.string task.name
|
31
|
+
xml.dict do
|
32
|
+
xml.key 'arguments'
|
33
|
+
xml.array do
|
34
|
+
task.arguments.each do |argument|
|
35
|
+
xml.string argument
|
36
|
+
end
|
37
|
+
end
|
38
|
+
xml.key 'command'
|
39
|
+
xml.string task.command
|
40
|
+
xml.key 'dependsOnTasks'
|
41
|
+
xml.array do
|
42
|
+
task.depends_on.each do |dependency|
|
43
|
+
xml.string dependency
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end.to_xml
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
data/lib/girdle/task.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module Girdle
|
2
|
+
|
3
|
+
class Task
|
4
|
+
|
5
|
+
attr_reader :name, :command, :arguments, :depends_on
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@name = options[:name]
|
9
|
+
@command = options[:command]
|
10
|
+
@arguments = options[:arguments]
|
11
|
+
@depends_on = options[:depends_on]
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe Girdle::Controller do
|
4
|
+
|
5
|
+
it 'must have id attribute' do
|
6
|
+
grid = Girdle::Controller.new(123)
|
7
|
+
grid.id.must_equal 123
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'must retrieve list of failover controllers' do
|
11
|
+
Girdle.expects(:run).
|
12
|
+
with(controller: 'list').
|
13
|
+
returns('controllerList' => Hash.new)
|
14
|
+
list = Girdle::Controller.list
|
15
|
+
list.must_equal Hash.new
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'must retrieve role of controller' do
|
19
|
+
Girdle.expects(:run).
|
20
|
+
with(controller: 'role').
|
21
|
+
returns('controllerRole' => 'MASTER')
|
22
|
+
role = Girdle::Controller.role
|
23
|
+
role.must_equal 'MASTER'
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '::promote' do
|
27
|
+
|
28
|
+
it 'must promote the controller to MASTER role' do
|
29
|
+
Girdle.expects(:run).
|
30
|
+
with(controller: 'promote', role: 'MASTER').
|
31
|
+
returns('controllerRole' => 'MASTER')
|
32
|
+
role = Girdle::Controller.promote(:master)
|
33
|
+
role.must_equal 'MASTER'
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'must promote the controller to PASSIVE role' do
|
37
|
+
Girdle.expects(:run).
|
38
|
+
with(controller: 'promote', role: 'PASSIVE').
|
39
|
+
returns('controllerRole' => 'PASSIVE')
|
40
|
+
role = Girdle::Controller.promote(:passive)
|
41
|
+
role.must_equal 'PASSIVE'
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '::autopromote' do
|
47
|
+
|
48
|
+
it 'must autopromote the controller to MASTER role' do
|
49
|
+
Girdle.expects(:run).
|
50
|
+
with(controller: 'autopromote', role: 'MASTER').
|
51
|
+
returns('controllerRole' => 'MASTER')
|
52
|
+
role = Girdle::Controller.autopromote(:master)
|
53
|
+
role.must_equal 'MASTER'
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'must autopromote the controller to PASSIVE role' do
|
57
|
+
Girdle.expects(:run).
|
58
|
+
with(controller: 'autopromote', role: 'PASSIVE').
|
59
|
+
returns('controllerRole' => 'PASSIVE')
|
60
|
+
role = Girdle::Controller.autopromote(:passive)
|
61
|
+
role.must_equal 'PASSIVE'
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe Griddle::Grid do
|
4
|
+
|
5
|
+
it 'must have id attribute' do
|
6
|
+
grid = Griddle::Grid.new(123)
|
7
|
+
grid.id.must_equal 123
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'must retrieve list identifiers of all logical grids' do
|
11
|
+
Griddle.expects(:run).with(grid: 'list').returns([1,2,3])
|
12
|
+
list = Griddle::Grid.list
|
13
|
+
list.must_equal [1,2,3]
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'a grid' do
|
17
|
+
|
18
|
+
before do
|
19
|
+
@grid = Griddle::Grid.new(123)
|
20
|
+
@attributes = {
|
21
|
+
'name' => 'name',
|
22
|
+
'gridMegahertz' => '0',
|
23
|
+
'isDefault' => 'YES'
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'must retrieve attributes' do
|
28
|
+
Griddle.expects(:run).with(grid: 'attributes', gid: 123).returns('gridAttributes' => @attributes)
|
29
|
+
@grid.attributes.must_equal @attributes
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'must retrieve name' do
|
33
|
+
@grid.expects(:attributes).returns(@attributes)
|
34
|
+
@grid.name.must_equal 'name'
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'must retrieve megahertz' do
|
38
|
+
@grid.expects(:attributes).returns(@attributes)
|
39
|
+
@grid.megahertz.must_equal '0'
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#is_default' do
|
43
|
+
|
44
|
+
it 'must be true when isDefault is YES' do
|
45
|
+
@grid.expects(:attributes).returns(@attributes)
|
46
|
+
@grid.is_default?.must_equal true
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'must be false when isDefault is NO' do
|
50
|
+
attributes = @attributes.merge('isDefault' => 'NO')
|
51
|
+
@grid.expects(:attributes).returns(attributes)
|
52
|
+
@grid.is_default?.must_equal false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe Girdle::Job do
|
4
|
+
|
5
|
+
it 'must have an id attribute' do
|
6
|
+
job = Girdle::Job.new(123)
|
7
|
+
job.id.must_equal 123
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'new jobs' do
|
11
|
+
it 'must submit asynchronous job and return an id' do
|
12
|
+
Girdle.expects(:run).with(job: 'submit', cmd: '/bin/echo hello').
|
13
|
+
returns('jobIdentifier' => '123')
|
14
|
+
id = Girdle::Job.submit('/bin/echo hello')
|
15
|
+
id.must_equal '123'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'must run and retrieve result synchronously' do
|
19
|
+
Girdle.expects(:run).with(job: 'run', cmd: '/bin/echo hello').
|
20
|
+
returns('hello')
|
21
|
+
result = Girdle::Job.run('/bin/echo hello')
|
22
|
+
result.must_equal 'hello'
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'must submit batch file and return an id' do
|
26
|
+
plist = Girdle::Specification.new(
|
27
|
+
name: 'specification name',
|
28
|
+
notification_email: 'email@example.com',
|
29
|
+
tasks: [
|
30
|
+
Girdle::Task.new(
|
31
|
+
name: 'task name',
|
32
|
+
command: '/bin/echo',
|
33
|
+
arguments: ['hello'],
|
34
|
+
depends_on: ['another task']
|
35
|
+
)
|
36
|
+
]
|
37
|
+
).to_plist
|
38
|
+
Girdle.expects(:run_batch).
|
39
|
+
with(plist, job: 'batch').
|
40
|
+
returns('jobIdentifier' => '123')
|
41
|
+
id = Girdle::Job.batch(plist)
|
42
|
+
id.must_equal '123'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'must retrieve list of jobs' do
|
47
|
+
Girdle.expects(:run).with(job: 'list').returns('jobList' => %w{1 2 3})
|
48
|
+
list = Girdle::Job.list
|
49
|
+
list.must_equal %w{1 2 3}
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'a job' do
|
53
|
+
|
54
|
+
before do
|
55
|
+
@job = Girdle::Job.new(123)
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'attributes' do
|
59
|
+
|
60
|
+
before do
|
61
|
+
@attributes = {
|
62
|
+
'activeCPUPower' => '0',
|
63
|
+
'dateNow' => DateTime.parse('2011-08-18 11:20:43 +0000'),
|
64
|
+
'dateStarted' => DateTime.parse('2011-07-15 10:05:18 +0000'),
|
65
|
+
'dateStopped' => DateTime.parse('2011-07-15 10:07:46 +0000'),
|
66
|
+
'dateSubmitted' => DateTime.parse('2011-07-15 10:02:53 +0000'),
|
67
|
+
'jobStatus' => 'Finished',
|
68
|
+
'name' => 'Untitled',
|
69
|
+
'percentDone' => 100.0,
|
70
|
+
'taskCount' => '13',
|
71
|
+
'undoneTaskCount' => '1'
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'must retrieve attributes' do
|
76
|
+
Girdle.expects(:run).
|
77
|
+
with(job: 'attributes', id: 123).
|
78
|
+
returns('jobAttributes' => @attributes)
|
79
|
+
@job.attributes.must_equal @attributes
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'must retrieve active cpu power' do
|
83
|
+
@job.expects(:attributes).returns(@attributes)
|
84
|
+
@job.active_cpu_power.must_equal 0
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'must retrieve date now' do
|
88
|
+
@job.expects(:attributes).returns(@attributes)
|
89
|
+
@job.date_now.must_equal DateTime.parse('2011-08-18 11:20:43 +0000')
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'must retrieve date started' do
|
93
|
+
@job.expects(:attributes).returns(@attributes)
|
94
|
+
@job.date_started.must_equal DateTime.parse('2011-07-15 10:05:18 +0000')
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'must retrieve date stopped' do
|
98
|
+
@job.expects(:attributes).returns(@attributes)
|
99
|
+
@job.date_stopped.must_equal DateTime.parse('2011-07-15 10:07:46 +0000')
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'must retrieve date submitted' do
|
103
|
+
@job.expects(:attributes).returns(@attributes)
|
104
|
+
@job.date_submitted.must_equal DateTime.parse('2011-07-15 10:02:53 +0000')
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'must retrieve status' do
|
108
|
+
@job.expects(:attributes).returns(@attributes)
|
109
|
+
@job.status.must_equal :finished
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'must retrieve name' do
|
113
|
+
@job.expects(:attributes).returns(@attributes)
|
114
|
+
@job.name.must_equal 'Untitled'
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'must retrieve percent done' do
|
118
|
+
@job.expects(:attributes).returns(@attributes)
|
119
|
+
@job.percent_done.must_equal 100
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'must retrieve task count' do
|
123
|
+
@job.expects(:attributes).returns(@attributes)
|
124
|
+
@job.task_count.must_equal 13
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'must retrieve undone task count' do
|
128
|
+
@job.expects(:attributes).returns(@attributes)
|
129
|
+
@job.undone_task_count.must_equal 1
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'must retrieve results' do
|
134
|
+
Girdle.expects(:run).with(job: 'results', id: 123).returns('results')
|
135
|
+
@job.results.must_equal 'results'
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'must retrieve specification' do
|
139
|
+
Girdle.expects(:run).
|
140
|
+
with(job: 'specification', id: 123).
|
141
|
+
returns('jobSpecification' => Hash.new)
|
142
|
+
@job.specification.must_equal Hash.new
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'must retrieve log' do
|
146
|
+
Girdle.expects(:run).with(job: 'log', id: 123).returns('log')
|
147
|
+
@job.log.must_equal 'log'
|
148
|
+
end
|
149
|
+
|
150
|
+
describe 'status' do
|
151
|
+
|
152
|
+
it 'must stop, but don\'t delete' do
|
153
|
+
Girdle.expects(:run).with(job: 'stop', id: 123)
|
154
|
+
@job.stop
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'must suspend' do
|
158
|
+
Girdle.expects(:run).with(job: 'suspend', id: 123)
|
159
|
+
@job.suspend
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'must resume' do
|
163
|
+
Girdle.expects(:run).with(job: 'resume', id: 123)
|
164
|
+
@job.resume
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'must stop and delete' do
|
168
|
+
Girdle.expects(:run).with(job: 'delete', id: 123)
|
169
|
+
@job.delete
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'must restart a running or stopped job' do
|
173
|
+
Girdle.expects(:run).with(job: 'restart', id: 123)
|
174
|
+
@job.restart
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
def plist
|
4
|
+
<<-EOS
|
5
|
+
<?xml version="1.0"?>
|
6
|
+
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
7
|
+
<plist version="1.0">
|
8
|
+
<array>
|
9
|
+
<key>name</key>
|
10
|
+
<string>specification name</string>
|
11
|
+
<key>notificationEmail</key>
|
12
|
+
<string>email@example.com</string>
|
13
|
+
<key>taskSpecifications</key>
|
14
|
+
<dict>
|
15
|
+
<key>name</key>
|
16
|
+
<string>task name</string>
|
17
|
+
<dict>
|
18
|
+
<key>arguments</key>
|
19
|
+
<array>
|
20
|
+
<string>hello</string>
|
21
|
+
</array>
|
22
|
+
<key>command</key>
|
23
|
+
<string>/bin/echo</string>
|
24
|
+
<key>dependsOnTasks</key>
|
25
|
+
<array>
|
26
|
+
<string>another task</string>
|
27
|
+
</array>
|
28
|
+
</dict>
|
29
|
+
</dict>
|
30
|
+
</array>
|
31
|
+
</plist>
|
32
|
+
EOS
|
33
|
+
end
|
34
|
+
|
35
|
+
describe Girdle::Specification do
|
36
|
+
|
37
|
+
before do
|
38
|
+
@spec = Girdle::Specification.new(
|
39
|
+
name: 'specification name',
|
40
|
+
notification_email: 'email@example.com',
|
41
|
+
tasks: [
|
42
|
+
Girdle::Task.new(
|
43
|
+
name: 'task name',
|
44
|
+
command: '/bin/echo',
|
45
|
+
arguments: ['hello'],
|
46
|
+
depends_on: ['another task']
|
47
|
+
)
|
48
|
+
]
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'must have name, notification_email, tasks and depends_on accessors' do
|
53
|
+
@spec.name.must_equal 'specification name'
|
54
|
+
@spec.notification_email.must_equal 'email@example.com'
|
55
|
+
@spec.tasks.size.must_equal 1
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'must append tasks' do
|
59
|
+
@spec.tasks.size.must_equal 1
|
60
|
+
@spec.tasks << Girdle::Task.new
|
61
|
+
@spec.tasks.size.must_equal 2
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'must render itself as a plist' do
|
65
|
+
@spec.to_plist.must_equal plist
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe Girdle::Task do
|
4
|
+
|
5
|
+
it 'must have name, command, arguments and depends_on attributes' do
|
6
|
+
task = Girdle::Task.new(
|
7
|
+
name: 'name',
|
8
|
+
command: '/bin/echo',
|
9
|
+
arguments: [],
|
10
|
+
depends_on: []
|
11
|
+
)
|
12
|
+
task.name.must_equal 'name'
|
13
|
+
task.command.must_equal '/bin/echo'
|
14
|
+
task.arguments.must_equal []
|
15
|
+
task.depends_on.must_equal []
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
end
|
data/spec/girdle_spec.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
def plist
|
4
|
+
<<-EOS
|
5
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
6
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
7
|
+
<plist version="1.0">
|
8
|
+
<dict>
|
9
|
+
</dict>
|
10
|
+
</plist>
|
11
|
+
EOS
|
12
|
+
end
|
13
|
+
|
14
|
+
describe Girdle do
|
15
|
+
|
16
|
+
describe '::run' do
|
17
|
+
|
18
|
+
it 'must call xgrid with default options' do
|
19
|
+
Girdle.expects(:`).
|
20
|
+
with('/usr/bin/xgrid -hostname localhost -auth None -format xml -failover YES -autocopy YES').
|
21
|
+
returns(plist)
|
22
|
+
Girdle.run
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'must format commands and arguments' do
|
26
|
+
Girdle.expects(:`).
|
27
|
+
with('/usr/bin/xgrid -hostname localhost -auth None -format xml -failover YES -autocopy YES -job run /bin/echo hello').
|
28
|
+
returns(plist)
|
29
|
+
Girdle.run(job: 'run', cmd: '/bin/echo hello')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
describe '::run_batch' do
|
35
|
+
|
36
|
+
it 'must pipe xml to xgrid using - argument' do
|
37
|
+
Girdle.expects(:`).
|
38
|
+
with('xml | /usr/bin/xgrid -hostname localhost -auth None -format xml -failover YES -autocopy YES -').
|
39
|
+
returns(plist)
|
40
|
+
Girdle.run_batch('xml')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: girdle
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jamie Hodge
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-08-18 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: &70331454389380 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70331454389380
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: guard
|
27
|
+
requirement: &70331454412740 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70331454412740
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: guard-minitest
|
38
|
+
requirement: &70331454412320 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70331454412320
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rb-fsevent
|
49
|
+
requirement: &70331454411900 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70331454411900
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: growl_notify
|
60
|
+
requirement: &70331454411480 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70331454411480
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: mocha
|
71
|
+
requirement: &70331454411060 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *70331454411060
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: nokogiri
|
82
|
+
requirement: &70331454410640 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :runtime
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *70331454410640
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: nokogiri-plist
|
93
|
+
requirement: &70331454410220 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
type: :runtime
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *70331454410220
|
102
|
+
description: An Xgrid client
|
103
|
+
email:
|
104
|
+
- jamiehodge@me.com
|
105
|
+
executables: []
|
106
|
+
extensions: []
|
107
|
+
extra_rdoc_files: []
|
108
|
+
files:
|
109
|
+
- .gitignore
|
110
|
+
- Gemfile
|
111
|
+
- Guardfile
|
112
|
+
- README.markdown
|
113
|
+
- Rakefile
|
114
|
+
- girdle.gemspec
|
115
|
+
- lib/girdle.rb
|
116
|
+
- lib/girdle/controller.rb
|
117
|
+
- lib/girdle/grid.rb
|
118
|
+
- lib/girdle/job.rb
|
119
|
+
- lib/girdle/specification.rb
|
120
|
+
- lib/girdle/task.rb
|
121
|
+
- lib/girdle/version.rb
|
122
|
+
- spec/girdle/controller_spec.rb
|
123
|
+
- spec/girdle/grid_spec.rb
|
124
|
+
- spec/girdle/job_spec.rb
|
125
|
+
- spec/girdle/specification_spec.rb
|
126
|
+
- spec/girdle/task_spec.rb
|
127
|
+
- spec/girdle_spec.rb
|
128
|
+
- spec/spec_helper.rb
|
129
|
+
homepage: http://github.com/jamiehodge/girdle
|
130
|
+
licenses: []
|
131
|
+
post_install_message:
|
132
|
+
rdoc_options: []
|
133
|
+
require_paths:
|
134
|
+
- lib
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
136
|
+
none: false
|
137
|
+
requirements:
|
138
|
+
- - ! '>='
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
|
+
none: false
|
143
|
+
requirements:
|
144
|
+
- - ! '>='
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
requirements: []
|
148
|
+
rubyforge_project:
|
149
|
+
rubygems_version: 1.8.5
|
150
|
+
signing_key:
|
151
|
+
specification_version: 3
|
152
|
+
summary: A client for submitting and managing Xgrid jobs
|
153
|
+
test_files:
|
154
|
+
- spec/girdle/controller_spec.rb
|
155
|
+
- spec/girdle/grid_spec.rb
|
156
|
+
- spec/girdle/job_spec.rb
|
157
|
+
- spec/girdle/specification_spec.rb
|
158
|
+
- spec/girdle/task_spec.rb
|
159
|
+
- spec/girdle_spec.rb
|
160
|
+
- spec/spec_helper.rb
|