2
0
mirror of https://github.com/xcat2/confluent.git synced 2025-01-17 21:23:18 +00:00

Add identify support

In the course of adding identify support, also took the opportunity to address
a few mistakes and refactor some code for future ease of development.
This commit is contained in:
Jarrod Johnon 2014-11-25 13:57:31 -05:00
parent 059b448932
commit a645e256eb
6 changed files with 93 additions and 39 deletions

View File

@ -110,6 +110,10 @@ noderesources = {
'default': 'ipmi',
}),
},
'identify': PluginRoute({
'pluginattrs': ['hardwaremanagement.method'],
'default': 'ipmi',
}),
'boot': {
'nextdevice': PluginRoute({
'pluginattrs': ['hardwaremanagement.method'],
@ -166,6 +170,8 @@ def show_user(name, configmanager):
def stripnode(iterablersp, node):
for i in iterablersp:
if i is None:
raise exc.NotImplementedException("Not Implemented")
i.strip_node(node)
yield i

View File

@ -36,6 +36,7 @@ class TargetEndpointUnreachable(ConfluentException):
# was unreachable. http code 504
pass
class TargetEndpointBadCredentials(ConfluentException):
# target was reachable, but authentication/authorization
# failed
@ -45,3 +46,9 @@ class TargetEndpointBadCredentials(ConfluentException):
class ForbiddenRequest(ConfluentException):
# The client request is not allowed by authorization engine
pass
class NotImplementedException(ConfluentException):
# The current configuration/plugin is unable to perform
# the requested task. http code 501
pass

View File

@ -390,8 +390,9 @@ def resourcehandler_backend(env, start_response):
except exc.TargetEndpointBadCredentials:
start_response('502 Bad Credentials', headers)
yield '502 - Bad Credentials'
except exc.NotImplementedException:
start_response('501 Not Implemented', headers)
yield '501 Not Implemented'
def _assemble_html(responses, resource, querydict, url, extension):
yield '<html><head><title>' \

View File

@ -171,6 +171,13 @@ class ConfluentChoiceMessage(ConfluentMessage):
valid_values = set()
valid_paramset = {}
def __init__(self, node, state):
self.kvpairs = {
node: {
self.keyname: {'value': state},
}
}
def html(self, extension=''):
snippet = ""
for key in self.kvpairs.iterkeys():
@ -247,6 +254,8 @@ def get_input_message(path, operation, inputdata, nodes=None):
return InputAttributes(path, inputdata, nodes)
elif path == ['boot', 'nextdevice'] and operation != 'retrieve':
return InputBootDevice(path, nodes, inputdata)
elif path == [ 'identify' ] and operation != 'retrieve':
return InputIdentifyMessage(path, nodes, inputdata)
elif inputdata:
raise exc.InvalidArgumentException()
@ -308,7 +317,49 @@ class InputAttributes(ConfluentMessage):
return nodeattr
class InputPowerMessage(ConfluentMessage):
class ConfluentInputMessage(ConfluentMessage):
keyname = 'state'
def __init__(self, path, nodes, inputdata):
self.inputbynode = {}
if not inputdata:
raise exc.InvalidArgumentException('missing input data')
if self.keyname not in inputdata:
#assume we have nested information
for key in nodes:
if key not in inputdata:
raise exc.InvalidArgumentException(key + ' not in request')
datum = inputdata[key]
if self.keyname not in datum:
raise exc.InvalidArgumentException(
'missing {0} argument'.format(self.keyname))
elif datum[self.keyname] not in self.valid_values:
raise exc.InvalidArgumentException(
datum[self.keyname] + ' is not one of ' +
','.join(self.valid_values))
self.inputbynode[key] = datum[self.keyname]
else: # we have a state argument not by node
datum = inputdata
if self.keyname not in datum:
raise exc.InvalidArgumentException('missing {0} argument'.format(self.keyname))
elif datum[self.keyname] not in self.valid_values:
raise exc.InvalidArgumentException(datum[self.keyname] +
' is not one of ' +
','.join(self.valid_values))
for node in nodes:
self.inputbynode[node] = datum[self.keyname]
class InputIdentifyMessage(ConfluentInputMessage):
valid_values = set([
'on',
'off',
])
keyname = 'identify'
class InputPowerMessage(ConfluentInputMessage):
valid_values = set([
'on',
'off',
@ -316,37 +367,8 @@ class InputPowerMessage(ConfluentMessage):
'boot',
])
def __init__(self, path, nodes, inputdata):
self.powerbynode = {}
if not inputdata:
raise exc.InvalidArgumentException('missing input data')
if 'state' not in inputdata:
#assume we have nested information
for key in nodes:
if key not in inputdata:
raise exc.InvalidArgumentException(key + ' not in request')
datum = inputdata[key]
if 'state' not in datum:
raise exc.InvalidArgumentException(
'missing state argument')
elif datum['state'] not in self.valid_values:
raise exc.InvalidArgumentException(
datum['state'] + ' is not one of ' +
','.join(self.valid_values))
self.powerbynode[key] = datum['state']
else: # we have a state argument not by node
datum = inputdata
if 'state' not in datum:
raise exc.InvalidArgumentException('missing state argument')
elif datum['state'] not in self.valid_values:
raise exc.InvalidArgumentException(datum['state'] +
' is not one of ' +
','.join(self.valid_values))
for node in nodes:
self.powerbynode[node] = datum['state']
def powerstate(self, node):
return self.powerbynode[node]
return self.inputbynode[node]
class BootDevice(ConfluentChoiceMessage):
@ -428,6 +450,14 @@ class InputBootDevice(BootDevice):
return self.bootmodebynode.get(node, 'unspecified')
class IdentifyState(ConfluentChoiceMessage):
valid_values = set([
'on',
'off',
])
keyname = 'identify'
class PowerState(ConfluentChoiceMessage):
valid_values = set([
'on',
@ -435,13 +465,9 @@ class PowerState(ConfluentChoiceMessage):
'reset',
'boot',
])
keyname = 'state'
def __init__(self, node, state):
self.kvpairs = {
node: {
'state': {'value': state},
}
}
class SensorReadings(ConfluentMessage):

View File

@ -213,6 +213,8 @@ def perform_request(operator, node, element, configdata, inputdata, cfg):
excmsg = str(ipmiexc)
if excmsg == 'Session no longer connected':
return msg.ConfluentTargetTimeout(node)
else:
raise
persistent_ipmicmds = {}
@ -275,6 +277,8 @@ class IpmiHandler(object):
return self.bootdevice()
elif self.element == ['health', 'hardware']:
return self.health()
elif self.element == ['identify']:
return self.identify()
@staticmethod
def _str_health(health):
@ -331,6 +335,12 @@ class IpmiHandler(object):
return msg.BootDevice(node=self.node,
device=bootdev['bootdev'])
def identify(self):
if 'update' == self.op:
identifystate = self.inputdata.inputbynode[self.node] == 'on'
self.ipmicmd.set_identify(on=identifystate)
return msg.IdentifyState(
node=self.node, state=self.inputdata.inputbynode[self.node])
def power(self):
if 'read' == self.op:
power = self.ipmicmd.get_power()

View File

@ -112,6 +112,10 @@ def sessionhdl(connection, authname, skipauth=False):
tlvdata.send(connection, {'errorcode': 504,
'error': 'Unreachable Target'})
tlvdata.send(connection, {'_requestdone': 1})
except exc.NotImplementedException:
tlvdata.send(connection, {'errorcode': 501,
'error': 'Not Implemented'})
tlvdata.send(connection, {'_requestdone': 1})
except SystemExit:
sys.exit(0)
except: