forked from sonic-net/sonic-buildimage
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add sonic-ledd (Front-panel LED control daemon) (sonic-net#5)
- Loading branch information
Showing
5 changed files
with
327 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# SONiC: Software for Open Networking in the Cloud | ||
|
||
## sonic-platform-daemons | ||
|
||
Daemons for controlling platform-specific functionality in SONiC | ||
|
||
|
||
# Contribution guide | ||
|
||
All contributors must sign a contribution license agreement before contributions can be accepted. Contact kasubra@microsoft.com or daloher@microsoft.com. Later this will be automated. | ||
|
||
### GitHub Workflow | ||
|
||
We're following basic GitHub Flow. If you have no idea what we're talking about, check out [GitHub's official guide](https://guides.github.com/introduction/flow/). Note that merge is only performed by the repository maintainer. | ||
|
||
Guide for performing commits: | ||
|
||
* Isolate each commit to one component/bugfix/issue/feature | ||
* Use a standard commit message format: | ||
|
||
> [component/folder touched]: Description intent of your changes | ||
> | ||
> [List of changes] | ||
> | ||
> Signed-off-by: Your Name your@email.com | ||
For example: | ||
|
||
> swss-common: Stabilize the ConsumerTable | ||
> | ||
> * Fixing autoreconf | ||
> * Fixing unit-tests by adding checkers and initialize the DB before start | ||
> * Adding the ability to select from multiple channels | ||
> * Health-Monitor - The idea of the patch is that if something went wrong with the notification channel, | ||
> we will have the option to know about it (Query the LLEN table length). | ||
> | ||
> Signed-off-by: user@dev.null | ||
|
||
* Each developer should fork this repository and [add the team as a Contributor](https://help.github.com/articles/adding-collaborators-to-a-personal-repository) | ||
* Push your changes to your private fork and do "pull-request" to this repository | ||
* Use a pull request to do code review | ||
* Use issues to keep track of what is going on |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
#!/usr/bin/env python | ||
# | ||
# ledd | ||
# | ||
# Front-panel LED control daemon for SONiC | ||
# | ||
|
||
try: | ||
import ast | ||
import getopt | ||
import os | ||
import imp | ||
import signal | ||
import subprocess | ||
import swsssdk | ||
import sys | ||
import syslog | ||
import time | ||
except ImportError, e: | ||
raise ImportError (str(e) + " - required module not found") | ||
|
||
#============================= Constants ============================= | ||
|
||
VERSION = '1.0' | ||
|
||
USAGE_HELP=""" | ||
Usage: ledd [options] | ||
Options: | ||
-h,--help Print this usage statement and exit | ||
-v,--version Print version information and exit | ||
""" | ||
|
||
SYSLOG_IDENTIFIER = "ledd" | ||
|
||
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_ROOT = "/usr/share/sonic/device" | ||
|
||
PORT_TABLE_PREFIX = "PORT_TABLE:" | ||
|
||
led_control = None | ||
|
||
#========================== 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...\n") | ||
return | ||
elif sig == signal.SIGINT: | ||
log_info("Caught SIGINT - exiting...\n") | ||
sys.exit(0) | ||
elif sig == signal.SIGTERM: | ||
log_info("Caught SIGTERM - exiting...\n") | ||
sys.exit(0) | ||
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(): | ||
global led_control | ||
|
||
# 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 = '/'.join([platform_path, '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 not os.path.isfile(module_file): | ||
log_info("Failed to locate platform-specific %s module. Exiting..." % LED_MODULE_NAME) | ||
sys.exit(0) | ||
|
||
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 -1 | ||
|
||
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 -2 | ||
|
||
log_info("Instantiated class '%s.%s'." % (LED_MODULE_NAME, LED_CLASS_NAME)) | ||
|
||
return 0 | ||
|
||
#=============================== Main ================================ | ||
|
||
def main(): | ||
port_status_dict = {} | ||
|
||
log_info("Starting up...") | ||
|
||
if not os.geteuid() == 0: | ||
log_error("Must be root to run this daemon") | ||
print "Error: Must be root to run this daemon" | ||
sys.exit(1) | ||
|
||
# Parse options if provided | ||
if (len(sys.argv) > 1): | ||
try: | ||
options, remainder = getopt.getopt(sys.argv[1:], | ||
'hv', | ||
['help', | ||
'version']) | ||
except getopt.GetoptError, e: | ||
print e | ||
print USAGE_HELP | ||
sys.exit(2) | ||
|
||
for opt, arg in options: | ||
if opt == '--help' or opt == '-h': | ||
print USAGE_HELP | ||
sys.exit(0) | ||
elif opt == '--version' or opt == '-v': | ||
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 class | ||
err = load_platform_led_control_module() | ||
if err != 0: | ||
sys.exit(1) | ||
|
||
# Connect to APPL_DB using SwSS SDK | ||
swss = swsssdk.SonicV2Connector() | ||
swss.connect(swss.APPL_DB) | ||
|
||
# Loop forever | ||
while True: | ||
# TODO: Move dictionary creation and population out of while loop. Do it only once | ||
# and subscribe for notifications from DB when ports come or go. Add/remove | ||
# dictionary entries as necessary. | ||
|
||
# Get a list of all ports from the database | ||
port_table_keys = swss.keys(swss.APPL_DB, PORT_TABLE_PREFIX + '*'); | ||
|
||
# Create a dictionary of <sonic_port_name>:<link_status> containing all ports | ||
# Initially set all statuses to 'down' | ||
for key in port_table_keys: | ||
# Remove table name prefix | ||
port_name = key[len(PORT_TABLE_PREFIX):] | ||
|
||
# TODO: Once the DB is fixed and this 'ConfigDone' entry is gone, remove this check | ||
if port_name == 'ConfigDone': | ||
continue | ||
|
||
port_status_dict[port_name] = 'down' | ||
led_control.port_link_state_change(port_name, port_status_dict[port_name]) | ||
|
||
for (key, value) in port_status_dict.iteritems(): | ||
status = swss.get(swss.APPL_DB, PORT_TABLE_PREFIX + key, 'oper_status') | ||
|
||
# If the status has changed, update it in our dictionary and report to our plugin | ||
if value != status: | ||
port_status_dict[key] = status | ||
led_control.port_link_state_change(key, status) | ||
|
||
time.sleep(1) | ||
pass | ||
|
||
if __name__ == '__main__': | ||
main() | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
from setuptools import setup | ||
|
||
setup( | ||
name='sonic-ledd', | ||
version='1.0', | ||
description='Front-panel LED control daemon for SONiC', | ||
license='Apache 2.0', | ||
author='SONiC Team', | ||
author_email='linuxnetdev@microsoft.com', | ||
url='https://github.com/Azure/sonic-platform-daemons', | ||
maintainer='Joe LeVeque', | ||
maintainer_email='jolevequ@microsoft.com', | ||
packages=['sonic_led'], | ||
scripts=[ | ||
'scripts/ledd', | ||
], | ||
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 LED led daemon LEDD ledd', | ||
) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#!/usr/bin/env python | ||
# | ||
# led_control_base.py | ||
# | ||
# Abstract base class for implementing platform-specific | ||
# LED control functionality for SONiC | ||
# | ||
|
||
try: | ||
import abc | ||
except ImportError, e: | ||
raise ImportError (str(e) + " - required module not found") | ||
|
||
class LedControlBase(object): | ||
__metaclass__ = abc.ABCMeta | ||
|
||
@abc.abstractmethod | ||
def port_link_state_change(self, port, state): | ||
""" | ||
Called when port link state changes. Update port link state LED here. | ||
:param port: A string, SONiC port name (e.g., "Ethernet0") | ||
:param state: A string, the port link state (either "up" or "down") | ||
""" | ||
return | ||
|