#750: Using more descriptive status; new route {{{POST /command}}} to launch command/script in a callback thread that returns all data to a server route.

oglive^2
Ramón M. Gómez 2018-06-30 17:13:45 +02:00
parent f0c847c35f
commit ddd54eea4b
3 changed files with 85 additions and 21 deletions

View File

@ -77,6 +77,32 @@ def catch_background_error(fnc):
return wrapper
def check_locked_partition(sync=False):
"""
Decorator to check if a partition is locked
"""
def outer(fnc):
def wrapper(*args, **kwargs):
part_id = 'None'
try:
this, path, get_params, post_params, server = args # @UnusedVariable
part_id = post_params['disk'] + post_params['part']
if this.locked.get(part_id, False):
this.locked[part_id] = True
fnc(*args, **kwargs)
else:
return 'partition locked'
except Exception as e:
this.locked[part_id] = False
return 'error {}'.format(e)
finally:
if sync is True:
this.locked[part_id] = False
logger.debug('Lock status: {} {}'.format(fnc, this.locked))
return wrapper
return outer
class OpenGnSysWorker(ServerWorker):
name = 'opengnsys'
interface = None # Bound interface for OpenGnsys
@ -218,23 +244,14 @@ class OpenGnSysWorker(ServerWorker):
:param server:
:return: JSON object {"status": "status_code", "loggedin": boolean}
"""
res = {'status': '', 'loggedin': self.logged_in}
if platform.system() == 'Linux': # GNU/Linux
# Check if it's OpenGnsys Client.
if os.path.exists('/scripts/oginit'):
# Check if OpenGnsys Client is busy.
if self.locked:
res['status'] = 'BSY'
else:
res['status'] = 'OPG'
else:
# Check if there is an active session.
res['status'] = 'LNX'
elif platform.system() == 'Windows': # Windows
# Check if there is an active session.
res['status'] = 'WIN'
elif platform.system() == 'Darwin': # Mac OS X ??
res['status'] = 'OSX'
res = {'loggedin': self.loggedin}
try:
res['status'] = operations.os_type.lower()
except KeyError:
res['status'] = ''
# Check if OpenGnsys Client is busy
if res['status'] == 'oglive' and self.locked:
res['status'] = 'busy'
return res
@check_secret
@ -344,7 +361,7 @@ class OpenGnSysWorker(ServerWorker):
# Skip blank rows
pass
elif len(cols) == 7:
disk, npart, tpart, fs, os, size, usage = cols
disk, npart, tpart, fs, opsys, size, usage = cols
try:
if int(npart) == 0:
# Disk information
@ -352,7 +369,7 @@ class OpenGnSysWorker(ServerWorker):
else:
# Partition information
storage.append({'disk': int(disk), 'partition': int(npart), 'parttype': tpart,
'filesystem': fs, 'operatingsystem': os, 'size': int(size),
'filesystem': fs, 'operatingsystem': opsys, 'size': int(size),
'usage': int(usage)})
except ValueError:
logger.warn('Configuration parameter error: {}'.format(cols))
@ -364,6 +381,38 @@ class OpenGnSysWorker(ServerWorker):
# Returning configuration data and count of warnings
return {'serialno': serialno, 'storage': storage, 'warnings': warnings}
def task_command(self, code, route):
"""
Task to execute a command
:param code: Code to execute
:param route: server REST route to return results (including its parameters)
"""
(stat, out, err) = operations.exec_command(code)
self.REST.sendMessage(route, {'status': stat, 'output': out, 'error': err})
def process_command(self, path, get_params, post_params, server):
"""
Launches a thread to executing a command
:param path: ignored
:param get_params: ignored
:param post_params: object with format {"id": OperationId, "code": "Code", url: "ReturnURL"}
:param server: ignored
:rtype: object with launching status
"""
logger.debug('Recieved command operation with params: {}'.format(post_params))
self.checkSecret(server)
# Processing data
try:
code = post_params.get('code')
cmd_id = post_params.get('id')
route = '{}?id={}'.format(post_params.get('route'), cmd_id)
# Launching new thread
threading.Thread(target=self.task_command, args=(code, route)).start()
except Exception as e:
logger.error('Got exception {}'.format(e))
return {'error': e}
return {'op': 'launched'}
def process_hardware(self, path, get_params, post_params, server):
"""
Returns client's hardware profile
@ -394,4 +443,4 @@ class OpenGnSysWorker(ServerWorker):
:return:
"""
logger.debug('Recieved software operation with params: {}'.format(post_params))
return operations.get_software(post_params['disk'], post_params['part'])
return operations.get_software(post_params.get('disk'), post_params.get('part'))

View File

@ -189,6 +189,21 @@ def get_configuration():
return cfgdata
def exec_command(cmd):
"""
Executing a shell command
:param cmd:
:return: object with components:
output: standard output
error: error output
exit: exit code
"""
proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = proc.communicate()
stat = proc.returncode
return stat, out, err
def get_hardware():
"""
Returns client's hardware list

View File

@ -139,5 +139,5 @@ setup(
description='OpenGnsys Agent',
author='Adolfo Gomez',
author_email='agomez@virtualcable.es',
zipfile='OGAgent.zip',
zipfile='OGAgent.zip', requires=['six']
)