Developing Go NDK applications with Bond#
The srl-labs/bond
package is a helper Go package that abstracts the low-level NDK API and assists in the development of the NDK applications. It is a wrapper around the NDK gRPC services with utility functions that were designed to provide a more pleasant development experience.
We recommend users to develop their apps with the bond
package and resort to the barebones NDK API only when the bond
package is not sufficient.
The development environment that we will use in this tutorial is covered in the introduction to the Go NDK development guide.
Deploying the lab#
Before taking a deep dive into the code, let's deploy the greeter
app to SR Linux using containerlab and see how it works.
Containerlab for NDK
When developing NDK applications, it is important to have a lab environment to test the application. The lab environment should be as close as possible to the production environment and also be easy to spin up and tear down.
The Containerlab tool is a perfect fit for this purpose. Containerlab makes it easy to create a personal lab environment composed of network devices and connected by virtual links. We are going to use Containerlab to create a lab environment for the greeter
NDK application development down the road.
It all starts with cloning the srl-labs/ndk-greeter-go
repo:
Note
Containerlab v0.57.2 version and SR Linux 24.3.3 are used in this tutorial. Users are advised to use these version to have the same outputs as in this tutorial.
Newer versions of Containerlab and SR Linux should work as well, but the outputs might be slightly different.
And then running the deployment script:
deploy-all
script builds thegreeter
app, deploys a containerlab topology file, and installs the app on the running SR Linux node.
It won't take you longer than 30 seconds to get the greeter
app up and running on a freshly deployed lab. Type ssh greeter
and let's configure our greeter app:
β― ssh greeter #(1)!
Warning: Permanently added 'greeter' (ED25519) to the list of known hosts.
Welcome to the srlinux CLI.
Type 'help' (and press <ENTER>) if you need any help using this.
--{ running }--[ ]--
A:greeter#
- Containerlab injects host routes and SSH config on your system to allow you to connect to the lab nodes using only its name.
Once connected to the greeter
SR Linux node, let's configure the app:
--{ running }--[ ]--
A:greeter# enter candidate
--{ candidate shared default }--[ ]--
A:greeter# greeter
--{ candidate shared default }--[ greeter ]--
A:greeter# name "Learn SR Linux Reader"
--{ * candidate shared default }--[ greeter ]--
A:greeter# commit stay
All changes have been committed. Starting new transaction.
Now that we've set the name
value, let's verify that the name is indeed set in the candidate configuration and running datastore:
--{ + candidate shared default }--[ greeter ]--
A:greeter# info from running
name "Learn SR Linux Reader"
Look at that, the greeting
value is not there. That's because the greeting
is a state leaf, it is only present in the state datastore. Let's check it out, while we're in the /greeter
context we can use info from state
command to get the state of the current context:
--{ + candidate shared default }--[ greeter ]--
A:greeter# info from state
name "Learn SR Linux Reader"
greeting "π Hi Learn SR Linux Reader, I am SR Linux and my uptime is 108h33m7s!"
As advertised, the greeter app greets us with a message that includes the name
value we've set, and the uptime of the SR Linux node. Should you change the name
value and commit the configuration, you will see the new greeting
message.
Now let's go and see how this app is written, starting with the project structure.
Project structure#
The project structure is a matter of personal preference. There are no strict rules on how to structure a Go project. However, there are some best practices we can enforce making the NDK project structure more consistent and easier to understand.
This is the project structure used in this tutorial:
β― tree
.
βββ LICENSE
βββ README.md
βββ build #(1)!
βββ go.mod
βββ go.sum
βββ goreleaser.yml #(2)!
βββ greeter #(3)!
βββ greeter.yml #(4)!
βββ lab
β βββ greeter.clab.yml #(5)!
βββ logs
β βββ greeter #(6)!
β βββ srl #(7)!
βββ main.go #(8)!
βββ nfpm.yml #(9)!
βββ run.sh #(10)!
βββ yang #(11)!
βββ greeter.yang
- Directory to store build artifacts. This directory is ignored by Git.
- Goreleaser config file to build and publish the NDK application. Usually run via CI/CD pipeline.
- Directory to store the
greeter
package source code. This is where the application logic is implemented. - Application configuration file.
- Containerlab topology file to assist with the development and testing of the NDK application.
- Directory with the application log file.
- Directory with the SR Linux log directory to browse the SR Linux applications logs.
- Main executable file.
- nFPM configuration file to build deb/rpm packages locally.
- Script to orchestrate lab environment and application lifecycle.
- Directory with the application YANG modules.
Besides short descriptions, we will cover the purpose of each file and directory in the following sections when we start to peel off the layers of the greeter
NDK application.
Application Configuration#
As was mentioned before, in order for the NDK application to be installed on the SR Linux node, it needs to be registered with the Application Manager. The Application Manager is a service that manages the lifecycle of all applications, native and custom ones.
The Application Manager uses the application configuration file to onboard the application. Our greeter app comes with the following greeter.yml
configuration file1:
greeter:
path: /usr/local/bin
launch-command: {{if ne (env.Getenv "NDK_DEBUG") "" }}{{ "/debug/dlv --listen=:7000"}}{{ if ne (env.Getenv "NDK_DEBUG") "" }} {{ "--continue --accept-multiclient" }}{{ end }} {{ "--headless=true --log=true --api-version=2 exec"}} {{ end }}greeter
version-command: greeter --version
failure-action: wait=10
config-delivery-format: json
yang-modules:
names:
- greeter
source-directories:
- /opt/greeter/yang
Refer to the application configuration section to better understand what each field means. Application Manager will look for the greeter
binary in the /usr/local/bin/
directory when starting our application.
Application YANG#
Every SR Linux application needs its own schema, this is what makes SR Linux a 100% modelled system. Even the custom, user-defined application must have a schema so that it can be onboarded to the SR Linux NOS.
We have covered the YANG module structure in the architecture section, here is the resulting YANG module of our greeter
application.
module greeter {
yang-version 1.1;
namespace "srlinux.dev/ndk/greeter";
prefix "srl-labs-greeter";
description
"greeter YANG module";
revision "2023-11-21" {
description
"initial release";
}
container greeter {
leaf name {
description
"name of the person to greet";
type string;
}
leaf greeting {
description
"greeting the greeter will say";
type string;
config false;
}
}
}
With this YANG module loaded in SR Linux, we will extend SR Linux schema with the following nodes:
Now that we have our YANG module and the application config file, we can start looking into the application's entrypoint - the main
function.
-
Don't mind a little template magic, it is for the debugging capabilities of the
greeter
app. ↩