1
|
|
|
'''Mining Rules''' |
2
|
|
|
import domain.minerstatistics |
3
|
|
|
from domain.mining import Miner |
4
|
|
|
|
5
|
|
|
class RuleParameters(object): |
6
|
|
|
'''configurable parameters for rules''' |
7
|
|
|
def __init__(self, minertype, hashlimit, controllertemplimit, boardtemplimit, restartaftersec, |
8
|
|
|
maxtempreset=None, hardware_errors_limit=None, hardware_errors_limit_time=None): |
9
|
|
|
self.minertype = minertype |
10
|
|
|
self.hashlimit = hashlimit |
11
|
|
|
self.controllertemplimit = controllertemplimit |
12
|
|
|
self.boardtemplimit = boardtemplimit |
13
|
|
|
self.restartaftersec = restartaftersec |
14
|
|
|
self.maxtempreset = maxtempreset |
15
|
|
|
self.hardware_errors_limit = hardware_errors_limit |
16
|
|
|
#hours (24h), minutes (60m), seconds (10s) |
17
|
|
|
self.hardware_errors_limit_time = hardware_errors_limit_time |
18
|
|
|
|
19
|
|
|
class BrokenRule(object): |
20
|
|
|
'''broken rules''' |
21
|
|
|
def __init__(self, miner, action, parameter): |
22
|
|
|
self.miner = miner |
23
|
|
|
self.action = action |
24
|
|
|
self.parameter = parameter |
25
|
|
|
|
26
|
|
|
def __str__(self): |
27
|
|
|
return 'broke {0}:{1} {2}'.format(self.miner.name, self.action, self.parameter) |
28
|
|
|
|
29
|
|
|
class MinerStatisticsRule(object): |
30
|
|
|
'''Rule for evaluating miner statistics''' |
31
|
|
|
|
32
|
|
|
def __init__(self, miner: Miner, statistics: domain.minerstatistics.MinerStatistics, ruleparameters: RuleParameters): |
33
|
|
|
self.miner = miner |
34
|
|
|
self.statistics = statistics |
35
|
|
|
self.ruleparameters = ruleparameters |
36
|
|
|
self.brokenrules = [] |
37
|
|
|
|
38
|
|
|
@classmethod |
39
|
|
|
def hasreading(cls, reading): |
40
|
|
|
'''True when the reading is not empty''' |
41
|
|
|
if reading is None: |
42
|
|
|
return False |
43
|
|
|
if reading: |
44
|
|
|
return True |
45
|
|
|
return False |
46
|
|
|
|
47
|
|
|
@classmethod |
48
|
|
|
def hasreading_num(cls, reading): |
49
|
|
|
'''True when the reading is numeric and not empty''' |
50
|
|
|
if reading is None: |
51
|
|
|
return False |
52
|
|
|
if reading == 0: |
53
|
|
|
return False |
54
|
|
|
if isinstance(reading, int): |
55
|
|
|
return True |
56
|
|
|
if isinstance(reading, float): |
57
|
|
|
return True |
58
|
|
|
return False |
59
|
|
|
|
60
|
|
|
def has_reboot_rule(self): |
61
|
|
|
return any(therule.action == 'restart' and therule.parameter == 'reboot' for therule in self.brokenrules) |
62
|
|
|
|
63
|
|
|
def addbrokenrule(self, rule): |
64
|
|
|
if rule.action == 'restart': |
65
|
|
|
if not self.has_reboot_rule(): |
66
|
|
|
self.brokenrules = [therule for therule in self.brokenrules if therule.action != 'restart'] |
67
|
|
|
self.brokenrules.append(rule) |
68
|
|
|
else: |
69
|
|
|
self.brokenrules.append(rule) |
70
|
|
|
|
71
|
|
|
def isbroken(self): |
72
|
|
|
'''true when the rule is broken''' |
73
|
|
|
self.brokenrules = [] |
74
|
|
|
if self.miner.miner_type != self.ruleparameters.minertype: |
75
|
|
|
return False |
76
|
|
|
|
77
|
|
|
self.check_hash() |
78
|
|
|
self.check_temp_controller() |
79
|
|
|
self.check_temp_boards() |
80
|
|
|
self.check_hardware_errors() |
81
|
|
|
|
82
|
|
|
return len(self.brokenrules) > 0 |
83
|
|
|
|
84
|
|
|
def check_hardware_errors(self): |
85
|
|
|
if MinerStatisticsRule.hasreading_num(self.statistics.hardware_errors): |
86
|
|
|
#TODO:for now compare absolute values instead of time normalized |
87
|
|
|
if self.statistics.hardware_errors >= self.ruleparameters.hardware_errors_limit: |
88
|
|
|
self.addbrokenrule(BrokenRule(self.miner, 'alert', 'on {} high error rate {}'.format(self.miner.name, self.statistics.hardware_errors))) |
89
|
|
|
|
90
|
|
|
def check_hash(self): |
91
|
|
|
if MinerStatisticsRule.hasreading_num(self.statistics.currenthash): |
92
|
|
|
if self.statistics.currenthash < self.ruleparameters.hashlimit: |
93
|
|
|
self.brokenrules.append(BrokenRule(self.miner, 'alert', 'on {0} low hash {1} below {2}'.format(self.miner.name, self.statistics.currenthash, self.ruleparameters.hashlimit))) |
94
|
|
|
if self.statistics.elapsed > self.ruleparameters.restartaftersec: |
95
|
|
|
self.addbrokenrule(BrokenRule(self.miner, 'restart', 'restart')) |
96
|
|
|
self.addbrokenrule(BrokenRule(self.miner, 'alert', 'restarting {0} '.format(self.miner.name))) |
97
|
|
|
|
98
|
|
|
def check_temp_controller(self): |
99
|
|
|
if MinerStatisticsRule.hasreading_num(self.statistics.controllertemp): |
100
|
|
|
if self.statistics.controllertemp and self.statistics.controllertemp > self.ruleparameters.controllertemplimit: |
101
|
|
|
self.addbrokenrule(BrokenRule(self.miner, 'alert', 'on {0} controller temp {1} exceeded {2}'.format(self.miner.name, self.statistics.controllertemp, self.ruleparameters.controllertemplimit))) |
102
|
|
|
|
103
|
|
|
def check_temp_boards(self): |
104
|
|
|
if MinerStatisticsRule.hasreading_num(self.statistics.tempboardmax()): |
105
|
|
|
if self.statistics.tempboardmax() > self.ruleparameters.boardtemplimit: |
106
|
|
|
self.addbrokenrule(BrokenRule(self.miner, 'alert', 'on {0} board temp {1} exceeded {2}'.format(self.miner.name, self.statistics.tempboardmax(), self.ruleparameters.boardtemplimit))) |
107
|
|
|
if self.ruleparameters.maxtempreset and self.statistics.tempboardmax() > self.ruleparameters.maxtempreset: |
108
|
|
|
if self.statistics.elapsed > self.ruleparameters.restartaftersec: |
109
|
|
|
self.addbrokenrule(BrokenRule(self.miner, 'restart', 'reboot')) |
110
|
|
|
|