summaryrefslogtreecommitdiff
path: root/ncserver/module/interfaces.py
blob: 497c63ad1656b8e571aa49f23f9175cc1f1b4b58 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
"""
NETCONF for APK Distributions server:
    ietf-interfaces 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 os
import pathlib
import subprocess

from lxml import etree
from netconf import error, util

from ncserver.base.util import _, yang_dt_for_timestamp


QName = etree.QName  # pylint: disable=I1101


LOGGER = logging.getLogger(__name__)
"""The object used for logging informational messages."""


M_ABI_VERSION = 1
"""The ABI version of this NETCONF module."""


M_PREFIX = "if"
"""The XML tag prefix for this module's tags."""


M_NS = "urn:ietf:params:xml:ns:yang:ietf-interfaces"
"""The XML namespace for this module."""


M_NAME = "ietf-interfaces"
"""The YANG model name for this module."""


M_REVISION = "2018-02-20"
"""The YANG revision date for this module."""


M_IMPORTS = {
    'ietf-yang-types@2013-07-15': {
        'ns': "urn:ietf:params:xml:ns:yang:ietf-yang-types", 'prefix': "yang"
    }
}
"""The imported YANG modules for this module."""


M_FEATURES = ['pre-provisioning']
"""The supported features declared in YANG for this module."""


def _add_running_contents(ifaces):
    """Retrieve the interface configuration for this device.

    Allows returning the 'config true' data for both datastores."""
    for ifname in pathlib.Path('/sys/class/net').iterdir():
        iface = util.subelm(ifaces, 'if:interface')
        iface.append(util.leaf_elm('if:name', ifname.name))


def running(node):
    """Retrieve the service configuration for this device."""
    ifaces = util.subelm(node, 'if:interfaces')
    _add_running_contents(ifaces)


def operational(node):
    """Retrieve the service state for this device."""
    ifaces = util.subelm(node, 'if:interfaces')
    _add_running_contents(ifaces)

    counter_tags = {
            'rx.octets': 'if:in-octets',
            'rx.discard': 'if:in-discards',
            'rx.errors': 'if:in-errors',
            'tx.octets': 'if:out-octets',
            'tx.discard': 'if:out-discards',
            'tx.errors': 'if:out-errors'
    }

    for iface in ifaces.iterchildren():
        name = iface.find('{'+M_NS+'}name').text
        stats = util.subelm(iface, 'if:statistics')
        # XXX BAD vvv
        stats.append(util.leaf_elm('if:discontinuity-time', '2020-01-01T01:01:01.011Z'))
        # XXX BAD ^^^

        result = subprocess.run(['/sbin/ifupdown', 'ifctrstat', name],
                                stdout=subprocess.PIPE)
        if result.returncode != 0:
            LOGGER.error(_('ifctrstat failed for %s: %s'),
                    name, result.returncode)
            continue

        counters = result.stdout.decode('utf-8').split('\n')
        counters.pop()
        for counter, value in [data.split(': ') for data in counters]:
            if counter not in counter_tags.keys():
                LOGGER.warning(_('unhandled ifctrstat counter for %s: %s'),
                    name, counter)
                continue
            stats.append(util.leaf_elm(counter_tags[counter], value))


def edit(session, rpc, node, def_op):
    """Edit the interface configuration for this device."""