pbs 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,103 @@
1
+ module PBS
2
+ class Query
3
+ attr_reader :type
4
+ attr_reader :conn
5
+ attr_accessor :where_procs
6
+
7
+ STATTYPE = {job: :pbs_statjob, queue: :pbs_statque,
8
+ node: :pbs_statnode, server: :pbs_statserver}
9
+
10
+ # Needs a connection object and a query type
11
+ # Query types: :job, :queue, :server, :node
12
+ def initialize(args = {})
13
+ @conn = args[:conn] || Conn.new
14
+ @type = args[:type] || :job
15
+ @where_procs = []
16
+ end
17
+
18
+ # Boolean procs used to filter out query results
19
+ # Examples:
20
+ # where {|h| h[PBS::ATTR[:N]] == "SimpleJob"}
21
+ # where(PBS::ATTR[:N]) {|v| v == "SimpleJob"}
22
+ # where
23
+ # the last one is used with other methods
24
+ # i.e., where.not(PBS::ATTR[:N]) => "SimpleJob")
25
+ def where(arg = nil, &block)
26
+ relation = self.clone
27
+ relation.where_procs = @where_procs.clone
28
+ relation.where_procs << (arg ? Proc.new {|h| block.call(h[arg])} : block)
29
+ relation
30
+ end
31
+
32
+ # Used to filter where key attrib is equal to value
33
+ # where.is(PBS::ATTR[:N] => "SimpleJob")
34
+ def is(hash)
35
+ key, value = hash.first
36
+ raise PBS::Error, "`where' method not called before" if where_procs.empty? || where_procs[-1]
37
+ self.where_procs[-1] = Proc.new {|h| h[key] == value}
38
+ self
39
+ end
40
+
41
+ # Used to filter where key attrib is NOT equal to value
42
+ # where.not(PBS::ATTR[:N] => "SimpleJob")
43
+ def not(hash)
44
+ key, value = hash.first
45
+ raise PBS::Error, "`where' method not called before" if where_procs.empty? || where_procs[-1]
46
+ self.where_procs[-1] = Proc.new {|h| h[key] != value}
47
+ self
48
+ end
49
+
50
+ # Used to filter specific user
51
+ # where.user("username")
52
+ def user(name)
53
+ raise PBS::Error, "`where' method not called before" if where_procs.empty? || where_procs[-1]
54
+ self.where_procs[-1] = Proc.new {|h| /^#{name}@/ =~ h[ATTR[:owner]]}
55
+ self
56
+ end
57
+
58
+ def find(args = {})
59
+ id = args[:id] || nil
60
+ filters = args[:filters]
61
+ filters = [args[:filter]] if args[:filter]
62
+
63
+ # Get array of batch status hashes
64
+ batch_list = _pbs_batchstat(id, filters)
65
+
66
+ # Further filter results and then output them
67
+ _filter_where_values(batch_list)
68
+ end
69
+
70
+ # Filter an array of hashes based on the defined where procs
71
+ # Comparisons are done inside the :attribs hash only
72
+ def _filter_where_values(array)
73
+ array.select do |hash|
74
+ pass = true
75
+ where_procs.each do |p|
76
+ pass = false unless p.call(hash[:attribs])
77
+ end
78
+ pass
79
+ end
80
+ end
81
+
82
+ # Connect, get status on batch server,
83
+ # disconnect, parse output, and finally check for errors
84
+ # Don't forget to free up memory the C-library creates
85
+ def _pbs_batchstat(id, filters)
86
+ # Generate attribute list from filter list
87
+ attrib_list = PBS::Torque::Attrl.from_list(filters) if filters
88
+
89
+ batch_status = nil
90
+ conn.connect unless conn.connected?
91
+ if type == :server
92
+ batch_status = Torque.send(STATTYPE[type], conn.conn_id, attrib_list, nil)
93
+ else
94
+ batch_status = Torque.send(STATTYPE[type], conn.conn_id, id, attrib_list, nil)
95
+ end
96
+ conn.disconnect
97
+ batch_list = batch_status.to_a
98
+ Torque.pbs_statfree(batch_status)
99
+ Torque.check_for_error
100
+ batch_list
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,305 @@
1
+ require "ffi"
2
+
3
+ module PBS
4
+ module Torque
5
+ extend FFI::Library
6
+
7
+ # Define torque methods using a supplied library
8
+ def self.init(args = {})
9
+ @@lib = args[:lib] || "torque"
10
+
11
+ # Set up FFI to use this library
12
+ ffi_lib @@lib
13
+
14
+ # int pbs_errno
15
+ attach_variable :pbs_errno, :int
16
+
17
+ # char *pbs_server
18
+ attach_variable :pbs_server, :string
19
+
20
+ # int pbs_connect(char *server)
21
+ attach_function :pbs_connect, [ :pointer ], :int
22
+
23
+ # char *pbs_default(void)
24
+ attach_function :pbs_default, [], :string
25
+
26
+ # char *pbs_strerror(int errno)
27
+ attach_function :pbs_strerror, [ :int ], :string
28
+
29
+ # int pbs_deljob(int connect, char *job_id, char *extend)
30
+ attach_function :pbs_deljob, [ :int, :pointer, :pointer ], :int
31
+
32
+ # int pbs_disconnect(int connect)
33
+ attach_function :pbs_disconnect, [ :int ], :int
34
+
35
+ # int pbs_holdjob(int connect, char *job_id, char *hold_type, char *extend)
36
+ attach_function :pbs_holdjob, [ :int, :pointer, :pointer, :pointer ], :int
37
+
38
+ # int pbs_rlsjob(int connect, char *job_id, char *hold_type, char *extend)
39
+ attach_function :pbs_rlsjob, [ :int, :pointer, :pointer, :pointer ], :int
40
+
41
+ # void pbs_statfree(struct batch_status *stat)
42
+ attach_function :pbs_statfree, [ :pointer ], :void
43
+
44
+ # batch_status * pbs_statjob(int connect, char *id, struct attrl *attrib, char *extend)
45
+ attach_function :pbs_statjob, [ :int, :pointer, :pointer, :pointer ], BatchStatus.ptr
46
+
47
+ # batch_status * pbs_statnode(int connect, char *id, struct attrl *attrib, char *extend)
48
+ attach_function :pbs_statnode, [ :int, :pointer, :pointer, :pointer ], BatchStatus.ptr
49
+
50
+ # batch_status * pbs_statque(int connect, char *id, struct attrl *attrib, char *extend)
51
+ attach_function :pbs_statque, [ :int, :pointer, :pointer, :pointer ], BatchStatus.ptr
52
+
53
+ # batch_status * pbs_statserver(int connect, struct attrl *attrib, char *extend)
54
+ attach_function :pbs_statserver, [ :int, :pointer, :pointer ], BatchStatus.ptr
55
+
56
+ # char *pbs_submit(int connect, struct attropl *attrib, char *script, char *destination, char *extend)
57
+ attach_function :pbs_submit, [ :int, :pointer, :pointer, :pointer, :pointer ], :string
58
+ end
59
+
60
+ def self.check_for_error
61
+ errno = pbs_errno
62
+ self.pbs_errno = 0 # reset error number
63
+ raise_error(errno) if errno > 0
64
+ end
65
+
66
+ def self.raise_error(errno)
67
+ raise (ERROR_CODES[errno] || PBS::Error), "#{pbs_strerror(errno)}"
68
+ end
69
+
70
+ # Data structures defined in pbs_ifl.h
71
+
72
+ # Enum for Batch Operation
73
+ BatchOp = enum(:set, :unset, :incr, :decr, :eq, :ne, :ge, :gt, :le, :lt, :dflt, :merge, :incr_old)
74
+
75
+ # Struct for Attribute C-linked list
76
+ class Attrl < FFI::Struct
77
+ layout :next, Attrl.ptr, # pointer to next Attrl object
78
+ :name, :pointer, # string for name of attribute
79
+ :resource, :pointer, # string for resource if this attribute is a resource
80
+ :value, :pointer, # string for value of attribute
81
+ :op, BatchOp # not used in an Attrl object
82
+
83
+ def self.from_list(list)
84
+ attrl = nil
85
+ prev = Attrl.new(FFI::Pointer::NULL)
86
+ list.each do |key|
87
+ attrl = Attrl.new
88
+ attrl[:name] = FFI::MemoryPointer.from_string(key.to_s)
89
+ attrl[:resource] = FFI::Pointer::NULL
90
+ attrl[:value] = FFI::Pointer::NULL
91
+ attrl[:op] = 0
92
+ attrl[:next] = prev
93
+ prev = attrl
94
+ end
95
+ attrl
96
+ end
97
+
98
+ def to_hash
99
+ hash = Hash.new{ |h,k| h[k] = Hash.new() }
100
+ attrl = self
101
+ until attrl.to_ptr.null?
102
+ name = attrl[:name].read_string.to_sym
103
+ value = attrl[:value].read_string
104
+ resource = nil
105
+ resource = attrl[:resource].read_string.to_sym unless attrl[:resource].null?
106
+ if resource.nil?
107
+ hash[name] = value
108
+ else
109
+ hash[name][resource] = value
110
+ end
111
+ attrl = attrl[:next]
112
+ end
113
+ hash
114
+ end
115
+ end
116
+
117
+ # Struct for Attribute Operation C-linked list
118
+ class Attropl < FFI::Struct
119
+ layout :next, Attropl.ptr, # pointer to next Attropl object
120
+ :name, :pointer, # string for name of attribute
121
+ :resource, :pointer, # string for resource if this attribute is a resource
122
+ :value, :pointer, # string for value of attribute
123
+ :op, BatchOp # operation to perform for this attribute
124
+
125
+ def self.from_hash(hash)
126
+ # Convert hash into array
127
+ # Format: {name: value, name: {resource: value, resource: value}}
128
+ # {a: 1, b: {c: 2, d: 3}} => [[:a,1],[:b,2,:c],[:b,3,:d]]
129
+ ary = hash.map{|k,v| [*v].map{|v2| [k,*[*v2].reverse]}}.flatten(1)
130
+ attropl = nil
131
+ prev = Attropl.new(FFI::Pointer::NULL)
132
+ ary.each do |attrib|
133
+ attropl = Attropl.new
134
+ attropl[:name] = FFI::MemoryPointer.from_string(attrib[0].to_s)
135
+ attropl[:value] = FFI::MemoryPointer.from_string(attrib[1])
136
+ attropl[:resource] = FFI::MemoryPointer.from_string(attrib[2].to_s) unless attrib[2].nil?
137
+ attropl[:op] = 0
138
+ attropl[:next] = prev
139
+ prev = attropl
140
+ end
141
+ attropl
142
+ end
143
+ end
144
+
145
+ # Struct for status of batch
146
+ class BatchStatus < FFI::ManagedStruct
147
+ layout :next, BatchStatus.ptr, # pointer to next BatchStatus object
148
+ :name, :string, # string for name of this status
149
+ :attribs, Attrl.ptr, # pointer to beginning of C-linked list of an Attrl object
150
+ :text, :string # string containing unknown text
151
+
152
+ def self.release(ptr)
153
+ pbs_statfree(ptr)
154
+ end
155
+
156
+ def to_a
157
+ ary = []
158
+ batch = self
159
+ until batch.to_ptr.null?
160
+ ary << {name: batch[:name], attribs: batch[:attribs].to_hash}
161
+ batch = batch[:next]
162
+ end
163
+ ary
164
+ end
165
+ end
166
+
167
+ # Defined error codes
168
+ # valid as of Torque >=4.2.10
169
+ ERROR_CODES = {
170
+ 15001 => PBS::UnkjobidError,
171
+ 15002 => PBS::NoattrError,
172
+ 15003 => PBS::AttrroError,
173
+ 15004 => PBS::IvalreqError,
174
+ 15005 => PBS::UnkreqError,
175
+ 15006 => PBS::ToomanyError,
176
+ 15007 => PBS::PermError,
177
+ 15008 => PBS::IffNotFoundError,
178
+ 15009 => PBS::MungeNotFoundError,
179
+ 15010 => PBS::BadhostError,
180
+ 15011 => PBS::JobexistError,
181
+ 15012 => PBS::SystemError,
182
+ 15013 => PBS::InternalError,
183
+ 15014 => PBS::RegrouteError,
184
+ 15015 => PBS::UnksigError,
185
+ 15016 => PBS::BadatvalError,
186
+ 15017 => PBS::ModatrrunError,
187
+ 15018 => PBS::BadstateError,
188
+ 15020 => PBS::UnkqueError,
189
+ 15021 => PBS::BadcredError,
190
+ 15022 => PBS::ExpiredError,
191
+ 15023 => PBS::QunoenbError,
192
+ 15024 => PBS::QacessError,
193
+ 15025 => PBS::BaduserError,
194
+ 15026 => PBS::HopcountError,
195
+ 15027 => PBS::QueexistError,
196
+ 15028 => PBS::AttrtypeError,
197
+ 15029 => PBS::QuebusyError,
198
+ 15030 => PBS::QuenbigError,
199
+ 15031 => PBS::NosupError,
200
+ 15032 => PBS::QuenoenError,
201
+ 15033 => PBS::ProtocolError,
202
+ 15034 => PBS::BadatlstError,
203
+ 15035 => PBS::NoconnectsError,
204
+ 15036 => PBS::NoserverError,
205
+ 15037 => PBS::UnkrescError,
206
+ 15038 => PBS::ExcqrescError,
207
+ 15039 => PBS::QuenodfltError,
208
+ 15040 => PBS::NorerunError,
209
+ 15041 => PBS::RouterejError,
210
+ 15042 => PBS::RouteexpdError,
211
+ 15043 => PBS::MomrejectError,
212
+ 15044 => PBS::BadscriptError,
213
+ 15045 => PBS::StageinError,
214
+ 15046 => PBS::RescunavError,
215
+ 15047 => PBS::BadgrpError,
216
+ 15048 => PBS::MaxquedError,
217
+ 15049 => PBS::CkpbsyError,
218
+ 15050 => PBS::ExlimitError,
219
+ 15051 => PBS::BadacctError,
220
+ 15052 => PBS::AlrdyexitError,
221
+ 15053 => PBS::NocopyfileError,
222
+ 15054 => PBS::CleanedoutError,
223
+ 15055 => PBS::NosyncmstrError,
224
+ 15056 => PBS::BaddependError,
225
+ 15057 => PBS::DuplistError,
226
+ 15058 => PBS::DisprotoError,
227
+ 15059 => PBS::ExecthereError,
228
+ 15060 => PBS::SisrejectError,
229
+ 15061 => PBS::SiscommError,
230
+ 15062 => PBS::SvrdownError,
231
+ 15063 => PBS::CkpshortError,
232
+ 15064 => PBS::UnknodeError,
233
+ 15065 => PBS::UnknodeatrError,
234
+ 15066 => PBS::NonodesError,
235
+ 15067 => PBS::NodenbigError,
236
+ 15068 => PBS::NodeexistError,
237
+ 15069 => PBS::BadndatvalError,
238
+ 15070 => PBS::MutualexError,
239
+ 15071 => PBS::GmoderrError,
240
+ 15072 => PBS::NorelymomError,
241
+ 15073 => PBS::NotsnodeError,
242
+ 15074 => PBS::JobtypeError,
243
+ 15075 => PBS::BadaclhostError,
244
+ 15076 => PBS::MaxuserquedError,
245
+ 15077 => PBS::BaddisallowtypeError,
246
+ 15078 => PBS::NointeractiveError,
247
+ 15079 => PBS::NobatchError,
248
+ 15080 => PBS::NorerunableError,
249
+ 15081 => PBS::NononrerunableError,
250
+ 15082 => PBS::UnkarrayidError,
251
+ 15083 => PBS::BadArrayReqError,
252
+ 15084 => PBS::BadArrayDataError,
253
+ 15085 => PBS::TimeoutError,
254
+ 15086 => PBS::JobnotfoundError,
255
+ 15087 => PBS::NofaulttolerantError,
256
+ 15088 => PBS::NofaultintolerantError,
257
+ 15089 => PBS::NojobarraysError,
258
+ 15090 => PBS::RelayedToMomError,
259
+ 15091 => PBS::MemMallocError,
260
+ 15092 => PBS::MutexError,
261
+ 15093 => PBS::ThreadattrError,
262
+ 15094 => PBS::ThreadError,
263
+ 15095 => PBS::SelectError,
264
+ 15096 => PBS::SocketFaultError,
265
+ 15097 => PBS::SocketWriteError,
266
+ 15098 => PBS::SocketReadError,
267
+ 15099 => PBS::SocketCloseError,
268
+ 15100 => PBS::SocketListenError,
269
+ 15101 => PBS::AuthInvalidError,
270
+ 15102 => PBS::NotImplementedError,
271
+ 15103 => PBS::QuenotavailableError,
272
+ 15104 => PBS::TmpdiffownerError,
273
+ 15105 => PBS::TmpnotdirError,
274
+ 15106 => PBS::TmpnonameError,
275
+ 15107 => PBS::CantopensocketError,
276
+ 15108 => PBS::CantcontactsistersError,
277
+ 15109 => PBS::CantcreatetmpdirError,
278
+ 15110 => PBS::BadmomstateError,
279
+ 15111 => PBS::SocketInformationError,
280
+ 15112 => PBS::SocketDataError,
281
+ 15113 => PBS::ClientInvalidError,
282
+ 15114 => PBS::PrematureEofError,
283
+ 15115 => PBS::CanNotSaveFileError,
284
+ 15116 => PBS::CanNotOpenFileError,
285
+ 15117 => PBS::CanNotWriteFileError,
286
+ 15118 => PBS::JobFileCorruptError,
287
+ 15119 => PBS::JobRerunError,
288
+ 15120 => PBS::ConnectError,
289
+ 15121 => PBS::JobworkdelayError,
290
+ 15122 => PBS::BadParameterError,
291
+ 15123 => PBS::ContinueError,
292
+ 15124 => PBS::JobsubstateError,
293
+ 15125 => PBS::CanNotMoveFileError,
294
+ 15126 => PBS::JobRecycledError,
295
+ 15127 => PBS::JobAlreadyInQueueError,
296
+ 15128 => PBS::InvalidMutexError,
297
+ 15129 => PBS::MutexAlreadyLockedError,
298
+ 15130 => PBS::MutexAlreadyUnlockedError,
299
+ 15131 => PBS::InvalidSyntaxError,
300
+ 15132 => PBS::NodeDownError,
301
+ 15133 => PBS::ServerNotFoundError,
302
+ 15134 => PBS::ServerBusyError,
303
+ }
304
+ end
305
+ end
@@ -0,0 +1,3 @@
1
+ module PBS
2
+ VERSION = "1.1.3"
3
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pbs/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "pbs"
8
+ spec.version = PBS::VERSION
9
+ spec.platform = Gem::Platform::RUBY
10
+ spec.authors = ["Jeremy Nicklas"]
11
+ spec.email = ["jnicklas@osc.edu"]
12
+ spec.summary = %q{PBS FFI Ruby gem to use FFI to interface with Adaptive Computing's resource manager Torque}
13
+ spec.description = %q{PBS FFI Ruby gem to use FFI to interface with Adaptive Computing's resource manager Torque}
14
+ spec.homepage = "https://github.com/OSC/pbs-ruby"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_runtime_dependency "ffi", "~> 1.9", ">= 1.9.6"
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pbs
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.3
5
+ platform: ruby
6
+ authors:
7
+ - Jeremy Nicklas
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-06-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ffi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.9'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.9.6
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.9'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.9.6
33
+ - !ruby/object:Gem::Dependency
34
+ name: bundler
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.3'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.3'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ description: PBS FFI Ruby gem to use FFI to interface with Adaptive Computing's resource
62
+ manager Torque
63
+ email:
64
+ - jnicklas@osc.edu
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - ".gitignore"
70
+ - Gemfile
71
+ - LICENSE.txt
72
+ - README.md
73
+ - Rakefile
74
+ - config/batch.yml
75
+ - config/websvcs02.osc.edu.yml
76
+ - config/websvcs08.osc.edu.yml
77
+ - examples/simplejob.rb
78
+ - lib/pbs.rb
79
+ - lib/pbs/attributes.rb
80
+ - lib/pbs/conn.rb
81
+ - lib/pbs/error.rb
82
+ - lib/pbs/job.rb
83
+ - lib/pbs/query.rb
84
+ - lib/pbs/torque.rb
85
+ - lib/pbs/version.rb
86
+ - pbs.gemspec
87
+ homepage: https://github.com/OSC/pbs-ruby
88
+ licenses:
89
+ - MIT
90
+ metadata: {}
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubyforge_project:
107
+ rubygems_version: 2.4.8
108
+ signing_key:
109
+ specification_version: 4
110
+ summary: PBS FFI Ruby gem to use FFI to interface with Adaptive Computing's resource
111
+ manager Torque
112
+ test_files: []