fix: inject DNS defaults on forkop->tachyon migration, add LuCI E2E check
Fixes Tachyon startup abort when migrated config has no dns_server or bootstrap_dns_server (forkop/podkop did not require these fields). Changes: - migration.uc: add ensure_dns_server_defaults migration that injects 77.88.8.8 as fallback when either dns list is empty - default config: pre-mark orphan_section_interface_cleanup and ensure_dns_server_defaults as applied so fresh installs skip them - tests/config_migration.sh: regression tests for both missing-DNS cases and stable named-marker assertion for the new migration - tests/package_contract.sh: enforce that default config ships both new migration IDs in applied_migrations - tests/docker_e2e_test.sh: also install luci-app-tachyon and verify menu.d + acl.d files are present after install (LuCI menu bug class)
This commit is contained in:
@@ -5,6 +5,8 @@ config settings 'settings'
|
|||||||
list applied_migrations 'http_connection_urls'
|
list applied_migrations 'http_connection_urls'
|
||||||
list applied_migrations 'dns_hosts_to_option'
|
list applied_migrations 'dns_hosts_to_option'
|
||||||
list applied_migrations 'global_hosts_to_section'
|
list applied_migrations 'global_hosts_to_section'
|
||||||
|
list applied_migrations 'orphan_section_interface_cleanup'
|
||||||
|
list applied_migrations 'ensure_dns_server_defaults'
|
||||||
option dns_type 'udp'
|
option dns_type 'udp'
|
||||||
list dns_server '77.88.8.8'
|
list dns_server '77.88.8.8'
|
||||||
list bootstrap_dns_server '77.88.8.8'
|
list bootstrap_dns_server '77.88.8.8'
|
||||||
|
|||||||
@@ -1292,6 +1292,35 @@ function migrate_http_connection_urls(ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure both main and bootstrap DNS server lists have at least one entry.
|
||||||
|
// forkop/podkop did not require bootstrap_dns_server, so it is often absent after
|
||||||
|
// migration. The validator refuses to start Tachyon when either list is empty.
|
||||||
|
// The default "77.88.8.8" matches the runtime fallback in singbox/dns.uc.
|
||||||
|
function migrate_ensure_dns_server_defaults(ctx) {
|
||||||
|
let settings = ctx.model.settings;
|
||||||
|
let dns_server = list_option(settings, "dns_server");
|
||||||
|
let has_dns = false;
|
||||||
|
for (let v in dns_server) {
|
||||||
|
if (as_string(v) != "") {
|
||||||
|
has_dns = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!has_dns)
|
||||||
|
set_list_option(ctx, settings, "dns_server", [ "77.88.8.8" ]);
|
||||||
|
|
||||||
|
let bootstrap = list_option(settings, "bootstrap_dns_server");
|
||||||
|
let has_bootstrap = false;
|
||||||
|
for (let v in bootstrap) {
|
||||||
|
if (as_string(v) != "") {
|
||||||
|
has_bootstrap = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!has_bootstrap)
|
||||||
|
set_list_option(ctx, settings, "bootstrap_dns_server", [ "77.88.8.8" ]);
|
||||||
|
}
|
||||||
|
|
||||||
function migrate_dns_hosts_to_option(ctx) {
|
function migrate_dns_hosts_to_option(ctx) {
|
||||||
let raw = object_or_empty(ctx.model.settings)["dns_hosts"];
|
let raw = object_or_empty(ctx.model.settings)["dns_hosts"];
|
||||||
if (raw == null)
|
if (raw == null)
|
||||||
@@ -1405,7 +1434,8 @@ const MIGRATIONS = [
|
|||||||
{ id: "http_connection_urls", run: migrate_http_connection_urls },
|
{ id: "http_connection_urls", run: migrate_http_connection_urls },
|
||||||
{ id: "dns_hosts_to_option", run: migrate_dns_hosts_to_option },
|
{ id: "dns_hosts_to_option", run: migrate_dns_hosts_to_option },
|
||||||
{ id: "global_hosts_to_section", run: migrate_global_hosts_to_section },
|
{ id: "global_hosts_to_section", run: migrate_global_hosts_to_section },
|
||||||
{ id: "orphan_section_interface_cleanup", run: migrate_orphan_section_interfaces }
|
{ id: "orphan_section_interface_cleanup", run: migrate_orphan_section_interfaces },
|
||||||
|
{ id: "ensure_dns_server_defaults", run: migrate_ensure_dns_server_defaults }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ grep -Fq '{ id: "enable_component_checks", run: migrate_enable_component_checks
|
|||||||
fail "component check migration must have a stable named marker"
|
fail "component check migration must have a stable named marker"
|
||||||
grep -Fq '{ id: "http_connection_urls", run: migrate_http_connection_urls }' "$MIGRATION" ||
|
grep -Fq '{ id: "http_connection_urls", run: migrate_http_connection_urls }' "$MIGRATION" ||
|
||||||
fail "HTTP connection URL migration must have a stable named marker"
|
fail "HTTP connection URL migration must have a stable named marker"
|
||||||
|
grep -Fq '{ id: "ensure_dns_server_defaults", run: migrate_ensure_dns_server_defaults }' "$MIGRATION" ||
|
||||||
|
fail "DNS server defaults migration must have a stable named marker"
|
||||||
grep -Fq 'release_at_most(ctx, "1.0.1")' "$MIGRATION" ||
|
grep -Fq 'release_at_most(ctx, "1.0.1")' "$MIGRATION" ||
|
||||||
fail "release-specific migrations must use the source release only as a condition"
|
fail "release-specific migrations must use the source release only as a condition"
|
||||||
grep -Fq 'release_at_most(ctx, "1.0.4")' "$MIGRATION" ||
|
grep -Fq 'release_at_most(ctx, "1.0.4")' "$MIGRATION" ||
|
||||||
@@ -175,7 +177,7 @@ assert(JSON.stringify(config.settings.dns_server) === JSON.stringify(['9.9.9.9']
|
|||||||
assert(JSON.stringify(config.settings.bootstrap_dns_server) === JSON.stringify(['1.1.1.1']), 'legacy Bootstrap DNS scalar migrated to ordered list');
|
assert(JSON.stringify(config.settings.bootstrap_dns_server) === JSON.stringify(['1.1.1.1']), 'legacy Bootstrap DNS scalar migrated to ordered list');
|
||||||
assert(config.settings.config_version === '1.0.5', 'legacy config should be marked at the current schema version');
|
assert(config.settings.config_version === '1.0.5', 'legacy config should be marked at the current schema version');
|
||||||
assert(config.settings.component_update_check_enabled === '1', 'component update checks should be enabled during migration');
|
assert(config.settings.component_update_check_enabled === '1', 'component update checks should be enabled during migration');
|
||||||
assert(JSON.stringify(config.settings.applied_migrations) === JSON.stringify(['interface_sections', 'enable_component_checks', 'http_connection_urls', 'dns_hosts_to_option', 'global_hosts_to_section', 'orphan_section_interface_cleanup']), 'legacy config should record named migrations');
|
assert(JSON.stringify(config.settings.applied_migrations) === JSON.stringify(['interface_sections', 'enable_component_checks', 'http_connection_urls', 'dns_hosts_to_option', 'global_hosts_to_section', 'orphan_section_interface_cleanup', 'ensure_dns_server_defaults']), 'legacy config should record named migrations');
|
||||||
|
|
||||||
function assert(condition, message) {
|
function assert(condition, message) {
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
@@ -712,4 +714,39 @@ ucode -L "$TACHYON_LIB" "$MIGRATION" commit
|
|||||||
grep -Fxq 'commit tachyon' "$WORK_DIR/uci-commit.log" ||
|
grep -Fxq 'commit tachyon' "$WORK_DIR/uci-commit.log" ||
|
||||||
fail "commit mode must commit tachyon through core.uci"
|
fail "commit mode must commit tachyon through core.uci"
|
||||||
|
|
||||||
|
|
||||||
|
# Regression: forkop configs often lack bootstrap_dns_server.
|
||||||
|
# The ensure_dns_server_defaults migration must inject a default so the validator
|
||||||
|
# does not abort Tachyon startup with "At least one Bootstrap DNS server is required".
|
||||||
|
cat >"$WORK_DIR/no_bootstrap.state" <<'EOF_UCI'
|
||||||
|
tachyon.settings=settings
|
||||||
|
tachyon.settings.dns_server=8.8.8.8
|
||||||
|
EOF_UCI
|
||||||
|
: >"$WORK_DIR/no_bootstrap.log"
|
||||||
|
TACHYON_UCI_STATE_FILE="$WORK_DIR/no_bootstrap.state" \
|
||||||
|
TACHYON_UCI_LOG_FILE="$WORK_DIR/no_bootstrap.log" \
|
||||||
|
TACHYON_CONFIG_NAME="tachyon" \
|
||||||
|
TACHYON_INTERNAL_CONFIG_TRIGGER_GUARD="$WORK_DIR/internal-config-change" \
|
||||||
|
ucode -L "$TACHYON_LIB" "$MIGRATION" migrate
|
||||||
|
|
||||||
|
grep -Fq 'tachyon.settings.bootstrap_dns_server=77.88.8.8' "$WORK_DIR/no_bootstrap.state" ||
|
||||||
|
fail "ensure_dns_server_defaults must inject 77.88.8.8 when bootstrap_dns_server is missing"
|
||||||
|
|
||||||
|
# Regression: forkop configs with neither dns_server nor bootstrap_dns_server must
|
||||||
|
# get both defaults injected.
|
||||||
|
cat >"$WORK_DIR/no_dns.state" <<'EOF_UCI'
|
||||||
|
tachyon.settings=settings
|
||||||
|
EOF_UCI
|
||||||
|
: >"$WORK_DIR/no_dns.log"
|
||||||
|
TACHYON_UCI_STATE_FILE="$WORK_DIR/no_dns.state" \
|
||||||
|
TACHYON_UCI_LOG_FILE="$WORK_DIR/no_dns.log" \
|
||||||
|
TACHYON_CONFIG_NAME="tachyon" \
|
||||||
|
TACHYON_INTERNAL_CONFIG_TRIGGER_GUARD="$WORK_DIR/internal-config-change" \
|
||||||
|
ucode -L "$TACHYON_LIB" "$MIGRATION" migrate
|
||||||
|
|
||||||
|
grep -Fq 'tachyon.settings.dns_server=77.88.8.8' "$WORK_DIR/no_dns.state" ||
|
||||||
|
fail "ensure_dns_server_defaults must inject 77.88.8.8 for missing dns_server"
|
||||||
|
grep -Fq 'tachyon.settings.bootstrap_dns_server=77.88.8.8' "$WORK_DIR/no_dns.state" ||
|
||||||
|
fail "ensure_dns_server_defaults must inject 77.88.8.8 for missing bootstrap_dns_server"
|
||||||
|
|
||||||
printf 'installer config migration checks passed\n'
|
printf 'installer config migration checks passed\n'
|
||||||
|
|||||||
@@ -142,6 +142,18 @@ sleep 5
|
|||||||
echo "=== Installing Tachyon IPK ==="
|
echo "=== Installing Tachyon IPK ==="
|
||||||
"$DOCKER_BIN" exec "$CONTAINER_NAME" opkg install --force-reinstall /work/build-out/tachyon_1.0.0.ipk
|
"$DOCKER_BIN" exec "$CONTAINER_NAME" opkg install --force-reinstall /work/build-out/tachyon_1.0.0.ipk
|
||||||
|
|
||||||
|
echo "=== Installing LuCI app IPK ==="
|
||||||
|
"$DOCKER_BIN" exec "$CONTAINER_NAME" opkg install --force-reinstall /work/build-out/luci-app-tachyon_1.0.0.ipk
|
||||||
|
|
||||||
|
echo "=== Verifying LuCI menu and ACL registration ==="
|
||||||
|
"$DOCKER_BIN" exec "$CONTAINER_NAME" test -f /usr/share/luci/menu.d/luci-app-tachyon.json \
|
||||||
|
|| { echo "FAIL: menu.d/luci-app-tachyon.json missing after install"; exit 1; }
|
||||||
|
"$DOCKER_BIN" exec "$CONTAINER_NAME" test -f /usr/share/rpcd/acl.d/luci-app-tachyon.json \
|
||||||
|
|| { echo "FAIL: acl.d/luci-app-tachyon.json missing after install"; exit 1; }
|
||||||
|
"$DOCKER_BIN" exec "$CONTAINER_NAME" grep -q '"tachyon/tachyon"' /usr/share/luci/menu.d/luci-app-tachyon.json \
|
||||||
|
|| { echo "FAIL: menu.d entry does not reference correct view path"; exit 1; }
|
||||||
|
echo "OK: LuCI app registration files in place"
|
||||||
|
|
||||||
echo "=== Configuring Tachyon ==="
|
echo "=== Configuring Tachyon ==="
|
||||||
"$DOCKER_BIN" exec "$CONTAINER_NAME" uci set tachyon.settings.enabled='1'
|
"$DOCKER_BIN" exec "$CONTAINER_NAME" uci set tachyon.settings.enabled='1'
|
||||||
"$DOCKER_BIN" exec "$CONTAINER_NAME" uci set tachyon.settings.log_level='debug'
|
"$DOCKER_BIN" exec "$CONTAINER_NAME" uci set tachyon.settings.log_level='debug'
|
||||||
|
|||||||
@@ -76,6 +76,10 @@ grep -Fq "list applied_migrations 'dns_hosts_to_option'" "$TACHYON_CONFIG" ||
|
|||||||
fail "new installations must mark the dns_hosts to option migration as applied"
|
fail "new installations must mark the dns_hosts to option migration as applied"
|
||||||
grep -Fq "list applied_migrations 'global_hosts_to_section'" "$TACHYON_CONFIG" ||
|
grep -Fq "list applied_migrations 'global_hosts_to_section'" "$TACHYON_CONFIG" ||
|
||||||
fail "new installations must mark the global hosts to section migration as applied"
|
fail "new installations must mark the global hosts to section migration as applied"
|
||||||
|
grep -Fq "list applied_migrations 'orphan_section_interface_cleanup'" "$TACHYON_CONFIG" ||
|
||||||
|
fail "new installations must mark the orphan section interface cleanup migration as applied"
|
||||||
|
grep -Fq "list applied_migrations 'ensure_dns_server_defaults'" "$TACHYON_CONFIG" ||
|
||||||
|
fail "new installations must mark the DNS server defaults migration as applied"
|
||||||
grep -Fq '/usr/lib/tachyon/config/migration.uc migrate' "$TACHYON_MAKEFILE" ||
|
grep -Fq '/usr/lib/tachyon/config/migration.uc migrate' "$TACHYON_MAKEFILE" ||
|
||||||
fail "OpenWrt package postinst must run configuration migrations"
|
fail "OpenWrt package postinst must run configuration migrations"
|
||||||
[ "$(grep -Fc '/usr/lib/tachyon/config/migration.uc migrate' "$BUILD_SCRIPT")" -ge 3 ] ||
|
[ "$(grep -Fc '/usr/lib/tachyon/config/migration.uc migrate' "$BUILD_SCRIPT")" -ge 3 ] ||
|
||||||
|
|||||||
Reference in New Issue
Block a user