refactor: 优化 OpenStack Nova 控制节点部署检测脚本的输出逻辑

This commit is contained in:
seahi committed 2026-09-30 15:23:55 +08:00
1 parent c16ab623c6
commit 9b9dbb45f3
1 file changed
+98 -111
+98 -111
View File
@@ -1,52 +1,46 @@
#!/bin/bash #!/bin/bash
# OpenStack 控制节点(CentOS 7.9 / Rocky)Nova 计算服务部署检测 # OpenStack 控制节点(CentOS 7.9 / Rocky)Nova 计算服务部署检测
# 参考 3.2.sh、3.3.sh;按手册章节汇总,异常提示对应章内步骤。
# 用法:以 root 执行 bash 3.4.sh。仅检查,不安装、同步数据库或重启服务。 # 用法:以 root 执行 bash 3.4.sh。仅检查,不安装、同步数据库或重启服务。
# 默认实验密码:数据库 root=123456,管理员 admin=admin。 # 默认实验密码:数据库 root=123456,管理员 admin=admin。
# 可通过 CHECK_DB_ROOT_PASSWORD、CHECK_ADMIN_PASSWORD 覆盖以上密码。 # 可通过 CHECK_DB_ROOT_PASSWORD、CHECK_ADMIN_PASSWORD 覆盖以上密码。
# 退出码:0=全部通过,1=有失败,2=无失败但存在未验证项。 # 退出码:0=本次检查项全部通过,1=有失败。
export LANG=en_US.UTF-8 export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8 export LC_ALL=en_US.UTF-8
set -o pipefail set -o pipefail
# 学生可见输出:每组一行,失败时列出原因;仅统计实际检查结果。
RED='\033[0;31m' RED='\033[0;31m'
GREEN='\033[0;32m' GREEN='\033[0;32m'
YELLOW='\033[0;33m'
CYAN='\033[0;36m' CYAN='\033[0;36m'
NC='\033[0m' NC='\033[0m'
PASS_CNT=0 PASS_CNT=0
FAIL_CNT=0 FAIL_CNT=0
SKIP_CNT=0
SECTION_TITLE='' SECTION_TITLE=''
SECTION_PASS=0 SECTION_PASS=0
SECTION_FAIL=0 SECTION_FAIL=0
SECTION_SKIP=0
SECTION_DETAILS=() SECTION_DETAILS=()
# 正常检查仅计数;每章输出一行汇总,异常才展开具体步骤。
pass() { PASS_CNT=$((PASS_CNT+1)); } pass() { PASS_CNT=$((PASS_CNT+1)); }
detail() { fail() {
FAIL_CNT=$((FAIL_CNT+1))
if [ -n "$SECTION_TITLE" ]; then if [ -n "$SECTION_TITLE" ]; then
SECTION_DETAILS+=("$1") SECTION_DETAILS+=("$1")
else else
printf '%s\n' "$1" printf '%b[✘ 失败] %s%b\n' "$RED" "$1" "$NC"
fi fi
} }
fail() { FAIL_CNT=$((FAIL_CNT+1)); detail " [✘ 失败] $1"; }
skip() { SKIP_CNT=$((SKIP_CNT+1)); detail " [− 跳过] $1"; }
section_summary() { section_summary() {
[ -n "$SECTION_TITLE" ] || return 0 [ -n "$SECTION_TITLE" ] || return 0
local passed=$((PASS_CNT-SECTION_PASS)) failed=$((FAIL_CNT-SECTION_FAIL)) skipped=$((SKIP_CNT-SECTION_SKIP)) local passed=$((PASS_CNT-SECTION_PASS)) failed=$((FAIL_CNT-SECTION_FAIL)) message
# 没有实际检查结果的分组不显示,也不记为通过。
if [ "$failed" -gt 0 ]; then if [ "$failed" -gt 0 ]; then
printf '%b[✘] %s:通过 %s,失败 %s,跳过 %s%b\n' "$RED" "$SECTION_TITLE" "$passed" "$failed" "$skipped" "$NC" printf '%b[✘ 失败] %s:通过 %s,失败 %s%b\n' "$RED" "$SECTION_TITLE" "$passed" "$failed" "$NC"
elif [ "$skipped" -gt 0 ]; then for message in "${SECTION_DETAILS[@]}"; do
printf '%b[−] %s:通过 %s,跳过 %s%b\n' "$YELLOW" "$SECTION_TITLE" "$passed" "$skipped" "$NC" printf '%b · %s%b\n' "$RED" "$message" "$NC"
else done
printf '%b[✔] %s:%s 项通过%b\n' "$GREEN" "$SECTION_TITLE" "$passed" "$NC" elif [ "$passed" -gt 0 ]; then
fi printf '%b[✔ 通过] %s(%s 项)%b\n' "$GREEN" "$SECTION_TITLE" "$passed" "$NC"
if [ "${#SECTION_DETAILS[@]}" -gt 0 ]; then
printf '%s\n' "${SECTION_DETAILS[@]}"
fi fi
} }
info() { info() {
@@ -54,13 +48,24 @@ info() {
SECTION_TITLE=$1 SECTION_TITLE=$1
SECTION_PASS=$PASS_CNT SECTION_PASS=$PASS_CNT
SECTION_FAIL=$FAIL_CNT SECTION_FAIL=$FAIL_CNT
SECTION_SKIP=$SKIP_CNT
SECTION_DETAILS=() SECTION_DETAILS=()
} }
finish() {
section_summary
printf '\n检查完毕:通过 %b%s%b 项,失败 %b%s%b 项。\n' \
"$GREEN" "$PASS_CNT" "$NC" "$RED" "$FAIL_CNT" "$NC"
if [ "$FAIL_CNT" -gt 0 ]; then
printf '%b请按失败提示修正后重试。%b\n' "$RED" "$NC"
exit 1
fi
printf '%b本次检查项全部通过。%b\n' "$GREEN" "$NC"
exit 0
}
printf '%bOpenStack Nova 控制节点自测%b\n' "$CYAN" "$NC"
printf '%bNova 控制节点部署检测%b\n' "$CYAN" "$NC"
if [ "$EUID" -ne 0 ]; then if [ "$EUID" -ne 0 ]; then
fail '[准备工作] 请在控制节点上使用 root 权限执行此脚本。' fail '请在控制节点上使用 root 权限执行此脚本。'
exit 1 exit 1
fi fi
@@ -72,10 +77,12 @@ ADMIN_PASSWORD=${CHECK_ADMIN_PASSWORD-admin}
# 远程查询均设置超时,避免服务不可达时一直等待。 # 远程查询均设置超时,避免服务不可达时一直等待。
for cmd in timeout mysql openstack rpm ip systemctl httpd nova-manage curl; do for cmd in timeout mysql openstack rpm ip systemctl httpd nova-manage curl; do
if ! command -v "$cmd" >/dev/null 2>&1; then if ! command -v "$cmd" >/dev/null 2>&1; then
fail "[准备工作第 3 步 / 第三部分第 1 步] 缺少命令 ${cmd},请检查实验环境及软件包安装;相关检查可能失败或跳过。" fail "缺少命令 ${cmd},请安装对应软件包"
fi fi
done done
[ "$FAIL_CNT" -eq 0 ] || finish
db_root() { db_root() {
MYSQL_PWD="$DB_ROOT_PASSWORD" timeout 15 mysql --connect-timeout=5 \ MYSQL_PWD="$DB_ROOT_PASSWORD" timeout 15 mysql --connect-timeout=5 \
-uroot -N -B -e "$1" 2>/dev/null -uroot -N -B -e "$1" 2>/dev/null
@@ -128,87 +135,82 @@ check_config() {
enabled_apis) actual=$(printf '%s' "$actual" | tr -d '[:space:]');; enabled_apis) actual=$(printf '%s' "$actual" | tr -d '[:space:]');;
esac esac
if [ "$actual" = "$expected" ]; then if [ "$actual" = "$expected" ]; then
pass "[第 2 步] [$section] $key 配置正确" pass "[$section] $key 配置正确"
else else
# 不回显实际值,避免泄露连接串或口令。 # 不回显实际值,避免泄露连接串或口令。
fail "[第 2 步] [$section] $key 缺失或与手册不符,请检查 $CONF" fail "[$section] $key 缺失或与手册不符,请检查 $CONF"
fi fi
} }
info '一、数据库与授权' info '数据库与授权'
ROOT_OK=0 ROOT_OK=0
if db_root 'SELECT 1;' >/dev/null; then if db_root 'SELECT 1;' >/dev/null; then
ROOT_OK=1 ROOT_OK=1
pass '[第 1 步] 数据库 root 可登录' pass '数据库 root 可登录'
else else
fail '[第 1 步] 数据库 root 登录失败,请检查 MariaDB、密码(默认 123456)或 CHECK_DB_ROOT_PASSWORD' fail '数据库 root 登录失败,请检查 MariaDB、密码(默认 123456)或 CHECK_DB_ROOT_PASSWORD'
fi fi
for database in nova_api nova nova_cell0 placement; do for database in nova_api nova nova_cell0 placement; do
if [ "$ROOT_OK" -eq 1 ]; then if [ "$ROOT_OK" -eq 1 ]; then
if [ "$(db_root "SELECT COUNT(*) FROM information_schema.SCHEMATA WHERE SCHEMA_NAME='$database';")" = 1 ]; then if [ "$(db_root "SELECT COUNT(*) FROM information_schema.SCHEMATA WHERE SCHEMA_NAME='$database';")" = 1 ]; then
pass "[第 2 步] $database 数据库已创建" pass "$database 数据库已创建"
else else
fail "[第 2 步] $database 数据库不存在或查询失败" fail "$database 数据库不存在或查询失败"
fi fi
user=nova user=nova
[ "$database" != placement ] || user=placement [ "$database" != placement ] || user=placement
grants=$(db_root "SHOW GRANTS FOR '$user'@'%';") grants=$(db_root "SHOW GRANTS FOR '$user'@'%';")
if printf '%s\n' "$grants" | tr -d '\140' | grep -Fq "GRANT ALL PRIVILEGES ON $database.* TO "; then if printf '%s\n' "$grants" | tr -d '\140' | grep -Fq "GRANT ALL PRIVILEGES ON $database.* TO "; then
pass "[第 3 步] '$user'@'%' 已获得 $database 的所有权限" pass "'$user'@'%' 已获得 $database 的所有权限"
else else
fail "[第 3 步] '$user'@'%' 缺少 $database 的 ALL PRIVILEGES 授权,或授权查询失败" fail "'$user'@'%' 缺少 $database 的 ALL PRIVILEGES 授权,或授权查询失败"
fi fi
else
skip "[第 2、3 步] 无法独立核查 $database 是否创建及 '%' 账号授权;继续测试实际连接"
fi fi
if db_query "$database" 'SELECT 1;' >/dev/null; then if db_query "$database" 'SELECT 1;' >/dev/null; then
pass "[第 3 步] 使用手册服务账号经 controller 的 TCP 连接可访问 $database" pass "使用手册服务账号经 controller 的 TCP 连接可访问 $database"
else else
fail "[第 2、3 步] 无法访问 ${database},请检查建库、账号密码、授权及 controller 解析" fail "无法访问 ${database},请检查建库、账号密码、授权及 controller 解析"
fi fi
done done
info '二、服务凭证与端点' info '服务凭证与端点'
AUTH_OK=0 AUTH_OK=0
if os_cli token issue >/dev/null; then if os_cli token issue >/dev/null; then
AUTH_OK=1 AUTH_OK=1
pass '[第 1 步] 管理员凭证可获取 Token' pass '管理员凭证可获取 Token'
else else
fail '[第 1 步] 管理员认证失败,请检查 Keystone、admin 密码及 admin-openstack.sh;继续检查本地配置' fail '管理员认证失败,请检查 Keystone 服务及 admin 密码'
fi fi
check_identity() { check_identity() {
local user=$1 type=$2 user_step=$3 role_step=$4 service_step=$5 endpoint_step=$6 url=$7 local user=$1 type=$2 url=$3
local user_id service_id service_type roles endpoints interface local user_id service_id service_type roles endpoints interface
if [ "$AUTH_OK" -ne 1 ]; then if [ "$AUTH_OK" -ne 1 ]; then
skip "[第 ${user_step}、${role_step}、${service_step}、${endpoint_step} 步] 管理员无法认证,暂不检查 $user 用户、角色、服务及端点"
return return
fi fi
user_id=$(os_cli user show --domain default "$user" -f value -c id) user_id=$(os_cli user show --domain default "$user" -f value -c id)
if [ -n "$user_id" ]; then if [ -n "$user_id" ]; then
pass "[第 ${user_step} 步] default 域内的 $user 用户已创建" pass "default 域内的 $user 用户已创建"
# 用实际服务密码签发 service 项目的令牌,同时确认账号可用。 # 用实际服务密码签发 service 项目的令牌,同时确认账号可用。
if os_cli --os-username "$user" --os-password "$user" --os-project-name service token issue >/dev/null; then if os_cli --os-username "$user" --os-password "$user" --os-project-name service token issue >/dev/null; then
pass "[第 ${user_step}、${role_step} 步] $user 可使用手册密码在 service 项目完成认证" pass "$user 可使用手册密码在 service 项目完成认证"
else else
fail "[第 ${user_step}、${role_step} 步] $user 认证失败,请检查密码、启用状态及 service 项目角色" fail "$user 认证失败,请检查密码、启用状态及 service 项目角色"
fi fi
if roles=$(os_cli role assignment list --user "$user_id" --project service --role admin -f value) && [ -n "$roles" ]; then if roles=$(os_cli role assignment list --user "$user_id" --project service --role admin -f value) && [ -n "$roles" ]; then
pass "[第 ${role_step} 步] $user 已绑定 service 项目的 admin 角色" pass "$user 已绑定 service 项目的 admin 角色"
else else
fail "[第 ${role_step} 步] $user 未绑定 service 项目的 admin 角色,或查询失败" fail "$user 未绑定 service 项目的 admin 角色,或查询失败"
fi fi
else else
fail "[第 ${user_step} 步] 未找到 default 域的 $user 用户,或查询失败" fail "未找到 default 域的 $user 用户,或查询失败"
skip "[第 ${role_step} 步] 无法确认 $user 用户,暂不检查其项目角色"
fi fi
service_id=$(os_cli service show "$user" -f value -c id) service_id=$(os_cli service show "$user" -f value -c id)
service_type=$(os_cli service show "$user" -f value -c type) service_type=$(os_cli service show "$user" -f value -c type)
if [ -n "$service_id" ] && [ "$service_type" = "$type" ]; then if [ -n "$service_id" ] && [ "$service_type" = "$type" ]; then
pass "[第 ${service_step} 步] $user 服务实体存在,类型为 $type" pass "$user 服务实体存在,类型为 $type"
else else
fail "[第 ${service_step} 步] $user 服务实体不存在、重名或类型不是 $type" fail "$user 服务实体不存在、重名或类型不是 $type"
skip "[第 ${endpoint_step} 步] 服务实体未确认,暂不检查端点"
return return
fi fi
for interface in public internal admin; do for interface in public internal admin; do
@@ -219,22 +221,22 @@ check_identity() {
if (NF == 2 && tolower($1) == "true" && $2 == url) valid++ } if (NF == 2 && tolower($1) == "true" && $2 == url) valid++ }
END { exit !(count == 1 && valid == 1) } END { exit !(count == 1 && valid == 1) }
'; then '; then
pass "[第 ${endpoint_step} 步] $user 的 RegionOne/$interface 端点为 $url" pass "$user 的 RegionOne/$interface 端点为 $url"
else else
fail "[第 ${endpoint_step} 步] $user 的 RegionOne/$interface 端点缺失、重复、未启用或 URL 错误,应为 $url" fail "$user 的 RegionOne/$interface 端点缺失、重复、未启用或 URL 错误,应为 $url"
fi fi
done done
} }
check_identity nova compute 2 3 4 5 http://controller:8774/v2.1 check_identity nova compute http://controller:8774/v2.1
check_identity placement placement 6 7 8 9 http://controller:8778 check_identity placement placement http://controller:8778
info '三、软件包与配置' info '软件包与配置'
for package in openstack-nova-api openstack-nova-conductor openstack-nova-novncproxy \ for package in openstack-nova-api openstack-nova-conductor openstack-nova-novncproxy \
openstack-nova-scheduler openstack-nova-placement-api; do openstack-nova-scheduler openstack-nova-placement-api; do
if rpm -q "$package" >/dev/null 2>&1; then if rpm -q "$package" >/dev/null 2>&1; then
pass "[第 1 步] $package 已安装" pass "$package 已安装"
else else
fail "[第 1 步] $package 未安装" fail "$package 未安装"
fi fi
done done
if [ -r "$CONF" ]; then if [ -r "$CONF" ]; then
@@ -272,20 +274,20 @@ CONFIG
my_ip=$(ini_value DEFAULT my_ip) my_ip=$(ini_value DEFAULT my_ip)
if [ -n "$my_ip" ] && ip -o -4 addr show scope global 2>/dev/null | \ if [ -n "$my_ip" ] && ip -o -4 addr show scope global 2>/dev/null | \
awk '{split($4,a,"/"); print a[1]}' | grep -Fxq "$my_ip"; then awk '{split($4,a,"/"); print a[1]}' | grep -Fxq "$my_ip"; then
pass '[第 2 步] [DEFAULT] my_ip 是本机已配置的 IPv4 地址' pass '[DEFAULT] my_ip 是本机已配置的 IPv4 地址'
else else
fail '[第 2 步] [DEFAULT] my_ip 为空或不是本机 IPv4 地址,应填写自己的控制节点管理 IP' fail '[DEFAULT] my_ip 为空或不是本机 IPv4 地址,应填写自己的控制节点管理 IP'
fi fi
for key in server_listen server_proxyclient_address; do for key in server_listen server_proxyclient_address; do
value=$(ini_value vnc "$key") value=$(ini_value vnc "$key")
if [ -n "$my_ip" ] && { [ "$value" = '$my_ip' ] || [ "$value" = "\${my_ip}" ] || [ "$value" = "$my_ip" ]; }; then if [ -n "$my_ip" ] && { [ "$value" = '$my_ip' ] || [ "$value" = "\${my_ip}" ] || [ "$value" = "$my_ip" ]; }; then
pass "[第 2 步] [vnc] $key 引用 my_ip 或使用相同地址" pass "[vnc] $key 引用 my_ip 或使用相同地址"
else else
fail "[第 2 步] [vnc] $key 应引用 \$my_ip 或填写相同的管理 IP" fail "[vnc] $key 应引用 \$my_ip 或填写相同的管理 IP"
fi fi
done done
else else
fail "[第 2 步] $CONF 不存在或不可读" fail "$CONF 不存在或不可读"
fi fi
# 仅在指定 Directory 块内检查,注释及其他目录的授权不能算作通过。 # 仅在指定 Directory 块内检查,注释及其他目录的授权不能算作通过。
@@ -299,59 +301,57 @@ if [ -r "$APACHE_CONF" ] && awk '
inside && line == "</directory>" { if(req && ord && allow) found=1; inside=0 } inside && line == "</directory>" { if(req && ord && allow) found=1; inside=0 }
END { exit !found } END { exit !found }
' "$APACHE_CONF"; then ' "$APACHE_CONF"; then
pass '[第 3 步] /usr/bin 的 Directory 块包含手册要求的访问授权指令' pass '/usr/bin 的 Directory 块包含手册要求的访问授权指令'
else else
fail "[第 3 步] $APACHE_CONF 缺少手册中的 /usr/bin Directory 授权配置" fail "$APACHE_CONF 缺少手册中的 /usr/bin Directory 授权配置"
fi fi
if timeout 15 httpd -t >/dev/null 2>&1; then if timeout 15 httpd -t >/dev/null 2>&1; then
pass '[第 3、4 步] Apache 配置语法检查通过' pass 'Apache 配置语法检查通过'
else else
fail '[第 3、4 步] Apache 配置语法检查失败,请执行 httpd -t 查看具体错误' fail 'Apache 配置语法检查失败,请执行 httpd -t 查看具体错误'
fi fi
if systemctl is-active --quiet httpd; then if systemctl is-active --quiet httpd 2>/dev/null; then
pass '[第 4 步] httpd 正在运行' pass 'httpd 正在运行'
else else
fail '[第 4 步] httpd 未运行,请检查配置并按手册重启' fail 'httpd 未运行,请检查配置并按手册重启'
fi fi
http_code=$(curl --noproxy '*' -s -o /dev/null -w '%{http_code}' \ http_code=$(curl --noproxy '*' -s -o /dev/null -w '%{http_code}' \
--connect-timeout 5 --max-time 10 http://controller:8778/ 2>/dev/null) --connect-timeout 5 --max-time 10 http://controller:8778/ 2>/dev/null)
case "$http_code" in case "$http_code" in
200) pass '[第 3、4 步] Placement API 根路径返回 HTTP 200';; 200) pass 'Placement API 根路径返回 HTTP 200';;
401) skip '[第 3、4 步] Placement API 返回 HTTP 401,仅确认服务可达,未验证认证后的访问';; 401) : ;; # 认证要求不能证明接口功能正常,此项不计分。
*) fail "[第 3、4 步] Placement API 返回 HTTP ${http_code:-000},请检查授权配置、httpd 日志及 8778 端口";; *) fail "Placement API 返回 HTTP ${http_code:-000},请检查授权配置、httpd 日志及 8778 端口";;
esac esac
info '四、数据库同步与 Cells' info '数据库同步与 Cells'
check_tables() { check_tables() {
local database=$1 step=$2 tables table missing='' local database=$1 tables table missing=''
shift 2 shift
if tables=$(db_query "$database" 'SHOW TABLES;'); then if tables=$(db_query "$database" 'SHOW TABLES;'); then
for table in "$@"; do for table in "$@"; do
if ! printf '%s\n' "$tables" | grep -Fxq "$table"; then missing="$missing $table"; fi if ! printf '%s\n' "$tables" | grep -Fxq "$table"; then missing="$missing $table"; fi
done done
if [ -z "$missing" ]; then if [ -z "$missing" ]; then
pass "[第 ${step}、6 步] $database 已生成关键数据表" pass "$database 已生成关键数据表"
else else
fail "[第 ${step}、6 步] $database 缺少表:${missing},请检查该步骤数据库同步是否成功" fail "$database 缺少表:${missing},请检查数据库同步"
fi fi
else else
skip "[第 ${step}、6 步] 无法连接 ${database},先完成第一部分第 2、3 步,再验证数据表" fail "$database 数据表查询失败,请检查连接和权限"
fi fi
} }
check_tables nova_api 1 cell_mappings instance_mappings check_tables nova_api cell_mappings instance_mappings
check_tables placement 1 resource_providers inventories allocations check_tables placement resource_providers inventories allocations
check_tables nova_cell0 4 instances instance_extra check_tables nova_cell0 instances instance_extra
check_tables nova 4 instances compute_nodes services check_tables nova instances compute_nodes services
# 查询数据库中的实际映射;不执行 map_cell0/create_cell/db sync 等写操作。 # 查询数据库中的实际映射;不执行 map_cell0/create_cell/db sync 等写操作。
if cells=$(db_query nova_api 'SELECT name,uuid,transport_url,database_connection FROM cell_mappings;'); then if cells=$(db_query nova_api 'SELECT name,uuid,transport_url,database_connection FROM cell_mappings;'); then
for cell in cell0 cell1; do for cell in cell0 cell1; do
if [ "$cell" = cell0 ]; then if [ "$cell" = cell0 ]; then
step=2
expected_db=mysql+pymysql://nova:nova@controller/nova_cell0 expected_db=mysql+pymysql://nova:nova@controller/nova_cell0
expected_transport=none:/// expected_transport=none:///
else else
step=3
expected_db=mysql+pymysql://nova:nova@controller/nova expected_db=mysql+pymysql://nova:nova@controller/nova
expected_transport=$(ini_value DEFAULT transport_url) expected_transport=$(ini_value DEFAULT transport_url)
fi fi
@@ -360,31 +360,31 @@ if cells=$(db_query nova_api 'SELECT name,uuid,transport_url,database_connection
(name != "cell0" || $2 == "00000000-0000-0000-0000-000000000000")) valid++ } (name != "cell0" || $2 == "00000000-0000-0000-0000-000000000000")) valid++ }
END { exit !(count == 1 && valid == 1) } END { exit !(count == 1 && valid == 1) }
'; then '; then
pass "[第 ${step}、5 步] $cell 唯一存在,数据库及消息队列映射正确" pass "$cell 唯一存在,数据库及消息队列映射正确"
else else
fail "[第 ${step}、5 步] $cell 缺失、重复或映射错误,请检查 list_cells(不要盲目重复创建 cell1)" fail "$cell 缺失、重复或映射错误,请检查 nova-manage cell_v2 list_cells"
fi fi
done done
else else
skip '[第 2、3、5 步] 无法读取 cell_mappings,请先检查数据库权限及第 1 步的同步结果' fail 'cell_mappings 查询失败,请检查数据库权限和同步结果'
fi fi
if timeout 30 su -s /bin/sh -c 'nova-manage cell_v2 list_cells' nova >/dev/null 2>&1; then if timeout 30 su -s /bin/sh -c 'nova-manage cell_v2 list_cells' nova >/dev/null 2>&1; then
pass '[第 5 步] nova 用户可成功执行 nova-manage cell_v2 list_cells' pass 'nova 用户可成功执行 nova-manage cell_v2 list_cells'
else else
fail '[第 5 步] nova 用户执行 list_cells 失败,请检查 nova.conf、文件权限及数据库连接' fail 'nova 用户执行 list_cells 失败,请检查 nova.conf、文件权限及数据库连接'
fi fi
info '五、服务运行与自启' info '服务运行与自启'
for service in openstack-nova-api openstack-nova-scheduler openstack-nova-conductor openstack-nova-novncproxy; do for service in openstack-nova-api openstack-nova-scheduler openstack-nova-conductor openstack-nova-novncproxy; do
if systemctl is-active --quiet "$service"; then if systemctl is-active --quiet "$service" 2>/dev/null; then
pass "[第 1、3 步] $service 正在运行" pass "$service 正在运行"
else else
fail "[第 1、3 步] $service 未正常运行" fail "$service 未正常运行"
fi fi
if [ "$(systemctl is-enabled "$service" 2>/dev/null)" = enabled ]; then if [ "$(systemctl is-enabled "$service" 2>/dev/null)" = enabled ]; then
pass "[第 2 步] $service 已设置开机自启" pass "$service 已设置开机自启"
else else
fail "[第 2 步] $service 未设置持久的开机自启" fail "$service 未设置持久的开机自启"
fi fi
done done
@@ -393,21 +393,8 @@ if [ "$AUTH_OK" -eq 1 ]; then
if os_cli compute service list >/dev/null; then if os_cli compute service list >/dev/null; then
pass '管理员可查询计算服务列表' pass '管理员可查询计算服务列表'
else else
fail '[第二部分第 5 步、第三部分第 2 步、第五部分第 3 步] 计算服务列表查询失败,请检查 API、端点和认证配置' fail '计算服务列表查询失败,请检查 API、端点和认证配置'
fi fi
else
skip '[第二部分第 1 步] 管理员认证失败,暂不验证 Compute API'
fi fi
section_summary finish
printf '\n合计:通过 %b%s%b,失败 %b%s%b,跳过 %b%s%b\n' \
"$GREEN" "$PASS_CNT" "$NC" "$RED" "$FAIL_CNT" "$NC" "$YELLOW" "$SKIP_CNT" "$NC"
if [ "$FAIL_CNT" -gt 0 ]; then
printf '%b请按异常项的手册编号修正后重试。%b\n' "$RED" "$NC"
exit 1
elif [ "$SKIP_CNT" -gt 0 ]; then
printf '%b存在未验证项,请解决跳过原因后重试。%b\n' "$YELLOW" "$NC"
exit 2
else
exit 0
fi