pbs 1.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +34 -0
- data/Rakefile +1 -0
- data/config/batch.yml +24 -0
- data/config/websvcs02.osc.edu.yml +24 -0
- data/config/websvcs08.osc.edu.yml +18 -0
- data/examples/simplejob.rb +66 -0
- data/lib/pbs.rb +38 -0
- data/lib/pbs/attributes.rb +110 -0
- data/lib/pbs/conn.rb +75 -0
- data/lib/pbs/error.rb +403 -0
- data/lib/pbs/job.rb +189 -0
- data/lib/pbs/query.rb +103 -0
- data/lib/pbs/torque.rb +305 -0
- data/lib/pbs/version.rb +3 -0
- data/pbs.gemspec +25 -0
- metadata +112 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b86e26918976f01fb7df0c1add6b90fe7d72bb62
|
4
|
+
data.tar.gz: ceb18d0411222ecf32bcca3c2c5a50df95faa5ad
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ba43a215a3fcf0db521e1cb7fdedadf1b022d96afe4b7d31a9688a7274a10b511bfe3c2d9e121a979eb6529979fb5078b4838148b77de456b1a44c50cdca628c
|
7
|
+
data.tar.gz: 86d41f545c90f662d35aa3a5971b57c14e8c1a74aaf6f847559406e2ea0a73f06b7fdadde79f8c04e26b696ae035b386aee716076d450500c131d929b31eaefd
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014-2016 Ohio Supercomputer Center
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# PBS Ruby
|
2
|
+
|
3
|
+
## Description
|
4
|
+
|
5
|
+
Trimmed down Ruby wrapper for the Torque C Library utilizing Ruby-FFI.
|
6
|
+
|
7
|
+
## Requirements
|
8
|
+
|
9
|
+
At minimum you will need:
|
10
|
+
* Ruby 2.0
|
11
|
+
* Ruby-FFI gem
|
12
|
+
* Torque >= 4.2.10
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this to your application's Gemfile:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
gem 'pbs'
|
20
|
+
```
|
21
|
+
|
22
|
+
And then execute:
|
23
|
+
|
24
|
+
```bash
|
25
|
+
$ bundle install
|
26
|
+
```
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
Most useful features are outlined in the `examples/simplejob.rb` provided. To run this simple example, type:
|
31
|
+
|
32
|
+
```bash
|
33
|
+
$ ruby -Ilib examples/simplejob.rb
|
34
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/config/batch.yml
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
oakley: &oakley
|
2
|
+
lib: '/usr/local/torque/default/lib/libtorque.so'
|
3
|
+
server: &oakley_server 'oak-batch.osc.edu'
|
4
|
+
qsub: 'LD_LIBRARY_PATH=/usr/local/torque/default/lib:$LD_LIBRARY_PATH /usr/local/torque/default/bin/qsub'
|
5
|
+
*oakley_server:
|
6
|
+
<<: *oakley
|
7
|
+
ruby: &ruby
|
8
|
+
lib: '/usr/local/torque/default/lib/libtorque.so'
|
9
|
+
server: &ruby_server 'ruby-batch.ten.osc.edu'
|
10
|
+
qsub: 'LD_LIBRARY_PATH=/usr/local/torque/default/lib:$LD_LIBRARY_PATH /usr/local/torque/default/bin/qsub'
|
11
|
+
*ruby_server:
|
12
|
+
<<: *ruby
|
13
|
+
oxymoron: &oxymoron
|
14
|
+
lib: '/usr/local/torque/default/lib/libtorque.so'
|
15
|
+
server: &oxymoron_server 'oak-batch.osc.edu:17001'
|
16
|
+
qsub: 'LD_LIBRARY_PATH=/usr/local/torque/default/lib:$LD_LIBRARY_PATH /usr/local/torque/default/bin/qsub'
|
17
|
+
*oxymoron_server:
|
18
|
+
<<: *oxymoron
|
19
|
+
quick: &quick
|
20
|
+
lib: '/usr/local/torque/default/lib/libtorque.so'
|
21
|
+
server: &quick_server 'quick-batch.osc.edu'
|
22
|
+
qsub: 'LD_LIBRARY_PATH=/usr/local/torque/default/lib:$LD_LIBRARY_PATH /usr/local/torque/default/bin/qsub'
|
23
|
+
*quick_server:
|
24
|
+
<<: *quick
|
@@ -0,0 +1,24 @@
|
|
1
|
+
oakley: &oakley
|
2
|
+
lib: '/usr/local/torque-4.2.8/lib/libtorque.so'
|
3
|
+
server: &oakley_server 'oak-batch.osc.edu'
|
4
|
+
qsub: 'LD_LIBRARY_PATH=/usr/local/torque-4.2.8/lib:$LD_LIBRARY_PATH /usr/local/torque-4.2.8/bin/qsub'
|
5
|
+
*oakley_server:
|
6
|
+
<<: *oakley
|
7
|
+
ruby: &ruby
|
8
|
+
lib: '/usr/local/torque-4.2.8/lib/libtorque.so'
|
9
|
+
server: &ruby_server 'ruby-batch.ten.osc.edu'
|
10
|
+
qsub: 'LD_LIBRARY_PATH=/usr/local/torque-4.2.8/lib:$LD_LIBRARY_PATH /usr/local/torque-4.2.8/bin/qsub'
|
11
|
+
*ruby_server:
|
12
|
+
<<: *ruby
|
13
|
+
oxymoron: &oxymoron
|
14
|
+
lib: '/usr/local/torque-4.2.8/lib/libtorque.so'
|
15
|
+
server: &oxymoron_server 'oak-batch.osc.edu:17001'
|
16
|
+
qsub: 'LD_LIBRARY_PATH=/usr/local/torque-4.2.8/lib:$LD_LIBRARY_PATH /usr/local/torque-4.2.8/bin/qsub'
|
17
|
+
*oxymoron_server:
|
18
|
+
<<: *oxymoron
|
19
|
+
quick: &quick
|
20
|
+
lib: '/usr/local/torque-4.2.8/lib/libtorque.so'
|
21
|
+
server: &quick_server 'quick-batch.osc.edu'
|
22
|
+
qsub: 'LD_LIBRARY_PATH=/usr/local/torque-4.2.8/lib:$LD_LIBRARY_PATH /usr/local/torque-4.2.8/bin/qsub'
|
23
|
+
*quick_server:
|
24
|
+
<<: *quick
|
@@ -0,0 +1,18 @@
|
|
1
|
+
oakley: &oakley
|
2
|
+
lib: '/usr/local/torque/5.1.1-1_fba25d92/lib/libtorque.so'
|
3
|
+
server: &oakley_server 'oak-batch.osc.edu'
|
4
|
+
qsub: 'LD_LIBRARY_PATH=/usr/local/torque/5.1.1-1_fba25d92/lib:$LD_LIBRARY_PATH /usr/local/torque/5.1.1-1_fba25d92/bin/qsub'
|
5
|
+
*oakley_server:
|
6
|
+
<<: *oakley
|
7
|
+
ruby: &ruby
|
8
|
+
lib: '/usr/local/torque/5.1.1-1_fba25d92/lib/libtorque.so'
|
9
|
+
server: &ruby_server 'ruby-batch.ten.osc.edu'
|
10
|
+
qsub: 'LD_LIBRARY_PATH=/usr/local/torque/5.1.1-1_fba25d92/lib:$LD_LIBRARY_PATH /usr/local/torque/5.1.1-1_fba25d92/bin/qsub'
|
11
|
+
*ruby_server:
|
12
|
+
<<: *ruby
|
13
|
+
quick: &quick
|
14
|
+
lib: '/usr/local/torque/5.1.1-1_fba25d92/lib/libtorque.so'
|
15
|
+
server: &quick_server 'quick-batch.osc.edu'
|
16
|
+
qsub: 'LD_LIBRARY_PATH=/usr/local/torque/5.1.1-1_fba25d92/lib:$LD_LIBRARY_PATH /usr/local/torque/5.1.1-1_fba25d92/bin/qsub'
|
17
|
+
*quick_server:
|
18
|
+
<<: *quick
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'pbs'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
# Set up connection to local server
|
5
|
+
c = PBS::Conn.batch 'oakley'
|
6
|
+
|
7
|
+
# Check info for local server
|
8
|
+
q = PBS::Query.new(conn: c, type: :server)
|
9
|
+
puts "# Batch server information ---"
|
10
|
+
puts q.find.to_yaml
|
11
|
+
puts ""
|
12
|
+
|
13
|
+
# Check if I have any jobs currently running
|
14
|
+
q = PBS::Query.new(conn: c, type: :job)
|
15
|
+
filters = [PBS::ATTR[:state], PBS::ATTR[:owner]]
|
16
|
+
puts "# All jobs you currently have in the batch ---"
|
17
|
+
puts q.where.user(ENV['USER']).find(filters: filters).to_yaml
|
18
|
+
puts ""
|
19
|
+
|
20
|
+
# Setup new job
|
21
|
+
j = PBS::Job.new(conn: c)
|
22
|
+
|
23
|
+
headers = { PBS::ATTR[:N] => "SimpleJob" }
|
24
|
+
resources = { walltime: "00:10:00" }
|
25
|
+
envvars = { WORLD: "world" }
|
26
|
+
script = "echo \"Hello ${WORLD}!\""
|
27
|
+
|
28
|
+
|
29
|
+
# Submit new job
|
30
|
+
puts "# Submitting new job ---"
|
31
|
+
puts j.submit(string: script, headers: headers, resources: resources, envvars: envvars, qsub: true).id
|
32
|
+
puts ""
|
33
|
+
|
34
|
+
# Show details of new job
|
35
|
+
puts "# Details of submitted job ---"
|
36
|
+
puts j.status.to_yaml
|
37
|
+
puts ""
|
38
|
+
|
39
|
+
# Hold job
|
40
|
+
puts "# Holding job now ---"
|
41
|
+
j.hold
|
42
|
+
puts j.status(filter: PBS::ATTR[:state]).to_yaml
|
43
|
+
puts ""
|
44
|
+
|
45
|
+
# Show only jobs on hold
|
46
|
+
puts "# All running jobs on hold ---"
|
47
|
+
puts q.where.user(ENV['USER']).where(PBS::ATTR[:state]) {|v| v == 'H'}.find(filters: filters).to_yaml
|
48
|
+
puts ""
|
49
|
+
puts "# All running jobs not on hold ---"
|
50
|
+
puts q.where.user(ENV['USER']).where.not(PBS::ATTR[:state] => 'H').find(filters: filters).to_yaml
|
51
|
+
puts ""
|
52
|
+
puts "# All running jobs not queued ---"
|
53
|
+
puts q.where.user(ENV['USER']).where.is(PBS::ATTR[:state] => 'H').find(filters: filters).to_yaml
|
54
|
+
puts ""
|
55
|
+
|
56
|
+
# Release job
|
57
|
+
puts "# Releasing job now ---"
|
58
|
+
j.release
|
59
|
+
puts j.status(filter: PBS::ATTR[:state]).to_yaml
|
60
|
+
puts ""
|
61
|
+
|
62
|
+
# Delete submitted job
|
63
|
+
puts "# Deleting job now ---"
|
64
|
+
j.delete
|
65
|
+
puts "Complete."
|
66
|
+
puts ""
|
data/lib/pbs.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
require_relative 'pbs/error'
|
5
|
+
require_relative 'pbs/attributes'
|
6
|
+
require_relative 'pbs/torque'
|
7
|
+
require_relative 'pbs/conn'
|
8
|
+
require_relative 'pbs/query'
|
9
|
+
require_relative 'pbs/job'
|
10
|
+
require_relative 'pbs/version'
|
11
|
+
|
12
|
+
module PBS
|
13
|
+
# Path to the batch config yaml file describing the batch servers for
|
14
|
+
# local batch schedulers.
|
15
|
+
# @return [String] Path to the batch config yaml file.
|
16
|
+
def self.default_batch_config_path
|
17
|
+
default_config = File.expand_path("../../config/batch.yml", __FILE__)
|
18
|
+
host_config = File.expand_path("../../config/#{Socket.gethostname}.yml", __FILE__)
|
19
|
+
File.file?(host_config) ? host_config : default_config
|
20
|
+
end
|
21
|
+
|
22
|
+
# Get the path to the batch config yaml file.
|
23
|
+
def self.batch_config_path
|
24
|
+
@batch_config_path ||= self.default_batch_config_path
|
25
|
+
end
|
26
|
+
|
27
|
+
# Set the path to the batch config yaml file.
|
28
|
+
# @param path [String] The path to the batch config yaml file.
|
29
|
+
def self.batch_config_path=(path)
|
30
|
+
@batch_config_path = File.expand_path(path)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Hash generated from reading the batch config yaml file.
|
34
|
+
# @return [Hash] Batch configuration generated from config yaml file.
|
35
|
+
def self.batch_config
|
36
|
+
YAML.load_file(batch_config_path)
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# Maintains a constant Hash of defined PBS attribute types
|
2
|
+
#
|
3
|
+
# Includes:
|
4
|
+
# Attribute names used by user commands
|
5
|
+
# Additional job and general attribute names
|
6
|
+
# Additional queue attribute names
|
7
|
+
# Additional server attribute names
|
8
|
+
# Additional node attribute names
|
9
|
+
module PBS
|
10
|
+
ATTR = {
|
11
|
+
# Attribute names used by user commands
|
12
|
+
a: :Execution_Time,
|
13
|
+
c: :Checkpoint,
|
14
|
+
e: :Error_Path,
|
15
|
+
f: :fault_tolerant,
|
16
|
+
g: :group_list,
|
17
|
+
h: :Hold_Types,
|
18
|
+
j: :Join_Path,
|
19
|
+
k: :Keep_Files,
|
20
|
+
l: :Resource_List,
|
21
|
+
m: :Mail_Points,
|
22
|
+
o: :Output_Path,
|
23
|
+
p: :Priority,
|
24
|
+
q: :destination,
|
25
|
+
r: :Rerunable,
|
26
|
+
t: :job_array_request,
|
27
|
+
array_id: :job_array_id,
|
28
|
+
u: :User_List,
|
29
|
+
v: :Variable_List,
|
30
|
+
A: :Account_Name,
|
31
|
+
args: :job_arguments,
|
32
|
+
reservation_id: :reservation_id,
|
33
|
+
login_node_id: :login_node_id,
|
34
|
+
login_prop: :login_property,
|
35
|
+
external_nodes: :external_nodes,
|
36
|
+
multi_req_alps: :multi_req_alps,
|
37
|
+
M: :Mail_Users,
|
38
|
+
N: :Job_Name,
|
39
|
+
S: :Shell_Path_List,
|
40
|
+
depend: :depend,
|
41
|
+
inter: :interactive,
|
42
|
+
stagein: :stagein,
|
43
|
+
stageout: :stageout,
|
44
|
+
jobtype: :jobtype,
|
45
|
+
submit_host: :submit_host,
|
46
|
+
init_work_dir: :init_work_dir,
|
47
|
+
|
48
|
+
# Additional job and general attribute names
|
49
|
+
ctime: :ctime,
|
50
|
+
exechost: :exec_host,
|
51
|
+
execport: :exec_port,
|
52
|
+
mtime: :mtime,
|
53
|
+
qtime: :qtime,
|
54
|
+
session: :session_id,
|
55
|
+
euser: :euser,
|
56
|
+
egroup: :egroup,
|
57
|
+
hashname: :hashname,
|
58
|
+
hopcount: :hop_count,
|
59
|
+
security: :security,
|
60
|
+
sched_hint: :sched_hint,
|
61
|
+
substate: :substate,
|
62
|
+
name: :Job_Name,
|
63
|
+
owner: :Job_Owner,
|
64
|
+
used: :resources_used,
|
65
|
+
state: :job_state,
|
66
|
+
queue: :queue,
|
67
|
+
server: :server,
|
68
|
+
maxrun: :max_running,
|
69
|
+
maxreport: :max_report,
|
70
|
+
total: :total_jobs,
|
71
|
+
comment: :comment,
|
72
|
+
cookie: :cookie,
|
73
|
+
qrank: :queue_rank,
|
74
|
+
altid: :alt_id,
|
75
|
+
etime: :etime,
|
76
|
+
exitstat: :exit_status,
|
77
|
+
forwardx11: :forward_x11,
|
78
|
+
submit_args: :submit_args,
|
79
|
+
tokens: :tokens,
|
80
|
+
netcounter: :net_counter,
|
81
|
+
umask: :umask,
|
82
|
+
start_time: :start_time,
|
83
|
+
start_count: :start_count,
|
84
|
+
checkpoint_dir: :checkpoint_dir,
|
85
|
+
checkpoint_name: :checkpoint_name,
|
86
|
+
checkpoint_time: :checkpoint_time,
|
87
|
+
checkpoint_restart_status: :checkpoint_restart_status,
|
88
|
+
restart_name: :restart_name,
|
89
|
+
comp_time: :comp_time,
|
90
|
+
reported: :reported,
|
91
|
+
intcmd: :inter_cmd,
|
92
|
+
job_radix: :job_radix,
|
93
|
+
sister_list: :sister_list,
|
94
|
+
total_runtime: :total_runtime,
|
95
|
+
P: :proxy_user,
|
96
|
+
node_exclusive: :node_exclusive,
|
97
|
+
exec_gpus: :exec_gpus,
|
98
|
+
exec_mics: :exec_mics,
|
99
|
+
J: :job_id,
|
100
|
+
pagg: :pagg_id,
|
101
|
+
system_start_time: :system_start_time,
|
102
|
+
gpu_flags: :gpu_flags,
|
103
|
+
|
104
|
+
# Additional queue attribute names
|
105
|
+
|
106
|
+
# Additional server attribute names
|
107
|
+
|
108
|
+
# Additional node attribute names
|
109
|
+
}
|
110
|
+
end
|
data/lib/pbs/conn.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
module PBS
|
2
|
+
class Conn
|
3
|
+
# @example Torque 4.2.8
|
4
|
+
# "/usr/local/torque-4.2.8/lib/libtorque.so"
|
5
|
+
# @return [String] The torque library to use for connection.
|
6
|
+
attr_reader :lib
|
7
|
+
|
8
|
+
# @example Oakley
|
9
|
+
# "oak-batch.osc.edu"
|
10
|
+
# @return [String] The batch server to connect to.
|
11
|
+
attr_reader :server
|
12
|
+
|
13
|
+
# @example Torque 4.2.8
|
14
|
+
# "PATH=/usr/local/torque-4.2.8/bin:$PATH LD_LIBRARY_PATH=/usr/local/torque-4.2.8/lib:$LD_LIBRARY_PATH"
|
15
|
+
# @return [String] The qsub command to be called from the command line.
|
16
|
+
attr_reader :qsub
|
17
|
+
|
18
|
+
# @return [Fixnum, nil] The connection id number if connected.
|
19
|
+
attr_reader :conn_id
|
20
|
+
|
21
|
+
# Create a new connection object from pre-defined batch server defined in
|
22
|
+
# batch config yaml.
|
23
|
+
# @example Create Oakley connection
|
24
|
+
# PBS::Conn.batch 'oakley'
|
25
|
+
#
|
26
|
+
# @param name [String] The name of the pre-defined batch server.
|
27
|
+
# @param opts [Hash] The options to create a connection object with.
|
28
|
+
# @option opts [String] :lib The torque library used to establish connection.
|
29
|
+
# @option opts [String] :server The batch server to connect to.
|
30
|
+
# @option opts [String] :qsub The qsub command to be called from the command line.
|
31
|
+
# @raise [Error] if pre-defined batch server doesn't exist.
|
32
|
+
def self.batch(name, opts = {})
|
33
|
+
context = PBS.batch_config[name] || raise(PBS::Error, "No pre-defined batch server (#{name})")
|
34
|
+
lib = opts[:lib] || context.fetch('lib', nil)
|
35
|
+
svr = opts[:server] || context.fetch('server', nil)
|
36
|
+
qsb = opts[:qsub] || context.fetch('qsub', nil)
|
37
|
+
Conn.new(lib: lib, server: svr, qsub: qsb)
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param opts [Hash] The options to create a connection object with.
|
41
|
+
# @option opts [String] :lib The torque library used to establish connection.
|
42
|
+
# @option opts [String] :server The batch server to connect to.
|
43
|
+
# @option opts [String] :qsub The qsub command to be called from the command line.
|
44
|
+
def initialize(opts)
|
45
|
+
@lib = opts[:lib] || "torque"
|
46
|
+
@server = opts[:server]
|
47
|
+
@qsub = opts[:qsub] || "qsub"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Creates a torque connection
|
51
|
+
#
|
52
|
+
# @return [Integer] The connection id.
|
53
|
+
def connect
|
54
|
+
Torque.init lib: lib # reset library used in Torque
|
55
|
+
disconnect if connected? # clean up any old connection
|
56
|
+
@conn_id = Torque.pbs_connect(server)
|
57
|
+
Torque.raise_error(@conn_id.abs) if @conn_id < 0 # raise error if negative conn_id
|
58
|
+
Torque.check_for_error # check for any other error that slipped by
|
59
|
+
conn_id
|
60
|
+
end
|
61
|
+
|
62
|
+
# Disconnects from the connection and sets the connection id to nil.
|
63
|
+
def disconnect
|
64
|
+
Torque.pbs_disconnect(@conn_id)
|
65
|
+
@conn_id = nil # reset connection id
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns true if the connection id is not nil and is greater than zero.
|
69
|
+
#
|
70
|
+
# @return [Boolean] Are we connected?
|
71
|
+
def connected?
|
72
|
+
!@conn_id.nil? && @conn_id > 0
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|