Extension¶
Extending the Connect
module requires the following steps:
Reading the MEF standard specification for your desired feature
Translating the
MEF
specification to Inmanta modelExtending 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 withExt_
and is extending the existinglsm::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 theentities
: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 thewith_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 theentities
,refinements
and their attributes together.when
is a compile timeif
, 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"
)
"""
)