Files
Iris/mopidy_iris/system.py

103 lines
3.1 KiB
Python
Raw Normal View History

2018-11-02 16:10:38 +13:00
from threading import Thread
import logging, os, pathlib, subprocess, json, sys
# import logger
logger = logging.getLogger(__name__)
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()
logger.error(message)
super().__init__(message)
class IrisSystemThread(Thread):
_USE_SUDO = True
def __init__(self, action, ioloop, callback):
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
self.ioloop = ioloop
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
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
##
def run(self):
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()
except IrisSystemError as e:
2018-11-02 16:10:38 +13:00
logger.error(e)
2018-11-02 21:44:16 +13:00
error = {
'message': e.reason,
'description': e.message
2018-11-02 21:44:16 +13:00
}
return {
'error': error
}
2018-11-02 21:44:16 +13:00
command = self.get_command()
logger.debug("Running '%s'", os.fsdecode(b' '.join(command)))
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:
logger.info(line)
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))
else:
self.ioloop.add_callback(lambda: self.callback(None, {'error': lines}, None))
##
2018-11-02 16:10:38 +13:00
# Check if we have access to the system script (system.sh)
#
# @return boolean or exception
##
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
command_bytes = b' '.join(self.get_command('check', non_interactive=True))
process = subprocess.Popen(command_bytes, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
result, error = process.communicate()
exitCode = process.wait()
# Some kind of failure, so we can't run any commands this way
if exitCode > 0:
raise IrisSystemPermissionError(self.script_path)
else:
return True