Skip to content

Commit f351cb7

Browse files
committed
[sonic-daemon-base] Create DaemonBase class for all daemons
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]>
1 parent f98bec4 commit f351cb7

File tree

5 files changed

+174
-0
lines changed

5 files changed

+174
-0
lines changed

rules/docker-platform-monitor.mk

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ $(DOCKER_PLATFORM_MONITOR)_PYTHON_DEBS += $(SONIC_LEDD) $(SONIC_XCVRD) $(SONIC_P
77
$(DOCKER_PLATFORM_MONITOR)_PYTHON_WHEELS += $(SONIC_PLATFORM_COMMON_PY2)
88
$(DOCKER_PLATFORM_MONITOR)_PYTHON_WHEELS += $(SWSSSDK_PY2)
99
$(DOCKER_PLATFORM_MONITOR)_PYTHON_WHEELS += $(SONIC_PLATFORM_API_PY2)
10+
$(DOCKER_PLATFORM_MONITOR)_PYTHON_WHEELS += $(SONIC_DAEMON_BASE_PY2)
1011
$(DOCKER_PLATFORM_MONITOR)_LOAD_DOCKERS = $(DOCKER_CONFIG_ENGINE)
1112

1213
SONIC_DOCKER_IMAGES += $(DOCKER_PLATFORM_MONITOR)

rules/sonic-daemon-base.mk

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# SONIC_DAEMON_BASE_PY2 package
2+
3+
SONIC_DAEMON_BASE_PY2 = sonic_daemon_base-1.0-py2-none-any.whl
4+
$(SONIC_DAEMON_BASE_PY2)_SRC_PATH = $(SRC_PATH)/sonic-daemon-base
5+
$(SONIC_DAEMON_BASE_PY2)_PYTHON_VERSION = 2
6+
SONIC_PYTHON_WHEELS += $(SONIC_DAEMON_BASE_PY2)
7+

src/sonic-daemon-base/setup.py

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from setuptools import setup
2+
3+
setup(
4+
name='sonic-daemon-base',
5+
version='1.0',
6+
description='Sonic daemon base package',
7+
license='Apache 2.0',
8+
author='SONiC Team',
9+
author_email='[email protected]',
10+
url='https://github.com/Azure/sonic-platform-daemons',
11+
maintainer='Kevin Wang',
12+
maintainer_email='[email protected]',
13+
packages=[
14+
'sonic_daemon_base',
15+
],
16+
classifiers=[
17+
'Development Status :: 4 - Beta',
18+
'Environment :: No Input/Output (Daemon)',
19+
'Intended Audience :: Developers',
20+
'Intended Audience :: Information Technology',
21+
'Intended Audience :: System Administrators',
22+
'License :: OSI Approved :: Apache Software License',
23+
'Natural Language :: English',
24+
'Operating System :: POSIX :: Linux',
25+
'Programming Language :: Python :: 2.7',
26+
'Topic :: System :: Hardware',
27+
],
28+
keywords='SONiC sonic PLATFORM platform DAEMON daemon',
29+
)
30+

src/sonic-daemon-base/sonic_daemon_base/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#!/usr/bin/env python2
2+
3+
try:
4+
import imp
5+
import signal
6+
import subprocess
7+
import sys
8+
import syslog
9+
from swsscommon import swsscommon
10+
except ImportError, e:
11+
raise ImportError (str(e) + " - required module not found")
12+
13+
#============================= Constants =============================
14+
15+
# Platform root directory inside docker
16+
PLATFORM_ROOT_DOCKER = "/usr/share/sonic/platform"
17+
SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen'
18+
HWSKU_KEY = 'DEVICE_METADATA.localhost.hwsku'
19+
PLATFORM_KEY = 'DEVICE_METADATA.localhost.platform'
20+
21+
class DaemonBase(object):
22+
# Redis DB information
23+
redis_hostname = "localhost"
24+
redis_port = 6379
25+
redis_timeout_msecs = 0
26+
27+
def __init__(self):
28+
self.log_info("Starting up...")
29+
# Register our signal handlers
30+
signal.signal(signal.SIGHUP, self.signal_handler)
31+
signal.signal(signal.SIGINT, self.signal_handler)
32+
signal.signal(signal.SIGTERM, self.signal_handler)
33+
34+
def __del__(self):
35+
self.log_error("Return from daemon, exiting...")
36+
37+
def run(self):
38+
raise NotImplementedError()
39+
40+
# ========================== Connect to DB ============================
41+
def db_connect(self, db):
42+
return swsscommon.DBConnector(db,
43+
self.redis_hostname,
44+
self.redis_port,
45+
self.redis_timeout_msecs)
46+
47+
# ========================== Syslog wrappers ==========================
48+
def log_info(self, msg):
49+
syslog.openlog()
50+
syslog.syslog(syslog.LOG_INFO, msg)
51+
syslog.closelog()
52+
53+
def log_warning(self, msg):
54+
syslog.openlog()
55+
syslog.syslog(syslog.LOG_WARNING, msg)
56+
syslog.closelog()
57+
58+
def log_error(self, msg):
59+
syslog.openlog()
60+
syslog.syslog(syslog.LOG_ERR, msg)
61+
syslog.closelog()
62+
63+
#========================== Signal Handling ==========================
64+
def signal_handler(self, sig, frame):
65+
if sig == signal.SIGHUP:
66+
self.log_info("Caught SIGHUP - ignoring...")
67+
return
68+
elif sig == signal.SIGINT:
69+
self.log_info("Caught SIGINT - exiting...")
70+
sys.exit(128 + sig)
71+
elif sig == signal.SIGTERM:
72+
self.log_info("Caught SIGTERM - exiting...")
73+
sys.exit(128 + sig)
74+
else:
75+
self.log_warning("Caught unhandled signal '" + sig + "'")
76+
return
77+
78+
#============ Functions to load platform-specific classes ============
79+
# Returns platform and HW SKU
80+
def get_platform_and_hwsku(self):
81+
try:
82+
proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-H', '-v', PLATFORM_KEY],
83+
stdout=subprocess.PIPE,
84+
shell=False,
85+
stderr=subprocess.STDOUT)
86+
stdout = proc.communicate()[0]
87+
proc.wait()
88+
platform = stdout.rstrip('\n')
89+
90+
proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-d', '-v', HWSKU_KEY],
91+
stdout=subprocess.PIPE,
92+
shell=False,
93+
stderr=subprocess.STDOUT)
94+
stdout = proc.communicate()[0]
95+
proc.wait()
96+
hwsku = stdout.rstrip('\n')
97+
except OSError, e:
98+
self.log_error("Cannot to detect platform")
99+
raise OSError("Cannot detect platform")
100+
101+
return (platform, hwsku)
102+
103+
# Returns path to hwsku
104+
def get_path_to_platform_and_hwsku(self):
105+
# Get platform and hwsku
106+
(platform, hwsku) = self.get_platform_and_hwsku()
107+
108+
# Load platform module from source
109+
platform_path = PLATFORM_ROOT_DOCKER
110+
hwsku_path = "/".join([platform_path, hwsku])
111+
112+
return (platform_path, hwsku_path)
113+
114+
# Loads platform specific psuutil module from source
115+
def load_platform_util(self, module_name, class_name):
116+
platform_util = None
117+
118+
# Get path to platform and hwsku
119+
(platform_path, hwsku_path) = self.get_path_to_platform_and_hwsku()
120+
121+
try:
122+
module_file = "/".join([platform_path, "plugins", module_name + ".py"])
123+
module = imp.load_source(module_name, module_file)
124+
except IOError, e:
125+
self.log_error("Failed to load platform module '%s': %s" % (module_name, str(e)))
126+
return None
127+
128+
try:
129+
platform_util_class = getattr(module, class_name)
130+
platform_util = platform_util_class()
131+
except AttributeError, e:
132+
self.log_error("Failed to instantiate '%s' class: %s" % (class_name, str(e)))
133+
return None
134+
135+
return platform_util
136+

0 commit comments

Comments
 (0)