Commit 32d82663 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Device component - GNMI OpenConfig:

- advanced development of driver
- updated unitary tests and related scripts
parent a3df08b8
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -22,4 +22,4 @@ RCFILE=$PROJECTDIR/coverage/.coveragerc
# Run unitary tests and analyze coverage of code at same time
# helpful pytest flags: --log-level=INFO -o log_cli=true --verbose --maxfail=1 --durations=0
coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose \
    device/tests/test_unitary_gnmi_openconfig.py
    device/tests/gnmi_openconfig/test_unitary_gnmi_openconfig.py
+33 −33
Original line number Diff line number Diff line
@@ -12,11 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import json, logging
import json, libyang, logging
from typing import Any, Dict, List, Tuple
import pyangbind.lib.pybindJSON as pybindJSON
from . import openconfig
from ._Handler import _Handler
from .YangHandler import YangHandler

LOGGER = logging.getLogger(__name__)

@@ -25,40 +24,41 @@ class InterfaceCounterHandler(_Handler):
    def get_resource_key(self) -> str: return '/interface/counters'
    def get_path(self) -> str: return '/openconfig-interfaces:interfaces/interface/state/counters'

    def parse(self, json_data : Dict) -> List[Tuple[str, Dict[str, Any]]]:
    def parse(
        self, json_data : Dict, yang_handler : YangHandler
    ) -> List[Tuple[str, Dict[str, Any]]]:
        LOGGER.info('json_data = {:s}'.format(json.dumps(json_data)))
        oc_interfaces = pybindJSON.loads_ietf(json_data, openconfig.interfaces, 'interfaces')
        LOGGER.info('oc_interfaces = {:s}'.format(pybindJSON.dumps(oc_interfaces, mode='ietf')))

        counters = []
        for interface_key, oc_interface in oc_interfaces.interface.items():
            LOGGER.info('interface_key={:s} oc_interfaces={:s}'.format(
                interface_key, pybindJSON.dumps(oc_interface, mode='ietf')
            ))
        yang_interfaces_path = self.get_path()
        json_data_valid = yang_handler.parse_to_dict(yang_interfaces_path, json_data, fmt='json')

            interface = {}
            interface['name'] = oc_interface.name

            interface_counters = oc_interface.state.counters
            interface['in-broadcast-pkts' ] = interface_counters.in_broadcast_pkts
            interface['in-discards'       ] = interface_counters.in_discards
            interface['in-errors'         ] = interface_counters.in_errors
            interface['in-fcs-errors'     ] = interface_counters.in_fcs_errors
            interface['in-multicast-pkts' ] = interface_counters.in_multicast_pkts
            interface['in-octets'         ] = interface_counters.in_octets
            interface['in-pkts'           ] = interface_counters.in_pkts
            interface['in-unicast-pkts'   ] = interface_counters.in_unicast_pkts
            interface['out-broadcast-pkts'] = interface_counters.out_broadcast_pkts
            interface['out-discards'      ] = interface_counters.out_discards
            interface['out-errors'        ] = interface_counters.out_errors
            interface['out-multicast-pkts'] = interface_counters.out_multicast_pkts
            interface['out-octets'        ] = interface_counters.out_octets
            interface['out-pkts'          ] = interface_counters.out_pkts
            interface['out-unicast-pkts'  ] = interface_counters.out_unicast_pkts
        entries = []
        for interface in json_data_valid['interfaces']['interface']:
            LOGGER.info('interface={:s}'.format(str(interface)))

            interface_name = interface['name']
            interface_counters = interface.get('state', {}).get('counters', {})
            _interface = {
                'name'              : interface_name,
                'in-broadcast-pkts' : interface_counters['in_broadcast_pkts' ],
                'in-discards'       : interface_counters['in_discards'       ],
                'in-errors'         : interface_counters['in_errors'         ],
                'in-fcs-errors'     : interface_counters['in_fcs_errors'     ],
                'in-multicast-pkts' : interface_counters['in_multicast_pkts' ],
                'in-octets'         : interface_counters['in_octets'         ],
                'in-pkts'           : interface_counters['in_pkts'           ],
                'in-unicast-pkts'   : interface_counters['in_unicast_pkts'   ],
                'out-broadcast-pkts': interface_counters['out_broadcast_pkts'],
                'out-discards'      : interface_counters['out_discards'      ],
                'out-errors'        : interface_counters['out_errors'        ],
                'out-multicast-pkts': interface_counters['out_multicast_pkts'],
                'out-octets'        : interface_counters['out_octets'        ],
                'out-pkts'          : interface_counters['out_pkts'          ],
                'out-unicast-pkts'  : interface_counters['out_unicast_pkts'  ],
            }
            LOGGER.info('interface = {:s}'.format(str(interface)))

            if len(interface) == 0: continue
            counters.append(('/interface[{:s}]'.format(interface['name']), interface))
            entry_interface_key = '/interface[{:s}]'.format(interface_name)
            entries.append((entry_interface_key, _interface))

        return counters
        return entries
