Advancing on actor

This commit is contained in:
Adolfo Gómez García 2019-11-28 14:11:55 +01:00
parent cf6a03b585
commit 6f3f573f61
10 changed files with 231 additions and 114 deletions

View File

@ -1,3 +1,4 @@
Linux:
python3-prctl (recommended, but not required in fact)
python3-pyqt5

View File

@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2014-2019 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
import sys
from ..log import logger
from .service import UDSActorSvc
def usage():
sys.stderr.write('usage: udsactor start|stop|restart|login "username"|logout "username"\n')
sys.exit(2)
logger.setLevel(20000)
if len(sys.argv) == 3 and sys.argv[1] in ('login', 'logout'):
logger.debug('Running client udsactor')
# client = None
# try:
# client = ipc.ClientIPC(IPC_PORT)
# if 'login' == sys.argv[1]:
# client.sendLogin(sys.argv[2])
# sys.exit(0)
# elif 'logout' == sys.argv[1]:
# client.sendLogout(sys.argv[2])
# sys.exit(0)
# else:
# usage()
# except Exception as e:
# logger.error(e)
sys.exit(0)
elif len(sys.argv) != 2:
usage()
daemonSvr = UDSActorSvc()
if len(sys.argv) == 2:
if sys.argv[1] == 'start':
daemonSvr.start()
elif sys.argv[1] == 'stop':
daemonSvr.stop()
elif sys.argv[1] == 'restart':
daemonSvr.restart()
else:
usage()
sys.exit(0)
else:
usage()

View File

