Introduction

Not every OpenDaylight project is available in lighty.io. Since we are not dependent on the OSGi framework (Karaf), we can’t simply add and start project features from the Karaf command line.

Here is a list of all OpenDaylight Projects. Before starting the integration, make sure that your project is not already integrated within lighty.io.

Here is the list of already integrated modules. In this article, we will use the OpenFlow project as an example of how to integrate the new project to lighty.io.

We have already integrated the OpenFlow project into lighty.io – it is available under lighty-modules/lighty-openflow-sb.

Create a new project

Create a new Java project for your module. In this example, we will be using Maven.

Create a new lighty.io module

Create a new Java class, which will represent new lighty.io module. In our example, we will create the class OpenflowSouthboundPlugin , which corresponds with the OpenFlow module.

lighty.io provides an abstract AbstractLightyModule class, containing methods to start and shut down a module. By extending the AbstractLightyModule, you only need to implement two abstract methods:

  • initProcedure 
  • stopProcedure 

to initialize/stop services & beans in your module. Additionall,y we recommend to use Builder pattern to create instances of your new module, in case your module requires a larger amount of input parameters.

Initialize Beans & Services

This section will give you hints on how to find all beans and services from the original project, that you may need to start in your new lighty.io module.

Clone OpenDaylight Project

Clone the project from opendaylight-gerrit repository. Check out the version you would like to integrate.

Find all necessary Blueprint files

Check all project features for blueprint files. Usually, you’re looking for the autowire.xml file, which is located in the project:

target/generated-sources/blueprint/OSGI-INF.blueprint/autowire.xml

This file is generated during the build from the annotations and blueprint .xml files. In the project are blueprint files usually located in:

src/main/resources/OSGI-INF.blueprint 

Here is the example of the interfacemanager-impl feature autowire.xml file from the genius module project.

<?xml version="1.0" encoding="UTF-8"?><blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
    <bean id="alivenessMonitorListenerImpl" class="org.opendaylight.genius.interfacemanager.listeners.AlivenessMonitorListenerImpl" init method="start" destroy-method="close">
        <argument ref="dataBroker"/>
        <argument ref="notificationService"/>
    </bean>    
	<bean id="ifmDiagStatusProvider" class="org.opendaylight.genius.interfacemanager.diagstatus.IfmDiagStatusProvider" destroy-method="close">
        <argument ref="diagStatusService"/>
    </bean>
	<bean id="interfacemgrProvider" class="org.opendaylight.genius.interfacemanager.InterfacemgrProvider" destroy-method="close">
        <argument ref="dataBroker"/>
        <argument ref="entityOwnershipService"/>
        <argument ref="idManagerService"/>
        <argument ref="interfaceManagerRpcService"/>
        <argument ref="jobCoordinator"/>
        <argument ref="interfaceManagerCommonUtils"/>
        <argument ref="interfaceMetaUtils"/>
        <argument ref="ifmConfig"/>
        <argument ref="ifmDiagStatusProvider"/>
    </bean> 
	<service ref="ifmDiagStatusProvider" interface="org.opendaylight.infrautils.diagstatus.ServiceStatusProvider"/
</blueprint>

As you can see, it contains 3 beans, where IfmDiagStatusProvider is a service. We need to create them within our lighty.io module project. Bean AlivenessMonitorListenerImpl has init and destroy methods, which we need to call as well – usually in the initProcedure and stopProcedure methods. 

Sometimes, beans require classes from other projects. Always check beforehand, if the required class isn’t already being created in one of the present lighty.io modules. If it’s there, don’t create it in your module – just pass it to the module as a dependency. Some beans are also created by the builder pattern, which needs to set up class attributes to specific values. Check if the project has a resource file under src/main/resources/initial/config-file.xml, which contains the default values.

Create Beans & initProcedure

In the initProcedure, we are going to initialize all necessary classes, which are in the blueprints. Here is a snippet of the OpenFlow plugin method:

