Directory change: Moved example to example/main to make room for other examples
This commit is contained in:
parent
60cb87f998
commit
a269e26c0d
19 changed files with 525 additions and 439 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -4,6 +4,7 @@
|
||||||
*_parse.tab.c
|
*_parse.tab.c
|
||||||
*_parse.tab.h
|
*_parse.tab.h
|
||||||
lex.*_parse.c
|
lex.*_parse.c
|
||||||
|
*.depend
|
||||||
|
|
||||||
Makefile
|
Makefile
|
||||||
apps/Makefile
|
apps/Makefile
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@
|
||||||
|
|
||||||
|
|
||||||
### API changes on existing features (you may need to change your code)
|
### API changes on existing features (you may need to change your code)
|
||||||
|
* Directory change: Moved example to example/main to make room for other examples.
|
||||||
* Removed argc/argv parameters from ca_start plugin API function:
|
* Removed argc/argv parameters from ca_start plugin API function:
|
||||||
* You may need to change signatures of your startup in your plugins, eg from:
|
* You may need to change signatures of your startup in your plugins, eg from:
|
||||||
```
|
```
|
||||||
|
|
|
||||||
3
configure
vendored
3
configure
vendored
|
|
@ -4447,7 +4447,7 @@ _ACEOF
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ac_config_files="$ac_config_files Makefile lib/Makefile lib/src/Makefile lib/clixon/Makefile apps/Makefile apps/cli/Makefile apps/backend/Makefile apps/netconf/Makefile apps/restconf/Makefile include/Makefile etc/Makefile etc/clixonrc example/Makefile extras/rpm/Makefile docker/Makefile docker/system/Makefile docker/base/Makefile datastore/Makefile util/Makefile yang/Makefile yang/clixon/Makefile yang/standard/Makefile doc/Makefile test/Makefile"
|
ac_config_files="$ac_config_files Makefile lib/Makefile lib/src/Makefile lib/clixon/Makefile apps/Makefile apps/cli/Makefile apps/backend/Makefile apps/netconf/Makefile apps/restconf/Makefile include/Makefile etc/Makefile etc/clixonrc example/Makefile example/main/Makefile extras/rpm/Makefile docker/Makefile docker/system/Makefile docker/base/Makefile datastore/Makefile util/Makefile yang/Makefile yang/clixon/Makefile yang/standard/Makefile doc/Makefile test/Makefile"
|
||||||
|
|
||||||
cat >confcache <<\_ACEOF
|
cat >confcache <<\_ACEOF
|
||||||
# This file is a shell script that caches the results of configure
|
# This file is a shell script that caches the results of configure
|
||||||
|
|
@ -5154,6 +5154,7 @@ do
|
||||||
"etc/Makefile") CONFIG_FILES="$CONFIG_FILES etc/Makefile" ;;
|
"etc/Makefile") CONFIG_FILES="$CONFIG_FILES etc/Makefile" ;;
|
||||||
"etc/clixonrc") CONFIG_FILES="$CONFIG_FILES etc/clixonrc" ;;
|
"etc/clixonrc") CONFIG_FILES="$CONFIG_FILES etc/clixonrc" ;;
|
||||||
"example/Makefile") CONFIG_FILES="$CONFIG_FILES example/Makefile" ;;
|
"example/Makefile") CONFIG_FILES="$CONFIG_FILES example/Makefile" ;;
|
||||||
|
"example/main/Makefile") CONFIG_FILES="$CONFIG_FILES example/main/Makefile" ;;
|
||||||
"extras/rpm/Makefile") CONFIG_FILES="$CONFIG_FILES extras/rpm/Makefile" ;;
|
"extras/rpm/Makefile") CONFIG_FILES="$CONFIG_FILES extras/rpm/Makefile" ;;
|
||||||
"docker/Makefile") CONFIG_FILES="$CONFIG_FILES docker/Makefile" ;;
|
"docker/Makefile") CONFIG_FILES="$CONFIG_FILES docker/Makefile" ;;
|
||||||
"docker/system/Makefile") CONFIG_FILES="$CONFIG_FILES docker/system/Makefile" ;;
|
"docker/system/Makefile") CONFIG_FILES="$CONFIG_FILES docker/system/Makefile" ;;
|
||||||
|
|
|
||||||
|
|
@ -248,6 +248,7 @@ AC_OUTPUT(Makefile
|
||||||
etc/Makefile
|
etc/Makefile
|
||||||
etc/clixonrc
|
etc/clixonrc
|
||||||
example/Makefile
|
example/Makefile
|
||||||
|
example/main/Makefile
|
||||||
extras/rpm/Makefile
|
extras/rpm/Makefile
|
||||||
docker/Makefile
|
docker/Makefile
|
||||||
docker/system/Makefile
|
docker/system/Makefile
|
||||||
|
|
|
||||||
12
doc/FAQ.md
12
doc/FAQ.md
|
|
@ -75,7 +75,7 @@ Clixon:
|
||||||
sudo make install;
|
sudo make install;
|
||||||
sudo make install-include
|
sudo make install-include
|
||||||
```
|
```
|
||||||
The example:
|
The main example:
|
||||||
```
|
```
|
||||||
cd example;
|
cd example;
|
||||||
make;
|
make;
|
||||||
|
|
@ -229,7 +229,7 @@ configuration file is /usr/local/etc/clixon.xml. The example
|
||||||
configuration file is installed at /usr/local/etc/example.xml. The
|
configuration file is installed at /usr/local/etc/example.xml. The
|
||||||
YANG specification for the configuration file is clixon-config.yang.
|
YANG specification for the configuration file is clixon-config.yang.
|
||||||
|
|
||||||
See the [example config file](../example/example.xml).
|
See the [example config file](../example/main/example.xml).
|
||||||
|
|
||||||
## How are Clixon configuration files found?
|
## How are Clixon configuration files found?
|
||||||
|
|
||||||
|
|
@ -364,7 +364,7 @@ You may also add a default method in the configuration file:
|
||||||
## Can I use systemd with Clixon?
|
## Can I use systemd with Clixon?
|
||||||
|
|
||||||
Yes. Systemd example files are provide for the backend and the
|
Yes. Systemd example files are provide for the backend and the
|
||||||
restconf daemon as part of the [example](../example/systemd).
|
restconf daemon as part of the [example](../example/main/systemd).
|
||||||
|
|
||||||
|
|
||||||
## How can I add extra XML?
|
## How can I add extra XML?
|
||||||
|
|
@ -386,7 +386,7 @@ The second way is by programming the plugin_reset() in the backend
|
||||||
plugin. The example code contains an example on how to do this (see plugin_reset() in example_backend.c).
|
plugin. The example code contains an example on how to do this (see plugin_reset() in example_backend.c).
|
||||||
|
|
||||||
## I want to program. How do I extend the example?
|
## I want to program. How do I extend the example?
|
||||||
See [../apps/example](../apps/example)
|
See [../example/main](../example/main)
|
||||||
- example.xml - Change the configuration file
|
- example.xml - Change the configuration file
|
||||||
- The yang specifications - This is the central part. It changes the XML, database and the config cli.
|
- The yang specifications - This is the central part. It changes the XML, database and the config cli.
|
||||||
- example_cli.cli - Change the fixed part of the CLI commands
|
- example_cli.cli - Change the fixed part of the CLI commands
|
||||||
|
|
@ -412,7 +412,7 @@ Each plugin is initiated with an API struct followed by a plugin init function a
|
||||||
return &api; /* Return NULL on error */
|
return &api; /* Return NULL on error */
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
For more info see [../example/README.md]
|
For more info see [../example/main/README.md]
|
||||||
|
|
||||||
|
|
||||||
## How do I write a commit function?
|
## How do I write a commit function?
|
||||||
|
|
@ -560,7 +560,7 @@ plugin_credentials(clicon_handle h,
|
||||||
|
|
||||||
To authenticate, the callback needs to return the value 1 and supply a username.
|
To authenticate, the callback needs to return the value 1 and supply a username.
|
||||||
|
|
||||||
See [../apps/example/example_restconf.c] example_restconf_credentials() for
|
See [../example/main/example_restconf.c] example_restconf_credentials() for
|
||||||
an example of HTTP basic auth.
|
an example of HTTP basic auth.
|
||||||
|
|
||||||
## What about access control?
|
## What about access control?
|
||||||
|
|
|
||||||
|
|
@ -33,127 +33,46 @@
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
prefix = @prefix@
|
|
||||||
bindir = @bindir@
|
|
||||||
includedir = @includedir@
|
|
||||||
datarootdir = @datarootdir@
|
|
||||||
sysconfdir = @sysconfdir@
|
|
||||||
datarootdir = @datarootdir@
|
|
||||||
localstatedir = @localstatedir@
|
|
||||||
libdir = @exec_prefix@/lib
|
|
||||||
|
|
||||||
APPNAME = example
|
|
||||||
# Here is where example yang appears
|
|
||||||
CLIXON_DATADIR = @CLIXON_DATADIR@
|
|
||||||
# Install here if you want default clixon location:
|
|
||||||
CLIXON_DEFAULT_CONFIG = @CLIXON_DEFAULT_CONFIG@
|
|
||||||
|
|
||||||
CC = @CC@
|
CC = @CC@
|
||||||
CFLAGS = @CFLAGS@ -rdynamic -fPIC
|
CFLAGS = @CFLAGS@
|
||||||
INSTALLFLAGS = @INSTALLFLAGS@
|
LDFLAGS = @LDFLAGS@
|
||||||
with_restconf = @with_restconf@
|
LIBS = @LIBS@
|
||||||
|
|
||||||
INCLUDES = -I$(includedir) @INCLUDES@
|
SHELL = /bin/sh
|
||||||
CPPFLAGS = @CPPFLAGS@ -fPIC
|
|
||||||
|
|
||||||
BE_PLUGIN = $(APPNAME)_backend.so
|
SUBDIRS = main
|
||||||
BE2_PLUGIN = $(APPNAME)_backend_nacm.so
|
|
||||||
CLI_PLUGIN = $(APPNAME)_cli.so
|
|
||||||
NETCONF_PLUGIN = $(APPNAME)_netconf.so
|
|
||||||
RESTCONF_PLUGIN = $(APPNAME)_restconf.so
|
|
||||||
|
|
||||||
PLUGINS = $(BE_PLUGIN) $(BE2_PLUGIN) $(CLI_PLUGIN) $(NETCONF_PLUGIN)
|
.PHONY: all clean depend install $(SUBDIRS)
|
||||||
ifeq ($(with_restconf),yes)
|
|
||||||
PLUGINS += $(RESTCONF_PLUGIN)
|
|
||||||
endif
|
|
||||||
|
|
||||||
.PHONY: all clean depend install
|
all: $(SUBDIRS)
|
||||||
|
|
||||||
all: $(PLUGINS)
|
depend:
|
||||||
|
for i in $(SUBDIRS); \
|
||||||
|
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
|
||||||
|
|
||||||
.SUFFIXES: .c .o
|
$(SUBDIRS):
|
||||||
|
(cd $@; $(MAKE) $(MFLAGS) all)
|
||||||
|
|
||||||
# implicit rule
|
install-include:
|
||||||
.c.o:
|
for i in $(SUBDIRS); \
|
||||||
$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -c $<
|
do (cd $$i && $(MAKE) $(MFLAGS) $@||exit 1); done;
|
||||||
|
|
||||||
CLISPECS = $(APPNAME)_cli.cli
|
install:
|
||||||
|
for i in $(SUBDIRS); \
|
||||||
|
do (cd $$i && $(MAKE) $(MFLAGS) $@)||exit 1; done
|
||||||
|
|
||||||
YANGSPECS = clixon-example@2019-01-13.yang
|
uninstall:
|
||||||
|
for i in $(SUBDIRS); \
|
||||||
# Backend plugin
|
do (cd $$i; $(MAKE) $(MFLAGS) $@)||exit 1; done
|
||||||
BE_SRC = $(APPNAME)_backend.c
|
|
||||||
BE_OBJ = $(BE_SRC:%.c=%.o)
|
|
||||||
$(BE_PLUGIN): $(BE_OBJ)
|
|
||||||
$(CC) -Wall -shared -o $@ -lc $<
|
|
||||||
|
|
||||||
# Secondary NACM backend plugin
|
|
||||||
BE2_SRC = $(APPNAME)_backend_nacm.c
|
|
||||||
BE2_OBJ = $(BE2_SRC:%.c=%.o)
|
|
||||||
$(BE2_PLUGIN): $(BE2_OBJ)
|
|
||||||
$(CC) -Wall -shared -o $@ -lc $<
|
|
||||||
|
|
||||||
# CLI frontend plugin
|
|
||||||
CLI_SRC = $(APPNAME)_cli.c
|
|
||||||
CLI_OBJ = $(CLI_SRC:%.c=%.o)
|
|
||||||
$(CLI_PLUGIN): $(CLI_OBJ)
|
|
||||||
$(CC) -Wall -shared -o $@ -lc $^
|
|
||||||
|
|
||||||
# NETCONF frontend plugin
|
|
||||||
NETCONF_SRC = $(APPNAME)_netconf.c
|
|
||||||
NETCONF_OBJ = $(NETCONF_SRC:%.c=%.o)
|
|
||||||
$(NETCONF_PLUGIN): $(NETCONF_OBJ)
|
|
||||||
$(CC) -Wall -shared -o $@ -lc $^
|
|
||||||
|
|
||||||
# See configure.ac
|
|
||||||
# RESTCONF frontend plugin
|
|
||||||
RESTCONF_SRC = $(APPNAME)_restconf.c
|
|
||||||
RESTCONF_OBJ = $(RESTCONF_SRC:%.c=%.o)
|
|
||||||
$(RESTCONF_PLUGIN): $(RESTCONF_OBJ)
|
|
||||||
$(CC) -Wall -shared -o $@ -lc $^
|
|
||||||
|
|
||||||
SRC = $(BE_SRC) $(BE2_SRC) $(CLI_SRC) $(NETCONF_SRC)
|
|
||||||
SRC += $(RESTCONF_SRC)
|
|
||||||
|
|
||||||
OBJS = $(BE_OBJ) $(BE2_OBJ) $(CLI_OBJ) $(NETCONF_OBJ)
|
|
||||||
OBJS += $(RESTCONF_OBJ)
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(PLUGINS) $(OBJS)
|
for i in $(SUBDIRS); \
|
||||||
|
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
rm -f Makefile *~ .depend
|
rm -f Makefile *~ .depend
|
||||||
|
for i in $(SUBDIRS); \
|
||||||
|
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
|
||||||
|
|
||||||
install: $(YANGSPECS) $(CLISPECS) $(PLUGINS) $(APPNAME).xml
|
TAGS:
|
||||||
install -d -m 0755 $(DESTDIR)$(sysconfdir)
|
find $(srcdir) -name '*.[chyl]' -print | etags -
|
||||||
install -m 0644 $(APPNAME).xml $(DESTDIR)$(sysconfdir)
|
|
||||||
# install -m 0644 $(APPNAME).xml $(DESTDIR)$(CLIXON_DEFAULT_CONFIG)
|
|
||||||
install -d -m 0755 $(DESTDIR)$(datarootdir)/$(APPNAME)/yang
|
|
||||||
install -m 0644 $(YANGSPECS) $(DESTDIR)$(DESTDIR)$(CLIXON_DATADIR)
|
|
||||||
install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/cli
|
|
||||||
install -m 0644 $(INSTALLFLAGS) $(CLI_PLUGIN) $(DESTDIR)$(libdir)/$(APPNAME)/cli
|
|
||||||
install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/backend
|
|
||||||
install -m 0644 $(INSTALLFLAGS) $(BE_PLUGIN) $(BE2_PLUGIN) $(DESTDIR)$(libdir)/$(APPNAME)/backend
|
|
||||||
install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/netconf
|
|
||||||
install -m 0644 $(INSTALLFLAGS) $(NETCONF_PLUGIN) $(DESTDIR)$(libdir)/$(APPNAME)/netconf
|
|
||||||
ifeq ($(with_restconf),yes)
|
|
||||||
install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/restconf
|
|
||||||
install -m 0644 $(INSTALLFLAGS) $(RESTCONF_PLUGIN) $(DESTDIR)$(libdir)/$(APPNAME)/restconf
|
|
||||||
endif
|
|
||||||
install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/clispec
|
|
||||||
install -m 0644 $(CLISPECS) $(DESTDIR)$(libdir)/$(APPNAME)/clispec
|
|
||||||
install -d -m 0755 $(DESTDIR)$(localstatedir)/$(APPNAME)
|
|
||||||
|
|
||||||
uninstall:
|
|
||||||
rm -rf $(DESTDIR)$(sysconfdir)/$(APPNAME).xml
|
|
||||||
rm -rf $(DESTDIR)$(datarootdir)/$(APPNAME)
|
|
||||||
rm -rf $(DESTDIR)$(localstatedir)/$(APPNAME)
|
|
||||||
rm -rf $(DESTDIR)$(libdir)/$(APPNAME)
|
|
||||||
|
|
||||||
install-include:
|
|
||||||
|
|
||||||
depend:
|
|
||||||
$(CC) $(DEPENDFLAGS) $(INCLUDES) $(CFLAGS) -MM $(SRC) > .depend
|
|
||||||
|
|
||||||
#include .depend
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,325 +1,4 @@
|
||||||
# Clixon example
|
# Clixon examples
|
||||||
|
|
||||||
* [Content](#content)
|
Clixon have the following examples:
|
||||||
* [Compile and run](#compile)
|
* [Main example](main/README.md)
|
||||||
* [Using the CLI](#using-the-cli)
|
|
||||||
* [Using netconf](#using-netconf)
|
|
||||||
* [Streams](#streams)
|
|
||||||
* [RPC Operations](#rpc-operations)
|
|
||||||
* [State data](#state-data)
|
|
||||||
* [Authentication and NACM](#authentication-and-nacm)
|
|
||||||
* [Systemd](#systemd)
|
|
||||||
* [Docker](#docker)
|
|
||||||
* [Plugins](#plugins)
|
|
||||||
|
|
||||||
## Content
|
|
||||||
|
|
||||||
This directory contains a Clixon example which includes a simple example. It contains the following files:
|
|
||||||
* `example.xml` The configuration file. See [yang/clixon-config@<date>.yang](../yang/clixon-config@2018-10-21.yang) for the documentation of all available fields.
|
|
||||||
* `clixon-example@2019-01-13.yang` The yang spec of the example.
|
|
||||||
* `example_cli.cli` CLIgen specification.
|
|
||||||
* `example_cli.c` CLI callback plugin containing functions called in the cli file above: a generic callback (`mycallback`) and an example RPC call (`example_client_rpc`).
|
|
||||||
* `example_backend.c` Backend callback plugin including example of:
|
|
||||||
* transaction callbacks (validate/commit),
|
|
||||||
* notification,
|
|
||||||
* rpc handler
|
|
||||||
* state-data handler, ie non-config data
|
|
||||||
* `example_backend_nacm.c` Secondary backend plugin. Plugins are loaded alphabetically.
|
|
||||||
* `example_restconf.c` Restconf callback plugin containing an HTTP basic authentication callback
|
|
||||||
* `example_netconf.c` Netconf callback plugin
|
|
||||||
* `Makefile.in` Example makefile where plugins are built and installed
|
|
||||||
|
|
||||||
|
|
||||||
## Compile and run
|
|
||||||
|
|
||||||
Before you start,
|
|
||||||
* Make [group setup](../doc/FAQ.md#do-i-need-to-setup-anything-important)
|
|
||||||
* Setup [restconf](../doc/FAQ.md#how-do-i-use-restconf)
|
|
||||||
|
|
||||||
```
|
|
||||||
cd example
|
|
||||||
make && sudo make install
|
|
||||||
```
|
|
||||||
Start backend:
|
|
||||||
```
|
|
||||||
sudo clixon_backend -f /usr/local/etc/example.xml -s init
|
|
||||||
```
|
|
||||||
Edit cli:
|
|
||||||
```
|
|
||||||
clixon_cli -f /usr/local/etc/example.xml
|
|
||||||
```
|
|
||||||
Send netconf command:
|
|
||||||
```
|
|
||||||
clixon_netconf -f /usr/local/etc/example.xml
|
|
||||||
```
|
|
||||||
Start clixon restconf daemon
|
|
||||||
```
|
|
||||||
sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/example.xml " -s /bin/sh www-data
|
|
||||||
```
|
|
||||||
Send restconf command
|
|
||||||
```
|
|
||||||
curl -G http://127.0.0.1/restconf/data
|
|
||||||
```
|
|
||||||
|
|
||||||
## Using the CLI
|
|
||||||
|
|
||||||
The example CLI allows you to modify and view the data model using `set`, `delete` and `show` via generated code.
|
|
||||||
There are also many other commands available as examples. View the source file (example_cli.cli)[example_cli.cli] for more details.
|
|
||||||
|
|
||||||
The following example shows how to add an interface in candidate, validate and commit it to running, then look at it (as xml) and finally delete it.
|
|
||||||
```
|
|
||||||
clixon_cli -f /usr/local/etc/example.xml
|
|
||||||
cli> set interfaces interface eth9 ?
|
|
||||||
description enabled ipv4
|
|
||||||
ipv6 link-up-down-trap-enable type
|
|
||||||
cli> set interfaces interface eth9 type ex:eth
|
|
||||||
cli> validate
|
|
||||||
cli> commit
|
|
||||||
cli> show configuration xml
|
|
||||||
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
|
|
||||||
<interface>
|
|
||||||
<name>eth9</name>
|
|
||||||
<type>ex:eth</type>
|
|
||||||
<enabled>true</enabled>
|
|
||||||
</interface>
|
|
||||||
</interfaces>
|
|
||||||
cli> delete interfaces interface eth9
|
|
||||||
```
|
|
||||||
|
|
||||||
## Using Netconf
|
|
||||||
|
|
||||||
The following example shows how to set data using netconf:
|
|
||||||
```
|
|
||||||
<rpc><edit-config><target><candidate/></target><config>
|
|
||||||
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
|
|
||||||
<interface>
|
|
||||||
<name>eth1</name>
|
|
||||||
<enabled>true</enabled>
|
|
||||||
<ipv4>
|
|
||||||
<address>
|
|
||||||
<ip>9.2.3.4</ip>
|
|
||||||
<prefix-length>24</prefix-length>
|
|
||||||
</address>
|
|
||||||
</ipv4>
|
|
||||||
</interface>
|
|
||||||
</interfaces>
|
|
||||||
</config></edit-config></rpc>]]>]]>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Getting data using netconf
|
|
||||||
```
|
|
||||||
<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>
|
|
||||||
<rpc><get-config><source><candidate/></source><filter/></get-config></rpc>]]>]]>
|
|
||||||
<rpc><get-config><source><candidate/></source><filter type="xpath"/></get-config></rpc>]]>]]>
|
|
||||||
<rpc><get-config><source><candidate/></source><filter type="subtree"><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth9</name><type>ex:eth</type></interface></interfaces></data></filter></get-config></rpc>]]>]]>
|
|
||||||
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface"/></get-config></rpc>]]>]]>
|
|
||||||
<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>
|
|
||||||
```
|
|
||||||
## Restconf
|
|
||||||
|
|
||||||
Setup a web/reverse-proxy server.
|
|
||||||
For example, using nginx, install, and edit config file: /etc/nginx/sites-available/default:
|
|
||||||
```
|
|
||||||
server {
|
|
||||||
...
|
|
||||||
location / {
|
|
||||||
root /usr/share/nginx/html/restconf;
|
|
||||||
fastcgi_pass unix:/www-data/fastcgi_restconf.sock;
|
|
||||||
include fastcgi_params;
|
|
||||||
}
|
|
||||||
location /restconf {
|
|
||||||
fastcgi_pass unix:/www-data/fastcgi_restconf.sock;
|
|
||||||
include fastcgi_params;
|
|
||||||
}
|
|
||||||
location /streams {
|
|
||||||
fastcgi_pass unix:/www-data/fastcgi_restconf.sock;
|
|
||||||
include fastcgi_params;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Connection "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
Start nginx daemon
|
|
||||||
```
|
|
||||||
sudo /etc/init.d/nginx start
|
|
||||||
```
|
|
||||||
Start the clixon restconf daemon
|
|
||||||
```
|
|
||||||
sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/example.xml " -s /bin/sh www-data
|
|
||||||
```
|
|
||||||
then access using curl or wget:
|
|
||||||
```
|
|
||||||
curl -G http://127.0.0.1/restconf/data/ietf-interfaces:interfaces/interface=eth9/type
|
|
||||||
```
|
|
||||||
|
|
||||||
## Streams
|
|
||||||
|
|
||||||
The example has an EXAMPLE stream notification triggering every 5s. To start a notification
|
|
||||||
stream in the session using netconf, create a subscription:
|
|
||||||
```
|
|
||||||
<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream></create-subscription></rpc>]]>]]>
|
|
||||||
<rpc-reply><ok/></rpc-reply>]]>]]>
|
|
||||||
<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>2019-01-02T10:20:05.929272</eventTime><event><event-class>fault</event-class><reportingEntity><card>Ethernet0</card></reportingEntity><severity>major</severity></event></notification>]]>]]>
|
|
||||||
...
|
|
||||||
```
|
|
||||||
This can also be triggered via the CLI:
|
|
||||||
```
|
|
||||||
clixon_cli -f /usr/local/etc/example.xml
|
|
||||||
cli> notify
|
|
||||||
cli> event-class fault;
|
|
||||||
reportingEntity {
|
|
||||||
card Ethernet0;
|
|
||||||
}
|
|
||||||
severity major;
|
|
||||||
...
|
|
||||||
cli> no notify
|
|
||||||
cli>
|
|
||||||
```
|
|
||||||
|
|
||||||
Restconf support is also supported, see (restc)[../apps/restconf/README.md].
|
|
||||||
|
|
||||||
|
|
||||||
## RPC Operations
|
|
||||||
|
|
||||||
Clixon implements Yang RPC operations by an extension mechanism. The
|
|
||||||
extension mechanism enables you to add application-specific
|
|
||||||
operations. It works by adding user-defined callbacks for added
|
|
||||||
netconf operations. It is possible to use the extension mechanism
|
|
||||||
independent of the yang rpc construct, but it is recommended. The example includes an example:
|
|
||||||
|
|
||||||
Example using CLI:
|
|
||||||
```
|
|
||||||
clixon_cli -f /usr/local/etc/example.xml
|
|
||||||
cli> rpc ipv4
|
|
||||||
<rpc-reply><x xmlns="urn:example:clixon">ipv4</x><y xmlns="urn:example:clixon">42</y></rpc-reply>
|
|
||||||
```
|
|
||||||
Example using Netconf:
|
|
||||||
```
|
|
||||||
clixon_netconf -qf /usr/local/etc/example.xml
|
|
||||||
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><example xmlns="urn:example:clixon"><x>ipv4</x></example></rpc>]]>]]>
|
|
||||||
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><x xmlns="urn:example:clixon">ipv4</x><y xmlns="urn:example:clixon">42</y></rpc-reply>]]>]]>
|
|
||||||
```
|
|
||||||
Restconf (assuming nginx started):
|
|
||||||
```
|
|
||||||
sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/example.xml " -s /bin/sh www-data&
|
|
||||||
curl -X POST http://localhost/restconf/operations/clixon-example:example -d '{"clixon-example:input":{"x":"ipv4"}}'
|
|
||||||
{
|
|
||||||
"clixon-example:output": {
|
|
||||||
"x": "ipv4",
|
|
||||||
"y": "42"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Details
|
|
||||||
|
|
||||||
The example works by defining an RPC in clixon-example.yang:
|
|
||||||
```
|
|
||||||
rpc example {
|
|
||||||
description "Some example input/output for testing RFC7950 7.14.
|
|
||||||
RPC simply echoes the input for debugging.";
|
|
||||||
input {
|
|
||||||
leaf x {
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
In the CLI a netconf rpc call is constructed and sent to the backend: See `example_client_rpc()` in [example_cli.c] CLI plugin.
|
|
||||||
|
|
||||||
The clixon backend plugin [example_backend.c] reveives the netconf call and replies. This is made byregistering a callback handling handling the RPC:
|
|
||||||
```
|
|
||||||
static int
|
|
||||||
example_rpc(clicon_handle h,
|
|
||||||
cxobj *xe, /* Request: <rpc><xn></rpc> */
|
|
||||||
cbuf *cbret, /* Reply eg <rpc-reply>... */
|
|
||||||
void *arg, /* Client session */
|
|
||||||
void *regarg) /* Argument given at register */
|
|
||||||
{
|
|
||||||
/* code that echoes the request */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int
|
|
||||||
clixon_plugin_init(clicon_handle h)
|
|
||||||
{
|
|
||||||
...
|
|
||||||
rpc_callback_register(h, example_rpc, NULL, "example");
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## State data
|
|
||||||
|
|
||||||
Netconf <get> and restconf GET also returns state data(not only configuration data).
|
|
||||||
|
|
||||||
In YANG state data is specified with `config false;`. In the example,
|
|
||||||
`state` is state data, see (example.yang)[example.yang]
|
|
||||||
|
|
||||||
To return state data, you need to write a backend state data callback
|
|
||||||
with the name "plugin_statedata" where you return an XML tree with
|
|
||||||
state. This is then merged with config data by the system.
|
|
||||||
|
|
||||||
A static example of returning state data is in the example. Note that
|
|
||||||
a real example would poll or get the interface counters via a system
|
|
||||||
call, as well as use the "xpath" argument to identify the requested
|
|
||||||
state data.
|
|
||||||
|
|
||||||
The state data is enabled by starting the backend with: `-- -s`.
|
|
||||||
|
|
||||||
## Authentication and NACM
|
|
||||||
The example contains some stubs for authorization according to [RFC8341(NACM)](https://tools.ietf.org/html/rfc8341):
|
|
||||||
* A basic auth HTTP callback, see: example_restconf_credentials() containing three example users: andy, wilma, and guest, according to the examples in Appendix A in [RFC8341](https://tools.ietf.org/html/rfc8341).
|
|
||||||
* A NACM backend plugin reporting the mandatory NACM state variables.
|
|
||||||
|
|
||||||
## Systemd
|
|
||||||
|
|
||||||
Example systemd files for backend and restconf daemons are found under the systemd directory. Install them under /etc/systemd/system for example.
|
|
||||||
|
|
||||||
## Docker
|
|
||||||
|
|
||||||
See [../docker/system] for instructions on how to build this example
|
|
||||||
as a docker container.
|
|
||||||
|
|
||||||
## Plugins
|
|
||||||
|
|
||||||
The example includes a restonf, netconf, CLI and two backend plugins.
|
|
||||||
Each plugin is initiated with an API struct followed by a plugin init function.
|
|
||||||
The content of the API struct is different depending on what kind of plugin it is.
|
|
||||||
The plugin init function may also include registering RPC functions, see below is for a backend.
|
|
||||||
```
|
|
||||||
static clixon_plugin_api api = {
|
|
||||||
"example", /* name */
|
|
||||||
clixon_plugin_init,
|
|
||||||
plugin_start,
|
|
||||||
plugin_exit,
|
|
||||||
.ca_reset=plugin_reset,/* reset for extra XML at startup*/
|
|
||||||
.ca_statedata=plugin_statedata, /* statedata */
|
|
||||||
.ca_upgrade=example_upgrade, /* upgrade configuration */
|
|
||||||
.ca_trans_begin=NULL, /* trans begin */
|
|
||||||
.ca_trans_validate=transaction_validate,/* trans validate */
|
|
||||||
.ca_trans_complete=NULL, /* trans complete */
|
|
||||||
.ca_trans_commit=transaction_commit, /* trans commit */
|
|
||||||
.ca_trans_end=NULL, /* trans end */
|
|
||||||
.ca_trans_abort=NULL /* trans abort */
|
|
||||||
};
|
|
||||||
|
|
||||||
clixon_plugin_api *
|
|
||||||
clixon_plugin_init(clicon_handle h)
|
|
||||||
{
|
|
||||||
/* Optional callback registration for RPC calls */
|
|
||||||
rpc_callback_register(h, example_rpc, NULL, "example");
|
|
||||||
/* Return plugin API */
|
|
||||||
return &api; /* Return NULL on error */
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Here is a corresponding example for a CLI plugin:
|
|
||||||
```
|
|
||||||
static clixon_plugin_api api = {
|
|
||||||
"example", /* name */
|
|
||||||
clixon_plugin_init, /* init */
|
|
||||||
NULL, /* start */
|
|
||||||
NULL, /* exit */
|
|
||||||
.ca_prompt=NULL, /* cli_prompthook_t */
|
|
||||||
.ca_suspend=NULL, /* cligen_susp_cb_t */
|
|
||||||
.ca_interrupt=NULL, /* cligen_interrupt_cb_t */
|
|
||||||
};
|
|
||||||
```
|
|
||||||
159
example/main/Makefile.in
Normal file
159
example/main/Makefile.in
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
#
|
||||||
|
# ***** BEGIN LICENSE BLOCK *****
|
||||||
|
#
|
||||||
|
# Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
||||||
|
#
|
||||||
|
# This file is part of CLIXON
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
# Alternatively, the contents of this file may be used under the terms of
|
||||||
|
# the GNU General Public License Version 3 or later (the "GPL"),
|
||||||
|
# in which case the provisions of the GPL are applicable instead
|
||||||
|
# of those above. If you wish to allow use of your version of this file only
|
||||||
|
# under the terms of the GPL, and not to allow others to
|
||||||
|
# use your version of this file under the terms of Apache License version 2,
|
||||||
|
# indicate your decision by deleting the provisions above and replace them with
|
||||||
|
# the notice and other provisions required by the GPL. If you do not delete
|
||||||
|
# the provisions above, a recipient may use your version of this file under
|
||||||
|
# the terms of any one of the Apache License version 2 or the GPL.
|
||||||
|
#
|
||||||
|
# ***** END LICENSE BLOCK *****
|
||||||
|
#
|
||||||
|
VPATH = @srcdir@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
prefix = @prefix@
|
||||||
|
bindir = @bindir@
|
||||||
|
includedir = @includedir@
|
||||||
|
datarootdir = @datarootdir@
|
||||||
|
sysconfdir = @sysconfdir@
|
||||||
|
datarootdir = @datarootdir@
|
||||||
|
localstatedir = @localstatedir@
|
||||||
|
libdir = @exec_prefix@/lib
|
||||||
|
|
||||||
|
APPNAME = example
|
||||||
|
# Here is where example yang appears
|
||||||
|
CLIXON_DATADIR = @CLIXON_DATADIR@
|
||||||
|
# Install here if you want default clixon location:
|
||||||
|
CLIXON_DEFAULT_CONFIG = @CLIXON_DEFAULT_CONFIG@
|
||||||
|
|
||||||
|
CC = @CC@
|
||||||
|
CFLAGS = @CFLAGS@ -rdynamic -fPIC
|
||||||
|
INSTALLFLAGS = @INSTALLFLAGS@
|
||||||
|
with_restconf = @with_restconf@
|
||||||
|
|
||||||
|
INCLUDES = -I$(includedir) @INCLUDES@
|
||||||
|
CPPFLAGS = @CPPFLAGS@ -fPIC
|
||||||
|
|
||||||
|
BE_PLUGIN = $(APPNAME)_backend.so
|
||||||
|
BE2_PLUGIN = $(APPNAME)_backend_nacm.so
|
||||||
|
CLI_PLUGIN = $(APPNAME)_cli.so
|
||||||
|
NETCONF_PLUGIN = $(APPNAME)_netconf.so
|
||||||
|
RESTCONF_PLUGIN = $(APPNAME)_restconf.so
|
||||||
|
|
||||||
|
PLUGINS = $(BE_PLUGIN) $(BE2_PLUGIN) $(CLI_PLUGIN) $(NETCONF_PLUGIN)
|
||||||
|
ifeq ($(with_restconf),yes)
|
||||||
|
PLUGINS += $(RESTCONF_PLUGIN)
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: all clean depend install
|
||||||
|
|
||||||
|
all: $(PLUGINS)
|
||||||
|
|
||||||
|
.SUFFIXES: .c .o
|
||||||
|
|
||||||
|
# implicit rule
|
||||||
|
.c.o:
|
||||||
|
$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -c $<
|
||||||
|
|
||||||
|
CLISPECS = $(APPNAME)_cli.cli
|
||||||
|
|
||||||
|
YANGSPECS = clixon-example@2019-01-13.yang
|
||||||
|
|
||||||
|
# Backend plugin
|
||||||
|
BE_SRC = $(APPNAME)_backend.c
|
||||||
|
BE_OBJ = $(BE_SRC:%.c=%.o)
|
||||||
|
$(BE_PLUGIN): $(BE_OBJ)
|
||||||
|
$(CC) -Wall -shared -o $@ -lc $<
|
||||||
|
|
||||||
|
# Secondary NACM backend plugin
|
||||||
|
BE2_SRC = $(APPNAME)_backend_nacm.c
|
||||||
|
BE2_OBJ = $(BE2_SRC:%.c=%.o)
|
||||||
|
$(BE2_PLUGIN): $(BE2_OBJ)
|
||||||
|
$(CC) -Wall -shared -o $@ -lc $<
|
||||||
|
|
||||||
|
# CLI frontend plugin
|
||||||
|
CLI_SRC = $(APPNAME)_cli.c
|
||||||
|
CLI_OBJ = $(CLI_SRC:%.c=%.o)
|
||||||
|
$(CLI_PLUGIN): $(CLI_OBJ)
|
||||||
|
$(CC) -Wall -shared -o $@ -lc $^
|
||||||
|
|
||||||
|
# NETCONF frontend plugin
|
||||||
|
NETCONF_SRC = $(APPNAME)_netconf.c
|
||||||
|
NETCONF_OBJ = $(NETCONF_SRC:%.c=%.o)
|
||||||
|
$(NETCONF_PLUGIN): $(NETCONF_OBJ)
|
||||||
|
$(CC) -Wall -shared -o $@ -lc $^
|
||||||
|
|
||||||
|
# See configure.ac
|
||||||
|
# RESTCONF frontend plugin
|
||||||
|
RESTCONF_SRC = $(APPNAME)_restconf.c
|
||||||
|
RESTCONF_OBJ = $(RESTCONF_SRC:%.c=%.o)
|
||||||
|
$(RESTCONF_PLUGIN): $(RESTCONF_OBJ)
|
||||||
|
$(CC) -Wall -shared -o $@ -lc $^
|
||||||
|
|
||||||
|
SRC = $(BE_SRC) $(BE2_SRC) $(CLI_SRC) $(NETCONF_SRC)
|
||||||
|
SRC += $(RESTCONF_SRC)
|
||||||
|
|
||||||
|
OBJS = $(BE_OBJ) $(BE2_OBJ) $(CLI_OBJ) $(NETCONF_OBJ)
|
||||||
|
OBJS += $(RESTCONF_OBJ)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(PLUGINS) $(OBJS)
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
rm -f Makefile *~ .depend
|
||||||
|
|
||||||
|
install: $(YANGSPECS) $(CLISPECS) $(PLUGINS) $(APPNAME).xml
|
||||||
|
install -d -m 0755 $(DESTDIR)$(sysconfdir)
|
||||||
|
install -m 0644 $(APPNAME).xml $(DESTDIR)$(sysconfdir)
|
||||||
|
# install -m 0644 $(APPNAME).xml $(DESTDIR)$(CLIXON_DEFAULT_CONFIG)
|
||||||
|
install -d -m 0755 $(DESTDIR)$(datarootdir)/$(APPNAME)/yang
|
||||||
|
install -m 0644 $(YANGSPECS) $(DESTDIR)$(DESTDIR)$(CLIXON_DATADIR)
|
||||||
|
install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/cli
|
||||||
|
install -m 0644 $(INSTALLFLAGS) $(CLI_PLUGIN) $(DESTDIR)$(libdir)/$(APPNAME)/cli
|
||||||
|
install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/backend
|
||||||
|
install -m 0644 $(INSTALLFLAGS) $(BE_PLUGIN) $(BE2_PLUGIN) $(DESTDIR)$(libdir)/$(APPNAME)/backend
|
||||||
|
install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/netconf
|
||||||
|
install -m 0644 $(INSTALLFLAGS) $(NETCONF_PLUGIN) $(DESTDIR)$(libdir)/$(APPNAME)/netconf
|
||||||
|
ifeq ($(with_restconf),yes)
|
||||||
|
install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/restconf
|
||||||
|
install -m 0644 $(INSTALLFLAGS) $(RESTCONF_PLUGIN) $(DESTDIR)$(libdir)/$(APPNAME)/restconf
|
||||||
|
endif
|
||||||
|
install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/clispec
|
||||||
|
install -m 0644 $(CLISPECS) $(DESTDIR)$(libdir)/$(APPNAME)/clispec
|
||||||
|
install -d -m 0755 $(DESTDIR)$(localstatedir)/$(APPNAME)
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rm -rf $(DESTDIR)$(sysconfdir)/$(APPNAME).xml
|
||||||
|
rm -rf $(DESTDIR)$(datarootdir)/$(APPNAME)
|
||||||
|
rm -rf $(DESTDIR)$(localstatedir)/$(APPNAME)
|
||||||
|
rm -rf $(DESTDIR)$(libdir)/$(APPNAME)
|
||||||
|
|
||||||
|
install-include:
|
||||||
|
|
||||||
|
depend:
|
||||||
|
$(CC) $(DEPENDFLAGS) $(INCLUDES) $(CFLAGS) -MM $(SRC) > .depend
|
||||||
|
|
||||||
|
#include .depend
|
||||||
|
|
||||||
325
example/main/README.md
Normal file
325
example/main/README.md
Normal file
|
|
@ -0,0 +1,325 @@
|
||||||
|
# Clixon main example
|
||||||
|
|
||||||
|
* [Content](#content)
|
||||||
|
* [Compile and run](#compile)
|
||||||
|
* [Using the CLI](#using-the-cli)
|
||||||
|
* [Using netconf](#using-netconf)
|
||||||
|
* [Streams](#streams)
|
||||||
|
* [RPC Operations](#rpc-operations)
|
||||||
|
* [State data](#state-data)
|
||||||
|
* [Authentication and NACM](#authentication-and-nacm)
|
||||||
|
* [Systemd](#systemd)
|
||||||
|
* [Docker](#docker)
|
||||||
|
* [Plugins](#plugins)
|
||||||
|
|
||||||
|
## Content
|
||||||
|
|
||||||
|
This directory contains a Clixon example which includes a simple example. It contains the following files:
|
||||||
|
* `example.xml` The configuration file. See [yang/clixon-config@<date>.yang](../../yang/clixon-config@2018-10-21.yang) for the documentation of all available fields.
|
||||||
|
* `clixon-example@2019-01-13.yang` The yang spec of the example.
|
||||||
|
* `example_cli.cli` CLIgen specification.
|
||||||
|
* `example_cli.c` CLI callback plugin containing functions called in the cli file above: a generic callback (`mycallback`) and an example RPC call (`example_client_rpc`).
|
||||||
|
* `example_backend.c` Backend callback plugin including example of:
|
||||||
|
* transaction callbacks (validate/commit),
|
||||||
|
* notification,
|
||||||
|
* rpc handler
|
||||||
|
* state-data handler, ie non-config data
|
||||||
|
* `example_backend_nacm.c` Secondary backend plugin. Plugins are loaded alphabetically.
|
||||||
|
* `example_restconf.c` Restconf callback plugin containing an HTTP basic authentication callback
|
||||||
|
* `example_netconf.c` Netconf callback plugin
|
||||||
|
* `Makefile.in` Example makefile where plugins are built and installed
|
||||||
|
|
||||||
|
|
||||||
|
## Compile and run
|
||||||
|
|
||||||
|
Before you start,
|
||||||
|
* Make [group setup](../../doc/FAQ.md#do-i-need-to-setup-anything-important)
|
||||||
|
* Setup [restconf](../../doc/FAQ.md#how-do-i-use-restconf)
|
||||||
|
|
||||||
|
```
|
||||||
|
cd example
|
||||||
|
make && sudo make install
|
||||||
|
```
|
||||||
|
Start backend:
|
||||||
|
```
|
||||||
|
sudo clixon_backend -f /usr/local/etc/example.xml -s init
|
||||||
|
```
|
||||||
|
Edit cli:
|
||||||
|
```
|
||||||
|
clixon_cli -f /usr/local/etc/example.xml
|
||||||
|
```
|
||||||
|
Send netconf command:
|
||||||
|
```
|
||||||
|
clixon_netconf -f /usr/local/etc/example.xml
|
||||||
|
```
|
||||||
|
Start clixon restconf daemon
|
||||||
|
```
|
||||||
|
sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/example.xml " -s /bin/sh www-data
|
||||||
|
```
|
||||||
|
Send restconf command
|
||||||
|
```
|
||||||
|
curl -G http://127.0.0.1/restconf/data
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using the CLI
|
||||||
|
|
||||||
|
The example CLI allows you to modify and view the data model using `set`, `delete` and `show` via generated code.
|
||||||
|
There are also many other commands available as examples. View the source file (example_cli.cli)[example_cli.cli] for more details.
|
||||||
|
|
||||||
|
The following example shows how to add an interface in candidate, validate and commit it to running, then look at it (as xml) and finally delete it.
|
||||||
|
```
|
||||||
|
clixon_cli -f /usr/local/etc/example.xml
|
||||||
|
cli> set interfaces interface eth9 ?
|
||||||
|
description enabled ipv4
|
||||||
|
ipv6 link-up-down-trap-enable type
|
||||||
|
cli> set interfaces interface eth9 type ex:eth
|
||||||
|
cli> validate
|
||||||
|
cli> commit
|
||||||
|
cli> show configuration xml
|
||||||
|
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
|
||||||
|
<interface>
|
||||||
|
<name>eth9</name>
|
||||||
|
<type>ex:eth</type>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</interface>
|
||||||
|
</interfaces>
|
||||||
|
cli> delete interfaces interface eth9
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using Netconf
|
||||||
|
|
||||||
|
The following example shows how to set data using netconf:
|
||||||
|
```
|
||||||
|
<rpc><edit-config><target><candidate/></target><config>
|
||||||
|
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
|
||||||
|
<interface>
|
||||||
|
<name>eth1</name>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
<ipv4>
|
||||||
|
<address>
|
||||||
|
<ip>9.2.3.4</ip>
|
||||||
|
<prefix-length>24</prefix-length>
|
||||||
|
</address>
|
||||||
|
</ipv4>
|
||||||
|
</interface>
|
||||||
|
</interfaces>
|
||||||
|
</config></edit-config></rpc>]]>]]>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Getting data using netconf
|
||||||
|
```
|
||||||
|
<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>
|
||||||
|
<rpc><get-config><source><candidate/></source><filter/></get-config></rpc>]]>]]>
|
||||||
|
<rpc><get-config><source><candidate/></source><filter type="xpath"/></get-config></rpc>]]>]]>
|
||||||
|
<rpc><get-config><source><candidate/></source><filter type="subtree"><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth9</name><type>ex:eth</type></interface></interfaces></data></filter></get-config></rpc>]]>]]>
|
||||||
|
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface"/></get-config></rpc>]]>]]>
|
||||||
|
<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>
|
||||||
|
```
|
||||||
|
## Restconf
|
||||||
|
|
||||||
|
Setup a web/reverse-proxy server.
|
||||||
|
For example, using nginx, install, and edit config file: /etc/nginx/sites-available/default:
|
||||||
|
```
|
||||||
|
server {
|
||||||
|
...
|
||||||
|
location / {
|
||||||
|
root /usr/share/nginx/html/restconf;
|
||||||
|
fastcgi_pass unix:/www-data/fastcgi_restconf.sock;
|
||||||
|
include fastcgi_params;
|
||||||
|
}
|
||||||
|
location /restconf {
|
||||||
|
fastcgi_pass unix:/www-data/fastcgi_restconf.sock;
|
||||||
|
include fastcgi_params;
|
||||||
|
}
|
||||||
|
location /streams {
|
||||||
|
fastcgi_pass unix:/www-data/fastcgi_restconf.sock;
|
||||||
|
include fastcgi_params;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Connection "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Start nginx daemon
|
||||||
|
```
|
||||||
|
sudo /etc/init.d/nginx start
|
||||||
|
```
|
||||||
|
Start the clixon restconf daemon
|
||||||
|
```
|
||||||
|
sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/example.xml " -s /bin/sh www-data
|
||||||
|
```
|
||||||
|
then access using curl or wget:
|
||||||
|
```
|
||||||
|
curl -G http://127.0.0.1/restconf/data/ietf-interfaces:interfaces/interface=eth9/type
|
||||||
|
```
|
||||||
|
|
||||||
|
## Streams
|
||||||
|
|
||||||
|
The example has an EXAMPLE stream notification triggering every 5s. To start a notification
|
||||||
|
stream in the session using netconf, create a subscription:
|
||||||
|
```
|
||||||
|
<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream></create-subscription></rpc>]]>]]>
|
||||||
|
<rpc-reply><ok/></rpc-reply>]]>]]>
|
||||||
|
<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>2019-01-02T10:20:05.929272</eventTime><event><event-class>fault</event-class><reportingEntity><card>Ethernet0</card></reportingEntity><severity>major</severity></event></notification>]]>]]>
|
||||||
|
...
|
||||||
|
```
|
||||||
|
This can also be triggered via the CLI:
|
||||||
|
```
|
||||||
|
clixon_cli -f /usr/local/etc/example.xml
|
||||||
|
cli> notify
|
||||||
|
cli> event-class fault;
|
||||||
|
reportingEntity {
|
||||||
|
card Ethernet0;
|
||||||
|
}
|
||||||
|
severity major;
|
||||||
|
...
|
||||||
|
cli> no notify
|
||||||
|
cli>
|
||||||
|
```
|
||||||
|
|
||||||
|
Restconf support is also supported, see (restc)[../../apps/restconf/README.md].
|
||||||
|
|
||||||
|
|
||||||
|
## RPC Operations
|
||||||
|
|
||||||
|
Clixon implements Yang RPC operations by an extension mechanism. The
|
||||||
|
extension mechanism enables you to add application-specific
|
||||||
|
operations. It works by adding user-defined callbacks for added
|
||||||
|
netconf operations. It is possible to use the extension mechanism
|
||||||
|
independent of the yang rpc construct, but it is recommended. The example includes an example:
|
||||||
|
|
||||||
|
Example using CLI:
|
||||||
|
```
|
||||||
|
clixon_cli -f /usr/local/etc/example.xml
|
||||||
|
cli> rpc ipv4
|
||||||
|
<rpc-reply><x xmlns="urn:example:clixon">ipv4</x><y xmlns="urn:example:clixon">42</y></rpc-reply>
|
||||||
|
```
|
||||||
|
Example using Netconf:
|
||||||
|
```
|
||||||
|
clixon_netconf -qf /usr/local/etc/example.xml
|
||||||
|
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><example xmlns="urn:example:clixon"><x>ipv4</x></example></rpc>]]>]]>
|
||||||
|
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><x xmlns="urn:example:clixon">ipv4</x><y xmlns="urn:example:clixon">42</y></rpc-reply>]]>]]>
|
||||||
|
```
|
||||||
|
Restconf (assuming nginx started):
|
||||||
|
```
|
||||||
|
sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/example.xml " -s /bin/sh www-data&
|
||||||
|
curl -X POST http://localhost/restconf/operations/clixon-example:example -d '{"clixon-example:input":{"x":"ipv4"}}'
|
||||||
|
{
|
||||||
|
"clixon-example:output": {
|
||||||
|
"x": "ipv4",
|
||||||
|
"y": "42"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Details
|
||||||
|
|
||||||
|
The example works by defining an RPC in clixon-example.yang:
|
||||||
|
```
|
||||||
|
rpc example {
|
||||||
|
description "Some example input/output for testing RFC7950 7.14.
|
||||||
|
RPC simply echoes the input for debugging.";
|
||||||
|
input {
|
||||||
|
leaf x {
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
In the CLI a netconf rpc call is constructed and sent to the backend: See `example_client_rpc()` in [example_cli.c] CLI plugin.
|
||||||
|
|
||||||
|
The clixon backend plugin [example_backend.c] reveives the netconf call and replies. This is made byregistering a callback handling handling the RPC:
|
||||||
|
```
|
||||||
|
static int
|
||||||
|
example_rpc(clicon_handle h,
|
||||||
|
cxobj *xe, /* Request: <rpc><xn></rpc> */
|
||||||
|
cbuf *cbret, /* Reply eg <rpc-reply>... */
|
||||||
|
void *arg, /* Client session */
|
||||||
|
void *regarg) /* Argument given at register */
|
||||||
|
{
|
||||||
|
/* code that echoes the request */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int
|
||||||
|
clixon_plugin_init(clicon_handle h)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
rpc_callback_register(h, example_rpc, NULL, "example");
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## State data
|
||||||
|
|
||||||
|
Netconf <get> and restconf GET also returns state data(not only configuration data).
|
||||||
|
|
||||||
|
In YANG state data is specified with `config false;`. In the example,
|
||||||
|
`state` is state data, see (example.yang)[example.yang]
|
||||||
|
|
||||||
|
To return state data, you need to write a backend state data callback
|
||||||
|
with the name "plugin_statedata" where you return an XML tree with
|
||||||
|
state. This is then merged with config data by the system.
|
||||||
|
|
||||||
|
A static example of returning state data is in the example. Note that
|
||||||
|
a real example would poll or get the interface counters via a system
|
||||||
|
call, as well as use the "xpath" argument to identify the requested
|
||||||
|
state data.
|
||||||
|
|
||||||
|
The state data is enabled by starting the backend with: `-- -s`.
|
||||||
|
|
||||||
|
## Authentication and NACM
|
||||||
|
The example contains some stubs for authorization according to [RFC8341(NACM)](https://tools.ietf.org/html/rfc8341):
|
||||||
|
* A basic auth HTTP callback, see: example_restconf_credentials() containing three example users: andy, wilma, and guest, according to the examples in Appendix A in [RFC8341](https://tools.ietf.org/html/rfc8341).
|
||||||
|
* A NACM backend plugin reporting the mandatory NACM state variables.
|
||||||
|
|
||||||
|
## Systemd
|
||||||
|
|
||||||
|
Example systemd files for backend and restconf daemons are found under the systemd directory. Install them under /etc/systemd/system for example.
|
||||||
|
|
||||||
|
## Docker
|
||||||
|
|
||||||
|
See [../../docker/system] for instructions on how to build this example
|
||||||
|
as a docker container.
|
||||||
|
|
||||||
|
## Plugins
|
||||||
|
|
||||||
|
The example includes a restonf, netconf, CLI and two backend plugins.
|
||||||
|
Each plugin is initiated with an API struct followed by a plugin init function.
|
||||||
|
The content of the API struct is different depending on what kind of plugin it is.
|
||||||
|
The plugin init function may also include registering RPC functions, see below is for a backend.
|
||||||
|
```
|
||||||
|
static clixon_plugin_api api = {
|
||||||
|
"example", /* name */
|
||||||
|
clixon_plugin_init,
|
||||||
|
plugin_start,
|
||||||
|
plugin_exit,
|
||||||
|
.ca_reset=plugin_reset,/* reset for extra XML at startup*/
|
||||||
|
.ca_statedata=plugin_statedata, /* statedata */
|
||||||
|
.ca_upgrade=example_upgrade, /* upgrade configuration */
|
||||||
|
.ca_trans_begin=NULL, /* trans begin */
|
||||||
|
.ca_trans_validate=transaction_validate,/* trans validate */
|
||||||
|
.ca_trans_complete=NULL, /* trans complete */
|
||||||
|
.ca_trans_commit=transaction_commit, /* trans commit */
|
||||||
|
.ca_trans_end=NULL, /* trans end */
|
||||||
|
.ca_trans_abort=NULL /* trans abort */
|
||||||
|
};
|
||||||
|
|
||||||
|
clixon_plugin_api *
|
||||||
|
clixon_plugin_init(clicon_handle h)
|
||||||
|
{
|
||||||
|
/* Optional callback registration for RPC calls */
|
||||||
|
rpc_callback_register(h, example_rpc, NULL, "example");
|
||||||
|
/* Return plugin API */
|
||||||
|
return &api; /* Return NULL on error */
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Here is a corresponding example for a CLI plugin:
|
||||||
|
```
|
||||||
|
static clixon_plugin_api api = {
|
||||||
|
"example", /* name */
|
||||||
|
clixon_plugin_init, /* init */
|
||||||
|
NULL, /* start */
|
||||||
|
NULL, /* exit */
|
||||||
|
.ca_prompt=NULL, /* cli_prompthook_t */
|
||||||
|
.ca_suspend=NULL, /* cligen_susp_cb_t */
|
||||||
|
.ca_interrupt=NULL, /* cligen_interrupt_cb_t */
|
||||||
|
};
|
||||||
|
```
|
||||||
Loading…
Add table
Add a link
Reference in a new issue