CiscoDevNet / ydk-gen

Generate model-driven APIs from YANG models
http://ciscodevnet.github.io/ydk-gen/
Apache License 2.0
137 stars 74 forks source link

EntityCollection Filter doesn't work as expected for IOS-XE when more than 1 entity passed #1040

Closed gusmb closed 3 years ago

gusmb commented 3 years ago

Trying to read Gig1 and NTP configuration from IOS-XE device using the Native model and a read filter, but only the last argument passed to the filter is correctly parsed from the RPC reply

Expected Behavior

Print both GigabitEthernet1 and ntp configurations

Current Behavior

Only the last entity passed to the filter is printed correctly

Steps to Reproduce

Run script against a CSR1000V device

Your Script

import logging
from ydk.types import Filter
from ydk.services import NetconfService, Datastore, CodecService, CRUDService
from ydk.providers import NetconfServiceProvider, CodecServiceProvider
from ydk.models.cisco_ios_xe import Cisco_IOS_XE_native \
    as xe_model
from ydk.models.openconfig import openconfig_interfaces as oc_interfaces

# Enabling logging to see what happens under the hood
logger = logging.getLogger('ydk')
logger.setLevel(logging.INFO)
handler = logging.StreamHandler()
formatter = logging.Formatter(("%(asctime)s - %(name)s - "
                               "%(levelname)s - %(message)s"))
handler.setFormatter(formatter)
logger.addHandler(handler)

provider = NetconfServiceProvider(
        address=device['ip'],
        port=830,
        username=device['username'],
        password=device['pass'],
        protocol='ssh',
    )

xe_native = xe_model.Native()
crud = CRUDService()

interfaces = xe_native.Interface() # Top level Entity
gig1 = interfaces.GigabitEthernet()  # GigabitEthernet1 entity
gig1.name = '1'

interfaces.gigabitethernet.append(gig1)  # Append the interface to the list

ntp = xe_native.Ntp() # Entity for the NTP container

read_filter = Filter()  # The read filter
read_filter.append(ntp)
read_filter.append(interfaces)

# Call the CRUD read-config to get configuration of entities
config = crud.read(provider, read_filter)

codec_service = CodecService()
codec_provider = CodecServiceProvider(type='json')

for entity in config:
    print(codec_service.encode(codec_provider, entity))```

Logs

Enable logging and post the logs below

</native></filter>
</get>
</rpc>
2021-01-04 11:19:45,704 - ydk - INFO - ============= Sending RPC to device =============
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><get xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <filter><native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
  <ntp/>
</native><native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
  <interface>
    <GigabitEthernet>
      <name>1</name>
    </GigabitEthernet>
  </interface>
</native></filter>
</get>
</rpc>
2021-01-04 11:19:45,758 - ydk - INFO - ============= Received RPC from device =============
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="24">
  <data>
    <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
      <ntp>
        <server xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-ntp">
          <server-list>
            <ip-address>192.168.3.44</ip-address>
          </server-list>
        </server>
      </ntp>
    </native>
    <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
      <interface>
        <GigabitEthernet>
          <name>1</name>
          <ip>
            <address>
              <primary>
                <address>10.1.1.100</address>
                <mask>255.255.255.0</mask>
              </primary>
            </address>
          </ip>
          <mop>
            <enabled>false</enabled>
            <sysid>false</sysid>
          </mop>
          <negotiation xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-ethernet">
            <auto>true</auto>
          </negotiation>
        </GigabitEthernet>
      </interface>
    </native>
  </data>
</rpc-reply>

However, in the printed statements, NTP container is not shown, although RPC reply was correct:
{
  "Cisco-IOS-XE-native:ntp": {
  }
}

{
  "Cisco-IOS-XE-native:interface": {
    "GigabitEthernet": [
      {
        "name": "1",
        "ip": {
          "address": {
            "primary": {
              "address": "10.1.1.100",
              "mask": "255.255.255.0"
            }
          }
        },
        "mop": {
          "enabled": false,
          "sysid": false
        },
        "Cisco-IOS-XE-ethernet:negotiation": {
          "auto": true
        }
      }
    ]
  }
}

Tried both JSON and XML codecs, but none of them worked as expected

System Information

Python3.8 Linux Mint Linux 5.4.0-58-generic #64-Ubuntu SMP Wed Dec 9 08:16:25 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux ydk-gen 0.8.5

gusmb commented 3 years ago

Adding the following solves the issue:

ntp.yfilter = YFilter.read, otherwise looks like the RPC Reply was correct but the read operation did not extract the data correctly without the yfilter attribute set