mirror of
https://github.com/xkatld/lxdapi-web-server.git
synced 2026-05-31 08:17:21 +08:00
重构:整理项目结构,删除冗余文件并调整目录组织
This commit is contained in:
116
Shell/debian_zfs.sh
Normal file
116
Shell/debian_zfs.sh
Normal file
@@ -0,0 +1,116 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "========================================"
|
||||
echo " ZFS 编译安装脚本 (Debian)"
|
||||
echo " LXDAPI by Github-xkatld"
|
||||
echo "========================================"
|
||||
echo
|
||||
|
||||
LOG_DIR="/var/log/zfs_build_logs"
|
||||
mkdir -p "$LOG_DIR"
|
||||
LOG_FILE="${LOG_DIR}/zfs_build_$(date +%Y%m%d_%H%M%S).log"
|
||||
exec &> >(tee -a "$LOG_FILE")
|
||||
|
||||
set -e
|
||||
set -u
|
||||
|
||||
DEBIAN_VER=$(cat /etc/debian_version | cut -d. -f1)
|
||||
ARCH=$(uname -m)
|
||||
|
||||
case "$DEBIAN_VER" in
|
||||
11)
|
||||
DEBIAN_NAME="Debian 11 (Bullseye)"
|
||||
ZFS_VER="2.2.9"
|
||||
;;
|
||||
12)
|
||||
DEBIAN_NAME="Debian 12 (Bookworm)"
|
||||
ZFS_VER="2.3.5"
|
||||
;;
|
||||
13|trixie)
|
||||
DEBIAN_NAME="Debian 13 (Trixie)"
|
||||
ZFS_VER="2.3.5"
|
||||
;;
|
||||
*)
|
||||
echo "错误: 不支持的 Debian 版本: $DEBIAN_VER"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ">>> 本次操作的完整日志将保存在: ${LOG_FILE}"
|
||||
echo ""
|
||||
|
||||
echo ">>> [1/5] 开始在 ${DEBIAN_NAME} ${ARCH} 上编译安装 OpenZFS 版本 ${ZFS_VER}"
|
||||
echo ">>> 内核版本: $(uname -r)"
|
||||
|
||||
echo ""
|
||||
echo ">>> [2/5] 正在安装编译依赖包..."
|
||||
|
||||
apt-get update
|
||||
|
||||
apt-get install -y \
|
||||
build-essential \
|
||||
autoconf \
|
||||
automake \
|
||||
libtool \
|
||||
pkg-config \
|
||||
linux-headers-$(uname -r) \
|
||||
libtirpc-dev \
|
||||
libblkid-dev \
|
||||
uuid-dev \
|
||||
zlib1g-dev \
|
||||
libattr1-dev \
|
||||
libacl1-dev \
|
||||
libudev-dev \
|
||||
libssl-dev \
|
||||
libelf-dev \
|
||||
python3 \
|
||||
python3-dev \
|
||||
python3-setuptools \
|
||||
python3-cffi \
|
||||
libffi-dev
|
||||
|
||||
echo ">>> 依赖包安装完成。"
|
||||
|
||||
echo ""
|
||||
echo ">>> [3/5] 正在下载 OpenZFS v${ZFS_VER} 源码..."
|
||||
|
||||
WORKDIR=$(mktemp -d)
|
||||
cd "${WORKDIR}"
|
||||
|
||||
curl -sL "https://github.com/openzfs/zfs/releases/download/zfs-${ZFS_VER}/zfs-${ZFS_VER}.tar.gz" -o "zfs-${ZFS_VER}.tar.gz"
|
||||
|
||||
tar -xzf "zfs-${ZFS_VER}.tar.gz"
|
||||
cd "zfs-${ZFS_VER}"
|
||||
|
||||
echo ">>> 源码下载并解压至 ${PWD}"
|
||||
|
||||
echo ""
|
||||
echo ">>> [4/5] 正在配置、编译、安装和注册 ZFS... (这可能需要较长时间)"
|
||||
|
||||
./autogen.sh
|
||||
./configure
|
||||
make -j$(nproc)
|
||||
make install
|
||||
depmod -a
|
||||
ldconfig
|
||||
modprobe zfs
|
||||
|
||||
echo ">>> ZFS 编译、安装和模块加载完成。"
|
||||
|
||||
echo ""
|
||||
echo ">>> [5/5] 正在清理临时文件..."
|
||||
|
||||
cd /
|
||||
rm -rf "${WORKDIR}"
|
||||
|
||||
echo ""
|
||||
echo "=============================================================================="
|
||||
echo " ZFS v${ZFS_VER} 已成功安装并加载!"
|
||||
echo ""
|
||||
echo " 您现在可以使用 'zpool' 和 'zfs' 命令了。"
|
||||
echo " 运行 'zpool status' 来检查ZFS模块是否正常工作。"
|
||||
echo "=============================================================================="
|
||||
|
||||
zpool status
|
||||
|
||||
exit 0
|
||||
202
Shell/image_import.sh
Normal file
202
Shell/image_import.sh
Normal file
@@ -0,0 +1,202 @@
|
||||
#!/bin/bash
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
LXC="/snap/bin/lxc"
|
||||
|
||||
ok() { echo -e "${GREEN}[OK]${NC} $1"; }
|
||||
err() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||
|
||||
reading() {
|
||||
read -rp "$(echo -e "${GREEN}[INPUT]${NC} $1")" "$2"
|
||||
}
|
||||
|
||||
detect_arch() {
|
||||
sys_arch=$(uname -m)
|
||||
case $sys_arch in
|
||||
x86_64)
|
||||
ARCH="amd64"
|
||||
;;
|
||||
aarch64|arm64)
|
||||
ARCH="arm64"
|
||||
;;
|
||||
*)
|
||||
err "不支持的架构: $sys_arch"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
ok "系统架构: $ARCH"
|
||||
}
|
||||
|
||||
IMAGES_BASE_URL="https://github.com/xkatld/lxdapi-web-server/releases/download/image"
|
||||
|
||||
declare -a IMAGE_LIST=(
|
||||
"almalinux-8"
|
||||
"almalinux-9"
|
||||
"alpine-320"
|
||||
"alpine-321"
|
||||
"alpine-322"
|
||||
"archlinux-latest"
|
||||
"centos-9-Stream"
|
||||
"debian-11"
|
||||
"debian-12"
|
||||
"debian-13"
|
||||
"fedora-42"
|
||||
"fedora-43"
|
||||
"opensuse-156"
|
||||
"opensuse-tumbleweed"
|
||||
"rockylinux-8"
|
||||
"rockylinux-9"
|
||||
"ubuntu-2204"
|
||||
"ubuntu-2404"
|
||||
)
|
||||
|
||||
download_and_import() {
|
||||
local image_name="$1"
|
||||
local image_type="$2"
|
||||
local image_url="${IMAGES_BASE_URL}/${image_name}-${ARCH}-${image_type}.tar.gz"
|
||||
|
||||
info "下载: ${image_name}-${ARCH}-${image_type}.tar.gz"
|
||||
|
||||
local temp_file=$(mktemp)
|
||||
if wget -q --show-progress -O "$temp_file" "$image_url" 2>&1; then
|
||||
info "导入到 LXD..."
|
||||
local alias="${image_name}-${image_type}"
|
||||
if $LXC image import "$temp_file" --alias "$alias" 2>/dev/null; then
|
||||
ok "成功导入: $alias"
|
||||
else
|
||||
warn "导入失败: $alias"
|
||||
fi
|
||||
rm -f "$temp_file"
|
||||
else
|
||||
warn "下载失败: ${image_name}-${ARCH}-${image_type}"
|
||||
rm -f "$temp_file"
|
||||
fi
|
||||
}
|
||||
|
||||
show_image_list() {
|
||||
echo
|
||||
echo "============================================================================================================"
|
||||
echo " 1) almalinux-8 2) almalinux-9 3) alpine-320 4) alpine-321 5) alpine-322"
|
||||
echo " 6) archlinux-latest 7) centos-9-Stream 8) debian-11 9) debian-12 10) debian-13"
|
||||
echo "11) fedora-42 12) fedora-43 13) opensuse-156 14) opensuse-tumbleweed"
|
||||
echo "15) rockylinux-8 16) rockylinux-9 17) ubuntu-2204 18) ubuntu-2404"
|
||||
echo "============================================================================================================"
|
||||
echo
|
||||
}
|
||||
|
||||
menu_import() {
|
||||
echo
|
||||
info "=== 导入镜像 ==="
|
||||
show_image_list
|
||||
|
||||
reading "输入编号,多个用逗号分隔,或 all 全部导入 [8,9,17,18]: " image_choices
|
||||
image_choices=${image_choices:-"8,9,17,18"}
|
||||
|
||||
while true; do
|
||||
reading "选择镜像类型 lxc/kvm [lxc]: " image_type
|
||||
image_type=${image_type:-lxc}
|
||||
if [[ "$image_type" =~ ^(lxc|kvm)$ ]]; then
|
||||
break
|
||||
else
|
||||
warn "请输入 lxc 或 kvm"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$image_type" == "kvm" && "$ARCH" == "arm64" ]]; then
|
||||
warn "KVM 镜像不支持 arm64 架构"
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ "$image_choices" == "all" ]]; then
|
||||
selected_images=("${IMAGE_LIST[@]}")
|
||||
else
|
||||
IFS=',' read -ra choices <<< "$image_choices"
|
||||
selected_images=()
|
||||
for choice in "${choices[@]}"; do
|
||||
choice=$(echo "$choice" | xargs)
|
||||
idx=$((choice - 1))
|
||||
if [[ $idx -ge 0 && $idx -lt ${#IMAGE_LIST[@]} ]]; then
|
||||
selected_images+=("${IMAGE_LIST[$idx]}")
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ ${#selected_images[@]} -eq 0 ]]; then
|
||||
warn "未选择任何镜像"
|
||||
return
|
||||
fi
|
||||
|
||||
ok "已选择 ${#selected_images[@]} 个镜像 (${image_type})"
|
||||
echo
|
||||
|
||||
current=0
|
||||
for img in "${selected_images[@]}"; do
|
||||
((current++))
|
||||
echo "[$current/${#selected_images[@]}]"
|
||||
download_and_import "$img" "$image_type"
|
||||
echo
|
||||
done
|
||||
}
|
||||
|
||||
menu_list() {
|
||||
echo
|
||||
info "=== 已有镜像 ==="
|
||||
$LXC image list
|
||||
}
|
||||
|
||||
menu_delete() {
|
||||
echo
|
||||
info "=== 删除镜像 ==="
|
||||
$LXC image list
|
||||
echo
|
||||
reading "输入要删除的镜像别名或指纹: " image_id
|
||||
if [ -z "$image_id" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
warn "确认删除镜像 $image_id?"
|
||||
reading "确认?(y/n) [n]: " confirm
|
||||
if [[ "$confirm" =~ ^[yY]$ ]]; then
|
||||
if $LXC image delete "$image_id"; then
|
||||
ok "镜像已删除"
|
||||
else
|
||||
err "删除失败"
|
||||
fi
|
||||
else
|
||||
info "已取消"
|
||||
fi
|
||||
}
|
||||
|
||||
main_menu() {
|
||||
while true; do
|
||||
echo
|
||||
echo "================================"
|
||||
echo " LXD 镜像管理脚本"
|
||||
echo " LXDAPI by Github-xkatld"
|
||||
echo "================================"
|
||||
echo "1. 导入镜像"
|
||||
echo "2. 查看已有镜像"
|
||||
echo "3. 删除镜像"
|
||||
echo "0. 退出"
|
||||
echo "================================"
|
||||
reading "请选择 [0-3]: " choice
|
||||
|
||||
case "$choice" in
|
||||
1) menu_import ;;
|
||||
2) menu_list ;;
|
||||
3) menu_delete ;;
|
||||
0) ok "退出"; exit 0 ;;
|
||||
*) warn "无效选择" ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
detect_arch
|
||||
main_menu
|
||||
327
Shell/lxd_install.sh
Normal file
327
Shell/lxd_install.sh
Normal file
@@ -0,0 +1,327 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd /root >/dev/null 2>&1
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
REGEX=("debian|astra" "ubuntu")
|
||||
RELEASE=("Debian" "Ubuntu")
|
||||
CMD=("$(grep -i pretty_name /etc/os-release 2>/dev/null | cut -d \" -f2)" "$(lsb_release -sd 2>/dev/null)")
|
||||
SYS="${CMD[0]}"
|
||||
[[ -n $SYS ]] || exit 1
|
||||
|
||||
for ((int = 0; int < ${#REGEX[@]}; int++)); do
|
||||
if [[ $(echo "$SYS" | tr '[:upper:]' '[:lower:]') =~ ${REGEX[int]} ]]; then
|
||||
SYSTEM="${RELEASE[int]}"
|
||||
[[ -n $SYSTEM ]] && break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$SYSTEM" != "Debian" && "$SYSTEM" != "Ubuntu" ]]; then
|
||||
echo -e "${RED}[ERR]${NC} 此脚本仅支持 Debian 和 Ubuntu 系统"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$SYSTEM" == "Debian" ]]; then
|
||||
OS_VERSION=$(cat /etc/debian_version | cut -d. -f1)
|
||||
elif [[ "$SYSTEM" == "Ubuntu" ]]; then
|
||||
OS_VERSION=$(grep VERSION_ID /etc/os-release | cut -d'"' -f2 | cut -d. -f1)
|
||||
fi
|
||||
|
||||
RECOMMENDED=false
|
||||
if [[ "$SYSTEM" == "Debian" && ("$OS_VERSION" == "12" || "$OS_VERSION" == "13") ]]; then
|
||||
RECOMMENDED=true
|
||||
elif [[ "$SYSTEM" == "Ubuntu" && ("$OS_VERSION" == "24" || "$OS_VERSION" == "25") ]]; then
|
||||
RECOMMENDED=true
|
||||
fi
|
||||
|
||||
if [[ "$RECOMMENDED" != "true" ]]; then
|
||||
echo -e "${YELLOW}[WARN]${NC} 当前系统: $SYSTEM $OS_VERSION"
|
||||
echo -e "${YELLOW}[WARN]${NC} 推荐使用: Debian 12/13 或 Ubuntu 24/25"
|
||||
read -rp "$(echo -e "${YELLOW}是否继续安装?(y/n) [n]:${NC}")" confirm_install
|
||||
confirm_install=${confirm_install:-n}
|
||||
if [[ ! "$confirm_install" =~ ^[yY]$ ]]; then
|
||||
echo -e "${RED}[ERR]${NC} 安装已取消"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
log() { echo -e "$1"; }
|
||||
ok() { log "${GREEN}[OK]${NC} $1"; }
|
||||
info() { log "${BLUE}[INFO]${NC} $1"; }
|
||||
warn() { log "${YELLOW}[WARN]${NC} $1"; }
|
||||
err() { log "${RED}[ERR]${NC} $1"; exit 1; }
|
||||
|
||||
reading() { read -rp "$(echo -e "${GREEN}$1${NC}")" "$2"; }
|
||||
|
||||
install_package() {
|
||||
package_name=$1
|
||||
if dpkg -l 2>/dev/null | grep -q "^ii.*$package_name"; then
|
||||
ok "$package_name 已安装"
|
||||
else
|
||||
apt-get install -y $package_name >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
apt-get install -y $package_name --fix-missing >/dev/null 2>&1
|
||||
fi
|
||||
if dpkg -l 2>/dev/null | grep -q "^ii.*$package_name"; then
|
||||
ok "$package_name 已安装"
|
||||
else
|
||||
warn "$package_name 安装失败"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
get_available_space() {
|
||||
local available_space
|
||||
available_space=$(df -BG / | awk 'NR==2 {gsub("G","",$4); print $4}')
|
||||
echo "$available_space"
|
||||
}
|
||||
|
||||
install_lxd() {
|
||||
lxd_snap=$(dpkg -l | awk '/^[hi]i/{print $2}' | grep -ow snap)
|
||||
lxd_snapd=$(dpkg -l | awk '/^[hi]i/{print $2}' | grep -ow snapd)
|
||||
if [[ "$lxd_snap" =~ ^snap.* ]] && [[ "$lxd_snapd" =~ ^snapd.* ]]; then
|
||||
ok "snap 已安装"
|
||||
else
|
||||
info "开始安装 snap..."
|
||||
apt-get update >/dev/null 2>&1
|
||||
install_package snapd
|
||||
fi
|
||||
snap_core=$(snap list core 2>/dev/null)
|
||||
snap_lxd=$(snap list lxd 2>/dev/null)
|
||||
if [[ "$snap_core" =~ core.* ]] && [[ "$snap_lxd" =~ lxd.* ]]; then
|
||||
ok "LXD 已安装"
|
||||
lxd_lxc_detect=$(lxc list 2>/dev/null)
|
||||
if [[ "$lxd_lxc_detect" =~ "snap-update-ns failed with code1".* ]]; then
|
||||
systemctl restart apparmor
|
||||
snap restart lxd
|
||||
else
|
||||
ok "环境检测无问题"
|
||||
fi
|
||||
else
|
||||
info "开始安装 LXD..."
|
||||
snap install lxd --channel=latest/stable 2>/dev/null
|
||||
if [[ $? -ne 0 ]]; then
|
||||
snap remove lxd 2>/dev/null
|
||||
snap install core 2>/dev/null
|
||||
snap install lxd --channel=latest/stable 2>/dev/null
|
||||
fi
|
||||
snap alias lxd.lxc lxc 2>/dev/null
|
||||
snap alias lxd.lxd lxd 2>/dev/null
|
||||
if [ ! -f /etc/profile.d/snap.sh ]; then
|
||||
echo 'export PATH=$PATH:/snap/bin' > /etc/profile.d/snap.sh
|
||||
fi
|
||||
export PATH=$PATH:/snap/bin
|
||||
if ! command -v lxc >/dev/null 2>&1; then
|
||||
err 'lxc 路径有问题,请检查 snap alias'
|
||||
fi
|
||||
ok "LXD 安装完成"
|
||||
fi
|
||||
|
||||
if dpkg -l lxcfs 2>/dev/null | grep -q "^ii"; then
|
||||
warn "检测到 deb 版 lxcfs,正在移除..."
|
||||
systemctl stop lxcfs 2>/dev/null || true
|
||||
systemctl disable lxcfs 2>/dev/null || true
|
||||
apt-get remove -y lxcfs >/dev/null 2>&1
|
||||
ok "deb 版 lxcfs 已移除"
|
||||
fi
|
||||
|
||||
lxd_version=$(lxd --version 2>/dev/null)
|
||||
info "LXD 版本: $lxd_version"
|
||||
if [[ ! "$lxd_version" =~ ^6\. ]]; then
|
||||
warn "当前 LXD 版本 $lxd_version 不兼容,推荐使用 6.x 版本"
|
||||
reading "是否继续?(y/n) [y]:" version_confirm
|
||||
version_confirm=${version_confirm:-y}
|
||||
if [[ ! "$version_confirm" =~ ^[yY]$ ]]; then
|
||||
err "已取消安装"
|
||||
fi
|
||||
else
|
||||
ok "LXD 版本兼容"
|
||||
fi
|
||||
|
||||
info "配置 LXD..."
|
||||
snap set lxd lxcfs.flags="-l" 2>/dev/null
|
||||
snap set lxd daemon.debug=false 2>/dev/null
|
||||
snap restart lxd 2>/dev/null
|
||||
sleep 3
|
||||
ok "LXD 已配置"
|
||||
}
|
||||
|
||||
init_lxd_network() {
|
||||
if ! /snap/bin/lxc network show lxdbr0 &>/dev/null; then
|
||||
info "创建默认网络 lxdbr0..."
|
||||
/snap/bin/lxc network create lxdbr0
|
||||
ok "网络 lxdbr0 创建成功"
|
||||
else
|
||||
ok "网络 lxdbr0 已存在"
|
||||
fi
|
||||
|
||||
if ! /snap/bin/lxc profile device show default 2>/dev/null | grep -q "eth0"; then
|
||||
info "配置 default profile 网络设备..."
|
||||
/snap/bin/lxc profile device add default eth0 nic network=lxdbr0 name=eth0
|
||||
ok "网络设备已添加到 default profile"
|
||||
fi
|
||||
}
|
||||
|
||||
setup_storage() {
|
||||
info "配置存储池..."
|
||||
|
||||
if /snap/bin/lxc storage show default &>/dev/null; then
|
||||
ok "存储池 default 已存在"
|
||||
/snap/bin/lxc storage list
|
||||
return 0
|
||||
fi
|
||||
|
||||
available_space=$(get_available_space)
|
||||
info "当前可用磁盘空间: ${available_space}GB"
|
||||
|
||||
while true; do
|
||||
reading "请选择存储后端 zfs/btrfs/lvm [zfs]:" storage_driver
|
||||
storage_driver=${storage_driver:-zfs}
|
||||
if [[ "$storage_driver" =~ ^(zfs|btrfs|lvm)$ ]]; then
|
||||
break
|
||||
else
|
||||
warn "请输入 zfs、btrfs 或 lvm"
|
||||
fi
|
||||
done
|
||||
|
||||
case "$storage_driver" in
|
||||
zfs)
|
||||
if ! command -v zpool &>/dev/null; then
|
||||
info "安装 ZFS..."
|
||||
if [[ "$SYSTEM" == "Ubuntu" ]]; then
|
||||
install_package zfsutils-linux
|
||||
else
|
||||
bash <(curl -sL https://raw.githubusercontent.com/xkatld/lxdapi-web-server/refs/heads/v2.1.0-vpsm.link/Shell/debian_zfs.sh)
|
||||
fi
|
||||
fi
|
||||
info "配置 LXD 使用系统 ZFS..."
|
||||
snap set lxd zfs.external=true
|
||||
snap restart lxd
|
||||
sleep 3
|
||||
;;
|
||||
btrfs)
|
||||
install_package btrfs-progs
|
||||
;;
|
||||
lvm)
|
||||
install_package lvm2
|
||||
;;
|
||||
esac
|
||||
|
||||
reading "请输入存储池大小(GB) [${available_space}]:" pool_size
|
||||
pool_size=${pool_size:-$available_space}
|
||||
|
||||
info "创建 default 存储池 (${storage_driver}, ${pool_size}GB)..."
|
||||
/snap/bin/lxc storage create default ${storage_driver} size=${pool_size}GB
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
ok "存储池 default 创建成功"
|
||||
if ! /snap/bin/lxc profile device show default 2>/dev/null | grep -q "root"; then
|
||||
/snap/bin/lxc profile device add default root disk path=/ pool=default
|
||||
ok "存储池已添加到 default profile"
|
||||
fi
|
||||
else
|
||||
err "存储池创建失败"
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
echo
|
||||
echo "========================================"
|
||||
echo " LXD 安装脚本"
|
||||
echo " by Github-xkatld"
|
||||
echo "========================================"
|
||||
echo
|
||||
|
||||
echo "======== 步骤 1/5: 检测系统 ========"
|
||||
info "系统: $SYSTEM $OS_VERSION"
|
||||
if [[ "$RECOMMENDED" == "true" ]]; then
|
||||
ok "系统版本符合推荐"
|
||||
else
|
||||
warn "建议使用 Debian 12/13 或 Ubuntu 24/25"
|
||||
fi
|
||||
|
||||
if [[ "$SYSTEM" == "Debian" ]]; then
|
||||
echo
|
||||
warn "Debian 使用 ZFS 存储需要编译安装,耗时较长"
|
||||
warn "如需使用 ZFS,推荐使用 Ubuntu 系统"
|
||||
reading "是否继续使用 Debian?(y/n) [y]:" debian_confirm
|
||||
debian_confirm=${debian_confirm:-y}
|
||||
if [[ ! "$debian_confirm" =~ ^[yY]$ ]]; then
|
||||
info "已取消安装"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "======== 步骤 2/5: 安装 LXD ========"
|
||||
reading "是否安装 LXD?(y/n) [y]:" step2_confirm
|
||||
step2_confirm=${step2_confirm:-y}
|
||||
if [[ "$step2_confirm" =~ ^[yY]$ ]]; then
|
||||
install_lxd
|
||||
ok "LXD 安装完成"
|
||||
else
|
||||
info "已跳过 LXD 安装"
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "======== 步骤 3/5: 网络配置 ========"
|
||||
reading "是否配置网络?(y/n) [y]:" step3_confirm
|
||||
step3_confirm=${step3_confirm:-y}
|
||||
if [[ "$step3_confirm" =~ ^[yY]$ ]]; then
|
||||
init_lxd_network
|
||||
reading "是否开启 IPv4 分配,分配NAT和独立IP需要开启 (y/n) [y]:" ipv4_dhcp
|
||||
ipv4_dhcp=${ipv4_dhcp:-y}
|
||||
if [[ ! "$ipv4_dhcp" =~ ^[yY]$ ]]; then
|
||||
/snap/bin/lxc network set lxdbr0 ipv4.dhcp false
|
||||
ok "IPv4 分配已关闭"
|
||||
else
|
||||
ok "IPv4 分配已开启"
|
||||
fi
|
||||
reading "是否开启 IPv6 分配,分配NAT和独立IP需要开启 (y/n) [y]:" ipv6_dhcp
|
||||
ipv6_dhcp=${ipv6_dhcp:-y}
|
||||
if [[ ! "$ipv6_dhcp" =~ ^[yY]$ ]]; then
|
||||
/snap/bin/lxc network set lxdbr0 ipv6.dhcp false
|
||||
/snap/bin/lxc network set lxdbr0 ipv6.address none
|
||||
ok "IPv6 分配已关闭"
|
||||
else
|
||||
ok "IPv6 分配已开启"
|
||||
fi
|
||||
ok "网络配置完成"
|
||||
else
|
||||
info "已跳过网络配置"
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "======== 步骤 4/5: 存储配置 ========"
|
||||
info "配置 default 存储池,首次安装推荐配置"
|
||||
reading "是否配置存储池?(y/n) [y]:" step4_confirm
|
||||
step4_confirm=${step4_confirm:-y}
|
||||
if [[ "$step4_confirm" =~ ^[yY]$ ]]; then
|
||||
setup_storage
|
||||
ok "存储配置完成"
|
||||
else
|
||||
info "已跳过存储配置"
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "======== 步骤 5/5: 完成 ========"
|
||||
echo
|
||||
echo "========================================"
|
||||
echo " LXD 安装完成"
|
||||
echo "========================================"
|
||||
echo
|
||||
info "LXD 版本: $(lxd --version 2>/dev/null)"
|
||||
echo
|
||||
info "===== 网络配置 ====="
|
||||
lxc network list 2>/dev/null || warn "无法获取网络列表"
|
||||
echo
|
||||
info "===== 存储配置 ====="
|
||||
lxc storage list 2>/dev/null || warn "无法获取存储列表"
|
||||
}
|
||||
|
||||
main
|
||||
510
Shell/lxdapi_install.sh
Normal file
510
Shell/lxdapi_install.sh
Normal file
@@ -0,0 +1,510 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd /root >/dev/null 2>&1
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
REGEX=("debian|astra" "ubuntu")
|
||||
RELEASE=("Debian" "Ubuntu")
|
||||
CMD=("$(grep -i pretty_name /etc/os-release 2>/dev/null | cut -d \" -f2)" "$(lsb_release -sd 2>/dev/null)")
|
||||
SYS="${CMD[0]}"
|
||||
[[ -n $SYS ]] || exit 1
|
||||
|
||||
for ((int = 0; int < ${#REGEX[@]}; int++)); do
|
||||
if [[ $(echo "$SYS" | tr '[:upper:]' '[:lower:]') =~ ${REGEX[int]} ]]; then
|
||||
SYSTEM="${RELEASE[int]}"
|
||||
[[ -n $SYSTEM ]] && break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$SYSTEM" != "Debian" && "$SYSTEM" != "Ubuntu" ]]; then
|
||||
echo -e "${RED}[ERR]${NC} 此脚本仅支持 Debian 和 Ubuntu 系统"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log() { echo -e "$1"; }
|
||||
ok() { log "${GREEN}[OK]${NC} $1"; }
|
||||
info() { log "${BLUE}[INFO]${NC} $1"; }
|
||||
warn() { log "${YELLOW}[WARN]${NC} $1"; }
|
||||
err() { log "${RED}[ERR]${NC} $1"; exit 1; }
|
||||
|
||||
reading() { read -rp "$(echo -e "${GREEN}$1${NC}")" "$2"; }
|
||||
|
||||
install_package() {
|
||||
package_name=$1
|
||||
if dpkg -l 2>/dev/null | grep -q "^ii.*$package_name"; then
|
||||
ok "$package_name 已安装"
|
||||
else
|
||||
apt-get install -y $package_name >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
apt-get install -y $package_name --fix-missing >/dev/null 2>&1
|
||||
fi
|
||||
if dpkg -l 2>/dev/null | grep -q "^ii.*$package_name"; then
|
||||
ok "$package_name 已安装"
|
||||
else
|
||||
warn "$package_name 安装失败"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
install_base_packages() {
|
||||
info "更新软件包列表..."
|
||||
apt-get update >/dev/null 2>&1
|
||||
apt-get autoremove -y >/dev/null 2>&1
|
||||
|
||||
info "安装基础软件包..."
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y unzip e2fsprogs bc nftables fdisk parted iptables-persistent nginx >/dev/null 2>&1
|
||||
ok "软件包安装完成"
|
||||
|
||||
systemctl enable nftables >/dev/null 2>&1
|
||||
systemctl start nftables >/dev/null 2>&1
|
||||
ok "nftables 已启动"
|
||||
|
||||
if command -v lxc &>/dev/null && lxc network show lxdbr0 &>/dev/null; then
|
||||
lxc network set lxdbr0 ipv4.nat true 2>/dev/null
|
||||
lxc network set lxdbr0 ipv6.nat true 2>/dev/null
|
||||
ok "LXD NAT 规则已重建"
|
||||
fi
|
||||
|
||||
systemctl enable nginx >/dev/null 2>&1
|
||||
systemctl start nginx >/dev/null 2>&1
|
||||
ok "nginx 已启动"
|
||||
}
|
||||
|
||||
deploy_lxdapi() {
|
||||
info "检测系统架构..."
|
||||
sys_arch=$(uname -m)
|
||||
case $sys_arch in
|
||||
x86_64)
|
||||
arch="amd64"
|
||||
ok "检测到架构: x86_64"
|
||||
;;
|
||||
aarch64|arm64)
|
||||
arch="arm64"
|
||||
ok "检测到架构: $sys_arch"
|
||||
;;
|
||||
*)
|
||||
err "不支持的架构: $sys_arch"
|
||||
;;
|
||||
esac
|
||||
|
||||
while true; do
|
||||
reading "请选择下载源 github/gitee [github]:" download_source
|
||||
download_source=${download_source:-github}
|
||||
if [[ "$download_source" =~ ^(github|gitee)$ ]]; then
|
||||
break
|
||||
else
|
||||
warn "请输入 github 或 gitee"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$download_source" == "github" ]]; then
|
||||
latest_tag=$(curl -s https://api.github.com/repos/xkatld/lxdapi-web-server/releases/latest | grep '"tag_name"' | sed -n 's/.*"tag_name": *"\([^"]*\)".*/\1/p')
|
||||
base_url="https://github.com/xkatld/lxdapi-web-server/releases/download"
|
||||
else
|
||||
latest_tag=$(curl -s https://gitee.com/api/v5/repos/xkatld/lxdapi-web-server/releases/latest | grep '"tag_name"' | sed -n 's/.*"tag_name": *"\([^"]*\)".*/\1/p')
|
||||
base_url="https://gitee.com/xkatld/lxdapi-web-server/releases/download"
|
||||
fi
|
||||
|
||||
if [ -z "$latest_tag" ]; then
|
||||
err "无法获取最新版本信息"
|
||||
fi
|
||||
|
||||
info "最新版本: $latest_tag"
|
||||
reading "请输入安装版本 [$latest_tag]:" install_version
|
||||
install_version=${install_version:-$latest_tag}
|
||||
ok "安装版本: $install_version"
|
||||
|
||||
download_url="${base_url}/${install_version}/lxdapi-linux-${arch}.tar.gz"
|
||||
|
||||
info "下载 lxdapi..."
|
||||
info "下载地址: $download_url"
|
||||
|
||||
temp_file=$(mktemp)
|
||||
if wget -q --show-progress -O "$temp_file" "$download_url" 2>&1; then
|
||||
ok "下载完成"
|
||||
else
|
||||
rm -f "$temp_file"
|
||||
err "下载失败"
|
||||
fi
|
||||
|
||||
info "解压到 /opt/lxdapi..."
|
||||
mkdir -p /opt/lxdapi
|
||||
tar -xzf "$temp_file" -C /opt/lxdapi --strip-components=1
|
||||
rm -f "$temp_file"
|
||||
}
|
||||
|
||||
configure_lxdapi() {
|
||||
info "配置 lxdapi..."
|
||||
|
||||
config_file="/opt/lxdapi/configs/config.yaml"
|
||||
|
||||
if [ ! -f "$config_file" ]; then
|
||||
err "配置文件不存在: $config_file"
|
||||
fi
|
||||
|
||||
reading "请输入服务端口 [8443]:" server_port
|
||||
server_port=${server_port:-8443}
|
||||
|
||||
reading "请输入API密钥 [随机生成]:" api_hash
|
||||
if [ -z "$api_hash" ]; then
|
||||
api_hash=$(openssl rand -hex 16)
|
||||
ok "API密钥已生成: $api_hash"
|
||||
fi
|
||||
|
||||
reading "请输入管理员用户名 [admin]:" admin_user
|
||||
admin_user=${admin_user:-admin}
|
||||
|
||||
reading "请输入管理员密码 [随机生成]:" admin_pass
|
||||
if [ -z "$admin_pass" ]; then
|
||||
admin_pass=$(openssl rand -hex 8)
|
||||
ok "管理员密码已生成: $admin_pass"
|
||||
fi
|
||||
|
||||
session_secret=$(openssl rand -hex 16)
|
||||
|
||||
reading "请输入流量采集间隔秒数 [20]:" traffic_interval
|
||||
traffic_interval=${traffic_interval:-20}
|
||||
|
||||
reading "请输入流量批量更新数量 [10]:" traffic_batch_size
|
||||
traffic_batch_size=${traffic_batch_size:-10}
|
||||
|
||||
reading "请输入任务自动清理天数 [7]:" auto_cleanup_days
|
||||
auto_cleanup_days=${auto_cleanup_days:-7}
|
||||
|
||||
while true; do
|
||||
reading "请选择任务队列后端 memory/redis [memory]:" task_backend
|
||||
task_backend=${task_backend:-memory}
|
||||
if [[ "$task_backend" =~ ^(memory|redis)$ ]]; then
|
||||
break
|
||||
else
|
||||
warn "请输入 memory 或 redis"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$task_backend" == "redis" ]]; then
|
||||
while true; do
|
||||
reading "使用本地安装还是远程配置?local/remote [local]:" redis_location
|
||||
redis_location=${redis_location:-local}
|
||||
if [[ "$redis_location" =~ ^(local|remote)$ ]]; then
|
||||
break
|
||||
else
|
||||
warn "请输入 local 或 remote"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$redis_location" == "local" ]]; then
|
||||
info "安装 Redis..."
|
||||
apt-get install -y redis-server >/dev/null 2>&1
|
||||
systemctl start redis-server
|
||||
systemctl enable redis-server
|
||||
|
||||
redis_host="localhost"
|
||||
redis_port="6379"
|
||||
redis_password=""
|
||||
redis_db="0"
|
||||
ok "Redis 已安装"
|
||||
else
|
||||
reading "请输入 Redis 主机地址:" redis_host
|
||||
reading "请输入 Redis 端口 [6379]:" redis_port
|
||||
redis_port=${redis_port:-6379}
|
||||
reading "请输入 Redis 密码 [留空表示无密码]:" redis_password
|
||||
reading "请输入 Redis 数据库编号 [0]:" redis_db
|
||||
redis_db=${redis_db:-0}
|
||||
fi
|
||||
else
|
||||
redis_host="localhost"
|
||||
redis_port="6379"
|
||||
redis_password=""
|
||||
redis_db="0"
|
||||
fi
|
||||
|
||||
while true; do
|
||||
reading "请选择数据库类型 sqlite/mysql/postgres [sqlite]:" db_type
|
||||
db_type=${db_type:-sqlite}
|
||||
if [[ "$db_type" =~ ^(sqlite|mysql|postgres)$ ]]; then
|
||||
break
|
||||
else
|
||||
warn "请输入 sqlite、mysql 或 postgres"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$db_type" == "mysql" ]]; then
|
||||
while true; do
|
||||
reading "使用本地安装还是远程配置?local/remote [local]:" mysql_location
|
||||
mysql_location=${mysql_location:-local}
|
||||
if [[ "$mysql_location" =~ ^(local|remote)$ ]]; then
|
||||
break
|
||||
else
|
||||
warn "请输入 local 或 remote"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$mysql_location" == "local" ]]; then
|
||||
info "安装 MariaDB..."
|
||||
apt-get install -y mariadb-server >/dev/null 2>&1
|
||||
systemctl start mariadb
|
||||
systemctl enable mariadb
|
||||
|
||||
mysql_host="localhost"
|
||||
mysql_port="3306"
|
||||
mysql_user="lxdapi"
|
||||
mysql_password=$(openssl rand -hex 8)
|
||||
mysql_database="lxdapi"
|
||||
|
||||
info "创建数据库和用户..."
|
||||
mysql -u root << EOF
|
||||
CREATE DATABASE IF NOT EXISTS ${mysql_database};
|
||||
CREATE USER IF NOT EXISTS '${mysql_user}'@'localhost' IDENTIFIED BY '${mysql_password}';
|
||||
GRANT ALL PRIVILEGES ON ${mysql_database}.* TO '${mysql_user}'@'localhost';
|
||||
FLUSH PRIVILEGES;
|
||||
EOF
|
||||
ok "MariaDB 数据库已创建"
|
||||
ok "用户: $mysql_user"
|
||||
ok "密码: $mysql_password"
|
||||
else
|
||||
reading "请输入 MySQL 主机地址:" mysql_host
|
||||
reading "请输入 MySQL 端口 [3306]:" mysql_port
|
||||
mysql_port=${mysql_port:-3306}
|
||||
reading "请输入 MySQL 用户名:" mysql_user
|
||||
reading "请输入 MySQL 密码:" mysql_password
|
||||
reading "请输入 MySQL 数据库名:" mysql_database
|
||||
fi
|
||||
|
||||
elif [[ "$db_type" == "postgres" ]]; then
|
||||
while true; do
|
||||
reading "使用本地安装还是远程配置?local/remote [local]:" postgres_location
|
||||
postgres_location=${postgres_location:-local}
|
||||
if [[ "$postgres_location" =~ ^(local|remote)$ ]]; then
|
||||
break
|
||||
else
|
||||
warn "请输入 local 或 remote"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$postgres_location" == "local" ]]; then
|
||||
info "安装 PostgreSQL..."
|
||||
apt-get install -y postgresql >/dev/null 2>&1
|
||||
systemctl start postgresql
|
||||
systemctl enable postgresql
|
||||
|
||||
postgres_host="localhost"
|
||||
postgres_port="5432"
|
||||
postgres_user="lxdapi"
|
||||
postgres_password=$(openssl rand -hex 8)
|
||||
postgres_database="lxdapi"
|
||||
postgres_sslmode="disable"
|
||||
|
||||
info "创建数据库和用户..."
|
||||
sudo -u postgres psql << EOF
|
||||
CREATE DATABASE ${postgres_database};
|
||||
CREATE USER ${postgres_user} WITH PASSWORD '${postgres_password}';
|
||||
GRANT ALL PRIVILEGES ON DATABASE ${postgres_database} TO ${postgres_user};
|
||||
EOF
|
||||
ok "PostgreSQL 数据库已创建"
|
||||
ok "用户: $postgres_user"
|
||||
ok "密码: $postgres_password"
|
||||
else
|
||||
reading "请输入 PostgreSQL 主机地址:" postgres_host
|
||||
reading "请输入 PostgreSQL 端口 [5432]:" postgres_port
|
||||
postgres_port=${postgres_port:-5432}
|
||||
reading "请输入 PostgreSQL 用户名:" postgres_user
|
||||
reading "请输入 PostgreSQL 密码:" postgres_password
|
||||
reading "请输入 PostgreSQL 数据库名:" postgres_database
|
||||
reading "请输入 PostgreSQL SSL模式 [disable]:" postgres_sslmode
|
||||
postgres_sslmode=${postgres_sslmode:-disable}
|
||||
fi
|
||||
fi
|
||||
|
||||
info "写入配置文件..."
|
||||
sed -i "s|__SERVER_PORT__|$server_port|g" "$config_file"
|
||||
sed -i "s|__API_HASH__|$api_hash|g" "$config_file"
|
||||
sed -i "s|__ADMIN_USER__|$admin_user|g" "$config_file"
|
||||
sed -i "s|__ADMIN_PASS__|$admin_pass|g" "$config_file"
|
||||
sed -i "s|__SESSION_SECRET__|$session_secret|g" "$config_file"
|
||||
sed -i "s|__TRAFFIC_INTERVAL__|$traffic_interval|g" "$config_file"
|
||||
sed -i "s|__TRAFFIC_BATCH_SIZE__|$traffic_batch_size|g" "$config_file"
|
||||
sed -i "s|__AUTO_CLEANUP_DAYS__|$auto_cleanup_days|g" "$config_file"
|
||||
sed -i "s|__TASK_BACKEND__|$task_backend|g" "$config_file"
|
||||
sed -i "s|__REDIS_HOST__|$redis_host|g" "$config_file"
|
||||
sed -i "s|__REDIS_PORT__|$redis_port|g" "$config_file"
|
||||
sed -i "s|__REDIS_PASSWORD__|$redis_password|g" "$config_file"
|
||||
sed -i "s|__REDIS_DB__|$redis_db|g" "$config_file"
|
||||
sed -i "s|__DB_TYPE__|$db_type|g" "$config_file"
|
||||
|
||||
if [[ "$db_type" == "mysql" ]]; then
|
||||
sed -i "s|__MYSQL_HOST__|$mysql_host|g" "$config_file"
|
||||
sed -i "s|__MYSQL_PORT__|$mysql_port|g" "$config_file"
|
||||
sed -i "s|__MYSQL_USER__|$mysql_user|g" "$config_file"
|
||||
sed -i "s|__MYSQL_PASSWORD__|$mysql_password|g" "$config_file"
|
||||
sed -i "s|__MYSQL_DATABASE__|$mysql_database|g" "$config_file"
|
||||
else
|
||||
sed -i "s|__MYSQL_HOST__|localhost|g" "$config_file"
|
||||
sed -i "s|__MYSQL_PORT__|3306|g" "$config_file"
|
||||
sed -i "s|__MYSQL_USER__|root|g" "$config_file"
|
||||
sed -i "s|__MYSQL_PASSWORD__||g" "$config_file"
|
||||
sed -i "s|__MYSQL_DATABASE__|lxdapi|g" "$config_file"
|
||||
fi
|
||||
|
||||
if [[ "$db_type" == "postgres" ]]; then
|
||||
sed -i "s|__POSTGRES_HOST__|$postgres_host|g" "$config_file"
|
||||
sed -i "s|__POSTGRES_PORT__|$postgres_port|g" "$config_file"
|
||||
sed -i "s|__POSTGRES_USER__|$postgres_user|g" "$config_file"
|
||||
sed -i "s|__POSTGRES_PASSWORD__|$postgres_password|g" "$config_file"
|
||||
sed -i "s|__POSTGRES_DATABASE__|$postgres_database|g" "$config_file"
|
||||
sed -i "s|__POSTGRES_SSLMODE__|$postgres_sslmode|g" "$config_file"
|
||||
else
|
||||
sed -i "s|__POSTGRES_HOST__|localhost|g" "$config_file"
|
||||
sed -i "s|__POSTGRES_PORT__|5432|g" "$config_file"
|
||||
sed -i "s|__POSTGRES_USER__|postgres|g" "$config_file"
|
||||
sed -i "s|__POSTGRES_PASSWORD__||g" "$config_file"
|
||||
sed -i "s|__POSTGRES_DATABASE__|lxdapi|g" "$config_file"
|
||||
sed -i "s|__POSTGRES_SSLMODE__|disable|g" "$config_file"
|
||||
fi
|
||||
|
||||
ok "配置文件已更新"
|
||||
}
|
||||
|
||||
setup_lxdapi_service() {
|
||||
info "配置 lxdapi 系统服务..."
|
||||
|
||||
config_file="/opt/lxdapi/configs/config.yaml"
|
||||
if [ ! -f "$config_file" ]; then
|
||||
err "配置文件不存在: $config_file"
|
||||
fi
|
||||
|
||||
if grep -q "__SERVER_PORT__" "$config_file"; then
|
||||
err "配置文件未完成配置"
|
||||
fi
|
||||
|
||||
sys_arch=$(uname -m)
|
||||
case $sys_arch in
|
||||
x86_64)
|
||||
exec_bin="/opt/lxdapi/lxdapi-amd64"
|
||||
;;
|
||||
aarch64|arm64)
|
||||
exec_bin="/opt/lxdapi/lxdapi-arm64"
|
||||
;;
|
||||
*)
|
||||
err "不支持的架构: $sys_arch"
|
||||
;;
|
||||
esac
|
||||
|
||||
service_file="/etc/systemd/system/lxdapi.service"
|
||||
|
||||
cat > "$service_file" << EOF
|
||||
[Unit]
|
||||
Description=LXD API Server
|
||||
After=network.target lxd.service
|
||||
Wants=lxd.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
WorkingDirectory=/opt/lxdapi
|
||||
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
|
||||
ExecStart=$exec_bin
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
ok "服务文件已创建: $service_file"
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable lxdapi
|
||||
systemctl start lxdapi
|
||||
|
||||
info "等待服务启动..."
|
||||
for i in {1..10}; do
|
||||
printf "\r[%-10s] %d/10s" "$(printf '#%.0s' $(seq 1 $i))" "$i"
|
||||
sleep 1
|
||||
done
|
||||
echo
|
||||
|
||||
if systemctl is-active --quiet lxdapi; then
|
||||
ok "lxdapi 服务已启动"
|
||||
else
|
||||
warn "lxdapi 服务启动失败"
|
||||
journalctl -u lxdapi -n 20 --no-pager
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
echo
|
||||
echo "========================================"
|
||||
echo " LXDAPI 安装脚本"
|
||||
echo " by Github-xkatld"
|
||||
echo "========================================"
|
||||
echo
|
||||
|
||||
echo "======== 步骤 1/5: 基础软件包安装 ========"
|
||||
reading "是否安装基础软件包?(y/n) [y]:" step1_confirm
|
||||
step1_confirm=${step1_confirm:-y}
|
||||
if [[ "$step1_confirm" =~ ^[yY]$ ]]; then
|
||||
install_base_packages
|
||||
ok "基础软件包安装完成"
|
||||
else
|
||||
info "已跳过基础软件包安装"
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "======== 步骤 2/5: 下载 ========"
|
||||
reading "是否下载 lxdapi?(y/n) [y]:" step2_confirm
|
||||
step2_confirm=${step2_confirm:-y}
|
||||
if [[ "$step2_confirm" =~ ^[yY]$ ]]; then
|
||||
deploy_lxdapi
|
||||
ok "下载完成"
|
||||
else
|
||||
info "已跳过下载"
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "======== 步骤 3/5: 配置 ========"
|
||||
reading "是否配置 lxdapi?(y/n) [y]:" step3_confirm
|
||||
step3_confirm=${step3_confirm:-y}
|
||||
if [[ "$step3_confirm" =~ ^[yY]$ ]]; then
|
||||
configure_lxdapi
|
||||
ok "配置完成"
|
||||
else
|
||||
info "已跳过配置"
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "======== 步骤 4/5: 启动服务 ========"
|
||||
reading "是否启动 lxdapi 服务?(y/n) [y]:" step4_confirm
|
||||
step4_confirm=${step4_confirm:-y}
|
||||
if [[ "$step4_confirm" =~ ^[yY]$ ]]; then
|
||||
setup_lxdapi_service
|
||||
ok "服务已启动"
|
||||
else
|
||||
info "已跳过服务启动"
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "======== 步骤 5/5: 完成 ========"
|
||||
echo
|
||||
echo "========================================"
|
||||
echo " LXDAPI 安装完成"
|
||||
echo "========================================"
|
||||
echo
|
||||
info "服务端口: $server_port"
|
||||
info "API密钥: $api_hash"
|
||||
info "管理员用户: $admin_user"
|
||||
info "管理员密码: $admin_pass"
|
||||
info "数据库类型: $db_type"
|
||||
info "任务队列: $task_backend"
|
||||
info "流量采集间隔: ${traffic_interval}s"
|
||||
echo
|
||||
systemctl status lxdapi --no-pager | head -5
|
||||
}
|
||||
|
||||
main
|
||||
112
Shell/lxdapi_tool.sh
Normal file
112
Shell/lxdapi_tool.sh
Normal file
@@ -0,0 +1,112 @@
|
||||
#!/bin/bash
|
||||
|
||||
INSTALL_DIR="/opt/lxdapi"
|
||||
SERVICE_NAME="lxdapi"
|
||||
SCRIPT_PATH="/usr/local/bin/lxdapi"
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
NC='\033[0m'
|
||||
|
||||
if [ "$(realpath "$0")" != "$SCRIPT_PATH" ]; then
|
||||
cp "$0" "$SCRIPT_PATH"
|
||||
chmod +x "$SCRIPT_PATH"
|
||||
echo "lxdapi 命令已安装"
|
||||
echo "用法: lxdapi 或 lxdapi {start|stop|restart|status|config|machine-id}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
wait_progress() {
|
||||
echo "等待服务响应..."
|
||||
for i in {1..10}; do
|
||||
printf "\r[%-10s] %d/10s" "$(printf '#%.0s' $(seq 1 $i))" "$i"
|
||||
sleep 1
|
||||
done
|
||||
echo
|
||||
}
|
||||
|
||||
do_start() {
|
||||
systemctl start $SERVICE_NAME
|
||||
echo "lxdapi 已启动"
|
||||
wait_progress
|
||||
systemctl status $SERVICE_NAME --no-pager | head -5
|
||||
}
|
||||
|
||||
do_stop() {
|
||||
systemctl stop $SERVICE_NAME
|
||||
echo "lxdapi 已停止"
|
||||
sleep 1
|
||||
systemctl status $SERVICE_NAME --no-pager | head -5
|
||||
}
|
||||
|
||||
do_restart() {
|
||||
systemctl restart $SERVICE_NAME
|
||||
echo "lxdapi 已重启"
|
||||
wait_progress
|
||||
systemctl status $SERVICE_NAME --no-pager | head -5
|
||||
}
|
||||
|
||||
do_status() {
|
||||
systemctl status $SERVICE_NAME --no-pager | head -5
|
||||
echo
|
||||
echo "===== 最近日志 ====="
|
||||
journalctl -u $SERVICE_NAME -n 10 --no-pager
|
||||
}
|
||||
|
||||
do_config() {
|
||||
CONFIG_FILE="$INSTALL_DIR/configs/config.yaml"
|
||||
PORT=$(grep "port:" "$CONFIG_FILE" | head -1 | awk '{print $2}')
|
||||
API_KEY=$(grep "api_key:" "$CONFIG_FILE" | awk -F'"' '{print $2}')
|
||||
echo "端口: $PORT"
|
||||
echo "API密钥: $API_KEY"
|
||||
}
|
||||
|
||||
do_machine_id() {
|
||||
ARCH=$(uname -m)
|
||||
case $ARCH in
|
||||
x86_64) ARCH="amd64" ;;
|
||||
aarch64|arm64) ARCH="arm64" ;;
|
||||
esac
|
||||
$INSTALL_DIR/lxdapi-$ARCH --machine-id
|
||||
}
|
||||
|
||||
show_menu() {
|
||||
echo
|
||||
echo "================================"
|
||||
echo " LXDAPI 管理工具"
|
||||
echo "================================"
|
||||
echo "1. 启动"
|
||||
echo "2. 停止"
|
||||
echo "3. 重启"
|
||||
echo "4. 状态"
|
||||
echo "5. 配置"
|
||||
echo "6. 机器码"
|
||||
echo "0. 退出"
|
||||
echo "================================"
|
||||
read -rp "$(echo -e "${GREEN}请选择 [0-6]: ${NC}")" choice
|
||||
|
||||
case "$choice" in
|
||||
1) do_start ;;
|
||||
2) do_stop ;;
|
||||
3) do_restart ;;
|
||||
4) do_status ;;
|
||||
5) do_config ;;
|
||||
6) do_machine_id ;;
|
||||
0) exit 0 ;;
|
||||
*) echo "无效选择" ;;
|
||||
esac
|
||||
show_menu
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start) do_start ;;
|
||||
stop) do_stop ;;
|
||||
restart) do_restart ;;
|
||||
status) do_status ;;
|
||||
config) do_config ;;
|
||||
machine-id) do_machine_id ;;
|
||||
"") show_menu ;;
|
||||
*)
|
||||
echo "用法: lxdapi 或 lxdapi {start|stop|restart|status|config|machine-id}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
237
Shell/lxdapi_update.sh
Normal file
237
Shell/lxdapi_update.sh
Normal file
@@ -0,0 +1,237 @@
|
||||
#!/bin/bash
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
log() { echo -e "$1"; }
|
||||
ok() { log "${GREEN}[OK]${NC} $1"; }
|
||||
info() { log "${BLUE}[INFO]${NC} $1"; }
|
||||
warn() { log "${YELLOW}[WARN]${NC} $1"; }
|
||||
err() { log "${RED}[ERR]${NC} $1"; exit 1; }
|
||||
|
||||
INSTALL_DIR="/opt/lxdapi"
|
||||
CONFIG_FILE="$INSTALL_DIR/configs/config.yaml"
|
||||
BACKUP_DIR="$INSTALL_DIR/backup"
|
||||
SERVICE_NAME="lxdapi"
|
||||
|
||||
check_environment() {
|
||||
info "检测运行环境..."
|
||||
|
||||
if [ ! -d "$INSTALL_DIR" ]; then
|
||||
err "未检测到 lxdapi 安装目录: $INSTALL_DIR"
|
||||
fi
|
||||
|
||||
ok "环境检测通过"
|
||||
}
|
||||
|
||||
detect_arch() {
|
||||
info "检测系统架构..."
|
||||
sys_arch=$(uname -m)
|
||||
case $sys_arch in
|
||||
x86_64)
|
||||
ARCH="amd64"
|
||||
ok "检测到架构: x86_64"
|
||||
;;
|
||||
aarch64|arm64)
|
||||
ARCH="arm64"
|
||||
ok "检测到架构: $sys_arch"
|
||||
;;
|
||||
*)
|
||||
err "不支持的架构: $sys_arch"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
get_current_version() {
|
||||
if [ -f "$INSTALL_DIR/lxdapi-$ARCH" ]; then
|
||||
CURRENT_VERSION=$(stat -c %y "$INSTALL_DIR/lxdapi-$ARCH" 2>/dev/null | cut -d' ' -f1)
|
||||
else
|
||||
CURRENT_VERSION="未安装"
|
||||
fi
|
||||
info "当前版本: $CURRENT_VERSION"
|
||||
}
|
||||
|
||||
get_latest_version() {
|
||||
info "获取最新版本..."
|
||||
LATEST_VERSION=$(curl -s https://api.github.com/repos/xkatld/lxdapi-web-server/releases/latest | grep '"tag_name"' | sed -n 's/.*"tag_name": *"\([^"]*\)".*/\1/p')
|
||||
|
||||
if [ -z "$LATEST_VERSION" ]; then
|
||||
err "无法获取最新版本信息,请检查网络连接"
|
||||
fi
|
||||
|
||||
info "最新版本: $LATEST_VERSION"
|
||||
read -rp "$(echo -e "${GREEN}请输入更新版本 [$LATEST_VERSION]: ${NC}")" UPDATE_VERSION
|
||||
UPDATE_VERSION=${UPDATE_VERSION:-$LATEST_VERSION}
|
||||
ok "更新版本: $UPDATE_VERSION"
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
info "停止 $SERVICE_NAME 服务..."
|
||||
|
||||
if systemctl is-active --quiet $SERVICE_NAME; then
|
||||
systemctl stop $SERVICE_NAME
|
||||
sleep 2
|
||||
if systemctl is-active --quiet $SERVICE_NAME; then
|
||||
err "无法停止 $SERVICE_NAME 服务"
|
||||
fi
|
||||
ok "服务已停止"
|
||||
else
|
||||
warn "服务未运行"
|
||||
fi
|
||||
}
|
||||
|
||||
backup_files() {
|
||||
info "备份当前文件..."
|
||||
|
||||
BACKUP_TIME=$(date +%Y%m%d_%H%M%S)
|
||||
BACKUP_PATH="$BACKUP_DIR/$BACKUP_TIME"
|
||||
mkdir -p "$BACKUP_PATH"
|
||||
|
||||
cp "$CONFIG_FILE" "$BACKUP_PATH/config.yaml"
|
||||
ok "配置文件已备份到: $BACKUP_PATH/config.yaml"
|
||||
|
||||
if [ -f "$INSTALL_DIR/lxdapi-$ARCH" ]; then
|
||||
cp "$INSTALL_DIR/lxdapi-$ARCH" "$BACKUP_PATH/lxdapi-$ARCH"
|
||||
ok "二进制文件已备份"
|
||||
fi
|
||||
|
||||
if [ -d "$INSTALL_DIR/certs" ]; then
|
||||
cp -r "$INSTALL_DIR/certs" "$BACKUP_PATH/certs"
|
||||
ok "证书文件已备份"
|
||||
fi
|
||||
|
||||
if [ -f "$INSTALL_DIR/lxdapi.db" ]; then
|
||||
cp "$INSTALL_DIR/lxdapi.db" "$BACKUP_PATH/lxdapi.db"
|
||||
ok "数据库文件已备份"
|
||||
fi
|
||||
}
|
||||
|
||||
download_latest() {
|
||||
info "下载版本 $UPDATE_VERSION..."
|
||||
|
||||
DOWNLOAD_URL="https://github.com/xkatld/lxdapi-web-server/releases/download/${UPDATE_VERSION}/lxdapi-linux-${ARCH}.tar.gz"
|
||||
info "下载地址: $DOWNLOAD_URL"
|
||||
|
||||
TEMP_FILE=$(mktemp)
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
|
||||
if wget -q --show-progress -O "$TEMP_FILE" "$DOWNLOAD_URL" 2>&1; then
|
||||
ok "下载完成"
|
||||
else
|
||||
rm -f "$TEMP_FILE"
|
||||
rm -rf "$TEMP_DIR"
|
||||
err "下载失败"
|
||||
fi
|
||||
|
||||
info "解压文件..."
|
||||
tar -xzf "$TEMP_FILE" -C "$TEMP_DIR" --strip-components=1
|
||||
|
||||
if [ ! -f "$TEMP_DIR/lxdapi-$ARCH" ]; then
|
||||
rm -f "$TEMP_FILE"
|
||||
rm -rf "$TEMP_DIR"
|
||||
err "解压后未找到可执行文件"
|
||||
fi
|
||||
|
||||
ok "解压完成"
|
||||
|
||||
info "更新文件..."
|
||||
cp "$TEMP_DIR/lxdapi-$ARCH" "$INSTALL_DIR/lxdapi-$ARCH"
|
||||
chmod +x "$INSTALL_DIR/lxdapi-$ARCH"
|
||||
|
||||
rm -f "$TEMP_FILE"
|
||||
rm -rf "$TEMP_DIR"
|
||||
|
||||
ok "文件更新完成"
|
||||
}
|
||||
|
||||
start_service() {
|
||||
info "启动 $SERVICE_NAME 服务..."
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl start $SERVICE_NAME
|
||||
|
||||
info "等待服务启动..."
|
||||
for i in {1..10}; do
|
||||
printf "\r[%-10s] %d/10s" "$(printf '#%.0s' $(seq 1 $i))" "$i"
|
||||
sleep 1
|
||||
done
|
||||
echo
|
||||
|
||||
if systemctl is-active --quiet $SERVICE_NAME; then
|
||||
ok "服务已启动"
|
||||
else
|
||||
warn "服务启动失败,查看日志:"
|
||||
journalctl -u $SERVICE_NAME -n 10 --no-pager
|
||||
err "请检查配置或手动启动服务"
|
||||
fi
|
||||
}
|
||||
|
||||
show_result() {
|
||||
echo
|
||||
echo "========================================"
|
||||
echo " lxdapi 更新完成"
|
||||
echo "========================================"
|
||||
echo
|
||||
info "更新前版本: $CURRENT_VERSION"
|
||||
info "更新后版本: $UPDATE_VERSION"
|
||||
info "备份目录: $BACKUP_PATH"
|
||||
echo
|
||||
info "===== 服务状态 ====="
|
||||
systemctl status $SERVICE_NAME --no-pager | head -10
|
||||
}
|
||||
|
||||
rollback() {
|
||||
warn "执行回滚..."
|
||||
|
||||
if [ -z "$BACKUP_PATH" ] || [ ! -d "$BACKUP_PATH" ]; then
|
||||
err "无法回滚:备份目录不存在"
|
||||
fi
|
||||
|
||||
if [ -f "$BACKUP_PATH/lxdapi-$ARCH" ]; then
|
||||
cp "$BACKUP_PATH/lxdapi-$ARCH" "$INSTALL_DIR/lxdapi-$ARCH"
|
||||
chmod +x "$INSTALL_DIR/lxdapi-$ARCH"
|
||||
ok "已恢复二进制文件"
|
||||
fi
|
||||
|
||||
systemctl start $SERVICE_NAME
|
||||
ok "回滚完成"
|
||||
}
|
||||
|
||||
main() {
|
||||
echo
|
||||
echo "========================================"
|
||||
echo " LXDAPI 更新脚本"
|
||||
echo " by Github-xkatld"
|
||||
echo "========================================"
|
||||
echo
|
||||
|
||||
check_environment
|
||||
detect_arch
|
||||
get_current_version
|
||||
get_latest_version
|
||||
|
||||
echo
|
||||
read -rp "$(echo -e "${GREEN}确认更新? (y/n) [y]: ${NC}")" confirm
|
||||
confirm=${confirm:-y}
|
||||
|
||||
if [[ ! "$confirm" =~ ^[yY]$ ]]; then
|
||||
info "已取消更新"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo
|
||||
stop_service
|
||||
backup_files
|
||||
|
||||
if download_latest; then
|
||||
start_service
|
||||
show_result
|
||||
else
|
||||
rollback
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
333
Shell/storage_pool.sh
Normal file
333
Shell/storage_pool.sh
Normal file
@@ -0,0 +1,333 @@
|
||||
#!/bin/bash
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
ok() { echo -e "${GREEN}[OK]${NC} $1"; }
|
||||
err() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||
|
||||
reading() {
|
||||
read -rp "$(echo -e "${GREEN}[INPUT]${NC} $1")" "$2"
|
||||
}
|
||||
|
||||
detect_system() {
|
||||
if [ -f /etc/os-release ]; then
|
||||
. /etc/os-release
|
||||
SYSTEM="$ID"
|
||||
else
|
||||
SYSTEM="unknown"
|
||||
fi
|
||||
}
|
||||
|
||||
check_zfs() {
|
||||
command -v zfs &>/dev/null && command -v zpool &>/dev/null
|
||||
}
|
||||
|
||||
install_zfs() {
|
||||
if check_zfs; then
|
||||
ok "ZFS 已安装"
|
||||
info "配置 LXD 使用系统 ZFS..."
|
||||
snap set lxd zfs.external=true
|
||||
snap restart lxd
|
||||
sleep 3
|
||||
return 0
|
||||
fi
|
||||
|
||||
detect_system
|
||||
|
||||
if [[ "$SYSTEM" == "debian" ]]; then
|
||||
warn "Debian 系统需要编译安装 ZFS,预计耗时 10-30 分钟"
|
||||
reading "是否继续?(y/n) [n]: " confirm
|
||||
if [[ ! "$confirm" =~ ^[yY]$ ]]; then
|
||||
return 1
|
||||
fi
|
||||
info "开始编译安装 ZFS..."
|
||||
bash <(curl -sL https://raw.githubusercontent.com/xkatld/lxdapi-web-server/refs/heads/v2.1.0-vpsm.link/Shell/debian_zfs.sh) || return 1
|
||||
else
|
||||
info "安装 ZFS..."
|
||||
apt-get update -qq && apt-get install -y zfsutils-linux -qq
|
||||
fi
|
||||
|
||||
info "配置 LXD 使用系统 ZFS..."
|
||||
snap set lxd zfs.external=true
|
||||
snap restart lxd
|
||||
sleep 3
|
||||
|
||||
ok "ZFS 安装完成"
|
||||
return 0
|
||||
}
|
||||
|
||||
check_root() {
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
err "请使用 root 用户运行此脚本"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_lxd() {
|
||||
if ! command -v lxc &>/dev/null; then
|
||||
err "未检测到 LXD,请先安装 LXD"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
get_available_space() {
|
||||
df -BG / | awk 'NR==2 {gsub("G","",$4); print $4}'
|
||||
}
|
||||
|
||||
get_available_pool_name() {
|
||||
local i=1
|
||||
while lxc storage show "pool${i}" &>/dev/null; do
|
||||
((i++))
|
||||
done
|
||||
echo "pool${i}"
|
||||
}
|
||||
|
||||
install_package() {
|
||||
local pkg="$1"
|
||||
if ! dpkg -l | grep -q "^ii $pkg "; then
|
||||
info "安装 $pkg..."
|
||||
apt-get update -qq && apt-get install -y "$pkg" -qq
|
||||
fi
|
||||
}
|
||||
|
||||
list_disks() {
|
||||
info "可用块设备 (>10GB):"
|
||||
echo
|
||||
lsblk -d -n -o NAME,SIZE,TYPE | while read name size type; do
|
||||
if [[ "$type" == "disk" ]]; then
|
||||
size_num=$(echo "$size" | sed 's/[^0-9.]//g')
|
||||
size_unit=$(echo "$size" | sed 's/[0-9.]//g')
|
||||
case "$size_unit" in
|
||||
T) size_gb=$(echo "$size_num * 1024" | bc 2>/dev/null || echo "1000") ;;
|
||||
G) size_gb=$size_num ;;
|
||||
*) size_gb=0 ;;
|
||||
esac
|
||||
if (( $(echo "$size_gb > 10" | bc -l 2>/dev/null || echo 0) )); then
|
||||
echo " /dev/$name ($size)"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
echo
|
||||
}
|
||||
|
||||
create_native_auto() {
|
||||
local backend="$1"
|
||||
local pool_name="$2"
|
||||
local size_gb="$3"
|
||||
|
||||
case "$backend" in
|
||||
zfs) install_zfs || return 1 ;;
|
||||
btrfs) install_package btrfs-progs ;;
|
||||
lvm) install_package lvm2 ;;
|
||||
esac
|
||||
|
||||
ok "创建 $backend 存储池..."
|
||||
if lxc storage create "$pool_name" "$backend" size="${size_gb}GiB"; then
|
||||
ok "$backend 存储池 $pool_name 创建成功"
|
||||
return 0
|
||||
else
|
||||
err "创建失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
create_zfs_disk() {
|
||||
local device="$1"
|
||||
local pool_name="$2"
|
||||
local zpool_name="${pool_name}_zpool"
|
||||
|
||||
[ ! -b "$device" ] && { err "设备 $device 不存在"; return 1; }
|
||||
install_zfs || return 1
|
||||
|
||||
ok "创建 ZFS 池..."
|
||||
zpool create -f "$zpool_name" "$device" || { err "创建 ZFS 池失败"; return 1; }
|
||||
|
||||
ok "创建 LXD 存储池..."
|
||||
if lxc storage create "$pool_name" zfs source="$zpool_name"; then
|
||||
ok "ZFS 存储池 $pool_name 创建成功"
|
||||
return 0
|
||||
else
|
||||
zpool destroy "$zpool_name"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
create_btrfs_disk() {
|
||||
local device="$1"
|
||||
local pool_name="$2"
|
||||
|
||||
[ ! -b "$device" ] && { err "设备 $device 不存在"; return 1; }
|
||||
install_package btrfs-progs
|
||||
|
||||
ok "格式化为 Btrfs..."
|
||||
mkfs.btrfs -f "$device" || { err "格式化失败"; return 1; }
|
||||
|
||||
if lxc storage create "$pool_name" btrfs source="$device"; then
|
||||
ok "Btrfs 存储池 $pool_name 创建成功"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
create_lvm_disk() {
|
||||
local device="$1"
|
||||
local pool_name="$2"
|
||||
|
||||
[ ! -b "$device" ] && { err "设备 $device 不存在"; return 1; }
|
||||
install_package lvm2
|
||||
|
||||
if lxc storage create "$pool_name" lvm source="$device"; then
|
||||
ok "LVM 存储池 $pool_name 创建成功"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
create_dir_pool() {
|
||||
local dir_path="$1"
|
||||
local pool_name="$2"
|
||||
|
||||
mkdir -p "$dir_path"
|
||||
if lxc storage create "$pool_name" dir source="$dir_path"; then
|
||||
ok "目录存储池 $pool_name 创建成功"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
delete_storage_pool() {
|
||||
local pool_name="$1"
|
||||
|
||||
lxc storage show "$pool_name" &>/dev/null || { err "存储池 $pool_name 不存在"; return 1; }
|
||||
|
||||
if lxc storage delete "$pool_name"; then
|
||||
ok "存储池 $pool_name 已删除"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
menu_native() {
|
||||
echo
|
||||
info "=== Loop 设备 (自动创建) ==="
|
||||
echo "1. ZFS"
|
||||
echo "2. Btrfs"
|
||||
echo "3. LVM"
|
||||
echo "4. Dir (目录)"
|
||||
echo "0. 返回"
|
||||
echo
|
||||
reading "请选择 [0-4]: " choice
|
||||
|
||||
local default_pool=$(get_available_pool_name)
|
||||
local default_size=$(get_available_space)
|
||||
|
||||
case "$choice" in
|
||||
1|2|3)
|
||||
info "当前可用磁盘空间: ${default_size}GB"
|
||||
reading "存储池名称 [$default_pool]: " pool_name
|
||||
pool_name=${pool_name:-$default_pool}
|
||||
reading "存储大小 GB [$default_size]: " size_gb
|
||||
size_gb=${size_gb:-$default_size}
|
||||
|
||||
case "$choice" in
|
||||
1) create_native_auto "zfs" "$pool_name" "$size_gb" ;;
|
||||
2) create_native_auto "btrfs" "$pool_name" "$size_gb" ;;
|
||||
3) create_native_auto "lvm" "$pool_name" "$size_gb" ;;
|
||||
esac
|
||||
;;
|
||||
4)
|
||||
reading "存储池名称 [$default_pool]: " pool_name
|
||||
pool_name=${pool_name:-$default_pool}
|
||||
reading "目录路径 [/opt/lxd-dir]: " dir_path
|
||||
dir_path=${dir_path:-/opt/lxd-dir}
|
||||
create_dir_pool "$dir_path" "$pool_name"
|
||||
;;
|
||||
0) return ;;
|
||||
*) warn "无效选择" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
menu_disk() {
|
||||
echo
|
||||
info "=== 块设备 (磁盘/分区) ==="
|
||||
list_disks
|
||||
echo "1. ZFS"
|
||||
echo "2. Btrfs"
|
||||
echo "3. LVM"
|
||||
echo "0. 返回"
|
||||
echo
|
||||
reading "请选择 [0-3]: " choice
|
||||
|
||||
local default_pool=$(get_available_pool_name)
|
||||
|
||||
case "$choice" in
|
||||
1|2|3)
|
||||
reading "存储池名称 [$default_pool]: " pool_name
|
||||
pool_name=${pool_name:-$default_pool}
|
||||
reading "设备路径: " device
|
||||
[ -z "$device" ] && { warn "设备路径不能为空"; return; }
|
||||
|
||||
warn "将使用 $device 创建存储池,数据将被清除!"
|
||||
reading "确认继续?(y/n) [n]: " confirm
|
||||
[[ ! "$confirm" =~ ^[yY]$ ]] && { info "已取消"; return; }
|
||||
|
||||
case "$choice" in
|
||||
1) create_zfs_disk "$device" "$pool_name" ;;
|
||||
2) create_btrfs_disk "$device" "$pool_name" ;;
|
||||
3) create_lvm_disk "$device" "$pool_name" ;;
|
||||
esac
|
||||
;;
|
||||
0) return ;;
|
||||
*) warn "无效选择" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
menu_delete() {
|
||||
echo
|
||||
info "=== 删除存储池 ==="
|
||||
lxc storage list
|
||||
echo
|
||||
reading "输入要删除的存储池名称: " pool_name
|
||||
[ -z "$pool_name" ] && return
|
||||
|
||||
warn "确认删除存储池 $pool_name?"
|
||||
reading "确认?(y/n) [n]: " confirm
|
||||
[[ "$confirm" =~ ^[yY]$ ]] && delete_storage_pool "$pool_name" || info "已取消"
|
||||
}
|
||||
|
||||
main_menu() {
|
||||
while true; do
|
||||
echo
|
||||
echo "================================"
|
||||
echo " LXD 存储池管理脚本"
|
||||
echo " LXDAPI by Github-xkatld"
|
||||
echo "================================"
|
||||
echo "1. Loop 设备 (自动创建)"
|
||||
echo "2. 块设备 (磁盘/分区)"
|
||||
echo "3. 查看存储池"
|
||||
echo "4. 删除存储池"
|
||||
echo "0. 退出"
|
||||
echo "================================"
|
||||
reading "请选择 [0-4]: " choice
|
||||
|
||||
case "$choice" in
|
||||
1) menu_native ;;
|
||||
2) menu_disk ;;
|
||||
3) echo; lxc storage list ;;
|
||||
4) menu_delete ;;
|
||||
0) ok "退出"; exit 0 ;;
|
||||
*) warn "无效选择" ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
check_root
|
||||
check_lxd
|
||||
install_package bc
|
||||
main_menu
|
||||
Reference in New Issue
Block a user