aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pyagl/services/base.py90
-rw-r--r--pyagl/services/mediascanner.py6
-rw-r--r--pyagl/tests/test_mediascanner.py2
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()