diff --git a/confluent_server/confluent/core.py b/confluent_server/confluent/core.py index 82d0f0cd..28c5294a 100644 --- a/confluent_server/confluent/core.py +++ b/confluent_server/confluent/core.py @@ -118,6 +118,16 @@ noderesources = { 'default': 'ipmi', }), }, + 'configuration': { + 'management_controller': { + 'alerts': { + 'destinations': PluginCollection({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + } + } + }, '_console': { 'session': PluginRoute({ 'pluginattrs': ['console.method'], @@ -128,12 +138,12 @@ noderesources = { 'session': PluginRoute({}), }, 'events': { - 'hardware': { - 'log': PluginRoute({ - 'pluginattrs': ['hardwaremanagement.method'], - 'default': 'ipmi', - }) - } + 'hardware': { + 'log': PluginRoute({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }) + }, }, 'health': { 'hardware': PluginRoute({ @@ -417,7 +427,8 @@ def handle_node_request(configmanager, inputdata, operation, except TypeError: allnodes.sort() return iterate_collections(allnodes) - if isnoderange and len(pathcomponents) == 3 and pathcomponents[2] == 'nodes': + if (isnoderange and len(pathcomponents) == 3 and + pathcomponents[2] == 'nodes'): # this means that it's a list of relevant nodes nodes = list(nodes) try: @@ -447,7 +458,7 @@ def handle_node_request(configmanager, inputdata, operation, passvalues = [] plugroute = routespec.routeinfo inputdata = msg.get_input_message( - pathcomponents, operation, inputdata, nodes) + pathcomponents, operation, inputdata, nodes, isnoderange) if 'handler' in plugroute: # fixed handler definition, easy enough hfunc = getattr(pluginmap[plugroute['handler']], operation) passvalue = hfunc( diff --git a/confluent_server/confluent/messages.py b/confluent_server/confluent/messages.py index 0b96f59e..4718aa79 100644 --- a/confluent_server/confluent/messages.py +++ b/confluent_server/confluent/messages.py @@ -121,15 +121,14 @@ class ConfluentMessage(object): snippet += _htmlify_structure(v) else: snippet += ('' + ' "title="{3}">\r' ).format(valtype, key, v, self.desc) if not self.readonly: snippet += ( '' '').format(valtype, key, self.desc) + 'value="{1}">\r').format(valtype, key, self.desc) return snippet - snippet += repr(val) if val is not None and 'value' in val: value = val['value'] if 'inheritedfrom' in val: @@ -159,7 +158,7 @@ class ConfluentMessage(object): snippet += (key + ":" + '' + 'name="restexplorerhonorkey" value="{1}">
\r' ).format(valtype, key, value, self.desc) if len(notes) > 0: snippet += '(' + ','.join(notes) + ')' @@ -308,13 +307,17 @@ class ChildCollection(LinkRelation): extension) -def get_input_message(path, operation, inputdata, nodes=None): +def get_input_message(path, operation, inputdata, nodes=None, multinode=False): if path[0] == 'power' and path[1] == 'state' and operation != 'retrieve': return InputPowerMessage(path, nodes, inputdata) elif path[0] in ('attributes', 'users') and operation != 'retrieve': return InputAttributes(path, inputdata, nodes) elif path == ['boot', 'nextdevice'] and operation != 'retrieve': return InputBootDevice(path, nodes, inputdata) + elif (len(path) == 5 and + path[:4] == ['configuration', 'management_controller', 'alerts', + 'destinations'] and operation != 'retrieve'): + return InputAlertDestination(path, nodes, inputdata, multinode) elif path == ['identify'] and operation != 'retrieve': return InputIdentifyMessage(path, nodes, inputdata) elif inputdata: @@ -573,6 +576,53 @@ class EventCollection(ConfluentMessage): self.kvpairs = {name: {'events': eventdata}} +class AlertDestination(ConfluentMessage): + def __init__(self, ip, acknowledge=False, retries=0, name=None): + self.desc = 'foo' + self.stripped = False + self.notnode = name is None + kvpairs = {'ip': {'value': ip}, + 'acknowledge': {'value': acknowledge}, + 'retries': {'value': retries}} + if self.notnode: + self.kvpairs = kvpairs + else: + self.kvpairs = {name: kvpairs} + + +class InputAlertDestination(ConfluentMessage): + valid_alert_params = ( + 'acknowledge', + 'ip', + 'retries' + ) + + def __init__(self, path, nodes, inputdata, multinode=False): + self.alertcfg = {} + if multinode: # keys are node names + for node in inputdata: + self.alertcfg[node] = inputdata[node] + for key in inputdata[node]: + if key not in self.valid_alert_params: + raise exc.InvalidArgumentException( + 'Unrecognized alert parameter ' + key) + if isinstance(inputdata[node][key], dict): + self.alertcfg[node][key] = \ + inputdata[node][key]['value'] + else: + for key in inputdata: + if key not in self.valid_alert_params: + raise exc.InvalidArgumentException( + 'Unrecognized alert parameter ' + key) + if isinstance(inputdata[key], dict): + inputdata[key] = inputdata[key]['value'] + for node in nodes: + self.alertcfg[node] = inputdata + + def alert_params_by_node(self, node): + return self.alertcfg[node] + + class SensorReadings(ConfluentMessage): readonly = True diff --git a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py index 56258260..c2dd8673 100644 --- a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py +++ b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py @@ -348,6 +348,8 @@ class IpmiHandler(object): self.identify() elif self.element[0] == 'sensors': self.handle_sensors() + elif self.element[0] == 'configuration': + self.handle_configuration() elif self.element[0] == 'inventory': self.handle_inventory() elif self.element == ['events', 'hardware', 'log']: @@ -355,6 +357,48 @@ class IpmiHandler(object): else: raise Exception('Not Implemented') + def handle_configuration(self): + if self.element[1:3] == ['management_controller', 'alerts' ]: + return self.handle_alerts() + raise Exception('Not implemented') + + def handle_alerts(self): + if self.element[3] == 'destinations': + if len(self.element) == 4: + # A list of destinations + maxdest = self.ipmicmd.get_alert_destination_count() + for alertidx in xrange(0, maxdest + 1): + self.output.put(msg.ChildCollection(alertidx)) + return + elif len(self.element) == 5: + alertidx = int(self.element[-1]) + if self.op == 'read': + destdata = self.ipmicmd.get_alert_destination(alertidx) + self.output.put(msg.AlertDestination( + ip=destdata['address'], + acknowledge=destdata['acknowledge_required'], + retries=destdata['retries'], + name=self.node)) + return + elif self.op == 'update': + alertparms = self.inputdata.alert_params_by_node( + self.node) + alertargs = {} + if 'acknowledge' in alertparms: + alertargs['acknowledge_required'] = alertparms['acknowledge'] + if 'ip' in alertparms: + alertargs['ip'] = alertparms['ip'] + if 'retries' in alertparms: + alertargs['retries'] = alertparms['retries'] + self.ipmicmd.set_alert_destination(destination=alertidx, + **alertargs) + return + elif self.op == 'delete': + self.ipmicmd.clear_alert_destination(alertidx) + return + raise Exception('Not implemented') + + def do_eventlog(self): eventout = [] for event in self.ipmicmd.get_event_log():