arvicco-avalon 0.0.23 → 0.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|