diff options
author | Maros Marsalek <mmarsale@cisco.com> | 2016-10-14 14:09:02 +0200 |
---|---|---|
committer | Marek Gradzki <mgradzki@cisco.com> | 2016-10-21 05:41:19 +0000 |
commit | f31e292087e56b5171dcdfc83bbd81462236977d (patch) | |
tree | e9ca15bba120278bbfb00d38497587bb45101483 /release-notes/src/main/asciidoc/devel_guide/devel_plugin_tutorial.adoc | |
parent | e0ff3ddc1c7a146c18f1ae4f15e0e4f30ed18a9f (diff) |
Release notes
- migrated from wiki
- updated versions to current version
- notes are built with each regular build
- notes root is at: target/generated-docs/release_notes.html
- notes are inlined into site
Change-Id: I581898988f41f77f5eafb20e9e61e08f09908b98
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
Diffstat (limited to 'release-notes/src/main/asciidoc/devel_guide/devel_plugin_tutorial.adoc')
-rw-r--r-- | release-notes/src/main/asciidoc/devel_guide/devel_plugin_tutorial.adoc | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/release-notes/src/main/asciidoc/devel_guide/devel_plugin_tutorial.adoc b/release-notes/src/main/asciidoc/devel_guide/devel_plugin_tutorial.adoc new file mode 100644 index 000000000..496ec55d1 --- /dev/null +++ b/release-notes/src/main/asciidoc/devel_guide/devel_plugin_tutorial.adoc @@ -0,0 +1,364 @@ += 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: + + mvn -X archetype:generate -DarchetypeGroupId=io.fd.honeycomb.tools -DarchetypeArtifactId=honeycomb-plugin-archetype -DarchetypeVersion={project-version} + +Fill in the parameters e.g. + + 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] +---- +<dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>notification-api</artifactId> + <version>${honeycomb.infra.version}</version> +</dependency> +---- + +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<Class<? extends Notification>> 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] +---- +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <parent> + <groupId>io.fd.honeycomb.common</groupId> + <artifactId>minimal-distribution-parent</artifactId> + <version>{project-version}</version> + </parent> + + <modelVersion>4.0.0</modelVersion> + <groupId>io.fd.honeycomb.tutorial</groupId> + <artifactId>sample-distribution</artifactId> + <version>{project-version}</version> + + <properties> + <exec.parameters>-Xms128m -Xmx128m</exec.parameters> + <main.class>io.fd.honeycomb.tutorial.Main</main.class> + <interfaces.mapping.version>{project-version}</interfaces.mapping.version> + <honeycomb.min.distro.version>{project-version}</honeycomb.min.distro.version> + </properties> + + <build> + <plugins> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.codehaus.gmaven</groupId> + <artifactId>groovy-maven-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + </plugin> + <plugin> + <artifactId>maven-assembly-plugin</artifactId> + </plugin> + </plugins> + </build> + + <dependencies> + <!-- Dependency on sample plugin --> + <dependency> + <groupId>io.fd.honeycomb.tutorial</groupId> + <artifactId>sample-plugin-impl</artifactId> + <version>${interfaces.mapping.version}</version> + </dependency> + <!-- Dependency on distribution base --> + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>minimal-distribution</artifactId> + <version>${honeycomb.min.distro.version}</version> + </dependency> + + </dependencies> +</project> +---- + +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<Module> 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] +---- + <module>sample-distribution</module> +---- + +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] +---- +<dependency> + <groupId>io.fd.honeycomb.samples.interfaces</groupId> + <artifactId>interfaces-mapping</artifactId> + <version>${interfaces.mapping.version}</version> +</dependency> +---- + +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: + + 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 + |