Source code for easyplayer.workshop

import os, subprocess, shlex
import datetime
import glob
import zipfile
from logging import getLogger
from circuits import task, Component, Event, Worker
from os import getpid
from shutil import which
from path import Path
from .events import time_adjusted, warning, screenshot, lastlogs, update_finished
from .remote.client import FWUpdate
from .settings import FWUPDATE_PATH
from .utils import now, tnow

log = getLogger(__name__)


[docs]class Command(object): """ command object """ COMMAND_HANDLERS ={ 'rb': 'reboot', 'fw': 'firmware_update', 'sc': 'send_screenshot', 'sl': 'send_logs' } def execute(self, cmd, *args, **kwargs): m = self.COMMAND_HANDLERS.get(cmd, None) if m: method = getattr(self, m, None) if method: return method(*args, **kwargs) else: log.warning('Action %s not found.', method) else: log.warning('Command %s not defined.', cmd)
[docs] def reboot(self, script_path, **kw): """ reboot device """ log.info("rebooting device") script = 'reboot.sh' path = Path(script_path).expanduser().joinpath(script) # launch new process in new console, don't wait for it to finish subprocess.Popen(['sudo', str(path)])
# terminate # return application_restart()
[docs] def firmware_update(self, data_dir, script_path, token, remote_url, **kw): """ update application or system software """ log.info('updating firmware') fwpath = Path(data_dir).expanduser().joinpath(FWUPDATE_PATH) dirpath = fwpath.dirname() dirpath.makedirs_p(mode=0o755) FWUpdate(token, remote_url).download(fwpath) if fwpath.isfile(): script = 'applyUpdate.sh' path = Path(script_path).expanduser().joinpath(script) cmd = ' '.join([path, fwpath]) result = subprocess.call(cmd, shell=True) log.info('Update finished with return code: %s', result) if result == 100: log.error('Script has to be run as root.') elif result == 101: log.error('GPG keys not found.') elif result == 102: log.error('Error when decrypting update.') elif result == 103: log.error('Error when unpacking update.') else: log.error("Update processed with return code: %s", result) return update_finished(result) else: result = 104 log.error('No update file found.') return update_finished(result)
[docs] def send_screenshot(self, data_dir, script_path, **kw): """ take current screenshot and send back """ program = 'raspi2png' cmd = which(program) if not cmd: sdir = Path(script_path).expanduser() cmd = which(program, path=sdir) if cmd: fname = data_dir.joinpath('snapshot.png') args = [cmd, '-p', str(fname), '-c', '5'] cmd = ' '.join(args) try: subprocess.call(shlex.split(cmd)) except Exception as e: msg = str(e) return warning('screenshot', 'Making screenshot failed: {}'.format(msg)) else: if fname.exists(): return screenshot(fname, tnow()) else: return warning('screenshot', 'Screenshot file not found.') else: return warning('screenshot', 'Missing utility to make screenshots.')
[docs] def send_logs(self, data_dir, logfile, **kw): """ pack log files and send back """ # prepare zip file with all the logs and configs logdir = '/home/easyplayer/logs' confdir = '/home/easyplayer/.easyplayer' dst = '/tmp/logs.zip' with zipfile.ZipFile(dst, 'w') as zipf: for path in glob.glob(logdir + '/*.log'): zipf.write(path, os.path.basename(path)) for path in glob.glob(confdir + '/*.json'): zipf.write(path, os.path.basename(path)) if Path(dst).exists(): return lastlogs(dst, tnow())
[docs]def execute(cmd, **kw): """ task executing a command """ log.info('Executing: %s in process %s', cmd, getpid()) command = Command() resp = command.execute(cmd, **kw) #log.info('Done executing %s: %s', cmd, resp) return resp
[docs]class Workshop(Component): """ execute commands coming from server """ channel = 'workshop' def init(self, config): self.logger = getLogger(__name__) self.config = config self.worker = Worker(channel=self.channel).register(self) self.make_executable(config['script_path']) def make_executable(self, script_path): sp = Path(script_path) for path in sp.files('*.sh'): path.chmod('u+x') def started(self, *args): self.logger.info('started: %r', self)
[docs] def handle(self, cmd): """ handle command """ self.logger.info('handle: %s', cmd) resp = yield self.call(task(execute, cmd=cmd, **self.config.data), self.worker.channel) self.logger.info('command %s finished: %s', cmd, resp) if resp and isinstance(resp.value, Event): self.fire(resp.value, self.parent.channel)
[docs] def adjust_systime(self, offset): """ adjust system time """ dt = now() + datetime.timedelta(seconds=offset) ds = dt.strftime("%Y-%m-%d %H:%M:%S") self.logger.info('adjusting system time to: %s', ds) #subprocess.call(shlex.split("timedatectl set-ntp false")) # May be necessary subprocess.call(shlex.split("sudo date -s '{}'".format(ds))) #subprocess.call(shlex.split("sudo hwclock -w")) # notify about time adjusted self.fire(time_adjusted())
#self.fire(terminate())