From a29032e70c0820792774b4da582f0bfdf42c1fe4 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Tue, 1 Apr 2014 16:53:20 -0400 Subject: [PATCH] Rework ipmi console object to block on connect Previously, the state would be seen as 'connected' and then 'disconnected' in event of connection failing. Rework things such that the console session stays in 'connecting' state until timeout or success occurs and don't send disconnect, instead raising an exception. This makes the connection action a bit more intuitive to the user, who would assume a 'connected' console means the endpoint was reachable. This may not always be possible in a console plugin, but it's a nice pattern when possible. If a console plugin cannot tell when 'connected' happens, then the previous behavior of this plugin makes sense as a 'best effort': return 'connected', send disconnect event when the console turns out to be bad. For example, executable consoles are most likely going to follow this pattern. An option could be for an executable to have a certain signature to print to show 'connected' though... --- plugins/hardwaremanagement/ipmi.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/plugins/hardwaremanagement/ipmi.py b/plugins/hardwaremanagement/ipmi.py index f14a36e6..c459dce6 100644 --- a/plugins/hardwaremanagement/ipmi.py +++ b/plugins/hardwaremanagement/ipmi.py @@ -16,11 +16,15 @@ console.session.select = eventlet.green.select console.session.threading = eventlet.green.threading _ipmithread = None +_ipmiwaiters = [] def _ipmi_evtloop(): while True: try: console.session.Session.wait_for_rsp(timeout=600) + while _ipmiwaiters: + waiter = _ipmiwaiters.pop() + waiter.send() except: import traceback traceback.print_exc() @@ -73,6 +77,7 @@ class IpmiConsole(conapi.Console): self.kg = connparams['kg'] self.bmc = connparams['bmc'] self.port = connparams['port'] + self.connected = False # Cannot actually create console until 'connect', when we get callback def handle_data(self, data): @@ -80,7 +85,9 @@ class IpmiConsole(conapi.Console): disconnect = frozenset(('Session Disconnected', 'timeout')) if 'error' in data and data['error'] in disconnect: self.broken = True - self.datacallback(conapi.ConsoleEvent.Disconnect) + self.error = data['error'] + if self.connected: + self.datacallback(conapi.ConsoleEvent.Disconnect) else: raise Exception("Unrecognized pyghmi input %s" % repr(data)) else: @@ -94,9 +101,16 @@ class IpmiConsole(conapi.Console): password=self.password, kg=self.kg, force=True, iohandler=self.handle_data) + while not self.solconnection.connected and not self.broken: + w = eventlet.event.Event() + _ipmiwaiters.append(w) + w.wait() + if self.broken: + raise exc.TargetEndpointUnreachable(self.error) except socket.gaierror as err: raise exc.TargetEndpointUnreachable(str(err)) + def write(self, data): self.solconnection.send_data(data)