diff options
Diffstat (limited to 'release-notes/src/main/asciidoc')
13 files changed, 1609 insertions, 0 deletions
diff --git a/release-notes/src/main/asciidoc/devel_guide/devel_guide.adoc b/release-notes/src/main/asciidoc/devel_guide/devel_guide.adoc new file mode 100644 index 000000000..78664e655 --- /dev/null +++ b/release-notes/src/main/asciidoc/devel_guide/devel_guide.adoc @@ -0,0 +1,13 @@ +== Devel guide + +Honeycomb plugin development guide. + +=== Tutorials +* link:devel_plugin_overview.html[Honeycomb plugin overview] +* link:devel_plugin_tutorial.html[How to write Honeycomb plugins] +* link:devel_plugin_vpp_tutorial.html[How to write Honeycomb plugins for VPP] + +=== Samples +* {project-git-web}/samples?h={project-branch}[Interface managmenet sample from Honeycomb] +** Generic(non-VPP) plugin with a custom distribution containing lots of useful information about Honeycomb and its plugins. + diff --git a/release-notes/src/main/asciidoc/devel_guide/devel_plugin_overview.adoc b/release-notes/src/main/asciidoc/devel_guide/devel_plugin_overview.adoc new file mode 100644 index 000000000..d844a2f5c --- /dev/null +++ b/release-notes/src/main/asciidoc/devel_guide/devel_plugin_overview.adoc @@ -0,0 +1,26 @@ += Plugin overview + +link:release_notes.html[< Home] + +Honeycomb provides a framework for plugins to participate in the data handling. The plugins use YANG modeling language to describe what: + +* *data* they can handle (Create, Read, Update, Delete operations) +* *notifications* do they emit + +NOTE: RPCs are not supported in this release. + +A plugin usually consists of: + +* *YANG models* - These models contain data and notification definitions that are implemented by the plugin. ODL's Yangtools project is used to generate Java APIs from those models (called Binding Aware APIs in ODL) and are later used in the translation code. +* *Set of readers* - Readers provide operational/state data from plugin or its underlying layer. This means that operational/state data is current state of the plugin or its underlying layer. Readers return these operational data by e.g. reading from underlying layer and transforming it into YANG modeled data. +* *Set of writers* - Writers handle configuration data for the plugin or its underlying layer This means that configuration data is the intent being sent to Honeycomb, that should be passed to plugins or their underlying layers. Writers handle these configuration data by transforming YANG modeled data into e.g. underlying layer calls. +* *Set of initializers* - Initializers are invoked right after Honeycomb starts. The gould here is to read current operational/state data of the plugin or its underlying layer and then transform the operational data into configuration data. This enables reconciliation in cases when Honeycomb looses it's persisted data, or is started fresh while the underlying layer already contains some configuration that is manifested as operational/state data +* *Plugin configuration* - Usually configuration in json format + it's Java equivalent. +* *Set of notification producers* - If there are any notifications, the producers transform the data into YANG model notifications and emit them. +* *Module* - Small class instantiating & exposing plugin's components + +What's good to add: + +* *Unit tests* +* *Documentation* (as Readme.adoc + update global release notes if the plugin is included into honeycomb integration distribution) +* *Sample REST or NETCONF requests* (as POSTMAN request collection)
\ No newline at end of file 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 + diff --git a/release-notes/src/main/asciidoc/devel_guide/devel_plugin_vpp_tutorial.adoc b/release-notes/src/main/asciidoc/devel_guide/devel_plugin_vpp_tutorial.adoc new file mode 100644 index 000000000..3f03c0b48 --- /dev/null +++ b/release-notes/src/main/asciidoc/devel_guide/devel_plugin_vpp_tutorial.adoc @@ -0,0 +1,615 @@ += Developing plugins for VPP + +link:release_notes.html[< Home] + +Honeycomb's primary use case is to provide an agent for VPP. This section provides a tutorial for how to develop a Honeycomb plugin that translates YANG modeled data into VPP binary API invocation. + +== Analyzing VPP's API +For this tutorial, VPP's VXLAN management API. Honeycomb already contains VXLAN management translation code inside V3PO plugin. This will be a simplified version. + +Looking at VPP's API definition file, there are 3 calls related to VXLAN: + +vxlan_add_del_tunnel - Creates and Deletes VXLAN tunnel (Update not supported) +vxlan_tunnel_dump - Reads all VXLAN tunnels +These are the shared-memory, binary APIs of VPP that would be difficult to use from Java. But VPP contains a jvpp component, that's completely generated from VPP's API definition file and allows Java applications to manage VPP in plain Java using JNI in the background. Honeycomb provides a component that can be included in a distribution. + +== Updating sample-plugin to manage VPP + +This tutorial starts where the previous one left and will continue to modify the sample plugin in order to be able to manage VPP's VXLAN tunnels. + +=== Updating YANG models +YANG models need to reflect the intent of managing VXLAN tunnels in VPP. As mentioned before, VPP exposes 2 calls to manage VXLAN tunnels. Each vxlan tunnel has a set of attributes, but for simplicity, only 2 of them will be exposed in YANG : source IP address and destination IP address. Rest of attributes will be set to default values in the code. + +So let's update the sample-plugin-params grouping to: + +[source,yang] +---- +grouping sample-plugin-params { + container vxlans { + list vxlan-tunnel { + + key id; + leaf id { + type string; + } + + leaf src { + type inet:ip-address; + } + leaf dst { + type inet:ip-address; + } + } + } +} +---- + +Since ietf-inet-types YANG model is used for the ip-address type, it needs to be imported (after the prefix statement): + +[source,yang] +---- +import ietf-inet-types { prefix "inet"; } +---- + +NOTE: The reason this works is that there are some general YANG models such as ietf-inet-types added to *-api module in its pom.xml. + +Now rebuild the *-api module. + +=== JVpp dependency +Another important thing that the plugin needs is dependency to VPP's JVpp (Java APIs). To do so, just update *-impl's pom.xml with: + +[source,xml] +---- +<!-- VPP's core Java APIs --> +<dependency> + <groupId>io.fd.vpp</groupId> + <artifactId>jvpp-core</artifactId> + <version>{project-vpp-snapshot-version}</version> +</dependency> +---- + +Also add vpp-translate-utils dependency so that writing translation code is easier: + +[source,xml] +---- +<dependency> + <groupId>io.fd.honeycomb.vpp</groupId> + <artifactId>vpp-translate-utils</artifactId> + <version>{project-version}</version> +</dependency> +---- + +Do not rebuild yet, since the APIs for this plugin have changed and the compilation would fail. But make sure to update the project if using an IDE to pick up the Jvpp dependency. + +=== Updating the customizers + +First of all, remove CrudService interface and ElementCrudService class. Will not be needed now. + +==== Changes to ElementStateCustomizer + +Rename it to VxlanReadCustomzier. Update the code to: + +[source,java] +---- +package io.fd.honeycomb.tutorial.read; + +import com.google.common.base.Preconditions; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.VxlansBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.vxlans.VxlanTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.vxlans.VxlanTunnelBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.vxlans.VxlanTunnelKey; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.core.dto.VxlanTunnelDetails; +import org.openvpp.jvpp.core.dto.VxlanTunnelDetailsReplyDump; +import org.openvpp.jvpp.core.dto.VxlanTunnelDump; +import org.openvpp.jvpp.core.future.FutureJVppCore; + +/** + * Reader for {@link VxlanTunnel} list node from our YANG model. + */ +public final class VxlanReadCustomizer implements + ListReaderCustomizer<VxlanTunnel, VxlanTunnelKey, VxlanTunnelBuilder> { + + // JVpp core. This is the Java API for VPP's core API. + private final FutureJVppCore jVppCore; + // Naming context for interfaces + // Honeycomb provides a "context" storage for plugins. This storage is used for storing metadata required during + // data translation (just like in this plugin). An example of such metadata would be interface identifier. In Honeycomb + // we use string names for interfaces, however VPP uses only indices (that are created automatically). + // This means that translation layer has to store the mapping between HC interface name <-> VPP' interface index. + // And since vxlan tunnel is a type of interface in VPP, the same applies here + // + // Honeycomb provides a couple utilities on top of context storage such as NamingContext. It is just a map + // backed by context storage that makes the lookup and storing easier. + private final NamingContext vxlanNamingContext; + + public VxlanReadCustomizer(final FutureJVppCore jVppCore, final NamingContext vxlanNamingContext) { + this.jVppCore = jVppCore; + this.vxlanNamingContext = vxlanNamingContext; + } + + /** + * Provide a list of IDs for all VXLANs in VPP + */ + @Nonnull + @Override + public List<VxlanTunnelKey> getAllIds(@Nonnull final InstanceIdentifier<VxlanTunnel> id, + @Nonnull final ReadContext context) + throws ReadFailedException { + // Create Dump request + final VxlanTunnelDump vxlanTunnelDump = new VxlanTunnelDump(); + // Set Dump request attributes + // Set interface index to 0, so all interfaces are dumped and we can get the list of all IDs + vxlanTunnelDump.swIfIndex = 0; + final VxlanTunnelDetailsReplyDump reply; + try { + reply = TranslateUtils.getReplyForRead(jVppCore.vxlanTunnelDump(vxlanTunnelDump).toCompletableFuture(), id); + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + + // Check for empty response (no vxlan tunnels to read) + if (reply == null || reply.vxlanTunnelDetails == null) { + return Collections.emptyList(); + } + + return reply.vxlanTunnelDetails.stream() + // Need a name of an interface here. Use context to look it up from index + // In case the naming context does not contain such mapping, it creates an artificial one + .map(a -> new VxlanTunnelKey(vxlanNamingContext.getName(a.swIfIndex, context.getMappingContext()))) + .collect(Collectors.toList()); + } + + @Override + public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<VxlanTunnel> readData) { + // Just set the readValue into parent builder + // The cast has to be performed here + ((VxlansBuilder) builder).setVxlanTunnel(readData); + } + + @Nonnull + @Override + public VxlanTunnelBuilder getBuilder(@Nonnull final InstanceIdentifier<VxlanTunnel> id) { + // Setting key from id is not necessary, builder will take care of that + return new VxlanTunnelBuilder(); + } + + /** + * Read all the attributes of a single VXLAN tunnel + */ + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanTunnel> id, + @Nonnull final VxlanTunnelBuilder builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + // The ID received here contains the name of a particular interface that should be read + // It was either requested directly by HC users or is one of the IDs from getAllIds that could have been invoked + // just before this method invocation + + // Create Dump request + final VxlanTunnelDump vxlanTunnelDump = new VxlanTunnelDump(); + // Set Dump request attributes + // Set the vxlan index from naming context + // Naming context must contain the mapping because: + // 1. The vxlan tunnel was created in VPP using HC + this plugin meaning we stored the mapping in write customizer + // 2. The vxlan tunnel was already present in VPP, but HC reconciliation mechanism took care of that (as long as proper Initializer is provided by this plugin) + final String vxlanName = id.firstKeyOf(VxlanTunnel.class).getId(); + vxlanTunnelDump.swIfIndex = vxlanNamingContext.getIndex(vxlanName, ctx.getMappingContext()); + + final VxlanTunnelDetailsReplyDump reply; + try { + reply = TranslateUtils.getReplyForRead(jVppCore.vxlanTunnelDump(vxlanTunnelDump).toCompletableFuture(), id); + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + + Preconditions.checkState(reply != null && reply.vxlanTunnelDetails != null); + final VxlanTunnelDetails singleVxlanDetail = reply.vxlanTunnelDetails.stream().findFirst().get(); + + // Now translate all attributes into provided builder + final Boolean isIpv6 = TranslateUtils.byteToBoolean(singleVxlanDetail.isIpv6); + builder.setSrc(TranslateUtils.arrayToIpAddress(isIpv6, singleVxlanDetail.srcAddress)); + builder.setDst(TranslateUtils.arrayToIpAddress(isIpv6, singleVxlanDetail.dstAddress)); + // There are additional attributes of a vxlan tunnel that wont be used here + } +} +---- + +The '"ReaderFactory also needs to be updated: + +[source,java] +---- +package io.fd.honeycomb.tutorial.read; + +import com.google.inject.Inject; +import io.fd.honeycomb.translate.impl.read.GenericListReader; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.SamplePluginState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.SamplePluginStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.Vxlans; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.VxlansBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.vxlans.VxlanTunnel; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.core.future.FutureJVppCore; + +/** + * Factory producing readers for sample-plugin plugin's data. + */ +public final class ModuleStateReaderFactory implements ReaderFactory { + + public static final InstanceIdentifier<SamplePluginState> ROOT_STATE_CONTAINER_ID = + InstanceIdentifier.create(SamplePluginState.class); + + /** + * Injected vxlan naming context shared with writer, provided by this plugin + */ + @Inject + private NamingContext vxlanNamingContext; + /** + * Injected jvpp core APIs, provided by Honeycomb's infrastructure + */ + @Inject + private FutureJVppCore jvppCore; + + @Override + public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) { + // register reader that only delegate read's to its children + registry.addStructuralReader(ROOT_STATE_CONTAINER_ID, SamplePluginStateBuilder.class); + // register reader that only delegate read's to its children + registry.addStructuralReader(ROOT_STATE_CONTAINER_ID.child(Vxlans.class), VxlansBuilder.class); + + // just adds reader to the structure + // use addAfter/addBefore if you want to add specific order to readers on the same level of tree + // use subtreeAdd if you want to handle multiple nodes in single customizer/subtreeAddAfter/subtreeAddBefore if you also want to add order + // be aware that instance identifier passes to subtreeAdd/subtreeAddAfter/subtreeAddBefore should define subtree, + // therefore it should be relative from handled node down - InstanceIdentifier.create(HandledNode), not parent.child(HandledNode.class) + registry.add(new GenericListReader<>( + // What part of subtree this reader handles is identified by an InstanceIdentifier + ROOT_STATE_CONTAINER_ID.child(Vxlans.class).child(VxlanTunnel.class), + // Customizer (the actual translation code to do the heavy lifting) + new VxlanReadCustomizer(jvppCore, vxlanNamingContext))); + } +} +---- + +==== Changes to ElementCustomizer + +Rename to VxlanWriteCustomizer. Update the code to: + +[source,java] +---- +package io.fd.honeycomb.tutorial.write; + +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.vxlans.VxlanTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.vxlans.VxlanTunnelKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.core.dto.VxlanAddDelTunnel; +import org.openvpp.jvpp.core.dto.VxlanAddDelTunnelReply; +import org.openvpp.jvpp.core.future.FutureJVppCore; + +/** + * Writer for {@link VxlanTunnel} list node from our YANG model. + */ +public final class VxlanWriteCustomizer implements ListWriterCustomizer<VxlanTunnel, VxlanTunnelKey> { + + /** + * JVpp APIs + */ + private final FutureJVppCore jvppCore; + /** + * Shared vxlan tunnel naming context + */ + private final NamingContext vxlanTunnelNamingContext; + + public VxlanWriteCustomizer(final FutureJVppCore jvppCore, final NamingContext vxlanTunnelNamingContext) { + this.jvppCore = jvppCore; + this.vxlanTunnelNamingContext = vxlanTunnelNamingContext; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanTunnel> id, + @Nonnull final VxlanTunnel dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + // Create and set vxlan tunnel add request + final VxlanAddDelTunnel vxlanAddDelTunnel = new VxlanAddDelTunnel(); + // 1 for add, 0 for delete + vxlanAddDelTunnel.isAdd = 1; + // dataAfter is the new vxlanTunnel configuration + final boolean isIpv6 = dataAfter.getSrc().getIpv6Address() != null; + vxlanAddDelTunnel.isIpv6 = TranslateUtils.booleanToByte(isIpv6); + vxlanAddDelTunnel.srcAddress = TranslateUtils.ipAddressToArray(isIpv6, dataAfter.getSrc()); + vxlanAddDelTunnel.dstAddress = TranslateUtils.ipAddressToArray(isIpv6, dataAfter.getDst()); + // There are other input parameters that are not exposed by our YANG model, default values will be used + + try { + final VxlanAddDelTunnelReply replyForWrite = TranslateUtils + .getReplyForWrite(jvppCore.vxlanAddDelTunnel(vxlanAddDelTunnel).toCompletableFuture(), id); + + // VPP returns the index of new vxlan tunnel + final int newVxlanTunnelIndex = replyForWrite.swIfIndex; + // It's important to store it in context so that reader knows to which name a vxlan tunnel is mapped + vxlanTunnelNamingContext.addName(newVxlanTunnelIndex, dataAfter.getId(), writeContext.getMappingContext()); + } catch (VppBaseCallException e) { + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanTunnel> id, + @Nonnull final VxlanTunnel dataBefore, + @Nonnull final VxlanTunnel dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + // Not supported at VPP API level, throw exception + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, + new UnsupportedOperationException("Vxlan tunnel update is not supported by VPP")); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanTunnel> id, + @Nonnull final VxlanTunnel dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + // Create and set vxlan tunnel add request + final VxlanAddDelTunnel vxlanAddDelTunnel = new VxlanAddDelTunnel(); + // 1 for add, 0 for delete + vxlanAddDelTunnel.isAdd = 0; + // Vxlan tunnel is identified by its attributes when deleting, not index, so set all attributes + // dataBefore is the vxlan tunnel that's being deleted + final boolean isIpv6 = dataBefore.getSrc().getIpv6Address() != null; + vxlanAddDelTunnel.isIpv6 = TranslateUtils.booleanToByte(isIpv6); + vxlanAddDelTunnel.srcAddress = TranslateUtils.ipAddressToArray(isIpv6, dataBefore.getSrc()); + vxlanAddDelTunnel.dstAddress = TranslateUtils.ipAddressToArray(isIpv6, dataBefore.getDst()); + // There are other input parameters that are not exposed by our YANG model, default values will be used + + try { + final VxlanAddDelTunnelReply replyForWrite = TranslateUtils + .getReplyForWrite(jvppCore.vxlanAddDelTunnel(vxlanAddDelTunnel).toCompletableFuture(), id); + // It's important to remove the mapping from context + vxlanTunnelNamingContext.removeName(dataBefore.getId(), writeContext.getMappingContext()); + } catch (VppBaseCallException e) { + throw new WriteFailedException.DeleteFailedException(id, e); + } + } +} +---- + +The '"WriterFactory also needs to be updated: + +[source,java] +---- +package io.fd.honeycomb.tutorial.write; + +import com.google.inject.Inject; +import io.fd.honeycomb.translate.impl.write.GenericWriter; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.WriterFactory; +import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.SamplePlugin; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.Vxlans; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.vxlans.VxlanTunnel; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.core.future.FutureJVppCore; + +/** + * Factory producing writers for sample-plugin plugin's data. + */ +public final class ModuleWriterFactory implements WriterFactory { + + private static final InstanceIdentifier<SamplePlugin> ROOT_CONTAINER_ID = InstanceIdentifier.create(SamplePlugin.class); + + /** + * Injected vxlan naming context shared with writer, provided by this plugin + */ + @Inject + private NamingContext vxlanNamingContext; + /** + * Injected jvpp core APIs, provided by Honeycomb's infrastructure + */ + @Inject + private FutureJVppCore jvppCore; + + @Override + public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) { + // Unlike ReaderFactory, there's no need to add structural writers, just the writers that actually do something + + // register writer for vxlan tunnel + registry.add(new GenericWriter<>( + // What part of subtree this writer handles is identified by an InstanceIdentifier + ROOT_CONTAINER_ID.child(Vxlans.class).child(VxlanTunnel.class), + // Customizer (the actual translation code to do the heavy lifting) + new VxlanWriteCustomizer(jvppCore, vxlanNamingContext))); + } +} +---- + +==== Changes to Module +The module needs to be updated to: + +* Include new instance of naming context +* Remove crud service + +and the code needs to look like: + +[source,java] +---- +package io.fd.honeycomb.tutorial; + +import com.google.inject.AbstractModule; +import com.google.inject.multibindings.Multibinder; +import io.fd.honeycomb.data.init.DataTreeInitializer; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.WriterFactory; +import io.fd.honeycomb.tutorial.init.ConfigDataInitializer; +import io.fd.honeycomb.tutorial.read.ModuleStateReaderFactory; +import io.fd.honeycomb.tutorial.write.ModuleWriterFactory; +import net.jmob.guice.conf.core.ConfigurationModule; + +/** + * Module class instantiating sample-plugin plugin components. + */ +public final class Module extends AbstractModule { + + @Override + protected void configure() { + // requests injection of properties + install(ConfigurationModule.create()); + requestInjection(ModuleConfiguration.class); + + // bind naming context instance for reader and writer factories + // the first parameter is artificial name prefix in cases a name needs to be reconstructed for a vxlan tunnel + // that is present in VPP but not in Honeycomb (could be extracted into configuration) + // the second parameter is just the naming context ID (could be extracted into configuration) + binder().bind(NamingContext.class).toInstance(new NamingContext("vxlan-tunnel", "vxlan-tunnel-context")); + + // creates reader factory binding + // can hold multiple binding for separate yang modules + final Multibinder<ReaderFactory> readerFactoryBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class); + readerFactoryBinder.addBinding().to(ModuleStateReaderFactory.class); + + // create writer factory binding + // can hold multiple binding for separate yang modules + final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class); + writerFactoryBinder.addBinding().to(ModuleWriterFactory.class); + + // create initializer binding + // can hold multiple binding for separate yang modules + final Multibinder<DataTreeInitializer> initializerBinder = + Multibinder.newSetBinder(binder(), DataTreeInitializer.class); + initializerBinder.addBinding().to(ConfigDataInitializer.class); + + // Disable notification producer for now +// Multibinder.newSetBinder(binder(), ManagedNotificationProducer.class).addBinding() +// .to(SampleNotificationProducer.class); + } +} +---- +*Now it's time to rebuild the plugin using mvn clean install to make the jars available for integrating them with vpp-integration distribution in next sections* + +== Integrating with vpp-integration distribution +The vxlan tunnel management plugin can now be integrated with any honeycomb distribution. Honeycomb provides a vpp-integration distribution, where all VPP related plugins integrate to create a distribution with all available VPP related features. + +This distribution comes with honeycomb infrastructure + common components for VPP Honeycomb plugins (e.g. Java APIs for VPP). + +In order to add this new plugin into vpp-integration: + +* clone honeycomb codebase (since that's the home of vpp-integration distribution) +* add a dependency for this sample plugin in vpp-integration distribution (honeycomb/vpp-integration/minimal-distribution/pom.xml): +[source,xml] +---- +<dependency> + <groupId>io.fd.honeycomb.tutorial</groupId> + <artifactId>sample-plugin-impl</artifactId> + <version>{project-version}</version> +</dependency> +---- +* modify Main of vpp-integration distribution to include sample-plugin (/home/mmarsale/Projects/honeycomb/vpp-integration/minimal-distribution/src/main/java/io/fd/honeycomb/vpp/integration/distro/Main.java): +[source,java] +---- +package io.fd.honeycomb.vpp.integration.distro; + +import com.google.common.collect.Lists; +import com.google.inject.Module; +import io.fd.honeycomb.vpp.distro.VppCommonModule; +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); + + // All the plugins should be listed here + sampleModules.add(new VppCommonModule()); +// Comment out V3po and Lisp module for the time being, since V3po and sample-plugin are in conflict over vxlan tunnel management +// a plugin implementing VPP's API that's not yet covered by V3po or LISP plugin would not have to do this +// sampleModules.add(new V3poModule()); +// sampleModules.add(new LispModule()); + sampleModules.add(new io.fd.honeycomb.tutorial.Module()); + + io.fd.honeycomb.infra.distro.Main.init(sampleModules); + } +} +---- + +Now just rebuild the honeycomb project. + +== Verifying distribution +At this point, the vpp-integration distribution with sample-plugin can now be started. But first, make sure that a compatible version of VPP is installed and running. Next, start honeycomb with: + + sudo vpp-integration/minimal-distribution/target/vpp-integration-distribution-1.16.9-hc/vpp-integration-distribution-1.16.9/honeycomb + +=== Testing over RESTCONF +Reading vxlans operational data (should return empty vxlans container at first): + + curl -u admin:admin http://localhost:8181/restconf/operational/sample-plugin:sample-plugin-state + +Adding a vxlan tunnel: + + curl -H 'Content-Type: application/json' -H 'Accept: application/json' -u admin:admin -X PUT -d '{"vxlans":{"vxlan-tunnel": [{"id":"vxlan-test-tunnel", "src":"10.0.0.1", "dst":"10.0.0.2"}]}}' http://localhost:8181/restconf/config/sample-plugin:sample-plugin/vxlans + +Reading vxlans config data (data that we posted to Honeycomb): + + curl -u admin:admin http://localhost:8181/restconf/config/sample-plugin:sample-plugin + +Reading vxlans operational data (data coming from VPP being transformed by ReaderCustomizer on the fly): + + curl -u admin:admin http://localhost:8181/restconf/operational/sample-plugin:sample-plugin-state + +Verifying vxlan tunnel existence in VPP: + + telnet 0 5002 + show interface + +should show: + +[source] +---- +Name Idx State Counter Count +local0 0 down +vxlan_tunnel0 1 up +---- + +Deleting a vxlan tunnel: + + curl -u admin:admin -X DELETE http://localhost:8181/restconf/config/sample-plugin:sample-plugin/vxlans/vxlan-tunnel/vxlan-test-tunnel + +Disclaimer: The vxlan tunnel will be removed from Honeycomb, and delete command will be executed on VPP, but VPP will just disable that interface and keep it as some sort of placeholder for next vxlan tunnel (that's VPPs behavior, so a vxlan tunnel cant be really deleted). So that's why you would still see the tunnel in VPP's CLI after delete. + +==== Testing over NETCONF +Netconf testing guide including Notifications, can be found in Honeycomb/Running_Honeycomb. + +NOTE: Netconf and Restconf are equivalent interfaces to Honeycomb, being capable of providing the same APIs. The only difference is with notifications. Only NETCONF is capable of emitting the notifications. + +== Full working sample + +Full working sample on github: https://github.com/marosmars/honeycomb-samples/tree/vpp-plugin + +[NOTE] +==== +just a note on what further work for this plugin might contain: + +* unit tests +* POSTMAN REST collection with sample requests +* logging +==== diff --git a/release-notes/src/main/asciidoc/install_guide/install_from_available_archives.adoc b/release-notes/src/main/asciidoc/install_guide/install_from_available_archives.adoc new file mode 100644 index 000000000..5eeb4fee2 --- /dev/null +++ b/release-notes/src/main/asciidoc/install_guide/install_from_available_archives.adoc @@ -0,0 +1,14 @@ += Installing from available archives + +link:release_notes.html[< Home] + +Honeycomb provides zip and tar.gz archives that can be downloaded and extracted to provide Honeycomb VPP distribution. + +== Downloading archives +In https://nexus.fd.io/#nexus-search;quick~vpp-integration-distribution[Honeycomb's nexus] look for vpp-integration-distribution artifact with version {project-version} and download either zip or tar.gz. After Extracting the archive, a folder vpp-integration-distribution-<version> will be created. + +== Running extracted distribution[edit] +In the new folder, locate honeycomb executable shell script and run it. + +Note: sudo privileges are necessary with default configuration. + diff --git a/release-notes/src/main/asciidoc/install_guide/install_from_available_binary_packages.adoc b/release-notes/src/main/asciidoc/install_guide/install_from_available_binary_packages.adoc new file mode 100644 index 000000000..c9e629427 --- /dev/null +++ b/release-notes/src/main/asciidoc/install_guide/install_from_available_binary_packages.adoc @@ -0,0 +1,66 @@ += Installing from available binary packages + +link:release_notes.html[< Home] + +== Centos +=== CentOS 7.2 - Honeycomb Release RPMs +==== Add fd.io repo +Create a file /etc/yum.repos.d/honeycomb-release.repo with contents: + + [honeycomb-release] + name=honeycomb release branch latest merge + baseurl=https://nexus.fd.io/content/repositories/fd.io.centos7/ + enabled=1 + gpgcheck=0 + +==== Install honeycomb packages + + sudo yum install honeycomb + +== Ubuntu +=== Ubuntu 14.04 - Honeycomb Release DEB + +[CAUTION] +==== +Add openjdk-8 repository. 1404 does not provide openjdk-8 by default + + According to http://stackoverflow.com/questions/32942023/ubuntu-openjdk-8-unable-to-locate-package +==== + +Pick Ubuntu version: + + export UBUNTU="trusty" + +Then run: + + sudo rm /etc/apt/sources.list.d/99fd.io.list + echo "deb [trusted=yes] https://nexus.fd.io/content/repositories/fd.io.ubuntu.$UBUNTU.main/ ./" | sudo tee -a /etc/apt/sources.list.d/99fd.io.list + sudo apt-get update + sudo apt-get install honeycomb + +[CAUTION] +==== +Uninstall previously installed java 7 + + look for packages e.g. openjdk-7-* and uninstall them +==== + +=== Ubuntu 16.04 - Honeycomb Release DEB + +Pick Ubuntu version: + + export UBUNTU="xenial" + +Then run: + + sudo rm /etc/apt/sources.list.d/99fd.io.list + echo "deb [trusted=yes] https://nexus.fd.io/content/repositories/fd.io.ubuntu.$UBUNTU.main/ ./" | sudo tee -a /etc/apt/sources.list.d/99fd.io.list + sudo apt-get update + sudo apt-get install honeycomb + +== SNAPSHOT versions + +For SNAPSHOT versions, SNAPSHOT repositories have to be used. +Each branch has its own repository at: https://nexus.fd.io/content/repositories/. +In case SNAPSHOT versions needs to be used, update the URL pointing to the repository from previous steps +according to the repository names listed at provided link.
\ No newline at end of file diff --git a/release-notes/src/main/asciidoc/install_guide/install_guide.adoc b/release-notes/src/main/asciidoc/install_guide/install_guide.adoc new file mode 100644 index 000000000..de2e02eda --- /dev/null +++ b/release-notes/src/main/asciidoc/install_guide/install_guide.adoc @@ -0,0 +1,23 @@ +== Install guide + +Installing binaries: + +* link:install_from_available_binary_packages.html[Installing from available binary packages] +* link:install_from_available_archives.html[Installing from available archives] + +=== Manual build + +* link:install_manual_build.html[Manual build] + +=== Distribution notes +Honeycomb is packaged as a static set of jars, that are loaded by Honeycomb Main class, where pre-configured plugins are then started. + +=== Footprint + +Minimal footprint for Honeycomb infrastructure (without any plugins) at rest below 100Mb. For Honeycomb distribution with VPP related plugins, minimal footprint was observed below 150Mb. +The footprint varies depending on: + +* VM load. Under heavier load, JVM tends to release some unused memory used during Honeycomb initialization. +* Northbound interface configuration (4 interfaces started by default: Restconf HTTP, HTTPS, Netconf TCP, SSH). Minimal footprint can be achieved by using only a single interface. +* JVM configuration. Even lower footprint numbers can be achieved by using aggressive JVM memory options: -client -Xms20m -Xmx32m -XX:MetaspaceSize=5m -XX:MaxMetaspaceSize=32m -XX:MaxMetaspaceExpansion=1m -Xss512k -XX:+UseSerialGC -Djava.compiler=NONE -Xverify:none -noverify +* Amount of data stored by Honeycomb.
\ No newline at end of file diff --git a/release-notes/src/main/asciidoc/install_guide/install_manual_build.adoc b/release-notes/src/main/asciidoc/install_guide/install_manual_build.adoc new file mode 100644 index 000000000..6fa4caa45 --- /dev/null +++ b/release-notes/src/main/asciidoc/install_guide/install_manual_build.adoc @@ -0,0 +1,196 @@ += Manual build + +link:release_notes.html[< Home] + +== Prerequisites +Building Honeycomb project requires: + +* Java 8 +* Maven (version 3.2.5 and above should be fine) +* Properly set maven settings(displayed below) to access nexus.fd.io + +== Obtain the honeycomb source code +TIP: Make sure you have https://wiki.fd.io/view/DEV/Setting_up_Gerrit[registered your ssh key with gerrit]. + + git clone ssh://[username]@gerrit.fd.io:29418/honeycomb + cd honeycomb + git checkout {project-branch} + +== Building the code +Make sure all the prerequisites are installed. + +NOTE: To make sure fresh Honeycomb build is compatible with VPP, building VPP is also required to make sure the same JVpp version is used preventing out-of-sync exceptions. In case only Honeycomb needs to be built, skip Building VPP section. + +=== Building VPP +Clone VPP according to: https://gerrit.fd.io/r/#/admin/projects/vpp and checkout {project-branch} branch + +Dive into VPP's build-root folder: + + cd vpp/build-root/ + +Build VPP: + + make distclean && ./bootstrap.sh && make V=0 PLATFORM=vpp TAG=vpp install-deb + +Install VPP: + + sudo dpkg -i *.deb + +Start VPP: + + sudo start vpp + +Install JVpp into local maven repository to make Honeycomb pick up the same JVpp version + + cd build-vpp-native/vpp-api/java/ + mvn install:install-file -Dfile=jvpp-registry-{project-vpp-version}.jar -DgroupId=io.fd.vpp -DartifactId=jvpp-registry -Dversion={project-vpp-snapshot-version} -Dpackaging=jar + mvn install:install-file -Dfile=jvpp-core-{project-vpp-version}.jar -DgroupId=io.fd.vpp -DartifactId=jvpp-core -Dversion={project-vpp-snapshot-version}-Dpackaging=jar + cd ../../plugins/snat-plugin/ + mvn install:install-file -Dfile=jvpp-snat-{project-snat-version}.jar -DgroupId=io.fd.vpp -DartifactId=jvpp-snat -Dversion={project-snat-snapshot-version} -Dpackaging=jar + +Now current Vpp is up and running and prepared for integration with HC. + +=== Building Honeycomb +Now Honeycomb can be built and it will use latest JVpp produced during VPP build. + +==== Setup settings.xml +Put the following in your ~/.m2/settings.xml: + +[source,xml] +---- +<?xml version="1.0" encoding="UTF-8"?> +<!-- vi: set et smarttab sw=2 tabstop=2: --> +<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> + + <profiles> + <profile> + <id>fd.io-release</id> + <repositories> + <repository> + <id>fd.io-mirror</id> + <name>fd.io-mirror</name> + <url>https://nexus.fd.io/content/groups/public/</url> + <releases> + <enabled>true</enabled> + <updatePolicy>never</updatePolicy> + </releases> + <snapshots> + <enabled>false</enabled> + </snapshots> + </repository> + </repositories> + <pluginRepositories> + <pluginRepository> + <id>fd.io-mirror</id> + <name>fd.io-mirror</name> + <url>https://nexus.fd.io/content/repositories/public/</url> + <releases> + <enabled>true</enabled> + <updatePolicy>never</updatePolicy> + </releases> + <snapshots> + <enabled>false</enabled> + </snapshots> + </pluginRepository> + </pluginRepositories> + </profile> + + <profile> + <id>fd.io-snapshots</id> + <repositories> + <repository> + <id>fd.io-snapshot</id> + <name>fd.io-snapshot</name> + <url>https://nexus.fd.io/content/repositories/fd.io.snapshot/</url> + <releases> + <enabled>false</enabled> + </releases> + <snapshots> + <enabled>true</enabled> + </snapshots> + </repository> + </repositories> + <pluginRepositories> + <pluginRepository> + <id>fd.io-snapshot</id> + <name>fd.io-snapshot</name> + <url>https://nexus.fd.io/content/repositories/fd.io.snapshot/</url> + <releases> + <enabled>false</enabled> + </releases> + <snapshots> + <enabled>true</enabled> + </snapshots> + </pluginRepository> + </pluginRepositories> + </profile> + <profile> + <id>opendaylight-snapshots</id> + <repositories> + <repository> + <id>opendaylight-snapshot</id> + <name>opendaylight-snapshot</name> + <url>https://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</url> + <releases> + <enabled>false</enabled> + </releases> + <snapshots> + <enabled>true</enabled> + </snapshots> + </repository> + </repositories> + <pluginRepositories> + <pluginRepository> + <id>opendaylight-shapshot</id> + <name>opendaylight-snapshot</name> + <url>https://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</url> + <releases> + <enabled>false</enabled> + </releases> + <snapshots> + <enabled>true</enabled> + </snapshots> + </pluginRepository> + </pluginRepositories> + </profile> + </profiles> + + <activeProfiles> + <activeProfile>fd.io-release</activeProfile> + <activeProfile>fd.io-snapshots</activeProfile> + <activeProfile>opendaylight-snapshots</activeProfile> + </activeProfiles> +</settings> +---- + +==== Building Honeycomb +cd honeycomb/ + + mvn clean install + +Now Honeycomb can be run with: + + sudo sh vpp-integration/minimal-distribution/target/vpp-integration-distribution-1.16.9-SNAPSHOT-hc/vpp-integration-distribution-1.16.9-SNAPSHOT/honeycomb + +=== Building packages +After the code has been built, you can build an RPM or DEB package for honeycomb. + +==== RPM +Export build number variable: + + export BUILD_NUMBER=33 + +Run package building script from: + + packaging/rpm/rpmbuild.sh + +==== DEB +Export build number variable: + + export BUILD_NUMBER=33 + +Run package building script from: + + packaging/deb/debuild.sh
\ No newline at end of file diff --git a/release-notes/src/main/asciidoc/release_notes.adoc b/release-notes/src/main/asciidoc/release_notes.adoc new file mode 100644 index 000000000..a0fa48b32 --- /dev/null +++ b/release-notes/src/main/asciidoc/release_notes.adoc @@ -0,0 +1,30 @@ += Honeycomb {project-version} Release notes + +Release notes for honeycomb {project-version}. Based on VPP {project-vpp-snapshot-version} + +== Release plan +https://wiki.fd.io/view/Honeycomb/Release_Plans/Release_Plan_{project-public-version}[Release plan] + +== Features +Adding to the list of existing features: https://wiki.fd.io/view/Honeycomb/Releases/1609#Features[1609 feature list]: + +=== New features +* NAT management + +=== Removed features + +=== Modified features +* ACL management improvements + +=== Deprecated features + +== Backlog + +* https://jira.fd.io/projects/HONEYCOMB/versions/{project-version-in-jira}[JIRA] +* https://jira.fd.io/jira/secure/ReleaseNote.jspa?projectId=10001&version={project-version-in-jira}[Release notes] + +include::install_guide/install_guide.adoc[] + +include::user_guide/user_guide.adoc[] + +include::devel_guide/devel_guide.adoc[]
\ No newline at end of file diff --git a/release-notes/src/main/asciidoc/user_guide/user_guide.adoc b/release-notes/src/main/asciidoc/user_guide/user_guide.adoc new file mode 100644 index 000000000..494f2d241 --- /dev/null +++ b/release-notes/src/main/asciidoc/user_guide/user_guide.adoc @@ -0,0 +1,48 @@ +== User guide + +=== Running Honeycomb +link:user_running_honeycomb.html[Running Honeycomb] + +=== Troubleshooting +link:user_troubleshooting.html[Troubleshooting] + +=== Honeycomb and ODL +link:user_honeycomb_and_ODL.html[Mounting Honeycomb in ODL] + +=== Configuration files +Honeycomb's configuration files present within its distribution: + +* Honeycomb infra: +** {project-git-web}/infra/minimal-distribution/src/main/resources/honeycomb-minimal-resources/config/honeycomb.json?h={project-branch}[Honeycomb base configuration] +* Honeycomb vpp plugins commons: +** {project-git-web}/vpp-common/minimal-distribution/src/main/resources/honeycomb-minimal-resources/config/jvpp.json?h={project-branch}[VPP plugins common configuration] +* V3PO plugin: +** {project-git-web}/v3po/v3po2vpp/src/main/resources/honeycomb-minimal-resources/config/v3po.json?h={project-branch}[V3PO plugin for Honeycomb configuration] +* LISP plugin +** {project-git-web}/lisp/lisp2vpp/src/main/resources/honeycomb-minimal-resources/config/lisp.json?h={project-branch}[LISP plugin for Honeycomb configuration] +* NSH plugin: +** {project-git-web}/nsh/impl/src/main/resources/honeycomb-minimal-resources/config/vppnsh.json?h={project-branch}[NSH_SFC plugin for Honeycomb configuration] + +=== YANG models + +* V3PO plugin +** {project-git-web}/v3po/api/src/main/yang?h={project-branch}[V3PO YANG models] +* LISP plugin +** {project-git-web}/lisp/api/src/main/yang?h={project-branch}[LISP YANG models] +* NSH plugin +** {project-git-web}/nsh/api/src/main/yang?h={project-branch}[NSH YANG models] +* NAT plugin +** {project-git-web}/nat/nat-api/src/main/yang?h={project-branch}[NAT YANG models] +* Context models +** {project-git-web}/vpp-common/naming-context-api/src/main/yang?h={project-branch}[Context YANG models] + +=== POSTMAN collections + +* V3PO plugin +** {project-git-web}/v3po/postman_rest_collection.json?h={project-branch}[V3PO postman collection] +* LISP plugin +** {project-git-web}/lisp/lisp_postman_rest_collection.json?h={project-branch}[LISP postman collection] +* NSH plugin +** {project-git-web}/nsh/nsh_postman_rest_collection.json?h={project-branch}[NSH postman collection] +* NAT plugin +** {project-git-web}/nat/postman_rest_collection.json?h={project-branch}[NAT postman collection] diff --git a/release-notes/src/main/asciidoc/user_guide/user_honeycomb_and_ODL.adoc b/release-notes/src/main/asciidoc/user_guide/user_honeycomb_and_ODL.adoc new file mode 100644 index 000000000..23c7e521c --- /dev/null +++ b/release-notes/src/main/asciidoc/user_guide/user_honeycomb_and_ODL.adoc @@ -0,0 +1,76 @@ += Honeycomb and ODL + +link:release_notes.html[< Home] + +Honeycomb can be managed using ODL as any NETCONF-enabled device. Please follow https://wiki.opendaylight.org/view/OpenDaylight_Controller:Config:Examples:Netconf for detailed instructions how to mount and connect to a NETCONF device + +== Troubleshooting + +Issues with Honeycomb and ODL integration + +=== Unable to open SSH session due to invalid crypto configuration + +If ODL fails to open ssh session due to InvalidAlgorithmParameterException, e.g.: + +[srouce] +==== +2016-09-13 13:52:34,852 | WARN | NioProcessor-3 | ClientSessionImpl | 180 - +org.apache.sshd.core - 0.14.0 | Exception caught +java.security.InvalidAlgorithmParameterException: Prime size must be multiple of 64, +and can only range from 512 to 2048 (inclusive) + at com.sun.crypto.provider.DHKeyPairGenerator.initialize(DHKeyPairGenerator.java:120) + [sunjce_provider.jar:1.8.0_45] + at java.security.KeyPairGenerator$Delegate.initialize(KeyPairGenerator.java:674) + [:1.8.0_45-internal] + at java.security.KeyPairGenerator.initialize(KeyPairGenerator.java:411) + [:1.8.0_45-internal] + at org.apache.sshd.common.kex.DH.getE(DH.java:65)[180:org.apache.sshd.core:0.14.0] + +... + +2016-09-13 13:52:34,852 | DEBUG | NioProcessor-3 | ClientSessionImpl | 180 - +org.apache.sshd.core - 0.14.0 | Closing ClientSessionImpl[admin@/127.0.0.1:2835] immediately +==== + +It probably means BouncyCastle provider is not properly configured/loaded on the ODL side. + +There are 2 solutions to this problem: + +==== Solution 1, HC side, less secure: + +First solution is to not use BouncyCastle in Honeycomb. This limits its capabilities in terms of security (using just default Java stuff), but makes it compatible with Opendaylight: + +As a workaround start honeycomb with (must be placed into Honeycomb's startup script) + + -Dorg.apache.sshd.registerBouncyCastle=false + +As a result 1024 bit DH group will be used for SSH key exchange. + +==== Solution 2, ODL side, more secure +Second solution is to locate mina sshd jar in ODL distribution's system folder. For Boron it is: + + system/org/apache/sshd/sshd-core/0.14.0/sshd-core-0.14.0.jar + +Open the jar (it's just a zip archive), locate META-INF/MANIFEST.MF file, open it and update the Import-Package section. Find this piece: + + org.bouncycast.openssl;version="[1.51,2)";resolution:=optional + +and replace it with: + + org.bouncycast.openssl;version="[1.51,2)" + +This needs to be done before ODL is started the first time or it needs to be started with "clean" parameter. + +=== Background +This issue is caused by a couple of reasons: + +* ODL and HC both use mina-sshd 0.14 for SSH +* mina-sshd relies partially on bouncy-castle as a security provider +* mina-sshd only defines bouncy-castle dependencies as optional for OSGi environment (which is not correct since there are bugs in the mina-sshd where missing bouncy-castle is just not expected, causing various problems... but that's a different topic) +* netconf features in ODL make sure to first load bouncy-castle bundles and only then mina-sshd (in addition, bouncy-castle provider is placed in karaf's lib/ext and marked to be a security provider in karaf's etc/custom.properties) +* however, when loading netconf features as initial features, there seems to be some sort of race condition in karaf and mina is started without bouncy-castle available, making it work only partially +* but so far so good, everything loads and mina should just use less secure provider from Java +* however when an SSH connection is started from ODL to e.g. Honeycomb. Mina-sshd is picking key size that's only supported by bouncy-castle (not by plain JDK) during negotiation +* this means that if remote supports such size, mina-sshd in ODL subsequently fails, since it finds out bouncy-castle is not present and Java is unable to handle it + +NOTE: If loading netconf post karaf startup manually, the issue does not appear
\ No newline at end of file diff --git a/release-notes/src/main/asciidoc/user_guide/user_running_honeycomb.adoc b/release-notes/src/main/asciidoc/user_guide/user_running_honeycomb.adoc new file mode 100644 index 000000000..676bb1cdd --- /dev/null +++ b/release-notes/src/main/asciidoc/user_guide/user_running_honeycomb.adoc @@ -0,0 +1,118 @@ += Running Honeycomb + +link:release_notes.html[< Home] + +== Starting Honeycomb agent +The zipped vpp-integration distribution can be started by invoking: + + sudo ./vpp-integration-distribution-{project-version}/honeycomb + +This will start Honeycomb with all ODL dependencies and VPP translation code. It will automatically initialize vpp-jvpp to create interface between VPP and Honeycomb. + +If Honeycomb was installed from the RPM or DEB packages, it can be started by (make sure you start vpp first): + + sudo service vpp start + sudo service honeycomb start + +The location of installed honeycomb is at /opt/honeycomb + +== Testing Honeycomb agent +There are multiple ways of testing Honeycomb agent, depending on e.g. which northbound interface will be used + +=== Using NETCONF Northbound + +Netconf northbound can be easily tested manually using CLI SSH client. Initialize SSH connection by invoking: + + ssh admin@localhost -p 2831 -s netconf + +NOTE: Using default credentials admin/admin, default port 2831 and netconf SSH channel Note: "Are you sure you want to continue connecting (yes/no)?" Answer yes + +Next thing to do is to provide client hello message to initialize netconf session. Following content must be copy&pasted into SSH session + hit enter: + +[source,xml] +---- +<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> + <capabilities> + <capability>urn:ietf:params:netconf:base:1.0</capability> + </capabilities> +</hello> +]]>]]> +---- + +This initializes netconf session silently. No response from Honeycomb will be provided + +Next step is to get all the configuration data from VPP using Honeycomb's netconf northbound interface. Following content must be copy&pasted into SSH session + hit enter: + +[source,xml] +---- +<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101"> + <get-config> + <source> + <running/> + </source> + </get-config> +</rpc> +]]>]]> +---- + +Honeycomb will respond will all the data currently configured in Honeycomb + VPP + +Next step is to get all the operational data from VPP using Honeycomb's netconf northbound interface. Following content must be copy&pasted into SSH session + hit enter: + +[source,xml] +---- +<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101"> + <get/> +</rpc> +]]>]]> +---- + +Honeycomb will respond will all operational data present in VPP. + +==== Listening for notifications + +Notifications over NETCONF are supported by Honeycomb. To test it out, open ssh NETCONF session and send hello message. Exactly as detailed above. + +Next thing to do is to activate honeycomb notification stream over NETCONF. So just send this rpc over ssh session: + +[source,xml] +---- +<netconf:rpc netconf:message-id="101" xmlns:netconf="urn:ietf:params:xml:ns:netconf:base:1.0"> +<create-subscription xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"> + <stream>honeycomb</stream> +</create-subscription> +</netconf:rpc> +]]>]]> +---- + +From now on, all notifications from honeycomb will appear in the netconf session. To verify, VPP's interface state can be changed over CLI: + + telnet 0 5002 + set interface state local0 up + +A notification should appear in opened NETCONF session. + +=== Using RESTCONF northbound + +[TIP] +==== +Testing over RESTCONF is easier, and common calls can be found in this postman collection: + +*{project-git-web}/v3po/postman_rest_collection.json?h={project-branch}[V3PO postman collection][Honeycomb V3PO POSTMAN collection]* + +Each request in the collection contains equivalent VPP command (over CLI or VAT, whichever works) in the description. +==== + +To use: + +* POSTMAN is a google chrome application +* Clicking the collection link above is not CORRECT +* Open POSTMAN and select Import https://www.dropbox.com/s/v2odj4gih5if99d/Screenshot%202016-05-19%2008.51.45.png?dl=0 +* Select import from link https://www.dropbox.com/s/s6wsqzf7h4yhesh/Screenshot%202016-05-19%2008.52.54.png?dl=0 +* Copy the link above into the dialogue https://www.dropbox.com/s/3qc3bbndhy6rr1g/Screenshot%202016-05-19%2008.53.30.png?dl=0 +* PROFIT! https://www.dropbox.com/s/lrdtua7zziqyqc3/Screenshot%202016-05-19%2008.53.51.png?dl=0 + +NOTE: All POSTMAN collections are listed under User Guide. + +==== Listening for notifications +Notifications over RESTCONF are not supported due to ODL's RESTCONF limitations.
\ No newline at end of file diff --git a/release-notes/src/main/asciidoc/user_guide/user_troubleshooting.adoc b/release-notes/src/main/asciidoc/user_guide/user_troubleshooting.adoc new file mode 100644 index 000000000..42215f261 --- /dev/null +++ b/release-notes/src/main/asciidoc/user_guide/user_troubleshooting.adoc @@ -0,0 +1,20 @@ += Troubleshooting + +link:release_notes.html[< Home] + +CAUTION: Trying to fix any Honeycomb issue should start with looking at honeycomb log file (default location: /var/log/honeycomb/) + +== Unable to open SSH session +If following warning is shown when invoking ssh command: WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!. Just invoke (as suggested by the warning): + + ssh-keygen -f ... + +== Honeycomb fails to start properly +First thing to do is to take a look at Honeycomb logs(default location: /var/log/honeycomb/). + +If following log message is present: VPP-ERROR: VPP api client connection failed java.io.IOException: Connection returned error -1. Make sure VPP is installed in the system and it's running. + +NOTE: If the VPP-ERROR also contains message stating vpp japi out of sync. It indicates incompatible versions of VPP and Honeycomb. + +== Honeycomb does not respond +Check suggestions from previous item: Honeycomb fails to start properly
\ No newline at end of file |