This commit is contained in:
2026-09-06 13:17:57 +08:00
parent 7c5ad9b0c4
commit 487959f30f
4 changed files with 60 additions and 21 deletions

1
.gitignore vendored
View File

@@ -22,3 +22,4 @@ dist-ssr
*.njsproj *.njsproj
*.sln *.sln
*.sw? *.sw?
/debug/

View File

@@ -203,8 +203,13 @@ LVM 场景下VG 的可用空间不足。脚本会先尝试扩展 PV 占满磁
``` ```
LinuxDiskAutoExpansion/ LinuxDiskAutoExpansion/
├── src/ ├── src/
│ └── main.sh # 主脚本 │ └── main.sh # 主脚本
├── README.md # 项目说明文档 ├── debug/
│ └── logs/ # 调试日志
│ ├── ubuntu.log
│ └── centos.log
├── README.md # 项目说明文档
├── USAGE.md # 详细使用文档
└── LinuxDiskAutoExpansion.iml └── LinuxDiskAutoExpansion.iml
``` ```

View File

@@ -88,7 +88,7 @@ sda 8:0 0 50G 0 disk
**方式一Git 克隆(推荐)** **方式一Git 克隆(推荐)**
```bash ```bash
git clone https://github.com/your-repo/LinuxDiskAutoExpansion.git git clone https://git.opensource-studio.info/database-mysql/LinuxDiskAutoExpansion.git
cd LinuxDiskAutoExpansion cd LinuxDiskAutoExpansion
``` ```

View File