+22 −12
Original line number Diff line number Diff line
@@ -12,11 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import json, libyang, logging
import operator
import json, libyang, logging, operator
from typing import Any, Dict, List, Tuple
from ._Handler import _Handler
from .Tools import get_bool, get_int, get_str
from .Tools import get_str
from .YangHandler import YangHandler

LOGGER = logging.getLogger(__name__)
@@ -56,21 +55,32 @@ class NetworkInstanceHandler(_Handler):
        ni_type = get_str(resource_value, 'type') # L3VRF / L2VSI / ...
        ni_type = MAP_NETWORK_INSTANCE_TYPE.get(ni_type, ni_type)

        # 'DIRECTLY_CONNECTED' is implicitly added
        str_path = '/network-instances/network-instance[name={:s}]'.format(ni_name)
        #str_data = json.dumps({
        #    'name': ni_name,
        #    'config': {'name': ni_name, 'type': ni_type},
        #})

        yang_nis : libyang.DContainer = yang_handler.get_data_path('/openconfig-network-instance:network-instances')
        yang_ni_path = 'network-instance[name="{:s}"]'.format(ni_name)
        yang_ni : libyang.DContainer = yang_nis.create_path(yang_ni_path)
        yang_ni.create_path('config/name', ni_name)
        yang_ni.create_path('config/type', ni_type)

        str_path = '/network-instances/network-instance[name={:s}]'.format(ni_name)
        str_data = json.dumps({
            'name': ni_name,
            'config': {'name': ni_name, 'type': ni_type},
        # 'DIRECTLY_CONNECTED' is implicitly added
        #'protocols': {'protocol': protocols},
        })

        str_data = yang_ni.print_mem('json')
        LOGGER.warning('str_data = {:s}'.format(str(str_data)))
        json_data = json.loads(str_data)
        json_data = json_data['openconfig-network-instance:network-instance'][0]
        str_data = json.dumps(json_data)
        return str_path, str_data

    def parse(
        self, json_data : Dict, yang_handler : YangHandler
    ) -> List[Tuple[str, Dict[str, Any]]]:
        LOGGER.debug('json_data = {:s}'.format(json.dumps(json_data)))
        LOGGER.info('json_data = {:s}'.format(json.dumps(json_data)))

        # Arista Parsing Fixes:
        # - Default instance comes with mpls/signaling-protocols/rsvp-te/global/hellos/state/hello-interval set to 0
+40 −12
Original line number Diff line number Diff line
@@ -12,20 +12,30 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import json, logging
import json, libyang, logging
from typing import Any, Dict, List, Tuple
from ._Handler import _Handler
from .Tools import get_int, get_str
from .YangHandler import YangHandler

LOGGER = logging.getLogger(__name__)

IS_CEOS = True

