Commit 3477a539 authored by Pablo Armingol's avatar Pablo Armingol
Browse files

Changes to manage inventory and device interfaces

parent 48269f02
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -38,6 +38,9 @@ def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]:
        #add_value_from_tag(interface, 'type', interface_type)

        interface_type = xml_interface.find('oci:config/oci:type', namespaces=NAMESPACES)
        if interface_type is None:
            interface_type = xml_interface.find('oci:state/oci:type', namespaces=NAMESPACES)         
        if interface_type is None: continue
        interface_type.text = interface_type.text.replace('ianaift:','')
        add_value_from_tag(interface, 'type', interface_type)

+100 −0
Original line number Diff line number Diff line
# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


"""
#Method Name: parse

#Parameters:
    
    - xml_data: [ET.Element] Represents the XML data to be parsed.

# Functionality:

The parse function of the interfaces_mng class has the functionality to parse
an XML document represented by the xml_data parameter and extract specific 
information from the XML elements, namely the active interfaces with their name, 
type, ipv4 and ipv6 addresses in case they have.

To generate the template the following steps are performed:

1) An empty list called response is created to store the results of the analysis.

2) Iterate over the XML elements that match the pattern specified by the XPATH_PORTS 
expression. These elements represent management interfaces in the XML document.

3) For each  management interfaces:
A dictionary called interfaces_mng is initialized that will store the information extracted 
from the interfaces.The values of the relevant XML elements are extracted and added to
the dictionary.

#Return: 
List[Tuple[str, Dict[str, Any]]] The response list containing the tuples (path, dictionary) 
with the information extracted from the XML document interfaces is returned.

"""


import logging, lxml.etree as ET
from typing import Any, Dict, List, Tuple
from .Namespace import NAMESPACES
from .Tools import add_value_from_tag

LOGGER = logging.getLogger(__name__)

XPATH_PORTS = "//oci:interfaces/oci:interface"
XPATH_SUBINTERFACES = ".//oci:subinterfaces/oci:subinterface"
XPATH_IPV4ADDRESSES = ".//ociip:ipv4/ociip:addresses/ociip:address"
XPATH_IPV6ADDRESSES = ".//ociip:ipv6/ociip:addresses/ociip:address"

def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]:
    response = []
    LOGGER.debug("Interfaces_mngPrueba")
    
    for xml_interface_mng in xml_data.xpath(XPATH_PORTS, namespaces=NAMESPACES):
        LOGGER.info('xml_component xml_interfaces_mng = {:s}'.format(str(ET.tostring(xml_interface_mng))))
        interfaces_mng = {}
        
        interface_enabled = xml_interface_mng.find('oci:config/oci:enabled', namespaces=NAMESPACES)
        if interface_enabled == None:
            interface_enabled = xml_interface_mng.find('oci:state/oci:enabled', namespaces=NAMESPACES)
        if interface_enabled == None: continue
        if 'false' in interface_enabled or 'false' in interface_enabled.text: continue

        interface_name = xml_interface_mng.find('oci:name', namespaces=NAMESPACES)
        if interface_name is None or interface_name.text is None: continue
        add_value_from_tag(interfaces_mng, 'name', interface_name)
              
        interface_type = xml_interface_mng.find('oci:config/oci:type', namespaces=NAMESPACES)
        if interface_type is None:
            interface_type = xml_interface_mng.find('oci:state/oci:type', namespaces=NAMESPACES)         
        if interface_type is None: continue
        interface_type.text = interface_type.text.replace('ianaift:','')
        add_value_from_tag(interfaces_mng, 'type', interface_type)
        
        for xml_subinterface in xml_interface_mng.xpath(XPATH_SUBINTERFACES, namespaces=NAMESPACES):
            for xml_ipv4_address in xml_subinterface.xpath(XPATH_IPV4ADDRESSES, namespaces=NAMESPACES):
                address_ipv4 = xml_ipv4_address.find('ociip:state/ociip:ip', namespaces=NAMESPACES)
                if not address_ipv4 is None:
                    add_value_from_tag(interfaces_mng, 'ipv4', address_ipv4)

            for xml_ipv6_address in xml_subinterface.xpath(XPATH_IPV6ADDRESSES, namespaces=NAMESPACES):
                address_ipv6 = xml_ipv6_address.find('ociip:state/ociip:ip', namespaces=NAMESPACES)
                if not address_ipv6 is None:
                    add_value_from_tag(interfaces_mng, 'ipv6', address_ipv6)
        if not 'ipv4' in interfaces_mng and not 'ipv6' in interfaces_mng: 
            if 'ip' in interfaces_mng['type'] or 'Loopback' in interfaces_mng['type']: continue
        response.append(('/interfaces_mng/{:s}'.format(interfaces_mng['name']), interfaces_mng))
                
    return response