@@ -131,6 +131,12 @@ ensure_dependencies() {
fi fi
fi fi
# 检查 parted 或 sfdisk用于获取分区信息
if ! command -v parted &>/dev/null && ! command -v sfdisk &>/dev/null; then
info "parted/sfdisk 未安装,正在安装 parted..."
install_package "parted"
fi
# 检查 lsblk # 检查 lsblk
if ! command -v lsblk &>/dev/null; then if ! command -v lsblk &>/dev/null; then
install_package "util-linux" install_package "util-linux"
@@ -253,6 +259,20 @@ check_expandable_space() {
fi fi
} }
#---------------------------------------
# 安全提取数值(去除小数部分,兼容 set -e
#---------------------------------------
parse_int() {
# 从字符串中提取整数部分,忽略小数和后缀
# 输入: "8217.60" / "8.22g" / " 100 " 等
# 输出: 纯整数字符串,如 "8217" / "8" / "100"
local val="$1"
# 去除首尾空格
val=$(echo "$val" | xargs)
# 提取整数部分(兼容小数点)
echo "$val" | awk '{printf "%d", $1}'
}
#--------------------------------------- #---------------------------------------
# LVM 模式:检查 VG 剩余空间 # LVM 模式:检查 VG 剩余空间
#--------------------------------------- #---------------------------------------
@@ -264,21 +284,24 @@ check_lvm_space() {
fi fi
info "根目录所在卷组 (VG): $ROOT_VG" info "根目录所在卷组 (VG): $ROOT_VG"
# 获取 VG 的可用空间(单位:字节 # 获取 VG 的可用空间(人类可读格式,用于显示
VG_FREE_BYTES=$(vgs -no vg_free "$ROOT_VG" --units b 2>/dev/null | xargs) VG_FREE_HUMAN=$(vgs -no vg_free "$ROOT_VG" --units g --nosuffix 2>/dev/null | xargs)
# 转换为人类可读格式
VG_FREE_HUMAN=$(vgs -no vg_free "$ROOT_VG" --units g 2>/dev/null | xargs)
info "卷组 $ROOT_VG 可用空间: ${VG_FREE_HUMAN}G" info "卷组 $ROOT_VG 可用空间: ${VG_FREE_HUMAN}G"
# 检查 VG 是否有剩余空间 # 检查 VG 是否有剩余空间(以 MB 为单位判断)
VG_FREE_NUM=$(vgs -no vg_free "$ROOT_VG" --units m 2>/dev/null | xargs | grep -oP '^\d+') local vg_free_raw
vg_free_raw=$(vgs -no vg_free "$ROOT_VG" --units m --nosuffix 2>/dev/null)
VG_FREE_NUM=$(parse_int "$vg_free_raw")
info "卷组可用空间: ${VG_FREE_NUM}MB"
if [[ -z "$VG_FREE_NUM" ]] || [[ "$VG_FREE_NUM" -lt 100 ]]; then if [[ -z "$VG_FREE_NUM" ]] || [[ "$VG_FREE_NUM" -lt 100 ]]; then
# VG 没有空间,检查是否是因为 PV 没有占满磁盘 # VG 没有空间,检查是否是因为 PV 没有占满磁盘
info "卷组可用空间不足,将检查是否需要扩展物理卷 (PV)..." info "卷组可用空间不足,将检查是否需要扩展物理卷 (PV)..."
expand_pv_if_needed expand_pv_if_needed
# 重新获取可用空间 # 重新获取可用空间
VG_FREE_NUM=$(vgs -no vg_free "$ROOT_VG" --units m 2>/dev/null | xargs | grep -oP '^\d+') vg_free_raw=$(vgs -no vg_free "$ROOT_VG" --units m --nosuffix 2>/dev/null)
VG_FREE_HUMAN=$(vgs -no vg_free "$ROOT_VG" --units g 2>/dev/null | xargs) VG_FREE_NUM=$(parse_int "$vg_free_raw")
VG_FREE_HUMAN=$(vgs -no vg_free "$ROOT_VG" --units g --nosuffix 2>/dev/null | xargs)
if [[ -z "$VG_FREE_NUM" ]] || [[ "$VG_FREE_NUM" -lt 100 ]]; then if [[ -z "$VG_FREE_NUM" ]] || [[ "$VG_FREE_NUM" -lt 100 ]]; then
die "卷组 $ROOT_VG 没有足够的可用空间进行扩容(需要至少 100MB" die "卷组 $ROOT_VG 没有足够的可用空间进行扩容(需要至少 100MB"
fi fi
@@ -314,17 +337,22 @@ expand_pv_if_needed() {
# 检查磁盘是否有未分配空间 # 检查磁盘是否有未分配空间
local disk_size sector_size total_sectors part_end_sector local disk_size sector_size total_sectors part_end_sector
disk_size=$(blockdev --getsize64 "$parent_disk" 2>/dev/null) disk_size=$(blockdev --getsize64 "$parent_disk" 2>/dev/null) || disk_size=0
sector_size=$(blockdev --getss "$parent_disk" 2>/dev/null) sector_size=$(blockdev --getss "$parent_disk" 2>/dev/null) || sector_size=512
total_sectors=$((disk_size / sector_size)) total_sectors=$((disk_size / sector_size))
if [[ "$pv_is_partition" == true ]]; then if [[ "$pv_is_partition" == true ]]; then
local part_num local part_num
part_num=$(get_partition_number "$pv_dev") part_num=$(get_partition_number "$pv_dev")
# 获取分区结束扇区 # 获取分区结束扇区(优先使用 parted备选 sfdisk
part_end_sector=$(parted -s "$parent_disk" unit s print 2>/dev/null | \ if command -v parted &>/dev/null; then
awk -v num="$part_num" '$1 == num { gsub(/s/,"",$3); print $3 }') part_end_sector=$(parted -s "$parent_disk" unit s print 2>/dev/null | \
awk -v num="$part_num" '$1 == num { gsub(/s/,"",$3); print $3 }')
elif command -v sfdisk &>/dev/null; then
part_end_sector=$(sfdisk -d "$parent_disk" 2>/dev/null | \
awk -F'[=,]' -v num="$part_num" '{for(i=1;i<=NF;i++) if($i ~ /start=/) {split($i,a,"="); if(a[2]+0 > 0) start=a[2]} if($i ~ /size=/) {split($i,b,"="); size=b[2]}} NR==num {print start+size-1}')
fi
if [[ -z "$part_end_sector" ]]; then if [[ -z "$part_end_sector" ]]; then
warn "无法获取分区结束扇区,尝试直接使用 pvresize..." warn "无法获取分区结束扇区,尝试直接使用 pvresize..."
@@ -376,14 +404,19 @@ check_partition_space() {
# 获取磁盘和分区的扇区信息 # 获取磁盘和分区的扇区信息
local disk_size sector_size total_sectors local disk_size sector_size total_sectors
disk_size=$(blockdev --getsize64 "$ROOT_DISK" 2>/dev/null) disk_size=$(blockdev --getsize64 "$ROOT_DISK" 2>/dev/null) || disk_size=0
sector_size=$(blockdev --getss "$ROOT_DISK" 2>/dev/null) sector_size=$(blockdev --getss "$ROOT_DISK" 2>/dev/null) || sector_size=512
total_sectors=$((disk_size / sector_size)) total_sectors=$((disk_size / sector_size))
# 获取分区结束扇区 # 获取分区结束扇区(优先使用 parted备选 sfdisk
local part_end_sector local part_end_sector
part_end_sector=$(parted -s "$ROOT_DISK" unit s print 2>/dev/null | \ if command -v parted &>/dev/null; then
awk -v num="$part_num" '$1 == num { gsub(/s/,"",$3); print $3 }') part_end_sector=$(parted -s "$ROOT_DISK" unit s print 2>/dev/null | \
awk -v num="$part_num" '$1 == num { gsub(/s/,"",$3); print $3 }')
elif command -v sfdisk &>/dev/null; then
part_end_sector=$(sfdisk -d "$ROOT_DISK" 2>/dev/null | \
awk -F'[=,]' -v num="$part_num" '{for(i=1;i<=NF;i++) if($i ~ /start=/) {split($i,a,"="); if(a[2]+0 > 0) start=a[2]} if($i ~ /size=/) {split($i,b,"="); size=b[2]}} NR==num {print start+size-1}')
fi
if [[ -z "$part_end_sector" ]]; then if [[ -z "$part_end_sector" ]]; then
die "无法获取分区 $ROOT_DEVICE 的结束扇区" die "无法获取分区 $ROOT_DEVICE 的结束扇区"