Files
Iris/mopidy_iris/system.py

115 lines
3.1 KiB
Python
Raw Normal View History

2018-11-02 16:10:38 +13:00
from threading import Thread
2020-02-03 16:48:39 +13:00
import logging
import os
import pathlib
import subprocess
# import logger
logger = logging.getLogger(__name__)
class IrisSystemError(Exception):
pass
class IrisSystemPermissionError(IrisSystemError):
reason = "Permission denied"
def __init__(self, path):
2020-02-03 16:14:04 +13:00
message = (
"Password-less access to %s was refused. "
"Check your /etc/sudoers file." % path.as_uri()
2020-02-06 10:12:28 +13:00
)
logger.error(message)
super().__init__(message)
class IrisSystemThread(Thread):
2023-06-01 18:09:46 -07:00
_USE_SUDO = os.environ.get("IRIS_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:
2020-02-03 16:14:04 +13:00
args = [b"sudo -n"]
else:
2020-02-03 16:14:04 +13:00
args = [b"sudo"]
else:
args = []
2020-02-03 16:14:04 +13:00
if action is None:
action = self.action
args = args + [bytes(self.script_path), action.encode()]
return args
2020-02-03 16:14:04 +13:00
2018-11-02 16:10:38 +13:00
##
# Run the defined action
##
def run(self):
2020-02-03 16:14:04 +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()
except IrisSystemError as e:
2018-11-02 16:10:38 +13:00
logger.error(e)
error = {"message": e.reason, "description": str(e)}
2020-02-03 16:14:04 +13:00
return {"error": error}
2018-11-02 21:44:16 +13:00
command = self.get_command()
2020-02-03 16:14:04 +13:00
logger.debug("Running '%s'", os.fsdecode(b" ".join(command)))
2020-02-03 16:48:39 +13:00
process = subprocess.Popen(
2020-02-06 10:12:28 +13:00
command, stdout=subprocess.PIPE, encoding="utf8"
)
2020-02-03 16:14:04 +13:00
lines = ""
while True:
line = process.stdout.readline()
if process.poll() is not None:
break
if line:
logger.info(line)
2020-02-03 16:14:04 +13:00
lines = lines + "\n" + line
if process.returncode == 0:
2020-02-03 16:14:04 +13:00
self.ioloop.add_callback(
lambda: self.callback({"output": lines}, None, None)
)
else:
2020-02-03 16:14:04 +13:00
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
2020-02-03 16:48:39 +13:00
command_bytes = b" ".join(
2020-02-06 10:12:28 +13:00
self.get_command("check", non_interactive=True)
)
2020-02-03 16:14:04 +13:00
process = subprocess.Popen(
2020-02-03 16:48:39 +13:00
command_bytes,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
2020-02-06 10:12:28 +13:00
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