arvicco-avalon 0.0.23 → 0.0.25
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +13 -7
- data/bin/test_switch +30 -0
- data/lib/avalon.rb +2 -0
- data/lib/avalon/btcguild.rb +93 -0
- data/lib/avalon/eloipool.rb +3 -4
- data/lib/avalon/extractable.rb +2 -1
- data/lib/avalon/internet.rb +8 -2
- data/lib/avalon/miner.rb +59 -29
- data/lib/avalon/monitor.rb +16 -7
- data/lib/avalon/node.rb +10 -2
- data/lib/avalon/switch.rb +20 -0
- data/lib/avalon/utils.rb +2 -2
- data/lib/avalon/version.rb +1 -1
- metadata +6 -2
data/README.md
CHANGED
@@ -14,7 +14,7 @@ Scripts:
|
|
14
14
|
|
15
15
|
$ monitor [environment]
|
16
16
|
|
17
|
-
Monitors all the nodes (miners, pools, Internet connections) that are listed in config/monitor.yml file. Sounds alarm
|
17
|
+
Monitors all the nodes (miners, pools, Internet connections) that are listed in config/monitor.yml file. Sounds alarm if anything goes wrong with the monitored nodes. Alarm sounds are configurable. TODO: takes action to correct errors found (like restarting the failing miners etc).
|
18
18
|
|
19
19
|
$ reboot_miner 145 146 192.168.0.150
|
20
20
|
|
@@ -40,14 +40,17 @@ Monitor script is periodically polling the mining units and other types of objec
|
|
40
40
|
# Prod configuration (default)
|
41
41
|
prod:
|
42
42
|
:alert_after: 2 # missed pings or status reports from a miner
|
43
|
-
:alert_temp_high:
|
43
|
+
:alert_temp_high: 55 # degrees C and above
|
44
44
|
:alert_temp_low: 30 # degrees C and below, Avalon miners only
|
45
45
|
:alert_last_share: 2 # minutes since last share hashed
|
46
46
|
:alert_sounds:
|
47
|
-
:failure: Glass.aiff # [] for no sound
|
48
47
|
:restart: Frog.aiff # [] for no sound
|
49
|
-
:
|
50
|
-
:
|
48
|
+
:failure: Glass.aiff
|
49
|
+
:perf_low: Glass.aiff
|
50
|
+
:last_share: Glass.aiff
|
51
|
+
:temp_high: Ping.aiff
|
52
|
+
:temp_low: Ping.aiff
|
53
|
+
:block_found: [Dog.aiff, Purr.aiff, Dog.aiff]
|
51
54
|
:block_updated: [Purr.aiff, Purr.aiff, Purr.aiff] # [] for no alert sound
|
52
55
|
:bitcoind:
|
53
56
|
:ip: 192.168.1.13
|
@@ -56,9 +59,12 @@ Monitor script is periodically polling the mining units and other types of objec
|
|
56
59
|
:monitor:
|
57
60
|
:verbose: true
|
58
61
|
:timeout: 30
|
62
|
+
:per_hour: true # If true, getworks, rejects... metrics will be displayed PER HOUR
|
59
63
|
:nodes:
|
60
|
-
- [
|
61
|
-
- [miner, 192.168.1.
|
64
|
+
- [btcguild, stratum.btcguild.com, apikey] # ping url, your API key
|
65
|
+
- [miner, 192.168.1.151, 70, jbond_151] # type, ip, gh/s, pool_name(optional)
|
66
|
+
- [miner, 192.168.1.152, 82, jbond_15]
|
67
|
+
- [miner, 192.168.1.153, 40]
|
62
68
|
- [internet, www.google.com, www.speedtest.net]
|
63
69
|
- [eloipool, 192.168.1.13, 4] # frequency of old block updates (once per X polls)
|
64
70
|
|
data/bin/test_switch
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Script to reboot Avalon miner
|
3
|
+
|
4
|
+
lib = File.expand_path('../../lib', __FILE__)
|
5
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
|
+
|
7
|
+
require 'avalon'
|
8
|
+
|
9
|
+
Avalon::Config.load 'prod'
|
10
|
+
|
11
|
+
monitor = Avalon::Monitor.new Avalon::Config[:monitor]
|
12
|
+
|
13
|
+
monitor.switches.each do |sw|
|
14
|
+
sw.off
|
15
|
+
sleep 2
|
16
|
+
sw.on
|
17
|
+
end
|
18
|
+
|
19
|
+
exit
|
20
|
+
|
21
|
+
ARGV.each do |id|
|
22
|
+
miner = monitor.nodes.find {|m| m.num == id}
|
23
|
+
miner ||= monitor.nodes.find {|m| m.ip =~ Regexp.new(id)}
|
24
|
+
if miner
|
25
|
+
miner.reset
|
26
|
+
puts "Miner #{id} reset"
|
27
|
+
else
|
28
|
+
puts "Unable to reset miner #{id}"
|
29
|
+
end
|
30
|
+
end
|
data/lib/avalon.rb
CHANGED
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Avalon
|
5
|
+
|
6
|
+
# Extracts Btcguild pool info
|
7
|
+
class Btcguild < Node
|
8
|
+
|
9
|
+
API_URL = 'http://www.btcguild.com'
|
10
|
+
API_PATH = 'api.php?api_key='
|
11
|
+
|
12
|
+
def initialize monitor, ping_url, api_key
|
13
|
+
@ping_url, @api_key = ping_url, api_key
|
14
|
+
|
15
|
+
@conn ||= Faraday.new(:url => API_URL) do |faraday|
|
16
|
+
# faraday.response :logger # log requests to STDOUT
|
17
|
+
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
|
18
|
+
end
|
19
|
+
|
20
|
+
super()
|
21
|
+
end
|
22
|
+
|
23
|
+
def get
|
24
|
+
reply = @conn.get "#{API_PATH}#{@api_key}"
|
25
|
+
if reply.success? && !(reply.body =~ /too many API requests/)
|
26
|
+
JSON.parse(reply.body, :symbolize_names => true)
|
27
|
+
else
|
28
|
+
{}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def poll verbose=true
|
33
|
+
@data[:ping] = ping @ping_url
|
34
|
+
|
35
|
+
if @data[:ping]
|
36
|
+
@data.merge!(get || {})
|
37
|
+
if @data[:workers] && @data[:workers].keys.include?(:'1')
|
38
|
+
@data[:workers] = Hash[*@data[:workers].map {|_, h| [h.delete(:worker_name), h]}.flatten]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
puts "#{self}" if verbose
|
42
|
+
end
|
43
|
+
|
44
|
+
# Check for any exceptional situations, sound alarm if any
|
45
|
+
def report
|
46
|
+
if self[:ping].nil?
|
47
|
+
alarm "BTC Guild not responding to ping"
|
48
|
+
else
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_s
|
53
|
+
"\nBTC Guild: #{pool_speed}TH/s ping:#{self[:ping]} diff:#{diff}M " +
|
54
|
+
"unpaid(24h) btc: #{unpaid}(#{past24}) nmc: #{unpaid_nmc}(#{past24_nmc})"
|
55
|
+
end
|
56
|
+
|
57
|
+
### Convenience data accessors
|
58
|
+
def access key1, key2, precision=nil, divider=1
|
59
|
+
if @data[key1] && @data[key1][key2]
|
60
|
+
if precision
|
61
|
+
(@data[key1][key2]/divider).round(precision)
|
62
|
+
else
|
63
|
+
(@data[key1][key2]/divider)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def past24
|
69
|
+
access :user, :past_24h_rewards, 2
|
70
|
+
end
|
71
|
+
|
72
|
+
def unpaid
|
73
|
+
access :user, :unpaid_rewards, 3
|
74
|
+
end
|
75
|
+
|
76
|
+
def past24_nmc
|
77
|
+
access :user, :past_24h_rewards_nmc, 1
|
78
|
+
end
|
79
|
+
|
80
|
+
def unpaid_nmc
|
81
|
+
access :user, :unpaid_rewards_nmc, 2
|
82
|
+
end
|
83
|
+
|
84
|
+
def pool_speed
|
85
|
+
access :pool, :pool_speed, 1, 1000.0
|
86
|
+
end
|
87
|
+
|
88
|
+
def diff
|
89
|
+
access :pool, :difficulty, 1, 1000_000.0
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
data/lib/avalon/eloipool.rb
CHANGED
@@ -2,9 +2,8 @@ module Avalon
|
|
2
2
|
# Pool is a node encapsulating pool software
|
3
3
|
class Eloipool < Node
|
4
4
|
|
5
|
-
def initialize ip, frequency
|
6
|
-
@ip = ip
|
7
|
-
@update_frequency = frequency
|
5
|
+
def initialize monitor, ip, frequency
|
6
|
+
@ip, @frequency = ip, frequency
|
8
7
|
@update_num = 0
|
9
8
|
@block_file = Avalon::Config[:block_file]
|
10
9
|
@blocks = load_blocks || {}
|
@@ -55,7 +54,7 @@ module Avalon
|
|
55
54
|
end
|
56
55
|
|
57
56
|
def update_old_block
|
58
|
-
if rand(@
|
57
|
+
if rand(@frequency) == 0 # update once per @frequency polls
|
59
58
|
hash = @blocks.keys[@update_num]
|
60
59
|
if @blocks[hash]
|
61
60
|
@update_num += 1
|
data/lib/avalon/extractable.rb
CHANGED
@@ -5,7 +5,8 @@ module Avalon
|
|
5
5
|
|
6
6
|
# type = :absolute_time | :absolute_date | :relative_time
|
7
7
|
def my_time t, type=:absolute_time
|
8
|
-
|
8
|
+
t = t.to_f < 0 ? 0 : t.to_f
|
9
|
+
time = Time.at(t)
|
9
10
|
case type
|
10
11
|
when :absolute_date
|
11
12
|
time.getlocal.strftime("%Y-%m-%d %H:%M:%S")
|
data/lib/avalon/internet.rb
CHANGED
@@ -3,8 +3,14 @@ module Avalon
|
|
3
3
|
# Internet is a node encapsulating information about Internet connectivity
|
4
4
|
class Internet < Node
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
IP_REGEXP = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/
|
7
|
+
|
8
|
+
def initialize monitor, *sites
|
9
|
+
sites.map! do |site|
|
10
|
+
name = site =~ IP_REGEXP ? site : site.split(/\./)[-2]
|
11
|
+
[name.to_sym, site]
|
12
|
+
end
|
13
|
+
@sites = Hash[ *sites.flatten ]
|
8
14
|
super()
|
9
15
|
end
|
10
16
|
|
data/lib/avalon/miner.rb
CHANGED
@@ -15,8 +15,10 @@ module Avalon
|
|
15
15
|
|
16
16
|
# Field formats: name => [width, pattern, type/conversion]
|
17
17
|
FIELDS = {
|
18
|
-
:
|
19
|
-
:
|
18
|
+
:unit => [6, /(?<=MHS av=)[\d\.]*/, :i],
|
19
|
+
:pool => [6, /./, nil], # not in miner status string...
|
20
|
+
:ping => [6, /./, nil], # not in miner status string...
|
21
|
+
:rst => [3, /./, nil], # not in miner status string...
|
20
22
|
:uptime => [9, /(?<=Elapsed=)[\d\.]*/, ->(x){ my_time(x, :relative_time)}],
|
21
23
|
:last => [8, /(?<=Status=Alive,).*?Last Share Time=[\d\.]*/,
|
22
24
|
->(x){ convert_last(x)}],
|
@@ -25,35 +27,36 @@ module Avalon
|
|
25
27
|
:'°C' => [2, /(?<=Temperature=)[\d\.]*/, :i],
|
26
28
|
:fan2 => [4, /(?<=fan2=)[\d\.]*/, :i],
|
27
29
|
:fan3 => [4, /(?<=fan3=)[\d\.]*/, :i],
|
28
|
-
:
|
29
|
-
:
|
30
|
-
:
|
31
|
-
:
|
32
|
-
:stale => [
|
33
|
-
:
|
34
|
-
:
|
30
|
+
:WU => [4, /(?<=,Work Utility=)[\d\.]*/, :i],
|
31
|
+
:getwork => [7, /(?<=Getworks=)[\d\.]*/, :i],
|
32
|
+
:accept => [6, /(?<=,Accepted=)[\d\.]*/, :i],
|
33
|
+
:reject => [6, /(?<=Rejected=)[\d\.]*/, :i],
|
34
|
+
:stale => [5, /(?<=Stale=)[\d\.]*/, :i],
|
35
|
+
:error => [6, /(?<=Hardware Errors=)[\d\.]*/, :i],
|
36
|
+
# :block => [5, /(?<=Network Blocks=)[\d\.]*/, :i],
|
35
37
|
# :found => [2, /(?<=Found Blocks=)[\d\.]*/, :i],
|
36
38
|
}
|
37
39
|
|
38
40
|
# Last share converter (Miner-specific)
|
39
41
|
def self.convert_last x
|
40
42
|
y = x[/(?<=Last Share Time=)[\d\.]*/]
|
43
|
+
|
41
44
|
if y.nil? || y == '0'
|
42
45
|
"never"
|
43
46
|
else
|
44
|
-
my_time(Time.now.getgm-y.to_i, :relative_time)
|
47
|
+
my_time(Time.now.getgm.to_i-y.to_i, :relative_time)
|
45
48
|
end
|
46
49
|
end
|
47
50
|
|
48
51
|
def self.print_headers
|
49
|
-
puts "\nMiner status as of #{Time.now.getlocal.asctime}:\
|
50
|
-
FIELDS.map {|name, (width,_,_ )| name.to_s.
|
52
|
+
puts "\nMiner status as of #{Time.now.getlocal.asctime}:\nmhs: " +
|
53
|
+
FIELDS.map {|name, (width,_,_ )| name.to_s.rjust(width)}.join(' ')
|
51
54
|
end
|
52
55
|
|
53
|
-
def initialize ip,
|
54
|
-
@ip = ip
|
55
|
-
@
|
56
|
-
@config = config
|
56
|
+
def initialize monitor, ip, min_mhs, worker_name=nil
|
57
|
+
@ip, @min_mhs, @worker_name = ip, min_mhs*1000 , worker_name
|
58
|
+
@monitor = monitor
|
59
|
+
@config = Avalon::Config.config # TODO: monitor.config?
|
57
60
|
@fails = 0
|
58
61
|
super()
|
59
62
|
end
|
@@ -66,20 +69,24 @@ module Avalon
|
|
66
69
|
self[:ping] = ping @ip
|
67
70
|
|
68
71
|
status = get_api('summary') + get_api('pools') + get_api('devs') + get_api('stats')
|
72
|
+
@poll_time = Time.now
|
69
73
|
# p get_api('summary')
|
70
|
-
# pools = get_api('pools')
|
71
|
-
# p pools[FIELDS[:last][1]]
|
72
|
-
# devs = get_api('devs')
|
73
|
-
# p devs
|
74
74
|
|
75
75
|
data = self.class.extract_data_from(status)
|
76
76
|
|
77
77
|
if data.empty?
|
78
|
-
@data = {}
|
78
|
+
@data = {:ping => self[:ping], :rst => self[:rst]}
|
79
79
|
else
|
80
80
|
@data.merge! data
|
81
|
+
if @config[:monitor][:per_hour]
|
82
|
+
[:getwork, :accept, :reject, :stale, :error].each do |key|
|
83
|
+
self[key] = (self[key]/upminutes*60).round(1) if self[key]
|
84
|
+
end
|
85
|
+
end
|
81
86
|
end
|
82
87
|
|
88
|
+
self[:pool] = pool_hash
|
89
|
+
|
83
90
|
puts "#{self}" if verbose
|
84
91
|
end
|
85
92
|
|
@@ -87,26 +94,49 @@ module Avalon
|
|
87
94
|
duration(self[:uptime])
|
88
95
|
end
|
89
96
|
|
97
|
+
def last
|
98
|
+
duration(self[:last])
|
99
|
+
end
|
100
|
+
|
101
|
+
def restart_time
|
102
|
+
@poll_time - upminutes * 60.0
|
103
|
+
end
|
104
|
+
|
90
105
|
def temp
|
91
106
|
self[:'°C']
|
92
107
|
end
|
93
108
|
|
109
|
+
def unit_hash
|
110
|
+
self[:unit] || 0
|
111
|
+
end
|
112
|
+
|
113
|
+
def pool_hash
|
114
|
+
if @monitor.pool && @worker_name && @monitor.pool[:workers] && @monitor.pool[:workers][@worker_name]
|
115
|
+
@monitor.pool[:workers][@worker_name][:hash_rate].round(0)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
94
119
|
# Check for any exceptional situations in stats, sound alarm if any
|
95
120
|
def report
|
96
|
-
if data[:ping].nil?
|
121
|
+
if data[:ping].nil? || data[:unit].nil?
|
97
122
|
@fails += 1
|
98
123
|
if @fails >= @config[:alert_after]
|
99
124
|
alarm "Miner #{num} did not respond to status query", :failure
|
100
125
|
end
|
101
126
|
else
|
102
127
|
@fails = 0
|
103
|
-
|
128
|
+
@last_restart ||= restart_time
|
129
|
+
|
130
|
+
# Detect Miner reset correctly
|
131
|
+
if (restart_time - @last_restart) > 20
|
132
|
+
@last_restart = restart_time
|
133
|
+
self[:rst] = (self[:rst] || 0) + 1
|
104
134
|
alarm "Miner #{num} restarted", :restart
|
105
|
-
elsif
|
106
|
-
if
|
107
|
-
alarm "Miner #{num} performance is #{
|
108
|
-
elsif
|
109
|
-
alarm "Miner #{num} last shares was #{
|
135
|
+
elsif upminutes > 5 # Miner settled down
|
136
|
+
if unit_hash < @min_mhs
|
137
|
+
alarm "Miner #{num} performance is #{unit_hash}, should be #{@min_mhs}", :perf_low
|
138
|
+
elsif last == 'never' || last > @config[:alert_last_share]
|
139
|
+
alarm "Miner #{num} last shares was #{last} min ago", :last_share
|
110
140
|
elsif temp >= @config[:alert_temp_high]
|
111
141
|
alarm "Miner #{num} too hot at #{temp}°C, needs cooling", :temp_high
|
112
142
|
elsif self[:freq] && temp <= @config[:alert_temp_low]
|
@@ -122,7 +152,7 @@ module Avalon
|
|
122
152
|
end
|
123
153
|
|
124
154
|
def to_s
|
125
|
-
"#{num}: " + FIELDS.map {|key, (width, _, _ )| @data[key].to_s.
|
155
|
+
"#{num}: " + FIELDS.map {|key, (width, _, _ )| @data[key].to_s.rjust(width)}.join(" ")
|
126
156
|
end
|
127
157
|
|
128
158
|
end
|
data/lib/avalon/monitor.rb
CHANGED
@@ -2,29 +2,38 @@ module Avalon
|
|
2
2
|
|
3
3
|
class Monitor
|
4
4
|
|
5
|
-
attr_reader :nodes
|
5
|
+
attr_reader :nodes, :switches, :pool
|
6
6
|
|
7
7
|
# List of nodes to monitor
|
8
8
|
def initialize opts
|
9
|
-
@nodes = opts[:nodes].map {|args| Avalon::Node.create(*args)}
|
10
9
|
@timeout = opts[:timeout] || 30
|
11
10
|
@verbose = opts[:verbose]
|
11
|
+
@switches = (opts[:switches] || []).map {|args| Avalon::Switch.new(*args)}
|
12
|
+
@nodes = opts[:nodes].map {|args| Avalon::Node.create(self, *args)}
|
13
|
+
@pool = @nodes.find {|node| node.is_a?(Avalon::Btcguild)}
|
12
14
|
end
|
13
15
|
|
14
16
|
def run
|
15
17
|
loop do
|
16
18
|
|
17
|
-
Avalon::Miner.print_headers if @verbose
|
18
|
-
|
19
19
|
# Check status for all nodes
|
20
|
-
@nodes.
|
20
|
+
@nodes.inject(false) do |headers_printed, node|
|
21
|
+
# Print miners headers once first miner encountered
|
22
|
+
if @verbose && node.is_a?(Avalon::Miner) && !headers_printed
|
23
|
+
Avalon::Miner.print_headers
|
24
|
+
headers_printed = true
|
25
|
+
end
|
26
|
+
node.poll(@verbose)
|
27
|
+
headers_printed
|
28
|
+
end
|
21
29
|
|
22
30
|
# Report node errors (if any)
|
23
31
|
@nodes.each {|node| node.report}
|
24
32
|
|
25
33
|
if @verbose
|
26
|
-
|
27
|
-
|
34
|
+
unit_hash = @nodes.reduce(0) {|hash, node| hash + (node.unit_hash || 0)}
|
35
|
+
pool_hash = @nodes.reduce(0) {|hash, node| hash + (node.pool_hash || 0)}
|
36
|
+
puts "Total hash rate (from pool): #{unit_hash} (#{pool_hash}) MH/s"
|
28
37
|
end
|
29
38
|
|
30
39
|
sleep @timeout
|
data/lib/avalon/node.rb
CHANGED
@@ -6,9 +6,9 @@ module Avalon
|
|
6
6
|
include Utils # Helper methods
|
7
7
|
|
8
8
|
# Builder method for creating Node subclasses from config arrays
|
9
|
-
def Node.create *args
|
9
|
+
def Node.create monitor, *args
|
10
10
|
subclass = Avalon.const_get(args.first.capitalize)
|
11
|
-
subclass.new *args.drop(1)
|
11
|
+
subclass.new monitor, *args.drop(1)
|
12
12
|
end
|
13
13
|
|
14
14
|
attr_reader :ip, :data
|
@@ -31,6 +31,14 @@ module Avalon
|
|
31
31
|
@data[key] = value
|
32
32
|
end
|
33
33
|
|
34
|
+
### Node API: following methods should be defined:
|
35
|
+
|
36
|
+
def unit_hash
|
37
|
+
end
|
38
|
+
|
39
|
+
def pool_hash
|
40
|
+
end
|
41
|
+
|
34
42
|
# Abstract: Check node status
|
35
43
|
# If verbose, the Node should print out its state after the status update
|
36
44
|
def poll verbose
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Avalon
|
2
|
+
|
3
|
+
# Encapsulates DLI Web Power Switch
|
4
|
+
class Switch
|
5
|
+
|
6
|
+
def initialize user, pass, ip, outlet
|
7
|
+
@user, @pass, @ip, @outlet = user, pass, ip, outlet
|
8
|
+
raise 'Please install curl: sudo apt-get install curl' if `which curl`.empty?
|
9
|
+
end
|
10
|
+
|
11
|
+
def on
|
12
|
+
`curl -s http://#{@user}:#{@pass}@#{@ip}/outlet?#{@outlet}=ON`
|
13
|
+
end
|
14
|
+
|
15
|
+
def off
|
16
|
+
`curl -s http://#{@user}:#{@pass}@#{@ip}/outlet?#{@outlet}=OFF`
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
data/lib/avalon/utils.rb
CHANGED
@@ -38,7 +38,7 @@ module Avalon
|
|
38
38
|
'never'
|
39
39
|
else
|
40
40
|
hour, min, sec = *time_string.split(/:/).map(&:to_i)
|
41
|
-
hour*60.0 + min + sec/60.0
|
41
|
+
(hour*60.0 + min + sec/60.0).round(2)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
@@ -46,7 +46,7 @@ module Avalon
|
|
46
46
|
def ping ip
|
47
47
|
ping_result = `ping -c 1 #{ip}`
|
48
48
|
if ping_result =~ /( | 0.)0% packet loss/
|
49
|
-
ping_result.match(/time=([\.\d]*) ms/)[1].to_f
|
49
|
+
ping_result.match(/time=([\.\d]*) ms/)[1].to_f.round(1)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
data/lib/avalon/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arvicco-avalon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.25
|
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: 2013-
|
12
|
+
date: 2013-07-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: faraday
|
@@ -34,6 +34,7 @@ executables:
|
|
34
34
|
- monitor
|
35
35
|
- mtgox_tx
|
36
36
|
- reboot_miner
|
37
|
+
- test_switch
|
37
38
|
extensions: []
|
38
39
|
extra_rdoc_files: []
|
39
40
|
files:
|
@@ -46,10 +47,12 @@ files:
|
|
46
47
|
- bin/monitor
|
47
48
|
- bin/mtgox_tx
|
48
49
|
- bin/reboot_miner
|
50
|
+
- bin/test_switch
|
49
51
|
- lib/avalon.rb
|
50
52
|
- lib/avalon/bitcoind.rb
|
51
53
|
- lib/avalon/block.rb
|
52
54
|
- lib/avalon/blockchain.rb
|
55
|
+
- lib/avalon/btcguild.rb
|
53
56
|
- lib/avalon/config.rb
|
54
57
|
- lib/avalon/eloipool.rb
|
55
58
|
- lib/avalon/extractable.rb
|
@@ -57,6 +60,7 @@ files:
|
|
57
60
|
- lib/avalon/miner.rb
|
58
61
|
- lib/avalon/monitor.rb
|
59
62
|
- lib/avalon/node.rb
|
63
|
+
- lib/avalon/switch.rb
|
60
64
|
- lib/avalon/utils.rb
|
61
65
|
- lib/avalon/version.rb
|
62
66
|
- sound/Dog.aiff
|