Skip to content

Commit

Permalink
Refactor daemons based on sonic-daemon-common package
Browse files Browse the repository at this point in the history
Signed-off-by: Kevin Wang <kevinw@mellanox.com>
  • Loading branch information
kevinwangsk committed Feb 20, 2019
1 parent e5d8155 commit 7789a34
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 424 deletions.
146 changes: 14 additions & 132 deletions sonic-ledd/scripts/ledd
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ try:
import sys
import syslog
from swsscommon import swsscommon
from sonic_daemon_common.daemon_common import daemon_util
except ImportError, e:
raise ImportError (str(e) + " - required module not found")

Expand All @@ -34,133 +35,18 @@ Options:

LED_MODULE_NAME = "led_control"
LED_CLASS_NAME = "LedControl"

SONIC_CFGGEN = "/usr/local/bin/sonic-cfggen"
MINIGRAPH_FILE = "/etc/sonic/minigraph.xml"
HWSKU_KEY = "minigraph_hwsku"
PLATFORM_KEY = "platform"

# platform directory in base image
PLATFORM_ROOT = "/usr/share/sonic/device"

# platform root directory inside docker
PLATFORM_ROOT_DOCKER = "/usr/share/sonic/platform"

REDIS_HOSTNAME = "localhost"
REDIS_PORT = 6379
REDIS_TIMEOUT_USECS = 0

SELECT_TIMEOUT = 1000

#========================== Syslog wrappers ==========================

def log_info(msg):
syslog.openlog(SYSLOG_IDENTIFIER)
syslog.syslog(syslog.LOG_INFO, msg)
syslog.closelog()

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

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

#========================== Signal Handling ==========================

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


#============ Functions to load platform-specific classes ============

# Returns platform and HW SKU
def get_platform_and_hwsku():
try:
proc = subprocess.Popen([SONIC_CFGGEN, '-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, '-m', MINIGRAPH_FILE, '-v', HWSKU_KEY],
stdout=subprocess.PIPE,
shell=False,
stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
hwsku = stdout.rstrip('\n')
except OSError, e:
log_error("Cannot detect platform")
raise OSError("Cannot detect platform")

return (platform, hwsku)


# Loads platform-specific LED control module from source
def load_platform_led_control_module():
# Get platform and hwsku
(platform, hwsku) = get_platform_and_hwsku()

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

module_file_base = '/'.join([platform_path, 'plugins', LED_MODULE_NAME + '.py'])

module_file_docker = '/'.join([PLATFORM_ROOT_DOCKER, 'plugins', LED_MODULE_NAME + '.py'])

# If we can't locate a platform-specific module, exit gracefully, assuming this
# platform utilizes a hardware-based LED control solution
if os.path.isfile(module_file_base):
module_file = module_file_base
elif os.path.isfile(module_file_docker):
module_file = module_file_docker
else:
log_info("Failed to locate platform-specific %s module." % LED_MODULE_NAME)
return None

try:
module = imp.load_source(LED_MODULE_NAME, module_file)
except IOError, e:
log_error("Failed to load platform module '%s': %s" % (LED_MODULE_NAME, str(e)))
return None

log_info("Loaded module '%s'." % LED_MODULE_NAME)

try:
led_control_class = getattr(module, LED_CLASS_NAME)
led_control = led_control_class()
except AttributeError, e:
log_error("Failed to instantiate '%s' class: %s" % (LED_CLASS_NAME, str(e)))
return None

log_info("Instantiated class '%s.%s'." % (LED_MODULE_NAME, LED_CLASS_NAME))

return led_control

#=============================== Main ================================

def main():
log_info("Starting up...")
ledd_util = daemon_util()
if not ledd_util:
print "Failed to load led daemon utilities"
sys.exit(1)

if not os.geteuid() == 0:
log_error("Must be root to run this daemon")
ledd_util.log_error("Must be root to run this daemon")
print "Error: Must be root to run this daemon"
sys.exit(1)

Expand All @@ -183,21 +69,17 @@ def main():
print 'ledd version ' + VERSION
sys.exit(0)

# Register our signal handlers
signal.signal(signal.SIGHUP, signal_handler)
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)

# Load platform-specific LedControl module
led_control = load_platform_led_control_module()
if led_control is None:
sys.exit(0)
led_control = ledd_util.load_platform_util(LED_MODULE_NAME, LED_CLASS_NAME)
if not led_control:
ledd_util.log_error("failed to load ledutil")
sys.exit(1)

# Open a handle to the Application database
appl_db = swsscommon.DBConnector(swsscommon.APPL_DB,
REDIS_HOSTNAME,
REDIS_PORT,
REDIS_TIMEOUT_USECS)
ledd_util.redis_hostname,
ledd_util.redis_port,
ledd_util.redis_timeout_usecs)

# Subscribe to PORT table notifications in the Application DB
sel = swsscommon.Select()
Expand All @@ -214,7 +96,7 @@ def main():
# Do not flood log when select times out
continue
if state != swsscommon.Select.OBJECT:
log_warning("sel.select() did not return swsscommon.Select.OBJECT")
ledd_util.log_warning("sel.select() did not return swsscommon.Select.OBJECT")
continue

