Skip to content

Commit

Permalink
[sonic-daemon-base] Create DaemonBase class for all daemons (#2570)
Browse files Browse the repository at this point in the history
DaemonBase is to wrap the common function of daemons, such as logging,
signal handling, db connector, load specific platform plugins.

Signed-off-by: Kevin Wang <[email protected]>
  • Loading branch information
kevinwangsk authored and liat-grozovik committed Mar 6, 2019
1 parent 66f5202 commit fa84c42
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 0 deletions.
1 change: 1 addition & 0 deletions rules/docker-platform-monitor.mk
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ $(DOCKER_PLATFORM_MONITOR)_PYTHON_DEBS += $(SONIC_LEDD) $(SONIC_XCVRD) $(SONIC_P
$(DOCKER_PLATFORM_MONITOR)_PYTHON_WHEELS += $(SONIC_PLATFORM_COMMON_PY2)
$(DOCKER_PLATFORM_MONITOR)_PYTHON_WHEELS += $(SWSSSDK_PY2)
$(DOCKER_PLATFORM_MONITOR)_PYTHON_WHEELS += $(SONIC_PLATFORM_API_PY2)
$(DOCKER_PLATFORM_MONITOR)_PYTHON_WHEELS += $(SONIC_DAEMON_BASE_PY2)
$(DOCKER_PLATFORM_MONITOR)_LOAD_DOCKERS = $(DOCKER_CONFIG_ENGINE)

SONIC_DOCKER_IMAGES += $(DOCKER_PLATFORM_MONITOR)
Expand Down
7 changes: 7 additions & 0 deletions rules/sonic-daemon-base.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# SONIC_DAEMON_BASE_PY2 package

SONIC_DAEMON_BASE_PY2 = sonic_daemon_base-1.0-py2-none-any.whl
$(SONIC_DAEMON_BASE_PY2)_SRC_PATH = $(SRC_PATH)/sonic-daemon-base
$(SONIC_DAEMON_BASE_PY2)_PYTHON_VERSION = 2
SONIC_PYTHON_WHEELS += $(SONIC_DAEMON_BASE_PY2)

30 changes: 30 additions & 0 deletions src/sonic-daemon-base/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from setuptools import setup

setup(
name='sonic-daemon-base',
version='1.0',
description='Sonic daemon base package',
license='Apache 2.0',
author='SONiC Team',
author_email='[email protected]',
url='https://github.com/Azure/sonic-platform-daemons',
maintainer='Kevin Wang',
maintainer_email='[email protected]',
packages=[
'sonic_daemon_base',
],
classifiers=[
'Development Status :: 4 - Beta',
'Environment :: No Input/Output (Daemon)',
'Intended Audience :: Developers',
'Intended Audience :: Information Technology',
'Intended Audience :: System Administrators',
'License :: OSI Approved :: Apache Software License',
'Natural Language :: English',
'Operating System :: POSIX :: Linux',
'Programming Language :: Python :: 2.7',
'Topic :: System :: Hardware',
],
keywords='SONiC sonic PLATFORM platform DAEMON daemon',
)

Empty file.
136 changes: 136 additions & 0 deletions src/sonic-daemon-base/sonic_daemon_base/daemon_base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#!/usr/bin/env python2

try:
import imp
import signal
import subprocess
import sys
import syslog
from swsscommon import swsscommon
except ImportError, e:
raise ImportError (str(e) + " - required module not found")

#============================= Constants =============================

# Platform root directory inside docker
PLATFORM_ROOT_DOCKER = "/usr/share/sonic/platform"
SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen'
HWSKU_KEY = 'DEVICE_METADATA.localhost.hwsku'
PLATFORM_KEY = 'DEVICE_METADATA.localhost.platform'

class DaemonBase(object):
# Redis DB information
redis_hostname = "localhost"
redis_port = 6379
redis_timeout_msecs = 0

def __init__(self):
self.log_info("Starting up...")
# Register our signal handlers
signal.signal(signal.SIGHUP, self.signal_handler)
signal.signal(signal.SIGINT, self.signal_handler)
signal.signal(signal.SIGTERM, self.signal_handler)

def __del__(self):
self.log_error("Return from daemon, exiting...")

def run(self):
raise NotImplementedError()

# ========================== Connect to DB ============================
def db_connect(self, db):
return swsscommon.DBConnector(db,
self.redis_hostname,
self.redis_port,
self.redis_timeout_msecs)

# ========================== Syslog wrappers ==========================
def log_info(self, msg):
syslog.openlog()
syslog.syslog(syslog.LOG_INFO, msg)
syslog.closelog()

def log_warning(self, msg):
syslog.openlog()
syslog.syslog(syslog.LOG_WARNING, msg)
syslog.closelog()

def log_error(self, msg):
syslog.openlog()
syslog.syslog(syslog.LOG_ERR, msg)
syslog.closelog()

#========================== Signal Handling ==========================
def signal_handler(self, sig, frame):
if sig == signal.SIGHUP:
self.log_info("Caught SIGHUP - ignoring...")
return
elif sig == signal.SIGINT:
self.log_info("Caught SIGINT - exiting...")
sys.exit(128 + sig)
elif sig == signal.SIGTERM:
self.log_info("Caught SIGTERM - exiting...")
sys.exit(128 + sig)
else:
self.log_warning("Caught unhandled signal '" + sig + "'")
return

#============ Functions to load platform-specific classes ============
# Returns platform and HW SKU
def get_platform_and_hwsku(self):
try:
proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-H', '-v', PLATFORM_KEY],
stdout=subprocess.PIPE,
shell=False,
stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
platform = stdout.rstrip('\n')

proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-d', '-v', HWSKU_KEY],
stdout=subprocess.PIPE,
shell=False,
stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
hwsku = stdout.rstrip('\n')
except OSError, e:
self.log_error("Cannot to detect platform")
raise OSError("Cannot detect platform")

return (platform, hwsku)

# Returns path to hwsku
def get_path_to_platform_and_hwsku(self):
# Get platform and hwsku
(platform, hwsku) = self.get_platform_and_hwsku()

# Load platform module from source
platform_path = PLATFORM_ROOT_DOCKER
hwsku_path = "/".join([platform_path, hwsku])

return (platform_path, hwsku_path)

# Loads platform specific psuutil module from source
def load_platform_util(self, module_name, class_name):
platform_util = None

# Get path to platform and hwsku
(platform_path, hwsku_path) = self.get_path_to_platform_and_hwsku()

try:
module_file = "/".join([platform_path, "plugins", module_name + ".py"])
module = imp.load_source(module_name, module_file)
except IOError, e:
self.log_error("Failed to load platform module '%s': %s" % (module_name, str(e)))
return None

try:
platform_util_class = getattr(module, class_name)
platform_util = platform_util_class()
except AttributeError, e:
self.log_error("Failed to instantiate '%s' class: %s" % (class_name, str(e)))
return None

return platform_util

0 comments on commit fa84c42

Please sign in to comment.