From 5e80407bc56cef6ddb05cfa4f53142600483bf2c Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Sat, 12 Oct 2013 15:13:34 -0400 Subject: [PATCH] Refactor plugin code to better assure all things happen in one greenthread Additionally, begin work to make ipmi.py start doing non-console things --- plugins/ipmi.py | 127 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 115 insertions(+), 12 deletions(-) diff --git a/plugins/ipmi.py b/plugins/ipmi.py index 9bd472d9..65e4470d 100644 --- a/plugins/ipmi.py +++ b/plugins/ipmi.py @@ -3,6 +3,7 @@ import eventlet import eventlet.event import os import pyghmi.ipmi.console as console +import pyghmi.ipmi.command as ipmicommand console.session.select = eventlet.green.select _ipmithread = None @@ -12,6 +13,13 @@ chainpulled = False tmptimeout = None ipmiq = collections.deque([]) ipmiwaiters = collections.deque([]) +ipmisessions = {} + + +def wait_on_ipmi(): + waitevt = eventlet.event.Event() + ipmiwaiters.append(waitevt) + waitevt.wait() def _ipmi_evtloop(): @@ -30,13 +38,22 @@ def _ipmi_evtloop(): waiter.send() def _process_chgs(intline): + #here we receive functions to run in our thread + #the tuples on the deque consist of: + #function, arg tuple, and optionally a callback + #to send the return value back to the requester global chainpulled os.read(intline,1) # answer the bell chainpulled = False while ipmiq: cval = ipmiq.popleft() if hasattr(cval[0], '__call__'): - cval[0](*cval[1]) + if isinstance(cval[1], tuple): + rv = cval[0](*cval[1]) + elif isinstance(cval[1], dict): + rv = cval[0](**cval[1]) + if len(cval) > 2: + cval[2](rv) @@ -91,16 +108,35 @@ class Console(object): def connect(self,callback): global _ipmithread global pullchain - self.solconnection = console.Console(bmc=self.bmc, - port=self.port, - userid=self.username, - password=self.password, - kg=self.kg, - force=True, - iohandler=callback) + global ipmisessions + global chainpulled + try: + ipmisession = ipmisessions[(self.bmc, self.port)] + except KeyError: + ipmisession = None if _ipmithread is None: pullchain = os.pipe() _ipmithread = eventlet.spawn(_ipmi_evtloop) + self.solconnection = None + ipmiq.append((console.Console,{'bmc': self.bmc, + 'port': self.port, + 'userid': self.username, + 'password': self.password, + 'kg': self.kg, + 'force': True, + 'ipmisession': ipmisession, + 'iohandler': callback}, self.got_consobject)) + if not chainpulled: + chainpulled = True + os.write(pullchain[1],'1') + while self.solconnection is None: + wait_on_ipmi() + if ipmisession is None: + ipmisessions[(self.bmc, self.port)] = \ + self.solconnection.ipmi_session + + def got_consobject(self, solconnection): + self.solconnection = solconnection def write(self, data): global chainpulled @@ -130,15 +166,81 @@ class Console(object): chainpulled=True os.write(pullchain[1],'1') eventlet.sleep(0.001) - waitevt = eventlet.event.Event() - ipmiwaiters.append(waitevt) - waitevt.wait() + wait_on_ipmi() #TODO: a channel for the ipmithread to tug back instead of busy wait #while tmptimeout is not None: # eventlet.sleep(0) #console.session.Session.wait_for_rsp(timeout=timeout) +class IpmiIterator(object): + def __init__(self, operator, nodes, element, cfg): + configdata = cfg.get_node_attributes(nodes, + ['secret.ipmiuser', 'secret.ipmipassphrase', + 'secret.managementuser', 'secret.managementpassphrase', + 'hardwaremanagement.manager']) + for node in nodes: + IpmiHandler(operator, node, element, configdata) + + def __iter__(self): + return self + + def next(self): + pass + + + + + +class IpmiHandler(object): + def __iter__(): + return self + + def __init__(self, operation, node, element, cfd): + self.cfg = cfd[node] + self.node = node + self.element = element + self.op = operation + connparams = get_conn_params(node, self.cfg) + self.ipmicmd = None + try: + ipmisession = ipmisessions[(self.bmc, self.port)] + except KeyError: + ipmisession = None + ipmiq.append((ipmicommand.Command,{'bmc': connparams['bmc'], + 'userid': connparams['username'], + 'password': connparams['passphrase'], + 'kg': connparams['kg'], + 'port': connparams['port'], + 'onlogon': self.handle_request, + 'ipmisession': ipmisession}, + got_ipmicmd)) + while self.ipmicmd == None: + wait_on_ipmi() + if ipmisession is None: + ipmisessions[(self.bmc, self.port)] = self.ipmicmd.ipmi_session + + def got_ipmicmd(self, ipmicmd): + self.ipmicmd = ipmicmd + + def call_ipmicmd(self, function, *args): + self.lastrsp = None + ipmiq.append((function, args, self.got_rsp)) + while self.lastrsp is None: + wait_on_ipmi() + return self.lastrsp + + def got_rsp(self, response): + self.lastrsp = response + + def handle_request(self, response): + if 'error' in response: + raise Exception(response['error']) + if self.element == 'power/state': + if 'read' == self.op: + rsp = self.call_ipmi(self.ipmicmd.get_power) + print(rsp) + def create(nodes, element, configmanager): if element == '_console/session': if len(nodes) > 1: @@ -149,5 +251,6 @@ def create(nodes, element, configmanager): "TODO(jbjohnso): ipmi api implementation of %s" % element) + def retrieve(nodes, element, configmanager): - raise Exception("TODO(jbjohnso): ipmi get implementation of %s" % element) + pass