summaryrefslogtreecommitdiff
path: root/ncserver/module/system.py
diff options
context:
space:
mode:
authorA. Wilcox <AWilcox@Wilcox-Tech.com>2020-09-04 21:54:50 -0500
committerA. Wilcox <AWilcox@Wilcox-Tech.com>2020-09-04 21:54:50 -0500
commit34b2a9526408fa8c5cfea99ead5a48e88120fbfd (patch)
tree2abb8f33fc0f5576de04cbabbae485958e21c2d0 /ncserver/module/system.py
parent3517209d63d5a8e3eda2b56250edaef3e74a382e (diff)
downloadnetconfapk-34b2a9526408fa8c5cfea99ead5a48e88120fbfd.tar.gz
netconfapk-34b2a9526408fa8c5cfea99ead5a48e88120fbfd.tar.bz2
netconfapk-34b2a9526408fa8c5cfea99ead5a48e88120fbfd.tar.xz
netconfapk-34b2a9526408fa8c5cfea99ead5a48e88120fbfd.zip
ietf-system: Return contact, location, hostname, DNS info
Diffstat (limited to 'ncserver/module/system.py')
-rw-r--r--ncserver/module/system.py113
1 files changed, 109 insertions, 4 deletions
diff --git a/ncserver/module/system.py b/ncserver/module/system.py
index 285b272..1b2f85c 100644
--- a/ncserver/module/system.py
+++ b/ncserver/module/system.py
@@ -10,14 +10,24 @@ with this source distribution for more information.
SPDX-License-Identifier: NCSA
"""
+import logging
+import os.path
import platform
import subprocess
import time
from datetime import datetime
from math import floor
+from socket import gethostname
+
from netconf import util
+from ncserver.base.util import _
+
+
+LOGGER = logging.getLogger(__name__)
+"""The object used for logging informational messages."""
+
M_ABI_VERSION = 1
"""The ABI version of this NETCONF module."""
@@ -56,8 +66,99 @@ M_IMPORTS = {
"""The imported YANG modules for this module."""
+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'):
+ root.append(util.leaf_elm('sys:enabled', 'false'))
+ return
+
+ # XXX TODO: parse NTP configuration.
+
+
+def _parse_resolv_conf_to(sys_node):
+ """Parse /etc/resolv.conf into /sys:system/dns-resolver format."""
+ root = util.subelm(sys_node, 'sys:dns-resolver')
+
+ with open('/etc/resolv.conf', 'r') as rconf_f:
+ rconf = rconf_f.readlines()
+
+ # Stores the last NAME: line seen.
+ last_name = 'Resolver'
+ # Containers for actual data.
+ resolvers = dict()
+ search = list()
+ # musl defaults; see musl:include/resolv.h
+ attempts = 2
+ timeout = 5
+
+ for line in rconf:
+ line = line.rstrip()
+ if line.startswith('# NAME: '):
+ last_name = line[8:]
+ elif line.startswith('nameserver '):
+ if len(resolvers) >= 3:
+ continue # invalid configuration, so don't report it.
+ if last_name in resolvers:
+ last_name = last_name + "-1"
+ resolvers[last_name] = line[11:]
+ elif line.startswith('options attempts:'):
+ try:
+ # musl caps attempts at 10
+ attempts = min(10, int(line[17:]))
+ except ValueError:
+ LOGGER.warning(_("invalid resolv.conf: non-integral attempts"))
+ elif line.startswith('options timeout:'):
+ try:
+ # musl caps timeout at 60
+ timeout = min(60, int(line[16:]))
+ except ValueError:
+ LOGGER.warning(_("invalid resolv.conf: non-integral timeout"))
+ # This logic is taken directly from musl source code.
+ elif line.startswith('domain') or line.startswith('search'):
+ search = line[7:].split(' ')
+
+ for domain in search:
+ root.append(util.leaf_elm('sys:search', domain))
+
+ for pair in resolvers.items():
+ res = util.subelm(root, 'sys:server')
+ res.append(util.leaf_elm('sys:name', pair[0]))
+ udp = util.subelm(res, 'sys:udp-and-tcp')
+ udp.append(util.leaf_elm('sys:address', pair[1]))
+
+ opts = util.subelm(root, 'sys:options')
+ opts.append(util.leaf_elm('sys:timeout', timeout))
+ opts.append(util.leaf_elm('sys:attempts', attempts))
+
+
+def _parse_authn_to(sys_node):
+ """Parse current config into /sys:system/authentication format."""
+ sys_node.append(util.leaf_elm('sys:authentication', ''))
+
+
def running(node):
"""Retrieve the running configuration for this system."""
+ sys = util.subelm(node, 'sys:system')
+
+ if os.path.exists('/etc/netconf/contact…txt'):
+ with open('/etc/netconf/contact.txt', 'r') as contact_f:
+ sys.append(util.leaf_elm('sys:contact', contact_f.read()))
+ else:
+ sys.append(util.leaf_elm('sys:contact', ''))
+
+ if os.path.exists('/etc/netconf/location.txt'):
+ with open('/etc/netconf/location.txt', 'r') as loc_f:
+ sys.append(util.leaf_elm('sys:location', loc_f.read()))
+ else:
+ sys.append(util.leaf_elm('sys:location', ''))
+
+ sys.append(util.leaf_elm('sys:hostname', gethostname()))
+
+ _parse_ntp_conf_to(sys)
+ _parse_resolv_conf_to(sys)
+ _parse_authn_to(sys)
def operational(node):
@@ -67,10 +168,14 @@ def operational(node):
plat = util.subelm(state, 'sys:platform')
plat.append(util.leaf_elm('sys:os-name', platform.system()))
plat.append(util.leaf_elm('sys:os-release', platform.release()))
- osv = subprocess.run(['/bin/sh', '-c',
- '( . /etc/os-release && echo -n $PRETTY_NAME )'],
- stdout=subprocess.PIPE)
- plat.append(util.leaf_elm('sys:os-version', osv.stdout.decode('utf-8')))
+ try:
+ osv = subprocess.run(['/bin/sh', '-c',
+ '( . /etc/os-release && echo -n $PRETTY_NAME )'],
+ stdout=subprocess.PIPE, check=True)
+ version = osv.stdout.decode('utf-8')
+ except subprocess.CalledProcessError:
+ version = "Unknown Distribution"
+ plat.append(util.leaf_elm('sys:os-version', version))
plat.append(util.leaf_elm('sys:machine', platform.machine()))
clock = util.subelm(state, 'sys:clock')