diff --git a/board/common/rootfs/libexec/infix/init.d/30-cfg-migrate b/board/common/rootfs/libexec/infix/init.d/30-cfg-migrate new file mode 100755 index 00000000..520df78c --- /dev/null +++ b/board/common/rootfs/libexec/infix/init.d/30-cfg-migrate @@ -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 diff --git a/package/confd/confd.mk b/package/confd/confd.mk index c6761a0a..9cab7b52 100644 --- a/package/confd/confd.mk +++ b/package/confd/confd.mk @@ -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 diff --git a/src/confd/bin/Makefile.am b/src/confd/bin/Makefile.am index 5c5eb265..fffa0766 100644 --- a/src/confd/bin/Makefile.am +++ b/src/confd/bin/Makefile.am @@ -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 diff --git a/src/confd/bin/bootstrap b/src/confd/bin/bootstrap index 2e8b077d..ce42ea78 100755 --- a/src/confd/bin/bootstrap +++ b/src/confd/bin/bootstrap @@ -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" diff --git a/src/confd/bin/gen-version.in b/src/confd/bin/gen-version.in new file mode 100644 index 00000000..3583f4d9 --- /dev/null +++ b/src/confd/bin/gen-version.in @@ -0,0 +1,9 @@ +#!/bin/sh + +cat < 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" + diff --git a/src/confd/share/migrate/1.0/Makefile.am b/src/confd/share/migrate/1.0/Makefile.am new file mode 100644 index 00000000..3a6ac18a --- /dev/null +++ b/src/confd/share/migrate/1.0/Makefile.am @@ -0,0 +1,3 @@ +migratedir = $(pkgdatadir)/migrate/1.0 +dist_migrate_DATA = 10-infix-shell-type.sh + diff --git a/src/confd/share/migrate/Makefile.am b/src/confd/share/migrate/Makefile.am new file mode 100644 index 00000000..d92bf0da --- /dev/null +++ b/src/confd/share/migrate/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = 1.0 +migratedir = $(pkgdatadir)/migrate diff --git a/src/confd/src/Makefile.am b/src/confd/src/Makefile.am index 0fdb7b28..009de2f6 100644 --- a/src/confd/src/Makefile.am +++ b/src/confd/src/Makefile.am @@ -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 diff --git a/src/confd/src/core.c b/src/confd/src/core.c index 2444b29a..b48f70b6 100644 --- a/src/confd/src/core.c +++ b/src/confd/src/core.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); diff --git a/src/confd/src/core.h b/src/confd/src/core.h index e5997d94..f7d52e68 100644 --- a/src/confd/src/core.h +++ b/src/confd/src/core.h @@ -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); diff --git a/src/confd/src/ietf-system.c b/src/confd/src/ietf-system.c index 280a8247..2a23e199 100644 --- a/src/confd/src/ietf-system.c +++ b/src/confd/src/ietf-system.c @@ -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(); diff --git a/src/confd/src/infix-meta.c b/src/confd/src/infix-meta.c new file mode 100644 index 00000000..2936fdc5 --- /dev/null +++ b/src/confd/src/infix-meta.c @@ -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; +} diff --git a/src/confd/yang-setup/yang-modules-confd.inc b/src/confd/yang-setup/yang-modules-confd.inc index 43388f5c..4a3d2365 100644 --- a/src/confd/yang-setup/yang-modules-confd.inc +++ b/src/confd/yang-setup/yang-modules-confd.inc @@ -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" diff --git a/src/confd/yang/infix-meta@2024-06-19.yang b/src/confd/yang/infix-meta@2024-06-19.yang new file mode 100644 index 00000000..e7c2fc12 --- /dev/null +++ b/src/confd/yang/infix-meta@2024-06-19.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; + } + } +}