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.
This commit is contained in:
Tobias Waldekranz
2023-03-31 17:31:34 +02:00
parent abd001f57d
commit e729c82c32
16 changed files with 554 additions and 0 deletions
+1
View File
@@ -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
+1
View File
@@ -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
+1
View File
@@ -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"
+8
View File
@@ -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.
+14
View File
@@ -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))
+1
View File
@@ -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
+1
View File
@@ -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
+33
View File
@@ -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
+3
View File
@@ -0,0 +1,3 @@
SUBDIRS = src xml
DISTCLEANFILES = *~ *.d
ACLOCAL_AMFLAGS = -I m4
+74
View File
@@ -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 <src> <dst>` | Copy `<src>` to `<dst>` | |
| `exit` | Exit | `C-d` |
| `logout` | Alias for `exit` | |
| `shell` | Start system shell | |
| `show <item>` | Show various configuration and status | |
#### Copy Command
`copy <src> <dst>`
Where `<src>` is one of:
- `factory-config`
- `startup-config`
- `running-config`
And `<dst>` is one of:
- `startup-config`
- `running-config`
#### Show Command
`show <item>`
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` |
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
autoreconf -W portability -vifm
+33
View File
@@ -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
+9
View File
@@ -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
+155
View File
@@ -0,0 +1,155 @@
#include <assert.h>
#include <stdio.h>
#include <sysrepo.h>
#include <sysrepo_types.h>
#include <klish/kplugin.h>
#include <klish/kcontext.h>
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;
}
+2
View File
@@ -0,0 +1,2 @@
klishconfdir = $(KLISHCONFDIR)
klishconf_DATA = $(wildcard *.xml)
+215
View File
@@ -0,0 +1,215 @@
<?xml version="1.0" encoding="UTF-8"?>
<KLISH
xmlns="https://klish.libcode.org/klish3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://src.libcode.org/pkun/klish/src/master/klish.xsd">
<PLUGIN name="klish"/>
<PLUGIN name="klinfix"/>
<PLUGIN name="script"/>
<PLUGIN name="sysrepo">
ShowBrackets = y
ShowSemicolons = y
FirstKeyWithStatement = n
MultiKeysWithStatement = y
Colorize = y
Indent = 2
</PLUGIN>
<PTYPE name="DATASTORE">
<COMPL>
<ACTION sym="printl">factory-config</ACTION>
<ACTION sym="printl">startup-config</ACTION>
<ACTION sym="printl">running-config</ACTION>
</COMPL>
<ACTION sym="STRING"/>
</PTYPE>
<PTYPE name="RW_DATASTORE">
<COMPL>
<ACTION sym="printl">startup-config</ACTION>
<ACTION sym="printl">running-config</ACTION>
</COMPL>
<ACTION sym="STRING"/>
</PTYPE>
<PTYPE name="PLINE_SET">
<COMPL>
<ACTION sym="srp_compl@sysrepo"/>
</COMPL>
<HELP>
<ACTION sym="srp_help@sysrepo"/>
</HELP>
<ACTION sym="PLINE_SET@sysrepo"/>
</PTYPE>
<PTYPE name="PLINE_DEL">
<COMPL>
<ACTION sym="srp_compl@sysrepo"/>
</COMPL>
<HELP>
<ACTION sym="srp_help@sysrepo"/>
</HELP>
<ACTION sym="PLINE_DEL@sysrepo"/>
</PTYPE>
<PTYPE name="PLINE_EDIT">
<COMPL>
<ACTION sym="srp_compl@sysrepo"/>
</COMPL>
<HELP>
<ACTION sym="srp_help@sysrepo"/>
</HELP>
<ACTION sym="PLINE_EDIT@sysrepo"/>
</PTYPE>
<PTYPE name="PLINE_INSERT_FROM">
<COMPL>
<ACTION sym="srp_compl@sysrepo"/>
</COMPL>
<HELP>
<ACTION sym="srp_help@sysrepo"/>
</HELP>
<ACTION sym="PLINE_INSERT_FROM@sysrepo"/>
</PTYPE>
<PTYPE name="PLINE_INSERT_TO">
<COMPL>
<ACTION sym="srp_compl_insert_to@sysrepo"/>
</COMPL>
<HELP>
<ACTION sym="srp_help_insert_to@sysrepo"/>
</HELP>
<ACTION sym="PLINE_INSERT_TO@sysrepo"/>
</PTYPE>
<VIEW name="main">
<HOTKEY key="^D" cmd="exit"/>
<PROMPT>
<ACTION sym="prompt" exec_on="always">%u@%h:exec> </ACTION>
</PROMPT>
<COMMAND name="shell" help="Enter system shell">
<ACTION sym="script" interactive="true">/bin/sh -l</ACTION>
</COMMAND>
<COMMAND name="exit" help="Exit">
<ACTION sym="nav">pop</ACTION>
</COMMAND>
<COMMAND name="logout" help="Alias for exit">
<ACTION sym="nav">pop</ACTION>
</COMMAND>
<COMMAND name="configure" help="Create new candidate-config based on running-config">
<ACTION sym="nav">replace configure</ACTION>
</COMMAND>
<COMMAND name="copy" help="Copy">
<PARAM name="src" ptype="/DATASTORE" help="Source datastore"/>
<PARAM name="dst" ptype="/RW_DATASTORE" help="Destination datastore"/>
<ACTION sym="klix_copy@klinfix"/>
</COMMAND>
<COMMAND name="show" help="Show" mode="switch">
<COMMAND name="running-config" help="Show running-config">
<ACTION sym="srp_show_running@sysrepo"/>
</COMMAND>
</COMMAND>
</VIEW>
<VIEW name="configure">
<PROMPT>
<ACTION sym="srp_prompt_edit_path@sysrepo"/>
<ACTION sym="prompt" exec_on="always">%u@%h:configure> </ACTION>
</PROMPT>
<HOTKEY key="^C" cmd="up"/>
<HOTKEY key="^D" cmd="abort"/>
<HOTKEY key="^Z" cmd="leave"/>
<!-- Move -->
<COMMAND name="abort" help="Abandon candidate">
<ACTION sym="srp_rollback@sysrepo"/>
<ACTION sym="nav">replace main</ACTION>
</COMMAND>
<COMMAND name="leave" help="Finalize candidate and apply to running-config">
<ACTION sym="klix_commit@klinfix"/>
<ACTION sym="nav" exec_on="success">replace main</ACTION>
</COMMAND>
<COMMAND name="exit" help="Ascend to the parent configuration node, or abort (from top)">
<ACTION sym="srp_up@sysrepo"/>
<ACTION sym="klix_commit@klinfix" exec_on="fail"/>
<ACTION sym="nav" exec_on="success">replace main</ACTION>
</COMMAND>
<COMMAND name="up" help="Ascend to the parent configuration node">
<ACTION sym="srp_up@sysrepo"/>
</COMMAND>
<COMMAND name="top" help="Ascend to the configuration root">
<ACTION sym="srp_top@sysrepo"/>
</COMMAND>
<COMMAND name="edit" help="Descend to the specified configuration node">
<PARAM name="path" ptype="/PLINE_EDIT" max="100"/>
<ACTION sym="srp_edit@sysrepo"/>
</COMMAND>
<!-- Edit -->
<COMMAND name="set" help="Set configuration setting">
<PARAM name="path" ptype="/PLINE_SET" max="100"/>
<ACTION sym="srp_set@sysrepo"/>
</COMMAND>
<COMMAND name="delete" help="Delete configuration setting(s)">
<PARAM name="path" ptype="/PLINE_DEL" max="100"/>
<ACTION sym="srp_del@sysrepo"/>
</COMMAND>
<COMMAND name="no" help="Alias for delete">
<PARAM name="path" ptype="/PLINE_DEL" max="100"/>
<ACTION sym="srp_del@sysrepo"/>
</COMMAND>
<COMMAND name="commit" help="Commit current candidate to running-config">
<ACTION sym="klix_commit@klinfix"/>
</COMMAND>
<COMMAND name="rollback" help="Restore candidate to running-config">
<ACTION sym="srp_rollback@sysrepo"/>
</COMMAND>
<!-- Display -->
<COMMAND name="check" help="Validate candidate">
<ACTION sym="srp_verify@sysrepo"/>
</COMMAND>
<COMMAND name="show" help="Show configuration">
<PARAM name="path" ptype="/PLINE_EDIT" min="0" max="100"/>
<ACTION sym="srp_show@sysrepo"/>
</COMMAND>
<COMMAND name="diff" help="Summarize uncommitted changes">
<PARAM name="path" ptype="/PLINE_EDIT" min="0" max="100"/>
<ACTION sym="srp_diff@sysrepo"/>
</COMMAND>
<!-- Misc -->
<COMMAND name="do" help="Execute operational mode command">
<VIEW name="operational" ref="/main"/>
</COMMAND>
</VIEW>
</KLISH>