#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^2
Ramón M. Gómez 2018-06-30 17:13:45 +02:00
parent ae066d2d6c
commit dfd2c05275
3 changed files with 68 additions and 16 deletions

View File

@ -46,12 +46,12 @@ from opengnsys.workers import ServerWorker
from six.moves.urllib import parse from six.moves.urllib import parse
# Check authorization header decorator # Check authorization header decorator
def check_secret(fnc): def check_secret(fnc):
""" """
Decorator to check for received secret key and raise exception if it isn't valid. Decorator to check for received secret key and raise exception if it isn't valid.
""" """
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
try: try:
this, path, get_params, post_params, server = args # @UnusedVariable this, path, get_params, post_params, server = args # @UnusedVariable
@ -74,6 +74,7 @@ def catch_background_error(fnc):
fnc(*args, **kwargs) fnc(*args, **kwargs)
except Exception as e: except Exception as e:
this.REST.sendMessage('error?id={}'.format(kwargs.get('requestId', 'error')), {'error': '{}'.format(e)}) this.REST.sendMessage('error?id={}'.format(kwargs.get('requestId', 'error')), {'error': '{}'.format(e)})
return wrapper return wrapper
@ -81,11 +82,12 @@ def check_locked_partition(sync=False):
""" """
Decorator to check if a partition is locked Decorator to check if a partition is locked
""" """
def outer(fnc): def outer(fnc):
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
part_id = 'None' part_id = 'None'
try: try:
this, path, get_params, post_params = args # @UnusedVariable this, path, get_params, post_params, server = args # @UnusedVariable
part_id = post_params['disk'] + post_params['part'] part_id = post_params['disk'] + post_params['part']
if this.locked.get(part_id, False): if this.locked.get(part_id, False):
this.locked[part_id] = True this.locked[part_id] = True
@ -99,7 +101,9 @@ def check_locked_partition(sync=False):
if sync is True: if sync is True:
this.locked[part_id] = False this.locked[part_id] = False
logger.debug('Lock status: {} {}'.format(fnc, this.locked)) logger.debug('Lock status: {} {}'.format(fnc, this.locked))
return wrapper return wrapper
return outer return outer
@ -245,15 +249,14 @@ class OpenGnSysWorker(ServerWorker):
:param server: :param server:
:return: JSON object {"status": "status_code", "loggedin": boolean} :return: JSON object {"status": "status_code", "loggedin": boolean}
""" """
st = {'linux': 'LNX', 'macos': 'OSX', 'oglive': 'OPG', 'windows': 'WIN'}
res = {'loggedin': self.loggedin} res = {'loggedin': self.loggedin}
try: try:
res['status'] = st[operations.os_type.lower()] res['status'] = operations.os_type.lower()
except KeyError: except KeyError:
res['status'] = '' res['status'] = ''
# Check if OpenGnsys Client is busy # Check if OpenGnsys Client is busy
if res['status'] == 'OPG' and self.locked: if res['status'] == 'oglive' and self.locked:
res['status'] = 'BSY' res['status'] = 'busy'
return res return res
@check_secret @check_secret
@ -271,6 +274,7 @@ class OpenGnSysWorker(ServerWorker):
# Rebooting thread # Rebooting thread
def rebt(): def rebt():
operations.reboot() operations.reboot()
threading.Thread(target=rebt).start() threading.Thread(target=rebt).start()
return {'op': 'launched'} return {'op': 'launched'}
@ -290,6 +294,7 @@ class OpenGnSysWorker(ServerWorker):
def pwoff(): def pwoff():
time.sleep(2) time.sleep(2)
operations.poweroff() operations.poweroff()
threading.Thread(target=pwoff).start() threading.Thread(target=pwoff).start()
return {'op': 'launched'} return {'op': 'launched'}
@ -363,7 +368,7 @@ class OpenGnSysWorker(ServerWorker):
# Skip blank rows # Skip blank rows
pass pass
elif len(cols) == 7: elif len(cols) == 7:
disk, npart, tpart, fs, os, size, usage = cols disk, npart, tpart, fs, opsys, size, usage = cols
try: try:
if int(npart) == 0: if int(npart) == 0:
# Disk information # Disk information
@ -371,7 +376,7 @@ class OpenGnSysWorker(ServerWorker):
else: else:
# Partition information # Partition information
storage.append({'disk': int(disk), 'partition': int(npart), 'parttype': tpart, 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)}) 'usage': int(usage)})
except ValueError: except ValueError:
logger.warn('Configuration parameter error: {}'.format(cols)) logger.warn('Configuration parameter error: {}'.format(cols))
@ -383,6 +388,38 @@ class OpenGnSysWorker(ServerWorker):
# Returning configuration data and count of warnings # Returning configuration data and count of warnings
return {'serialno': serialno, 'storage': storage, 'warnings': 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): def process_hardware(self, path, get_params, post_params, server):
""" """
Returns client's hardware profile Returns client's hardware profile
@ -413,4 +450,4 @@ class OpenGnSysWorker(ServerWorker):
:return: :return:
""" """
logger.debug('Recieved software operation with params: {}'.format(post_params)) 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 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(): def get_hardware():
""" """
Returns client's hardware list Returns client's hardware list

View File

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