2018-11-02 16:10:38 +13:00
|
|
|
from threading import Thread
|
2020-01-17 23:14:43 +13:00
|
|
|
import logging, os, pathlib, subprocess, json, tornado, sys, shlex
|
2018-11-02 10:20:32 +13:00
|
|
|
|
|
|
|
|
# import logger
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
2020-01-08 01:34:44 +00:00
|
|
|
|
|
|
|
|
class IrisSystemError(Exception):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class IrisSystemPermissionError(IrisSystemError):
|
|
|
|
|
reason = "Permission denied"
|
|
|
|
|
|
|
|
|
|
def __init__(self, path):
|
|
|
|
|
message = "Password-less access to %s was refused. Check your /etc/sudoers file." % path.as_uri()
|
2020-01-08 01:37:44 +00:00
|
|
|
logger.error(message)
|
2020-01-08 01:34:44 +00:00
|
|
|
super().__init__(message)
|
|
|
|
|
|
|
|
|
|
|
2020-01-01 21:41:38 +13:00
|
|
|
class IrisSystemThread(Thread):
|
2020-01-08 01:37:44 +00:00
|
|
|
_USE_SUDO = True
|
|
|
|
|
|
2020-01-03 06:01:36 +13:00
|
|
|
def __init__(self, action, callback):
|
2020-01-01 21:41:38 +13:00
|
|
|
Thread.__init__(self)
|
2018-11-02 16:10:38 +13:00
|
|
|
self.action = action
|
2020-01-03 06:01:36 +13:00
|
|
|
self.callback = callback
|
2020-01-17 21:55:12 +13:00
|
|
|
self.ioloop = tornado.ioloop.IOLoop.current()
|
2020-01-06 00:26:55 +00:00
|
|
|
self.script_path = pathlib.Path(__file__).parent / "system.sh"
|
2018-11-02 16:10:38 +13:00
|
|
|
|
2020-01-08 01:37:44 +00:00
|
|
|
def get_command(self, action=None, *, non_interactive=False):
|
|
|
|
|
if self._USE_SUDO:
|
|
|
|
|
if non_interactive:
|
|
|
|
|
args = [b'sudo -n']
|
|
|
|
|
else:
|
|
|
|
|
args = [b'sudo']
|
|
|
|
|
else:
|
|
|
|
|
args = []
|
|
|
|
|
|
|
|
|
|
if action is None:
|
|
|
|
|
action = self.action
|
|
|
|
|
|
|
|
|
|
args = args + [bytes(self.script_path), action.encode()]
|
|
|
|
|
return args
|
|
|
|
|
|
2018-11-02 16:10:38 +13:00
|
|
|
##
|
|
|
|
|
# Run the defined action
|
|
|
|
|
##
|
2020-01-01 21:41:38 +13:00
|
|
|
def run(self):
|
2019-12-30 21:13:15 +13:00
|
|
|
logger.info("Running system action '"+self.action+"'")
|
2018-11-02 16:10:38 +13:00
|
|
|
|
|
|
|
|
try:
|
2019-04-04 14:37:40 +13:00
|
|
|
self.can_run()
|
2020-01-08 01:34:44 +00:00
|
|
|
except IrisSystemError as e:
|
2018-11-02 16:10:38 +13:00
|
|
|
logger.error(e)
|
|
|
|
|
|
2018-11-02 21:44:16 +13:00
|
|
|
error = {
|
2020-01-08 01:34:44 +00:00
|
|
|
'message': e.reason,
|
|
|
|
|
'description': e.message
|
2018-11-02 21:44:16 +13:00
|
|
|
}
|
2020-01-01 12:13:18 +13:00
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
'error': error
|
|
|
|
|
}
|
2018-11-02 21:44:16 +13:00
|
|
|
|
2020-01-08 01:37:44 +00:00
|
|
|
command = self.get_command()
|
|
|
|
|
logger.debug("Running '%s'", os.fsdecode(b' '.join(command)))
|
2020-01-17 23:14:43 +13:00
|
|
|
process = subprocess.Popen(command, stdout=subprocess.PIPE, encoding='utf8')
|
|
|
|
|
|
|
|
|
|
lines = ''
|
|
|
|
|
while True:
|
|
|
|
|
line = process.stdout.readline()
|
|
|
|
|
if process.poll() is not None:
|
|
|
|
|
break
|
|
|
|
|
if line:
|
2020-01-17 23:15:39 +13:00
|
|
|
logger.info(line)
|
2020-01-17 23:14:43 +13:00
|
|
|
lines = lines+'\n'+line
|
|
|
|
|
# This seems to be ignored. Detected as spammy io?
|
|
|
|
|
#self.ioloop.add_callback(lambda: self.callback(None, None, {'output': line}))
|
|
|
|
|
|
|
|
|
|
if process.returncode == 0:
|
|
|
|
|
self.ioloop.add_callback(lambda: self.callback({'output': lines}, None, None))
|
2020-01-01 12:13:18 +13:00
|
|
|
else:
|
2020-01-17 23:14:43 +13:00
|
|
|
self.ioloop.add_callback(lambda: self.callback(None, {'error': lines}, None))
|
2020-01-01 21:41:38 +13:00
|
|
|
|
2018-11-02 10:20:32 +13:00
|
|
|
##
|
2018-11-02 16:10:38 +13:00
|
|
|
# Check if we have access to the system script (system.sh)
|
|
|
|
|
#
|
|
|
|
|
# @return boolean or exception
|
2018-11-02 10:20:32 +13:00
|
|
|
##
|
2019-04-04 14:37:40 +13:00
|
|
|
def can_run(self, *args, **kwargs):
|
2018-11-02 21:44:16 +13:00
|
|
|
# Attempt an empty call to our system file
|
2020-01-08 01:37:44 +00:00
|
|
|
command_bytes = b' '.join(self.get_command('check', non_interactive=True))
|
|
|
|
|
process = subprocess.Popen(command_bytes, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
|
2019-04-10 16:33:41 +12:00
|
|
|
result, error = process.communicate()
|
|
|
|
|
exitCode = process.wait()
|
|
|
|
|
|
|
|
|
|
# Some kind of failure, so we can't run any commands this way
|
|
|
|
|
if exitCode > 0:
|
2020-01-08 01:34:44 +00:00
|
|
|
raise IrisSystemPermissionError(self.script_path)
|
2019-04-10 16:33:41 +12:00
|
|
|
else:
|
|
|
|
|
return True
|