Developer

 View Only
last person joined: 4 hours ago 

Expand all | Collapse all

v10.13 pycxaos, EVPN and package completeness

This thread has been viewed 28 times
  • 1.  v10.13 pycxaos, EVPN and package completeness

    Posted Mar 07, 2024 06:32 AM

    Hi all,

    I'm building a small tool to deploy a vlan, EVPN configuration and VNI configuration under a vxlan interface. I'm running pyaoscx 2.5.1 but I have noticed that it still only supports versions 10.04, 10.07 and 10.09. It was last updated 4 months ago, but not much was changed according to Github.

    I can't find any EVPN specific code in the package and this leaves me wondering if this package is still being actively maintained to any meaningful degree.

    I use AFC with one of my customers and there one can easily use AFC to deploy a full EVPN BGP VXLAN network. I'm assuming that AFC doesn't use pyaoscx as it looks incomplete to me, but I'm happy to be proven otherwise.

    Does anyone here have their own code using pyaoscx to create EVPN VNIs and VXLAN interfaces?

    Cheers,

    C



  • 2.  RE: v10.13 pycxaos, EVPN and package completeness

    Posted Mar 08, 2024 01:40 AM

    Hi, I'm using NetBox as SoT and Ansible for configuration. I don't use pyaoscx directly.



    ------------------------------
    Arne Opdal
    ------------------------------



  • 3.  RE: v10.13 pycxaos, EVPN and package completeness

    Posted Mar 13, 2024 05:13 PM

    Hei Arne,

    Have you created EVPN specific configuration with Ansible? If so, did you write your own code?

    Cheers,

    C




  • 4.  RE: v10.13 pycxaos, EVPN and package completeness

    Posted Mar 15, 2024 04:08 AM

    Hi,

    I have more than one workflow which configures devices, and inventory is from NetBox.

    So for getting the devices I use netbox inventory plugin.

    1 - Creating "complete" configuration

    Here I use Ansible URI to retrieve needed information and use Jinja templates to generate the config.

    So the automation is like this:

    I use DHCP and TFTP for ZTP to get a correct firmware and a base config into the device

    syslog sendt to StackStorm when base config is downloaded

    StackStorm extract IP for syslog message

    StackStorm start workflow for updating ZTP server - generate config files and copy them to TFTP server

    Stackstorm start playbook for deploy config - Get serial number from new device, lookup in NetBox which device, copy config from TFTP to running, save config , reboot

    And the device is ready to be mounted on site.

    And a bit modified way is used when DC deployment is used - there its possible to use MGMT address and MAC to give the device the correct IP from DHCP.

    2 - Change config 

    Here I use arubanetworks.aoscx.aoscx_config for EVPN, VNI and the VXLAN interface

    So my code is just playbooks, templates  and Some StackStorm packs.



    ------------------------------
    Arne Opdal
    ------------------------------



  • 5.  RE: v10.13 pycxaos, EVPN and package completeness

    MVP GURU
    Posted Mar 11, 2024 08:46 AM

    it is only 10.04, 10.07 and 10.09 of API versions, (10.13 always support this API release...)

    but yes, missing some dev and feature on pyaoscx (and ansible collections...)



    ------------------------------
    PowerArubaSW : Powershell Module to use Aruba Switch API for Vlan, VlanPorts, LACP, LLDP...

    PowerArubaCP: Powershell Module to use ClearPass API (create NAD, Guest...)

    PowerArubaCL: Powershell Module to use Aruba Central

    PowerArubaCX: Powershell Module to use ArubaCX API (get interface/vlan/ports info)..

    ACEP / ACMX #107 / ACDX #1281
    ------------------------------



  • 6.  RE: v10.13 pycxaos, EVPN and package completeness

    Posted Mar 12, 2024 03:46 PM

    Thank you, alagoutte.

    Do you know which endpoint one would use to create an interface vxlan 1 and its VNI configurations. Looking at the POST /system/interfaces docs, one can send an options attribute with a 

    "tunnel_source_intf"

    which looks promising, but I can't find what to send to create the VNI configuration under the vxlan interface configuration. The goal is to produce the following configuration from one or more calls to the switch's API.

    interface vxlan 1 
        source ip 10.47.27.208
        no shutdown
        vni 5
            vlan 5

    Would you or anyone else reading this know which endpoint to use?

    Cheers,

    C




  • 7.  RE: v10.13 pycxaos, EVPN and package completeness

    MVP GURU
    Posted Mar 13, 2024 09:23 AM

    Hi Conor,

    You can look this playbook from this repo https://github.com/aruba/aoscx-ansible-dcn-workflows/blob/master/tasks/aoscx/vxlan.yml

    it is using directly API call for add vxlan interface and vni (but it is using old v1 API and no longer supported, there is for example not longer system/port API call it is directly on system/interfaces)



    ------------------------------
    PowerArubaSW : Powershell Module to use Aruba Switch API for Vlan, VlanPorts, LACP, LLDP...

    PowerArubaCP: Powershell Module to use ClearPass API (create NAD, Guest...)

    PowerArubaCL: Powershell Module to use Aruba Central

    PowerArubaCX: Powershell Module to use ArubaCX API (get interface/vlan/ports info)..

    ACEP / ACMX #107 / ACDX #1281
    ------------------------------



  • 8.  RE: v10.13 pycxaos, EVPN and package completeness

    Posted Mar 13, 2024 11:44 AM

    Thanks for that, that's put me on the right path. I've gotten it up and running. Looks like I hadn't actually done the EVI side of things after all, I'll need to look into that. But for the time being, this code will create a VLAN and an existing interface vxlan 1's VNI with the same ID as the VLAN if anyone is interested.

    from typing import Dict
    from pyaoscx.session import Session
    from pyaoscx.interface import Interface
    from pyaoscx.vni import Vni
    from pyaoscx.vlan import Vlan
    
    
    version = '10.09'
    switch_ip = '1.1.1.1'
    
    evi = {
        "export_route_targets": [
            "both"
        ],
        "import_route_targets": [
            "both"
        ],
        "rd": "auto",
        "redistribute": {
            "host-route": True
        },
        "vlan": 998
    }
    
    
    def main():
        # TODO: catch exceptions and logout of session
        # TODO: add logging
        session = Session(switch_ip, version)
        session.open(username='jellybean', password='yum-yumyumyum')
    
        vlan_id = 998
        vlan_name = "bob"
    
        vlans = Vlan.get_all(session)
        print(vlans.keys())
    
        # confirm vlan exists, else create it
        if check_if_vlan_exists(vlans, 998):
            vlan = vlans[vlan_id]
        else:
            vlan = Vlan(session, vlan_id, name=vlan_name)
            vlan.create()
    
        # check that vlan name matches our desired name
        # TODO: api VLANS from Vlan.get() have a name attribute
        # TODO: but a a None value even though switch VLANs have a name
        # if vlan.name != vlan_name:
        #     vlan.name = vlan_name
        #     vlan.apply()
    
        # get interface vxlan 1
        # TODO: check if interface exists, else create it
        interface = Interface(session, 'vxlan1')
        interface.get()
    
        # create vni
        # TODO: check if vni exists, else create it
        vni = {
            "vlan": vlan,
            "type": "vxlan_vni",
        }
        vni_id = vlan_id
        vni_string_id = f"vxlan_vni,{str(vni_id)}"
    
        all_vnis = Vni.get_all(session, interface)
        if check_if_vni_exists(all_vnis, vni_string_id):
            vni = all_vnis[vni_string_id]
        else:
            vni = Vni(session, 998, interface, **vni)
            vni.create()
    
        if check_if_vni_exists(vni.get_all(session, interface), vni_string_id):
            print("VNI exists")
        else:
            print("VNI does not exist")
        session.close()
    
    
    def check_if_vlan_exists(vlans: Dict, vlan_id: int):
        return key_attr_check(vlans, vlan_id)
    
    
    def check_if_vni_exists(vnis: Dict, vni_id: str):
        return key_attr_check(vnis, vni_id)
    
    
    def key_attr_check(obj: Dict, key) -> bool:
        attr = obj.get(key, None)
        if attr is not None:
            return True
        return False
    
    
    if __name__ == "__main__":
        main()
    

    And here you can see the expected output from the switch




  • 9.  RE: v10.13 pycxaos, EVPN and package completeness

    Posted Mar 13, 2024 03:34 PM

    Hi @flatline! Thank you for your interest in our pyaoscx package! I can assure you this is something we're actively developing and improving! Internally we're continuously working on bug improvements and feature requests provided by users. I'm glad you were able to find a solution, is this using version 2.0.0+ of the python package? It seems so but I just wanted to verify. In regards to Ansible support for VNIs/VXLAN we have planned development for these features to be included but no estimation of delivery as of today as we're tackling other requests. 



    ------------------------------
    Ti Chiapuzio-Wong (they/them)
    HPE Aruba Networking
    ------------------------------



  • 10.  RE: v10.13 pycxaos, EVPN and package completeness

    Posted Mar 13, 2024 04:30 PM

    Hi Tiffany,

    Thank you for the answer, it is much appreciated. Yes, I'm definitely using v2, specifically 2.5.1. From what I can see, there is no mention of EVPN in the package, but excited to here that it might be on the agenda at some point. I'm not using Ansible but it is something that I should look into as I know little about it. Fun fact, the first time I ever used Ansible was at TSS in Paris at a lab that you were leading. I said to you then that I should look into Ansible and now I'm repeating myself, probably 7 - 9 years later!

    If anyone else is looking to create EVPN configuration such as this

    evnpn

        vlan 998
            rd auto
            route-target export auto
            route-target import auto

    I have hacked/cut and pasted together an EvpnVlan class which inherits from pyaoscx's PyaoscxModule. To use the class, do this:

    # I stuck the EvpnVlan class in a file called file called evpn.py in a folder
    # named aruba_cxos_tools in my srcs root.
    # You can put it wherever you like
    from aruba_cxos_tools.evpn import EvpnVlan
    
    def create_evpn_vni(vlan_id: int):
        version = '10.09'
        switch_ip = '1.1.1.1'    
        session = Session(switch_ip, version)
        session.open(username='hello', password='hellohello')
        vlan = Vlan(session, vlan_id)
        vlan.get()
    
        # you must pass the VLAN's URI to the EvpnVlan object, VLAN object
        # or ID will not work.
        evpn_vlan = EvpnVlan(session, vlan.get_uri())
        evpn_vlan.create()

    It does the bare minimum, but It will set import, export and RD to auto. Look at the below code if you want to change that. If I get considerably more useful and robust, I'll push to my github and paste the repo here, but if I'm honest, that's a long shot.

    from pyaoscx.pyaoscx_module import PyaoscxModule
    
    
    class EvpnVlan(PyaoscxModule):
    
        base_uri = "system/evpn/evpn_vlans"
        resource_uri_name = "vlans"
        indices = ["id"]
    
        def __init__(
                self, session, vlan_id,  uri=None, **kwargs
        ):
            self.session = session
            self._uri = None
            self.evpn_vlans = {}
            self.export_route_targets = ["auto"]
            self.import_route_targets = ["auto"]
            self.rd = "auto"
            self.redistribute = {"host-route": True}
            self.vlan = vlan_id
            self.arp_suppression_enabled = None
            self.dyn_vxlan_tunnel_bridging_mode = "no-bridging"
            self.nd_suppression_enabled = True
            self.redistribute = {}
    
            # List used to determine attributes related to the VLAN configuration
            self.config_attrs = []
            self.materialized = False
            # Attribute dictionary used to manage the original data
            # obtained from the GET
            self._original_attributes = {}
            # utils.set_creation_attrs(self, **kwargs)
            # Use to manage MACs
            self.macs = []
            # Use to manage Static MACs
            self.static_macs = []
            # Attribute used to know if object was changed recently
            self.__modified = False
    
        def create(self):
            payload = {
                "vlan": self.vlan,
                "export_route_targets": self.export_route_targets,
                "import_route_targets": self.import_route_targets,
                "redistribute": self.redistribute,
                "rd": self.rd,
            }
            self._post_data(payload)
    
        def _post_data(self, data):
            """
            Perform a POST request to the switch.
    
            :param data: data to send.
            """
            self._send_data(self.base_uri, data, "POST", "Adding")
            # Get the data from the created object
            self.get()
            return True
    
        @PyaoscxModule.connected
        def get(self, depth=None, selector=None):
            pass
    
        @classmethod
        def get_all(cls, session):
            pass
    
        @PyaoscxModule.connected
        def apply(self):
            pass
    
        @PyaoscxModule.connected
        def update(self):
            pass
    
        @PyaoscxModule.connected
        def delete(self):
            pass
    
        @classmethod
        def from_response(cls, session, response_data):
            pass
    
        @classmethod
        def from_uri(cls, session, uri):
            pass
    

    Cheers,

    C