class NetworkInstanceInterfaceHandler(_Handler):
    def get_resource_key(self) -> str: return '/network_instance/interface'
    def get_path(self) -> str: return '/network-instances/network-instance/interfaces'
    def get_path(self) -> str: return '/openconfig-network-instance:network-instances/network-instance/interfaces'

    def compose(
        self, resource_key : str, resource_value : Dict, yang_handler : YangHandler, delete : bool = False
    ) -> Tuple[str, str]:
        ni_name   = get_str(resource_value, 'name'        ) # test-svc
        if_name   = get_str(resource_value, 'if_name'     ) # ethernet-1/1
        sif_index = get_int(resource_value, 'sif_index', 0) # 0
        
    def compose(self, resource_key : str, resource_value : Dict, delete : bool = False) -> Tuple[str, str]:
        ni_name   = str(resource_value['name'     ])    # test-svc
        if_name   = str(resource_value['if_name'  ])    # ethernet-1/1
        sif_index = int(resource_value['sif_index'])    # 0
        if IS_CEOS:
            if_id = if_name
        else:
            if_id = '{:s}.{:d}'.format(if_name, sif_index)

        if delete:
@@ -35,12 +45,30 @@ class NetworkInstanceInterfaceHandler(_Handler):
            return str_path, str_data

        str_path = '/network-instances/network-instance[name={:s}]/interfaces/interface[id={:s}]'.format(ni_name, if_id)
        str_data = json.dumps({
            'id': if_id,
            'config': {'id': if_id, 'interface': if_name, 'subinterface': sif_index},
        })
        #str_data = json.dumps({
        #    'id': if_id,
        #    'config': {'id': if_id, 'interface': if_name, 'subinterface': sif_index},
        #})

        yang_nis : libyang.DContainer = yang_handler.get_data_path('/openconfig-network-instance:network-instances')
        yang_ni : libyang.DContainer = yang_nis.create_path('network-instance[name="{:s}"]'.format(ni_name))
        yang_ni_ifs : libyang.DContainer = yang_ni.create_path('interfaces')
        yang_ni_if_path = 'interface[id="{:s}"]'.format(if_id)
        yang_ni_if : libyang.DContainer = yang_ni_ifs.create_path(yang_ni_if_path)
        yang_ni_if.create_path('config/id',           if_id)
        yang_ni_if.create_path('config/interface',    if_name)
        yang_ni_if.create_path('config/subinterface', sif_index)

        str_data = yang_ni_if.print_mem('json')
        LOGGER.warning('[compose] str_data = {:s}'.format(str(str_data)))
        json_data = json.loads(str_data)
        json_data = json_data['openconfig-network-instance:interface'][0]
        str_data = json.dumps(json_data)
        return str_path, str_data

    def parse(self, json_data : Dict) -> List[Tuple[str, Dict[str, Any]]]:
    def parse(
        self, json_data : Dict, yang_handler : YangHandler
    ) -> List[Tuple[str, Dict[str, Any]]]:
        LOGGER.warning('[parse] json_data = {:s}'.format(str(json_data)))
        response = []
        return response
+56 −23
Original line number Diff line number Diff line
@@ -12,21 +12,25 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import json, logging
import json, libyang, logging
from typing import Any, Dict, List, Tuple
from ._Handler import _Handler
from .Tools import get_int, get_str
from .YangHandler import YangHandler

LOGGER = logging.getLogger(__name__)

class NetworkInstanceStaticRouteHandler(_Handler):
    def get_resource_key(self) -> str: return '/network_instance/static_route'
    def get_path(self) -> str: return '/network-instances/network-instance/static_route'
    def get_path(self) -> str: return '/openconfig-network-instance:network-instances/network-instance/static_route'

    def compose(self, resource_key : str, resource_value : Dict, delete : bool = False) -> Tuple[str, str]:
        ni_name        = str(resource_value['name'                 ]) # test-svc
        prefix         = str(resource_value['prefix'               ]) # '172.0.1.0/24'
    def compose(
        self, resource_key : str, resource_value : Dict, yang_handler : YangHandler, delete : bool = False
    ) -> Tuple[str, str]:
        ni_name   = get_str(resource_value, 'name'  )   # test-svc
        prefix    = get_str(resource_value, 'prefix')   # '172.0.1.0/24'

        identifier = 'STATIC'
        identifier = 'openconfig-policy-types:STATIC'
        name = 'static'
        if delete:
            PATH_TMPL  = '/network-instances/network-instance[name={:s}]/protocols'
