summaryrefslogtreecommitdiff
path: root/ncserver/module/system.py
diff options
context:
space:
mode:
authorA. Wilcox <AWilcox@Wilcox-Tech.com>2020-10-23 20:22:19 -0500
committerA. Wilcox <AWilcox@Wilcox-Tech.com>2020-10-23 20:22:19 -0500
commit1ae754a07a38be3a524774c42928aa4e13801d71 (patch)
tree81b5911a847e630f6d3bdc52482d2e4c8b04f093 /ncserver/module/system.py
parent145878b97d008b255251c7fc4eb4e1e2aa5816da (diff)
downloadnetconfapk-1ae754a07a38be3a524774c42928aa4e13801d71.tar.gz
netconfapk-1ae754a07a38be3a524774c42928aa4e13801d71.tar.bz2
netconfapk-1ae754a07a38be3a524774c42928aa4e13801d71.tar.xz
netconfapk-1ae754a07a38be3a524774c42928aa4e13801d71.zip
ietf-system: Support read of NTPsec configuration
Diffstat (limited to 'ncserver/module/system.py')
-rw-r--r--ncserver/module/system.py156
1 files changed, 154 insertions, 2 deletions
diff --git a/ncserver/module/system.py b/ncserver/module/system.py
index c27b3a0..d5c097c 100644
--- a/ncserver/module/system.py
+++ b/ncserver/module/system.py
@@ -85,15 +85,165 @@ _LOCATION_PATH = '/etc/netconf/location.txt'
"""The file path for the contents of /sys:system/location."""
+class NTPServer: # pylint: disable=R0902
+ """Represents an NTP server entry."""
+ def __init__(self, host: str, **kwargs):
+ """Create a new NTP server entry.
+
+ :param str host:
+ The host, in IP or DNS form.
+ """
+ self.host = host
+ self.mode = kwargs.pop('mode', 'pool')
+ if self.mode in ('server', 'peer'):
+ self.key = kwargs.pop('key', None)
+ else:
+ self.key = None
+ self.burst = kwargs.pop('burst', False)
+ self.iburst = kwargs.pop('iburst', False)
+ self.version = kwargs.pop('version', None)
+ self.prefer = kwargs.pop('prefer', False)
+ self.minpoll = kwargs.pop('minpoll', None)
+ self.maxpoll = kwargs.pop('maxpoll', None)
+ if self.mode == 'poll':
+ self.preempt = kwargs.pop('preempt', False)
+ else:
+ self.preempt = False
+
+ def __repr__(self):
+ """Return a representation of this object."""
+ args = {'mode': '"' + self.mode + '"'}
+ if self.burst:
+ args['burst'] = True
+ if self.iburst:
+ args['iburst'] = True
+ if self.version is not None:
+ args['version'] = '"' + self.version + '"'
+ if self.prefer:
+ args['prefer'] = True
+ if self.minpoll is not None:
+ args['minpoll'] = '"' + self.minpoll + '"'
+ if self.maxpoll is not None:
+ args['maxpoll'] = '"' + self.maxpoll + '"'
+
+ if self.mode in ('server', 'peer') and self.key is not None:
+ args['key'] = '"' + self.key + '"'
+ if self.mode == 'poll' and self.preempt:
+ args['preempt'] = True
+
+ nondef_args = ', '.join(
+ ['{}={}'.format(*item) for item in args.items()]
+ )
+ return "NTPServer('{host}', {nondef_args})".format(host=self.host,
+ nondef_args=nondef_args)
+
+ def __str__(self):
+ """Return the configuration line for this server."""
+ line = self.mode + ' '
+
+ if ':' in self.host and '[' not in self.host:
+ if '%' in self.host:
+ addr, dev = self.host.split('%')
+ line += '[' + addr + ']%' + dev
+ else:
+ line += '[' + self.host + ']'
+ else:
+ line += self.host
+
+ if self.mode in ('server', 'peer') and self.key is not None:
+ line += ' key ' + self.key
+
+ if self.mode in ('pool', 'server'):
+ if self.burst:
+ line += ' burst'
+ if self.iburst:
+ line += ' iburst'
+
+ if self.version is not None:
+ line += ' version ' + str(self.version)
+
+ if self.prefer:
+ line += ' prefer'
+
+ if self.minpoll is not None:
+ line += ' minpoll ' + self.minpoll
+ if self.maxpoll is not None:
+ line += ' maxpoll ' + self.maxpoll
+
+ if self.mode == 'pool' and self.preempt:
+ line += ' preempt'
+
+ return line
+
+ @classmethod
+ def from_line(cls, line: str):
+ """Create an NTPServer object from a configuration file line."""
+ tokens = line.strip().split(' ')
+ tokens.reverse()
+
+ kwargs = {'mode': tokens.pop()}
+ host = tokens.pop()
+
+ bool_keys = ('burst', 'iburst', 'prefer', 'preempt')
+ value_keys = ('key', 'version', 'minpoll', 'maxpoll')
+
+ while len(tokens) > 0:
+ key = tokens.pop()
+ if key in bool_keys:
+ kwargs[key] = True
+ elif key in value_keys:
+ kwargs[key] = tokens.pop()
+ else:
+ LOGGER.warning('unknown NTP server conf key: %s', key)
+
+ return cls(host, **kwargs)
+
+
+def _parse_ntp_config() -> dict:
+ """Parse /etc/ntp.conf and return the configuration.
+
+ The return value is a dictionary with the following keys:
+
+ * servers: a list of NTPServer objects.
+ """
+ conf = open('/etc/ntp.conf', 'r')
+ lines = conf.readlines()
+ conf.close()
+
+ result = {'servers': list()}
+
+ for line in lines:
+ line.strip()
+ if line.startswith('#') or len(line) == 0:
+ continue
+ if any([line.startswith(word) for word in ('server', 'pool', 'peer')]):
+ result['servers'].append(NTPServer.from_line(line))
+ else:
+ LOGGER.warning('unhandled NTP configuration line: %s', line)
+
+ return result
+
+
def _parse_ntp_conf_to(sys_node):
"""Parse NTP configuration into /sys:system/ntp format."""
root = util.subelm(sys_node, 'sys:ntp')
- if not os.path.exists('/etc/ntpsec/ntp.conf'):
+ if not os.path.exists('/etc/ntp.conf'):
root.append(util.leaf_elm('sys:enabled', 'false'))
return
- # XXX TODO: parse NTP configuration.
+ conf = _parse_ntp_config()
+ for server in conf['servers']:
+ serv_node = util.subelm(root, 'sys:server')
+ serv_node.append(util.leaf_elm('sys:name', server.host))
+ serv_node.append(util.leaf_elm('sys:association-type', server.mode))
+ serv_node.append(util.leaf_elm('sys:iburst',
+ str(server.iburst).lower()))
+ serv_node.append(util.leaf_elm('sys:prefer',
+ str(server.prefer).lower()))
+ udp = util.subelm(serv_node, 'sys:udp')
+ udp.append(util.leaf_elm('sys:address', server.host))
+ return
def _parse_resolv_conf() -> dict:
@@ -318,6 +468,8 @@ def _edit_dns_search(session, rpc, node, def_op, curr: dict):
def _edit_dns_server(session, rpc, node, def_op, curr: dict):
+ # yes, this function is too complex.
+ # pylint: disable=R0912,R0914,R0915
"""Edit DNS nameserver configuration."""
operation = node_operation(node, def_op)
xmlmap = {'': 'urn:ietf:params:xml:ns:yang:ietf-system'}