2
0
mirror of https://github.com/xcat2/confluent.git synced 2024-11-22 09:32:21 +00:00

Add health/hardware resource to nodes and wire up for IPMI

This commit is contained in:
Jarrod Johnson 2014-04-15 14:59:36 -04:00
parent 6aaee681e7
commit ca2a4ed775
4 changed files with 134 additions and 19 deletions

4
TODO
View File

@ -36,3 +36,7 @@ Traceback (most recent call last):
passvalue = pluginmap[plugpath].__dict__[operation](
KeyError: ''
-reuse SDR to make health faster
-have pyghmi and friends do multiprocessing pools (particularly the PBKDF stuff in auth)
-bad password retrie

View File

@ -21,7 +21,27 @@ import confluent.exceptions as exc
import json
def _htmlify_structure(indict):
ret = "<ul>"
if isinstance(indict, dict):
for key in indict.iterkeys():
ret += "<li>{0}: ".format(key)
if type(indict[key]) in (str, unicode):
ret += indict[key]
else:
ret += _htmlify_structure(indict[key])
elif isinstance(indict, list):
if type(indict[0]) in (str, unicode):
ret += ",".join(indict)
else:
for v in indict:
ret += _htmlify_structure(v)
return ret + '</ul>'
class ConfluentMessage(object):
readonly = False
defaultvalue = ''
defaulttype = 'text'
@ -72,24 +92,31 @@ class ConfluentMessage(object):
value = '********'
if isinstance(val, list):
snippet += key + ":"
if len(val) == 0:
if len(val) == 0 and not self.readonly:
snippet += ('<input type="{0}" name="{1}" value="" '
' "title="{2}">'
).format(type, key, self.desc)
for v in val:
snippet += ('<input type="{0}" name="{1}" value="{2}" '
' "title="{3}">'
).format(type, key, v, self.desc)
snippet += (
'<input type="{0}" name="{1}" value="" title="{2}">'
'<input type="checkbox" name="restexplorerhonorkey" '
'value="{1}">').format(type, key, self.desc)
if self.readonly:
snippet += _htmlify_structure(v)
else:
snippet += ('<input type="{0}" name="{1}" value="{2}" '
' "title="{3}">'
).format(type, key, v, self.desc)
if not self.readonly:
snippet += (
'<input type="{0}" name="{1}" value="" title="{2}">'
'<input type="checkbox" name="restexplorerhonorkey" '
'value="{1}">').format(type, key, self.desc)
return snippet
snippet += (key + ":" +
'<input type="{0}" name="{1}" value="{2}" '
'title="{3}"><input type="checkbox" '
'name="restexplorerhonorkey" value="{1}">'
).format(type, key, value, self.desc)
if self.readonly:
snippet += "{0}: {1}".format(key, value)
else:
snippet += (key + ":" +
'<input type="{0}" name="{1}" value="{2}" '
'title="{3}"><input type="checkbox" '
'name="restexplorerhonorkey" value="{1}">'
).format(type, key, value, self.desc)
if len(notes) > 0:
snippet += '(' + ','.join(notes) + ')'
return snippet
@ -325,6 +352,45 @@ class PowerState(ConfluentChoiceMessage):
}
class SensorReadings(ConfluentMessage):
readonly = True
def __init__(self, sensors=[], name=None):
readings = []
for sensor in sensors:
sensordict = {'name': sensor['name']}
if 'value' in sensor:
sensordict['value'] = sensor['value']
if 'units' in sensor:
sensordict['units'] = sensor['units']
if 'states' in sensor:
sensordict['states'] = sensor['states']
if 'health' in sensor:
sensordict['health'] = sensor['health']
readings.append(sensordict)
if name is None:
self.kvpairs = {'sensors': readings}
else:
self.kvpairs = {name: {'sensors': readings}}
class HealthSummary(ConfluentMessage):
readonly = True
valid_values = set([
'ok',
'warning',
'critical',
'failed',
])
def __init__(self, health, name=None):
if health not in self.valid_values:
raise ValueError("%d is not a valid health state" % health)
if name is None:
self.kvpairs = {'health': {'value': health}}
else:
self.kvpairs = {name: {'health': {'value': health}}}
class Attributes(ConfluentMessage):
def __init__(self, name=None, kv=None, desc=''):
self.desc = desc

View File

@ -98,6 +98,12 @@ noderesources = {
'default': 'ipmi',
}),
},
'health': {
'hardware': PluginRoute({
'pluginattrs': ['hardwaremanagement.method'],
'default': 'ipmi',
}),
},
'boot': {
'nextdevice': PluginRoute({
'pluginattrs': ['hardwaremanagement.method'],

View File

@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import collections
import confluent.exceptions as exc
import confluent.interface.console as conapi
import confluent.messages as msg
@ -21,7 +20,7 @@ import eventlet.event
import eventlet.green.threading as threading
import eventlet.greenpool as greenpool
import eventlet.queue
import os
import pyghmi.constants as pygconstants
import pyghmi.exceptions as pygexc
import pyghmi.ipmi.console as console
import pyghmi.ipmi.command as ipmicommand
@ -156,6 +155,7 @@ class IpmiConsole(conapi.Console):
class IpmiIterator(object):
def __init__(self, operator, nodes, element, cfg, inputdata):
self.currdata = None
crypt = cfg.decrypt
cfg.decrypt = True
configdata = cfg.get_node_attributes(nodes, _configattributes)
@ -168,10 +168,15 @@ class IpmiIterator(object):
return self
def next(self):
ndata = self.gpile.next()
if self.currdata is None:
self.currdata = self.gpile.next()
# need to apply any translations between pyghmi and confluent
return ndata
try:
retdata = self.currdata.next()
except AttributeError:
retdata = self.currdata
self.currdata = None
return retdata
def perform_request(operator, node, element, configdata, inputdata):
return IpmiHandler(operator, node, element, configdata, inputdata).handle_request()
@ -220,6 +225,41 @@ class IpmiHandler(object):
return self.power()
elif self.element == [ 'boot', 'nextdevice' ]:
return self.bootdevice()
elif self.element == [ 'health', 'hardware' ]:
return self.health()
def _str_health(self, health):
if pygconstants.Health.Failed & health:
health = 'failed'
elif pygconstants.Health.Critical & health:
health = 'critical'
elif pygconstants.Health.Warning & health:
health = 'warning'
else:
health = 'ok'
return health
def _dict_sensor(self, pygreading):
retdict = {}
retdict['name'] = pygreading.name
retdict['value'] = pygreading.value
retdict['states'] = pygreading.states
retdict['health'] = self._str_health(pygreading.health)
return retdict
def health(self):
if 'read' == self.op:
response = self.ipmicmd.get_health()
health = response['health']
health = self._str_health(health)
yield msg.HealthSummary(health, self.node)
if 'badreadings' in response:
badsensors = []
for reading in response['badreadings']:
badsensors.append(self._dict_sensor(reading))
yield msg.SensorReadings(badsensors, name=self.node)
else:
raise exc.InvalidArgumentException('health is read-only')
def bootdevice(self):
if 'read' == self.op:
@ -275,4 +315,3 @@ def update(nodes, element, configmanager, inputdata):
def retrieve(nodes, element, configmanager, inputdata):
initthread()
return IpmiIterator('read', nodes, element, configmanager, inputdata)