name: deploy-fault-analyzer description: 部署故障分析及解決助手 — 接收日誌/報錯文本,優先查詢 MySQL 故障知識庫;未命中時檢索 /data/scripts/ 指令碼庫;支援互動式單條更新故障庫並生成 Word 分析報告。 version: 1.2.1 author: Hermes created: 2026-05-09
當用戶提供日誌檔案(.json .log)或包含 error/錯誤/異常/故障/報錯/failed 等關鍵詞的文字內容時,自動分析故障並生成 Word 文件。分析前必須優先查詢 MySQL 故障知識庫 fault_knowledge_base.fault_records,用歷史案例提高定位準確率;所有新問題繼續記錄到 Excel 知識庫中累積沉澱,並可同步到資料庫。
⚠️ 交付規則: Word 報告生成後必須在同一條回覆中附帶故障分析摘要 + 傳送 Word 檔案給使用者,不能只生成到本地而不傳送。
滿足以下任一條件即觸發:
| 觸發方式 | 判定標準 |
|---|---|
| 日誌檔案 | 使用者上傳/拖入 .json、.log 檔案,或指明檔案路徑 |
| 報錯文本 | 使用者訊息中包含 error/錯誤/異常/故障/報錯/failed/failure/exception/失敗 等關鍵詞 |
| 主動請求 | 使用者說"幫我分析這個故障"/"這是什麼錯"/"幫我看下日誌"等 |
排除:使用者只是在陳述中順帶提到"沒有錯誤"/"沒問題"/"成功了"時不觸發。
故障知識庫來自部署排期表第 10 個 sheet「故障庫」,由 /data/work/scripts/sync_fault_knowledge_base.py 同步到 MySQL。
| 項 | 值 |
|---|---|
| 資料庫 | fault_knowledge_base |
| 主表 | fault_records |
| 連線命令 | docker exec resource_pool_mysql mysql -upool_user -ppool_password_2024 fault_knowledge_base |
| Python 指令碼連庫埠 | 宿主機 33307(insert_fault_record.py 預設已配置) |
| Excel 同步指令碼 | /data/work/scripts/sync_fault_knowledge_base.py |
| 單條入庫指令碼 | /data/work/scripts/insert_fault_record.py |
| 指令碼庫檢索 | /data/work/scripts/search_deploy_scripts.py |
| 預設 Excel | /data/work/bom/基礎平臺部署排期表-2026年度.xlsx |
根目錄:/data/scripts/
| 庫目錄 | 說明 | 典型場景 |
|---|---|---|
cephdeployscripts/ |
Ceph 塊儲存部署/擴容指令碼(Fabric + ceph-deploy) | 新建塊儲存叢集、OSD 擴容、cusmartcache、cephfs、pool 建立 |
deploy-perfect-20250821/ |
基座新建部署指令碼 | bootstrap、yum、repo、基座、DNS、ironic |
kubeos-ansible/ |
雙引擎部署指令碼 | OpenStack 元件部署/擴容/新建、nova、neutron |
用途:Ceph 塊儲存新建部署與擴容的標準指令碼庫。執行節點一般為部署機(含
ceph-deploy/fabric),通過 SSH 批次操作 monitor/OSD 節點。故障庫未命中且涉及塊儲存、cinder、osd、pool、擴容時,優先在本庫檢索。
/data/scripts/cephdeployscripts/
├── blockstorage/ # 主入口:新建 + 擴容
│ ├── fabfile.py # 核心編排(Fabric),新建/擴容主流程
│ ├── config.json # 新建叢集配置(monitors/osdnodes/disks)
│ ├── expand.json # 擴容配置(newosdnodes/ebs0001_ip)
│ └── create_cephfs_pool.py # 建立 CephFS pool + MDS(獨立流程)
├── common/
│ └── common.py # 公共邏輯:叢集型別判定、校驗、pool/OSD 檢查
├── config_samples/ # 各場景配置樣例(對照現場 config 用)
│ ├── config_mix.json
│ ├── config_allflash.json
│ ├── config_highperformance.json
│ ├── expand_mix.json
│ └── ...
├── resources/ # 下發到各節點的輔助指令碼/配置
│ ├── check-cusmartcache.sh # cusmartcache LV 標籤與 enable 校驗
│ ├── modprobe-cusmartcache.sh
│ ├── clearcephlvm.sh # 清理 ceph LVM(lv/vg/pv/dm)
│ ├── balancer_osd_pg.sh # PG 分佈與均衡診斷
│ ├── patch-ceph-osd-prestart.sh
│ ├── upgrade_package.sh # openssl/openssh/libblkid 等版本升級
│ └── extended.ceph.conf
└── cephdeploy/ # 子模組(git),與上層 blockstorage 配合
| 項 | 說明 |
|---|---|
| 編排框架 | Python 2 + Fabric(fabric.api),遠端執行 run/sudo |
| Ceph 工具 | ceph-deploy(ceph-deploy osd create、gatherkeys、mon create) |
| 部署目錄 | 各節點 /opt/cephdeploy,指令碼從 resources/ 複製 |
| 新建配置 | blockstorage/config.json |
| 擴容配置 | blockstorage/expand.json(含 newosdnodes、ebs0001_ip) |
| 工作目錄 | 執行前 cd /cephdeployscripts/blockstorage/(程式碼內 WORKDIR) |
fabfile.py 函式命名約定(讀程式碼/日誌時對照):
Capital*:主流程入口(如 DeployMixOsds、AddNewHostsToCluster)local_*:部署節點本地執行monitor_*:monitor 節點osd_*:OSD 節點all_*:全部節點(mon + osd)decide_cluster_type)由 config.json / expand.json 中 disks 的 hdds/ssds 組合自動判定,同一叢集所有節點型別必須一致:
| 型別常量 | 名稱 | 磁碟特徵 | 預設 RBD Pool |
|---|---|---|---|
CLUSTER_TYPE_ALLFLASH (2) |
allflash | 僅 SSD | volumes-ssd |
CLUSTER_TYPE_ALLNVME (5) |
allnvme | 僅 NVMe SSD | volumes-nvme |
CLUSTER_TYPE_HIGHPERFORMANCE (3) |
highperformance | SSD+HDD(無 cusmartcache) | volumes 或 volumes-enhance |
CLUSTER_TYPE_MIX (4) |
mix-cusmartcache | SSD+HDD + cusmartcache | volumes 或 volumes-enhance |
mix 部署模式(mixdeploymode,僅 MIX 叢集):
newcluster:新建 mix 叢集(預設)addcusmartcacheforbcache:為已有 bcache 補 cusmartcacheaddcusmartcacheforhdd:為 HDD 補 cusmartcacheHCUFS 特殊叢集:8×NVMe + 60×HDD(is_hcufs_cluster),佈局 [8,8,8,8,7,7,7,7] HDD/SSD 配對。
python fabfile.py 或 fab -f fabfile.py)Init() → 讀 config.json → 校驗磁碟/IP/掛載
→ all_generateauth / all_sshnopassword / all_systemconfig
→ all_do_misc_check(包版本、tuned、firewalld/SELinux)
→ all_install_ceph_package(mix 時含 cusmartcache)
→ CreateMonMgr() → Deploy*Osds() → RestartAllOsds() → Check*OsdCount()
→ 建立 pool(images + volumes*)+ client.cinder/client.glance + balancer
按叢集型別分支:DeployAllFlashOsds / DeployHighPerformaceOsds / DeployMixOsds。
新建成功判定(CheckNewClusterDeployResult):mon/mgr 程序數 = 配置數;totalosd == uposd == inosd == total_data_disk_num;mix 時 cusmartcache 數量 = OSD 數量。
AddNewHostsToCluster)LoadExpandConfig() → 讀 expand.json
→ check_expand_mon_osd / check_all_disks
→ decide_cluster_type(擴容節點型別)
→ get_expand_type(擴充套件現有 pool 或新建 pool)
→ IsEbs001MixNode()(mix 擴容時檢查 ebs0001 是否 mix 節點)
→ ceph-deploy gatherkeys → 新節點 init(裝包、拷 keyring、清盤)
→ Deploy*Osds() → Check*ExpandResult()
擴容成功判定:totalosd - ORIGINALTOTAL == 新增 OSD 數;失敗常見日誌:some osds is FAILED, please double check your configuration。
expand_type:
expand_current_pool:OSD 加入現有 pool(如 volumes、volumes-ssd、cephfs-data)create_new_pool:需手工建立新 pool(日誌提示 please create new pool)create_cephfs_pool.py)與塊儲存 RBD 新建並行可選步驟,依賴已有 Ceph 叢集 + config.json 中 monitors 與 ceph.conf 一致:
CreateCephfsForCluster()
→ 安裝 ceph-mds → 建立 MDS → 按主機名字首建立 pool → 掛載目錄初始化
主機名字首 → pool 規格對映(node_pool_map):ebs/ebn/hci → cephfs-metadata/cephfs-data;nasssd → *-ssd;nashdden → *-enhance 等。
| 故障現象 / 關鍵詞 | 優先檢索路徑 | 指令碼內關注點 |
|---|---|---|
osd node ip mismatch / 配置 IP 不一致 |
blockstorage/fabfile.py LoadConfig/LoadExpandConfig |
osdnodes 與 disks[].ips 必須完全一致 |
not support nvme partition / ssd partition |
fabfile.py LoadConfig |
SSD 不允許分割槽裝置 |
no enough space for ssd / to many hdds |
fabfile.py osd_deploy_* |
HDD/SSD 容量比、MAXHDDPERSSD=6 |
some osds is FAILED / OSD 數量不對 |
common/common.py CheckNewClusterDeployResult |
ceph -s、pgrep ceph-osd、cusmartcache 數量 |
cusmartcache num mismatch |
common/common.py + resources/check-cusmartcache.sh |
/proc/cusmartcache/、cusc_cli、lv_tags |
cusmartcache kernel module not loaded |
resources/modprobe-cusmartcache.sh |
cusmartcache.ko、depmod、insmod |
there are N objects in cluster 無法新建 |
common/common.py CheckClusterObjectNum |
叢集已有資料,需清 pool 再部署 |
invalid expand pool |
common/common.py check_expand_pool |
擴容 pool 名與節點型別不匹配 |
ebs0001 is not mix node |
common/common.py IsEbs001MixNode |
expand.json 中 ebs0001_ip/ebs0001_password |
host deploy type error |
common/common.py decide_cluster_type |
各節點磁碟型別不一致 |
package.*version / openssl openssh |
common/common.py all_do_misc_check |
resources/upgrade_package.sh |
| LVM 啟用失敗 / 重啟後 OSD down | common/common.py osds_config_rc_local |
ceph-volume lvm activate --all |
| PG 不均衡 / incomplete pgs | resources/balancer_osd_pg.sh |
ceph pg dump、primary PG 分佈 |
| 清盤重灌 / LVM 殘留 | resources/clearcephlvm.sh |
lvremove/vgremove/pvremove |
| cephfs pool / mds 建立失敗 | blockstorage/create_cephfs_pool.py |
monitors 與 ceph.conf 一致性、主機名字首 |
ceph-deploy osd create 失敗 |
fabfile.py osd_deploy_* |
wipefs、sgdisk、block-db/block-wal/data 路徑 |
| mix 擴容降級 highperformance | fabfile.py LoadExpandConfig |
ebs0001 無 cusmartcache 時自動降級 |
# 1. 按現象檢索(module 填 塊儲存)
python3 /data/work/scripts/search_deploy_scripts.py \
--query "osd FAILED cusmartcache ceph-deploy" \
--module "塊儲存" \
--path-contains "cephdeployscripts/blockstorage" \
--path-contains "cephdeployscripts/common" \
--top 8 --json
# 2. 配置/校驗類
python3 /data/work/scripts/search_deploy_scripts.py \
--query "osd node ip mismatch expand.json config.json" \
--module "塊儲存" \
--path-contains "cephdeployscripts" \
--top 5 --json
# 3. cusmartcache 專項
python3 /data/work/scripts/search_deploy_scripts.py \
--query "cusmartcache cusc_cli lv_tags proc/cusmartcache" \
--module "塊儲存" \
--path-contains "cephdeployscripts/resources" \
--top 5 --json
命中後須閱讀對應指令碼中的校驗分支與 exit 條件(見 Step 2.6C),再給出可執行的排查/修復步驟。
當用戶說“同步故障庫”“把 Excel 故障庫入庫”等含義時,執行以下流程:
# 1. 先檢查 Excel 可解析和有效行數
python3 /data/work/scripts/sync_fault_knowledge_base.py --dry-run
# 2. 正式同步,重複執行不會重複插入同一條故障
python3 /data/work/scripts/sync_fault_knowledge_base.py
# 3. 驗證行數和去重
docker exec resource_pool_mysql mysql -upool_user -ppool_password_2024 fault_knowledge_base \
-e "SELECT COUNT(*) AS total, COUNT(DISTINCT content_hash) AS unique_hashes FROM fault_records;"
如資料庫未初始化,先執行:
docker exec -i resource_pool_mysql mysql -uroot -proot_password_2024 \
< /data/work/sql/create_fault_knowledge_base.sql
| 欄位 | 含義 | 查詢用途 |
|---|---|---|
module_name |
模組 | 第一層收窄範圍,優先從報錯中的產品/元件/任務名推斷 |
issue_type |
問題型別 | 第二層收窄範圍,優先從故障現象推斷 |
issue_description |
問題描述 | 核心相似度匹配欄位 |
solution_summary |
解決方法概要 | 給出歷史解決路徑 |
product_version |
交付產品集版本 | 版本相關問題過濾 |
delivery_branch |
交付分支 | 架構/OS/分支差異過濾 |
resource_pool |
資源池 | 判斷是否為特定現場案例 |
以 id:1110 為標杆:
issue_description:保留完整報錯原文(命令輸出、stderr、Traceback、exit code),≥50 字,禁止僅寫「部署失敗」等空泛描述solution_summary:明確可操作修復動作(如「部署表字段 X:TRUE 改 FALSE」),≥10 字,禁止「待排查」「聯絡研發」delivery_mode(交付形態):必填,填寫現場交付型別,例如:私有云 / 行業雲 / 內部上雲resource_pool(資源池):必填,填寫具體資源池名稱,例如:北京九區 / 巴西CT雲 / 呼和國產化product_version(交付產品集版本):必填,填寫版本號,例如:7.6.0 / 7.7.0 / 7.5.0delivery_branch(交付分支):必填,填寫架構與 OS 組合,例如:@X86@CUlinux / @ARM@CUlinux / @X86@CentOS;多分支用逗號分隔,如 @X86@CUlinux,@ARM@CUlinuxdeployer(部署人):必填,填寫實際部署負責人姓名,例如:田慶霖 / 姜金科任何輸入在處理前必須先存檔,防止後續分析覆蓋原始資料:
from pathlib import Path
from datetime import datetime
import shutil
RAW_DIR = Path.home() / '.hermes/skills/openclaw-imports/deploy-fault-analyzer/data/raw'
RAW_DIR.mkdir(parents=True, exist_ok=True)
# 檔案輸入 → 複製到 raw/
ts = datetime.now().strftime('%Y-%m-%d_%H%M%S')
raw_path = RAW_DIR / f'{ts}_{Path(src_file).name}'
shutil.copy2(src_file, raw_path)
# 文本輸入 → 寫入 raw/
raw_path = RAW_DIR / f'{ts}_user_input.txt'
raw_path.write_text(user_text, encoding='utf-8')
按檔案格式選擇解析策略:
1A. 結構化 JSON 日誌(特徵:頂層有 logs 陣列,每項有 type/message 欄位)
import json
with open(filepath) as f:
data = json.load(f)
logs = data['logs'] # 日誌陣列
# 提取欄位:
# log['type'] → 'error'|'warning'|'info'|'success'
# log['message'] → 日誌內容(含時間戳 `[HH:MM:SS]`)
# log['timestamp']→ ISO 時間(JSON欄位,可能缺失)
# log['task_id'] → 任務ID(如 PREP_UPLOAD_33B3DC)
errors = [l for l in logs if l['type'] == 'error']
warnings = [l for l in logs if l['type'] == 'warning']
infos = [l for l in logs if l['type'] == 'info']
1B. 純文本 .log 檔案
# 逐行讀取,按關鍵詞提取 ERROR/WARN/CRITICAL/FAIL 行
# 使用正則: ^\d{4}-\d{2}-\d{2}.*(ERROR|WARN|CRITICAL|FAIL)
1C. 使用者貼上文本 → 直接作為分析輸入
使用關鍵詞正則匹配,按優先順序從高到低匹配:
| 優先順序 | 匹配模式(關鍵詞) | 類別 |
|---|---|---|
| 1 | 日期格式不正確 日期格式錯誤 格式yyyy-mm-dd |
資料異常 — 日期格式 |
| 2 | 資源池名稱不正確 名稱不一致 sheet.*≠ |
配置錯誤 — 資源池名 |
| 3 | 未填寫 必填項.*未 必填.*缺失 |
配置錯誤 — 必填欄位 |
| 4 | 缺失 不存在 not found No such file |
資源不足 — 檔案/目錄 |
| 5 | 格式不正確.*IP IP地址格式 格式不合法 |
配置錯誤 — IP格式 |
| 6 | already installed is already 衝突 conflict |
服務異常 — 安裝衝突 |
| 7 | 已終止 使用者.*終止 使用者.*取消 |
使用者操作 — 部署終止 |
| 8 | Verifying verification 校驗失敗 驗證失敗 |
服務異常 — 驗證超時 |
| 9 | 連線.*拒絕 Connection refused timeout unreachable |
網路/連線故障 |
| 10 | host.*not found DNS.*fail 解析失敗 |
網路/連線故障 |
| 11 | bms.*pri hostname.*invalid |
配置錯誤 — 主機名 |
| 12 | Permission denied 許可權不足 訪問被拒 |
許可權問題 |
| 13 | OOM out of memory 磁碟空間不足 No space |
資源不足 — 系統資源 |
| 14 | ModuleNotFoundError ImportError 依賴.*缺失 |
依賴缺失 |
實現:
def categorize_error_message(msg: str) -> str:
"""根據中文關鍵詞自動歸類錯誤"""
patterns = [
(r'日期格式不正確|日期格式錯誤|格式yyyy-mm-dd', '資料異常'),
(r'資源池名稱不正確|名稱不一致', '配置錯誤'),
(r'未填寫|必填項.*未填|必填.*缺失', '配置錯誤'),
(r'缺失|不存在|not found|No such file|no such file', '資源不足'),
(r'格式不正確.*IP|IP地址格式|格式不合法', '配置錯誤'),
(r'already installed|is already|衝突|conflict', '服務異常'),
(r'已終止|使用者.*終止|使用者.*取消', '使用者操作'),
(r'Connection refused|timeout|unreachable|連線.*拒絕', '網路/連線故障'),
(r'Permission denied|許可權不足|訪問被拒', '許可權問題'),
(r'OOM|out of memory|磁碟空間不足|No space', '資源不足'),
(r'ModuleNotFoundError|ImportError|依賴.*缺失', '依賴缺失'),
]
for pattern, category in patterns:
if re.search(pattern, msg):
return category
return '待分類'
真實日誌中同根因錯誤通常大量重複。必須先去重再分析:
已終止/使用者終止)→ 不計入故障,僅在報告中標註message 中 ERROR 關鍵字後的核心文本去重fault_data 字典def deduplicate_errors(errors: list) -> list:
"""歸併重複錯誤 → 根因列表"""
# 1. 分離使用者操作
real_faults = [e for e in errors if '使用者已終止' not in e['message'] and '使用者終止' not in e['message']]
# 2. 按訊息核心去重
seen = {}
for e in real_faults:
msg = e['message']
# 提取核心:ERROR 後的文本或訊息中獨特部分
core = re.sub(r'\[.*?\]', '', msg).strip()[:100]
cat = categorize_error_message(core)
key = f"{cat}:{core[:50]}"
if key not in seen:
seen[key] = {'count': 1, 'sample': e, 'category': cat, 'task_ids': {e.get('task_id','?')}}
else:
seen[key]['count'] += 1
seen[key]['task_ids'].add(e.get('task_id', '?'))
return list(seen.values())
在進入根因分析前,必須先用去重後的核心錯誤到 fault_knowledge_base.fault_records 查詢歷史案例。查詢目標是找到相同或相近的 module_name、issue_type、issue_description,並把命中的 solution_summary 作為解決方案候選,而不是直接憑經驗生成結論。
module_name優先從日誌裡的產品名、任務名、服務名、報錯路徑、部署階段推斷模組;無法確定時再不帶模組查詢。
高頻 module_name 候選(按歷史庫頻次和故障定位價值排序):
| 候選模組 | 常見關鍵詞 |
|---|---|
基座 |
bootstrap、基礎包、yum、repo、平臺基礎服務、部署指令碼公共步驟 |
主機交付問題 |
主機、host、IPMI、root密碼、作業系統、lldp、網路不通 |
環境檢查 |
precheck、前置檢查、埠檢查、連通性檢查、環境檢查 |
塊儲存 |
cinder、ceph、塊儲存、volume、儲存池、磁碟 |
VPP |
vpp、dpdk、轉發、網絡卡繫結、HugePage |
監控 |
telegraf、prometheus、grafana、監控節點、採集 |
SDN |
sdn、neutron、網路控制、雲內sdn、雲間sdn |
門戶 |
portal、控制台、門戶匯入表、規格族 |
物件儲存 |
obs、s3、物件儲存、bucket |
CSK / 容器 / 雲原生 |
csk、k8s、kube、容器、master、worker |
Trove |
mysql、redis、trove、資料庫服務 |
虛擬化 / 裸金屬 |
nova、ecs、bms、ironic、裸金屬 |
DNS |
dns、域名、解析失敗 |
ECR |
ecr、映象倉庫、registry |
網路交付問題 |
交換機、路由、vlan、外部網路、防火牆 |
issue_typeissue_type 用於第二層收窄。優先候選:
| 候選型別 | 常見關鍵詞 |
|---|---|
指令碼問題 |
script、指令碼、執行失敗、返回碼、命令失敗、already installed |
環境問題 |
網路不通、埠不通、系統版本、依賴環境、服務狀態 |
新建部署問題 |
新建、首次部署、安裝、部署失敗 |
新建驗收問題 |
驗收、驗證、verification、檢查失敗 |
部署包問題 |
包缺失、rpm、tar、映象、目錄不存在、版本包 |
部署表問題 |
Excel、部署表、必填、格式、資源池名稱、規格族 |
網路交付問題 |
DNS、路由、交換機、連通性、防火牆、VLAN |
主機交付問題 |
主機名、IPMI、作業系統、root密碼、lldp、網絡卡 |
部署文件問題 |
文件、步驟、章節、說明不一致 |
操作問題 |
人工操作、輸入錯誤、誤操作、順序錯誤 |
擴容問題 / 擴容驗收問題 |
擴容、增加節點、擴容後驗收 |
最佳化建議 / 其他問題 |
無明確故障但存在改進項 |
按“強約束 → 放寬”的順序查詢,避免一開始全庫模糊搜尋導致誤命中:
module_name + issue_type + issue_description 關鍵詞查詢module_name + issue_description 查詢issue_type + issue_description 查詢issue_description 全文/LIKE 查詢推薦命令模板:
docker exec resource_pool_mysql mysql -upool_user -ppool_password_2024 fault_knowledge_base -e "
SELECT
id, module_name, issue_type, found_at, product_version, delivery_branch,
LEFT(issue_description, 220) AS issue_preview,
LEFT(solution_summary, 220) AS solution_preview
FROM fault_records
WHERE module_name = '基座'
AND issue_type = '指令碼問題'
AND (
issue_description LIKE '%bootstrap%'
OR solution_summary LIKE '%bootstrap%'
OR MATCH(issue_description, solution_summary, remark) AGAINST('bootstrap 指令碼 失敗' IN NATURAL LANGUAGE MODE)
)
ORDER BY
(module_name = '基座') DESC,
(issue_type = '指令碼問題') DESC,
updated_at DESC
LIMIT 5;"
如果無法穩定判斷模組,使用關鍵詞全庫檢索:
docker exec resource_pool_mysql mysql -upool_user -ppool_password_2024 fault_knowledge_base -e "
SELECT id, module_name, issue_type,
LEFT(issue_description, 200) AS issue_preview,
LEFT(solution_summary, 200) AS solution_preview
FROM fault_records
WHERE issue_description LIKE '%關鍵報錯%'
OR solution_summary LIKE '%關鍵報錯%'
OR remark LIKE '%關鍵報錯%'
LIMIT 10;"
module_name、issue_type、核心報錯關鍵詞均匹配,解決方案可作為首選,但仍要結合當前日誌證據驗證。若 Step 2.5 無高置信命中(模組、問題型別、核心報錯關鍵詞均未對齊),必須先進入 Step 2.6 指令碼庫檢索,不得直接憑經驗給出最終結論。
告知使用者:「歷史故障庫未找到高置信匹配,開始分析指令碼庫 /data/scripts/」,然後執行:
指令碼庫根目錄:/data/scripts/,當前已知指令碼庫與推薦索引範圍如下(優先在推薦範圍內命中):
| 指令碼庫 | 推薦索引範圍(優先順序從高到低) | 適用模組/場景(示例關鍵詞) |
|---|---|---|
deploy-perfect-20250821/ |
second_deploy/dns/、second_deploy/ironic/、second_deploy/trove/、second_deploy/dcs/、second_deploy/ecml/、second_deploy/dims/、second_deploy/cloud_sdn/、sdn/、yum_repo/、perfect_deploy.sh、create_conf.py、globals.yml |
基座新建/二次部署、DNS/ironic/trove、yum/repo、部署表生成(dns、ironic、trove、bootstrap、yum、repo、portal、多套內部浮動網) |
kubeos-ansible/ |
ansible/site.yml、ansible/pre_deploy.yml、ansible/*extend*.yml、ansible/roles/**/tasks/、ansible/roles/**/templates/、tools/ |
雙引擎 OpenStack/元件部署擴容(ansible、nova、neutron、rabbitmq、prometheus、worker_extend、precheck) |
cephdeployscripts/ |
blockstorage/fabfile.py、blockstorage/create_cephfs_pool.py、common/common.py、resources/*.sh、config_samples/ |
塊儲存新建/擴容(ceph-deploy、osd、cusmartcache、pool、cephfs、expand.json、config.json) |
檢索檔案型別:.sh .py .yml .yaml .ini .conf .cfg .j2 .md
排除範圍:.git、node_modules、.idea、__pycache__ 等非業務內容。
為保證指令碼檢索精準度,--query 不能只用“部署失敗/執行失敗”這類泛詞,必須從輸入中抽取:
No valid service subnet、KeyError、Connection refused、TarballDownloadException、iptables -t raw 等neutron、ceph-deploy、cusc_cli、ceph-volume、fabfile、expand.json、wipefs、sgdiskceph-provisioners-0.1.0.tgz、/data/monitor-deploy/、/opt/ECR/推薦:把 issue_description 中的 2~6 個關鍵詞拼成 query(中英文混合可用)。
python3 /data/work/scripts/search_deploy_scripts.py \
--query "核心報錯關鍵詞" \
--module "推斷的模組名" \
--top 5 --json
指令碼檢索的目的不是“給出一堆路徑”,而是讓故障問題根據指令碼內容得到驗證或定位。對每個 Top 候選指令碼,至少完成以下動作之一:
neutron floatingip-create、armada apply、python2 /usr/bin/db_populate.py)以及 rc/異常處理方式向用戶展示 Top 候選(庫名、指令碼路徑、匹配行摘要),並詢問:
以上指令碼是否命中並解決了此次問題?(是 / 否)
remark 欄位可記錄命中的指令碼路徑,例如:指令碼庫命中: cephdeployscripts/blockstorage/fabfile.py 或 cephdeployscripts/resources/check-cusmartcache.sh
從去重後的錯誤列表,為每個根因提取結構化資訊:
提取方法:
| 提取項 | JSON 日誌提取方法 | 文本日誌提取方法 |
|---|---|---|
| 故障時間 | e['timestamp'](ISO格式)或從 message 中提取 [HH:MM:SS] |
正則 \d{4}-\d{2}-\d{2}.*\d{2}:\d{2}:\d{2} |
| 錯誤型別 | task_id + 異常描述拼接,如 CHECK_DEPLOY_F5B45D: checkTableImpl.DateFormatError |
異常類名或錯誤碼 |
| 錯誤訊息 | e['message'] 前200字元 |
緊跟在 ERROR 後的描述文本 |
| 出現次數 | dedup_count |
行數統計 |
| 堆疊跟蹤 | 從 message 中的 checkTableImpl.py:318 等提取呼叫鏈 |
Traceback 段落前20行 |
| 影響元件 | task_id 字首 + message 中的模組路徑(如 /home/conf/) |
服務名、主機名 |
| 影響範圍 | 從部署流程推斷(阻塞/警告/跳過) | 從錯誤推斷 |
| 關聯配置 | message 中的檔案路徑、引數名 |
配置檔案引用 |
任務ID解析(JSON日誌特有):
# task_id 字首含義:
# PREP_UPLOAD_* → 上傳檢查步驟
# PREP_TASK_* → 前置任務
# CHECK_DEPLOY_* → 部署表檢查
# PREP_DEPLOY_* → 部署準備
def parse_task_id(task_id: str) -> dict:
"""解析 task_id → 任務型別和階段"""
if task_id is None:
return {'phase': '全域性', 'type': '系統'}
parts = task_id.split('_')
if len(parts) >= 2:
return {'phase': parts[0], 'type': parts[1], 'id': parts[-1] if len(parts) > 2 else ''}
return {'phase': task_id, 'type': 'UNKNOWN'}
基於提取的資訊,執行以下分析步驟:
⬜ 資料異常(data corrupt, schema mismatch)
歷史案例對齊:把 Step 2.5 命中的故障庫記錄與當前日誌證據逐項對比,確認模組、問題型別、關鍵詞、版本/分支是否一致
因果關係鏈:從堆疊自底向上追溯,找到最初觸發點
關鍵證據:摘錄日誌中能佐證根因的2-3條關鍵行
優先採用高置信歷史案例中的 solution_summary,再結合當前日誌、環境和標準排查路徑細化;沒有命中時才完全按通用框架生成方案。
| 錯誤類別 | 標準排查路徑 | 典型解決步驟 |
|---|---|---|
| 網路/連線 | telnet/ping/curl 測試連通性 → 防火牆規則 → DNS解析 | 檢查目的埠可達性、放行防火牆規則、修正IP配置 |
| 配置錯誤 | 對比配置模板 → 校驗引數值 | 修正配置檔案、重啟服務、驗證引數生效 |
| 資源不足 | free/df -h/ulimit -n 檢查 → top 定位佔用程序 | 清理磁碟、擴容、調大 ulimit、重啟服務釋放洩漏 |
| 服務異常 | systemctl status → journalctl 查崩潰原因 | 重啟服務、檢查依賴服務狀態、排查 OOM killer |
| 許可權問題 | ls -l / id / 檢查 sudo | 修正檔案許可權(chmod/chown)、新增 sudo 授權 |
| 依賴缺失 | rpm -qa / pip list → 對比版本要求 | 安裝缺失包、版本降級/升級 |
| 資料異常 | 檢查資料完整性 → 對比 schema | 資料修復、遷移、回滾 |
輸出解決方案時遵循的結構:
【解決方案】
1. 排查步驟
- 第一步:xxx
- 第二步:xxx
2. 修復操作
- 操作命令(可複製執行)
3. 驗證方法
- 驗證命令 + 預期結果
4. 回滾方案(如適用)
if len(root_causes) == 1:
mode = 'single' # 單故障 → 標準五段式報告
else:
mode = 'multi' # 多故障 → 總覽 + 逐項分析 + 綜合建議
生成 部署故障分析及解決方案_YYYY-MM-DD_HHmmss.docx,標準五段式結構(同原版)。
當 mode == 'multi' 時,增加總覽頁和綜合建議:
封面
├── 總體概況表
│ ├── 文件編號 / 分析時間 / 部署目標 / 部署計劃
│ ├── 總日誌數 / 總錯誤數 / 歸併根因數
│ └── 最高故障級別
├── 錯誤全景圖(表格)
│ ├── # / 故障 / 類別 / 級別 / 出現次數
├── 逐項詳細分析
│ ├── 故障 1:...(完整五段式)
│ ├── 故障 2:...
│ └── ...
└── 綜合建議與整改清單
└── 按優先順序排列的改進項
重點:每個故障頁有明確的 故障 N / 總N 標註,分隔線分隔。
from scripts.generate_report import generate_fault_report, generate_multi_fault_report, append_to_excel
# 單故障
if len(faults) == 1:
docx_path = generate_fault_report(output_path, faults[0])
# 多故障
else:
docx_path = generate_multi_fault_report(output_path, faults)
# 批次追加 Excel(所有故障都寫一行)
for fault in faults:
append_to_excel(xlsx_path, {...})
文件儲存路徑: ~/.hermes/skills/openclaw-imports/deploy-fault-analyzer/output/
⚠️ 分析完成後必須在同一條回覆中做兩件事:
message 工具傳送檔案給使用者# 傳送 .docx 檔案給使用者(以當前會話的 chat 通道傳送)
# 使用 message 工具: action=send, filePath=docx_path, caption='部署故障分析報告'
傳送規則:
- 回覆訊息中貼摘要表(純文本,不依賴 markdown 表格渲染)
- 同時呼叫 message 工具傳送 Word 檔案
- 傳送後回覆 NO_REPLY 避免重複訊息
摘要模板(回覆訊息中貼出):
🔍 部署故障分析結果
概覽:N條日誌,M條錯誤 → 歸併 K 個根因
| # | 故障 | 類別 | 級別 | 次數 | 定位 |
F1 | xxx | 資料異常 | P1 | 44 | xxx
F2 | ...
🎯 核心結論:xxx
📄 Word 報告已同步傳送,請查收。
適用場景: 1. Step 2.6 中使用者確認指令碼已解決問題,且同意更新故障庫 2. 使用者主動說「錄入這條故障」「更新故障庫」「把這次問題加到故障庫」
注意:本流程僅寫入 MySQL fault_records,不修改 Excel。
根據會話上下文整理 JSON 草稿,欄位規則:
| 欄位 | 必填 | 規則 |
|---|---|---|
module_name |
是 | 複用 Step 2.5A 推斷 |
issue_type |
建議 | 複用 Step 2.5B 推斷 |
issue_description |
是 | 完整報錯原文,參照 id:1110 |
solution_summary |
是 | 明確修復動作,參照 id:1110 |
found_at |
建議 | 預設今天 YYYY-MM-DD |
delivery_mode |
是 | 交付形態,如 私有云 / 行業雲 / 內部上雲 |
resource_pool |
是 | 資源池名稱,如 北京九區 |
product_version |
是 | 交付產品集版本,如 7.6.0 |
delivery_branch |
是 | 交付分支,如 @X86@CUlinux / @ARM@CUlinux / @X86@CentOS |
deployer |
是 | 部署人姓名 |
word_file |
否 | 預設 不涉及 |
remark |
否 | 可寫關聯指令碼路徑 |
草稿 JSON 示例:
{
"module_name": "DNS",
"issue_type": "新建部署問題",
"found_at": "2026-06-08",
"issue_description": "+ neutron floatingip-create ...\nfloatingip 建立失敗,請檢查\n+ exit 1",
"solution_summary": "部署表「內網dns雲主機是否通過外部網路訪問外網」TRUE 改 FALSE",
"delivery_mode": "私有云",
"resource_pool": "巴西CT雲",
"product_version": "7.6.0",
"delivery_branch": "@X86@CUlinux",
"deployer": "田慶霖",
"word_file": "不涉及",
"remark": "指令碼庫命中: deploy-perfect-20250821/second_deploy/dns/dns_deploy/dns.sh"
}
將草稿儲存到 skill 目錄,例如:output/fault_draft_YYYY-MM-DD_HHmmss.json
向用戶展示完整草稿(模板如下),詢問:
📋 故障庫入庫草稿(請確認或補充)
模組:DNS
問題型別:新建部署問題
問題描述:
<完整報錯原文...>
解決方法概要:
部署表「內網dns雲主機是否通過外部網路訪問外網」TRUE 改 FALSE
交付形態:私有云
資源池:巴西CT雲 | 版本:7.6.0 | 分支:@X86@CUlinux | 部署人:田慶霖
請回復:確認同步 / 需要修改:<說明> / 取消
請確認或補充:回覆「確認同步」/「需要修改:…」/「取消」
7w4.net小蔥技能。
使用者確認後執行:
# 1. 校驗(不寫入)
python3 /data/work/scripts/insert_fault_record.py \
--json output/fault_draft_YYYY-MM-DD_HHmmss.json --dry-run
# 2. 正式寫入(追加到最後,id = MAX(id)+1)
python3 /data/work/scripts/insert_fault_record.py \
--json output/fault_draft_YYYY-MM-DD_HHmmss.json \
--port 33307
# 3. 驗證
docker exec resource_pool_mysql mysql -upool_user -ppool_password_2024 fault_knowledge_base \
-e "SELECT id, module_name, issue_type, LEFT(issue_description,80), LEFT(solution_summary,80) FROM fault_records ORDER BY id DESC LIMIT 1;"
校驗失敗時根據指令碼輸出修正草稿,重新展示給使用者確認,不得使用 --force 跳過校驗。
from docx import Document
from docx.shared import Inches, Pt, Cm, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from datetime import datetime
import os
def generate_fault_report(output_path, fault_data):
"""
fault_data = {
'fault_time': '2026-05-09 10:23:45',
'error_type': 'ConnectionError',
'error_message': '...',
'stack_trace': '...',
'affected_component': 'nova-api',
'affected_scope': 'AZ-1 計算節點',
'related_config': '/etc/nova/nova.conf',
'error_category': '網路/連線故障',
'fault_level': 'P1',
'root_cause': '...',
'evidence_lines': ['...', '...'],
'solution_steps': [...],
'verification': '...',
'prevention': '...',
}
"""
doc = Document()
# 標題
title = doc.add_heading('部署故障分析及解決方案', level=0)
title.alignment = WD_ALIGN_PARAGRAPH.CENTER
# 文件資訊表
doc.add_paragraph('')
info_table = doc.add_table(rows=3, cols=2, style='Light Grid Accent 1')
info_data = [
('文件編號', f"DOC-{datetime.now().strftime('%Y%m%d')}-{fault_data.get('fault_level','P2')}"),
('分析時間', datetime.now().strftime('%Y-%m-%d %H:%M:%S')),
('故障級別', fault_data.get('fault_level', 'P2')),
]
for i, (k, v) in enumerate(info_data):
info_table.rows[i].cells[0].text = k
info_table.rows[i].cells[1].text = v
doc.add_paragraph('')
# 一、故障概述
doc.add_heading('一、故障概述', level=1)
doc.add_paragraph(f"故障時間:{fault_data.get('fault_time', '未知')}")
doc.add_paragraph(f"影響元件:{fault_data.get('affected_component', '未知')}")
doc.add_paragraph(f"影響範圍:{fault_data.get('affected_scope', '未知')}")
doc.add_paragraph(f"錯誤型別:{fault_data.get('error_type', '未知')}")
# 二、故障詳情
doc.add_heading('二、故障詳情', level=1)
doc.add_heading('錯誤訊息', level=2)
doc.add_paragraph(fault_data.get('error_message', ''))
if fault_data.get('stack_trace'):
doc.add_heading('堆疊跟蹤', level=2)
p = doc.add_paragraph()
p.style = doc.styles['No Spacing']
for line in fault_data['stack_trace'].split('\n')[:20]:
doc.add_paragraph(line, style='No Spacing')
if fault_data.get('related_config'):
doc.add_paragraph(f"關聯配置:{fault_data['related_config']}")
# 三、根因分析
doc.add_heading('三、根因分析', level=1)
doc.add_paragraph(f"錯誤分類:{fault_data.get('error_category', '未分類')}")
doc.add_paragraph(f"根本原因:{fault_data.get('root_cause', '待進一步分析')}")
if fault_data.get('evidence_lines'):
doc.add_heading('關鍵證據', level=2)
for i, line in enumerate(fault_data['evidence_lines'], 1):
doc.add_paragraph(f"{i}. {line}")
# 四、解決方案
doc.add_heading('四、解決方案', level=1)
for step in fault_data.get('solution_steps', []):
doc.add_paragraph(step, style='List Bullet')
if fault_data.get('verification'):
doc.add_heading('驗證方法', level=2)
doc.add_paragraph(fault_data['verification'])
# 五、預防措施
doc.add_heading('五、預防措施', level=1)
doc.add_paragraph(fault_data.get('prevention', '—'))
doc.save(output_path)
return output_path
如果日誌/文本中找不到明確的錯誤資訊,不要強行編造分析結果。此時: - 輸出一份簡要的"日誌初步篩查報告" Word 文件 - 在文件中標註"待補充資訊" - Excel 中錯誤類別記為"待分類"
流程:
1. Step 2A 自動歸類 → 按關鍵詞將錯誤分入不同類別
2. Step 2B 錯誤去重 → 歸併重複錯誤,統計每個根因出現次數
3. 過濾"使用者操作"類(已終止/使用者終止)→ 不計入故障清單
4. 對每個根因執行 Step 2.5,按 module_name、issue_type、issue_description 查詢 MySQL 故障知識庫
5. 按故障級別(P1→P2→P3)和歷史命中置信度排序輸出
6. Word 文件使用多故障模式 → 生成總覽表 + 逐項分析 + 歷史故障庫匹配
7. Excel 中每個根因佔一行,必要時同步到 MySQL 故障庫
以下是從實際部署日誌中提取的典型錯誤模式,用於指導分類:
模式 1 — 部署表日期格式錯誤(44條 → 1個根因)
[CHECK_DEPLOY_F5B45D] 匯入表:日期格式不正確45677.7661111, 格式yyyy-mm-dd hh:mm:ss
→ 類別:資料異常 | 根因:Excel日期序列號未轉換 | 級別:P1
模式 2 — 資源池名稱不一致(35條 → 1個根因)
[CHECK_DEPLOY_F5B45D] 資源池名稱不正確 sheet11:呼和交付驗證雲池; sheet1:呼和國產化...
→ 類別:配置錯誤 | 根因:多sheet資源池名未統一 | 級別:P1
模式 3 — 部署包目錄缺失(6條 → 1個根因)
[PREP_UPLOAD_33B3DC] /opt/ImageManager: 缺失
→ 類別:資源不足 | 根因:部署包未上傳或不在此次部署範圍 | 級別:P1
模式 4 — RPM 安裝誤報(1條 → 不阻塞)
[PREP_TASK_53658B] rpm -ivh → already installed → exit code ≠ 0
→ 類別:服務異常 | 根因:安裝指令碼未處理"已安裝"狀態 | 級別:P3
以下訊息型別不歸類為故障,僅在報告中備註:
- 使用者已終止部署流程 → 使用者主動操作
- 部署已自動暫停,等待使用者確認 → 流程機制,非故障本身
- 使用者確認繼續 → 流程恢復
所有輸出統一在 skill 目錄下:
~/.hermes/skills/openclaw-imports/deploy-fault-analyzer/
├── SKILL.md
├── output/ # Word 文件輸出
├── data/
│ ├── problems.xlsx # Excel 知識庫
│ └── raw/ # 原始輸入存檔
MySQL 故障知識庫不在 skill 目錄下,固定查詢 fault_knowledge_base.fault_records。
相關指令碼均在 /data/work/scripts/:sync_fault_knowledge_base.py(Excel 批次同步)、insert_fault_record.py(單條入庫)、search_deploy_scripts.py(指令碼庫檢索)。
| 使用者說什麼 | 你做什麼 |
|---|---|
| 上傳 xxxx.log | 讀取 → 提取ERROR行 → 推斷 module_name/issue_type → 查詢 MySQL 故障庫 → 分析 → 生成 docx + 寫入 xlsx → 傳送 docx 給使用者 + 貼摘要 |
| 貼上報錯文本 | 同日志流程,必須先查 fault_knowledge_base.fault_records 再給結論 |
| "幫我看下這個報錯" | 識別附帶文本 → 查 MySQL 歷史案例 → 分析 → 生成 docx + 寫入 xlsx → 傳送 docx 給使用者 + 貼摘要 |
| "查一下之前類似問題" | 優先查詢 fault_knowledge_base.fault_records,按模組、問題型別、問題描述返回歷史案例 |
| "這個錯之前遇到過嗎" | 在 MySQL 故障庫中搜索匹配的 issue_description 和 solution_summary |
| 故障庫未命中 | 告知使用者 → search_deploy_scripts.py 檢索 /data/scripts/ → 詢問是否解決 → 可選進入 Step 8 |
| "同步故障庫" / "把 Excel 故障庫入庫" | sync_fault_knowledge_base.py --dry-run → 確認後正式同步 |
| "更新故障庫" / "錄入這條故障" / "把這次問題加到故障庫" | Step 8:起草 JSON → 使用者確認 → insert_fault_record.py --dry-run → 正式寫入 |
這是一款專業級的部署故障分析助手,能自動解析日誌、匹配歷史故障庫、生成 Word 報告。文件詳細、流程完整、覆蓋面廣是其優勢,對中文使用者友好。但檔案過大、配置依賴多、某些步驟描述不夠具體,實際使用時可能需要較長的學習成本。總體質量中等偏上,適合有特定運維環境支撐的專業使用者使用。