mirror of
https://github.com/home-assistant/operating-system.git
synced 2025-07-24 13:36:31 +00:00
Rewrite datactl command (#1046)
* Rewrite datactl command Prepare the target partition as part of the datactl command. Rely on partlabel for the target disk since we are always using GPT on the target disk. Use systemd and partlabel mechanism to wait and find the target data disk. Keep using the file system label to identify the source disk. Also use e2image instead of raw dd to move data. This should speed up the processes significantly. * Fix corner case when reusing same disk again
This commit is contained in:
parent
1537d02408
commit
46bb12844f
@ -51,10 +51,13 @@ Log in as `root` to get to the Home Assistant CLI and then enter `login` to cont
|
||||
|
||||
Confirm your USB SSD/HD is connected and recognized using `fdisk -l`.
|
||||
|
||||
Make sure the drive has no partition named `hassos-data` (or no partition at all). With the drive, use the below command (again, replacing XXX with your drive)
|
||||
With the drive connected, use the following command (replacing sdx with your drive, without a partition number):
|
||||
|
||||
```sh
|
||||
$ datactl move /dev/xxx
|
||||
$ datactl move /dev/sdx
|
||||
```
|
||||
|
||||
Hit any key to continue, and then the move will happen after the next reboot. Once complete, the external drive will be owned and used by the system.
|
||||
Enter "yes" to confirm the operation. This will prepare the disk, however, the
|
||||
actual move will be running on next reboot. Once complete, the external drive
|
||||
will contain the data and will need to be plugged in to successfully boot Home
|
||||
Assistant OS.
|
||||
|
@ -34,6 +34,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
|
||||
BR2_PACKAGE_PROCPS_NG=y
|
||||
BR2_PACKAGE_JQ=y
|
||||
BR2_PACKAGE_E2FSPROGS=y
|
||||
BR2_PACKAGE_E2FSPROGS_E2IMAGE=y
|
||||
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
|
||||
BR2_PACKAGE_SQUASHFS=y
|
||||
BR2_PACKAGE_LINUX_FIRMWARE=y
|
||||
|
@ -36,6 +36,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
|
||||
BR2_PACKAGE_PROCPS_NG=y
|
||||
BR2_PACKAGE_JQ=y
|
||||
BR2_PACKAGE_E2FSPROGS=y
|
||||
BR2_PACKAGE_E2FSPROGS_E2IMAGE=y
|
||||
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
|
||||
BR2_PACKAGE_SQUASHFS=y
|
||||
BR2_PACKAGE_CRDA=y
|
||||
|
@ -36,6 +36,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
|
||||
BR2_PACKAGE_PROCPS_NG=y
|
||||
BR2_PACKAGE_JQ=y
|
||||
BR2_PACKAGE_E2FSPROGS=y
|
||||
BR2_PACKAGE_E2FSPROGS_E2IMAGE=y
|
||||
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
|
||||
BR2_PACKAGE_SQUASHFS=y
|
||||
BR2_PACKAGE_CRDA=y
|
||||
|
@ -36,6 +36,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
|
||||
BR2_PACKAGE_PROCPS_NG=y
|
||||
BR2_PACKAGE_JQ=y
|
||||
BR2_PACKAGE_E2FSPROGS=y
|
||||
BR2_PACKAGE_E2FSPROGS_E2IMAGE=y
|
||||
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
|
||||
BR2_PACKAGE_SQUASHFS=y
|
||||
BR2_PACKAGE_CRDA=y
|
||||
|
@ -36,6 +36,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
|
||||
BR2_PACKAGE_PROCPS_NG=y
|
||||
BR2_PACKAGE_JQ=y
|
||||
BR2_PACKAGE_E2FSPROGS=y
|
||||
BR2_PACKAGE_E2FSPROGS_E2IMAGE=y
|
||||
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
|
||||
BR2_PACKAGE_SQUASHFS=y
|
||||
BR2_PACKAGE_LINUX_FIRMWARE=y
|
||||
|
@ -35,6 +35,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
|
||||
BR2_PACKAGE_PROCPS_NG=y
|
||||
BR2_PACKAGE_JQ=y
|
||||
BR2_PACKAGE_E2FSPROGS=y
|
||||
BR2_PACKAGE_E2FSPROGS_E2IMAGE=y
|
||||
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
|
||||
BR2_PACKAGE_SQUASHFS=y
|
||||
BR2_PACKAGE_CRDA=y
|
||||
|
@ -37,6 +37,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
|
||||
BR2_PACKAGE_PROCPS_NG=y
|
||||
BR2_PACKAGE_JQ=y
|
||||
BR2_PACKAGE_E2FSPROGS=y
|
||||
BR2_PACKAGE_E2FSPROGS_E2IMAGE=y
|
||||
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
|
||||
BR2_PACKAGE_SQUASHFS=y
|
||||
BR2_PACKAGE_RPI_WIFI_FIRMWARE=y
|
||||
|
@ -37,6 +37,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
|
||||
BR2_PACKAGE_PROCPS_NG=y
|
||||
BR2_PACKAGE_JQ=y
|
||||
BR2_PACKAGE_E2FSPROGS=y
|
||||
BR2_PACKAGE_E2FSPROGS_E2IMAGE=y
|
||||
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
|
||||
BR2_PACKAGE_SQUASHFS=y
|
||||
BR2_PACKAGE_RPI_FIRMWARE=y
|
||||
|
@ -37,6 +37,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
|
||||
BR2_PACKAGE_PROCPS_NG=y
|
||||
BR2_PACKAGE_JQ=y
|
||||
BR2_PACKAGE_E2FSPROGS=y
|
||||
BR2_PACKAGE_E2FSPROGS_E2IMAGE=y
|
||||
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
|
||||
BR2_PACKAGE_SQUASHFS=y
|
||||
BR2_PACKAGE_RPI_FIRMWARE=y
|
||||
|
@ -37,6 +37,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
|
||||
BR2_PACKAGE_PROCPS_NG=y
|
||||
BR2_PACKAGE_JQ=y
|
||||
BR2_PACKAGE_E2FSPROGS=y
|
||||
BR2_PACKAGE_E2FSPROGS_E2IMAGE=y
|
||||
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
|
||||
BR2_PACKAGE_SQUASHFS=y
|
||||
BR2_PACKAGE_RPI_FIRMWARE=y
|
||||
|
@ -37,6 +37,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
|
||||
BR2_PACKAGE_PROCPS_NG=y
|
||||
BR2_PACKAGE_JQ=y
|
||||
BR2_PACKAGE_E2FSPROGS=y
|
||||
BR2_PACKAGE_E2FSPROGS_E2IMAGE=y
|
||||
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
|
||||
BR2_PACKAGE_SQUASHFS=y
|
||||
BR2_PACKAGE_RPI_FIRMWARE=y
|
||||
|
@ -37,6 +37,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
|
||||
BR2_PACKAGE_PROCPS_NG=y
|
||||
BR2_PACKAGE_JQ=y
|
||||
BR2_PACKAGE_E2FSPROGS=y
|
||||
BR2_PACKAGE_E2FSPROGS_E2IMAGE=y
|
||||
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
|
||||
BR2_PACKAGE_SQUASHFS=y
|
||||
BR2_PACKAGE_RPI_FIRMWARE=y
|
||||
|
@ -37,6 +37,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
|
||||
BR2_PACKAGE_PROCPS_NG=y
|
||||
BR2_PACKAGE_JQ=y
|
||||
BR2_PACKAGE_E2FSPROGS=y
|
||||
BR2_PACKAGE_E2FSPROGS_E2IMAGE=y
|
||||
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
|
||||
BR2_PACKAGE_SQUASHFS=y
|
||||
BR2_PACKAGE_RPI_FIRMWARE=y
|
||||
|
@ -38,6 +38,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
|
||||
BR2_PACKAGE_PROCPS_NG=y
|
||||
BR2_PACKAGE_JQ=y
|
||||
BR2_PACKAGE_E2FSPROGS=y
|
||||
BR2_PACKAGE_E2FSPROGS_E2IMAGE=y
|
||||
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
|
||||
BR2_PACKAGE_SQUASHFS=y
|
||||
BR2_PACKAGE_LINUX_FIRMWARE=y
|
||||
|
@ -1,31 +1,59 @@
|
||||
#!/bin/sh
|
||||
# ==============================================================================
|
||||
# HassOS data partition handling
|
||||
# Home Assistant OS data partition handling
|
||||
# ==============================================================================
|
||||
set -e
|
||||
|
||||
OPTION_FILE=/mnt/overlay/data.opt
|
||||
DATA_DEVICE_CHILD="$(findfs LABEL="hassos-data")"
|
||||
# Use current mount point. This avoids "Can't be the same disk!" error
|
||||
# when using a drive which has been used as a data drive previously.
|
||||
DATA_DEVICE_CHILD="$(findmnt --noheadings --output=source /mnt/data)"
|
||||
DATA_DEVICE_ROOT="/dev/$(lsblk -no pkname "${DATA_DEVICE_CHILD}")"
|
||||
|
||||
# Move command
|
||||
if [ "${1}" = "move" ] && [ -e "${2}" ]; then
|
||||
DEVICE="${2}"
|
||||
NEW_DEVICE_ROOT="${2}"
|
||||
|
||||
# Check device
|
||||
if ! lsblk "${DEVICE}" | grep disk > /dev/null 2>&1; then
|
||||
if ! lsblk "${NEW_DEVICE_ROOT}" | grep disk > /dev/null 2>&1; then
|
||||
echo "[ERROR] Is not disk!"
|
||||
exit 1
|
||||
elif [ "${DEVICE}" = "${DATA_DEVICE_ROOT}" ]; then
|
||||
elif [ "${NEW_DEVICE_ROOT}" = "${DATA_DEVICE_ROOT}" ]; then
|
||||
echo "[ERROR] Can't be the same disk!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Flag device
|
||||
echo "WARNING: ${DEVICE} will be reset on next restart!"
|
||||
echo "Press a key to move forward"
|
||||
read -r
|
||||
echo "WARNING: All partitions on ${NEW_DEVICE_ROOT} will be deleted!"
|
||||
printf "Enter \"yes\" to confirm: "
|
||||
read -r confirm
|
||||
if [ "${confirm}" != "yes" ]; then
|
||||
echo "Aborting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sgdisk --zap-all "${NEW_DEVICE_ROOT}"
|
||||
sgdisk \
|
||||
-n "0:0:0" \
|
||||
-c "0:hassos-data-external" \
|
||||
-t "0:0FC63DAF-8483-4772-8E79-3D69D8477DE4" \
|
||||
-u "0:a52a4597-fa3a-4851-aefd-2fbe9f849079" \
|
||||
"${NEW_DEVICE_ROOT}"
|
||||
|
||||
touch "/mnt/overlay/move-data"
|
||||
cat << EOF
|
||||
Disk ${NEW_DEVICE_ROOT} has been prepared to be used as data drive and the data
|
||||
move has been scheduled for the next reboot. Please reboot the device now and
|
||||
make sure to leave the disk connected to the system from now on.
|
||||
EOF
|
||||
|
||||
else
|
||||
cat << EOF
|
||||
Usage: datactl move <device>
|
||||
|
||||
Moves data partition to external device provided by <device> (without partition
|
||||
number). A new partition table and a partition for the complete device will be
|
||||
created by datactl.
|
||||
EOF
|
||||
|
||||
echo "${DEVICE}" > ${OPTION_FILE}
|
||||
fi
|
||||
|
||||
|
@ -1,16 +1,17 @@
|
||||
[Unit]
|
||||
Description=HassOS data partition
|
||||
Description=Home Assistant OS data partition migration
|
||||
DefaultDependencies=no
|
||||
RefuseManualStart=true
|
||||
RefuseManualStop=true
|
||||
Requires=mnt-overlay.mount dev-disk-by\x2dlabel-hassos\x2ddata.device
|
||||
Requires=mnt-overlay.mount dev-disk-by\x2dlabel-hassos\x2ddata.device dev-disk-by\x2dpartlabel-hassos\x2ddata\x2dexternal.service
|
||||
Wants=hassos-expand.service
|
||||
After=mnt-overlay.mount dev-disk-by\x2dlabel-hassos\x2ddata.device systemd-fsck@dev-disk-by\x2dlabel-hassos\x2ddata.service
|
||||
After=mnt-overlay.mount dev-disk-by\x2dlabel-hassos\x2ddata.device systemd-fsck@dev-disk-by\x2dlabel-hassos\x2ddata.service dev-disk-by\x2dpartlabel-hassos\x2ddata\x2dexternal.service
|
||||
Before=hassos-expand.service
|
||||
ConditionPathExists=/mnt/overlay/data.opt
|
||||
ConditionPathExists=/mnt/overlay/move-data
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStartPre=-/usr/bin/rm -f /mnt/overlay/move-data
|
||||
ExecStart=/usr/libexec/hassos-data
|
||||
|
||||
[Install]
|
||||
|
@ -1,83 +1,24 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC2039
|
||||
# ==============================================================================
|
||||
# HassOS data partition handler
|
||||
# Home Assistant OS data partition migration script
|
||||
# ==============================================================================
|
||||
set -e
|
||||
|
||||
OPTION_FILE=/mnt/overlay/data.opt
|
||||
# Rely on systemd-udev symlinks to find current data partition by fs label
|
||||
OLD_DEVICE_CHILD="$(readlink -f "/dev/disk/by-label/hassos-data")"
|
||||
|
||||
# New data partition exits
|
||||
if ! [ -e "${OPTION_FILE}" ]; then
|
||||
echo "[INFO] No data option found"
|
||||
exit 0
|
||||
else
|
||||
NEW_DEVICE_ROOT="$(cat ${OPTION_FILE})"
|
||||
rm ${OPTION_FILE}
|
||||
fi
|
||||
# Rely on systemd-udev symlinks to find external data partition by partlabel
|
||||
NEW_DEVICE_CHILD="$(readlink -f "/dev/disk/by-partlabel/hassos-data-external")"
|
||||
|
||||
# Get device information
|
||||
OLD_DEVICE_CHILD="$(findfs LABEL="hassos-data")"
|
||||
OLD_DEVICE_ROOT="/dev/$(lsblk -no pkname "${OLD_DEVICE_CHILD}")"
|
||||
OLD_PART_NUM="${OLD_DEVICE_CHILD: -1}"
|
||||
|
||||
# Wait for devices
|
||||
timeout 90 \
|
||||
ash -c \
|
||||
"until [ -e \"${NEW_DEVICE_ROOT}\" ]; do sleep 5; done" \
|
||||
> /dev/null 2>&1 || true;
|
||||
|
||||
# Check if block device is exists
|
||||
if [ ! -b "${NEW_DEVICE_ROOT}" ]; then
|
||||
echo "[ERROR] No block device ${NEW_DEVICE_ROOT}!"
|
||||
exit 1
|
||||
fi
|
||||
echo "[INFO] Cleanup device ${NEW_DEVICE_ROOT}!"
|
||||
sgdisk -Z "${NEW_DEVICE_ROOT}"
|
||||
|
||||
# Create new partition
|
||||
echo "[INFO] Create new hassos-data partition"
|
||||
sgdisk -o "${NEW_DEVICE_ROOT}"
|
||||
sgdisk \
|
||||
-n "0:0:0" \
|
||||
-c "0:hassos-data" \
|
||||
-t "0:0FC63DAF-8483-4772-8E79-3D69D8477DE4" \
|
||||
-u "0:a52a4597-fa3a-4851-aefd-2fbe9f849079" \
|
||||
"${NEW_DEVICE_ROOT}"
|
||||
sgdisk -v "${NEW_DEVICE_ROOT}"
|
||||
partx -u "${NEW_DEVICE_ROOT}"
|
||||
|
||||
NEW_DEVICE_CHILD="$(fdisk -l "${NEW_DEVICE_ROOT}" | grep '^/dev' | cut -d' ' -f1 | head -n 1)"
|
||||
|
||||
echo "[INFO] Move hassos-data from ${OLD_DEVICE_CHILD} to ${NEW_DEVICE_CHILD}"
|
||||
if ! dd if="${OLD_DEVICE_CHILD}" of="${NEW_DEVICE_CHILD}" status=none; then
|
||||
echo "[ERROR] Data copy fails!"
|
||||
|
||||
# Reset new data partition
|
||||
sgdisk -o "${NEW_DEVICE_ROOT}"
|
||||
partx -u "${NEW_DEVICE_ROOT}"
|
||||
echo "[INFO] Moving data from ${OLD_DEVICE_CHILD} to ${NEW_DEVICE_CHILD}"
|
||||
if ! e2image -ra -p "${OLD_DEVICE_CHILD}" "${NEW_DEVICE_CHILD}"; then
|
||||
echo "[ERROR] Copying data partition to external device failed!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[INFO] Remove old hassos-data partition ${OLD_PART_NUM} / ${OLD_DEVICE_ROOT}"
|
||||
if sfdisk -dq "${OLD_DEVICE_ROOT}" | grep -q 'label: gpt'; then
|
||||
sgdisk -d "${OLD_PART_NUM}" "${OLD_DEVICE_ROOT}"
|
||||
sgdisk -v "${OLD_DEVICE_ROOT}"
|
||||
# At this point we have two partition with the same fs label. Make sure
|
||||
# to rename the internal partition so we won't mount it anymore.
|
||||
echo "[INFO] Rename old hassos-data partition ${OLD_DEVICE_CHILD}"
|
||||
e2label "${OLD_DEVICE_CHILD}" hassos-data-old
|
||||
|
||||
else
|
||||
sfdisk --delete "${OLD_DEVICE_ROOT}" "${OLD_PART_NUM}" --force
|
||||
sfdisk -V "${OLD_DEVICE_ROOT}"
|
||||
fi
|
||||
|
||||
echo "[INFO] fix filesystem & layout"
|
||||
|
||||
# Fix filesystem
|
||||
e2fsck -y "${NEW_DEVICE_CHILD}"
|
||||
resize2fs -f "${NEW_DEVICE_CHILD}"
|
||||
|
||||
# Fix partition layout
|
||||
partx -d "${OLD_DEVICE_CHILD}"
|
||||
partx -u "${OLD_DEVICE_ROOT}"
|
||||
partx -u "${NEW_DEVICE_ROOT}"
|
||||
|
||||
echo "[INFO] Finish hassos data movement"
|
||||
echo "[INFO] Data move has been completed successfully"
|
||||
|
Loading…
x
Reference in New Issue
Block a user