xp5k 0.0.1 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +81 -1
- data/lib/xp5k/config.rb +1 -1
- data/lib/xp5k/exceptions.rb +7 -0
- data/lib/xp5k/role.rb +23 -0
- data/lib/xp5k/version.rb +1 -1
- data/lib/xp5k/xp.rb +41 -14
- data/lib/xp5k.rb +2 -0
- data/xp5k.gemspec +1 -0
- metadata +6 -3
data/README.md
CHANGED
@@ -1,2 +1,82 @@
|
|
1
|
-
|
1
|
+
## Capistrano sample
|
2
|
+
|
3
|
+
require 'xp5k'
|
4
|
+
|
5
|
+
XP5K::Config.load
|
6
|
+
|
7
|
+
@myxp = XP5K::XP.new(:logger => logger)
|
8
|
+
|
9
|
+
@myxp.define_job({
|
10
|
+
:resources => "nodes=2,walltime=1",
|
11
|
+
:site => XP5K::Config[:site] || 'rennes',
|
12
|
+
:types => ["deploy"],
|
13
|
+
:name => "job1",
|
14
|
+
:command => "sleep 86400"
|
15
|
+
})
|
16
|
+
|
17
|
+
@myxp.define_job({
|
18
|
+
:resources => "nodes=6,walltime=1",
|
19
|
+
:site => XP5K::Config[:site] || 'rennes',
|
20
|
+
:types => ["deploy"],
|
21
|
+
:name => "job2",
|
22
|
+
:roles => [
|
23
|
+
XP5K::Role.new({ :name => 'server', :size => 1 }),
|
24
|
+
XP5K::Role.new({ :name => 'nodes', :size => 5 })
|
25
|
+
]
|
26
|
+
:command => "sleep 86400"
|
27
|
+
})
|
28
|
+
|
29
|
+
@myxp.define_deployment({
|
30
|
+
:site => XP5K::Config[:site] || 'rennes',
|
31
|
+
:environment => "squeeze-x64-nfs",
|
32
|
+
:jobs => %w{ job1 },
|
33
|
+
:roles => %w{ server }
|
34
|
+
:key => File.read(XP5K::Config[:public_key])
|
35
|
+
})
|
36
|
+
|
37
|
+
role :job1 do
|
38
|
+
@myxp.job_with_name('job1')['assigned_nodes'].first
|
39
|
+
end
|
40
|
+
|
41
|
+
role :job2 do
|
42
|
+
@myxp.job_with_name('job2')['assigned_nodes'].first
|
43
|
+
end
|
44
|
+
|
45
|
+
role :nodes do
|
46
|
+
@myxp.role_with_name('nodes').servers
|
47
|
+
end
|
48
|
+
|
49
|
+
desc 'Submit jobs'
|
50
|
+
task :submit do
|
51
|
+
@myxp.submit
|
52
|
+
end
|
53
|
+
|
54
|
+
desc 'Deploy with Kadeplopy'
|
55
|
+
task :deploy do
|
56
|
+
@myxp.deploy
|
57
|
+
end
|
58
|
+
|
59
|
+
desc 'Status'
|
60
|
+
task :status do
|
61
|
+
@myxp.status
|
62
|
+
end
|
63
|
+
|
64
|
+
desc 'Remove all running jobs'
|
65
|
+
task :clean do
|
66
|
+
logger.debug "Clean all Grid'5000 running jobs..."
|
67
|
+
@myxp.clean
|
68
|
+
end
|
69
|
+
|
70
|
+
desc 'Run date command'
|
71
|
+
task :date, :roles => [:job1, :job2] do
|
72
|
+
set :user, 'root'
|
73
|
+
run 'date'
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
## _xp.conf_ sample file
|
78
|
+
|
79
|
+
site 'rennes'
|
80
|
+
public_key '/Users/pmorillon/.ssh/id_rsa_g5k.pub'
|
81
|
+
|
2
82
|
|
data/lib/xp5k/config.rb
CHANGED
@@ -14,8 +14,8 @@ module XP5K
|
|
14
14
|
if File.exist?(File.expand_path(File.join(Dir.pwd, 'xp.conf')))
|
15
15
|
file_path = File.expand_path(File.join(Dir.pwd, 'xp.conf'))
|
16
16
|
self.instance_eval(IO.read(file_path),file_path, 1)
|
17
|
+
@@config[:loaded] = true
|
17
18
|
end
|
18
|
-
@@config[:loaded] = true
|
19
19
|
end # def:: self.load
|
20
20
|
|
21
21
|
def self.loaded?
|
data/lib/xp5k/role.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
class XP5K::Role
|
2
|
+
|
3
|
+
attr_accessor :name, :size, :desc, :servers, :jobid
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
# Required parameters
|
7
|
+
@name = ""
|
8
|
+
@size = 0
|
9
|
+
%w{ name size }.each do |param|
|
10
|
+
if options[param.to_sym].nil?
|
11
|
+
raise XP5K::Exceptions::Role, "#{self.to_s}: #{param.to_sym} needed at initialization"
|
12
|
+
else
|
13
|
+
instance_variable_set("@#{param}", options[param.to_sym])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Optional parameters
|
18
|
+
%w{ desc servers }.each do |param|
|
19
|
+
instance_variable_set("@#{param}", options[param.to_sym])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/lib/xp5k/version.rb
CHANGED
data/lib/xp5k/xp.rb
CHANGED
@@ -8,22 +8,23 @@ module XP5K
|
|
8
8
|
|
9
9
|
include Term::ANSIColor
|
10
10
|
|
11
|
-
attr_accessor :jobs, :jobs2submit, :deployments, :todeploy, :connection
|
11
|
+
attr_accessor :jobs, :jobs2submit, :deployments, :todeploy, :connection, :roles
|
12
12
|
attr_reader :starttime
|
13
13
|
|
14
14
|
def initialize(options = {})
|
15
|
-
@jobs
|
15
|
+
@jobs = []
|
16
16
|
@jobs2submit = []
|
17
17
|
@deployments = []
|
18
|
-
@todeploy
|
19
|
-
@
|
20
|
-
@
|
18
|
+
@todeploy = []
|
19
|
+
@roles = []
|
20
|
+
@starttime = Time.now
|
21
|
+
@logger = options[:logger] || Logger.new(STDOUT)
|
21
22
|
XP5K::Config.load unless XP5K::Config.loaded?
|
22
23
|
|
23
24
|
@connection = Restfully::Session.new(
|
24
25
|
:configuration_file => "~/.restfully/api.grid5000.fr.yml",
|
25
26
|
:logger => begin
|
26
|
-
tmplogger
|
27
|
+
tmplogger = ::Logger.new(STDERR)
|
27
28
|
tmplogger.level = ::Logger::WARN
|
28
29
|
tmplogger
|
29
30
|
end
|
@@ -35,6 +36,8 @@ module XP5K
|
|
35
36
|
end
|
36
37
|
|
37
38
|
def define_deployment(deployment_hash)
|
39
|
+
deployment_hash[:jobs] ||= []
|
40
|
+
deployment_hash[:roles] ||= []
|
38
41
|
self.todeploy << deployment_hash
|
39
42
|
end
|
40
43
|
|
@@ -46,16 +49,19 @@ module XP5K
|
|
46
49
|
job = self.job_with_name(jobname)
|
47
50
|
x[:nodes] += job["assigned_nodes"]
|
48
51
|
end
|
52
|
+
x[:roles].each do |rolename|
|
53
|
+
x[:nodes] += role_with_name(rolename).servers
|
54
|
+
end
|
49
55
|
deployment = @connection.root.sites[x[:site].to_sym].deployments.submit(x)
|
50
56
|
self.deployments << { :uid => deployment["uid"], :site => deployment["site_uid"] }
|
51
|
-
update_cache
|
57
|
+
#update_cache
|
52
58
|
puts "Waiting for the deployment ##{deployment['uid']} to be terminated..."
|
53
59
|
while deployment.reload['status'] == 'processing'
|
54
60
|
print(".")
|
55
61
|
sleep 10
|
56
62
|
end
|
57
63
|
print(" [#{green("OK")}]\n")
|
58
|
-
update_cache
|
64
|
+
#update_cache
|
59
65
|
end
|
60
66
|
end
|
61
67
|
|
@@ -68,9 +74,10 @@ module XP5K
|
|
68
74
|
uid = datas["jobs"].select { |x| x["name"] == job_hash[:name] }.first["uid"]
|
69
75
|
unless uid.nil?
|
70
76
|
job = @connection.root.sites[job_hash[:site].to_sym].jobs["#{uid}".to_sym]
|
71
|
-
|
77
|
+
if (not job.nil? or job["state"] == "running")
|
72
78
|
j = job.reload
|
73
79
|
self.jobs << j
|
80
|
+
create_roles(j, job_hash) unless job_hash[:roles].nil?
|
74
81
|
end
|
75
82
|
end
|
76
83
|
end
|
@@ -81,23 +88,45 @@ module XP5K
|
|
81
88
|
job = self.job_with_name(job2submit[:name])
|
82
89
|
if job.nil?
|
83
90
|
job = @connection.root.sites[job2submit[:site].to_sym].jobs.submit(job2submit)
|
84
|
-
self.jobs << job
|
91
|
+
self.jobs << { :uid => job.properties['uid'], :name => job.properties['name'] }
|
85
92
|
update_cache
|
86
93
|
logger.info "Waiting for the job #{job["name"]} ##{job['uid']} to be running at #{job2submit[:site]}..."
|
87
94
|
while job.reload["state"] != "running"
|
88
95
|
print(".")
|
89
96
|
sleep 3
|
90
97
|
end
|
98
|
+
create_roles(job, job2submit) unless job2submit[:roles].nil?
|
91
99
|
print(" [#{green("OK")}]\n")
|
92
|
-
|
100
|
+
else
|
101
|
+
logger.info "Job #{job["name"]} already submitted ##{job["uid"]}"
|
93
102
|
end
|
94
103
|
end
|
95
104
|
end
|
96
105
|
|
106
|
+
def create_roles(job, job_definition)
|
107
|
+
count_needed_nodes = 0
|
108
|
+
job_definition[:roles].each { |role| count_needed_nodes += role.size }
|
109
|
+
if job['assigned_nodes'].length < count_needed_nodes
|
110
|
+
self.clean
|
111
|
+
raise "Job ##{job['uid']} require more nodes for required roles"
|
112
|
+
end
|
113
|
+
available_nodes = job['assigned_nodes'].sort
|
114
|
+
job_definition[:roles].each do |role|
|
115
|
+
role.servers = available_nodes[0..(role.size - 1)]
|
116
|
+
available_nodes -= role.servers
|
117
|
+
role.jobid = job['uid']
|
118
|
+
self.roles << role
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
97
122
|
def job_with_name(name)
|
98
123
|
self.jobs.select { |x| x["name"] == name }.first
|
99
124
|
end
|
100
125
|
|
126
|
+
def role_with_name(name)
|
127
|
+
self.roles.select { |x| x.name == name}.first
|
128
|
+
end
|
129
|
+
|
101
130
|
def status
|
102
131
|
# self.jobs2submit.each do |job2submit|
|
103
132
|
# job = self.job_with_name(job2submit[:name])
|
@@ -125,9 +154,7 @@ module XP5K
|
|
125
154
|
end
|
126
155
|
|
127
156
|
def update_cache
|
128
|
-
cache = { :jobs => self.jobs.
|
129
|
-
:deployments => self.deployments
|
130
|
-
}
|
157
|
+
cache = { :jobs => self.jobs.map { |x| { :uid => x[:uid], :name => x[:name] } } }
|
131
158
|
open(".xp_cache", "w") do |f|
|
132
159
|
f.puts cache.to_json
|
133
160
|
end
|
data/lib/xp5k.rb
CHANGED
data/xp5k.gemspec
CHANGED
@@ -8,6 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
9
|
s.authors = ['Pascal Morillon']
|
10
10
|
s.email = ['pascal.morillon@irisa.fr']
|
11
|
+
s.license = 'MIT'
|
11
12
|
s.homepage = 'https://github.com/pmorillon/xp5k'
|
12
13
|
s.summary = %q{A small Grid'5000 helper to submit jobs and deploy environments via REST API}
|
13
14
|
s.description = %q{A small Grid'5000 helper to submit jobs and deploy environments via REST API}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xp5k
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-08-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: restfully
|
@@ -90,11 +90,14 @@ files:
|
|
90
90
|
- README.md
|
91
91
|
- lib/xp5k.rb
|
92
92
|
- lib/xp5k/config.rb
|
93
|
+
- lib/xp5k/exceptions.rb
|
94
|
+
- lib/xp5k/role.rb
|
93
95
|
- lib/xp5k/version.rb
|
94
96
|
- lib/xp5k/xp.rb
|
95
97
|
- xp5k.gemspec
|
96
98
|
homepage: https://github.com/pmorillon/xp5k
|
97
|
-
licenses:
|
99
|
+
licenses:
|
100
|
+
- MIT
|
98
101
|
post_install_message:
|
99
102
|
rdoc_options: []
|
100
103
|
require_paths:
|