(key, op, fvp) = sst.pop()
Expand Down
150 changes: 17 additions & 133 deletions sonic-psud/scripts/psud
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python2

"""
Psud
psud
PSU information update daemon for SONiC
This daemon will loop to collect PSU related information and then write the information to state DB.
Currently it is implemented based on old plugins rather than new platform APIs. So the PSU information just
Expand All @@ -10,180 +10,64 @@
"""

try:
import getopt
import os
import imp
import signal
import subprocess
import sys
import syslog
import time
from swsscommon import swsscommon
from sonic_daemon_common.daemon_common import daemon_util
except ImportError, e:
raise ImportError (str(e) + " - required module not found")

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

VERSION = '1.0'

SYSLOG_IDENTIFIER = os.path.basename(__file__)
PLATFORM_SPECIFIC_MODULE_NAME = "psuutil"
PLATFORM_SPECIFIC_CLASS_NAME = "PsuUtil"

# 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'

# Global platform-specific psuutil class instance
platform_psuutil = None

REDIS_HOSTNAME = "localhost"
REDIS_PORT = 6379
REDIS_TIMEOUT_MSECS = 0

PSU_INFO_UPDATE_PERIOD_SECS = 3

#========================== Syslog wrappers ==========================

def log_info(msg, also_print_to_console=False):
syslog.openlog(SYSLOG_IDENTIFIER)
syslog.syslog(syslog.LOG_INFO, msg)
syslog.closelog()

if also_print_to_console:
print msg

def log_warning(msg, also_print_to_console=False):
syslog.openlog(SYSLOG_IDENTIFIER)
syslog.syslog(syslog.LOG_WARNING, msg)
syslog.closelog()

if also_print_to_console:
print msg

def log_error(msg, also_print_to_console=False):
syslog.openlog(SYSLOG_IDENTIFIER)
syslog.syslog(syslog.LOG_ERR, msg)
syslog.closelog()

if also_print_to_console:
print msg

#========================== Signal Handling ==========================

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

#============ Functions to load platform-specific classes ============

# Returns platform and HW SKU
def get_platform_and_hwsku():
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:
raise OSError("Cannot detect platform")

return (platform, hwsku)

# Loads platform specific psuutil module from source
def load_platform_psuutil():
global platform_psuutil

# Get platform and hwsku
(platform, hwsku) = get_platform_and_hwsku()

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

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

try:
platform_psuutil_class = getattr(module, PLATFORM_SPECIFIC_CLASS_NAME)
platform_psuutil = platform_psuutil_class()
except AttributeError, e:
log_error("Failed to instantiate '%s' class: %s" % (PLATFORM_SPECIFIC_CLASS_NAME, str(e)), True)
return -2

return 0

def psu_db_update(psu_tbl, num_psus):
def psu_db_update(psuutil, psu_tbl, num_psus):
for psu_index in range(1, num_psus + 1):
fvs = swsscommon.FieldValuePairs([('presence',
'true' if platform_psuutil.get_psu_presence(psu_index) else 'false'),
'true' if psuutil.get_psu_presence(psu_index) else 'false'),
('status',
'true' if platform_psuutil.get_psu_status(psu_index) else 'false')])
'true' if psuutil.get_psu_status(psu_index) else 'false')])
psu_tbl.set("PSU {}".format(psu_index), fvs)

#=============================== Main ================================

def main():
log_info("Starting up...")

# Register our signal handlers
signal.signal(signal.SIGHUP, signal_handler)
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
psud_util = daemon_util()
if not psud_util:
print "Failed to load psu daemon utilities"
sys.exit(1)

# Load platform-specific psuutil class
err = load_platform_psuutil()
if err != 0:
log_error("failed to load psuutil")
platform_psuutil = psud_util.load_platform_util(PLATFORM_SPECIFIC_MODULE_NAME, PLATFORM_SPECIFIC_CLASS_NAME)
if not platform_psuutil:
psud_util.log_error("failed to load psuutil")
sys.exit(1)

state_db = swsscommon.DBConnector(swsscommon.STATE_DB,
REDIS_HOSTNAME,
REDIS_PORT,
REDIS_TIMEOUT_MSECS)
psud_util.redis_hostname,
psud_util.redis_port,
psud_util.redis_timeout_msecs)
psu_tbl = swsscommon.Table(state_db, "PSU_INFO")
chassis_tbl = swsscommon.Table(state_db, "CHASSIS_INFO")
num_psus = platform_psuutil.get_num_psus()
fvs = swsscommon.FieldValuePairs([('num_psus', str(num_psus))])
chassis_tbl.set('chassis 1', fvs)

# Start main loop to listen to the PSU change event.
log_info("Start main loop")
psud_util.log_info("Start main loop")
while True:
psu_db_update(psu_tbl, num_psus)
psu_db_update(platform_psuutil, psu_tbl, num_psus)
time.sleep(PSU_INFO_UPDATE_PERIOD_SECS)

# Clean all the information from DB and then exit
for psu_index in range(1, num_psus + 1):
psu_tbl._del("PSU {}".format(psu_index))
chassis_tbl._del('chassis 1')
log_error("Error: return error from psu daemon, exiting...")
return 1

if __name__ == '__main__':
Expand Down
Loading

0 comments on commit 7789a34

Please sign in to comment.