Update vps_manager.sh

This commit is contained in:
Lsmoisu 2025-05-18 01:18:54 +08:00 committed by GitHub
parent 048e7c9947
commit 42a3814356
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -16,9 +16,14 @@ show_menu() {
echo "9. 查看虚拟机列表"
echo "10. 创建虚拟机"
echo "11. 删除虚拟机"
echo "12. 查看该项目下 socks5 配置"
echo "13. 配置防火墙"
echo "14. 查看防火墙规则"
echo "15. 删除防火墙规则"
echo "0. 退出脚本"
echo "====================================="
echo "请输入选项0-11"
echo "请输入选项0-13"
}
# 获取当前日期,格式为 YYYYMMDD
@ -61,26 +66,81 @@ get_instance_quota() {
return 0
}
# 动态获取支持 e2-micro 的区域和可用区,并分组
# 动态获取支持 e2-micro 的区域和可用区,并分组(优化版)
get_regions_and_zones() {
echo "正在获取支持 e2-micro 机器类型的区域和可用区..."
zones=$(gcloud compute machine-types list --filter="name=e2-micro" --format="value(ZONE)" --limit=1000 2>/dev/null | sort | uniq)
if [ -z "$zones" ]; then
echo "无法获取可用区列表,请检查 gcloud 配置或网络连接。"
return 1
fi
# 硬编码的支持 e2-micro 的区域和可用区列表,加速获取
declare -g -A region_map
declare -g -a regions
regions=()
IFS=$'\n'
for zone in $zones; do
region=$(echo "$zone" | cut -d'-' -f1)
if [[ ! " ${regions[@]} " =~ " ${region} " ]]; then
regions+=("$region")
regions=("us-central1" "us-east1" "us-east4" "us-east5" "us-east7" "us-west1" "us-west2" "us-west3" "us-west4" "us-west8" "us-south1" "europe-central2" "europe-north1" "europe-north2" "europe-southwest1" "europe-west1" "europe-west2" "europe-west3" "europe-west4" "europe-west6" "europe-west8" "europe-west9" "europe-west10" "europe-west12" "asia-east1" "asia-east2" "asia-northeast1" "asia-northeast2" "asia-northeast3" "asia-south1" "asia-south2" "asia-southeast1" "asia-southeast2" "australia-southeast1" "australia-southeast2" "southamerica-east1" "southamerica-west1" "northamerica-northeast1" "northamerica-northeast2" "northamerica-south1" "me-central1" "me-central2" "me-west1" "africa-south1")
# 初始化 region_map
region_map["us-central1"]="us-central1-a us-central1-b us-central1-c us-central1-d us-central1-f"
region_map["us-east1"]="us-east1-a us-east1-b us-east1-c us-east1-d"
region_map["us-east4"]="us-east4-a us-east4-b us-east4-c"
region_map["us-east5"]="us-east5-a us-east5-b us-east5-c"
region_map["us-east7"]="us-east7-a us-east7-b us-east7-c"
region_map["us-west1"]="us-west1-a us-west1-b us-west1-c"
region_map["us-west2"]="us-west2-a us-west2-b us-west2-c"
region_map["us-west3"]="us-west3-a us-west3-b us-west3-c"
region_map["us-west4"]="us-west4-a us-west4-b us-west4-c"
region_map["us-west8"]="us-west8-a us-west8-b us-west8-c"
region_map["us-south1"]="us-south1-a us-south1-b us-south1-c"
region_map["europe-central2"]="europe-central2-a europe-central2-b europe-central2-c"
region_map["europe-north1"]="europe-north1-a europe-north1-b europe-north1-c"
region_map["europe-north2"]="europe-north2-a europe-north2-b europe-north2-c"
region_map["europe-southwest1"]="europe-southwest1-a europe-southwest1-b europe-southwest1-c"
region_map["europe-west1"]="europe-west1-b europe-west1-c europe-west1-d"
region_map["europe-west2"]="europe-west2-a europe-west2-b europe-west2-c"
region_map["europe-west3"]="europe-west3-a europe-west3-b europe-west3-c"
region_map["europe-west4"]="europe-west4-a europe-west4-b europe-west4-c"
region_map["europe-west6"]="europe-west6-a europe-west6-b europe-west6-c"
region_map["europe-west8"]="europe-west8-a europe-west8-b europe-west8-c"
region_map["europe-west9"]="europe-west9-a europe-west9-b europe-west9-c"
region_map["europe-west10"]="europe-west10-a europe-west10-b europe-west10-c"
region_map["europe-west12"]="europe-west12-a europe-west12-b europe-west12-c"
region_map["asia-east1"]="asia-east1-a asia-east1-b asia-east1-c"
region_map["asia-east2"]="asia-east2-a asia-east2-b asia-east2-c"
region_map["asia-northeast1"]="asia-northeast1-a asia-northeast1-b asia-northeast1-c"
region_map["asia-northeast2"]="asia-northeast2-a asia-northeast2-b asia-northeast2-c"
region_map["asia-northeast3"]="asia-northeast3-a asia-northeast3-b asia-northeast3-c"
region_map["asia-south1"]="asia-south1-a asia-south1-b asia-south1-c"
region_map["asia-south2"]="asia-south2-a asia-south2-b asia-south2-c"
region_map["asia-southeast1"]="asia-southeast1-a asia-southeast1-b asia-southeast1-c"
region_map["asia-southeast2"]="asia-southeast2-a asia-southeast2-b asia-southeast2-c"
region_map["australia-southeast1"]="australia-southeast1-a australia-southeast1-b australia-southeast1-c"
region_map["australia-southeast2"]="australia-southeast2-a australia-southeast2-b australia-southeast2-c"
region_map["southamerica-east1"]="southamerica-east1-a southamerica-east1-b southamerica-east1-c"
region_map["southamerica-west1"]="southamerica-west1-a southamerica-west1-b southamerica-west1-c"
region_map["northamerica-northeast1"]="northamerica-northeast1-a northamerica-northeast1-b northamerica-northeast1-c"
region_map["northamerica-northeast2"]="northamerica-northeast2-a northamerica-northeast2-b northamerica-northeast2-c"
region_map["northamerica-south1"]="northamerica-south1-a northamerica-south1-b northamerica-south1-c"
region_map["me-central1"]="me-central1-a me-central1-b me-central1-c"
region_map["me-central2"]="me-central2-a me-central2-b me-central2-c"
region_map["me-west1"]="me-west1-a me-west1-b me-west1-c"
region_map["africa-south1"]="africa-south1-a africa-south1-b africa-south1-c"
# 检查硬编码列表是否有效(例如,至少有一个区域)
if [ ${#regions[@]} -eq 0 ]; then
echo "硬编码区域列表为空,尝试动态获取支持 e2-micro 的区域和可用区..."
zones=$(gcloud compute machine-types list --filter="name=e2-micro" --format="value(ZONE)" --limit=1000 2>/dev/null | sort | uniq)
if [ -z "$zones" ]; then
echo "无法获取可用区列表,请检查 gcloud 配置或网络连接。"
return 1
fi
region_map["$region"]="${region_map[$region]} $zone"
done
unset IFS
regions=()
IFS=$'\n'
for zone in $zones; do
region=$(echo "$zone" | cut -d'-' -f1)
if [[ ! " ${regions[@]} " =~ " ${region} " ]]; then
regions+=("$region")
fi
region_map["$region"]="${region_map[$region]} $zone"
done
unset IFS
fi
if [ ${#regions[@]} -eq 0 ]; then
echo "未找到支持 e2-micro 的大区域。"
return 1
@ -93,7 +153,12 @@ show_region_menu() {
echo "请选择大区域:"
local i=1
for region in "${regions[@]}"; do
echo "$i. $region"
location=${region_location_map["$region"]}
if [ -n "$location" ]; then
echo "$i. $region$location"
else
echo "$i. $region"
fi
((i++))
done
echo "0. 取消选择"
@ -112,8 +177,13 @@ show_zone_menu() {
return 1
fi
local i=1
location=${region_location_map["$region"]}
for zone in "${zones_list[@]}"; do
echo "$i. $zone"
if [ -n "$location" ]; then
echo "$i. $zone$location"
else
echo "$i. $zone"
fi
((i++))
done
echo "0. 取消选择"
@ -126,7 +196,13 @@ show_zone_selection_method() {
echo "请选择地区选择方式:"
local default_zone=$(gcloud config get-value compute/zone 2>/dev/null)
if [ -n "$default_zone" ]; then
echo "1. 使用默认地区:$default_zone"
region=$(echo "$default_zone" | sed 's/-[a-z]$//')
location=${region_location_map["$region"]}
if [ -n "$location" ]; then
echo "1. 使用默认地区:$default_zone$location"
else
echo "1. 使用默认地区:$default_zone"
fi
else
echo "1. 使用默认地区(未设置,需手动指定)"
fi
@ -167,7 +243,13 @@ show_instance_menu() {
instance_name=$(echo "$line" | awk '{print $1}')
instance_zone=$(echo "$line" | awk '{print $2}')
if [ -n "$instance_name" ] && [ -n "$instance_zone" ]; then
echo "$i. $instance_name (区域: $instance_zone)"
region=$(echo "$instance_zone" | sed 's/-[a-z]$//')
location=${region_location_map["$region"]}
if [ -n "$location" ]; then
echo "$i. $instance_name (区域: $instance_zone$location)"
else
echo "$i. $instance_name (区域: $instance_zone)"
fi
instance_array+=("$instance_name|$instance_zone")
((i++))
fi
@ -629,7 +711,6 @@ while true; do
read -e -r -n 1
continue
fi
# 下载启动脚本
echo "正在从远程地址下载启动脚本..."
script_url="https://github.com/Lsmoisu/Toolbox/raw/refs/heads/main/enablesshandcreatesocks5.sh"
@ -670,7 +751,52 @@ while true; do
read -e -r -n 1
continue
fi
# 定义区域到地理位置的映射
declare -A region_location_map
region_location_map["africa-south1"]="南非约翰内斯堡"
region_location_map["us-central1"]="美国爱荷华州"
region_location_map["us-east1"]="美国南卡罗来纳州"
region_location_map["us-east4"]="美国弗吉尼亚州北部"
region_location_map["us-east5"]="美国俄亥俄州"
region_location_map["us-east7"]="美国弗吉尼亚州"
region_location_map["us-west1"]="美国俄勒冈州"
region_location_map["us-west2"]="美国加利福尼亚州洛杉矶"
region_location_map["us-west3"]="美国犹他州盐湖城"
region_location_map["us-west4"]="美国内华达州拉斯维加斯"
region_location_map["us-west8"]="美国德克萨斯州达拉斯"
region_location_map["us-south1"]="美国得克萨斯州"
region_location_map["europe-central2"]="波兰华沙"
region_location_map["europe-north1"]="芬兰哈米纳"
region_location_map["europe-north2"]="挪威斯塔万格"
region_location_map["europe-southwest1"]="西班牙马德里"
region_location_map["europe-west1"]="比利时圣吉斯兰"
region_location_map["europe-west2"]="英国伦敦"
region_location_map["europe-west3"]="德国法兰克福"
region_location_map["europe-west4"]="荷兰埃姆斯哈文"
region_location_map["europe-west6"]="瑞士苏黎世"
region_location_map["europe-west8"]="意大利米兰"
region_location_map["europe-west9"]="法国巴黎"
region_location_map["europe-west10"]="德国柏林"
region_location_map["europe-west12"]="意大利都灵"
region_location_map["asia-east1"]="台湾彰化县"
region_location_map["asia-east2"]="中国香港"
region_location_map["asia-northeast1"]="日本东京"
region_location_map["asia-northeast2"]="日本大阪"
region_location_map["asia-northeast3"]="韩国首尔"
region_location_map["asia-south1"]="印度孟买"
region_location_map["asia-south2"]="印度德里"
region_location_map["asia-southeast1"]="新加坡"
region_location_map["asia-southeast2"]="亚太地区印度尼西亚雅加达"
region_location_map["australia-southeast1"]="澳大利亚悉尼"
region_location_map["australia-southeast2"]="澳大利亚墨尔本"
region_location_map["southamerica-east1"]="巴西圣保罗"
region_location_map["southamerica-west1"]="智利圣地亚哥"
region_location_map["northamerica-northeast1"]="加拿大蒙特利尔"
region_location_map["northamerica-northeast2"]="加拿大多伦多"
region_location_map["northamerica-south1"]="美国南卡罗来纳州"
region_location_map["me-central1"]="卡塔尔多哈"
region_location_map["me-central2"]="沙特阿拉伯达曼"
region_location_map["me-west1"]="以色列特拉维夫"
# 选择地区选择方式
while true; do
show_zone_selection_method
@ -683,7 +809,13 @@ while true; do
elif [ "$method_choice" -eq 1 ]; then
default_zone=$(gcloud config get-value compute/zone 2>/dev/null)
if [ -n "$default_zone" ]; then
echo "使用默认地区:$default_zone"
region=$(echo "$default_zone" | cut -d'-' -f1-2)
location=${region_location_map["$region"]}
if [ -n "$location" ]; then
echo "使用默认地区:$default_zone$location"
else
echo "使用默认地区:$default_zone"
fi
zone="$default_zone"
break
else
@ -698,7 +830,13 @@ while true; do
echo "正在设置默认地区为 $input_zone..."
gcloud config set compute/zone "$input_zone"
if [ $? -eq 0 ]; then
echo "默认地区已设置为 $input_zone"
region=$(echo "$input_zone" | cut -d'-' -f1-2)
location=${region_location_map["$region"]}
if [ -n "$location" ]; then
echo "默认地区已设置为 $input_zone$location"
else
echo "默认地区已设置为 $input_zone"
fi
zone="$input_zone"
break
else
@ -709,6 +847,7 @@ while true; do
fi
fi
elif [ "$method_choice" -eq 2 ]; then
echo "正在获取支持 e2-micro 机器类型的区域和可用区..."
get_regions_and_zones
if [ $? -ne 0 ]; then
echo "按任意键返回菜单..."
@ -716,7 +855,18 @@ while true; do
continue 2
fi
while true; do
show_region_menu
echo "请选择大区域:"
for i in "${!regions[@]}"; do
region="${regions[$i]}"
location=${region_location_map["$region"]}
if [ -n "$location" ]; then
printf "%2d. %s (%s)\n" "$((i+1))" "$region" "$location"
else
printf "%2d. %s\n" "$((i+1))" "$region"
fi
done
echo "0. 取消选择"
echo "请输入选项0-${#regions[@]}"
read -e -r region_choice
if [ "$region_choice" -eq 0 ]; then
echo "操作取消。"
@ -750,12 +900,36 @@ while true; do
fi
if [ "$zone_choice" -ge 1 ] && [ "$zone_choice" -le "${#zones_list[@]}" ]; then
zone="${zones_list[$((zone_choice-1))]}"
# 自动设置选择的区域为默认区域
echo "正在设置默认地区为 $zone..."
gcloud config set compute/zone "$zone"
region=$(echo "$zone" | cut -d'-' -f1-2)
location=${region_location_map["$region"]}
if [ $? -eq 0 ]; then
if [ -n "$location" ]; then
echo "默认地区已设置为 $zone$location"
else
echo "默认地区已设置为 $zone"
fi
else
if [ -n "$location" ]; then
echo "设置默认地区失败,请检查区域格式或权限,但将继续使用 $zone$location 创建虚拟机。"
else
echo "设置默认地区失败,请检查区域格式或权限,但将继续使用 $zone 创建虚拟机。"
fi
fi
break
else
echo "无效选项,请选择 0-${#zones_list[@]} 之间的数字。"
fi
done
echo "选择的可用区:$zone"
region=$(echo "$zone" | cut -d'-' -f1-2)
location=${region_location_map["$region"]}
if [ -n "$location" ]; then
echo "选择的可用区:$zone$location"
else
echo "选择的可用区:$zone"
fi
break
elif [ "$method_choice" -eq 3 ]; then
echo "请输入新的默认地区(如 us-central1-a"
@ -769,7 +943,13 @@ while true; do
echo "正在设置默认地区为 $new_zone..."
gcloud config set compute/zone "$new_zone"
if [ $? -eq 0 ]; then
echo "默认地区已更新为 $new_zone"
region=$(echo "$new_zone" | cut -d'-' -f1-2)
location=${region_location_map["$region"]}
if [ -n "$location" ]; then
echo "默认地区已更新为 $new_zone$location"
else
echo "默认地区已更新为 $new_zone"
fi
else
echo "设置默认地区失败,请检查区域格式或权限。"
echo "按任意键返回菜单..."
@ -781,7 +961,7 @@ while true; do
fi
done
# 直接提示用户输入创建数量
# 直接提示用户输入创建数量(保持不变)
while true; do
echo "请输入要创建的虚拟机数量(大于 0 的整数):"
read -e -r instance_count
@ -792,7 +972,7 @@ while true; do
break
done
# 批量创建虚拟机
# 批量创建虚拟机(保持不变)
echo "将创建 $instance_count 台虚拟机..."
for ((i=1; i<=instance_count; i++)); do
random_suffix=$(generate_random_suffix)
@ -894,7 +1074,13 @@ while true; do
for inst in "${selected_instances[@]}"; do
instance_name=$(echo "$inst" | cut -d'|' -f1)
instance_zone=$(echo "$inst" | cut -d'|' -f2)
echo "- $instance_name (区域: $instance_zone)"
region=$(echo "$instance_zone" | sed 's/-[a-z]$//')
location=${region_location_map["$region"]}
if [ -n "$location" ]; then
echo "- $instance_name (区域: $instance_zone$location)"
else
echo "- $instance_name (区域: $instance_zone)"
fi
done
echo "确认删除这些虚拟机吗?(输入 'yes' 确认,任意其他输入取消):"
read -e -r confirm
@ -924,12 +1110,370 @@ while true; do
echo "按任意键返回菜单..."
read -e -r -n 1
;;
12)
echo "正在查看当前项目下所有实例的 socks5 配置..."
current_project=$(gcloud config get-value project)
if [ -z "$current_project" ]; then
echo "未找到默认项目,请先切换默认项目(选项 8。"
echo "按任意键返回菜单..."
read -e -r -n 1
continue
fi
echo "当前默认项目:$current_project"
instance_data=$(get_instance_list "$current_project")
if [ $? -ne 0 ]; then
echo "按任意键返回菜单..."
read -e -r -n 1
continue
fi
# 定义区域到地理位置的映射
declare -A region_location_map
region_location_map["africa-south1"]="南非约翰内斯堡"
region_location_map["us-central1"]="美国爱荷华州"
region_location_map["us-east1"]="美国南卡罗来纳州"
region_location_map["us-east4"]="美国弗吉尼亚州北部"
region_location_map["us-east5"]="美国俄亥俄州"
region_location_map["us-east7"]="美国弗吉尼亚州"
region_location_map["us-west1"]="美国俄勒冈州"
region_location_map["us-west2"]="美国加利福尼亚州洛杉矶"
region_location_map["us-west3"]="美国犹他州盐湖城"
region_location_map["us-west4"]="美国内华达州拉斯维加斯"
region_location_map["us-west8"]="美国德克萨斯州达拉斯"
region_location_map["us-south1"]="美国得克萨斯州"
region_location_map["europe-central2"]="波兰华沙"
region_location_map["europe-north1"]="芬兰哈米纳"
region_location_map["europe-north2"]="挪威斯塔万格"
region_location_map["europe-southwest1"]="西班牙马德里"
region_location_map["europe-west1"]="比利时圣吉斯兰"
region_location_map["europe-west2"]="英国伦敦"
region_location_map["europe-west3"]="德国法兰克福"
region_location_map["europe-west4"]="荷兰埃姆斯哈文"
region_location_map["europe-west6"]="瑞士苏黎世"
region_location_map["europe-west8"]="意大利米兰"
region_location_map["europe-west9"]="法国巴黎"
region_location_map["europe-west10"]="德国柏林"
region_location_map["europe-west12"]="意大利都灵"
region_location_map["asia-east1"]="台湾彰化县"
region_location_map["asia-east2"]="中国香港"
region_location_map["asia-northeast1"]="日本东京"
region_location_map["asia-northeast2"]="日本大阪"
region_location_map["asia-northeast3"]="韩国首尔"
region_location_map["asia-south1"]="印度孟买"
region_location_map["asia-south2"]="印度德里"
region_location_map["asia-southeast1"]="新加坡"
region_location_map["asia-southeast2"]="亚太地区印度尼西亚雅加达"
region_location_map["australia-southeast1"]="澳大利亚悉尼"
region_location_map["australia-southeast2"]="澳大利亚墨尔本"
region_location_map["southamerica-east1"]="巴西圣保罗"
region_location_map["southamerica-west1"]="智利圣地亚哥"
region_location_map["northamerica-northeast1"]="加拿大蒙特利尔"
region_location_map["northamerica-northeast2"]="加拿大多伦多"
region_location_map["northamerica-south1"]="美国南卡罗来纳州"
region_location_map["me-central1"]="卡塔尔多哈"
region_location_map["me-central2"]="沙特阿拉伯达曼"
region_location_map["me-west1"]="以色列特拉维夫"
# 显示虚拟机列表并获取数组
show_instance_menu "$instance_data"
if [ $? -ne 0 ]; then
echo "按任意键返回菜单..."
read -e -r -n 1
continue
fi
# 遍历每个实例,读取 /opt/socks.txt 文件内容
echo "正在读取每个实例的 /opt/socks.txt 文件内容..."
for inst in "${instance_array[@]}"; do
instance_name=$(echo "$inst" | cut -d'|' -f1)
instance_zone=$(echo "$inst" | cut -d'|' -f2)
echo "----------------------------------------"
region=$(echo "$instance_zone" | sed 's/-[a-z]$//')
location=${region_location_map["$region"]}
if [ -n "$location" ]; then
echo "实例:$instance_name (区域: $instance_zone$location)"
else
echo "实例:$instance_name (区域: $instance_zone)"
fi
# 使用 gcloud compute ssh 远程读取文件内容
socks_content=$(gcloud compute ssh "$instance_name" \
--project="$current_project" \
--zone="$instance_zone" \
--command="cat /opt/socks.txt" \
--quiet 2>/dev/null)
if [ $? -eq 0 ] && [ -n "$socks_content" ]; then
echo "$socks_content"
else
echo "无法读取文件内容,可能是文件不存在、权限不足或 SSH 连接失败。"
fi
echo "----------------------------------------"
done
echo "按任意键返回菜单..."
read -e -r -n 1
;;
13)
echo "正在配置防火墙规则..."
current_project=$(gcloud config get-value project)
if [ -z "$current_project" ]; then
echo "未找到默认项目,请先切换默认项目(选项 8。"
echo "按任意键返回菜单..."
read -e -r -n 1
continue
fi
echo "当前默认项目:$current_project"
# 提示用户输入防火墙规则名称
echo "请输入防火墙规则名称(小写字母、数字或短划线组成,留空取消操作):"
read -e -r rule_name
if [ -z "$rule_name" ]; then
echo "未输入规则名称,操作取消。"
echo "按任意键返回菜单..."
read -e -r -n 1
continue
fi
# 验证规则名称格式(仅允许小写字母、数字和短划线)
if [[ ! "$rule_name" =~ ^[a-z0-9][a-z0-9-]*[a-z0-9]$ ]] || [[ "$rule_name" =~ ^- ]] || [[ "$rule_name" =~ -$ ]]; then
echo "规则名称格式无效,仅允许小写字母、数字和短划线,且不能以短划线开头或结尾。"
echo "按任意键返回菜单..."
read -e -r -n 1
continue
fi
# 检查规则名称是否已存在
echo "正在检查规则名称是否已存在..."
if gcloud compute firewall-rules list --project="$current_project" | grep -q "^$rule_name "; then
echo "规则名称 '$rule_name' 已存在,请使用其他名称。"
echo "按任意键返回菜单..."
read -e -r -n 1
continue
fi
# 提示用户选择协议类型
echo "请选择协议类型:"
echo "1. TCP"
echo "2. UDP"
echo "3. TCP 和 UDP"
echo "0. 取消操作"
read -e -r protocol_choice
case $protocol_choice in
1)
protocol="tcp"
;;
2)
protocol="udp"
;;
3)
protocol="tcp,udp"
;;
0)
echo "操作取消。"
echo "按任意键返回菜单..."
read -e -r -n 1
continue
;;
*)
echo "无效选项,操作取消。"
echo "按任意键返回菜单..."
read -e -r -n 1
continue
;;
esac
# 提示用户输入端口号或范围
echo "请输入端口号(支持单个端口如 '8080',非连续端口如 '8080,8081',连续端口范围如 '8000-9000'"
read -e -r port_input
if [ -z "$port_input" ]; then
echo "未输入端口号,操作取消。"
echo "按任意键返回菜单..."
read -e -r -n 1
continue
fi
# 验证端口输入格式
if [[ ! "$port_input" =~ ^[0-9]+(-[0-9]+)?([,][0-9]+(-[0-9]+)?)*$ ]]; then
echo "端口格式无效仅支持数字、逗号和短划线用于范围。示例8080 或 8000-9000 或 8080,8081,9000-9100"
echo "按任意键返回菜单..."
read -e -r -n 1
continue
fi
# 拆分端口输入,检查每个端口或范围是否合法
IFS=',' read -ra port_entries <<< "$port_input"
for entry in "${port_entries[@]}"; do
if [[ "$entry" =~ ^[0-9]+-[0-9]+$ ]]; then
# 范围端口
IFS='-' read -ra range <<< "$entry"
start_port=${range[0]}
end_port=${range[1]}
if [ "$start_port" -lt 1 ] || [ "$start_port" -gt 65535 ] || [ "$end_port" -lt 1 ] || [ "$end_port" -gt 65535 ] || [ "$start_port" -gt "$end_port" ]; then
echo "端口范围 $entry 无效,端口必须在 1-65535 之间,且起始端口不能大于结束端口。"
echo "按任意键返回菜单..."
read -e -r -n 1
continue 2
fi
elif [[ "$entry" =~ ^[0-9]+$ ]]; then
# 单个端口
if [ "$entry" -lt 1 ] || [ "$entry" -gt 65535 ]; then
echo "端口 $entry 无效,端口必须在 1-65535 之间。"
echo "按任意键返回菜单..."
read -e -r -n 1
continue 2
fi
else
echo "端口格式 $entry 无效。"
echo "按任意键返回菜单..."
read -e -r -n 1
continue 2
fi
done
unset IFS
# 提示用户输入来源 IP 范围(默认为 0.0.0.0/0即所有来源
echo "请输入允许的来源 IP 范围CIDR 格式,如 0.0.0.0/0 表示所有 IP留空使用默认值 0.0.0.0/0"
read -e -r source_ranges
if [ -z "$source_ranges" ]; then
source_ranges="0.0.0.0/0"
fi
# 验证 CIDR 格式(简单检查)
if [[ ! "$source_ranges" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+$ ]]; then
echo "来源 IP 范围格式无效,应为 CIDR 格式(如 0.0.0.0/0 或 192.168.1.0/24。"
echo "按任意键返回菜单..."
read -e -r -n 1
continue
fi
# 确认创建防火墙规则
echo "即将创建以下防火墙规则:"
echo "规则名称:$rule_name"
echo "协议:$protocol"
echo "端口:$port_input"
echo "来源 IP 范围:$source_ranges"
echo "确认创建吗?(输入 'y' 确认,其他取消):"
read -e -r -n 1 confirm
echo ""
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
echo "创建操作已取消。"
echo "按任意键返回菜单..."
read -e -r -n 1
continue
fi
# 格式化 --rules 参数
rules=""
IFS=',' read -ra protocols <<< "$protocol"
IFS=',' read -ra ports <<< "$port_input"
for proto in "${protocols[@]}"; do
for port in "${ports[@]}"; do
if [ -n "$rules" ]; then
rules="$rules,"
fi
rules="$rules$proto:$port"
done
done
unset IFS
# 创建防火墙规则
echo "正在创建防火墙规则 '$rule_name'..."
gcloud compute firewall-rules create "$rule_name" \
--project="$current_project" \
--direction=INGRESS \
--priority=1000 \
--network=default \
--action=ALLOW \
--rules="$rules" \
--source-ranges="$source_ranges"
if [ $? -eq 0 ]; then
echo "防火墙规则 '$rule_name' 创建成功!"
else
echo "创建防火墙规则失败,可能是规则名称已存在或没有权限。"
echo "错误信息如上,请检查。"
fi
echo "按任意键返回菜单..."
read -e -r -n 1
;;
14)
echo "正在查看当前防火墙规则..."
current_project=$(gcloud config get-value project)
if [ -z "$current_project" ]; then
echo "未找到默认项目,请先切换默认项目(选项 8。"
echo "按任意键返回菜单..."
read -e -r -n 1
continue
fi
echo "当前默认项目:$current_project"
echo "列出所有防火墙规则:"
# 使用 gcloud 命令列出防火墙规则
gcloud compute firewall-rules list --project="$current_project" --format="table(name,network,direction,priority,allow,disabled)" 2>/dev/null
if [ $? -eq 0 ]; then
echo "防火墙规则列表显示完毕。"
else
echo "无法获取防火墙规则列表,请检查是否有权限或项目是否正确。"
fi
echo "按任意键返回菜单..."
read -e -r -n 1
;;
15)
echo "正在准备删除防火墙规则..."
current_project=$(gcloud config get-value project)
if [ -z "$current_project" ]; then
echo "未找到默认项目,请先切换默认项目(选项 8。"
echo "按任意键返回菜单..."
read -e -r -n 1
continue
fi
echo "当前默认项目:$current_project"
echo "当前防火墙规则列表:"
# 列出所有防火墙规则供用户参考
gcloud compute firewall-rules list --project="$current_project" --format="table(name,network,direction,priority,allow,disabled)" 2>/dev/null
if [ $? -ne 0 ]; then
echo "无法获取防火墙规则列表,请检查是否有权限或项目是否正确。"
echo "按任意键返回菜单..."
read -e -r -n 1
continue
fi
# 提示用户输入要删除的规则名称
echo "请输入要删除的防火墙规则名称(留空取消操作):"
read -e -r rule_name
if [ -z "$rule_name" ]; then
echo "未输入规则名称,操作取消。"
echo "按任意键返回菜单..."
read -e -r -n 1
continue
fi
# 确认删除操作
echo "确认要删除防火墙规则 '$rule_name' 吗?(输入 'y' 确认,其他取消):"
read -e -r -n 1 confirm
echo ""
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
echo "删除操作已取消。"
echo "按任意键返回菜单..."
read -e -r -n 1
continue
fi
# 执行删除操作
echo "正在删除防火墙规则 '$rule_name'..."
gcloud compute firewall-rules delete "$rule_name" --project="$current_project" --quiet 2>/dev/null
if [ $? -eq 0 ]; then
echo "防火墙规则 '$rule_name' 删除成功。"
else
echo "删除防火墙规则失败,可能是规则不存在或没有权限。"
fi
echo "按任意键返回菜单..."
read -e -r -n 1
;;
0)
echo "退出脚本..."
exit 0
;;
*)
echo "无效选项,请选择 0-11 之间的数字。"
echo "无效选项,请选择 0-12 之间的数字。"
echo "按任意键返回菜单..."
read -e -r -n 1
;;