[OpenDaylight] Static Distribution

OpenDaylight‘s distribution package remained the same for several years. But what if there is a different way to do this, making distribution more aligned with the latest containerization trends? This is where an OpenDaylight Static Distribution comes to the rescue.

Original Distribution & Containerized Deployments

Let’s take a quick look at the usual way.

A standard distribution is made up of:

  • a pre-configured Apache Karaf
  • a full set of OpenDaylight’s bundles (modules)

It’s an excellent strategy for when the user wants to choose modules and build his application dynamically from construction blocks. Additionally, Karaf provides a set of tools that can affect configuration and features in runtime.

However, when it comes to micro-services and containerized deployments, this approach confronts some best practices for operating containers – statelessness and immutability.

Perks of a Static Distribution

Starting from version 4.2.x, Apache Karaf provides the capability to build a static distribution, aiming to be more compatible with the containerized environment – and OpenDaylight can use that as well.

So, what are the differences between a static vs. dynamic distribution?

  • Specified List of Features

Instead of adding everything to the distribution, you only need to specify a minimal list of features and required bundles in your runtime, so only they will be installed. This would help produce a lightweight distribution package and omit unnecessary stuff, including some Karaf features from the default distribution.

  • Pre-Configured Boot-Features

Boot features are pre-configured, no need to execute any feature installations from Karaf’s shell.

  • Configuration Admin

Configuration admin is replaced with a read-only version that only picks up configuration files from the ‘/etc/’ folder.

  • Speed

Bundle dependencies are resolved and verified during the build phase, which leads to more stable builds overall.

With all these changes in place, we can achieve an almost entirely immutable distribution, which can be used for the containerized deployments.

How to Build a Static Distribution with OpenDaylight’s Components

The latest version of the odl-parent component introduced a new project called karaf-dist-static, which defines a minimal list of features needed by all OpenDaylight’s components (static framework, security libraries, etc.).

This can be used as a parent POM to create our own static distribution. Let’s try to use it and assemble a static distribution with some particular features.

  1. Assuming that you already have an empty pom.xml file, in the first step, we’re going to declare the karaf-dist-static project as a parent for our one:
    <parent>
        <groupId>org.opendaylight.odlparent</groupId>
        <artifactId>karaf-dist-static</artifactId>
        <version>8.1.1-SNAPSHOT</version>
    </parent>
  2. Optionally, you can override two properties to disable the assembling of .zip/tar.gz archives with a distribution. Default values are ‘true’ for both properties.Let’s make an assumption, that we only need the ZIP:
    <properties>
        <karaf.archiveTarGz>false</karaf.archiveTarGz>
        <karaf.archiveZip>true</karaf.archiveZip>
    </properties>

     

  3. This example aims to demonstrate how to produce a static distribution containing NETCONF southbound connectors and RESTCONF northbound implementation.Let’s add the corresponding items to the dependencies section:
    <dependencies>
       <dependency>
          <groupId>org.opendaylight.netconf</groupId>
          <artifactId>odl-netconf-connector-all</artifactId>
          <version>1.10.0-SNAPSHOT</version>
          <classifier>features</classifier>
          <type>xml</type>
       </dependency>
       <dependency>
          <groupId>org.opendaylight.netconf</groupId>
          <artifactId>odl-restconf-nb-rfc8040</artifactId>
          <version>1.13.0-SNAPSHOT</version>
          <classifier>features</classifier>
          <type>xml</type>
       </dependency>
    </dependencies>

     

  4. Once we have these features on the dependency list, we can add them to Karaf’s Maven plugin configuration. Usually, when you want to add some OpenDaylight’s features, you can use the <bootFeatures> container.This should work fine for everything, except features delivered with a Karaf framework (like ssh, diagnostic, etc.).

    When it comes to adding features provided by the Karaf framework, a <startupFeatures> block should be used; as we are going to check the installation of the features within the static distribution.

    First, let’s add the ‘ssh’ feature to the list.

    <build>
      <plugins>
        <plugin>
          <groupId>org.apache.karaf.tooling</groupId>
          <artifactId>karaf-maven-plugin</artifactId>
          <configuration>
             <bootFeatures combine.children="append">
                <feature>odl-netconf-connector-all</feature>
                <feature>odl-restconf-nb-rfc8040</feature>
             </bootFeatures>
          </configuration>
        </plugin>
      </plugins>
    </build>

    After applying all of these things, you should get a pom.xml file similar to the one below:

    <?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>org.opendaylight.odlparent</groupId>
            <artifactId>karaf-dist-static</artifactId>
            <version>8.1.1-SNAPSHOT</version>
        </parent>
     
        <modelVersion>4.0.0</modelVersion>
        <groupId>org.opendaylight.examples</groupId>
        <artifactId>netconf-karaf-static</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <packaging>karaf-assembly</packaging>
     
        <properties>
            <karaf.archiveTarGz>false</karaf.archiveTarGz>
            <karaf.archiveZip>true</karaf.archiveZip>
        </properties>
     
        <dependencies>
            <dependency>
                <groupId>org.opendaylight.netconf</groupId>
                <artifactId>odl-netconf-connector-all</artifactId>
                <version>1.10.0-SNAPSHOT</version>
                <classifier>features</classifier>
                <type>xml</type>
            </dependency>
            <dependency>
                <groupId>org.opendaylight.netconf</groupId>
                <artifactId>odl-restconf-nb-rfc8040</artifactId>
                <version>1.13.0-SNAPSHOT</version>
                <classifier>features</classifier>
                <type>xml</type>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.karaf.tooling</groupId>
                    <artifactId>karaf-maven-plugin</artifactId>
                    <configuration>
                        <startupFeatures combine.children="append">
                            <feature>ssh</feature>
                        </startupFeatures>
                        <bootFeatures combine.children="append">
                            <feature>odl-netconf-connector-all</feature>
                            <feature>odl-restconf-nb-rfc8040</feature>
                        </bootFeatures>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>

