diff options
-rw-r--r-- | pyagl/services/base.py | 90 | ||||
-rw-r--r-- | pyagl/services/mediascanner.py | 6 | ||||
-rw-r--r-- | pyagl/tests/test_mediascanner.py | 2 |
3 files changed, 78 insertions, 20 deletions
diff --git a/pyagl/services/base.py b/pyagl/services/base.py index 0ffbcde..40f7640 100644 --- a/pyagl/services/base.py +++ b/pyagl/services/base.py @@ -21,6 +21,7 @@ from random import randint from enum import IntEnum from typing import Union import asyncssh +from asyncssh import SSHClientConnection import argparse import asyncio import binascii @@ -29,7 +30,6 @@ import json import sys import os import re - # logging.getLogger('AGLBaseService') # logging.basicConfig(level=logging.DEBUG) @@ -43,7 +43,7 @@ class AFBT(IntEnum): msgq = {} -AFBLEN = 3 +AFBLEN = 3 # usual AppFrameworkBinder responses/events have 3 items in the list - [messagetype, sessionid, payload] def newrand(): @@ -133,7 +133,7 @@ class AGLBaseService: return parser def __init__(self, api: str, ip: str, port: str = None, url: str = None, - token: str = 'HELLO', uuid: str = 'magic', service: str = None): + token: str = 'HELLO', uuid: str = 'magic', service: str = None, runservice: bool = False): self.api = api self.url = url self.ip = ip @@ -141,6 +141,7 @@ class AGLBaseService: self.token = token self.uuid = uuid self.service = service + self.runsvc = runservice self.logger = logging.getLogger(service) def __await__(self): @@ -153,7 +154,7 @@ class AGLBaseService: # setting ping_timeout to None because AFB does not support websocket ping # if set to !None, the library will close the socket after the default timeout if self.port is None: - serviceport = await self.portfinder() + serviceport = await self.portfinder(runservice=self.runsvc) if serviceport is not None: self.port = serviceport else: @@ -178,7 +179,7 @@ class AGLBaseService: async def receive(self): return await self.websocket.recv() - async def portfinder(self): + async def portfinder(self, runservice=False): fieldsstr = '{sl}: {local_address} {rem_address} {st} {tx_queue}:{rx_queue} {tr}:{tmwhen} {retrnsmt} {uid}' \ ' {timeout} {inode} {sref_cnt} {memloc} {rto} {pred_sclk} {ackquick} {congest} {slowstart}' # TODO:handle ssh timeouts, asyncssh does not support it apparently, and connect returns context_manager which @@ -187,13 +188,26 @@ class AGLBaseService: servicename = check_output(f"systemctl --all | grep {self.service}-- | awk '{{print $1}}'".encode(), shell=True) servicename = servicename.decode().strip() if self.service not in servicename: - self.logger.error(f"Service matching pattern - '{self.service}' - NOT FOUND") - exit(1) + if runservice: + await self.runafmservice() + servicename = await check_output(f"systemctl --all | grep {self.service}-- | awk '{{print $1}}'", + shell=True) # retry getting service name after starting + servicename = servicename.decode().strip() + else: + self.logger.error(f"Service matching pattern - '{self.service}' - NOT FOUND") + exit(1) pid = check_output(f'systemctl show --property MainPID --value {servicename}'.encode(), shell=True) pid = int(pid.decode().strip(), 10) - if pid == 0: + if pid == 0 and servicename != '': self.logger.warning(f'Service {servicename} is stopped') - return None + if runservice: + self.logger.warning(f' Trying to start service {servicename}') + await self.startsystemdservice(servicename=servicename) + pid = check_output(f'systemctl show --property MainPID --value {servicename}', shell=True) + pid = int(pid.stdout.strip(), 10) + + else: + return None else: self.logger.debug(f'Service PID: {str(pid)}') @@ -208,14 +222,27 @@ class AGLBaseService: else: async with asyncssh.connect(self.ip, username='root') as c: servicename = await c.run(f"systemctl --all | grep {self.service}-- | awk '{{print $1}}'", check=False) - if self.service not in servicename.stdout: - self.logger.error(f"Service matching pattern - '{self.service}' - NOT FOUND") - exit(1) - pidres = await c.run(f'systemctl show --property MainPID --value {servicename.stdout.strip()}') + servicename = servicename.stdout.strip() + if self.service not in servicename: + if runservice: + await self.runafmservice(connection=c) + servicename = await c.run(f"systemctl --all | grep {self.service}-- | awk '{{print $1}}'", + check=False) # retry getting service name after starting + servicename = servicename.stdout.strip() + else: + self.logger.error(f"Service matching pattern - '{self.service}' - NOT FOUND") + exit(1) + pidres = await c.run(f'systemctl show --property MainPID --value {servicename}') pid = int(pidres.stdout.strip(), 10) - if pid == 0: - self.logger.warning(f'Service {servicename.stdout.strip()} is stopped') - return None + if pid == 0 and servicename != '': + self.logger.warning(f'Service {servicename} is stopped') + if runservice: + self.logger.warning(f' Trying to start service {servicename}') + await self.startsystemdservice(servicename=servicename, connection=c) + pidres = await c.run(f'systemctl show --property MainPID --value {servicename}') + pid = int(pidres.stdout.strip(), 10) + else: + return None else: self.logger.debug(f'Service PID: {str(pid)}') @@ -250,6 +277,37 @@ class AGLBaseService: self.logger.debug(f'Service running at port {port}') return port + async def runafmservice(self, servicename: str = None, connection: SSHClientConnection = None): + name = servicename if servicename is not None else self.service + pid = None + result = None + if self.ip == '127.0.0.1' or self.ip == 'localhost': # running locally, ssh not needed + result = check_output(f'afm-util start {name}', shell=True).decode().strip() + else: # running remotely + if connection is not None: + result = await connection.run(f'afm-util start {self.service}') + result = result.stdout.strip() + else: + self.logger.error('Trying to start service remotely but no SSHClientConnection given') + + if result.isnumeric: + self.logger.debug(f'Started service via afm-util, PID: {result}') + pid = int(result) + else: + self.logger.error(f'Unable to start service via afm-util: {result}') + + return pid + + @staticmethod + async def startsystemdservice(servicename: str, connection: SSHClientConnection = None): + result = None + if connection is not None: + result = await connection.run(f'systemctl start {servicename}') + result = result.stdout.strip() + else: + result = check_output(f'systemctl start {servicename}', shell=True) + print(result) + async def listener(self, stdout: bool = False): while True: raw = await self.response() diff --git a/pyagl/services/mediascanner.py b/pyagl/services/mediascanner.py index e3016ec..b40457f 100644 --- a/pyagl/services/mediascanner.py +++ b/pyagl/services/mediascanner.py @@ -21,12 +21,12 @@ verbs = ['subscribe', 'unsubscribe', 'media_result'] class MediaScannerService(AGLBaseService): - service = 'service-mediascanner' + service = 'agl-service-mediascanner' parser = AGLBaseService.getparser() parser.add_argument('--media_result', help='Query media_results verb', action='store_true') - def __init__(self, ip, port=None, service='service-mediascanner'): - super().__init__(api='mediascanner', ip=ip, port=port, service=service) + def __init__(self, ip, port=None, service='agl-service-mediascanner', runservice=True): + super().__init__(api='mediascanner', ip=ip, port=port, service=service, runservice=runservice) # more init stuff specific to the new service async def media_result(self): diff --git a/pyagl/tests/test_mediascanner.py b/pyagl/tests/test_mediascanner.py index a4d57ee..9aba4b0 100644 --- a/pyagl/tests/test_mediascanner.py +++ b/pyagl/tests/test_mediascanner.py @@ -33,7 +33,7 @@ def event_loop(): async def service(): address = os.environ.get('AGL_TGT_IP', 'localhost') port = os.environ.get('AGL_TGT_PORT', None) - ns = await mss(ip=address, port=port) + ns = await mss(ip=address, port=port, runservice=True) yield ns await ns.websocket.close() |