Skip to content

Commit b88b96f

Browse files
blu3chipsxclaude
andcommitted
feat(migrate): support custom data-dir (2nd disk) migrations
migrate-node-naming.sh 1.1.0 -> 1.2.0. Ran tools/gen-checksums.sh per AGENTS.md. Previously the migration hard-aborted on any custom DATA_DIR (a node installed on a 2nd disk/SSD, e.g. /mnt/data), even though setup-node.sh supports installing there. Now it migrates those nodes too, keeping the data exactly where it is. Introduce EFFECTIVE_DATA_DIR = where the data ends up under the unified layout: - default role-suffixed (/var/lib/telcoin/<role>) or already-unified: collapse onto /var/lib/telcoin (relocate moves it) -- unchanged behaviour. - CUSTOM mount (setup-node.sh records the operator's exact path, no role suffix): PRESERVE it in place. relocate_dir() no-ops it (src==dst), so the multi-GB db never makes a slow/risky cross-fs copy onto the boot disk; only the NAMING is unified. Thread EFFECTIVE_DATA_DIR through the relocate call, .node-meta DATA_DIR + node-info path, the plan/report display, and the rollback (reverse from where data was actually moved to -- correct by construction; MOVED_DATA is only ever true in the default case). Config always relocates /etc/telcoin/<role> -> /etc/telcoin (never on the custom mount). Rollback stays safe: a custom mount moves nothing (MOVED_DATA=false), so rollback only restores the unit/wrapper/meta. Validated: bash -n, decision-logic unit test across default/unified/custom cases, sidecar integrity. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 6af5a16 commit b88b96f

2 files changed

Lines changed: 37 additions & 20 deletions

File tree

migrate-node-naming.sh

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ source "${SCRIPT_DIR}/lib/common.sh"
6666
set -E
6767

6868
# Version, gated by update-scripts.sh like every other tracked file.
69-
readonly SCRIPT_VERSION="1.1.0"
69+
readonly SCRIPT_VERSION="1.2.0"
7070

7171
# Unified (target) identity -- mirrors lib/fallback.sh's canonical new-install names.
7272
readonly SYSTEMD_DIR="/etc/systemd/system"
@@ -82,6 +82,10 @@ LEGACY_UNIT="" # /etc/systemd/system/telcoin-<role>.service
8282
LEGACY_WRAPPER="" # /opt/telcoin/start-telcoin-<role>.sh (read from ExecStart)
8383
LEGACY_CONFIG_DIR="" # /etc/telcoin/<role>
8484
LEGACY_DATA_DIR="" # /var/lib/telcoin/<role> (or .node-meta DATA_DIR)
85+
EFFECTIVE_DATA_DIR="" # where the data ENDS UP under the unified layout: /var/lib/telcoin for
86+
# a default role-suffixed install, or the operator's custom mount kept
87+
# AS-IS (a 2nd disk, e.g. /mnt/data) -- see detect_legacy.
88+
CUSTOM_DATA_DIR=false # true when the node lives on a custom mount (data preserved in place)
8589
LEGACY_CONTAINER="" # telcoin-<role>
8690
RPC_PORT="${DEFAULT_RPC_PORT:-8545}" # post-start verify port; the unified node runs with NO
8791
# --instance, so it serves RPC on the protocol default (8545), not 8541.
@@ -153,10 +157,14 @@ rollback() {
153157

154158
local base
155159
if [[ "$MOVED_DATA" == true ]]; then
160+
# Reverse from where the data was actually moved TO (EFFECTIVE_DATA_DIR). MOVED_DATA is
161+
# only ever true for the default layout (a custom mount no-ops the relocate: src==dst),
162+
# where EFFECTIVE_DATA_DIR == UNIFIED_DATA_DIR -- but key off EFFECTIVE so the reverse is
163+
# correct by construction.
156164
mkdir -p "$LEGACY_DATA_DIR"
157165
for base in "${DATA_MOVED[@]}"; do
158-
[[ -e "${UNIFIED_DATA_DIR}/${base}" ]] && \
159-
mv "${UNIFIED_DATA_DIR}/${base}" "${LEGACY_DATA_DIR}/${base}"
166+
[[ -e "${EFFECTIVE_DATA_DIR}/${base}" ]] && \
167+
mv "${EFFECTIVE_DATA_DIR}/${base}" "${LEGACY_DATA_DIR}/${base}"
160168
done
161169
# mkdir above (re)created the dir as root; restore the captured owner so the legacy
162170
# node can write to its datadir. Without this a "rolled-back" node still can't rotate
@@ -255,16 +263,19 @@ detect_legacy() {
255263
LEGACY_DATA_DIR="${UNIFIED_DATA_DIR}/${ROLE}"
256264
fi
257265

258-
# Only the role-suffixed default (or an already-unified dir) is auto-relocated.
259-
# A custom DATA_DIR (the setup wizard allows one) is NOT moved: it could be a
260-
# slow, risky cross-filesystem copy of the multi-GB db, and the path subs only
261-
# rewrite the default. Abort and let the operator handle it.
262-
if [[ "$LEGACY_DATA_DIR" != "$UNIFIED_DATA_DIR" \
263-
&& "$LEGACY_DATA_DIR" != "${UNIFIED_DATA_DIR}/${ROLE}" ]]; then
264-
print_error "Custom data dir detected: ${LEGACY_DATA_DIR}"
265-
print_info "This migration only relocates the default ${UNIFIED_DATA_DIR}/${ROLE} layout."
266-
print_info "Move the data to ${UNIFIED_DATA_DIR}/${ROLE} first, or migrate manually."
267-
exit 1
266+
# Where the data ENDS UP under the unified layout:
267+
# - Default role-suffixed (/var/lib/telcoin/<role>) or already-unified
268+
# (/var/lib/telcoin): collapse onto /var/lib/telcoin (the relocate below moves it).
269+
# - CUSTOM mount (a 2nd disk/SSD, e.g. /mnt/data -- setup-node.sh records the
270+
# operator's exact path as DATA_DIR, no role suffix): PRESERVE it in place. The
271+
# data never leaves its disk (no slow/risky cross-fs copy onto the boot disk),
272+
# and relocate_dir() no-ops it because src == dst. Only the NAMING is unified.
273+
if [[ "$LEGACY_DATA_DIR" == "$UNIFIED_DATA_DIR" \
274+
|| "$LEGACY_DATA_DIR" == "${UNIFIED_DATA_DIR}/${ROLE}" ]]; then
275+
EFFECTIVE_DATA_DIR="$UNIFIED_DATA_DIR"
276+
else
277+
EFFECTIVE_DATA_DIR="$LEGACY_DATA_DIR"
278+
CUSTOM_DATA_DIR=true
268279
fi
269280

270281
# Wrapper path: read the unit's ExecStart= (authoritative), else convention.
@@ -299,7 +310,11 @@ detect_legacy() {
299310
print_info " unit: ${UNIFIED_UNIT}"
300311
print_info " wrapper: ${UNIFIED_WRAPPER}"
301312
print_info " config dir: ${UNIFIED_CONFIG_DIR}"
302-
print_info " data dir: ${UNIFIED_DATA_DIR}"
313+
if [[ "$CUSTOM_DATA_DIR" == true ]]; then
314+
print_info " data dir: ${EFFECTIVE_DATA_DIR} (custom mount -- preserved in place, no data moved)"
315+
else
316+
print_info " data dir: ${EFFECTIVE_DATA_DIR}"
317+
fi
303318
print_info " RPC port: ${RPC_PORT} (default; --observer/--instance removed)"
304319
echo ""
305320

@@ -507,11 +522,13 @@ update_meta() {
507522
: > "$meta"
508523
fi
509524
local ws_port=8546 # reth WS default with no --instance (legacy --instance 5 -> 8554)
510-
print_step "Updating ${meta} (NODE_TYPE=observer, DATA_DIR=${UNIFIED_DATA_DIR}, RPC_PORT=${RPC_PORT}, WS_PORT=${ws_port})"
525+
print_step "Updating ${meta} (NODE_TYPE=observer, DATA_DIR=${EFFECTIVE_DATA_DIR}, RPC_PORT=${RPC_PORT}, WS_PORT=${ws_port})"
511526
# NODE_TYPE is only the default-view HINT; the UI promotes to the validator view
512527
# from on-chain tn_isValidator. Every migrated node is the same identity.
513528
meta_set NODE_TYPE observer "$meta"
514-
meta_set DATA_DIR "$UNIFIED_DATA_DIR" "$meta"
529+
# EFFECTIVE_DATA_DIR: /var/lib/telcoin for a default install, or the operator's
530+
# preserved custom mount (2nd disk) -- so the node keeps finding its data.
531+
meta_set DATA_DIR "$EFFECTIVE_DATA_DIR" "$meta"
515532
# RPC + WS revert to their protocol defaults now that --instance is stripped (the legacy
516533
# observer's --instance 5 put them on 8541/8554). RPC_PORT/WS_PORT in .node-meta are read by
517534
# the local Node Manager UI, check-node.sh, and install-caddy.sh (operator-facing, this repo)
@@ -525,7 +542,7 @@ update_meta() {
525542
# Optional: record VALIDATOR_ADDRESS from node-info.yaml execution_address for
526543
# the UI's on-chain status card. NOT consumed at node launch (only by keygen /
527544
# staking and the post-start status check), so it is purely informational here.
528-
local ni="${UNIFIED_DATA_DIR}/node-info.yaml" exec_addr=""
545+
local ni="${EFFECTIVE_DATA_DIR}/node-info.yaml" exec_addr=""
529546
if [[ -f "$ni" ]]; then
530547
exec_addr="$(grep -E '^[[:space:]]*execution_address[[:space:]]*:' "$ni" 2>/dev/null \
531548
| head -n1 | sed -E 's/.*:[[:space:]]*"?([0-9a-fA-Fx]+)"?.*/\1/' || true)"
@@ -644,7 +661,7 @@ report() {
644661
print_info " unit: ${UNIFIED_UNIT}"
645662
print_info " wrapper: ${UNIFIED_WRAPPER}"
646663
print_info " config dir: ${UNIFIED_CONFIG_DIR}"
647-
print_info " data dir: ${UNIFIED_DATA_DIR}"
664+
print_info " data dir: ${EFFECTIVE_DATA_DIR}$([[ "$CUSTOM_DATA_DIR" == true ]] && echo ' (custom mount, preserved)')"
648665
print_info " NODE_TYPE: observer (presentation hint; on-chain tn_isValidator is authoritative)"
649666
echo ""
650667
print_info "Node RPC/WS now on ${RPC_PORT}/8546 (was 8541/8554 under --instance). The local"
@@ -674,7 +691,7 @@ main() {
674691
snapshot # step 2 (arms rollback)
675692
stop_legacy # step 3
676693
relocate_dir "$LEGACY_CONFIG_DIR" "$UNIFIED_CONFIG_DIR" CONFIG_MOVED config # step 4
677-
relocate_dir "$LEGACY_DATA_DIR" "$UNIFIED_DATA_DIR" DATA_MOVED data # step 5
694+
relocate_dir "$LEGACY_DATA_DIR" "$EFFECTIVE_DATA_DIR" DATA_MOVED data # step 5 (no-op for a custom mount: src==dst)
678695
rewrite_unit # step 6
679696
rewrite_wrapper # step 7 (strip --observer and --instance)
680697
update_meta # step 8

migrate-node-naming.sh.sha256

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
e3e438695d12132d1fa3c4ef598b1033d165fa07a9a1d1508bbc33a1558df660 migrate-node-naming.sh
1+
636cd2d4c109254006ea7a0451fcbd6632adae86d46b02a8a4146055b937f2e7 migrate-node-naming.sh

0 commit comments

Comments
 (0)