protected boolean initProcedure() {
    ForwardingPingPongDataBroker forwardingPingPongDataBroker =
          new ForwardingPingPongDataBroker(lightyServices.getBindingDataBroker());
    SwitchConnectionProviderList switchConnectionProviders = new SwitchConnectionProviderList(providers);
	this.mastershipChangeServiceManager = new MastershipChangeServiceManagerImpl();
    final OpenflowDiagStatusProvider diagStat = new OpenflowDiagStatusProviderImpl(this.lightyServices
          .getDiagStatusService());
    this.openFlowPluginProvider = new OpenFlowPluginProviderImpl(
          this.configurationService,
          switchConnectionProviders,
          forwardingPingPongDataBroker,
          this.lightyServices.getRpcProviderService(),
          this.lightyServices.getBindingNotificationPublishService(),
          this.lightyServices.getClusterSingletonServiceProvider(),
          this.lightyServices.getEntityOwnershipService(),
          this.mastershipChangeServiceManager, diagStat,
          this.lightyServices.getSystemReadyMonitor());
    this.openFlowPluginProvider.initialize();
...

We are creating 2 classes from the OpenFlow blueprints directly in the initProcedure. The OpenFlowPluginProviderImpl class requires some dependencies, which are provided by lightyServices – located in the lighty controller module. We are also calling the initialize method on the bean as well.

Close Beans in the stopProcedure

In stopProcedure, we are going to call the destroy-methods on all beans, which have it described in the blueprints.

@Override
protected boolean stopProcedure() {
    destroy(this.packetListenerNotificationRegistration);
    destroy(this.flowCapableTopologyProvider);
    destroy(this.operationProcessor);
    destroy(this.forwardingRulesManagerImpl);
    destroy(this.arbitratorReconciliationManager);
    destroy(this.openFlowPluginProvider);
    destroy(this.mastershipChangeServiceManager);
    destroy(this.terminationPointChangeListener);
    destroy(this.nodeChangeListener);
    return true;
}

Runnable application with the new module

A lighty.io application is basically just a plain old Java main method, that will run your module and all necessary dependencies. In order to create an application for your module, simply create and start all the necessary dependencies in the main method first, and then create and start your module.

We are now going to show you, how we have made the example OpenFlow application. First step is to get the configuration of the modules:


final Set<YangModuleInfo> modelPaths = Stream.concat(RestConfConfigUtils.YANG_MODELS.stream(),
	OpenflowConfigUtils.OFP_MODELS.stream())
	.collect(Collectors.toSet());
controllerConfiguration = ControllerConfigUtils.getDefaultSingleNodeConfiguration(modelPaths);
restConfConfiguration =  RestConfConfigUtils.getDefaultRestConfConfiguration();
openflowpluginConfiguration = OpenflowConfigUtils.getDefaultOfpConfiguration();

After we have the required configuration, we can start the modules one after the other.

//1. initialize and start Lighty controller (MD-SAL, Controller, YangTools, Akka)
final LightyControllerBuilder lightyControllerBuilder = new LightyControllerBuilder();
final LightyController lightyController = lightyControllerBuilder.from(controllerConfiguration).build();
lightyController.start().get();
//2. start RESTCONF server
final CommunityRestConfBuilder communityRestConfBuilder = new CommunityRestConfBuilder();
final CommunityRestConf communityRestConf = communityRestConfBuilder.from(RestConfConfigUtils
	.getRestConfConfiguration(restConfConfiguration, lightyController.getServices()))
	.build();
communityRestConf.start();
//3. start OpenFlow SBP
final OpenflowSouthboundPlugin plugin;
plugin = new OpenflowSouthboundPluginBuilder()
	.from(configuration, lightyController.getServices())
	.withPacketListener(new PacketInListener())
	.build();
ListenableFuture<Boolean> start = plugin.start();

Check out the example applications in lighty.io or other articles, for more information.

Summary

In this article, we have described the way to include other OpenDaylight projects, which are not integrated into our lighty.io. Steps of integrating the new module were:

  • Creating new project for the module
  • Initializing module classes from blueprints
  • Creating the runnable application in which a new module started

Don’t forget, some classes require dependencies from another module and its recommended to use existing implementations if they are available in lighty.io.

by Peter Válka