diff --git a/confluent_server/confluent/core.py b/confluent_server/confluent/core.py index 51138801..58cfaa4a 100644 --- a/confluent_server/confluent/core.py +++ b/confluent_server/confluent/core.py @@ -250,6 +250,25 @@ def _init_core(): }, }, }, + 'media': { + 'uploads': PluginCollection({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + 'attach': PluginRoute({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + 'detach': PluginRoute({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + 'current': PluginRoute({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + + }, 'power': { 'state': PluginRoute({ 'pluginattrs': ['hardwaremanagement.method'], diff --git a/confluent_server/confluent/firmwaremanager.py b/confluent_server/confluent/firmwaremanager.py index 0c836f95..10b4c287 100644 --- a/confluent_server/confluent/firmwaremanager.py +++ b/confluent_server/confluent/firmwaremanager.py @@ -23,13 +23,17 @@ import confluent.messages as msg import eventlet updatesbytarget = {} +uploadsbytarget = {} updatepool = eventlet.greenpool.GreenPool(256) -def execupdate(handler, filename, updateobj): +def execupdate(handler, filename, updateobj, type): try: - completion = handler(filename, progress=updateobj.handle_progress, - bank=updateobj.bank) + if type == 'firmware': + completion = handler(filename, progress=updateobj.handle_progress, + bank=updateobj.bank) + else: + completion = handler(filename, progress=updateobj.handle_progress) if completion is None: completion = 'complete' updateobj.handle_progress({'phase': completion, 'progress': 100.0}) @@ -44,26 +48,30 @@ def execupdate(handler, filename, updateobj): class Updater(object): def __init__(self, node, handler, filename, tenant=None, name=None, - bank=None): + bank=None, type='firmware'): self.bank = bank self.node = node self.phase = 'initializing' self.detail = '' self.percent = 0.0 - #Change the below to a pool??? - self.updateproc = updatepool.spawn(execupdate, handler, filename, self) - if (node, tenant) not in updatesbytarget: - updatesbytarget[(node, tenant)] = {} + self.updateproc = updatepool.spawn(execupdate, handler, filename, + self, type) + if type == 'firmware': + myparty = updatesbytarget + elif type == 'mediaupload': + myparty = uploadsbytarget + if (node, tenant) not in myparty: + myparty[(node, tenant)] = {} if name is None: name = 1 - while '{0}'.format(name) in updatesbytarget[(node, tenant)]: + while '{0}'.format(name) in myparty[(node, tenant)]: name += 1 self.name = '{0}'.format(name) - updatesbytarget[(node, tenant)][self.name] = self + myparty[(node, tenant)][self.name] = self def handle_progress(self, progress): - self.phase = progress['phase'] - self.percent = float(progress['progress']) + self.phase = progress.get('phase', 'unknown') + self.percent = float(progress.get('progress', 100.0)) self.detail = progress.get('detail', '') def cancel(self): @@ -91,18 +99,25 @@ def remove_updates(nodes, tenant, element): node, upid)) -def list_updates(nodes, tenant, element): +def list_updates(nodes, tenant, element, type='firmware'): showmode = False + if type == 'mediaupload': + myparty = uploadsbytarget + verb = 'upload' + else: + myparty = updatesbytarget + verb = 'update' if len(element) > 4: showmode = True upid = element[-1] for node in nodes: if showmode: try: - updater = updatesbytarget[(node, tenant)][upid] + updater = myparty[(node, tenant)][upid] except KeyError: - raise exc.NotFoundException('No matching update process found') + raise exc.NotFoundException( + 'No matching {0} process found'.format(verb)) yield msg.KeyValueData(updater.progress, name=node) else: - for updateid in updatesbytarget.get((node, tenant), {}): + for updateid in myparty.get((node, tenant), {}): yield msg.ChildCollection(updateid) diff --git a/confluent_server/confluent/messages.py b/confluent_server/confluent/messages.py index b89f4505..321361a6 100644 --- a/confluent_server/confluent/messages.py +++ b/confluent_server/confluent/messages.py @@ -407,6 +407,10 @@ def get_input_message(path, operation, inputdata, nodes=None, multinode=False, return InputNTPServer(path, nodes, inputdata) elif 'inventory/firmware/updates/active' in '/'.join(path) and inputdata: return InputFirmwareUpdate(path, nodes, inputdata) + elif '/'.join(path).startswith('media/detach'): + return DetachMedia(path, nodes, inputdata) + elif '/'.join(path).startswith('media/'): + return InputMedia(path, nodes, inputdata) elif inputdata: raise exc.InvalidArgumentException( 'No known input handler for request') @@ -414,10 +418,22 @@ def get_input_message(path, operation, inputdata, nodes=None, multinode=False, class InputFirmwareUpdate(ConfluentMessage): def __init__(self, path, nodes, inputdata): - self.filename = inputdata['filename'] + self.filename = inputdata.get('filename', inputdata['url']) self.bank = inputdata.get('bank', None) self.nodes = nodes +class InputMedia(InputFirmwareUpdate): + # Use InputFirmwareUpdate + pass + +class DetachMedia(ConfluentMessage): + def __init__(self, path, nodes, inputdata): + if inputdata['detach'] != 'all': + raise exc.InvalidArgumentException('Currently only supporting' + '{"detach": "all"}') +class Media(ConfluentMessage): + def __init__(self, node, media): + self.kvpairs = {node: {'name': media.name, 'url': media.url}} class InputAlertData(ConfluentMessage): diff --git a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py index b3030b63..756ee04e 100644 --- a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py +++ b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py @@ -450,6 +450,14 @@ class IpmiHandler(object): self.handle_update() elif self.element[0] == 'inventory': self.handle_inventory() + elif self.element == ['media', 'attach']: + self.handle_attach_media() + elif self.element == ['media', 'detach']: + self.handle_detach_media() + elif self.element == ['media', 'uploads']: + self.handle_media_upload() + elif self.element == ['media', 'current']: + self.handle_list_media() elif self.element == ['events', 'hardware', 'log']: self.do_eventlog() elif self.element == ['events', 'hardware', 'decode']: @@ -468,6 +476,22 @@ class IpmiHandler(object): 'nodes/{0}/inventory/firmware/updates/active/{1}'.format( self.node, u.name))) + def handle_media_upload(self): + u = firmwaremanager.Updater(self.node, self.ipmicmd.upload_media, + self.inputdata.filename, self.tenant, + type='mediaupload') + self.output.put(msg.CreatedResource( + 'nodes/{0}/media/uploads/{1}'.format(self.node, u.name))) + + def handle_attach_media(self): + self.ipmicmd.attach_remote_media(self.inputdata.filename) + + def handle_detach_media(self): + self.ipmicmd.detach_remote_media() + + def handle_list_media(self): + for media in self.ipmicmd.list_media(): + self.output.put(msg.Media(self.node, media)) def handle_configuration(self): if self.element[1:3] == ['management_controller', 'alerts']: @@ -1022,6 +1046,9 @@ def retrieve(nodes, element, configmanager, inputdata): if '/'.join(element).startswith('inventory/firmware/updates/active'): return firmwaremanager.list_updates(nodes, configmanager.tenant, element) + elif '/'.join(element).startswith('media/uploads'): + return firmwaremanager.list_updates(nodes, configmanager.tenent, + element, 'mediaupload') else: return perform_requests('read', nodes, element, configmanager, inputdata)