+140 −40
Original line number Diff line number Diff line
@@ -12,6 +12,40 @@
# See the License for the specific language governing permissions and
# limitations under the License.


"""
#Method Name: parse

#Parameters:
    
    - xml_data: [ET.Element] Represents the XML data to be parsed.

# Functionality:

The parse function of the inventerio class has the functionality to parse
an XML document represented by the xml_data parameter and extract specific 
information from the XML elements, namely the relevant characteristics of the 
components.     

To generate the template the following steps are performed:

1) An empty list called response is created to store the results of the analysis.

2) Iterate over the XML elements that match the pattern specified by the XPATH_PORTS 
expression. These elements represent components in the XML document.

3) For each component element:
A dictionary called inventory is initialized that will store the information extracted 
from the component.The values of the relevant XML elements are extracted and added to
the dictionary.

#Return: 
List[Tuple[str, Dict[str, Any]]] The response list containing the tuples (path, dictionary) 
with the information extracted from the XML document components is returned.

"""


import logging, lxml.etree as ET
from typing import Any, Dict, List, Tuple
from .Namespace import NAMESPACES
@@ -23,64 +57,130 @@ XPATH_PORTS = "//ocp:components/ocp:component"

def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]:
    response = []
    LOGGER.info("InventoryPrueba")

    LOGGER.debug("InventoryPrueba")
    parent_types = {}
    for xml_component in xml_data.xpath(XPATH_PORTS, namespaces=NAMESPACES):
        #LOGGER.info('xml_component = {:s}'.format(str(ET.tostring(xml_component))))
        LOGGER.info('xml_component inventario = {:s}'.format(str(ET.tostring(xml_component))))
        inventory = {}
        inventory['parent-component-references'] = ''
        inventory['uuid'] = ''
        inventory['name'] = ''    
        inventory['type'] = ''
        inventory['datos'] = {}   
        inventory['class'] = ''
        inventory['attributes'] = {}
        component_reference = []

        component_name = xml_component.find('ocp:name', namespaces=NAMESPACES)
        if component_name is None or component_name.text is None: continue
        add_value_from_tag(inventory, 'uuid', component_name)
        add_value_from_tag(inventory, 'name', component_name)        

        component_description = xml_component.find('ocp:state/ocp:description', namespaces=NAMESPACES)
        if not component_description is None:
            add_value_from_tag(inventory['attributes'], 'description', component_description)
        #Podría estar presente en lugar del name
        component_alias = xml_component.find('ocp:state/ocp:alias', namespaces=NAMESPACES)
        if not component_alias is None:
            add_value_from_tag(inventory['attributes'], 'alias', component_alias)
        
        component_location = xml_component.find('ocp:state/ocp:location', namespaces=NAMESPACES)
        if not component_location is None:
            add_value_from_tag(inventory['attributes'], 'location', component_location)
        
        component_type = xml_component.find('ocp:state/ocp:type', namespaces=NAMESPACES)
        component_type.text = component_type.text.replace('oc-platform-types:','')
        if component_type is None: continue
        add_value_from_tag(inventory, 'type', component_type)
        add_value_from_tag(inventory, 'class', component_type)
        if inventory['class'] == 'CPU' or inventory['class'] == 'STORAGE': continue

        component_empty = xml_component.find('ocp:state/ocp:empty', namespaces=NAMESPACES)
        if not component_empty is None:
            add_value_from_tag(inventory['attributes'], 'contained-child', component_empty)

        #añadir el parent pos

        component_parent = xml_component.find('ocp:state/ocp:parent', namespaces=NAMESPACES)
        if component_parent is None or component_parent.text is None:
            add_value_from_tag(inventory, 'parent-component-references', component_type)
        else:
            add_value_from_tag(inventory, 'parent-component-references', component_parent)

        component_HW = xml_component.find('ocp:state/ocp:hardware-version', namespaces=NAMESPACES)
        if not component_HW is None:
            add_value_from_tag(inventory['attributes'], 'hardware-rev', component_HW)

        component_firmware_version = xml_component.find('ocp:state/ocp:firmware-version', namespaces=NAMESPACES)
        if not component_firmware_version is None:
            add_value_from_tag(inventory['attributes'], 'firmware-rev', component_firmware_version)

        component_SW = xml_component.find('ocp:state/ocp:software-version', namespaces=NAMESPACES)
        if not component_SW is None:
            add_value_from_tag(inventory['attributes'], 'software-rev', component_SW)

        component_serial = xml_component.find('ocp:state/ocp:serial-no', namespaces=NAMESPACES)
        if not component_serial is None:
            add_value_from_tag(inventory['attributes'], 'serial-num', component_serial)

        component_serial_t = xml_component.find('ocptr:transceiver/ocptr:state/ocptr:serial-no', namespaces=NAMESPACES)
        if not component_serial_t is None:
            add_value_from_tag(inventory['attributes'], 'serial-num', component_serial_t)

        component_mfg_name = xml_component.find('ocp:state/ocp:mfg-name', namespaces=NAMESPACES)
        if not component_mfg_name is None:
            add_value_from_tag(inventory['attributes'], 'mfg-name', component_mfg_name)

        component_part_no = xml_component.find('ocp:state/ocp:part-no', namespaces=NAMESPACES)
        if not component_part_no is None:
            add_value_from_tag(inventory['attributes'], 'part-number', component_part_no)

        #modificar es un identificador de seguimiento de activos asignado por el usuario para el componente
        component_asset_id = xml_component.find('ocp:state/ocp:asset-id', namespaces=NAMESPACES)
        if not component_asset_id is None:
            add_value_from_tag(inventory['attributes'], 'asset-id', component_asset_id)
        
        component_removable = xml_component.find('ocp:state/ocp:removable', namespaces=NAMESPACES)
        if not component_removable is None:
            add_value_from_tag(inventory['attributes'], 'is-fru', component_removable)

        component_mfg_date = xml_component.find('ocp:state/ocp:mfg-date', namespaces=NAMESPACES)
        if not component_mfg_date is None:
            add_value_from_tag(inventory['attributes'], 'mfg-date', component_mfg_date)

        #modificar "Este nodo contiene información de identificación sobre el componente"
        component_uri = xml_component.find('ocp:state/ocp:uri', namespaces=NAMESPACES)
        if not component_uri is None:
            add_value_from_tag(inventory['attributes'], 'uri', component_uri)

        #Para transceiver
        component_present = xml_component.find('ocptr:transceiver/ocptr:state/ocptr:present', namespaces=NAMESPACES)
        if not component_present is None:
            add_value_from_tag(inventory['datos'], 'present', component_present)
            if 'present' in inventory['datos'] and inventory['datos']['present'] == 'NOT_PRESENT': continue
        if component_present is not None and 'NOT_PRESENT' in component_present.text: continue
        
        component_vendor = xml_component.find('ocptr:transceiver/ocptr:state/ocptr:vendor', namespaces=NAMESPACES)
        if not component_vendor is None:
            add_value_from_tag(inventory['datos'], 'vendor', component_vendor)
            add_value_from_tag(inventory['attributes'], 'vendor', component_vendor)
        component_connector = xml_component.find('ocptr:transceiver/ocptr:state/ocptr:connector-type', namespaces=NAMESPACES)
        if not component_connector is None:
            component_connector.text = component_connector.text.replace('oc-opt-types:','')
            add_value_from_tag(inventory['datos'], 'connector-type', component_connector)
        component_serial = xml_component.find('ocptr:transceiver/ocptr:state/ocptr:serial-no', namespaces=NAMESPACES)
        if not component_serial is None:
            add_value_from_tag(inventory['datos'], 'serial-no', component_serial)
            add_value_from_tag(inventory['attributes'], 'connector-type', component_connector)
        
        component_form = xml_component.find('ocptr:transceiver/ocptr:state/ocptr:form-factor', namespaces=NAMESPACES)
        if not component_form is None:
            component_form.text = component_form.text.replace('oc-platform-types:','')
            add_value_from_tag(inventory['datos'], 'form-factor', component_form)
        component_parent = xml_component.find('ocp:state/ocp:parent', namespaces=NAMESPACES)
            component_form.text = component_form.text.replace('oc-opt-types:','')
            add_value_from_tag(inventory['attributes'], 'form-factor', component_form)
        #añadir características del parent references
        if inventory['parent-component-references'] not in parent_types:
            parent_types[inventory['parent-component-references']] = len(parent_types) + 1

        component_HW = xml_component.find('ocp:state/ocp:hardware-version', namespaces=NAMESPACES)
        if not component_HW is None:
            add_value_from_tag(inventory['datos'], 'hardware-version', component_HW)
        component_SW = xml_component.find('ocp:state/ocp:software-version', namespaces=NAMESPACES)
        if not component_SW is None:
            add_value_from_tag(inventory['datos'], 'software-version', component_SW)
        component_serial = xml_component.find('ocp:state/ocp:serial-no', namespaces=NAMESPACES)
        if not component_serial is None:
            add_value_from_tag(inventory['datos'], 'serial-no', component_serial)
        component_oper_status = xml_component.find('ocp:state/ocp:oper-status', namespaces=NAMESPACES)
        if not component_oper_status is None and inventory['type'] != 'CHASSIS' and inventory['type'] != 'CPU':
            component_oper_status.text = component_oper_status.text.replace('oc-platform-types:','')
            add_value_from_tag(inventory['datos'], 'oper-status', component_oper_status)
        component_parent = xml_component.find('ocp:state/ocp:parent', namespaces=NAMESPACES)
        if not component_parent is None and inventory['type'] != 'CHASSIS':
            add_value_from_tag(inventory['datos'], 'parent', component_parent)
        component_reference.extend([parent_types[inventory['parent-component-references']]])
        
        

        response.append(('/inventory/{:s}'.format(inventory['name']), inventory))

        for tupla in response:
            if inventory['parent-component-references'] in tupla[0]:
                component_reference.extend([tupla[1]['class']])
                component_reference.extend([tupla[1]['uuid']])

        if 'type' not in inventory: inventory['type'] = '-'
        inventory['component-reference'] = component_reference
        
        #LOGGER.info('Inventoty = {:s}'.format(str(inventory)))
        if len(inventory) == 0: continue
        response.append(('/inventory[{:s}]'.format(inventory['name']), inventory))
    return response
 No newline at end of file
