mirror of
				https://github.com/xcat2/confluent.git
				synced 2025-11-04 13:22:42 +00:00 
			
		
		
		
	Add health/hardware resource to nodes and wire up for IPMI
This commit is contained in:
		
							
								
								
									
										4
									
								
								TODO
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								TODO
									
									
									
									
									
								
							@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -98,6 +98,12 @@ noderesources = {
 | 
			
		||||
            'default': 'ipmi',
 | 
			
		||||
        }),
 | 
			
		||||
    },
 | 
			
		||||
    'health': {
 | 
			
		||||
        'hardware': PluginRoute({
 | 
			
		||||
            'pluginattrs': ['hardwaremanagement.method'],
 | 
			
		||||
            'default': 'ipmi',
 | 
			
		||||
        }),
 | 
			
		||||
    },
 | 
			
		||||
    'boot': {
 | 
			
		||||
        'nextdevice': PluginRoute({
 | 
			
		||||
            'pluginattrs': ['hardwaremanagement.method'],
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user