@ -34,8 +34,6 @@ import platform
import socket
import fcntl
import os
import ctypes
import ctypes.util
import subprocess
import struct
import array
@ -44,6 +42,7 @@ import typing
from .. import types
from .renamer import rename
from . import xss
def _getMacAddr(ifname: str) -> typing.Optional[str]:
@ -106,7 +105,6 @@ def _getIpAndMac(ifname: str) -> typing.Tuple[typing.Optional[str], typing.Optio
ip, mac = _getIpAddr(ifname), _getMacAddr(ifname)
return (ip, mac)
def checkPermissions() -> bool:
return os.getuid() == 0
@ -166,33 +164,6 @@ def changeUserPassword(user: str, oldPassword: str, newPassword: str) -> None:
os.system('echo "{1}\n{1}" | /usr/bin/passwd {0} 2> /dev/null'.format(user, newPassword))
class XScreenSaverInfo(ctypes.Structure): # pylint: disable=too-few-public-methods
_fields_ = [('window', ctypes.c_long),
('state', ctypes.c_int),
('kind', ctypes.c_int),
('til_or_since', ctypes.c_ulong),
('idle', ctypes.c_ulong),
('eventMask', ctypes.c_ulong)]
# Initialize xlib & xss
try:
xlibPath = ctypes.util.find_library('X11')
xssPath = ctypes.util.find_library('Xss')
xlib = xss = None
if not xlibPath or not xssPath:
raise Exception()
xlib = ctypes.cdll.LoadLibrary(xlibPath)
xss = ctypes.cdll.LoadLibrary(xssPath)
# Fix result type to XScreenSaverInfo Structure
xss.XScreenSaverQueryExtension.restype = ctypes.c_int
xss.XScreenSaverAllocInfo.restype = ctypes.POINTER(XScreenSaverInfo) # Result in a XScreenSaverInfo structure
display = xlib.XOpenDisplay(None)
xssInfo = xss.XScreenSaverAllocInfo()
except Exception: # Libraries not accesible, not found or whatever..
xlib = xss = display = xssInfo = None
def initIdleDuration(atLeastSeconds: int) -> None:
subprocess.call(['/usr/bin/xset', 's', '{}'.format(atLeastSeconds + 30)])
# And now reset it
@ -200,28 +171,7 @@ def initIdleDuration(atLeastSeconds: int) -> None:
def getIdleDuration() -> float:
'''
Returns idle duration, in seconds
'''
if xlib is None or xss is None:
return 0 # Libraries not available
event_base = ctypes.c_int()
error_base = ctypes.c_int()
available = xss.XScreenSaverQueryExtension(display, ctypes.byref(event_base), ctypes.byref(error_base))
if available != 1:
return 0 # No screen saver is available, no way of getting idle
xss.XScreenSaverQueryInfo(display, xlib.XDefaultRootWindow(display), xssInfo)
# Centos seems to set state to 1?? (weird, but it's happening don't know why... will try this way)
if xssInfo.contents.state != 0 and 'centos' not in getLinuxOs().lower().strip():
return 3600 * 100 * 1000 # If screen saver is active, return a high enough value
return xssInfo.contents.idle / 1000.0
return xss.getIdleDuration()
def getCurrentUser() -> str:
'''

View File

@ -30,3 +30,6 @@
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from .common import rename
# Import packages
from . import debian, opensuse, redhat

View File

@ -49,11 +49,3 @@ def rename(newName: str) -> bool:
logger.info('Renamer for platform "{0}" not found, tryin debian renamer'.format(distribution))
return renamers['debian'](newName)
# Do load of packages
def _init():
pkgpath = os.path.dirname(sys.modules[__name__].__file__)
for _, name, _ in pkgutil.iter_modules([pkgpath]):
__import__(__name__ + '.' + name, globals(), locals())
_init()

View File

@ -29,7 +29,6 @@
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
import sys
import signal
import typing
@ -57,10 +56,9 @@ class UDSActorSvc(daemon.Daemon, CommonService):
signal.signal(signal.SIGTERM, self.markForExit)
def markForExit(self, signum, frame):
def markForExit(self, signum, frame) -> None:
self._isAlive = False
def rename( # pylint: disable=unused-argument
self,
name: str,
@ -78,6 +76,8 @@ class UDSActorSvc(daemon.Daemon, CommonService):
logger.info('Computer name is already {}'.format(hostName))
return
logger.debug('Data: {}'.format((name, userName, oldPassword, newPassword)))
# Check for password change request for an user
if userName and oldPassword and newPassword:
logger.info('Setting password for user {}'.format(userName))
@ -100,14 +100,15 @@ class UDSActorSvc(daemon.Daemon, CommonService):
) -> None:
logger.fatal('Join domain is not supported on linux platforms right now')
def run(self):
logger.debug('Running Daemon')
def run(self) -> None:
logger.debug('Running Daemon: {}'.format(self._isAlive))
set_proctitle('UDSActorDaemon')
# Linux daemon will continue running unless something is requested to
if not self.initialize():
return # Stop daemon if initializes told to do so
logger.debug('Initialized, setting ready')
# Initialization is done, set machine to ready for UDS, communicate urls, etc...
self.setReady()
@ -117,7 +118,7 @@ class UDSActorSvc(daemon.Daemon, CommonService):
# Counter used to check ip changes only once every 10 seconds, for
# example
counter = 0
while self.isAlive:
while self._isAlive:
counter += 1
if counter % 10 == 0:
self.checkIpsChanged()
@ -125,45 +126,3 @@ class UDSActorSvc(daemon.Daemon, CommonService):
self.doWait(1000)
self.notifyStop()
def usage():
sys.stderr.write("usage: {} start|stop|restart|login 'username'|logout 'username'\n".format(sys.argv[0]))
sys.exit(2)
if __name__ == '__main__':
logger.setLevel(20000)
if len(sys.argv) == 3 and sys.argv[1] in ('login', 'logout'):
logger.debug('Running client udsactor')
# client = None
# try:
# client = ipc.ClientIPC(IPC_PORT)
# if 'login' == sys.argv[1]:
# client.sendLogin(sys.argv[2])
# sys.exit(0)
# elif 'logout' == sys.argv[1]:
# client.sendLogout(sys.argv[2])
# sys.exit(0)
# else:
# usage()
# except Exception as e:
# logger.error(e)
elif len(sys.argv) != 2:
usage()
logger.debug('Executing actor')
daemonSvr = UDSActorSvc()
if len(sys.argv) == 2:
if sys.argv[1] == 'start':
daemonSvr.start()
elif sys.argv[1] == 'stop':
daemonSvr.stop()
elif sys.argv[1] == 'restart':
daemonSvr.restart()
else:
usage()
sys.exit(0)
else:
usage()

View File

@ -0,0 +1,105 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2014-2019 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
# pylint: disable=invalid-name
import ctypes
import ctypes.util
import subprocess
xlib = None
xss = None
display = None
xssInfo = None
initialized = False
class XScreenSaverInfo(ctypes.Structure): # pylint: disable=too-few-public-methods
_fields_ = [('window', ctypes.c_long),
('state', ctypes.c_int),
('kind', ctypes.c_int),
('til_or_since', ctypes.c_ulong),
('idle', ctypes.c_ulong),
('eventMask', ctypes.c_ulong)]
def _init():
global xlib, xss, xssInfo, display, initialized # pylint: disable=global-statement
initialized = True
# Initialize xlib & xss
try:
xlibPath = ctypes.util.find_library('X11')
xssPath = ctypes.util.find_library('Xss')
xlib = xss = None
if not xlibPath or not xssPath:
raise Exception()
xlib = ctypes.cdll.LoadLibrary(xlibPath)
xss = ctypes.cdll.LoadLibrary(xssPath)
# Fix result type to XScreenSaverInfo Structure
xss.XScreenSaverQueryExtension.restype = ctypes.c_int
xss.XScreenSaverAllocInfo.restype = ctypes.POINTER(XScreenSaverInfo) # Result in a XScreenSaverInfo structure
display = xlib.XOpenDisplay(None)
xssInfo = xss.XScreenSaverAllocInfo()
if display <= 0:
raise Exception() # Invalid display, not accesible
except Exception: # Libraries not accesible, not found or whatever..
xlib = xss = display = xssInfo = None
def initIdleDuration(atLeastSeconds: int) -> None:
subprocess.call(['/usr/bin/xset', 's', '{}'.format(atLeastSeconds + 30)])
# And now reset it
subprocess.call(['/usr/bin/xset', 's', 'reset'])
def getIdleDuration() -> float:
'''
Returns idle duration, in seconds
'''
if not initialized:
_init()
if not xlib or not xss or not xssInfo:
return 0 # Libraries not available
event_base = ctypes.c_int()
error_base = ctypes.c_int()
available = xss.XScreenSaverQueryExtension(display, ctypes.byref(event_base), ctypes.byref(error_base))
if available != 1:
return 0 # No screen saver is available, no way of getting idle
xss.XScreenSaverQueryInfo(display, xlib.XDefaultRootWindow(display), xssInfo)
# Centos seems to set state to 1?? (weird, but it's happening don't know why... will try this way)
if xssInfo.contents.state == 1: # state = 1 means "active", so idle is not a valid state
return 3600 * 100 * 1000 # If screen saver is active, return a high enough value
return xssInfo.contents.idle / 1000.0

View File

@ -69,7 +69,7 @@ class CommonService:
@staticmethod
def execute(cmdLine: str, section: str) -> bool:
try:
res = subprocess.check_call(cmdLine)
res = subprocess.check_call(cmdLine, shell=True)
except Exception as e:
logger.error('Got exception executing: {} - {} - {}'.format(section, cmdLine, e))
return False

View File

@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2014 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
# pylint: disable=invalid-name
import win32serviceutil
from .service import UDSActorSvc
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(UDSActorSvc)

View File

@ -364,8 +364,3 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
self.endAPI() # And deinitializes REST api if needed
self.notifyStop()
if __name__ == '__main__':
initCfg()
win32serviceutil.HandleCommandLine(UDSActorSvc)