lvm 扩容脚本

一、需求

1、对已经分区好的/backup进行卸载,把空间扩容到/healsci

2、对新磁盘sdb这种,加入逻辑卷,扩容空间到/healsci

3、可进行功能选择,要做哪一种扩容

二、代码

#!/bin/bash

# set -e

# Get partition mount paths and volume group name
get_mount_points() {
    BACKUP_MOUNT_POINT=$(df --output=target | grep /backup)
    HEALSCI_MOUNT_POINT=$(df --output=target | grep /healsci)

    if [ -z "$HEALSCI_MOUNT_POINT" ]; then
        echo "/healsci partition is not mounted correctly, please check the system status."
        exit 1
    fi

    VG_NAME=$(lvdisplay | grep 'VG Name' | head -n 1 | awk '{print $3}')
    BACKUP_LV_PATH=$(lvdisplay | grep 'LV Path' | grep "$VG_NAME/backup" | awk '{print $3}')
    HEALSCI_LV_PATH=$(lvdisplay | grep 'LV Path' | grep "$VG_NAME/healsci" | awk '{print $3}')

    echo '-------------------------------'
    echo "VG Name: $VG_NAME"
    echo "Backup LV Path: $BACKUP_LV_PATH"
    echo "Healsci LV Path: $HEALSCI_LV_PATH"
    echo -e '----------------------------\n'
}

# Function 1: Expand /backup to /healsci
expand_backup() {
    # Check if rsync is installed
    if ! command -v rsync &> /dev/null; then
        echo "rsync is not installed, please install it before running this script."
        exit 1
    fi

    if [ -z "$BACKUP_MOUNT_POINT" ]; then
        echo "/backup partition is not mounted, please check the system status."
        exit 1
    fi

    # Get space before expansion in bytes
    BEFORE_SPACE=$(df --output=size -B1 "$HEALSCI_MOUNT_POINT" | tail -n 1 | xargs)

    # Synchronize data
    rsync -avh --progress /backup/ "$HEALSCI_MOUNT_POINT/backup/"

    # Unmount /backup partition
    umount /backup || {
        echo "/backup is in use and cannot be unmounted."
        lsof +D /backup
        exit 1
    }

    echo "Successfully unmounted /backup"

    # Remove the logical volume
    lvremove -f "$BACKUP_LV_PATH"

    # Extend the healsci volume group
    lvextend -l +100%FREE "$HEALSCI_LV_PATH"

    # Extend the filesystem
    FS_TYPE=$(df -T "$HEALSCI_LV_PATH" | awk 'NR==2 {print $2}')
    if [ "$FS_TYPE" == "ext4" ]; then
        resize2fs "$HEALSCI_LV_PATH"
    elif [ "$FS_TYPE" == "xfs" ]; then
        xfs_growfs "$HEALSCI_LV_PATH"
    else
        echo "Unsupported filesystem type: $FS_TYPE"
        exit 1
    fi

    # Get space after expansion in bytes
    AFTER_SPACE=$(df --output=size -B1 "$HEALSCI_MOUNT_POINT" | tail -n 1 | xargs)
    
    # Calculate expanded space in bytes
    EXPANDED_SPACE=$(($AFTER_SPACE - $BEFORE_SPACE))
    
    # Display results in human-readable format
    echo "Space before expansion: $(numfmt --to=iec $BEFORE_SPACE)"
    echo "Space after expansion: $(numfmt --to=iec $AFTER_SPACE)"
    echo "Expanded by: $(numfmt --to=iec $EXPANDED_SPACE)"

    # Update /etc/fstab
    sed -i '/\/backup/d' /etc/fstab
    
    # Create a symbolic link
    rm -rf /backup
    ln -s /healsci/backup /backup

    echo "Function 1 completed: /backup has been successfully expanded to /healsci!"
}

