cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
1692
Views
0
Helpful
1
Comments
Andrew Melsom
Level 1
Level 1

Hi All

 

I am new to developing as you will see from my code :P, I am a network engineer trying to learn Devops, and I am struggling a bit with create services that apply configs to multiple devices.

I am trying to create my own code to create a l3vpn service and when I run it I get an error from the python code, I will post the code and error and if anyone can help in pointing me to the correct way, I would be most grateful.

 

Yang

module l3vpnpy {

  namespace "http://example.com/l3vpnpy";
  prefix l3vpnpy;

  import ietf-inet-types {
    prefix inet;
  }
  import tailf-common {
    prefix tailf;
  }
  import tailf-ncs {
    prefix ncs;
  }

  augment /ncs:services {
  list l3vpnpy {
    key customername;

    uses ncs:service-data;
    ncs:servicepoint l3vpnpy-servicepoint;

    leaf customername {
      type string;
    }

    leaf customerdescription {
      type string;
    }

    leaf rd {
      type string;
    }

    leaf-list rtexport {
      type string;
    }

    leaf-list rtimport {
      type string;
    }

    leaf prefixlimit {
      type uint16;
    }

    leaf vlan {
      type uint16;
    }

    leaf ipv4address {
      type string;
    }

    leaf warningpercent {
      type uint16;
    }

    list devices {
      key device;

      leaf device {
        type leafref {
          path "/ncs:devices/ncs:device/ncs:name";
        }
      }

      leaf ipv4address {
        type string;
      }
    } 
  }
  }
}

XML

<config-template xmlns="http://tail-f.com/ns/config/1.0">
  <devices xmlns="http://tail-f.com/ns/ncs">
    <device>
      <name>{/devices/device}</name>
        <config>        
          <vrf xmlns="urn:ios">
            <definition>
              <name>{/customername}</name>
              <description>{/customerdescription}</description>
              <rd>{/rd}</rd>
              <address-family>
                <ipv4>
                  <route-target>
                    <export>
                      <asn-ip>{/rtexport}</asn-ip>
                    </export>
                    <import>
                      <asn-ip>{/rtimport}</asn-ip>
                    </import>
                  </route-target>
                  <maximum>
                    <routes>
                      <limit>{/prefixlimit}</limit>
                      <warn-threshold>{/warningpercent}</warn-threshold>
                    </routes>
                  </maximum>
                </ipv4>
              </address-family>
            </definition>
          </vrf>       
          <interface xmlns="urn:ios">   
            <GigabitEthernet>
              <name>2.{/vlan}</name>
              <description>{/customerdescriptopn}</description>
              <encapsulation>
                <dot1Q>
                  <vlan-id>{/vlan}</vlan-id>
                </dot1Q>
              </encapsulation>
              <vrf>
                <forwarding>{/customername}</forwarding>
              </vrf>
              <ip>
                <address>
                  <primary>
                    <address>{/devices/ipv4address}</address>
                    <mask>255.255.255.0</mask>
                  </primary>
                </address>
                <ospf>
                  <process-id>
                    <id>1</id>
                    <area>0</area>
                  </process-id>
                </ospf>
              </ip>
            </GigabitEthernet>
          </interface>
          <router xmlns="urn:ios">
            <bgp>
              <as-no>65000</as-no>
              <address-family>
                <with-vrf>
                  <ipv4>
                    <af>unicast</af>
                    <vrf>
                      <name>{/customername}</name>
                      <redistribute>
                        <ospf>
                          <id>{/vlan}</id>
                        </ospf>
                      </redistribute>
                    </vrf>
                  </ipv4>
                </with-vrf>
              </address-family> 
            </bgp>
            <ospf>
              <id>{/vlan}</id>
              <vrf>{/customername}</vrf>
              <redistribute>
                <bgp>
                  <as-no>65000</as-no>
                </bgp>
              </redistribute>
            </ospf>
          </router>
        </config>
    </device>
  </devices>
</config-template>

Python

# -*- mode: python; python-indent: 4 -*-
import ncs
from ncs.application import Service


# ------------------------
# SERVICE CALLBACK EXAMPLE
# ------------------------
class ServiceCallbacks(Service):

    # The create() callback is invoked inside NCS FASTMAP and
    # must always exist.
    @Service.create
    def cb_create(self, tctx, root, service, proplist):
        self.log.info('Service create(service=', service._path, ')')
    
        vars = ncs.template.Variables()
        for dev in service.devices:
            device = root.devices.device[service.devices.device]
            self.log.info('device: ', device.name)

        template = ncs.template.Template(service)
        template.apply('l3vpnpy-template', vars)

    # The pre_modification() and post_modification() callbacks are optional,
    # and are invoked outside FASTMAP. pre_modification() is invoked before
    # create, update, or delete of the service, as indicated by the enum
    # ncs_service_operation op parameter. Conversely
    # post_modification() is invoked after create, update, or delete
    # of the service. These functions can be useful e.g. for
    # allocations that should be stored and existing also when the
    # service instance is removed.

    # @Service.pre_lock_create
    # def cb_pre_lock_create(self, tctx, root, service, proplist):
    #     self.log.info('Service plcreate(service=', service._path, ')')

    # @Service.pre_modification
    # def cb_pre_modification(self, tctx, op, kp, root, proplist):
    #     self.log.info('Service premod(service=', kp, ')')

    # @Service.post_modification
    # def cb_post_modification(self, tctx, op, kp, root, proplist):
    #     self.log.info('Service premod(service=', kp, ')')


# ---------------------------------------------
# COMPONENT THREAD THAT WILL BE STARTED BY NCS.
# ---------------------------------------------
class Main(ncs.application.Application):
    def setup(self):
        # The application class sets up logging for us. It is accessible
        # through 'self.log' and is a ncs.log.Log instance.
        self.log.info('Main RUNNING')

        # Service callbacks require a registration for a 'service point',
        # as specified in the corresponding data model.
        #
        self.register_service('l3vpnpy-servicepoint', ServiceCallbacks)

        # If we registered any callback(s) above, the Application class
        # took care of creating a daemon (related to the service/action point).

        # When this setup method is finished, all registrations are
        # considered done and the application is 'started'.

    def teardown(self):
        # When the application is finished (which would happen if NCS went
        # down, packages were reloaded or some error occurred) this teardown
        # method will be called.

        self.log.info('Main FINISHED')

Thanks to anyone that has time to have a flick through.

 

Andy

1 Comment
yfherzog
Cisco Employee
Cisco Employee

Don't see the error, but you're looping service.devices and then inside the loop accessing service.devices.device.

Instead, you should access the loop variable - dev.device.

 

Getting Started

Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the NSO Developer community: