jah 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +7 -0
- data/LICENSE +20 -0
- data/README.md +115 -0
- data/Rakefile +75 -0
- data/VERSION +1 -0
- data/bin/jah +9 -0
- data/jah.gemspec +89 -0
- data/lib/jah/agent.rb +128 -0
- data/lib/jah/agents/dump.rb +5 -0
- data/lib/jah/agents/post.rb +18 -0
- data/lib/jah/agents/xmpp.rb +194 -0
- data/lib/jah/cli.rb +124 -0
- data/lib/jah/collector.rb +12 -0
- data/lib/jah/collectors/cpu.rb +35 -0
- data/lib/jah/collectors/disk.rb +14 -0
- data/lib/jah/collectors/mem.rb +51 -0
- data/lib/jah/collectors/net.rb +27 -0
- data/lib/jah/collectors/prok.rb +88 -0
- data/lib/jah/collectors/services.rb +13 -0
- data/lib/jah/collectors/who.rb +20 -0
- data/lib/jah/command.rb +23 -0
- data/lib/jah/commands/admin.rb +40 -0
- data/lib/jah/commands/extra.rb +14 -0
- data/lib/jah/commands/pub.rb +34 -0
- data/lib/jah/commands/status.rb +61 -0
- data/lib/jah/god.rb +24 -0
- data/lib/jah/install.rb +336 -0
- data/lib/jah.rb +26 -0
- data/lib/jah.yaml.template +26 -0
- data/lib/locales/en_us.yml +2 -0
- data/lib/locales/pt_br.yml +2 -0
- data/lib/locales/pt_br_gostosa.yml +10 -0
- data/lib/locales/pt_br_mano.yml +10 -0
- data/lib/locales/pt_br_mineiro.yml +10 -0
- data/spec/console +12 -0
- data/spec/jah_spec.rb +7 -0
- data/spec/spec_helper.rb +9 -0
- metadata +123 -0
data/lib/jah/cli.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
#
|
2
|
+
# Jah Gem CLI
|
3
|
+
#
|
4
|
+
|
5
|
+
#TODO: def init
|
6
|
+
require 'logger'
|
7
|
+
|
8
|
+
module Jah
|
9
|
+
|
10
|
+
HOME = ENV['HOME'] + "/.jah/"
|
11
|
+
unless File.exists? HOME
|
12
|
+
FileUtils.mkdir_p HOME
|
13
|
+
end
|
14
|
+
|
15
|
+
Log = Logger.new(HOME + "jah.log")
|
16
|
+
def Log.write(d); self.warn(d); end
|
17
|
+
$stderr = Log
|
18
|
+
|
19
|
+
Opt = {}
|
20
|
+
|
21
|
+
def self.hostname
|
22
|
+
`hostname`.chomp.gsub(/\W/, "") rescue "jah#{rand(42000)}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.locale
|
26
|
+
`locale | grep LANG`.scan(/LANG=(.*)\./)[0][0].downcase rescue "en_us"
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.method_missing(w)
|
30
|
+
Opt[w.to_s.gsub("?", "").to_sym]
|
31
|
+
end
|
32
|
+
|
33
|
+
class Cli
|
34
|
+
|
35
|
+
def self.parse_options(argv)
|
36
|
+
options = {}
|
37
|
+
|
38
|
+
ARGV.options do |opts|
|
39
|
+
opts.banner = <<BANNER
|
40
|
+
Jah Gem Usage:
|
41
|
+
|
42
|
+
jah [command] [opts] -c [config file]
|
43
|
+
|
44
|
+
Commands:
|
45
|
+
|
46
|
+
start
|
47
|
+
stop
|
48
|
+
restart
|
49
|
+
install
|
50
|
+
|
51
|
+
BANNER
|
52
|
+
opts.separator "Config file:"
|
53
|
+
opts.on("-c", "--config CONFIG", String, "Jah Config file path" ) { |file| options[:config] = file }
|
54
|
+
opts.separator ""
|
55
|
+
opts.separator "Operation mode:"
|
56
|
+
opts.on("-m", "--mode MODE", String, "Jah operation mode") { |val| options[:mode] = val.to_sym }
|
57
|
+
opts.separator ""
|
58
|
+
opts.separator " xmpp - Use xmpp client, requires JID and Password"
|
59
|
+
opts.separator " post - Use post client, requires Jah Web Key"
|
60
|
+
opts.separator " dump - Just dump to disk, Jah Web can login and read"
|
61
|
+
opts.separator ""
|
62
|
+
opts.separator "Server Options:"
|
63
|
+
opts.on("-j", "--jid JID", String, "Client JID (user@domain)") { |val| options[:jid] = val }
|
64
|
+
opts.on("-k", "--key KEY", String, "Client XMPP Password or Jah Web Key") { |val| options[:key] = val }
|
65
|
+
opts.on("-s", "--server SERVER", String, "Jah Server URL" ) { |url| options[:server] = url }
|
66
|
+
opts.on("-p", "--port PORT", Integer, "Jah Server Port") { |val| options[:port] = val.to_i }
|
67
|
+
opts.separator ""
|
68
|
+
|
69
|
+
opts.on("-t", "--talk TALK", String, "Which locale to use" ) { |i18n| options[:i18n] = i18n }
|
70
|
+
opts.on("-f", "--file FILE", String, "Local temp file to track history" ) { |file| options[:history] = file }
|
71
|
+
opts.on("-i", "--interval INTERVAL", Integer, "Poller interval") { |val| options[:interval] = val.to_i }
|
72
|
+
opts.on("-l", "--level LEVEL", Logger::SEV_LABEL.map { |l| l.downcase }, "The level of logging to report" ) { |level| options[:level] = level }
|
73
|
+
opts.on("-g", "--[no-]god", "Don't use god") { |val| options[:god] = false }
|
74
|
+
opts.on("-d", "--daemonize", "Run in background" ) { |d| options[:daemon] = d }
|
75
|
+
opts.on("-r", "--report REPORT", "Report status to others on roster" ) { |r| options[:report] = r }
|
76
|
+
|
77
|
+
opts.separator ""
|
78
|
+
opts.separator "Common Options:"
|
79
|
+
opts.on("-h", "--help", "Show this message" ) { puts opts; exit }
|
80
|
+
opts.on("-v", "--[no-]verbose", "Turn on logging to STDOUT" ) { |bool| options[:verbose] = bool }
|
81
|
+
opts.on("-V", "--version", "Show version") { |version| puts Jah::VERSION; exit }
|
82
|
+
opts.separator ""
|
83
|
+
begin
|
84
|
+
opts.parse!
|
85
|
+
@usage = opts.to_s
|
86
|
+
rescue
|
87
|
+
puts opts
|
88
|
+
exit
|
89
|
+
end
|
90
|
+
end
|
91
|
+
options
|
92
|
+
end
|
93
|
+
private_class_method :parse_options
|
94
|
+
|
95
|
+
def self.dispatch(argv)
|
96
|
+
Jah::Opt.merge! autoload_config(parse_options(argv))
|
97
|
+
if comm = argv.shift
|
98
|
+
Jah::Agent.send(comm) rescue puts "Command not found: #{comm}"
|
99
|
+
else
|
100
|
+
Jah.mode ? Jah::Agent.start : Install.new
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Load config [., ~/.jah, /etc]
|
105
|
+
def self.autoload_config(options)
|
106
|
+
conf = "jah.yaml"
|
107
|
+
file = options[:config] || [nil, HOME, "/etc/"].select { |c| File.exists? "#{c}#{conf}" }[0]
|
108
|
+
options = YAML.load(File.read(file + conf)).merge!(options) if file
|
109
|
+
|
110
|
+
# Map acl and group arrays
|
111
|
+
[:acl, :groups].each do |g|
|
112
|
+
options[g] = options[g].split(",").map(&:strip)
|
113
|
+
end
|
114
|
+
options[:groups].map! { |g| "#{g}@conference.#{options[:host]}" }
|
115
|
+
|
116
|
+
# find a better place for this
|
117
|
+
I18n.load_path += Dir[File.join(File.dirname(__FILE__), '..', 'locales', "*.{rb,yml}")]
|
118
|
+
I18n.default_locale = options[:i18n] || "en_us"
|
119
|
+
options
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Jah
|
2
|
+
class Cpu < Collector
|
3
|
+
attr_reader :load, :one, :five, :ten, :med
|
4
|
+
EXEC = "uptime"
|
5
|
+
|
6
|
+
def self.get
|
7
|
+
new
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
l = cpu_load
|
12
|
+
@one = l[:one]
|
13
|
+
@five = l[:five]
|
14
|
+
@ten = l[:ten]
|
15
|
+
@load = l.values.join(", ")
|
16
|
+
@med = @ten / cores
|
17
|
+
end
|
18
|
+
|
19
|
+
def cpu_load
|
20
|
+
if `#{EXEC}` =~ /load average(s*): ([\d.]+)(,*) ([\d.]+)(,*) ([\d.]+)\Z/
|
21
|
+
{ :one => $2.to_f,
|
22
|
+
:five => $4.to_f,
|
23
|
+
:ten => $6.to_f }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def cores
|
28
|
+
case RUBY_PLATFORM
|
29
|
+
when /linux/ then `cat /proc/cpuinfo | grep 'model name' | wc -l`.to_i
|
30
|
+
when /darwin/ then `hwprefs cpu_count`.to_i
|
31
|
+
else 1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Jah
|
2
|
+
|
3
|
+
class Disk < Collector
|
4
|
+
EXEC = "df -h"
|
5
|
+
|
6
|
+
def self.all
|
7
|
+
@disks = `#{EXEC}`.to_a.reject { |dl| dl =~ /Size|none/ }.map do |l|
|
8
|
+
l = l.split(" ")
|
9
|
+
{ :path => l[0], :total => l[1], :used => l[2], :avail => l[3], :percent => l[4]}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Jah
|
2
|
+
|
3
|
+
class Mem < Collector
|
4
|
+
attr_reader :total, :free, :used, :percent, :cached, :buffered,
|
5
|
+
:swap_total, :swap_free, :swap_used, :swap_percent
|
6
|
+
|
7
|
+
EXEC = "cat /proc/meminfo"
|
8
|
+
|
9
|
+
def self.get
|
10
|
+
new
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
do_something
|
15
|
+
end
|
16
|
+
|
17
|
+
def do_something
|
18
|
+
mem_info = {}
|
19
|
+
`#{EXEC}`.each do |line|
|
20
|
+
_, key, value = *line.match(/^(\w+):\s+(\d+)\s/)
|
21
|
+
mem_info[key] = value.to_i
|
22
|
+
end
|
23
|
+
|
24
|
+
# memory info is empty - operating system may not support it (why doesn't an exception get raised earlier on mac osx?)
|
25
|
+
raise "No such file or directory" if mem_info.empty?
|
26
|
+
|
27
|
+
@total = mem_info['MemTotal'] / 1024
|
28
|
+
@free = (mem_info['MemFree'] + mem_info['Buffers'] + mem_info['Cached']) / 1024
|
29
|
+
@used = @total - @free
|
30
|
+
@percent = (@used / @total.to_f * 100).to_i
|
31
|
+
|
32
|
+
@swap_total = mem_info['SwapTotal'] / 1024
|
33
|
+
@swap_free = mem_info['SwapFree'] / 1024
|
34
|
+
@swap_used = swap_total - swap_free
|
35
|
+
unless @swap_total == 0
|
36
|
+
@swap_percent = (@swap_used / @swap_total.to_f * 100).to_i
|
37
|
+
end
|
38
|
+
rescue Exception => e
|
39
|
+
if e.message =~ /No such file or directory/
|
40
|
+
puts "/proc/meminfo not found.. trying top!"
|
41
|
+
top = `top -l 1`.to_a[5].split.map!{|m| m[0..-2].to_i}.reject(&:zero?)
|
42
|
+
@used, @free = top[3,4]
|
43
|
+
@total = @used + @free
|
44
|
+
@percent = (@used / @total.to_f * 100).to_i
|
45
|
+
else
|
46
|
+
raise e
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Jah
|
2
|
+
class Net < Collector
|
3
|
+
# :net => "netstat -n | grep -i established | wc -l"
|
4
|
+
class << self
|
5
|
+
# attr_reader :count, :ips
|
6
|
+
|
7
|
+
|
8
|
+
def count
|
9
|
+
`netstat -n | grep -i established | wc -l`.to_i
|
10
|
+
end
|
11
|
+
|
12
|
+
def connections
|
13
|
+
`netstat -ntu | grep ESTAB | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr`.to_a.map do |l|
|
14
|
+
count, ip = l.split
|
15
|
+
[ip, count]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Jah
|
2
|
+
|
3
|
+
class Ps < Collector
|
4
|
+
COMM = "ps auxww"
|
5
|
+
|
6
|
+
def self.all
|
7
|
+
`#{COMM}`.to_a[1..-1].map do |l|
|
8
|
+
Prok.new(l.split)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.find(name)
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
class Prok
|
20
|
+
BANLIST = [/^ata/, /^init$/, /^scsi_/, /\/\d$/, /agetty/ ]
|
21
|
+
attr_reader :pid, :comm, :cpu, :mem, :rss, :vsz, :stat
|
22
|
+
|
23
|
+
def initialize(args) # USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
|
24
|
+
return unless args[0]
|
25
|
+
@user = args[0]
|
26
|
+
@pid = args[1].chomp.to_i
|
27
|
+
@cpu = args[2].chomp.to_f
|
28
|
+
@mem = args[3].chomp.to_f
|
29
|
+
@vsz = args[4].chomp.to_i
|
30
|
+
@rss = args[5].chomp.to_i
|
31
|
+
@tty = args[6]
|
32
|
+
@stat = args[7]
|
33
|
+
@start = args[8]
|
34
|
+
@time = args[9]
|
35
|
+
@comm = args[10]
|
36
|
+
#@shr = args[6]
|
37
|
+
end
|
38
|
+
|
39
|
+
def hup!
|
40
|
+
exec "kill -1 #{pid}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def kill!
|
44
|
+
exec "kill #{pid}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def move_to_acre!
|
48
|
+
exec "kill -9 #{pid}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.genocide!(ary, f = nil)
|
52
|
+
for prok in ary
|
53
|
+
prok.kill
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def exec(comm)
|
58
|
+
# SSHWorker.new(@host, @host.user, comm)
|
59
|
+
end
|
60
|
+
|
61
|
+
def force(f)
|
62
|
+
{ :hup => "-1", :die => "-9"}[f]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
# COMM = {
|
69
|
+
# :top => "top -n 1",
|
70
|
+
# }
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
# def top
|
75
|
+
# info, tasks, cpus, mem, swap, n, n, *rest = *@res[:top]
|
76
|
+
# n, total, used, free, buffered = *mem.match(/(\d*)k\D*(\d*)k\D*(\d*)k\D*(\d*)k.*/)
|
77
|
+
# cached = swap.match(/(\d*)k cached/)[0]
|
78
|
+
# proks = rest.map do |r|
|
79
|
+
# r.split(" ")
|
80
|
+
# end
|
81
|
+
|
82
|
+
# # fail... top don't show a good stat....
|
83
|
+
# @proks = proks.reject do |p|
|
84
|
+
# p[0] == nil || Prok::BANLIST.select{ |pl| pl =~ p[11] }[0]
|
85
|
+
# end
|
86
|
+
# rescue => e
|
87
|
+
# nil
|
88
|
+
# end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Jah
|
2
|
+
|
3
|
+
class Who < Collector
|
4
|
+
EXEC = "who"
|
5
|
+
|
6
|
+
def self.all
|
7
|
+
@who = `#{EXEC}`.to_a.map do |l|
|
8
|
+
l = l.split(" ")
|
9
|
+
|
10
|
+
hash = {}
|
11
|
+
|
12
|
+
hash[:who] = l[0]
|
13
|
+
hash[:terminal] = l[1]
|
14
|
+
2.times{ l.delete(l[0]) }
|
15
|
+
hash[:date] = l.join(" ")
|
16
|
+
hash
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/jah/command.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Jah
|
2
|
+
REG = []
|
3
|
+
|
4
|
+
module Command
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.find(msg)
|
11
|
+
REG.select { |r| r[1] =~ msg.squeeze(" ").strip }.first
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
|
16
|
+
def register(handler, regex)
|
17
|
+
REG << [handler, /^#{regex}/, self]
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Jah
|
2
|
+
|
3
|
+
class Admin
|
4
|
+
include Command
|
5
|
+
|
6
|
+
register(:get_roster, "roster$")
|
7
|
+
register(:drop_user, "drop\s")
|
8
|
+
#Jah::Command.register(:create_group, "")
|
9
|
+
|
10
|
+
class << self
|
11
|
+
|
12
|
+
|
13
|
+
def get_roster
|
14
|
+
out = ""
|
15
|
+
client.roster.grouped.each do |group, items|
|
16
|
+
out << "#{'*'*3} #{group || 'Ungrouped'} #{'*'*3}\n"
|
17
|
+
items.each { |item| out << "- #{item.name} (#{item.jid})\n" }
|
18
|
+
out << "\n"
|
19
|
+
end
|
20
|
+
out
|
21
|
+
end
|
22
|
+
|
23
|
+
def drop_user(user)
|
24
|
+
puts "DROP..."
|
25
|
+
end
|
26
|
+
|
27
|
+
def join_group()
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
def create_group(name)
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "blather/client/dsl"
|
2
|
+
|
3
|
+
module Jah
|
4
|
+
|
5
|
+
class Pub
|
6
|
+
include Command
|
7
|
+
|
8
|
+
register :create, 'create\spubsub.*'
|
9
|
+
|
10
|
+
|
11
|
+
def self.create(_, node)
|
12
|
+
# pubsub = Blather::DSL::PubSub.new()
|
13
|
+
request(Blather::Stanza::PubSub::Create.new(:set,
|
14
|
+
"Jah.host.com", node)) { |n| yield n if block_given? }
|
15
|
+
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.all
|
20
|
+
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Jah
|
2
|
+
|
3
|
+
class Status
|
4
|
+
include Command
|
5
|
+
register(:ok, 'ok\??$')
|
6
|
+
register(:who, 'who\??$')
|
7
|
+
register(:mem, 'mem\??$')
|
8
|
+
register(:cpu, 'cpu\??$')
|
9
|
+
register(:net, 'net\??$')
|
10
|
+
register(:disk, 'disk\??$')
|
11
|
+
register(:proks, 'prok$|top$')
|
12
|
+
|
13
|
+
|
14
|
+
class << self
|
15
|
+
|
16
|
+
def ok
|
17
|
+
I18n.t("states." + case Jah::Cpu.get.med
|
18
|
+
when 0..0.5 then :green
|
19
|
+
when 0.51..0.7 then :yellow
|
20
|
+
else :red
|
21
|
+
end.to_s)
|
22
|
+
end
|
23
|
+
|
24
|
+
def mem
|
25
|
+
Mem.get.percent.to_s + "%"
|
26
|
+
end
|
27
|
+
|
28
|
+
def cpu
|
29
|
+
Cpu.get.load
|
30
|
+
end
|
31
|
+
|
32
|
+
def net
|
33
|
+
out = ""
|
34
|
+
Net.connections.each do |c|
|
35
|
+
out << "#{c[0]} => #{c[1]} connections\n"
|
36
|
+
end
|
37
|
+
out << "Total: #{Net.count}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def disk
|
41
|
+
Disk.all.map do |d|
|
42
|
+
"\n*#{d[:path]}* => #{d[:percent]}"
|
43
|
+
end.join("\n")
|
44
|
+
end
|
45
|
+
|
46
|
+
def who
|
47
|
+
Who.all.map do |w|
|
48
|
+
"#{w[:who]} Logado via #{w[:terminal]} desde a data: #{w[:date]}"
|
49
|
+
end.join("\n")
|
50
|
+
end
|
51
|
+
|
52
|
+
def proks(find = nil)
|
53
|
+
Ps.all.map do |p|
|
54
|
+
next if find && p.comm !~ /#{find}/i
|
55
|
+
"#{p.comm} => #{p.mem}\n"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/jah/god.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# def setup
|
2
|
+
# DRb.start_service
|
3
|
+
# @server = DRbObject.new(nil, God::Socket.socket(@config['god_port'])) || nil
|
4
|
+
# rescue => e
|
5
|
+
# @config[:god] = false
|
6
|
+
# end
|
7
|
+
|
8
|
+
# # ping server to ensure that it is responsive
|
9
|
+
# def ping
|
10
|
+
# if god?
|
11
|
+
# tries = 3
|
12
|
+
# begin
|
13
|
+
# @server.ping
|
14
|
+
# rescue Exception => e
|
15
|
+
# retry if (tries -= 1) > 1
|
16
|
+
# raise e, "The server is not available (or you do not have permissions to access it)"
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
|
21
|
+
|
22
|
+
# def god?
|
23
|
+
# @config[:god]
|
24
|
+
# end
|