# Function 2: Add a new disk to LVM
add_new_disks() {
    while true; do
        # List all unformatted disks
        UNFORMATTED_DISKS=$(lsblk -dn -o NAME,TYPE | while read -r disk type; do
            if [ "$type" = "disk" ] && [ "$disk" != "sr0" ]; then
                if [ -z "$(lsblk -no FSTYPE "/dev/$disk")" ]; then
                    echo "$disk"
                fi
            fi
        done)

        if [ -z "$UNFORMATTED_DISKS" ]; then
            echo "No unformatted disks available for use."
            exit 1
        fi

        echo "Available disks:"
        for disk in $UNFORMATTED_DISKS; do
            echo "$disk"
        done

        read -p "Please select the disk to add to LVM (e.g., sdb or sdb,sdc): " SELECTED_DISKS
        
        # Convert comma or space separated input to space-separated array
        SELECTED_DISKS=$(echo "$SELECTED_DISKS" | tr ', ' ' ')
        SELECTED_DISK_ARRAY=($SELECTED_DISKS)

        # Check if each selected disk is valid
        valid=true
        for SELECTED_DISK in "${SELECTED_DISK_ARRAY[@]}"; do
            SELECTED_DISK=$(echo "$SELECTED_DISK" | xargs)

            # Check if the disk is in the unformatted disk list
            if ! echo "$UNFORMATTED_DISKS" | grep -qw "$SELECTED_DISK"; then
                echo "The selected disk $SELECTED_DISK is not in the unformatted disk list, please re-enter."
                valid=false
                break
            fi
        done

        if ! $valid; then
            continue
        fi
        
        # Get space before expansion in bytes
        BEFORE_SPACE=$(df --output=size -B1 "$HEALSCI_MOUNT_POINT" | tail -n 1 | xargs)

        # Process all valid disks
        for SELECTED_DISK in "${SELECTED_DISK_ARRAY[@]}"; do
            echo "Adding disk /dev/$SELECTED_DISK to LVM"
            pvcreate "/dev/$SELECTED_DISK"
            vgextend "$VG_NAME" "/dev/$SELECTED_DISK"

            # Confirm the logical volume exists
            if ! lvdisplay "$HEALSCI_LV_PATH" &>/dev/null; then
                echo "Logical volume does not exist, please check the settings."
                exit 1
            fi

            lvextend -l +100%FREE "$HEALSCI_LV_PATH"

            # Extend the filesystem
            FS_TYPE=$(df -T "$HEALSCI_LV_PATH" | awk 'NR==2 {print $2}')
            if [ "$FS_TYPE" == "ext4" ]; then
                resize2fs "$HEALSCI_LV_PATH" || { echo "Failed to extend the filesystem"; exit 1; }
            elif [ "$FS_TYPE" == "xfs" ]; then
                xfs_growfs "$HEALSCI_LV_PATH" || { echo "Failed to extend the filesystem"; exit 1; }
            else
                echo "Unsupported filesystem type: $FS_TYPE"
                exit 1
            fi

            # Get space after expansion in bytes
            AFTER_SPACE=$(df --output=size -B1 "$HEALSCI_MOUNT_POINT" | tail -n 1 | xargs)
            
            # Calculate expanded space in bytes
            EXPANDED_SPACE=$(($AFTER_SPACE - $BEFORE_SPACE))
            
            # Display results in human-readable format
            echo "Space before expansion: $(numfmt --to=iec $BEFORE_SPACE)"
            echo "Space after expansion: $(numfmt --to=iec $AFTER_SPACE)"
            echo "Expanded by: $(numfmt --to=iec $EXPANDED_SPACE)"

            echo "Disk /dev/$SELECTED_DISK has been successfully added to LVM!"
        done

        echo "Function 2 completed: Selected disks have been successfully added to LVM!"
        break
    done
}

# Main Program
get_mount_points

echo "Please select a number to perform the corresponding function:"
echo "1) Expand /backup to /healsci"
echo "2) Add new disks to LVM"
echo "3) Execute all the above functions"
echo 
read -p "Please enter your choice [1/2/3]: " CHOICE

case $CHOICE in
    1)
        expand_backup
        ;;
    2)
        add_new_disks
        ;;
    3)
        expand_backup
        add_new_disks
        ;;
    *)
        echo "Invalid option, please enter 1, 2, or 3."
        exit 1
        ;;
esac

echo "All operations completed!"

三、重点逻辑

1、未格式化分区磁盘的判断

UNFORMATTED_DISKS=$(lsblk -dn -o NAME,TYPE | while read -r disk type; do
            if [ "$type" = "disk" ] && [ "$disk" != "sr0" ]; then
                if [ -z "$(lsblk -no FSTYPE "/dev/$disk")" ]; then
                    echo "$disk"
                fi
            fi
        done)