+5 −1
Original line number Diff line number Diff line
@@ -16,9 +16,10 @@ import json, logging, lxml.etree as ET, re
from typing import Any, Dict, Optional
from jinja2 import Environment, PackageLoader, select_autoescape
from device.service.driver_api._Driver import (
    RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES, RESOURCE_ROUTING_POLICIES, RESOURCE_ACL, RESOURCE_INVENTORY)
    RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_INTERFACES_MNG,RESOURCE_NETWORK_INSTANCES, RESOURCE_ROUTING_POLICIES, RESOURCE_ACL, RESOURCE_INVENTORY)
from .EndPoints import parse as parse_endpoints
from .Interfaces import parse as parse_interfaces, parse_counters
from .Interfaces_mng import parse as parse_interfaces_mng
from .NetworkInstances import parse as parse_network_instances
from .RoutingPolicy import parse as parse_routing_policy
from .Acl import parse as parse_acl
@@ -28,6 +29,7 @@ ALL_RESOURCE_KEYS = [
    RESOURCE_INVENTORY,
    RESOURCE_ENDPOINTS,
    RESOURCE_INTERFACES,
    RESOURCE_INTERFACES_MNG,
    RESOURCE_ROUTING_POLICIES,      # routing policies should come before network instances
    RESOURCE_NETWORK_INSTANCES,
    RESOURCE_ACL,
@@ -37,6 +39,7 @@ RESOURCE_KEY_MAPPINGS = {
    RESOURCE_INVENTORY        : 'inventory',
    RESOURCE_ENDPOINTS        : 'component',
    RESOURCE_INTERFACES       : 'interface',
    RESOURCE_INTERFACES_MNG    : 'interfaces_mng',
    RESOURCE_NETWORK_INSTANCES: 'network_instance',
    RESOURCE_ROUTING_POLICIES : 'routing_policy',
    RESOURCE_ACL              : 'acl',
@@ -46,6 +49,7 @@ RESOURCE_PARSERS = {
    'inventory'       : parse_inventory,
    'component'       : parse_endpoints,
    'interface'       : parse_interfaces,
    'interfaces_mng'  : parse_interfaces_mng,
    'network_instance': parse_network_instances,
    'routing_policy'  : parse_routing_policy,
    'interfaces/interface/state/counters': parse_counters,
+3 −0
Original line number Diff line number Diff line
<interfaces xmlns="http://openconfig.net/yang/interfaces">
    <interface/>
</interfaces>
 No newline at end of file