added firewall checks and notices
[monitor.git] / nodebad.py
1 #!/usr/bin/python
2
3 import os
4 import sys
5 import string
6 import time
7 from datetime import datetime,timedelta
8
9 from nodequery import verify,query_to_dict,node_select
10
11 from monitor.common import *
12
13 from monitor import config
14 from monitor.wrapper import plc,plccache
15 from monitor.const import MINUP
16 from monitor.database.info.model import  FindbadNodeRecord, HistoryNodeRecord
17 from monitor.database.dborm import  mon_session as session
18
19 from monitor.model import *
20
21 api = plc.getAuthAPI()
22
23 round = 1
24 count = 0
25 def main():
26         main2(config)
27
28 def main2(config):
29
30         l_plcnodes = plccache.l_nodes
31         l_nodes = get_nodeset(config)
32         
33         checkAndRecordState(l_nodes, l_plcnodes)
34
35 # Node states:
36
37 def check_node_state(rec, node):
38
39         node_state = rec.observed_status
40         if rec.plc_node_stats:
41                 print rec.plc_node_stats
42                 boot_state = rec.plc_node_stats['boot_state']
43                 last_contact = rec.plc_node_stats['last_contact']
44                 node.plc_nodeid = rec.plc_node_stats['node_id']
45         else:
46                 boot_state = "unknown"
47                 last_contact = None
48
49         if boot_state == 'disable': boot_state = 'disabled'
50         if boot_state == 'diag' or boot_state == 'diagnose': boot_state = 'safeboot'
51
52         if len(rec.plc_node_stats['pcu_ids']) > 0:
53                 node.haspcu = True
54         else:
55                 node.haspcu = False
56
57         node.firewall = rec.firewall
58
59
60         # NOTE: 'DOWN' and 'DEBUG'  are temporary states, so only need
61         #                       'translations' into the node.status state
62         #               'BOOT' is a permanent state, but we want it to have a bit of
63         #                       hysteresis (less than 0.5 days)
64
65         #################################################################
66         # "Initialize" the findbad states into nodebad status if they are not already set
67
68         if node_state == 'DOWN':
69                 if boot_state == 'disabled' and changed_lessthan(node.last_changed, 60) and \
70                         node.status != 'disabled':
71                         # NOTE: if changed less than 2 months, then we can allow this. 
72                         # otherwise, apply 'down' status after greater than 2 months (below).
73
74                         print "changed status from %s to %s" % (node.status, boot_state)
75                         node.status = boot_state
76                         node.last_changed = datetime.now()
77
78                 if node.status not in ['offline', 'down', 'disabled']:
79                         print "changed status from %s to offline" % node.status
80                         node.status = 'offline'
81                         node.last_changed = datetime.now()
82                         
83
84         #if node_state == 'DOWN' and node.status not in ['offline', 'down', 'disabled']:
85         #       if boot_state != 'disabled':
86         #               print "changed status from %s to offline" % node.status
87         #               node.status = 'offline'
88         #               node.last_changed = datetime.now()
89         #       else:
90         #               print "changed status from %s to %s" % (node.status, boot_state)
91         #               node.status = boot_state
92         #               node.last_changed = datetime.now()
93
94         if node_state == 'DEBUG' and node.status != 'monitordebug' and \
95                                                                  node.status != 'disabled' and \
96                                                                  node.status != 'safeboot':
97                 if boot_state != 'disabled' and boot_state != 'safeboot':
98
99                         print "changed status from %s to monitordebug" % (node.status)
100                         node.status = "monitordebug"
101                         node.last_changed = datetime.now()
102                 else:
103                         print "changed status from %s to %s" % (node.status, boot_state)
104                         node.status = boot_state
105                         node.last_changed = datetime.now()
106
107         if node_state == 'BOOT' and node.status != 'online' and node.status != 'good':
108                 print "changed status from %s to online" % node.status
109                 node.status = 'online'
110                 node.last_changed = datetime.now()
111
112         #################################################################
113         # Switch temporary hystersis states into their 'firm' states.
114         #         online -> good                after half a day
115         #         offline -> down               after two days
116         #         monitordebug -> down  after 30 days
117         #         safeboot -> monitordebug after 60 days
118         #         disabled -> down              after 60 days
119
120         if node.status == 'online' and changed_greaterthan(node.last_changed, 0.5):
121                 print "changed status from %s to good" % node.status
122                 node.status = 'good'
123                 # NOTE: do not reset last_changed, or you lose how long it's been up.
124
125         if node.status == 'offline' and changed_greaterthan(node.last_changed, 2):
126                 print "changed status from %s to down" % node.status
127                 node.status = 'down'
128                 # NOTE: do not reset last_changed, or you lose how long it's been down.
129
130         if node.status == 'monitordebug' and changed_greaterthan(node.last_changed, 30):
131                 print "changed status from %s to down" % node.status
132                 node.status = 'down'
133                 # NOTE: do not reset last_changed, or you lose how long it's been down.
134
135         if node.status == 'safeboot' and changed_greaterthan(node.last_changed, 60):
136                 print "changed status from %s to down" % node.status
137                 # NOTE: change an admin mode back into monitordebug after two months.
138                 node.status = 'monitordebug'
139                 node.last_changed = datetime.now()
140
141         # extreme cases of offline nodes
142         if ( boot_state == 'disabled' or last_contact == None ) and \
143                         changed_greaterthan(node.last_changed, 2*30) and \
144                         node.status != 'down':
145                 print "changed status from %s to down" % node.status
146                 node.status = 'down'
147                 node.last_changed = datetime.now()
148
149 def checkAndRecordState(l_nodes, l_plcnodes):
150         global count
151
152         for nodename in l_nodes:
153
154                 nodehist = HistoryNodeRecord.findby_or_create(hostname=nodename, 
155                                                         if_new_set={'status' : 'offline', 
156                                                                                 'last_changed' : datetime.now()})
157                 nodehist.last_checked = datetime.now()
158
159                 try:
160                         # Find the most recent record
161                         noderec = FindbadNodeRecord.get_latest_by(hostname=nodename)
162                 except:
163                         print "COULD NOT FIND %s" % nodename
164                         import traceback
165                         email_exception()
166                         print traceback.print_exc()
167                         continue
168
169                 if not noderec:
170                         print "none object for %s"% nodename
171                         continue
172
173                 check_node_state(noderec, nodehist)
174
175                 count += 1
176                 print "%d %35s %s since(%s)" % (count, nodename, nodehist.status, diff_time(time.mktime(nodehist.last_changed.timetuple())))
177
178         # NOTE: this commits all pending operations to the DB.  Do not remove. 
179         session.flush()
180
181         return True
182
183 if __name__ == '__main__':
184         from monitor import parser as parsermodule
185         parser = parsermodule.getParser(['nodesets'])
186         parser.set_defaults(filename=None, node=None, nodeselect=False, nodegroup=None, cachenodes=False)
187         parser = parsermodule.getParser(['defaults'], parser)
188         config = parsermodule.parse_args(parser)
189
190         try:
191                 main2(config)
192         except Exception, err:
193                 import traceback
194                 print traceback.print_exc()
195                 print "Exception: %s" % err
196                 sys.exit(0)