|
| 1 | +#!//bin/bash |
| 2 | +# Nov 2025 |
| 3 | +# 45Drives |
| 4 | +# Matthew Hutchinson <mhutchinson@45drives.com> |
| 5 | + |
| 6 | +set -euo pipefail |
| 7 | + |
| 8 | +need() { command -v "$1" >/dev/null 2>&1 || { echo "Missing $1"; exit 1; }; } |
| 9 | +need ceph |
| 10 | +need ceph-volume |
| 11 | +need lvs |
| 12 | +need readlink |
| 13 | +need systemctl |
| 14 | +need awk |
| 15 | + |
| 16 | +stop_osd() { systemctl stop "ceph-osd@$1" 2>/dev/null || true; } |
| 17 | +start_osd() { systemctl start "ceph-osd@$1" 2>/dev/null || true; } |
| 18 | + |
| 19 | +to_vg_lv() { |
| 20 | + local dev="$1" |
| 21 | + if [[ "$dev" =~ ^/dev/[^/]+/[^/]+$ ]]; then |
| 22 | + awk -F'/' '{print $3"/"$4}' <<<"$dev" |
| 23 | + return 0 |
| 24 | + fi |
| 25 | + local vg lv |
| 26 | + read -r vg lv < <(lvs --noheadings -o vg_name,lv_name "$dev" 2>/dev/null | awk '{print $1, $2}') |
| 27 | + if [[ -n "${vg:-}" && -n "${lv:-}" ]]; then |
| 28 | + printf "%s/%s\n" "$vg" "$lv" |
| 29 | + return 0 |
| 30 | + fi |
| 31 | + return 1 |
| 32 | +} |
| 33 | + |
| 34 | +mapfile -t DB_LINKS < <(ls /var/lib/ceph/osd/ceph-*/block.db 2>/dev/null | while read -r p; do [[ -L "$p" ]] && echo "$p"; done) |
| 35 | +
|
| 36 | +if [[ ${#DB_LINKS[@]} -eq 0 ]]; then |
| 37 | + echo "No OSDs on this host have a separate DB. Nothing to do." |
| 38 | + exit 0 |
| 39 | +fi |
| 40 | +
|
| 41 | +OSD_IDS=() |
| 42 | +for link in "${DB_LINKS[@]}"; do |
| 43 | + osd_id="$(basename "$(dirname "$link")" | cut -d- -f2)" |
| 44 | + OSD_IDS+=("$osd_id") |
| 45 | +done |
| 46 | +
|
| 47 | +echo "OSDs to migrate on this host:" |
| 48 | +printf "%s\n" "${OSD_IDS[@]}" |
| 49 | +
|
| 50 | +echo |
| 51 | +read -rp "Continue and migrate all of the above OSDs now? [y/N] " go |
| 52 | +[[ "$go" =~ ^[Yy]$ ]] || { echo "Aborted"; exit 0; } |
| 53 | +
|
| 54 | +echo |
| 55 | +echo "Setting noout for this host" |
| 56 | +ceph osd set noout || true |
| 57 | +cleanup() { echo; echo "Clearing noout"; ceph osd unset noout || true; } |
| 58 | +trap cleanup EXIT |
| 59 | +
|
| 60 | +DB_LVS_TO_REMOVE=() |
| 61 | +
|
| 62 | +for osd_id in "${OSD_IDS[@]}"; do |
| 63 | + osd_dir="/var/lib/ceph/osd/ceph-$osd_id" |
| 64 | + [[ -d "$osd_dir" ]] || { echo "Skipping OSD $osd_id (no directory)"; continue; } |
| 65 | +
|
| 66 | + fsid="$(cat "$osd_dir/fsid" 2>/dev/null || true)" |
| 67 | + block_link="$(readlink "$osd_dir/block" || true)" |
| 68 | + block_real="$(readlink -f "$osd_dir/block" || true)" |
| 69 | + db_lv_link="$(readlink "$osd_dir/block.db" || true)" |
| 70 | +
|
| 71 | + if [[ -z "$fsid" || -z "$db_lv_link" ]]; then |
| 72 | + echo "Skipping OSD $osd_id (missing fsid or block.db)" |
| 73 | + continue |
| 74 | + fi |
| 75 | +
|
| 76 | + target="" |
| 77 | + if target="$(to_vg_lv "$block_link")"; then :; elif target="$(to_vg_lv "$block_real")"; then :; else |
| 78 | + echo "Skipping OSD $osd_id (target vg/lv not found)" |
| 79 | + continue |
| 80 | + fi |
| 81 | +
|
| 82 | + echo |
| 83 | + echo "Migrating OSD $osd_id to $target" |
| 84 | +
|
| 85 | + stop_osd "$osd_id" |
| 86 | + ceph-volume lvm migrate --osd-id "$osd_id" --osd-fsid "$fsid" --from db wal --target "$target" |
| 87 | + start_osd "$osd_id" |
| 88 | +
|
| 89 | + DB_LVS_TO_REMOVE+=("$db_lv_link") |
| 90 | +done |
| 91 | +
|
| 92 | +echo |
| 93 | +echo "All migrations complete." |
| 94 | +
|
| 95 | +if (( ${#DB_LVS_TO_REMOVE[@]} > 0 )); then |
| 96 | + echo |
| 97 | + read -rp "Do you want to remove the old DB LVs to reclaim space? [y/N] " rmdb |
| 98 | + if [[ "$rmdb" =~ ^[Yy]$ ]]; then |
| 99 | + for p in "${DB_LVS_TO_REMOVE[@]}"; do |
| 100 | + echo "Removing $p" |
| 101 | + lvremove -y "$p" || echo "lvremove failed for $p" |
| 102 | + done |
| 103 | + else |
| 104 | + echo |
| 105 | + echo "You chose to keep the old DB LVs. You can remove them later using:" |
| 106 | + for p in "${DB_LVS_TO_REMOVE[@]}"; do |
| 107 | + echo " lvremove -y $p" |
| 108 | + done |
| 109 | + fi |
| 110 | +fi |
| 111 | +
|
| 112 | +echo |
| 113 | +echo "Done." |
0 commit comments