3 # This script is used to manipulate the operational state of nodes in
4 # different node groups. These are basically set operations on nodes via the
7 # Take the ng name as an argument....
9 # * get a list of nodes in the given nodegroup.
10 # * set some or all in the set to rins.
12 # * do something else to them all.
17 api = plc.PLC(auth.auth, auth.plc)
21 from config import config as cfg
22 from optparse import OptionParser
24 from nodecommon import *
25 from nodequery import verify,query_to_dict,node_select
27 from unified_model import *
32 import bootman # debug nodes
33 import monitor # down nodes with pcu
34 import reboot # down nodes without pcu
39 def __init__(self, fbnode):
42 def _send_pcunotice(self, host):
44 args['hostname'] = host
46 args['pcu_id'] = plc.getpcu(host)['pcu_id']
50 m = PersistMessage(host, mailtxt.pcudown_one[0] % args,
51 mailtxt.pcudown_one[1] % args, True, db='pcu_persistmessages')
53 loginbase = plc.siteId(hostname)
54 m.send([policy.TECHEMAIL % loginbase])
57 # TODO: It should be possible to diagnose the various conditions of
58 # the PCU here, and send different messages as appropriate.
59 if self.fbnode['pcu'] == "PCU":
60 self.action = "reboot.reboot('%s')" % host
62 pflags = PersistFlags(host, 1*60*60*24, db='pcu_persistflags')
63 if not pflags.getRecentFlag('pcutried'): # or not pflags.getFlag('pcufailed'):
64 pflags.setRecentFlag('pcutried')
66 ret = reboot.reboot(host)
72 import traceback; print traceback.print_exc(); print e
74 # NOTE: this failure could be an implementation issue on
75 # our end. So, extra notices are confusing...
76 # self._send_pcunotice(host)
78 pflags.setRecentFlag('pcufailed')
82 # we've tried the pcu recently, but it didn't work,
83 # so did we send a message about it recently?
84 if not pflags.getRecentFlag('pcumessagesent'):
86 self._send_pcunotice(host)
88 pflags.setRecentFlag('pcumessagesent')
100 # Reset every 4 weeks or so
101 pflags = PersistFlags(host, 27*60*60*24, db='mail_persistflags')
102 if not pflags.getRecentFlag('endrecord'):
103 node_end_record(host)
104 pflags.setRecentFlag('endrecord')
107 # Then in either case, run monitor.reboot()
108 self.action = "monitor.reboot('%s')" % host
110 return monitor.reboot(host)
112 import traceback; print traceback.print_exc(); print e
115 class RebootDebug(Reboot):
117 def direct(self, host):
118 self.action = "bootman.reboot('%s', config, None)" % host
119 return bootman.reboot(host, config, None)
121 class RebootBoot(Reboot):
123 def direct(self, host):
124 self.action = "bootman.reboot('%s', config, 'reboot')" % host
125 return bootman.reboot(host, config, 'reboot')
127 class RebootDown(Reboot):
129 def direct(self, host):
131 return False # this always fails, since the node will be down.
135 rebootlog = soltesz.dbLoad("rebootlog")
137 rebootlog = LogRoll()
139 parser = OptionParser()
140 parser.set_defaults(nodegroup=None,
156 parser.add_option("", "--node", dest="node", metavar="nodename.edu",
157 help="A single node name to add to the nodegroup")
158 parser.add_option("", "--nodelist", dest="nodelist", metavar="list.txt",
159 help="Use all nodes in the given file for operation.")
160 parser.add_option("", "--nodegroup", dest="nodegroup", metavar="NodegroupName",
161 help="Specify a nodegroup to perform actions on")
162 parser.add_option("", "--nodeselect", dest="nodeselect", metavar="querystring",
163 help="Specify a query to perform on findbad db")
165 parser.add_option("", "--verbose", dest="verbose", action="store_true",
166 help="Extra debug output messages.")
167 parser.add_option("", "--nosetup", dest="nosetup", action="store_true",
168 help="Do not perform the orginary setup phase.")
170 parser.add_option("", "--skip", dest="skip",
171 help="Number of machines to skip on the input queue.")
172 parser.add_option("", "--timewait", dest="timewait",
173 help="Minutes to wait between iterations of 10 nodes.")
175 parser.add_option("", "--stopselect", dest="stopselect", metavar="",
176 help="The select string that must evaluate to true for the node to be considered 'done'")
178 parser.add_option("", "--stopkey", dest="stopkey", metavar="",
180 parser.add_option("", "--stopvalue", dest="stopvalue", metavar="",
183 parser.add_option("", "--findbad", dest="findbad", action="store_true",
184 help="Re-run findbad on the nodes we're going to check before acting.")
185 parser.add_option("", "--force", dest="force", action="store_true",
186 help="Force action regardless of previous actions/logs.")
187 parser.add_option("", "--rins", dest="rins", action="store_true",
188 help="Set the boot_state to 'rins' for all nodes.")
189 parser.add_option("", "--reboot", dest="reboot", action="store_true",
190 help="Actively try to reboot the nodes, keeping a log of actions.")
191 #config = config(parser)
195 # COLLECT nodegroups, nodes and node lists
197 ng = api.GetNodeGroups({'name' : config.nodegroup})
198 nodelist = api.GetNodes(ng[0]['node_ids'])
199 hostnames = [ n['hostname'] for n in nodelist ]
201 if config.node or config.nodelist:
202 if config.node: hostnames = [ config.node ]
203 else: hostnames = config.getListFromFile(config.nodelist)
205 if config.nodeselect:
206 hostnames = node_select(config.nodeselect)
209 # rerun findbad with the nodes in the given nodes.
212 config.setFileFromList(file, hostnames)
213 os.system("./findbad.py --cachenodes --debug=0 --dbname=findbad --increment --nodelist %s" % file)
215 fb = soltesz.dbLoad("findbad")
219 for host in hostnames:
221 #if 'echo' in host or 'hptest-1' in host: continue
225 node = api.GetNodes(host)[0]
227 import traceback; print traceback.print_exc();
228 print "FAILED GETNODES for host: %s" % host
231 print "%-2d" % i, nodegroup_display(node, fb)
233 if i < int(config.skip): continue
235 if config.stopselect:
236 dict_query = query_to_dict(config.stopselect)
237 fbnode = fb['nodes'][host]['values']
238 observed_state = get_current_state(fbnode)
240 if verify(dict_query, fbnode) and observed_state != "dbg ":
241 # evaluates to true, therefore skip.
242 print "%s evaluates true for %s ; skipping..." % ( config.stopselect, host )
245 if config.stopkey and config.stopvalue:
246 fbnode = fb['nodes'][host]['values']
247 observed_state = get_current_state(fbnode)
249 if config.stopkey in fbnode:
250 if config.stopvalue in fbnode[config.stopkey] and observed_state != "dbg ":
251 print "%s has stopvalue; skipping..." % host
254 print "stopkey %s not in fbnode record for %s; skipping..." % (config.stopkey, host)
258 if not config.force and rebootlog.find(host, {'action' : ".*reboot"}, 60*60*2):
259 print "recently rebooted %s. skipping... " % host
263 # reset the boot_state to 'rins'
264 node = api.GetNodes(host, ['boot_state', 'last_contact', 'last_updated', 'date_created'])
265 record = {'observation' : node[0],
266 'model' : 'USER_REQUEST',
267 'action' : 'api.UpdateNode(%s, {"boot_state" : "rins"})' % host,
268 'time' : time.time()}
269 l = Log(host, record)
271 ret = api.UpdateNode(host, {'boot_state' : 'rins'})
273 # it's nice to see the current status rather than the previous status on the console
274 node = api.GetNodes(host)[0]
276 print "%-2d" % (i-1), nodegroup_display(node, fb)
279 print "FAILED TO UPDATE NODE BOOT STATE : %s" % host
284 fbnode = fb['nodes'][host]['values']
285 observed_state = get_current_state(fbnode)
287 if observed_state == "dbg ":
288 o = RebootDebug(fbnode)
290 elif observed_state == "boot" :
291 o = RebootBoot(fbnode)
293 elif observed_state == "down":
294 o = RebootDown(fbnode)
298 record = {'observation' : "DIRECT_SUCCESS: %s" % observed_state,
301 'time' : time.time()}
303 record = {'observation' : "PCU_SUCCESS: %s" % observed_state,
306 'time' : time.time()}
308 record = {'observation' : "MAIL_SUCCESS: %s" % observed_state,
311 'time' : time.time()}
313 record = {'observation' : "REBOOT_FAILED: %s" % observed_state,
314 'action' : "log failure",
316 'time' : time.time()}
318 print "ALL METHODS OF RESTARTING %s FAILED" % host
320 l = Log(host, record)
323 except KeyboardInterrupt:
324 print "Killed by interrupt"
327 import traceback; print traceback.print_exc();
328 print "Continuing..."
332 print "Saving rebootlog"
333 soltesz.dbDump("rebootlog", rebootlog)
334 wait_time = int(config.timewait)
335 print "Sleeping %d minutes" % wait_time
337 print "Minutes slept: ",
339 while ti < wait_time:
347 print "Saving rebootlog"
348 soltesz.dbDump("rebootlog", rebootlog)