torque-vpc-toolkit 1.0.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/.gitignore +21 -0
- data/.rvmrc +1 -0
- data/COPYING +26 -0
- data/README.rdoc +32 -0
- data/Rakefile +30 -0
- data/VERSION +1 -0
- data/bin/torque-vpc-toolkit +28 -0
- data/contrib/conf/jobs.json.example +13 -0
- data/contrib/rake/Rakefile +16 -0
- data/lib/torque-vpc-toolkit.rb +277 -0
- data/rake/torque_vpc_toolkit.rake +197 -0
- metadata +105 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.8.7@chef_vpc_toolkit
|
data/COPYING
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Unless otherwise noted, all files are released under the MIT license,
|
2
|
+
exceptions contain licensing information in them.
|
3
|
+
|
4
|
+
Copyright (C) 2010 Rackspace US, Inc.
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
14
|
+
all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
SOFTWARE.
|
23
|
+
|
24
|
+
Except as contained in this notice, the name of Rackspace US, Inc. shall not
|
25
|
+
be used in advertising or otherwise to promote the sale, use or other dealings
|
26
|
+
in this Software without prior written authorization from Rackspace US, Inc.
|
data/README.rdoc
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
= Torque VPC Toolkit
|
2
|
+
|
3
|
+
Rake tasks to submit jobs and interact with Torque via a web API.
|
4
|
+
|
5
|
+
== Description
|
6
|
+
|
7
|
+
The Torque VPC Toolkit is a set of Rake tasks that provide a way to interact
|
8
|
+
with a Torque web API application. Intended to be used with the Chef VPC Toolkit and the Torque Job Control application.
|
9
|
+
|
10
|
+
== Installation
|
11
|
+
|
12
|
+
gem install torque-vpc-toolkit
|
13
|
+
|
14
|
+
Once you have the Torque toolkit gem install you can add tasks to job tasks
|
15
|
+
to any Chef VPC by running the the following command inside of the Chef
|
16
|
+
VPC project directory.
|
17
|
+
|
18
|
+
cd <my chef vpc project>
|
19
|
+
torque-vpc-toolkit
|
20
|
+
|
21
|
+
== Tasks
|
22
|
+
|
23
|
+
The following Rake tasks are provided by the toolkit:
|
24
|
+
|
25
|
+
rake job:create_and_run_all # Create a new server group and run all jobs.
|
26
|
+
rake job:list # List jobs
|
27
|
+
rake job:log # Print job logs for the specified JOB_ID.
|
28
|
+
rake job:node_states # List node states
|
29
|
+
rake job:poll_controller # Poll/loop until job controller is online
|
30
|
+
rake job:poll_jobs # Poll/loop until jobs finish
|
31
|
+
rake job:submit # Submit a job (requires: SCRIPT=<job_script_name>)
|
32
|
+
rake job:submit_all # Submit all jobs (uses the jobs.json config file)
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "torque-vpc-toolkit"
|
8
|
+
gem.summary = %Q{Rake tasks to submit Torque jobs. }
|
9
|
+
gem.description = %Q{Rake tasks to submit, and poll Torque jobs.}
|
10
|
+
gem.email = "dan.prince@rackspace.com"
|
11
|
+
gem.homepage = "http://github.com/dprince/torque_vpc_toolkit"
|
12
|
+
gem.authors = ["Dan Prince"]
|
13
|
+
gem.add_dependency "rake", ">= 0"
|
14
|
+
gem.add_dependency "chef-vpc-toolkit", ">= 2.0"
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'rake/rdoctask'
|
23
|
+
Rake::RDocTask.new do |rdoc|
|
24
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
25
|
+
|
26
|
+
rdoc.rdoc_dir = 'rdoc'
|
27
|
+
rdoc.title = "Torque VPC Toolkit #{version}"
|
28
|
+
rdoc.rdoc_files.include('README*')
|
29
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
30
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
CHEF_VPC_PROJECT = "#{File.dirname(__FILE__)}" unless defined?(CHEF_VPC_PROJECT)
|
7
|
+
|
8
|
+
require 'torque-vpc-toolkit'
|
9
|
+
include TorqueVPCToolkit
|
10
|
+
|
11
|
+
# check to make sure this is a valid Chef VPC project dir
|
12
|
+
if not File.exists?("config/chef_installer.yml") then
|
13
|
+
puts "Run this command within your Chef VPC project directory."
|
14
|
+
exit 1
|
15
|
+
end
|
16
|
+
|
17
|
+
if not File.exists?("tasks") then
|
18
|
+
FileUtils.mkdir("tasks")
|
19
|
+
end
|
20
|
+
FileUtils.cp(File.join(TorqueVPCToolkit::TORQUE_VPC_TOOLKIT_ROOT, 'contrib', 'rake', 'Rakefile'), File.join("tasks", "torque_vpc_toolkit.rake"))
|
21
|
+
|
22
|
+
if not File.exists?("config/jobs.json") and not File.exists?(File.join('config', 'jobs.json.example')) then
|
23
|
+
FileUtils.cp(File.join(TorqueVPCToolkit::TORQUE_VPC_TOOLKIT_ROOT, 'contrib', 'conf', 'jobs.json.example'), 'config')
|
24
|
+
end
|
25
|
+
|
26
|
+
if not File.exists?("jobs") then
|
27
|
+
FileUtils.mkdir("jobs")
|
28
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
jc_toolkit_version=nil
|
4
|
+
if ENV['TORQUE_VPC_TOOLKIT_VERSION'] then
|
5
|
+
jc_toolkit_version=ENV['TORQUE_VPC_TOOLKIT_VERSION']
|
6
|
+
end
|
7
|
+
|
8
|
+
gem 'torque-vpc-toolkit', "= #{jc_toolkit_version}" if jc_toolkit_version
|
9
|
+
|
10
|
+
require 'torque-vpc-toolkit'
|
11
|
+
|
12
|
+
include TorqueVPCToolkit
|
13
|
+
|
14
|
+
Dir[File.join(TorqueVPCToolkit::TORQUE_VPC_TOOLKIT_ROOT, 'rake', '*.rake')].each do |rakefile|
|
15
|
+
import(rakefile)
|
16
|
+
end
|
@@ -0,0 +1,277 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
require 'rexml/xpath'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
require 'chef-vpc-toolkit'
|
6
|
+
|
7
|
+
module TorqueVPCToolkit
|
8
|
+
|
9
|
+
TORQUE_VPC_TOOLKIT_ROOT = File.dirname(File.expand_path("./", File.dirname(__FILE__)))
|
10
|
+
|
11
|
+
include ChefVPCToolkit
|
12
|
+
|
13
|
+
def self.jobs_list(xml)
|
14
|
+
list=[]
|
15
|
+
dom = REXML::Document.new(xml)
|
16
|
+
|
17
|
+
REXML::XPath.each(dom, "//job") do |job|
|
18
|
+
job_attrs = {
|
19
|
+
"id" => job.elements["id"].text,
|
20
|
+
"description" => job.elements["description"].text,
|
21
|
+
"queue-job-id" => job.elements["queue-job-id"].text,
|
22
|
+
"resources" => job.elements["resources"].text,
|
23
|
+
"additional-attrs" => job.elements["additional-attrs"].text,
|
24
|
+
"status" => job.elements["status"].text
|
25
|
+
}
|
26
|
+
|
27
|
+
stdout=job.elements["stdout"]
|
28
|
+
job_attrs.store("stdout", stdout.text) if stdout
|
29
|
+
|
30
|
+
stderr=job.elements["stderr"]
|
31
|
+
job_attrs.store("stderr", stderr.text) if stderr
|
32
|
+
|
33
|
+
list << job_attrs
|
34
|
+
end
|
35
|
+
|
36
|
+
list
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.submit_job(configs, script, description, resources, additional_attrs="")
|
41
|
+
|
42
|
+
Util.raise_if_nil_or_empty(configs, "ssh_gateway_ip")
|
43
|
+
Util.raise_if_nil_or_empty(configs, "torque_job_control_username")
|
44
|
+
Util.raise_if_nil_or_empty(configs, "torque_job_control_password")
|
45
|
+
|
46
|
+
post_data={
|
47
|
+
"job[description]" => description
|
48
|
+
}
|
49
|
+
if not resources.nil? and not resources.empty? then
|
50
|
+
post_data.store("job[resources]", resources)
|
51
|
+
end
|
52
|
+
if not additional_attrs.nil? and not additional_attrs.empty? then
|
53
|
+
post_data.store("job[additional_attrs]", additional_attrs)
|
54
|
+
end
|
55
|
+
|
56
|
+
file_data={
|
57
|
+
"job[script_file_upload]" => script
|
58
|
+
}
|
59
|
+
|
60
|
+
resp=HttpUtil.file_upload(
|
61
|
+
"https://"+configs["ssh_gateway_ip"]+"/jobs.xml",
|
62
|
+
file_data,
|
63
|
+
post_data,
|
64
|
+
configs["torque_job_control_username"],
|
65
|
+
configs["torque_job_control_password"]
|
66
|
+
)
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.node_states(xml)
|
71
|
+
|
72
|
+
node_states={}
|
73
|
+
dom = REXML::Document.new(xml)
|
74
|
+
|
75
|
+
REXML::XPath.each(dom, "//Node") do |job|
|
76
|
+
node_states.store(job.elements["name"].text, job.elements["state"].text)
|
77
|
+
end
|
78
|
+
|
79
|
+
node_states
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
# default timeout of 20 minutes
|
84
|
+
def self.poll_until_online(ip, timeout=1200, configs=Util.load_configs)
|
85
|
+
|
86
|
+
online = false
|
87
|
+
count=0
|
88
|
+
until online or (count*20) >= timeout.to_i do
|
89
|
+
count+=1
|
90
|
+
xml=""
|
91
|
+
begin
|
92
|
+
xml=HttpUtil.get(
|
93
|
+
"https://#{ip}/nodes",
|
94
|
+
configs["torque_job_control_username"],
|
95
|
+
configs["torque_job_control_password"]
|
96
|
+
)
|
97
|
+
rescue
|
98
|
+
sleep 20
|
99
|
+
next
|
100
|
+
end
|
101
|
+
|
102
|
+
jobs=TorqueVPCToolkit.node_states(xml)
|
103
|
+
|
104
|
+
online=true
|
105
|
+
jobs.each_pair do |name, state|
|
106
|
+
if state != "free" then
|
107
|
+
online=false
|
108
|
+
end
|
109
|
+
end
|
110
|
+
if not online
|
111
|
+
yield jobs if block_given?
|
112
|
+
sleep 20
|
113
|
+
end
|
114
|
+
end
|
115
|
+
if (count*20) >= timeout.to_i then
|
116
|
+
raise "Timeout waiting for job control to come online."
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.print_job(hash)
|
122
|
+
|
123
|
+
puts "Job ID: #{hash["id"]}"
|
124
|
+
puts "description: #{hash["description"]}"
|
125
|
+
puts "Queue job ID: #{hash["queue-job-id"]}"
|
126
|
+
puts "Resources: #{hash["resources"]}"
|
127
|
+
puts "Additional Attrs: #{hash["additional-attrs"]}"
|
128
|
+
puts "Status: #{hash["status"]}"
|
129
|
+
puts "--"
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.submit_all(configs, config_file=CHEF_VPC_PROJECT + File::SEPARATOR + "config" + File::SEPARATOR + "jobs.json")
|
134
|
+
|
135
|
+
if not File.exists?(config_file) then
|
136
|
+
puts "The jobs.json config file is missing. No jobs scheduled."
|
137
|
+
return
|
138
|
+
end
|
139
|
+
|
140
|
+
json_hash=JSON.parse(IO.read(config_file))
|
141
|
+
|
142
|
+
# hash for job_name/job_id's (used for variable substitution)
|
143
|
+
jobid_vars={}
|
144
|
+
jobs_dir=CHEF_VPC_PROJECT + File::SEPARATOR + "jobs" + File::SEPARATOR
|
145
|
+
|
146
|
+
json_hash.each do |job|
|
147
|
+
script=job["script"]
|
148
|
+
name=job["name"]
|
149
|
+
if File.exists?(jobs_dir+script) then
|
150
|
+
resources=self.replace_jobid_vars(job["resources"], jobid_vars)
|
151
|
+
additional_attrs=self.replace_jobid_vars(job["additional_attrs"], jobid_vars)
|
152
|
+
xml=self.submit_job(configs, jobs_dir+script, name, resources, additional_attrs)
|
153
|
+
job_hash=TorqueVPCToolkit.jobs_list(xml)[0]
|
154
|
+
if jobid_vars.has_key?(name) then
|
155
|
+
raise "A unique job name must be specified in jobs.json"
|
156
|
+
else
|
157
|
+
jobid_vars.store(name, job_hash["queue-job-id"])
|
158
|
+
end
|
159
|
+
puts "\tJob ID "+job_hash["id"]+ " submitted."
|
160
|
+
|
161
|
+
else
|
162
|
+
raise "Job script '#{script}' does not exist."
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.job_hash(vpn_gateway, job_id, configs=Util.load_configs)
|
169
|
+
if job_id.nil? or job_id.empty? then
|
170
|
+
raise "A valid job_id is required."
|
171
|
+
end
|
172
|
+
xml=HttpUtil.get(
|
173
|
+
"https://#{vpn_gateway}/jobs/#{job_id}.xml",
|
174
|
+
configs["torque_job_control_username"],
|
175
|
+
configs["torque_job_control_password"]
|
176
|
+
)
|
177
|
+
TorqueVPCToolkit.jobs_list(xml)[0]
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
def self.get_jobs(ip, configs)
|
182
|
+
xml=HttpUtil.get(
|
183
|
+
"https://#{ip}/jobs.xml",
|
184
|
+
configs["torque_job_control_username"],
|
185
|
+
configs["torque_job_control_password"]
|
186
|
+
)
|
187
|
+
return TorqueVPCToolkit.jobs_list(xml)
|
188
|
+
end
|
189
|
+
|
190
|
+
def self.poll_until_job_range_finished(ip, from_id, to_id, timeout=1200, configs=Util.load_configs)
|
191
|
+
|
192
|
+
def gen_filter(from_id, to_id)
|
193
|
+
return Proc.new { |i| from_id <= i and i <= to_id }
|
194
|
+
end
|
195
|
+
|
196
|
+
criteria = gen_filter(from_id, to_id)
|
197
|
+
poll_until_jobs_finished(ip, timeout, configs, criteria)
|
198
|
+
end
|
199
|
+
|
200
|
+
# default timeout of 20 minutes
|
201
|
+
def self.poll_until_jobs_finished(ip, timeout=1200, configs=Util.load_configs, criteria=nil)
|
202
|
+
count=0
|
203
|
+
until (count*20) >= timeout.to_i do
|
204
|
+
count+=1
|
205
|
+
jobs = nil
|
206
|
+
begin
|
207
|
+
jobs=TorqueVPCToolkit.get_jobs(ip, configs)
|
208
|
+
rescue
|
209
|
+
sleep 20
|
210
|
+
next
|
211
|
+
end
|
212
|
+
|
213
|
+
all_jobs_finished = true
|
214
|
+
jobs.each do |job|
|
215
|
+
id = Integer(job['id'])
|
216
|
+
if criteria != nil and not criteria.call(id) then
|
217
|
+
next
|
218
|
+
end
|
219
|
+
|
220
|
+
if job["status"] == "Failed" then
|
221
|
+
raise "Job ID #{job['id']} failed."
|
222
|
+
elsif job["status"] != "Completed" then
|
223
|
+
all_jobs_finished = false
|
224
|
+
end
|
225
|
+
end
|
226
|
+
if all_jobs_finished then
|
227
|
+
break
|
228
|
+
else
|
229
|
+
yield jobs if block_given?
|
230
|
+
sleep 20
|
231
|
+
end
|
232
|
+
end
|
233
|
+
if (count*20) >= timeout.to_i then
|
234
|
+
raise "Timeout waiting for jobs to finish."
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
238
|
+
|
239
|
+
# parse the torque_server role for job_control credentials
|
240
|
+
def self.job_control_credentials(ip_addr)
|
241
|
+
role_text=%x{ssh root@#{ip_addr} /usr/bin/knife role show torque_server}
|
242
|
+
json=JSON.parse(role_text.gsub(/\"json_class\"[^,]*,/, ''))
|
243
|
+
username=json["override_attributes"]["job_control"]["auth_username"]
|
244
|
+
password=json["override_attributes"]["job_control"]["auth_password"]
|
245
|
+
if block_given?
|
246
|
+
yield username, password
|
247
|
+
else
|
248
|
+
{
|
249
|
+
"torque_job_control_username" => username,
|
250
|
+
"torque_job_control_password"=> password
|
251
|
+
}
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
private
|
256
|
+
def self.replace_jobid_vars(str, vars)
|
257
|
+
return nil if str.nil?
|
258
|
+
vars=vars.sort { |a,b| b[0].length <=> a[0].length }
|
259
|
+
vars.each do |arr|
|
260
|
+
regex=Regexp.new("\\$#{arr[0]}")
|
261
|
+
str=str.gsub(regex, arr[1])
|
262
|
+
end
|
263
|
+
str
|
264
|
+
end
|
265
|
+
|
266
|
+
|
267
|
+
def self.get_max_job_id(configs, hash)
|
268
|
+
ip=hash['vpn-gateway']
|
269
|
+
jobs=TorqueVPCToolkit.get_jobs(ip, configs)
|
270
|
+
|
271
|
+
if jobs.empty?
|
272
|
+
return 0
|
273
|
+
else
|
274
|
+
return jobs.collect { |job| Integer(job['id']) }.sort.last
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
namespace :job do
|
2
|
+
|
3
|
+
desc "Submit a job (requires: SCRIPT=<job_script_name>)"
|
4
|
+
task :submit do
|
5
|
+
|
6
|
+
script=ENV['SCRIPT']
|
7
|
+
resources=ENV['RESOURCES']
|
8
|
+
additional_attrs=ENV['ATTRIBUTES']
|
9
|
+
|
10
|
+
configs=Util.load_configs
|
11
|
+
hash=Util.hash_for_group(configs)
|
12
|
+
configs["ssh_gateway_ip"]=hash["vpn-gateway"]
|
13
|
+
configs.merge!(TorqueVPCToolkit.job_control_credentials(hash['vpn-gateway']))
|
14
|
+
|
15
|
+
xml=TorqueVPCToolkit.submit_job(configs, "jobs/#{script}", script, resources, additional_attrs)
|
16
|
+
job_hash=TorqueVPCToolkit.jobs_list(xml)[0]
|
17
|
+
TorqueVPCToolkit.print_job(job_hash)
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "Submit all jobs (uses the jobs.json config file)"
|
22
|
+
task :submit_all do
|
23
|
+
|
24
|
+
configs=Util.load_configs
|
25
|
+
hash=Util.hash_for_group(configs)
|
26
|
+
configs["ssh_gateway_ip"]=hash["vpn-gateway"]
|
27
|
+
configs.merge!(TorqueVPCToolkit.job_control_credentials(hash['vpn-gateway']))
|
28
|
+
xml=TorqueVPCToolkit.submit_all(configs)
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "Submit job group (requires: JOB_GROUP=<file>)"
|
33
|
+
task :submit_group do
|
34
|
+
job_group=ENV['JOB_GROUP']
|
35
|
+
|
36
|
+
configs=Util.load_configs
|
37
|
+
hash=Util.hash_for_group(configs)
|
38
|
+
configs["ssh_gateway_ip"]=hash["vpn-gateway"]
|
39
|
+
configs.merge!(TorqueVPCToolkit.job_control_credentials(hash['vpn-gateway']))
|
40
|
+
|
41
|
+
xml=TorqueVPCToolkit.submit_all(configs, job_group)
|
42
|
+
end
|
43
|
+
|
44
|
+
desc "List jobs"
|
45
|
+
task :list do
|
46
|
+
|
47
|
+
configs=Util.load_configs
|
48
|
+
hash=Util.hash_for_group(configs)
|
49
|
+
configs.merge!(TorqueVPCToolkit.job_control_credentials(hash['vpn-gateway']))
|
50
|
+
xml=HttpUtil.get(
|
51
|
+
"https://"+hash["vpn-gateway"]+"/jobs.xml",
|
52
|
+
configs["torque_job_control_username"],
|
53
|
+
configs["torque_job_control_password"]
|
54
|
+
)
|
55
|
+
jobs=TorqueVPCToolkit.jobs_list(xml)
|
56
|
+
puts "Jobs:"
|
57
|
+
jobs.each do |job|
|
58
|
+
puts "\t#{job['id']}: #{job['description']} (#{job['status']})"
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
desc "List node states"
|
64
|
+
task :node_states do
|
65
|
+
|
66
|
+
configs=Util.load_configs
|
67
|
+
hash=Util.hash_for_group(configs)
|
68
|
+
configs.merge!(TorqueVPCToolkit.job_control_credentials(hash['vpn-gateway']))
|
69
|
+
xml=HttpUtil.get(
|
70
|
+
"https://"+hash["vpn-gateway"]+"/nodes",
|
71
|
+
configs["torque_job_control_username"],
|
72
|
+
configs["torque_job_control_password"]
|
73
|
+
)
|
74
|
+
node_states=TorqueVPCToolkit.node_states(xml)
|
75
|
+
puts "Nodes:"
|
76
|
+
node_states.each_pair do |name, state|
|
77
|
+
puts "\t#{name}: #{state}"
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
desc "Poll/loop until job controller is online"
|
83
|
+
task :poll_controller do
|
84
|
+
timeout=ENV['CONTROLLER_TIMEOUT']
|
85
|
+
if timeout.nil? or timeout.empty? then
|
86
|
+
timeout=1200
|
87
|
+
end
|
88
|
+
|
89
|
+
configs=Util.load_configs
|
90
|
+
hash=Util.hash_for_group(configs)
|
91
|
+
configs.merge!(TorqueVPCToolkit.job_control_credentials(hash['vpn-gateway']))
|
92
|
+
|
93
|
+
puts "Polling for job controller to come online (this may take a couple minutes)..."
|
94
|
+
nodes=nil
|
95
|
+
TorqueVPCToolkit.poll_until_online(hash["vpn-gateway"], timeout, configs) do |nodes_hash|
|
96
|
+
if nodes != nodes_hash then
|
97
|
+
nodes = nodes_hash
|
98
|
+
nodes_hash.each_pair do |name, state|
|
99
|
+
puts "\t#{name}: #{state}"
|
100
|
+
end
|
101
|
+
puts "\t--"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
puts "Job controller online."
|
105
|
+
end
|
106
|
+
|
107
|
+
desc "Poll/loop until jobs finish"
|
108
|
+
task :poll_jobs do
|
109
|
+
timeout=ENV['JOBS_TIMEOUT']
|
110
|
+
if timeout.nil? or timeout.empty? then
|
111
|
+
timeout=3600
|
112
|
+
end
|
113
|
+
|
114
|
+
configs=Util.load_configs
|
115
|
+
hash=Util.hash_for_group(configs)
|
116
|
+
configs.merge!(TorqueVPCToolkit.job_control_credentials(hash['vpn-gateway']))
|
117
|
+
|
118
|
+
puts "Polling for jobs to finish running..."
|
119
|
+
TorqueVPCToolkit.poll_until_jobs_finished(hash["vpn-gateway"], timeout, configs)
|
120
|
+
puts "Jobs finished."
|
121
|
+
end
|
122
|
+
|
123
|
+
desc "Poll/loop until a range of jobs finishes (requires: FROM_ID=<id>, TO_ID=<id>"
|
124
|
+
task :poll_jobs_range do
|
125
|
+
timeout=ENV['JOBS_TIMEOUT']
|
126
|
+
if timeout.nil? or timeout.empty? then
|
127
|
+
timeout=3600
|
128
|
+
end
|
129
|
+
|
130
|
+
from_id=ENV['FROM_ID']
|
131
|
+
to_id=ENV['TO_ID']
|
132
|
+
|
133
|
+
configs=Util.load_configs
|
134
|
+
hash=Util.hash_for_group(configs)
|
135
|
+
puts "Polling for jobs #{from_id}-#{to_id} to finish running..."
|
136
|
+
TorqueVPCToolkit.poll_until_job_range_finished(hash["vpn-gateway"], Integer(from_id), Integer(to_id),
|
137
|
+
timeout, configs)
|
138
|
+
puts "Jobs finished."
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
desc "Submit a job group and poll until it is complete (requires: JOB_GROUP=<file>)"
|
143
|
+
task :submit_group_and_poll do
|
144
|
+
configs=Util.load_configs
|
145
|
+
hash=Util.hash_for_group(configs)
|
146
|
+
|
147
|
+
initial_max = TorqueVPCToolkit.get_max_job_id(configs, hash)
|
148
|
+
Rake::Task['job:submit_group'].invoke
|
149
|
+
new_max = TorqueVPCToolkit.get_max_job_id(configs, hash)
|
150
|
+
|
151
|
+
ENV['FROM_ID'] = "#{initial_max + 1}"
|
152
|
+
ENV['TO_ID'] = "#{new_max}"
|
153
|
+
Rake::Task['job:poll_jobs_range'].invoke
|
154
|
+
end
|
155
|
+
|
156
|
+
desc "Print job logs for the specified JOB_ID."
|
157
|
+
task :log do
|
158
|
+
job_id=ENV['JOB_ID']
|
159
|
+
|
160
|
+
configs=Util.load_configs
|
161
|
+
hash=Util.hash_for_group(configs)
|
162
|
+
configs.merge!(TorqueVPCToolkit.job_control_credentials(hash['vpn-gateway']))
|
163
|
+
job=TorqueVPCToolkit.job_hash(hash["vpn-gateway"], job_id, configs)
|
164
|
+
|
165
|
+
puts "--"
|
166
|
+
puts "Job ID: #{job['id']}"
|
167
|
+
puts "Description: #{job['description']}"
|
168
|
+
puts "Status: #{job['status']}"
|
169
|
+
puts "--"
|
170
|
+
puts "Stdout:\n#{job['stdout']}"
|
171
|
+
puts "--"
|
172
|
+
puts "Stderr:\n#{job['stderr']}"
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
desc "Poll the controller, sync data, submit and poll all jobs."
|
179
|
+
task :jobs do
|
180
|
+
|
181
|
+
Rake::Task['job:poll_controller'].invoke
|
182
|
+
Rake::Task['share:sync'].invoke
|
183
|
+
Rake::Task['job:submit_all'].invoke
|
184
|
+
Rake::Task['job:poll_jobs'].invoke
|
185
|
+
cleanup=ENV['CLEANUP']
|
186
|
+
|
187
|
+
if cleanup then
|
188
|
+
Rake::Task['group:delete'].invoke
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
desc "DEPRECATED"
|
194
|
+
task :all do
|
195
|
+
|
196
|
+
puts "DEPRECATED: The 'all' task is deprecated. Use the 'rake create && rake jobs' tasks instead."
|
197
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: torque-vpc-toolkit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Dan Prince
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-01-11 00:00:00 -05:00
|
19
|
+
default_executable: torque-vpc-toolkit
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rake
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: chef-vpc-toolkit
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 2
|
46
|
+
- 0
|
47
|
+
version: "2.0"
|
48
|
+
type: :runtime
|
49
|
+
version_requirements: *id002
|
50
|
+
description: Rake tasks to submit, and poll Torque jobs.
|
51
|
+
email: dan.prince@rackspace.com
|
52
|
+
executables:
|
53
|
+
- torque-vpc-toolkit
|
54
|
+
extensions: []
|
55
|
+
|
56
|
+
extra_rdoc_files:
|
57
|
+
- README.rdoc
|
58
|
+
files:
|
59
|
+
- .gitignore
|
60
|
+
- .rvmrc
|
61
|
+
- COPYING
|
62
|
+
- README.rdoc
|
63
|
+
- Rakefile
|
64
|
+
- VERSION
|
65
|
+
- bin/torque-vpc-toolkit
|
66
|
+
- contrib/conf/jobs.json.example
|
67
|
+
- contrib/rake/Rakefile
|
68
|
+
- lib/torque-vpc-toolkit.rb
|
69
|
+
- rake/torque_vpc_toolkit.rake
|
70
|
+
has_rdoc: true
|
71
|
+
homepage: http://github.com/dprince/torque_vpc_toolkit
|
72
|
+
licenses: []
|
73
|
+
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options:
|
76
|
+
- --charset=UTF-8
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
hash: 3
|
85
|
+
segments:
|
86
|
+
- 0
|
87
|
+
version: "0"
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
hash: 3
|
94
|
+
segments:
|
95
|
+
- 0
|
96
|
+
version: "0"
|
97
|
+
requirements: []
|
98
|
+
|
99
|
+
rubyforge_project:
|
100
|
+
rubygems_version: 1.3.7
|
101
|
+
signing_key:
|
102
|
+
specification_version: 3
|
103
|
+
summary: Rake tasks to submit Torque jobs.
|
104
|
+
test_files: []
|
105
|
+
|