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():