拆解与解释

**UNFORMATTED_DISKS=$(...)**:
这是一个命令替换的结构,将命令的输出结果存储在变量 UNFORMATTED_DISKS 中。

**lsblk -dn -o NAME,TYPE**:

  lsblk 是一个列出磁盘和块设备的命令

  -d 选项表示只显示磁盘,不显示分区

  -n 选项表示不打印标题行

  -o NAME,TYPE 选项指定输出显示列,具体是设备名称 (NAME) 和设备类型 (TYPE)

输出类似于

sda disk
sdb disk
sr0 rom

**| while read -r disk type; do ... done**:
  管道符 (|) 将 lsblk 的输出传递给 while 循环。循环会逐行读取上面的输出,将每行的设备名称赋值给变量 disk,将设备类型赋值给变量 type

**if [ "$type" = "disk" ] && [ "$disk" != "sr0" ]; then**:

  该条件判断当前读取的设备类型是否为 "disk",并且设备名称不是 "sr0"(通常是光驱设备)。

如果条件满足,代码块会执行下面的内容。

**if [ -z "$(lsblk -no FSTYPE "/dev/$disk")" ]; then**:

  lsblk -no FSTYPE "/dev/$disk" 命令用于检查当前设备的文件系统类型 (FSTYPE)。

  -n 选项表示不输出标题。

  -o FSTYPE 指定只输出文件系统类型。

  -z 检查命令的输出是否为空;即,无文件系统格式则返回 true

如果该设备没有文件系统,代码块会执行下面的内容。

  **echo "$disk"**:

如果前面的条件(设备是磁盘且没有文件系统)满足,则输出该设备名称 ($disk)。

2、扩容空间的计算

BEFORE_SPACE=$(df --output=size -B1 "$HEALSCI_MOUNT_POINT" | tail -n 1 | xargs)
AFTER_SPACE=$(df --output=size -B1 "$HEALSCI_MOUNT_POINT" | tail -n 1 | xargs)
EXPANDED_SPACE=$(($AFTER_SPACE - $BEFORE_SPACE))

echo "Space before expansion: $(numfmt --to=iec $BEFORE_SPACE)"
echo "Space after expansion: $(numfmt --to=iec $AFTER_SPACE)"
echo "Expanded by: $(numfmt --to=iec $EXPANDED_SPACE)"

补充

2.1 numfmt 是一个命令行工具,用于在不同的数字格式之间进行转换。它在处理数值的表示和转换时非常有用,尤其是在需要人类可读的格式与用于计算的纯数字格式之间进行转换时。

--to=iec 选项是 numfmt 的一个参数,用于将数字转换为人类可读的格式,并使用 IEC(International Electrotechnical Commission)单位前缀。这种格式主要用于表示数据存储的尺寸和处理速度等,单位包括:

  • KiB(kibibyte)= 1024 字节
  • MiB(mebibyte)= 1024 Kibibytes
  • GiB(gibibyte)= 1024 Mebibytes
  • TiB(tebibyte)= 1024 Gibibytes
# numfmt --to=iec  4852936458240
4.5T

2.2  df --output=size -B1 

在 df 命令中,--output=size 和 -B1 选项结合使用,用于指定输出格式和块大小:

  1. --output=size: 这个选项指定要输出的列为“size”,即文件系统的总大小。这是 df 的自定义输出功能之一,允许用户选择只显示某些感兴趣的数据列。

  2. -B1: 这个选项将块大小设置为字节df 默认显示的单位是以 1K(kilobyte)为计量单位

df --output --help 
FIELD_LIST is a comma-separated list of columns to be included. Valid
field names are: 'source', 'fstype', 'itotal', 'iused', 'iavail', 'ipcent',
'size', 'used', 'avail', 'pcent', 'file' and 'target' (see info page).

3、打印文件系统的类型

df -T  /healsci  | awk 'NR==2 {print $2}'

-T 参数输出文件系统类型

NR是行,NF是列

NR==2 {print $2} 打印第二行第二列

 

posted @ 2025-02-14 18:17  凡人半睁眼  阅读(61)  评论(0)    收藏  举报