@@ -35,27 +39,56 @@ class NetworkInstanceStaticRouteHandler(_Handler):
            str_data = json.dumps({})
            return str_path, str_data

        next_hop       = str(resource_value['next_hop'             ]) # '172.0.0.1'
        next_hop_index = int(resource_value.get('next_hop_index', 0)) # 0
        next_hop       = get_str(resource_value, 'next_hop'         )   # '172.0.0.1'
        next_hop_index = get_int(resource_value, 'next_hop_index', 0)   # 0

        PATH_TMPL = '/network-instances/network-instance[name={:s}]/protocols/protocol[identifier={:s}][name={:s}]'
        str_path = PATH_TMPL.format(ni_name, identifier, name)
        str_data = json.dumps({
            'identifier': identifier, 'name': name,
            'config': {'identifier': identifier, 'name': name, 'enabled': True},
            'static_routes': {'static': [{
                'prefix': prefix,
                'config': {'prefix': prefix},
                'next_hops': {
                    'next-hop': [{
                        'index': next_hop_index,
                        'config': {'index': next_hop_index, 'next_hop': next_hop}
                    }]
                }
            }]}
        })
        #str_data = json.dumps({
        #    'identifier': identifier, 'name': name,
        #    'config': {'identifier': identifier, 'name': name, 'enabled': True},
        #    'static_routes': {'static': [{
        #        'prefix': prefix,
        #        'config': {'prefix': prefix},
        #        'next_hops': {
        #            'next-hop': [{
        #                'index': next_hop_index,
        #                'config': {'index': next_hop_index, 'next_hop': next_hop}
        #            }]
        #        }
        #    }]}
        #})

        yang_nis : libyang.DContainer = yang_handler.get_data_path('/openconfig-network-instance:network-instances')
        yang_ni : libyang.DContainer = yang_nis.create_path('network-instance[name="{:s}"]'.format(ni_name))
        yang_ni_prs : libyang.DContainer = yang_ni.create_path('protocols')
        yang_ni_pr_path = 'protocol[identifier="{:s}"][name="{:s}"]'.format(identifier, name)
        yang_ni_pr : libyang.DContainer = yang_ni_prs.create_path(yang_ni_pr_path)
        yang_ni_pr.create_path('config/identifier', identifier)
        yang_ni_pr.create_path('config/name',       name      )
        yang_ni_pr.create_path('config/enabled',    True      )

        yang_ni_pr_srs : libyang.DContainer = yang_ni_pr.create_path('static-routes')
        yang_ni_pr_sr_path = 'static[prefix="{:s}"]'.format(prefix)
        yang_ni_pr_sr : libyang.DContainer = yang_ni_pr_srs.create_path(yang_ni_pr_sr_path)
        yang_ni_pr_sr.create_path('config/prefix', prefix)

        yang_ni_pr_sr_nhs : libyang.DContainer = yang_ni_pr_sr.create_path('next-hops')
        yang_ni_pr_sr_nh_path = 'next-hop[index="{:d}"]'.format(next_hop_index)
        yang_ni_pr_sr_nh : libyang.DContainer = yang_ni_pr_sr_nhs.create_path(yang_ni_pr_sr_nh_path)
        yang_ni_pr_sr_nh.create_path('config/index', next_hop_index)
        yang_ni_pr_sr_nh.create_path('config/next-hop', next_hop)

        str_data = yang_ni_pr.print_mem('json')
        LOGGER.warning('[compose] str_data = {:s}'.format(str(str_data)))
        json_data = json.loads(str_data)
        json_data = json_data['openconfig-network-instance:protocol'][0]
        str_data = json.dumps(json_data)
        return str_path, str_data

    def parse(self, json_data : Dict) -> List[Tuple[str, Dict[str, Any]]]:
    def parse(
        self, json_data : Dict, yang_handler : YangHandler
    ) -> List[Tuple[str, Dict[str, Any]]]:
        LOGGER.warning('[parse] json_data = {:s}'.format(str(json_data)))
        response = []
        return response
Loading