Skip to content

Commit

Permalink
Merge pull request #876 from kernelkit/change-boot-order
Browse files Browse the repository at this point in the history
Change boot order
  • Loading branch information
mattiaswal authored Dec 19, 2024
2 parents 1f2973d + e00737e commit a8545e3
Show file tree
Hide file tree
Showing 17 changed files with 229 additions and 90 deletions.
2 changes: 2 additions & 0 deletions doc/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ All notable changes to the project are documented in this file.
as "reflector" and filtering of reflected services. Issue #678
- Review of default `sysctl` settings, issue #829
- Upgrade Linux kernel to 6.12.3 (LTS)
- Add the possibility to change the boot order for the system with a
RPC and add boot order to operational datastore.

### Fixes

Expand Down
38 changes: 37 additions & 1 deletion src/confd/src/infix-system-software.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include "core.h"
#include "rauc-installer.h"


static RaucInstaller *infix_system_sw_new_rauc(void)
{
RaucInstaller *rauc;
Expand Down Expand Up @@ -51,12 +50,49 @@ static int infix_system_sw_install(sr_session_ctx_t *session, uint32_t sub_id,
return srerr;
}

/*
boot order can only be: primary, secondary and net, limited by model
*/
static int infix_system_sw_set_boot_order(sr_session_ctx_t *session, uint32_t sub_id,
const char *path, const sr_val_t *input,
const size_t input_cnt, sr_event_t event,
unsigned request_id, sr_val_t **output,
size_t *output_cnt, void *priv) {
char boot_order[23] = "";
for (size_t i = 0; i < input_cnt; i++) {
const sr_val_t *val = &input[i];

if (i != 0)
strlcat(boot_order, " ", sizeof(boot_order));
strlcat(boot_order, val->data.string_val, sizeof(boot_order));
}

if (fexist("/sys/firmware/devicetree/base/chosen/u-boot,version")) {
if (systemf("fw_setenv BOOT_ORDER %s", boot_order)) {
ERROR("Set-boot-order: Failed to set boot order in U-Boot");
return SR_ERR_INTERNAL;
}
} else if (fexist("/mnt/aux/grub/grubenv")) {
if (systemf("grub-editenv /mnt/aux/grub/grubenv set ORDER=\"%s\"", boot_order)) {
ERROR("Set-boot-order: Failed to set boot order in Grub");
return SR_ERR_INTERNAL;
}
} else {
ERROR("No supported boot loader found");
return SR_ERR_UNSUPPORTED;
}

return SR_ERR_OK;
}

int infix_system_sw_init(struct confd *confd)
{
int rc = 0;

REGISTER_RPC(confd->session, "/infix-system:install-bundle",
infix_system_sw_install, NULL, &confd->sub);
REGISTER_RPC(confd->session, "/infix-system:set-boot-order",
infix_system_sw_set_boot_order, NULL, &confd->sub);

fail:
return rc;
Expand Down
33 changes: 31 additions & 2 deletions src/confd/yang/infix-system-software.yang
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ submodule infix-system-software {
contact "[email protected]";
description "Software status and upgrade.";

revision 2024-12-16 {
description "Add boot-order operational data";
reference "Internal";
}
revision 2023-06-27 {
description "Initial revision.";
reference "internal";
Expand All @@ -39,6 +43,18 @@ submodule infix-system-software {
}
}

grouping boot-order {
leaf-list boot-order {
type enumeration {
enum "primary";
enum "secondary";
enum "net";
}
ordered-by user;
min-elements 1; // At least one value is required
max-elements 3; // Ensure reasonable maximum size if needed
}
}
grouping installer-state {
leaf operation {
type string;
Expand All @@ -64,7 +80,6 @@ submodule infix-system-software {
"The last error encountered by the installer service.";
}
}

augment "/sys:system-state" {
container software {
description
Expand Down Expand Up @@ -95,6 +110,7 @@ submodule infix-system-software {
description
"Slot from which the system was booted.";
}
uses boot-order;

container installer {
description
Expand Down Expand Up @@ -184,7 +200,7 @@ submodule infix-system-software {
}

rpc install-bundle {
nacm:default-deny-all;
nacm:default-deny-all;
description
"Upgrade the system's software by installing the specified bundle.";
input {
Expand All @@ -198,4 +214,17 @@ nacm:default-deny-all;
}
}
}
rpc set-boot-order {
nacm:default-deny-all;
description
"Set order of boot partitions";
input {
uses boot-order;
must "count(boot-order[.='primary']) <= 1 and
count(boot-order[.='secondary']) <= 1 and
count(boot-order[.='net']) <= 1" {
error-message "Not possible to have duplicate targets in boot order.";
}
}
}
}
File renamed without changes.
2 changes: 1 addition & 1 deletion src/klish-plugin-infix/xml/infix.xml
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@
sysrepocfg -d operational -X -f json -x /ietf-system:system-state/infix-system:software | \
jq -r '.[][].slot |= sort_by(.name)' > "$tmp"
if [ -n "$KLISH_PARAM_name" ]; then
cat "$tmp" | /usr/libexec/statd/cli-pretty "infix-system" -n "$KLISH_PARAM_name"
cat "$tmp" | /usr/libexec/statd/cli-pretty "show-software" -n "$KLISH_PARAM_name"
else
cat "$tmp" | /usr/libexec/statd/cli-pretty "show-software"
fi
Expand Down
17 changes: 14 additions & 3 deletions src/statd/python/cli_pretty/cli_pretty.py
Original file line number Diff line number Diff line change
Expand Up @@ -691,12 +691,21 @@ def show_software(json, name):
print("Error, cannot find infix-system:software")
sys.exit(1)

slots = get_json_data({}, json, 'ietf-system:system-state', 'infix-system:software', 'slot')
software = get_json_data({}, json, 'ietf-system:system-state', 'infix-system:software')
slots = software.get("slot")
boot_order = software.get("boot-order", ["Unknown"])
if name:
slot = find_slot(slots, name)
if slot:
slot.detail()
else:
print(Decore.invert("BOOT ORDER"))
order=""
for boot in boot_order:
order+=f"{boot.strip()} "
print(order)
print("")

hdr = (f"{'NAME':<{PadSoftware.name}}"
f"{'STATE':<{PadSoftware.state}}"
f"{'VERSION':<{PadSoftware.version}}"
Expand Down Expand Up @@ -773,10 +782,12 @@ def main():
parser_show_software = subparsers.add_parser('show-software', help='Show software versions')
parser_show_software.add_argument('-n', '--name', help='Slotname')

parser_show_routing_table = subparsers.add_parser('show-hardware', help='Show USB ports')
parser_show_hardware = subparsers.add_parser('show-hardware', help='Show USB ports')

parser_show_ntp_sources = subparsers.add_parser('show-ntp', help='Show NTP sources')

parser_show_boot_order = subparsers.add_parser('show-boot-order', help='Show NTP sources')

args = parser.parse_args()
UNIT_TEST = args.test

Expand All @@ -793,7 +804,7 @@ def main():
elif args.command == "show-ntp":
show_ntp(json_data)
else:
print(f"Error, unknown command {args.command}")
print(f"Error, unknown command '{args.command}'")
sys.exit(1)


Expand Down
70 changes: 54 additions & 16 deletions src/statd/python/yanger/yanger.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,23 @@ def datetime_now():
return datetime(2023, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
return datetime.now(timezone.utc)

def uboot_get_boot_order():
data = run_cmd("fw_printenv BOOT_ORDER".split(), "boot-order.txt")
for line in data:
if "BOOT_ORDER" in line:
return line.strip().split("=")[1].split()

raise Exception

def grub_get_boot_order():
data = run_cmd("grub-editenv /mnt/aux/grub/grubenv list".split(), None) # No need for testfile, will be returned from uboot

for line in data:
if "ORDER" in line:
return line.split("=")[1].strip().split()

raise Exception

def json_get_yang_type(iface_in):
if iface_in['link_type'] == "loopback":
return "infix-if-type:loopback"
Expand Down Expand Up @@ -1091,35 +1108,56 @@ def add_system_software_slots(out, data):
new["class"] = slot[key].get("class")
new["state"] = slot[key].get("state")
new["bundle"] = {}
slot_status=value.get("slot_status", {})
if slot_status.get("bundle", {}).get("compatible"):
new["bundle"]["compatible"] = slot_status.get("bundle", {}).get("compatible")
if slot_status.get("bundle", {}).get("version"):
new["bundle"]["version"] = slot_status.get("bundle", {}).get("version")
if slot_status.get("checksum", {}).get("size"):
new["size"] = str(slot_status.get("checksum", {}).get("size"))
if slot_status.get("checksum", {}).get("sha256"):
new["sha256"] = slot_status.get("checksum", {}).get("sha256")

if value.get("slot_status",{}).get("bundle", {}).get("compatible"):
new["bundle"]["compatible"] = value.get("slot_status",{}).get("bundle", {}).get("compatible")
if value.get("slot_status", {}).get("bundle", {}).get("version"):
new["bundle"]["version"] = value.get("slot_status", {}).get("bundle", {}).get("version")
if value.get("checksum", {}).get("size"):
new["size"] = value.get("checksum", {}).get("size")
if value.get("checksum", {}).get("sha256"):
new["sha256"] = value.get("checksum", {}).get("sha256")
new["installed"] = {}
if value.get("installed", {}).get("timestamp"):
new["installed"]["datetime"] = value.get("installed", {}).get("timestamp")
if value.get("installed", {}).get("count"):
new["installed"]["count"] = value.get("installed", {}).get("count")
if slot_status.get("installed", {}).get("timestamp"):
new["installed"]["datetime"] = slot_status.get("installed", {}).get("timestamp")

if slot_status.get("installed", {}).get("count"):
new["installed"]["count"] = slot_status.get("installed", {}).get("count")

new["activated"] = {}
if value.get("activated", {}).get("timestamp"):
new["activated"]["datetime"] = value.get("activated", {}).get("timestamp")
if value.get("activated", {}).get("count"):
new["activated"]["count"] = value.get("activated", {}).get("count")
if slot_status.get("activated", {}).get("timestamp"):
new["activated"]["datetime"] = slot_status.get("activated", {}).get("timestamp")

if slot_status.get("activated", {}).get("count"):
new["activated"]["count"] = slot_status.get("activated", {}).get("count")
slots.append(new)
out["slot"] = slots

def get_system_software_boot_order():
order = None
try:
order = uboot_get_boot_order()
except:
pass
try:
if order is None:
order = grub_get_boot_order()
except:
pass

return order

def add_system_software(out):
software = {}
try:
data = run_json_cmd(["rauc", "status", "--detailed", "--output-format=json"], "rauc-status.json")
software["compatible"] = data["compatible"]
software["variant"] = data["variant"]
software["booted"] = data["booted"]
boot_order = get_system_software_boot_order()
if not boot_order is None:
software["boot-order"] = boot_order
add_system_software_slots(software, data)
except subprocess.CalledProcessError:
pass # Maybe an upgrade i progress, then rauc does not respond
Expand Down
6 changes: 6 additions & 0 deletions test/case/cli/cli-output/show-software.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
BOOT ORDER
net primary secondary

NAME STATE VERSION DATE 
secondary inactive pr873.2a39a38 2024-12-16T14:40:54Z
primary inactive pr871.a4ef38f 2024-12-13T20:00:42Z
16 changes: 14 additions & 2 deletions test/case/cli/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ if [ $# -eq 2 ] && [ $1 = "update" ]; then
elif [ $2 = "show-bridge-mdb" ]; then
"$SR_EMULATOR_TOOL" | "$CLI_PRETTY_TOOL" "show-bridge-mdb" > "$CLI_OUTPUT_PATH/show-bridge-mdb.txt"
elif [ $2 = "show-ntp" ]; then
"$SR_EMULATOR_TOOL" | "$CLI_PRETTY_TOOL" "show-ntp" > "$CLI_OUTPUT_PATH/show-ntp.txt"
"$SR_EMULATOR_TOOL" | "$CLI_PRETTY_TOOL" "show-ntp" > "$CLI_OUTPUT_PATH/show-ntp.txt"
elif [ $2 = "show-software" ]; then
"$SR_EMULATOR_TOOL" | "$CLI_PRETTY_TOOL" "show-software" > "$CLI_OUTPUT_PATH/show-software.txt"
else
echo "Unsupported cli-pretty command $2"
exit 1
Expand All @@ -69,7 +71,7 @@ if [ $# -eq 2 ] && [ $1 = "update" ]; then
exit 0
fi

echo "1..11"
echo "1..12"
echo "# Running:"

# Show interfaces
Expand Down Expand Up @@ -101,6 +103,16 @@ if ! diff -u "$CLI_OUTPUT_PATH/show-ntp.txt" "$CLI_OUTPUT_FILE"; then
fi
ok "\"show ntp\" output looks intact"

# Show software
echo "# $SR_EMULATOR_TOOL | $CLI_PRETTY_TOOL show-software"
"$SR_EMULATOR_TOOL" | "$CLI_PRETTY_TOOL" "show-software" > "$CLI_OUTPUT_FILE"

if ! diff -u "$CLI_OUTPUT_PATH/show-software.txt" "$CLI_OUTPUT_FILE"; then
print_update_txt
fail "\"show software\" output has changed"
fi
ok "\"show software\" output looks intact"

# Show ipv4 routes
echo "# $SR_EMULATOR_TOOL | $CLI_PRETTY_TOOL -t show-routing-table -i ipv4"
"$SR_EMULATOR_TOOL" | "$CLI_PRETTY_TOOL" "-t" "show-routing-table" -i "ipv4" > "$CLI_OUTPUT_FILE"
Expand Down
1 change: 1 addition & 0 deletions test/case/cli/system-output/boot-order.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
BOOT_ORDER=net primary secondary
2 changes: 1 addition & 1 deletion test/case/cli/system-output/rauc-status.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"compatible":"infix-x86_64","variant":"","booted":"primary","boot_primary":"rootfs.0","slots":[{"rootfs.1":{"class":"rootfs","device":"/dev/disk/by-partlabel/secondary","type":"raw","bootname":"secondary","state":"inactive","parent":null,"mountpoint":null,"boot_status":"good"}},{"rootfs.0":{"class":"rootfs","device":"/dev/disk/by-partlabel/primary","type":"raw","bootname":"primary","state":"booted","parent":null,"mountpoint":null,"boot_status":"good"}},{"net.0":{"class":"net","device":"/dev/ram0","type":"raw","bootname":"net","state":"inactive","parent":null,"mountpoint":null,"boot_status":"good"}}]}
{"compatible":"infix-aarch64","variant":"","booted":"net","boot_primary":"net.0","slots":[{"rootfs.1":{"class":"rootfs","device":"/dev/disk/by-partlabel/secondary","type":"raw","bootname":"secondary","state":"inactive","parent":null,"mountpoint":null,"boot_status":"bad","slot_status":{"bundle":{"compatible":"infix-aarch64","version":"pr873.2a39a38","hash":"99a9543fe85a2b32a4a28409f7103099fd8cfce3f3bbccb5175ace74e7bf9ea6"},"checksum":{"sha256":"d2595e8af8468c19a5da6c3fffbf27ff8e00d7ac2559a87f60591829151fd7e3","size":59707392},"installed":{"timestamp":"2024-12-16T14:40:54Z","count":12},"activated":{"timestamp":"2024-12-16T14:40:54Z","count":12},"status":"ok"}}},{"rootfs.0":{"class":"rootfs","device":"/dev/disk/by-partlabel/primary","type":"raw","bootname":"primary","state":"inactive","parent":null,"mountpoint":null,"boot_status":"bad","slot_status":{"bundle":{"compatible":"infix-aarch64","version":"pr871.a4ef38f","hash":"d36189afff31ac1193ee7eda161f7e9b2007df08ccdc0014cfa231f9a836780a"},"checksum":{"sha256":"d78a9ef52f08238972b6b9151c381327dd0c40e410f9ed4634e379056f9bacd8","size":59699200},"installed":{"timestamp":"2024-12-13T20:00:42Z","count":3},"activated":{"timestamp":"2024-12-13T20:00:42Z","count":4},"status":"ok"}}},{"net.0":{"class":"net","device":"/dev/ram0","type":"raw","bootname":"net","state":"booted","parent":null,"mountpoint":null,"boot_status":"good","slot_status":{"bundle":{"compatible":null}}}}]}
2 changes: 0 additions & 2 deletions test/case/ietf_system/upgrade/Readme.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ endif::topdoc[]
. Wait for upgrade to finish
. Verify boot order has changed and reboot
. Verify that the partition is the booted
. Restore boot order to original configured
. Verify the boot order is the orignal configured


<<<
Expand Down
Loading

0 comments on commit a8545e3

Please sign in to comment.