From e729c82c32be801ad791143e909db2b645b3fb5f Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Wed, 29 Mar 2023 13:35:23 +0200 Subject: [PATCH] klinfix: Initial add Infix integration of klish and klish-plugin-sysrepo. Initially we add: More flexible management of running vs. startup: Instead of always committing changes both to running and startup, commit only modifies running. To persist changes to startup, the copy command is introduced. This lets the user copy from factory/startup/running to startup/running at any time. Well-known verbs like abort, leave, end, etc. --- configs/aarch64_defconfig | 1 + configs/amd64_defconfig | 1 + package/Config.in | 1 + package/klinfix/Config.in | 8 + package/klinfix/klinfix.mk | 14 ++ package/klish-plugin-sysrepo/Config.in | 1 + package/klish/Config.in | 1 + src/klinfix/.gitignore | 33 ++++ src/klinfix/Makefile.am | 3 + src/klinfix/README.md | 74 +++++++++ src/klinfix/autogen.sh | 3 + src/klinfix/configure.ac | 33 ++++ src/klinfix/src/Makefile.am | 9 ++ src/klinfix/src/klinfix.c | 155 ++++++++++++++++++ src/klinfix/xml/Makefile.am | 2 + src/klinfix/xml/infix.xml | 215 +++++++++++++++++++++++++ 16 files changed, 554 insertions(+) create mode 100644 package/klinfix/Config.in create mode 100644 package/klinfix/klinfix.mk create mode 100644 src/klinfix/.gitignore create mode 100644 src/klinfix/Makefile.am create mode 100644 src/klinfix/README.md create mode 100755 src/klinfix/autogen.sh create mode 100644 src/klinfix/configure.ac create mode 100644 src/klinfix/src/Makefile.am create mode 100644 src/klinfix/src/klinfix.c create mode 100644 src/klinfix/xml/Makefile.am create mode 100644 src/klinfix/xml/infix.xml diff --git a/configs/aarch64_defconfig b/configs/aarch64_defconfig index 887fa2b4..620cf446 100644 --- a/configs/aarch64_defconfig +++ b/configs/aarch64_defconfig @@ -131,6 +131,7 @@ BR2_PACKAGE_FINIT_PLUGIN_RTC=y BR2_PACKAGE_FINIT_PLUGIN_TTY=y BR2_PACKAGE_FINIT_PLUGIN_URANDOM=y BR2_PACKAGE_IFUPDOWN_NG=y +BR2_PACKAGE_KLINFIX=y BR2_PACKAGE_KLISH=y BR2_PACKAGE_KLISH_PLUGIN_SYSREPO=y BR2_PACKAGE_P_NET=y diff --git a/configs/amd64_defconfig b/configs/amd64_defconfig index 5356cafe..60170bdc 100644 --- a/configs/amd64_defconfig +++ b/configs/amd64_defconfig @@ -134,6 +134,7 @@ BR2_PACKAGE_FINIT_PLUGIN_RTC=y BR2_PACKAGE_FINIT_PLUGIN_TTY=y BR2_PACKAGE_FINIT_PLUGIN_URANDOM=y BR2_PACKAGE_IFUPDOWN_NG=y +BR2_PACKAGE_KLINFIX=y BR2_PACKAGE_KLISH=y BR2_PACKAGE_KLISH_PLUGIN_SYSREPO=y BR2_PACKAGE_P_NET=y diff --git a/package/Config.in b/package/Config.in index a0a0a24f..f9e24aff 100644 --- a/package/Config.in +++ b/package/Config.in @@ -6,6 +6,7 @@ source "$BR2_EXTERNAL_INFIX_PATH/package/faux/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/finit/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/ifupdown2/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/ifupdown-ng/Config.in" +source "$BR2_EXTERNAL_INFIX_PATH/package/klinfix/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/klish/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/klish-plugin-sysrepo/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/mdnsd/Config.in" diff --git a/package/klinfix/Config.in b/package/klinfix/Config.in new file mode 100644 index 00000000..933d1289 --- /dev/null +++ b/package/klinfix/Config.in @@ -0,0 +1,8 @@ +config BR2_PACKAGE_KLINFIX + bool "klinfix" + select BR2_PACKAGE_KLISH + select BR2_PACKAGE_KLISH_PLUGIN_SYSREPO + select BR2_PACKAGE_SYSREPO + help + A plugin to klish with an opinionated config and some + command extensions, suitable for systems running Infix. diff --git a/package/klinfix/klinfix.mk b/package/klinfix/klinfix.mk new file mode 100644 index 00000000..d2f88539 --- /dev/null +++ b/package/klinfix/klinfix.mk @@ -0,0 +1,14 @@ +################################################################################ +# +# klinfix +# +################################################################################ + +KLINFIX_VERSION = 1.0 +KLINFIX_LICENSE = BSD-3-Clause +KLINFIX_SITE_METHOD = local +KLINFIX_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/klinfix +KLINFIX_DEPENDENCIES = klish-plugin-sysrepo +KLINFIX_AUTORECONF = YES + +$(eval $(autotools-package)) diff --git a/package/klish-plugin-sysrepo/Config.in b/package/klish-plugin-sysrepo/Config.in index b61e20b9..b9c735e8 100644 --- a/package/klish-plugin-sysrepo/Config.in +++ b/package/klish-plugin-sysrepo/Config.in @@ -13,6 +13,7 @@ config BR2_PACKAGE_KLISH_PLUGIN_SYSREPO config BR2_PACKAGE_KLISH_PLUGIN_SYSREPO_XML bool "install xml" depends on BR2_PACKAGE_KLISH_PLUGIN_SYSREPO + depends on !BR2_PACKAGE_KLINFIX default y help Install the default XML spec bundled with the project, which diff --git a/package/klish/Config.in b/package/klish/Config.in index 9f55b085..e3f03e0e 100644 --- a/package/klish/Config.in +++ b/package/klish/Config.in @@ -12,6 +12,7 @@ config BR2_PACKAGE_KLISH config BR2_PACKAGE_KLISH_DEFAULT_XML bool "install xml" depends on BR2_PACKAGE_KLISH + depends on !BR2_PACKAGE_KLINFIX default y help Install a small XML spec containing a definition of an diff --git a/src/klinfix/.gitignore b/src/klinfix/.gitignore new file mode 100644 index 00000000..e9e8e747 --- /dev/null +++ b/src/klinfix/.gitignore @@ -0,0 +1,33 @@ +*~ +*.o +*.la +*.lo +*.so +.deps +.libs + +/aclocal.m4 +/autom4te.cache/ +/aux +/clixon.xml +/compile +/config.h +/config.h.in +/config.guess +/config.log +/config.status +/config.sub +/configure +/depcomp +/install-sh +/libtool +/ltmain.sh +/m4 +/missing + +GPATH +GRTAGS +GTAGS +Makefile +Makefile.in + diff --git a/src/klinfix/Makefile.am b/src/klinfix/Makefile.am new file mode 100644 index 00000000..cb106dee --- /dev/null +++ b/src/klinfix/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = src xml +DISTCLEANFILES = *~ *.d +ACLOCAL_AMFLAGS = -I m4 diff --git a/src/klinfix/README.md b/src/klinfix/README.md new file mode 100644 index 00000000..7dfcc518 --- /dev/null +++ b/src/klinfix/README.md @@ -0,0 +1,74 @@ +Infix Extensions to klish-plugin-sysrepo +---------------------------------------- + +Tailor `klish` and `klish-plugin-sysrepo` to suit Infix. The resulting +CLI is, in many respects, still very similar to Juniper's JunOS, since +that is also the primary inspiration for klish, with some additions +and modifications. + +Broadly speaking, the CLI is split up in two major modes: + +- Admin/Exec: This is the default mode, where operational commands can + be issued. +- Configure: Where a new candidate configuration is prepared. + + +### Admin/Exec Mode + +The following table lists the available commands: + +| Command | Description | Hotkey | +|--------------------|---------------------------------------|--------| +| `configure` | Enter configuration mode | | +| `copy ` | Copy `` to `` | | +| `exit` | Exit | `C-d` | +| `logout` | Alias for `exit` | | +| `shell` | Start system shell | | +| `show ` | Show various configuration and status | | + +#### Copy Command + +`copy ` + +Where `` is one of: +- `factory-config` +- `startup-config` +- `running-config` + +And `` is one of: +- `startup-config` +- `running-config` + +#### Show Command + +`show ` + +The following table lists the available items: + +| Item | Description | +|------------------|--------------------------------------| +| `running-config` | Show the active system configuration | +| | | + + +### Configure + +The following table lists the available commands: + +| Command | Description | Hotkey | +|------------|--------------------------------------------------------------|--------| +| `abort` | Abandon candidate | `C-d` | +| `check` | Validate candidate | | +| `commit` | Commit current candidate to running-config | | +| `delete` | Delete configuration setting(s) | | +| `diff` | Summarize uncommitted changes | | +| `do` | Execute operational mode command | | +| `edit` | Descend to the specified configuration node | | +| `exit` | Ascend to the parent configuration node, or abort (from top) | | +| `leave` | Finalize candidate and apply to running-config | `C-z` | +| `no` | Alias for delete | | +| `rollback` | Restore candidate to running-config | | +| `set` | Set configuration setting | | +| `show` | Show configuration | | +| `top` | Ascend to the configuration root | | +| `up` | Ascend to the parent configuration node | `C-c` | diff --git a/src/klinfix/autogen.sh b/src/klinfix/autogen.sh new file mode 100755 index 00000000..69ad0e18 --- /dev/null +++ b/src/klinfix/autogen.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +autoreconf -W portability -vifm diff --git a/src/klinfix/configure.ac b/src/klinfix/configure.ac new file mode 100644 index 00000000..06f0af1d --- /dev/null +++ b/src/klinfix/configure.ac @@ -0,0 +1,33 @@ +AC_PREREQ(2.61) +AC_INIT([klinfix], [1.0.0], + [https://github.com/kernelkit/infix/issues]) +AM_INIT_AUTOMAKE(1.11 foreign subdir-objects) +AM_SILENT_RULES(yes) + +LT_INIT + +AC_CONFIG_FILES([ + Makefile + src/Makefile + xml/Makefile +]) + +AC_PROG_CC +AC_PROG_INSTALL + +# Check for pkg-config first, warn if it's not installed +PKG_PROG_PKG_CONFIG + +PKG_CHECK_MODULES([sysrepo], [sysrepo >= 2.2.60]) +AC_CHECK_LIB([klish], [kplugin_new],, AC_MSG_ERROR([Klish not found])) + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +KLISHLIBDIR=`eval echo $libdir/klish` +AC_SUBST(KLISHLIBDIR) + +KLISHCONFDIR=`eval echo $sysconfdir/klish` +AC_SUBST(KLISHCONFDIR) + +AC_OUTPUT diff --git a/src/klinfix/src/Makefile.am b/src/klinfix/src/Makefile.am new file mode 100644 index 00000000..5e236e85 --- /dev/null +++ b/src/klinfix/src/Makefile.am @@ -0,0 +1,9 @@ +CFLAGS = -Wall -Wextra -Werror -Wno-unused-parameter + +pluginsdir = $(KLISHLIBDIR)/plugins +plugins_LTLIBRARIES = kplugin-klinfix.la + +kplugin_klinfix_la_CFLAGS = $(sysrepo_CFLAGS) $(klish_CFLAGS) $(CFLAGS) +kplugin_klinfix_la_LIBADD = $(sysrepo_LIBS) $(klish_LIBS) +kplugin_klinfix_la_LDFLAGS = -module -avoid-version -shared +kplugin_klinfix_la_SOURCES = klinfix.c diff --git a/src/klinfix/src/klinfix.c b/src/klinfix/src/klinfix.c new file mode 100644 index 00000000..8abd910f --- /dev/null +++ b/src/klinfix/src/klinfix.c @@ -0,0 +1,155 @@ +#include +#include + +#include +#include + +#include +#include + +const uint8_t kplugin_klinfix_major = 1; +const uint8_t kplugin_klinfix_minor = 0; + +int klix_ds_from_str(const char *text, sr_datastore_t *ds) +{ + size_t len = strlen(text); + + if (!strncmp("startup-config", text, len)) + *ds = SR_DS_STARTUP; + else if (!strncmp("running-config", text, len)) + *ds = SR_DS_RUNNING; + else if (!strncmp("candidate-config", text, len)) + *ds = SR_DS_CANDIDATE; + else if (!strncmp("operational-config", text, len)) + *ds = SR_DS_OPERATIONAL; + else if (!strncmp("factory-config", text, len)) + *ds = SR_DS_FACTORY_DEFAULT; + else + return -1; + + return 0; +} + +int klix_copy(kcontext_t *ctx) +{ + kpargv_t *pargv = kcontext_pargv(ctx); + sr_datastore_t srcds, dstds; + kparg_t *srcarg, *dstarg; + sr_session_ctx_t *sess; + sr_conn_ctx_t *conn; + int err; + + srcarg = kpargv_find(pargv, "src"); + dstarg = kpargv_find(pargv, "dst"); + if (!srcarg || !dstarg) + goto err; + + if (klix_ds_from_str(kparg_value(srcarg), &srcds)) { + fprintf(stderr, + "Error: \"%s\" is not the name of any known datastore\n", + kparg_value(srcarg)); + goto err; + } + if (klix_ds_from_str(kparg_value(dstarg), &dstds)) { + fprintf(stderr, + "Error: \"%s\" is not the name of any known datastore\n", + kparg_value(dstarg)); + goto err; + } + + switch (srcds) { + case SR_DS_STARTUP: + case SR_DS_RUNNING: + case SR_DS_FACTORY_DEFAULT: + break; + default: + fprintf(stderr, + "Error: \"%s\" is not a valid source datastore\n", + kparg_value(srcarg)); + goto err; + } + + switch (dstds) { + case SR_DS_STARTUP: + case SR_DS_RUNNING: + break; + default: + fprintf(stderr, + "Error: \"%s\" is not a valid destination datastore\n", + kparg_value(dstarg)); + goto err; + } + + if (sr_connect(SR_CONN_DEFAULT, &conn)) { + fprintf(stderr, "Error: Connection to datastore failed\n"); + goto err; + } + if (sr_session_start(conn, dstds, &sess)) { + fprintf(stderr, "Error: Unable to open transaction to %s\n", + kparg_value(dstarg)); + goto err_disconnect; + } + + err = sr_copy_config(sess, NULL, srcds, 0); + if (err) { + fprintf(stderr, "Error: Unable to copy configuration (%d)\n", + err); + goto err_disconnect; + } + + sr_disconnect(conn); + return 0; + +err_disconnect: + sr_disconnect(conn); +err: + return -1; +} + +int klix_commit(kcontext_t *ctx) +{ + sr_session_ctx_t *sess; + sr_conn_ctx_t *conn; + int err; + + if (sr_connect(SR_CONN_DEFAULT, &conn)) { + fprintf(stderr, "Error: Connection to datastore failed\n"); + goto err; + } + + if (sr_session_start(conn, SR_DS_RUNNING, &sess)) { + fprintf(stderr, + "Error: Unable to open transaction to running-config\n"); + goto err_disconnect; + } + + err = sr_copy_config(sess, NULL, SR_DS_CANDIDATE, 0); + if (err) { + fprintf(stderr, + "Error: Unable to commit candidate to running (%d)\n", + err); + goto err; + } + + sr_disconnect(conn); + return 0; + +err_disconnect: + sr_disconnect(conn); +err: + return -1; +} + +int kplugin_klinfix_fini(kcontext_t *ctx) +{ + return 0; +} + +int kplugin_klinfix_init(kcontext_t *ctx) +{ + kplugin_t *plugin = kcontext_plugin(ctx); + + kplugin_add_syms(plugin, ksym_new("klix_copy", klix_copy)); + kplugin_add_syms(plugin, ksym_new("klix_commit", klix_commit)); + return 0; +} diff --git a/src/klinfix/xml/Makefile.am b/src/klinfix/xml/Makefile.am new file mode 100644 index 00000000..1bd6bfa9 --- /dev/null +++ b/src/klinfix/xml/Makefile.am @@ -0,0 +1,2 @@ +klishconfdir = $(KLISHCONFDIR) +klishconf_DATA = $(wildcard *.xml) diff --git a/src/klinfix/xml/infix.xml b/src/klinfix/xml/infix.xml new file mode 100644 index 00000000..927ff1dc --- /dev/null +++ b/src/klinfix/xml/infix.xml @@ -0,0 +1,215 @@ + + + + + + + + + ShowBrackets = y + ShowSemicolons = y + FirstKeyWithStatement = n + MultiKeysWithStatement = y + Colorize = y + Indent = 2 + + + + + factory-config + startup-config + running-config + + + + + + + startup-config + running-config + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %u@%h:exec> + + + + /bin/sh -l + + + + pop + + + pop + + + + replace configure + + + + + + + + + + + + + + + + + + + + + %u@%h:configure> + + + + + + + + + + + replace main + + + + + replace main + + + + + + replace main + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +