= Developing generic plugins
link:release_notes.html[< Home]
Since Honeycomb is a generic agent. Any plugin (translation code) can be injected into the framework, creating a custom agent providing RESTCONF/NETCONF northbound interfaces out-of-box.
== Developing plugin code
Honeycomb provides a maven archetype to generate a plugin skeleton. To use that archetype, run maven:
[subs="+attributes"]
mvn -X archetype:generate -DarchetypeGroupId=io.fd.honeycomb.tools -DarchetypeArtifactId=honeycomb-plugin-archetype -DarchetypeVersion={project-version}
Fill in the parameters e.g.
[subs="+attributes"]
groupId: io.fd.honeycomb.tutorial
artifactId: sample-plugin
version: {project-version}
package: io.fd.honeycomb.tutorial
And following structure should be created:
[source]
----
sample-plugin/
├── pom.xml
├── sample-plugin-api
│ ├── pom.xml
│ └── src
│ └── main
│ ├── java
│ └── yang
│ └── sample-plugin.yang
└── sample-plugin-impl
├── pom.xml
├── Readme.adoc
└── src
├── main
│ └── java
│ └── io
│ └── fd
│ └── honeycomb
│ └── tutorial
│ ├── CrudService.java
│ ├── ElementCrudService.java
│ ├── init
│ │ └── ConfigDataInitializer.java
│ ├── ModuleConfiguration.java
│ ├── Module.java
│ ├── read
│ │ ├── ElementStateCustomizer.java
│ │ └── ModuleStateReaderFactory.java
│ └── write
│ ├── ElementCustomizer.java
│ └── ModuleWriterFactory.java
└── test
└── java
----
There are 2 modules:
* sample-plugin-api - Contains YANG models and generates Java APIs from the models.
* sample-plugin-impl - Contains: Readers, Writers, Initializers, Notification producers (not yet), Configuration and Wiring.
There is plenty of comments within the code, so its is advised to import the code into an IDE and take a look around.
*The archetype generates a plugin that is fully working right from the start*. Since it contains all the components necessary, works on a sample yang model and provides some sample values.
== Building the code
To build the code, just execute maven:
mvn clean install
And that's it. This is a working Honeycomb plugin.
== Adding notifications
No notification producer is generated by the archetype, but it is pretty straightforward to add one.
First, the notification has to be defined in YANG (sample-plugin-api/src/main/yang/sample-plugin.yang) e.g.
[source,yang]
----
notification sample-notification {
leaf content {
type string;
}
}
----
Now rebuild the plugin to generate new APIs for our notification.
Next part is implementing the Notification producer. First thing to do is to add a dependency on notification-api, since it's not included by default. Update sample-plugin-impl's pom file with:
[source,xml]
----
io.fd.honeycomb
notification-api
${honeycomb.infra.version}
----
Now, the producer code can be added:
[source,java]
----
package io.fd.honeycomb.tutorial.notif;
import io.fd.honeycomb.notification.ManagedNotificationProducer;
import io.fd.honeycomb.notification.NotificationCollector;
import java.util.Collection;
import java.util.Collections;
import javax.annotation.Nonnull;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.SampleNotification;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.SampleNotificationBuilder;
import org.opendaylight.yangtools.yang.binding.Notification;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Notification producer for sample plugin
*/
public class SampleNotificationProducer implements ManagedNotificationProducer {
private static final Logger LOG = LoggerFactory.getLogger(SampleNotificationProducer.class);
private Thread thread;
@Override
public void start(@Nonnull final NotificationCollector collector) {
LOG.info("Starting notification stream for interfaces");
// Simulating notification producer
thread = new Thread(() -> {
while(true) {
if (Thread.currentThread().isInterrupted()) {
return;
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
final SampleNotification notification = new SampleNotificationBuilder()
.setContent("Hello world " + System.currentTimeMillis())
.build();
LOG.info("Emitting notification: {}", notification);
collector.onNotification(notification);
}
}, "NotificationProducer");
thread.setDaemon(true);
thread.start();
}
@Override
public void stop() {
if(thread != null) {
thread.interrupt();
}
}
@Nonnull
@Override
public Collection> getNotificationTypes() {
// Producing only this single type of notification
return Collections.singleton(SampleNotification.class);
}
@Override
public void close() throws Exception {
stop();
}
}
----
This is placed sample-plugin/sample-plugin-impl/src/main/java/io/fd/honeycomb/tutorial/notif/SampleNotificationProducer.java.
NOTE: This is a sample producer, that creates a thread to periodically emit a sample notification
Now it needs to be exposed from the plugin. The configure method in Module class needs to be updated with:
[source,java]
----
Multibinder.newSetBinder(binder(), ManagedNotificationProducer.class).addBinding().to(SampleNotificationProducer.class);
----
Plugin needs to be rebuilt, but that's it for notification producers.
== Creating custom distribution
The plugin is now ready to have a Honeycomb distribution for it. This section will provides information on how to create a custom Honeycomb distribution.
A new maven module needs to be created. So in sample-plugin folder:
mkdir sample-distribution
cd sample-distribution
mkdir -p src/main/java/io/fd/honeycomb/tutorial
Then create the pom:
[source,xml,subs="+attributes"]
----
io.fd.honeycomb.common
minimal-distribution-parent
{project-version}
4.0.0
io.fd.honeycomb.tutorial
sample-distribution
{project-version}
-Xms128m -Xmx128m
io.fd.honeycomb.tutorial.Main
{project-version}
{project-version}
maven-compiler-plugin
org.codehaus.gmaven
groovy-maven-plugin
org.apache.maven.plugins
maven-jar-plugin
org.apache.maven.plugins
maven-dependency-plugin
maven-assembly-plugin
io.fd.honeycomb.tutorial
sample-plugin-impl
${interfaces.mapping.version}
io.fd.honeycomb
minimal-distribution
${honeycomb.min.distro.version}
----
Now, Main class has to be added in folder src/main/java/io/fd/honeycomb/tutorial:
[source,java]
----
package io.fd.honeycomb.tutorial;
import com.google.common.collect.Lists;
import com.google.inject.Module;
import java.util.List;
public class Main {
public static void main(String[] args) {
final List sampleModules = Lists.newArrayList(io.fd.honeycomb.infra.distro.Main.BASE_MODULES);
sampleModules.add(new io.fd.honeycomb.tutorial.Module());
io.fd.honeycomb.infra.distro.Main.init(sampleModules);
}
}
----
Last thing to do is to update sample-plugin/pom.xml with:
[source,xml]
----
sample-distribution
----
Another rebuild and the distribution should be created in sample-distribution/target.
=== Adding existing plugins to the mix
In previous section, a custom Honeycomb distribution was created. This section will show how to add existing plugins to the new distribution.
So in order to add another existing sample (sample interface plugin from Honeycomb) into the distribution, update the sample-plugin/sample-distribution/pom.xml with:
[source,xml]
----
io.fd.honeycomb.samples.interfaces
interfaces-mapping
${interfaces.mapping.version}
----
Now in main, add this line:
[source,java]
----
sampleModules.add(new SampleInterfaceModule());
----
That's it, just rebuild.
== Verifying distribution
The distribution with this sample plugin and sample interface plugin is now available and can be tested.
Distribution can now be found in sample-plugin/sample-distribution/target as:
zip archive
tar.gz archive
folder
The distribution can be started by:
[subs="attributes"]
sudo ./sample-distribution/target/sample-distribution-{project-version}-hc/sample-distribution-{project-version}/honeycomb
NOTE: honeycomb-start script is the background alternative
Honeycomb will display following message in the log:
2016-09-02 13:20:30.424 CEST [main] INFO io.fd.honeycomb.infra.distro.Main - Honeycomb started successfully!
and that means Honeycomb was started successfully.
=== Testing over RESTCONF
Reading sample-plugin operational data:
curl -u admin:admin http://localhost:8181/restconf/operational/sample-plugin:sample-plugin-state
Writing sample-plugin operational data:
Not possible from YANG spec. Operational data is only for read.
Writing sample-plugin config data:
curl -H 'Content-Type: application/json' -H 'Accept: application/json' -u admin:admin -X PUT -d '{"sample-plugin":{"element":[{"id":10,"description":"This is a example of loaded data"}]}}' http://localhost:8181/restconf/config/sample-plugin:sample-plugin
Reading sample-plugin config data:
curl -u admin:admin http://localhost:8181/restconf/config/sample-plugin:sample-plugin
=== Testing over NETCONF
Netconf testing guide including Notifications, can be found in link:user_running_honeycomb.html[User guide]
== Full working example
Full working example on github: https://github.com/marosmars/honeycomb-samples