Once everything is ready, let’s build a project!

Building a project

mvn clean package

If you check the log messages, you probably will notice the KAR artifact is not the same one we had for dynamic distribution (in dynamic distribution, you can expect the following one – org.apache.karaf.features/framework/4.3.0/kar).

[INFO] Loading direct KAR and features XML dependencies
[INFO]    Standard startup Karaf KAR found: mvn:org.apache.karaf.features/static/4.3.0/kar
[INFO]    Feature static will be added as a startup feature

Eventually, we can check the output directory of the maven build – it should contain an ‘assembly’ folder with a static distribution we created and netconf-karaf-static-1.0.0-SNAPSHOT.zip archive that contains this distribution.

$ ls --group-directories-first -1 ./target
antrun
assembly
classes
dependency-maven-plugin-markers
site
checkstyle-cachefile
checkstyle-checker.xml
checkstyle-header.txt
checkstyle-result.xml
checkstyle-suppressions.xml
cpd.xml
netconf-karaf-static-1.0.0-SNAPSHOT.zip

While a ZIP archive can be used as an artifact, you would usually like to push to some repository; we will verify our distribution by running Karaf from the assembly folder.

./assembly/bin/karaf

If everything goes well, you should see some system messages saying that Karaf is started, following by a shell command-line interface:

Apache Karaf starting up. Press Enter to open the shell now...
100% [========================================================================]
Karaf started in 1s. Bundle stats: 50 active, 51 total
                                                                                            
    ________                       ________                .__  .__       .__     __      
    \_____  \ ______   ____   ____ \______ \ _____  ___.__.|  | |__| ____ |  |___/  |_    
     /   |   \\____ \_/ __ \ /    \ |    |  \\__  \<   |  ||  | |  |/ ___\|  |  \   __\   
    /    |    \  |_> >  ___/|   |  \|    `   \/ __ \\___  ||  |_|  / /_/  >   Y  \  |     
    \_______  /   __/ \___  >___|  /_______  (____  / ____||____/__\___  /|___|  /__|     
            \/|__|        \/     \/        \/     \/\/            /_____/      \/         
                                                                                            
 
Hit '<tab>' for a list of available commands
and '[cmd] --help' for help on a specific command.
Hit '<ctrl-d>' or type 'system:shutdown' or 'logout' to shutdown OpenDaylight.
 
opendaylight-user@root>

With a static distribution, you don’t need to do any feature installation manually.

Let’s just check if our features are running by executing the following command

feature:list | grep 'Started'

The produced output will contain a list of already started features; among them, you should find features we selected in our previous steps.

...
odl-netconf-connector    | 1.10.0.SNAPSHOT  │ Started │ odl-netconf-1.10.0-SNAPSHOT             │ OpenDaylight :: Netconf Connector
odl-restconf-nb-rfc8040  | 1.13.0.SNAPSHOT  │ Started │ odl-restconf-nb-rfc8040-1.13.0-SNAPSHOT │ OpenDaylight :: Restconf :: NB :: RFC8040
...

We can also run an additional check by sending a request to the corresponding RESTCONF endpoint:

curl -vs --user admin:admin 'http://localhost:8181/rests/data/network-topology:network-topology/topology=topology-netconf' | jq

The expected output would be the following:

{
  "network-topology:topology": [
    {
      "topology-id": "topology-netconf"
    }
  ]
}

What’s next?

Now, we can produce immutable & lightweight OpenDaylight distributions with a selected number of pre-installed features, which can be the first step to create Docker images that would be fully compliant for the containerized deployment.

Our next steps would be to make logging and clustered configuration more suitable for running in containers, but that’s a topic for another article.


by Oleksii Mozghovyi | Leave us your feedback on this post!

You can contact us here.

Explore our PANTHEON.tech GitHub.

Watch our YouTube Channel.