summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorA. Wilcox <AWilcox@Wilcox-Tech.com>2020-08-31 11:43:38 -0500
committerA. Wilcox <AWilcox@Wilcox-Tech.com>2020-08-31 11:43:38 -0500
commit2116c2b62512c7ec9f10a9ac523962f0671e94c1 (patch)
treeae9118b3229ceb4a588e334069564aae63623e47
parent0c52c51a33a5db9dfa7f2514b7bc72e608b25ef2 (diff)
downloadnetconfapk-2116c2b62512c7ec9f10a9ac523962f0671e94c1.tar.gz
netconfapk-2116c2b62512c7ec9f10a9ac523962f0671e94c1.tar.bz2
netconfapk-2116c2b62512c7ec9f10a9ac523962f0671e94c1.tar.xz
netconfapk-2116c2b62512c7ec9f10a9ac523962f0671e94c1.zip
Add server and configuration modules
-rw-r--r--ncserver/config.py85
-rw-r--r--ncserver/server.py80
-rw-r--r--requirements.txt2
3 files changed, 167 insertions, 0 deletions
diff --git a/ncserver/config.py b/ncserver/config.py
new file mode 100644
index 0000000..047e3a5
--- /dev/null
+++ b/ncserver/config.py
@@ -0,0 +1,85 @@
+"""
+NETCONF for APK Distributions server:
+ Configuration manager module
+
+Copyright © 2020 Adélie Software in the Public Benefit, Inc.
+
+Released under the terms of the NCSA license. See the LICENSE file included
+with this source distribution for more information.
+
+SPDX-License-Identifier: NCSA
+"""
+
+import logging
+import yaml
+
+from taillight import Signal
+
+from ncserver.base.util import _
+
+
+CONFIG_RELOADED = Signal(('ConfigManager', 'reloaded'))
+"""Signal fired when configuration is reloaded."""
+
+
+class ConfigManager:
+ """The configuration manager for NETCONF for APK Distributions."""
+
+ def __init__(self):
+ """Initialise the configuration manager."""
+ self._config = {'server': {'port': 830, 'debug': False, 'modules': [],
+ 'users': ['netconf']}}
+ self._logger = logging.getLogger("ConfigManager")
+ self.reload_config()
+
+ def reload_config(self):
+ """Reload the configuration from disk."""
+ try:
+ with open('/etc/netconf/netconf.conf', 'r') as conf:
+ self._config = yaml.safe_load(conf)
+ except IOError as exc:
+ self._logger.error(_("Couldn't open configuration file: %s"), exc)
+ except BaseException as exc: # pylint: disable=W0703
+ self._logger.error(_("Couldn't read configuration file: %s"), exc)
+ else:
+ CONFIG_RELOADED.call()
+
+ def get(self, clade: str, key: str):
+ """Retrieve the value for the specified configuration key.
+
+ :param str clade:
+ The configuration clade (typically 'server').
+
+ :param str key:
+ The configuration key desired.
+
+ :returns str:
+ The value of the specified configuration key.
+
+ :raises KeyError:
+ The key is not configured or set.
+ """
+ return self._config[clade][key]
+
+ def get_list(self, clade: str, key: str) -> list:
+ """Retrieve a list value for the specified configuration key.
+
+ :param str clade:
+ The configuration clade (typically 'server').
+
+ :param str key:
+ The configuration key desired.
+
+ :returns list:
+ The value of the specified configuration key.
+
+ :raises KeyError:
+ The key is not configured or set.
+
+ :raises TypeError:
+ The value for this key is not a list.
+ """
+ value = self._config[clade][key]
+ if not isinstance(value, list):
+ raise TypeError(_("{}/{} is not a list value").format(clade, key))
+ return value
diff --git a/ncserver/server.py b/ncserver/server.py
new file mode 100644
index 0000000..a0eed8e
--- /dev/null
+++ b/ncserver/server.py
@@ -0,0 +1,80 @@
+"""
+NETCONF for APK Distributions server:
+ Server module
+
+Copyright © 2020 Adélie Software in the Public Benefit, Inc.
+
+Released under the terms of the NCSA license. See the LICENSE file included
+with this source distribution for more information.
+
+SPDX-License-Identifier: NCSA
+"""
+
+import logging
+
+from netconf import util
+from netconf.server import NetconfSSHServer, SSHAuthorizedKeysController
+
+from ncserver.base.modman import ModuleManager
+from ncserver.config import ConfigManager
+
+
+class Server:
+ """The NETCONF server component."""
+
+ def __init__(self, port=830):
+ """Create the NETCONF server.
+
+ :param int port:
+ The port number to listen on. Typically 830.
+ """
+ self.config = ConfigManager()
+ self.auth = SSHAuthorizedKeysController(
+ users=self.config.get_list('server', 'users')
+ )
+
+ self.debug = self.config.get('server', 'debug')
+ if self.debug:
+ logging.basicConfig(level=logging.DEBUG)
+ else:
+ logging.basicConfig(level=logging.INFO)
+
+ self.server = NetconfSSHServer(
+ self.auth, self, port, self.config.get('server', 'host_key'),
+ self.debug
+ )
+ self.modman = ModuleManager()
+ for module in self.config.get_list('server', 'modules'):
+ self.modman.load_module(module)
+
+ def close(self):
+ """Close all connections."""
+ self.server.close()
+
+ def nc_append_capabilities(self, capabilities):
+ """List all capabilities of this NETCONF server."""
+ for module in self.modman.modules.values():
+ util.subelm(capabilities, 'capability').text = module.M_NS
+
+ def rpc_get(self, session, rpc, filter_or_none): # pylint: disable=W0613
+ """Handle the <get/> RPC."""
+ root = util.elm('nc:data')
+ self.modman.collect_running(root)
+ self.modman.collect_operational(root)
+
+ return util.filter_results(rpc, root, filter_or_none, self.debug)
+
+ # pylint: disable=W0613
+ def rpc_get_config(self, session, rpc, source, filter_or_none):
+ """Handle the <get-config/> RPC."""
+ root = util.elm('nc:data')
+ self.modman.collect_running(root)
+
+ return util.filter_results(rpc, root, filter_or_none, self.debug)
+
+if __name__ == "__main__":
+ s = Server()
+ try:
+ s.server.join()
+ except KeyboardInterrupt:
+ s.close()
diff --git a/requirements.txt b/requirements.txt
index 959bb53..57d28ca 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1 +1,3 @@
netconf>=2.1.0
+taillight
+PyYAML