mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-22 01:13:00 +02:00
conf: add support for handling breaking model changes
Add metadata 'version' field to ietf-system to be able to detect .cfg file version. Fixes #308 Add early boot script to automatically migrate configuration files of older version to new syntax. Fixes #178 Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
+102
@@ -0,0 +1,102 @@
|
||||
#!/bin/sh
|
||||
# Run .cfg migration jq scripts to backup and transform older .cfg files
|
||||
ident=$(basename "$0")
|
||||
|
||||
MIGRATIONS_DIR="/usr/share/confd/migrate"
|
||||
CONFIG_FILE="/cfg/startup-config.cfg"
|
||||
BACKUP_DIR="/cfg/backup"
|
||||
|
||||
note()
|
||||
{
|
||||
logger -k -p user.notice -t "$ident" "$1"
|
||||
}
|
||||
|
||||
err()
|
||||
{
|
||||
logger -k -p user.err -t "$ident" "$1"
|
||||
}
|
||||
|
||||
file_version()
|
||||
{
|
||||
jq -r '
|
||||
if .["infix-meta:meta"] | has("version") then
|
||||
.["infix-meta:meta"]["version"]
|
||||
else
|
||||
"0.0"
|
||||
end
|
||||
' "$1"
|
||||
}
|
||||
|
||||
atoi()
|
||||
{
|
||||
echo "$1" | awk -F. '{print $1 * 1000 + $2}'
|
||||
}
|
||||
|
||||
if [ ! -f "$CONFIG_FILE" ]; then
|
||||
# Nothing to migrate
|
||||
note "No $(basename "$CONFIG_FILE" .cfg) yet, likely factory reset."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cfg_version=$(file_version "$CONFIG_FILE")
|
||||
current_version=$(atoi "$cfg_version")
|
||||
|
||||
# Find the latest version by examining the highest numbered directory
|
||||
sys_version=$(find "$MIGRATIONS_DIR" -mindepth 1 -maxdepth 1 -type d | sort -V | tail -n1 | xargs -n1 basename)
|
||||
latest_version=$(atoi "$sys_version")
|
||||
|
||||
# Check for downgrade
|
||||
if [ "$current_version" -gt "$latest_version" ]; then
|
||||
err "Configuration file $CONFIG_FILE version ($cfg_version) is newer than the latest supported version ($sys_version). Exiting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If the current version is already the latest, exit the script
|
||||
if [ "$current_version" -eq "$latest_version" ]; then
|
||||
note "Configuration is already at the latest version ($sys_version). No migration needed."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
note "Configuration file $CONFIG_FILE is of version $cfg_version, migrating ..."
|
||||
|
||||
# Create the backup directory if it doesn't exist
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
# Create a backup of the current configuration file
|
||||
nm=$(basename "$CONFIG_FILE" .cfg)
|
||||
BACKUP_FILE="$BACKUP_DIR/${nm}-${cfg_version}.cfg"
|
||||
if cp "$CONFIG_FILE" "$BACKUP_FILE"; then
|
||||
note "Backup created: $BACKUP_FILE"
|
||||
else
|
||||
err "Failed creating backup: $BACKUP_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Apply the scripts for each version directory in sequence
|
||||
for version_dir in $(find "$MIGRATIONS_DIR" -mindepth 1 -maxdepth 1 -type d | sort -V); do
|
||||
dir=$(basename "$version_dir")
|
||||
version=$(atoi "$dir")
|
||||
|
||||
# Step by step upgrade file to latest version
|
||||
if [ "$current_version" -lt "$version" ]; then
|
||||
note "Applying migrations for version $dir ..."
|
||||
|
||||
# Apply all scripts in the version directory in order
|
||||
for script in $(find "$version_dir" -type f -name '*.sh' | sort -V); do
|
||||
note "Calling $script for $CONFIG_FILE ..."
|
||||
sh "$script" "$CONFIG_FILE"
|
||||
done
|
||||
|
||||
# File now at $version ...
|
||||
current_version="$version"
|
||||
fi
|
||||
done
|
||||
|
||||
# Update the JSON file to the latest version
|
||||
if jq --arg version "$sys_version" '.["infix-meta:meta"]["infix-meta:version"] = $version' "$CONFIG_FILE" \
|
||||
> "${CONFIG_FILE}.tmp" && mv "${CONFIG_FILE}.tmp" "$CONFIG_FILE"; then
|
||||
note "Configuration updated to version $sys_version."
|
||||
else
|
||||
err "Failed updating configuration to version $sys_version!"
|
||||
exit 1
|
||||
fi
|
||||
@@ -12,7 +12,7 @@ CONFD_LICENSE_FILES = LICENSE
|
||||
CONFD_REDISTRIBUTE = NO
|
||||
CONFD_DEPENDENCIES = host-sysrepo sysrepo netopeer2 jansson libite sysrepo libsrx libglib2
|
||||
CONFD_AUTORECONF = YES
|
||||
|
||||
CONFD_CONF_OPTS += --disable-silent-rules
|
||||
CONFD_SYSREPO_SHM_PREFIX = sr_buildroot$(subst /,_,$(CONFIG_DIR))_confd
|
||||
|
||||
define CONFD_CONF_ENV
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
pkglibexec_SCRIPTS = bootstrap error load gen-service gen-hostkeys \
|
||||
gen-hostname gen-interfaces gen-motd gen-hardware
|
||||
gen-hostname gen-interfaces gen-motd gen-hardware gen-version
|
||||
sbin_SCRIPTS = dagger
|
||||
|
||||
@@ -101,6 +101,7 @@ factory()
|
||||
gen-hardware >"$FACTORY_D/20-hardware.json"
|
||||
# shellcheck disable=SC2086
|
||||
gen-interfaces $GEN_IFACE_OPTS >"$FACTORY_D/20-interfaces.json"
|
||||
gen-version >"$FACTORY_D/20-version.json"
|
||||
|
||||
[ -s "$FACTORY_D/20-hostkey.json" ] || gen-hostkeys >"$FACTORY_D/20-hostkey.json"
|
||||
|
||||
@@ -120,6 +121,7 @@ failure()
|
||||
|
||||
gen-hostname "$FAIL_HOSTNAME" >"$FAILURE_D/20-hostname.json"
|
||||
gen-interfaces >"$FAILURE_D/20-interfaces.json"
|
||||
gen-version >"$FACTORY_D/20-version.json"
|
||||
|
||||
[ -s "$FAILURE_D/20-hostkey.json" ] || gen-hostkeys >"$FAILURE_D/20-hostkey.json"
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
cat <<EOF
|
||||
{
|
||||
"infix-meta:meta": {
|
||||
"infix-meta:version": "@VERSION@"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
@@ -1,14 +1,18 @@
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT([confd], [1.0.0], [https://github.com/kernelkit/infix/issues])
|
||||
# confd version is same as system YANG model version, step on breaking changes
|
||||
AC_INIT([confd], [1.0], [https://github.com/kernelkit/infix/issues])
|
||||
AM_INIT_AUTOMAKE(1.11 foreign subdir-objects)
|
||||
AM_SILENT_RULES(yes)
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
bin/Makefile
|
||||
bin/gen-version
|
||||
share/Makefile
|
||||
share/factory.d/Makefile
|
||||
share/failure.d/Makefile
|
||||
share/migrate/Makefile
|
||||
share/migrate/1.0/Makefile
|
||||
src/Makefile
|
||||
yang/Makefile
|
||||
])
|
||||
|
||||
@@ -53,6 +53,7 @@ MODULES=(
|
||||
"infix-routing@2024-03-06.yang"
|
||||
"ieee802-dot1ab-lldp@2022-03-15.yang"
|
||||
"infix-lldp@2023-08-23.yang"
|
||||
"infix-meta@2024-06-19.yang"
|
||||
"infix-dhcp-client@2024-04-12.yang"
|
||||
"infix-system@2024-06-15.yang"
|
||||
"infix-services@2024-05-30.yang"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
SUBDIRS = factory.d failure.d
|
||||
SUBDIRS = factory.d failure.d migrate
|
||||
dist_pkgdata_DATA = README
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
# Migrate infix-shell-type:bash -> infix-system:bash
|
||||
|
||||
file=$1
|
||||
temp=$1.tmp
|
||||
|
||||
jq '.["ietf-system:system"].authentication.user |= map(.["infix-system:shell"] |= gsub("infix-shell-type:"; ""))' "$file" > "$temp"
|
||||
mv "$temp" "$file"
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
migratedir = $(pkgdatadir)/migrate/1.0
|
||||
dist_migrate_DATA = 10-infix-shell-type.sh
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
SUBDIRS = 1.0
|
||||
migratedir = $(pkgdatadir)/migrate
|
||||
@@ -29,8 +29,9 @@ confd_plugin_la_SOURCES = \
|
||||
ietf-factory-default.c \
|
||||
ietf-routing.c \
|
||||
infix-dhcp.c \
|
||||
infix-services.c \
|
||||
infix-factory.c \
|
||||
infix-meta.c \
|
||||
infix-services.c \
|
||||
infix-system-software.c \
|
||||
ietf-hardware.c
|
||||
|
||||
|
||||
@@ -140,6 +140,9 @@ int sr_plugin_init_cb(sr_session_ctx_t *session, void **priv)
|
||||
if (rc)
|
||||
goto err;
|
||||
rc = ietf_routing_init(&confd);
|
||||
if (rc)
|
||||
goto err;
|
||||
rc = infix_meta_init(&confd);
|
||||
if (rc)
|
||||
goto err;
|
||||
rc = infix_system_sw_init(&confd);
|
||||
|
||||
@@ -191,6 +191,9 @@ int ietf_routing_init(struct confd *confd);
|
||||
/* infix-factory.c */
|
||||
int infix_factory_init(struct confd *confd);
|
||||
|
||||
/* infix-factory.c */
|
||||
int infix_meta_init(struct confd *confd);
|
||||
|
||||
/* infix-system-software.c */
|
||||
int infix_system_sw_init(struct confd *confd);
|
||||
|
||||
|
||||
@@ -1666,7 +1666,7 @@ static int hostname_cb(sr_session_ctx_t *session, uint32_t sub_id, const char *m
|
||||
|
||||
int ietf_system_init(struct confd *confd)
|
||||
{
|
||||
int rc = 0;
|
||||
int rc;
|
||||
|
||||
os_init();
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include "core.h"
|
||||
|
||||
#define META_XPATH "/infix-meta:meta/version"
|
||||
|
||||
|
||||
static int set_version(sr_session_ctx_t *session)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = sr_set_item_str(session, META_XPATH, VERSION, NULL, 0);
|
||||
if (rc) {
|
||||
ERROR("Failed setting .cfg version %s: %d", VERSION, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
static int change_cb(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
|
||||
const char *xpath, sr_event_t event, unsigned request_id, void *priv)
|
||||
{
|
||||
if (event == SR_EV_UPDATE)
|
||||
return set_version(session);
|
||||
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
int infix_meta_init(struct confd *confd)
|
||||
{
|
||||
int rc;
|
||||
|
||||
REGISTER_CHANGE(confd->session, "infix-meta", META_XPATH, SR_SUBSCR_UPDATE,
|
||||
change_cb, confd, &confd->sub);
|
||||
return SR_ERR_OK;
|
||||
fail:
|
||||
ERROR("%s(): failed. %s", __func__, sr_strerror(rc));
|
||||
return rc;
|
||||
}
|
||||
@@ -25,6 +25,7 @@ MODULES=(
|
||||
"ieee802-dot1ab-lldp@2022-03-15.yang"
|
||||
"infix-lldp@2023-08-23.yang"
|
||||
"infix-dhcp-client@2024-04-12.yang"
|
||||
"infix-meta@2024-06-19.yang"
|
||||
"infix-system@2024-06-15.yang"
|
||||
"infix-services@2024-05-30.yang"
|
||||
"ieee802-ethernet-interface@2019-06-21.yang"
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
module infix-meta {
|
||||
yang-version 1.1;
|
||||
namespace "urn:infix:meta:ns:yang:1.0";
|
||||
prefix infix-meta;
|
||||
|
||||
organization "KernelKit";
|
||||
contact "kernelkit@googlegroups.com";
|
||||
description "Infix metadata.";
|
||||
|
||||
revision 2024-06-19 {
|
||||
description "Initial revision.";
|
||||
reference "internal";
|
||||
}
|
||||
|
||||
container meta {
|
||||
leaf version {
|
||||
status obsolete; // Ensure frontends don't show this, used for migration.
|
||||
description "Configuration file format version, automatically generated.";
|
||||
type string;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user