diff --git a/.gitignore b/.gitignore index c191c5b0..4927378c 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ docker/Makefile docker/*/Makefile etc/Makefile example/Makefile +example/*/Makefile lib/Makefile lib/*/Makefile test/Makefile diff --git a/CHANGELOG.md b/CHANGELOG.md index e5b54800..7edfe80e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ ### API changes on existing features (you may need to change your code) +* The directory `docker/system` has been moved to `docker/main`, to reflect that it runs the main example. * xmldb_get() removed "config" parameter: * Change all calls to dbget from: `xmldb_get(h, db, xpath, 0|1, &xret, msd)` to `xmldb_get(h, db, xpath, &xret, msd)` * Structural change: removed datastore plugin and directory, and merged into regular clixon lib code. @@ -101,6 +102,7 @@ ### Minor changes +* A new "hello world" example is added * Optimized validation of large lists * New xmldb_get1() returning actual cache - not a copy. This has lead to some householding instead of just deleting the copy * xml_diff rewritten to work linearly instead of O(2) diff --git a/configure b/configure index 64161685..bc0eed46 100755 --- a/configure +++ b/configure @@ -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 example/main/Makefile extras/rpm/Makefile docker/Makefile docker/system/Makefile docker/base/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 example/hello/Makefile extras/rpm/Makefile docker/Makefile docker/main/Makefile docker/base/Makefile util/Makefile yang/Makefile yang/clixon/Makefile yang/standard/Makefile doc/Makefile test/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -5155,9 +5155,10 @@ do "etc/clixonrc") CONFIG_FILES="$CONFIG_FILES etc/clixonrc" ;; "example/Makefile") CONFIG_FILES="$CONFIG_FILES example/Makefile" ;; "example/main/Makefile") CONFIG_FILES="$CONFIG_FILES example/main/Makefile" ;; + "example/hello/Makefile") CONFIG_FILES="$CONFIG_FILES example/hello/Makefile" ;; "extras/rpm/Makefile") CONFIG_FILES="$CONFIG_FILES extras/rpm/Makefile" ;; "docker/Makefile") CONFIG_FILES="$CONFIG_FILES docker/Makefile" ;; - "docker/system/Makefile") CONFIG_FILES="$CONFIG_FILES docker/system/Makefile" ;; + "docker/main/Makefile") CONFIG_FILES="$CONFIG_FILES docker/main/Makefile" ;; "docker/base/Makefile") CONFIG_FILES="$CONFIG_FILES docker/base/Makefile" ;; "util/Makefile") CONFIG_FILES="$CONFIG_FILES util/Makefile" ;; "yang/Makefile") CONFIG_FILES="$CONFIG_FILES yang/Makefile" ;; diff --git a/configure.ac b/configure.ac index d7e2e741..47b79aa2 100644 --- a/configure.ac +++ b/configure.ac @@ -248,10 +248,11 @@ AC_OUTPUT(Makefile etc/Makefile etc/clixonrc example/Makefile - example/main/Makefile + example/main/Makefile + example/hello/Makefile extras/rpm/Makefile docker/Makefile - docker/system/Makefile + docker/main/Makefile docker/base/Makefile util/Makefile yang/Makefile diff --git a/doc/FAQ.md b/doc/FAQ.md index 0afffdc0..a5c81437 100644 --- a/doc/FAQ.md +++ b/doc/FAQ.md @@ -6,6 +6,7 @@ * [Is Clixon extendible?](#is-clixon-extendible) * [Which programming language is used?](#which-programming-language-is-used) * [How to best understand Clixon?](#how-to-best-understand-clixon) + * [Hello world?](#hello-world) * [How do you build and install Clixon (and the example)?](how-do-you-build-and-install-clixon) * [How do I run Clixon example commands?](#how-do-i-run-clixon-example-commands) * [Do I need to setup anything? (IMPORTANT)](#do-i-need-to-setup-anything)) @@ -67,6 +68,10 @@ specification uses [CLIgen](http://github.com/olofhagsand/cligen) ## How to best understand Clixon? Run the Clixon example, in the [example](../example) directory. +## Hello world? + +One of the examples is [a hello world example](../example/hello). Please start with that. + ## How do you build and install Clixon? Clixon: ``` diff --git a/docker/Makefile.in b/docker/Makefile.in index 51443a4e..83bb7191 100644 --- a/docker/Makefile.in +++ b/docker/Makefile.in @@ -41,7 +41,7 @@ LIBS = @LIBS@ SHELL = /bin/sh SUBDIRS = base -SUBDIRS += system +SUBDIRS += main #SUBDIRS += cluster .PHONY: all clean distclean depend install-include install uninstall test $(SUBDIRS) diff --git a/docker/README.md b/docker/README.md index ad190774..117705ee 100644 --- a/docker/README.md +++ b/docker/README.md @@ -2,6 +2,6 @@ This directory contains sub-directories with examples of Clixon docker images: - * [base](base/README.md) Clixon base image - * [system](system/README.md) Example and test application + * [base](base/README.md) Clixon base image + * [main](main/README.md) Main example and test application diff --git a/docker/base/README.md b/docker/base/README.md index de26e094..0acdca79 100644 --- a/docker/base/README.md +++ b/docker/base/README.md @@ -8,7 +8,7 @@ The clixon docker base image can be used to build clixon applications. It has all the whole code for a clixon release which it downloads from git. -See [clixon-system](../system/README.md) for a more complete clixon image. +See [clixon-system](../main/README.md) for a more complete clixon image. ## Build and push @@ -20,7 +20,7 @@ You may also do `make push` if you want to push the image, but you may then cons ## Example run -The base container is a minimal and primitive example. Look at the [clixon-system](../system) for a more stream-lined application. +The base container is a minimal and primitive example. Look at the [clixon-system](../main) for a more stream-lined application. The following shows a simple example of how to run the example application. First, the container is started with the backend running: diff --git a/docker/system/Dockerfile b/docker/main/Dockerfile similarity index 100% rename from docker/system/Dockerfile rename to docker/main/Dockerfile diff --git a/docker/system/Makefile.in b/docker/main/Makefile.in similarity index 100% rename from docker/system/Makefile.in rename to docker/main/Makefile.in diff --git a/docker/system/README.md b/docker/main/README.md similarity index 100% rename from docker/system/README.md rename to docker/main/README.md diff --git a/docker/system/cleanup.sh b/docker/main/cleanup.sh similarity index 100% rename from docker/system/cleanup.sh rename to docker/main/cleanup.sh diff --git a/docker/system/start.sh b/docker/main/start.sh similarity index 100% rename from docker/system/start.sh rename to docker/main/start.sh diff --git a/docker/system/startsystem.sh b/docker/main/startsystem.sh similarity index 100% rename from docker/system/startsystem.sh rename to docker/main/startsystem.sh diff --git a/example/README.md b/example/README.md index 709cf2dd..58cdc401 100644 --- a/example/README.md +++ b/example/README.md @@ -1,4 +1,6 @@ # Clixon examples Clixon have the following examples: - * [Main example](main/README.md) \ No newline at end of file + * [Main example](main/README.md) + * [Hello world](hello/README.md) + \ No newline at end of file diff --git a/example/hello/Makefile.in b/example/hello/Makefile.in new file mode 100644 index 00000000..7ba400aa --- /dev/null +++ b/example/hello/Makefile.in @@ -0,0 +1,167 @@ +# +# ***** 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 = hello + +# 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 +CLI_PLUGIN = $(APPNAME)_cli.so +NETCONF_PLUGIN = $(APPNAME)_netconf.so +RESTCONF_PLUGIN = $(APPNAME)_restconf.so + +PLUGINS = $(BE_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-hello@2019-04-17.yang + +# CLI frontend plugin (see also install rule) +#CLI_SRC = $(APPNAME)_cli.c +CLI_OBJ = $(CLI_SRC:%.c=%.o) +$(CLI_PLUGIN): $(CLI_OBJ) + $(CC) -Wall -shared -o $@ -lc $^ + +# Backend plugin (see also install rule) +#BE_SRC = $(APPNAME)_backend.c +BE_OBJ = $(BE_SRC:%.c=%.o) +$(BE_PLUGIN): $(BE_OBJ) + $(CC) -Wall -shared -o $@ -lc $< + +# NETCONF frontend plugin (see also install rule) +#NETCONF_SRC = $(APPNAME)_netconf.c +NETCONF_OBJ = $(NETCONF_SRC:%.c=%.o) +$(NETCONF_PLUGIN): $(NETCONF_OBJ) + $(CC) -Wall -shared -o $@ -lc $^ + +# See configure.ac for disabling restconf +# RESTCONF frontend plugin (see also install rule) +#RESTCONF_SRC = $(APPNAME)_restconf.c +RESTCONF_OBJ = $(RESTCONF_SRC:%.c=%.o) +$(RESTCONF_PLUGIN): $(RESTCONF_OBJ) + $(CC) -Wall -shared -o $@ -lc $^ + +SRC = $(BE_SRC) $(CLI_SRC) $(NETCONF_SRC) +SRC += $(RESTCONF_SRC) + +OBJS = $(BE_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 -m 0644 $(APPNAME).xml $(DESTDIR)$(CLIXON_DEFAULT_CONFIG) + install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME) + install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/clispec + install -m 0644 $(CLISPECS) $(DESTDIR)$(libdir)/$(APPNAME)/clispec + install -d -m 0755 $(DESTDIR)$(datarootdir)/$(APPNAME)/yang + install -m 0644 $(YANGSPECS) $(DESTDIR)$(DESTDIR)$(CLIXON_DATADIR) + install -d -m 0755 $(DESTDIR)$(localstatedir)/$(APPNAME) + +# Uncomment for installing config file in /usr/local/etc instead +# install -d -m 0755 $(DESTDIR)$(sysconfdir) +# install -m 0644 $(APPNAME).xml $(DESTDIR)$(sysconfdir) + +# Uncomment for installing cli plugin (see CLI_SRC) +# install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/cli +# install -m 0644 $(INSTALLFLAGS) $(CLI_PLUGIN) $(DESTDIR)$(libdir)/$(APPNAME)/cli + +# Uncomment for installing backend plugin (see BE_SRC) +# install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/backend +# install -m 0644 $(INSTALLFLAGS) $(BE_PLUGIN) $(DESTDIR)$(libdir)/$(APPNAME)/backend + +# Uncomment for installing netconf plugin (see NETCONF_SRC) +# install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/netconf +# install -m 0644 $(INSTALLFLAGS) $(NETCONF_PLUGIN) $(DESTDIR)$(libdir)/$(APPNAME)/netconf + +# Uncomment for installing restconf plugin (see RESTCONF_SRC). The conditional is +# because it is an option to disable restconf +#ifeq ($(with_restconf),yes) +# install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/restconf +# install -m 0644 $(INSTALLFLAGS) $(RESTCONF_PLUGIN) $(DESTDIR)$(libdir)/$(APPNAME)/restconf +#endif + +uninstall: + rm -rf $(DESTDIR)$(CLIXON_DEFAULT_CONFIG) + rm -rf $(DESTDIR)$(libdir)/$(APPNAME) + rm -rf $(DESTDIR)$(localstatedir)/$(APPNAME) + rm -rf $(DESTDIR)$(datarootdir)/$(APPNAME) + + +install-include: + +depend: + $(CC) $(DEPENDFLAGS) $(INCLUDES) $(CFLAGS) -MM $(SRC) > .depend + +#include .depend + diff --git a/example/hello/README.md b/example/hello/README.md new file mode 100644 index 00000000..0c7c3a0b --- /dev/null +++ b/example/hello/README.md @@ -0,0 +1,111 @@ +# Clixon hello world example + + * [Content](#content) + * [Compile and run](#compile) + * [Using the CLI](#using-the-cli) + * [Netconf](#netconf) + * [Restconf](#restconf) + * [Next steps](#next-steps) + +## Content + +This directory contains a Clixon example which includes a simple example. It contains the following files: +* `hello.xml` The configuration file. See [yang/clixon-config@.yang](../../yang/clixon-config@2019-03-05.yang) for the documentation of all available fields. +* `clixon-hello@2019-04-17.yang` The yang spec of the example. +* `hello_cli.cli` CLIgen specification. +* `Makefile.in` Example makefile where plugins are built and installed +* `README.md` This file + + +## Compile and run + +Before you start, +* Make [group setup](../../doc/FAQ.md#do-i-need-to-setup-anything-important) + +``` + make && sudo make install +``` +Start backend in the background: +``` + sudo clixon_backend +``` +Start cli: +``` + clixon_cli +``` + +## Using the CLI + +The example CLI allows you to modify and view the data model using `set`, `delete` and `show` via generated code. + +The following example shows how to add a very simple configuration `hello world` using the generated CLI. The config is added to the candidate database, shown, committed to running, and then deleted. +``` + olof@vandal> clixon_cli + cli> set + hello + cli> set hello world + cli> show configuration + hello world; + cli> commit + cli> delete + all Delete whole candidate configuration + hello + cli> delete hello + cli> show configuration + cli> commit + cli> quit + olof@vandal> +``` + +## Netconf + +Clixon also provides a Netconf interface. The following example starts a netconf client form the shell, adds the hello world config, commits it, and shows it: +``` + olof@vandal> clixon_netconf -q + ]]>]]> + ]]>]]> + ]]>]]> + ]]>]]> + ]]>]]> + ]]>]]> +olof@vandal> +``` + +## Restconf + +Clixon also provides a Restconf interface. A reverse proxy needs to be configured. There are [instructions how to setup Nginx](../../doc/FAQ.md#how-do-i-use-restconf) for Clixon. + +Start restconf daemon +``` + sudo su -c "/www-data/clixon_restconf" -s /bin/sh www-data & +``` + +Start sending restconf commands (using Curl): +``` + olof@vandal> curl -X POST http://localhost/restconf/data -d '{"clixon-hello:hello":{"world":null}}' + olof@vandal> curl -X GET http://localhost/restconf/data + { + "data": { + "clixon-hello:hello": { + "world": null + } + } + } +``` + +## Next steps + +The hello world example only has a Yang spec and a template CLI +spec. For more advanced applications, customized backend, cli, netconf +and restconf code callbacks becomes necessary. + +Further, you may want to add upgrade, RPC:s, state data, notification +streams, authentication and authorization. The [main example](../main) +contains examples for such capabilities. + +There are also [container examples](../../docker) and lots more. + + + + + diff --git a/example/hello/clixon-hello@2019-04-17.yang b/example/hello/clixon-hello@2019-04-17.yang new file mode 100644 index 00000000..89c30acd --- /dev/null +++ b/example/hello/clixon-hello@2019-04-17.yang @@ -0,0 +1,14 @@ +module clixon-hello { + yang-version 1.1; + namespace "urn:example:hello"; + prefix he; + revision 2019-04-17 { + description + "Clixon hello world example"; + } + container hello{ + container world{ + presence true; + } + } +} diff --git a/example/hello/hello.xml b/example/hello/hello.xml new file mode 100644 index 00000000..1210e1f2 --- /dev/null +++ b/example/hello/hello.xml @@ -0,0 +1,13 @@ + + /usr/local/etc/example.xml + *:* + /usr/local/share/clixon + clixon-hello + hello + /usr/local/lib/hello/clispec + /usr/local/var/hello.sock + /usr/local/var/hello.pidfile + /usr/local/var/hello + init + false + diff --git a/example/hello/hello_cli.cli b/example/hello/hello_cli.cli new file mode 100644 index 00000000..a3b469f5 --- /dev/null +++ b/example/hello/hello_cli.cli @@ -0,0 +1,54 @@ +# Common CLI syntax for both server and PMNode operatio mode +CLICON_MODE="hello"; +CLICON_PROMPT="cli> "; + +# Reference generated data model +set @datamodel, cli_set(); +merge @datamodel, cli_merge(); +create @datamodel, cli_create(); +delete("Delete a configuration item") @datamodel, cli_del(); + +validate("Validate changes"), cli_validate(); +commit("Commit the changes"), cli_commit(); +quit("Quit"), cli_quit(); +delete("Delete a configuration item") all("Delete whole candidate configuration"), delete_all("candidate"); + +startup("Store running as startup config"), db_copy("running", "startup"); +no("Negate or remove") debug("Debugging parts of the system"), cli_debug_cli((int32)0); +debug("Debugging parts of the system"), cli_debug_cli((int32)1);{ + level("Set debug level: 1..n") ("Set debug level (0..n)"), cli_debug_backend(); +} +discard("Discard edits (rollback 0)"), discard_changes(); +compare("Compare running and candidate"), compare_dbs((int32)1); + +show("Show a particular state of the system"){ + xpath("Show configuration") ("XPATH expression"), show_conf_xpath("candidate"); + version("Show version"), cli_show_version("candidate", "text", "/"); + compare("Compare candidate and running databases"), compare_dbs((int32)0);{ + xml("Show comparison in xml"), compare_dbs((int32)0); + text("Show comparison in text"), compare_dbs((int32)1); + } + configuration("Show configuration"), cli_show_config("candidate", "text", "/");{ + xml("Show configuration as XML"), cli_show_config("candidate", "xml", "/");{ + @datamodel, cli_show_auto("candidate", "xml"); + } + cli("Show configuration as CLI commands"), cli_show_config("candidate", "cli", "/");{ + @datamodel, cli_show_auto("candidate", "cli"); + } + netconf("Show configuration as netconf edit-config operation"), cli_show_config("candidate", "netconf", "/");{ + @datamodel, cli_show_auto("candidate", "netconf"); + } + text("Show configuration as text"), cli_show_config("candidate","text","/");{ + @datamodel, cli_show_auto("candidate", "text"); + } + json("Show configuration as JSON"), cli_show_config("candidate", "json", "/");{ + @datamodel, cli_show_auto("candidate", "json"); + } + } +} + +save("Save candidate configuration to XML file") ("Filename (local filename)"), save_config_file("candidate","filename"); +load("Load configuration from XML file") ("Filename (local filename)"),load_config_file("filename", "replace");{ + replace("Replace candidate with file contents"), load_config_file("filename", "replace"); + merge("Merge file with existent candidate"), load_config_file("filename", "merge"); +} diff --git a/example/main/README.md b/example/main/README.md index 76f9eb02..16215237 100644 --- a/example/main/README.md +++ b/example/main/README.md @@ -15,7 +15,7 @@ ## 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@.yang](../../yang/clixon-config@2018-10-21.yang) for the documentation of all available fields. +* `example.xml` The configuration file. See [yang/clixon-config@.yang](../../yang/clixon-config@2019-03-05.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`).