Extension

Extending the Connect module requires the following steps:

  • Reading the MEF standard specification for your desired feature

  • Translating the MEF specification to Inmanta model

  • Extending the LSM

  • Developing plugins

  • Writing unit tests

There are circumstances where you need to introduce additional features to the Connect API which are not part of the MEF standard. For instance, deploying E-Line with either LDP or EVPN. In such cases, we distinctively use the Ext_ prefix for those entities and if required, define custom data types. In other words, by following these steps we update and extend the existing LSM API, and diverge from the MEF standard.

Let’s take L2 MPLS VPN as an example to extend the existing API:

  • Define the required types:

    typedef connectivity_type as string matching self in ["VPWS", "VPLS"]
    """
    L2 connectivity type. VPWS or VPLS.
    """
    
  • Define a new entity, representing the service/technology:

    entity Ext_L2MPLSType extends lsm::EmbeddedEntity:
        """
        The entity represents L2 MPLS VPN technology.
        :attr type: Can be VPWS or VPLS.
        """
        connectivity_type type
    end
    

    Please note that the entity is prefixed with Ext_ and is extending the existing lsm::EmbeddedEntity object. All extensions to the API have to follow the same structure.

    EmbeddedEntity contains attributes that should be embedded into a ServiceEntity or another EmbeddedEntity.

  • Define the implementations (refinement) for the entities:

    implementation with_VPWS for Ext_L2MPLSType:
        """The specific VPWS implementation goes here"""
        std::print("VPWS selected")
    end
    
    implementation with_VPLS for Ext_L2MPLSType:
        """The specific VPLS implementation goes here"""
        std::print("VPLS selected")
    end
    

    In with_VPLS implementation, the attribute types declaration is omitted for brevity; however, the steps are the same as for the with_VPWS example.

  • Implement the refinements:

    implement Ext_L2MPLSType using with_VPWS when self.connectivity_type=="VPWS"
    
    implement Ext_L2MPLSType using with_VPLS when self.connectivity_type=="VPLS"
    

    The implement is used to construct and connect the entities, refinements and their attributes together. when is a compile time if, which gives us control over how the model should be constructed.

Developing Plugins

There are times when you need to perform some additional validation, modification or conversions on the input data. A very simple example would be converting the connectivity_type value provided by the user in lowercase to uppercase. Plugins can be used to provide the aforementioned functionalities.

Head to __init__.py file under the plugins directory and implement the solution:

from inmanta.plugins import plugin

@plugin
def transform_to_uppercase(word: "string?") -> "string":  
    return word.upper()

There are a few point to note here:

  • It is strongly advised to use type hinting; however, the types here are accommodated with double quotes since they differ from Python’s built-in data types.

  • The @plugin decorator makes the function available to Inmanta model and it can then be referenced inside your model. This decorated function (transform_to_uppercase) can utilize any other undecorated function defined inside the __init__.py file for further processing.

Writing Unit Tests

The most basic type of testing is a compile test in which an Inmanta model is fed to project.compile() and then compiler will run the initial assessments on our provided data/model.

import pytest
from pytest_inmanta.plugin import Project


def test_connectivity_type(project: Project) -> None:
    project.compile(
        """
            import connect

            backend = connect::Ext_L2MPLSType(
                type="VPWS"
            )
        """
    )