2
0
mirror of https://github.com/xcat2/confluent.git synced 2024-11-26 11:30:23 +00:00

Enable support for IPMI user management

Provide a framework for management of users on managed endpoints, and implement for IPMI plugin.

From Juliana Motira
This commit is contained in:
Jarrod Johnson 2015-07-06 14:41:15 -04:00
parent 49bff93eed
commit 14a9220acb
4 changed files with 155 additions and 9 deletions

View File

@ -83,7 +83,7 @@ def load_plugins():
if plugtype == '.sh':
pluginmap[plugin] = shellmodule.Plugin(
os.path.join(plugindir, plugin + '.sh'))
elif "__init__" not in plugin:
elif "__init__" not in plugin:
plugins.add(plugin)
for plugin in plugins:
tmpmod = __import__(plugin)
@ -126,7 +126,11 @@ noderesources = {
'pluginattrs': ['hardwaremanagement.method'],
'default': 'ipmi',
}),
}
},
'users': PluginCollection({
'pluginattrs': ['hardwaremanagement.method'],
'default': 'ipmi',
}),
}
},
'_console': {

View File

@ -103,9 +103,36 @@ def node_creation_resources():
desc=attribs.node[attr]['description']).html() + '<br>\n'
def user_creation_resources():
credential = {
'uid': {
'description': (''),
},
'username': {
'description': (''),
},
'password': {
'description': (''),
},
'privilege_level': {
'description': (''),
},
}
for attr in sorted(credential.iterkeys()):
if attr == "password":
yield confluent.messages.CryptedAttributes(
kv={attr: None},
desc=credential[attr]['description']).html() + '<br>\n'
else:
yield confluent.messages.Attributes(
kv={attr: None},
desc=credential[attr]['description']).html() + '<br>\n'
create_resource_functions = {
'/nodes/': node_creation_resources,
'/groups/': group_creation_resources,
'nodes': node_creation_resources,
'groups': group_creation_resources,
'users': user_creation_resources,
}
@ -444,11 +471,15 @@ def _assemble_html(responses, resource, querydict, url, extension):
if iscollection:
# localpath = url[:-2] (why was this here??)
try:
if url == '/users/':
return
firstpass = True
for y in create_resource_functions[url]():
module = url.split('/')
if not module:
return
for y in create_resource_functions[module[-2]]():
if firstpass:
yield "<hr>Define new resource in %s:<BR>" % \
url.split("/")[-2]
yield "<hr>Define new resource in %s:<BR>" % module[-2]
firstpass = False
yield y
yield ('<input value="create" name="restexplorerop" type="submit">'

View File

@ -107,7 +107,10 @@ class ConfluentMessage(object):
for key in pairs.iterkeys():
val = pairs[key]
value = self.defaultvalue
valtype = self.defaulttype
if isinstance(val, dict) and 'type' in val:
valtype = val['type']
else:
valtype = self.defaulttype
notes = []
if isinstance(val, list):
@ -322,6 +325,9 @@ def get_input_message(path, operation, inputdata, nodes=None, multinode=False):
return InputIdentifyMessage(path, nodes, inputdata)
elif path == ['events', 'hardware', 'decode']:
return InputAlertData(path, inputdata, nodes)
elif (path[:3] == ['configuration', 'management_controller', 'users'] and
operation != 'retrieve'):
return InputCredential(path, inputdata, nodes)
elif inputdata:
raise exc.InvalidArgumentException()
@ -405,6 +411,61 @@ class InputAttributes(ConfluentMessage):
return nodeattr
class InputCredential(ConfluentMessage):
valid_privilege_levels = set([
'callback',
'user',
'operator',
'administrator',
'proprietary',
'no_access',
])
def __init__(self, path, inputdata, nodes=None):
self.credentials = {}
nestedmode = False
if not inputdata:
raise exc.InvalidArgumentException('no request data provided')
if len(path) == 4:
inputdata['uid'] = path[-1]
if ('uid' not in inputdata or 'privilege_level' not in inputdata
or 'username' not in inputdata or 'password' not in inputdata):
raise exc.InvalidArgumentException('missing arguments')
if not inputdata['uid'].isdigit():
raise exc.InvalidArgumentException('uid must be a number')
else:
inputdata['uid'] = int(inputdata['uid'])
if inputdata['privilege_level'] not in self.valid_privilege_levels:
raise exc.InvalidArgumentException('privilege_level is not one of '
+ ','.join(self.valid_privilege_levels))
if nodes is None:
raise exc.InvalidArgumentException(
'This only supports per-node input')
for node in nodes:
self.credentials[node] = inputdata
def get_attributes(self, node):
if node not in self.credentials:
return {}
credential = self.credentials[node]
for attr in credentials:
if type(credentials[attr]) in (str, unicode):
try:
# as above, use format() to see if string follows
# expression, store value back in case of escapes
tv = credential[attr].format()
credential[attr] = tv
except (KeyError, IndexError):
# an expression string will error if format() done
# use that as cue to put it into config as an expr
credential[attr] = {'expression': credential[attr]}
return credential
class ConfluentInputMessage(ConfluentMessage):
keyname = 'state'
@ -480,7 +541,7 @@ class BootDevice(ConfluentChoiceMessage):
valid_paramset = {
'bootmode': valid_bootmodes,
}
def __init__(self, node, device, bootmode='unspecified'):
if device not in self.valid_values:
@ -601,6 +662,21 @@ class EventCollection(ConfluentMessage):
self.kvpairs = {name: {'events': eventdata}}
class User(ConfluentMessage):
def __init__(self, uid, username, privilege_level, name=None):
self.desc = 'foo'
self.stripped = False
self.notnode = name is None
kvpairs = {'username': {'value': username},
'password': {'value': '', 'type': 'password'},
'privilege_level': {'value': privilege_level}
}
if self.notnode:
self.kvpairs = kvpairs
else:
self.kvpairs = {name: kvpairs}
class AlertDestination(ConfluentMessage):
def __init__(self, ip, acknowledge=False, retries=0, name=None):
self.desc = 'foo'

View File

@ -371,6 +371,8 @@ class IpmiHandler(object):
def handle_configuration(self):
if self.element[1:3] == ['management_controller', 'alerts' ]:
return self.handle_alerts()
elif self.element[1:3] == ['management_controller', 'users' ]:
return self.handle_users()
raise Exception('Not implemented')
def decode_alert(self):
@ -421,6 +423,39 @@ class IpmiHandler(object):
return
raise Exception('Not implemented')
def handle_users(self):
if len(self.element) == 3:
if self.op == 'update':
user = self.inputdata.credentials[self.node]
self.ipmicmd.create_user(uid=user['uid'], name=user['username'],
password=user['password'], channel=1,
callback=True,link_auth=True, ipmi_msg=True,
privilege_level=user['privilege_level'])
# A list of users
for user in self.ipmicmd.get_users(channel=1):
self.output.put(msg.ChildCollection(user))
return
elif len(self.element) == 4:
user = int(self.element[-1])
if self.op == 'read':
data = self.ipmicmd.get_user(uid=user, channel=1)
self.output.put(msg.User(
uid=data['uid'],
username=data['name'],
privilege_level=data['access']['privilege_level'],
name=self.node))
return
elif self.op == 'update':
user = self.inputdata.credentials[self.node]
self.ipmicmd.create_user(uid=user['uid'], name=user['username'],
password=user['password'], channel=1,
callback=True,link_auth=True, ipmi_msg=True,
privilege_level=user['privilege_level'])
return
elif self.op == 'delete':
self.ipmicmd.user_delete(uid=user, channel=1)
return
def do_eventlog(self):
eventout = []
for event in self.ipmicmd.get_event_log():