cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
3063
Views
0
Helpful
15
Replies

YDK wrapper fro YAML

horseinthesky
Level 1
Level 1

Hello.
I'm trying to implement this solution to be able to describe YANG models in YAML and build appropriate models using YDK modules.
But I'm kind of stuck. Here is what I'm testing right now:

from ydk.services import CRUDService, CodecService
from ydk.providers import NetconfServiceProvider, CodecServiceProvider
from ydk.types import Empty
from ydk.models.cisco_ios_xe.Cisco_IOS_XE_native import Native
from ydk.filters import YFilter
import yaml
import logging

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)


def instantiate(binding, model_key, model_value, action='assign'):
    if isinstance(model_value, str) and model_value.lower() == 'empty':
        if action == 'return':
            return Empty()
        elif action == 'assign':
            setattr(binding, model_key, Empty())
    elif any(isinstance(model_value, x) for x in [str, bool, int]):
        if action == 'return':
            return model_value
        elif action == 'assign':
            setattr(binding, model_key, model_value)
    elif isinstance(model_value, list):
        list_obj = getattr(binding, model_key.lower())

        for el in model_value:
            list_obj.append(instantiate(binding, model_key, el, action='return'))
    elif isinstance(model_value, dict):
        # special case handling enum type
        if all([x is None for x in model_value.values()]):
            enum_name = ''.join([x.capitalize() for x in model_key.split('_')]) + 'Enum'
            enum_class = getattr(binding, enum_name)

            for el in model_value.keys():
                enum = getattr(enum_class, el)

                if action == 'return':
                    return enum
                elif action == 'assign':
                    setattr(binding, model_key, enum)
        else:
            container = getattr(binding, model_key, None)
            if container and not isinstance(container, list):
                container_instance = container
            elif container.__class__.__name__ == 'YLeafList':
                container_instance = container
            else:
                model_key_camelized = ''.join([x.capitalize() for x in model_key.split('_')])
                container_instance = getattr(binding, model_key_camelized)()

            for k, v in model_value.items():
                instantiate(container_instance, k, v, action='assign')

            if action == 'return':
                return container_instance
            elif action == 'assign':
                setattr(binding, model_key, container_instance)
    else:
        raise ValueError('Unexpected YAML value: {} of type {}'.format(model_value, type(model_value)))


if __name__ == '__main__':
    with open('interfaces2.yml') as f:
        config = yaml.load(f)['config']

    for model_name, model_data in config.items():
        for k, v in model_data.items():
            binding = globals().get(model_name.capitalize())()
            instantiate(binding, k, v)

    # codec = CodecService()
    # provider = CodecServiceProvider(type='xml')
    # print(codec.encode(provider, native))
    provider = NetconfServiceProvider(
        address='10.10.30.6',
        port=830,
        username='admin',
        password='admin',
        protocol='ssh'
    )
    crud = CRUDService()
    crud.create(provider, binding)

And config file is:

config:
  native:
    interface:
      gigabitethernet:
        - name: "2"
          description: Configured via ydk
          ip:
            address:
              primary:
                address: 172.16.2.0
                mask: 255.255.255.254
              secondary:
                - address: 192.168.20.1
                  mask: 255.255.255.254
secondary: - address: 192.168.20.3 mask: 255.255.255.254
secondary: - name: "3" description: Configured via ydk ip: address: primary: address: 172.16.3.0 mask: 255.255.255.254 - name: "4" description: Configured via ydk ip: address: primary: address: 172.16.4.0 mask: 255.255.255.254 loopback: - name: 0 description: ROUTER ID ip: address: primary: address: 1.1.1.6 mask: 255.255.255.255


The problem is that Interface class has camel case namings for classes of particular interface type, GigabitEthernet for instance. This is why I've got:

python3 xe_intf_test2.py
Traceback (most recent call last):
  File "xe_intf_test2.py", line 75, in <module>
    instantiate(binding, k, v)
  File "xe_intf_test2.py", line 58, in instantiate
    instantiate(container_instance, k, v, action='assign')
  File "xe_intf_test2.py", line 33, in instantiate
    list_obj.append(instantiate(binding, model_key, el, action='return'))
  File "xe_intf_test2.py", line 55, in instantiate
    container_instance = getattr(binding, model_key_camelized)()
AttributeError: 'Interface' object has no attribute 'Gigabitethernet'

Do you have any idea or even implementation of this?

15 Replies 15

The answer is in the RFC:

 

https://tools.ietf.org/html/rfc7951

 

section 6.9 (about empty type)