Files
aiops/backend/seed/seed.go
T
attackerandClaude 92a2247390 feat: 新增 Agent CLI — Web 版 AI 运维 Agent(参考 opsxcli 移植)
后端引擎 backend/pkg/agentcli/(纯引擎库,零业务依赖,剥离 CLI/TUI 外壳):
- llm: OpenAI 兼容客户端,复用 model.LLMConfig
- tools: ssh_execute(复用 pkg/remoteexec)+ analyze_output + 风险评估黑名单
- safety: 三级安全模式 + 五级风险 + WebSocket 异步确认
- prompt: 五层 System Prompt
- core: ReAct 16 轮循环 + 自适应检查点 + 循环检测
- evolver: 四层记忆 + 进化循环,data/agentcli/ 文件存储

集成层:
- controller/agent_cli.go: WebSocket 控制器(事件流推流 + 高危确认 + 会话持久化)
- model/agent_cli.go: agent_cli_sessions/messages 表 + AutoMigrate
- 路由 /ws/agent-cli + /api/v1/aiops/agent-cli/sessions
- seed 权限 aiops:agent-cli / aiops:llm-config

前端:
- AgentCLI.tsx: 对话流 + 工具块 + 高危确认 + 四模块 tips 面板
- LLMConfig.tsx: 大模型设置独立页
- api/agentCli.ts + Sidebar/App 菜单路由

文档:
- docs/agent/ 11 篇(opsxcli 同名文档适配改写 + 00-README 映射总览)

其他:
- CLAUDE.md 补充 agent-cli 模块说明
- 修正 .gitignore 根级二进制规则(前导 /,避免误伤 frontend/src/components/aiops/)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-27 09:55:17 +08:00

710 lines
30 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package seed
import (
"strings"
"ezops/model"
"ezops/pkg/toolinstaller"
"go.uber.org/zap"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
// seedData 初始化种子数据(admin用户 + LDAP配置 + 审批模板 + 权限角色)
func SeedData(db *gorm.DB) {
// 1. 创建默认 admin 用户(仅首次)
var userCount int64
db.Model(&model.User{}).Count(&userCount)
if userCount == 0 {
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte("123456"), bcrypt.DefaultCost)
admin := model.User{
Username: "admin",
Password: string(hashedPassword),
Email: "admin@ezops.local",
RealName: "管理员",
Status: 1,
IsAdmin: true,
AuthSource: "local",
}
if err := db.Create(&admin).Error; err != nil {
zap.L().Warn("failed to seed admin user", zap.Error(err))
} else {
zap.L().Info("seeded default admin user (admin/123456)")
}
}
// 2. 创建默认 LDAP 配置
var ldapCount int64
db.Model(&model.LDAPConfig{}).Count(&ldapCount)
if ldapCount == 0 {
port := 389
useLDAPS := false
searchFilter := "(objectClass=inetOrgPerson)"
userMapping := `{"username":"uid","email":"mail","display_name":"cn"}`
ldapCfg := model.LDAPConfig{
LDAPHost: "8.217.205.92",
LDAPPort: &port,
UseLDAPS: &useLDAPS,
AdminDN: "cn=admin,dc=opsx,dc=vip",
AdminPassword: "LQl2GX7EEg2N",
BaseDN: "dc=opsx,dc=vip",
SearchFilter: &searchFilter,
UserMapping: &userMapping,
}
if err := db.Create(&ldapCfg).Error; err != nil {
zap.L().Warn("failed to seed LDAP config", zap.Error(err))
} else {
zap.L().Info("seeded default LDAP config (8.217.205.92:389)")
}
}
// 3. 创建默认审批模板(资源申请)
var tplCount int64
db.Model(&model.ApprovalTemplate{}).Count(&tplCount)
if tplCount == 0 {
templates := []model.ApprovalTemplate{
{
Name: "云服务器申请",
Code: "server_apply",
Description: "申请云服务器资源(ECS/EC2),包含规格、数量、用途等信息",
Type: "server_apply",
Category: "resource",
FormSchema: `{
"fields": [
{"key": "provider", "label": "云厂商", "type": "select", "options": ["阿里云","腾讯云","华为云","AWS"], "required": true},
{"key": "region", "label": "地域", "type": "text", "placeholder": "如 cn-hangzhou", "required": true},
{"key": "spec", "label": "规格", "type": "select", "options": ["2C4G","4C8G","8C16G","16C32G","32C64G"], "required": true},
{"key": "disk", "label": "系统盘(GB)", "type": "number", "default": 40, "required": true},
{"key": "count", "label": "数量(台)", "type": "number", "default": 1, "required": true},
{"key": "duration", "label": "时长", "type": "select", "options": ["1个月","3个月","6个月","1年"], "required": true},
{"key": "purpose", "label": "用途说明", "type": "textarea", "required": true}
]
}`,
FlowConfig: `[{"name":"直接主管","approver_role":"team_lead","step_type":"audit"},{"name":"运维负责人","approver_role":"ops_manager","step_type":"audit"},{"name":"运维执行","approver_role":"ops_manager","step_type":"execute"}]`,
Enabled: true,
},
{
Name: "应用部署申请",
Code: "app_deploy",
Description: "申请新应用部署,包含 Git 地址、端口、Nacos 等配置信息",
Type: "app_deploy",
Category: "app",
FormSchema: `{
"fields": [
{"key": "app_name", "label": "应用名称", "type": "text", "placeholder": "如 user-service", "required": true},
{"key": "git_url", "label": "Git 地址", "type": "text", "placeholder": "如 https://github.com/org/repo.git", "required": true},
{"key": "branch", "label": "分支", "type": "text", "default": "main", "required": true},
{"key": "language", "label": "开发语言", "type": "select", "options": ["Java","Go","Python","Node.js","C++"], "required": true},
{"key": "http_port", "label": "HTTP 端口", "type": "number", "placeholder": "如 8080", "required": false},
{"key": "grpc_port", "label": "gRPC 端口", "type": "number", "placeholder": "如 9090", "required": false},
{"key": "nacos_addr", "label": "Nacos 地址", "type": "text", "placeholder": "如 nacos.opsx.vip:8848", "required": true},
{"key": "nacos_namespace", "label": "Nacos 命名空间", "type": "text", "placeholder": "如 production", "required": false},
{"key": "env", "label": "部署环境", "type": "select", "options": ["dev","staging","prod"], "required": true},
{"key": "replicas", "label": "副本数", "type": "number", "default": 2, "required": true},
{"key": "remark", "label": "备注", "type": "textarea", "required": false}
]
}`,
FlowConfig: `[{"name":"技术负责人","approver_role":"tech_lead","step_type":"audit"},{"name":"运维负责人","approver_role":"ops_manager","step_type":"audit"},{"name":"部署执行","approver_role":"ops_manager","step_type":"execute"}]`,
Enabled: true,
},
{
Name: "权限申请",
Code: "permission_request",
Description: "申请堡垒机、生产VPN、日志查询、数据查询等运维权限",
Type: "permission_request",
Category: "permission",
FormSchema: `{
"fields": [
{"key": "perm_type", "label": "权限类型", "type": "select", "options": ["堡垒机权限","生产VPN权限","日志查询权限","数据库查询权限","服务器SSH权限","K8s集群权限"], "required": true},
{"key": "target", "label": "目标资源", "type": "text", "placeholder": "如 生产环境服务器 10.10.10.x / k8s-prod 集群", "required": true},
{"key": "account", "label": "申请账号", "type": "text", "placeholder": "如 logan.li", "required": true},
{"key": "reason", "label": "申请理由", "type": "textarea", "placeholder": "说明为什么需要该权限", "required": true},
{"key": "duration", "label": "权限时长", "type": "select", "options": ["临时(24小时)","短期(7天)","中期(30天)","长期(90天)","永久"], "required": true},
{"key": "dept", "label": "所属部门", "type": "text", "placeholder": "如 基础架构部", "required": true}
]
}`,
FlowConfig: `[{"name":"直接主管","approver_role":"team_lead","step_type":"audit"},{"name":"安全负责人","approver_role":"security_lead","step_type":"audit"},{"name":"权限开通","approver_role":"ops_manager","step_type":"execute"}]`,
Enabled: true,
},
}
if err := db.Create(&templates).Error; err != nil {
zap.L().Warn("failed to seed approval templates", zap.Error(err))
} else {
zap.L().Info("seeded default approval templates (server_apply + app_deploy + permission_request)")
}
}
// 4. 创建默认权限和角色权限映射
var permCount int64
db.Model(&model.Permission{}).Count(&permCount)
if permCount == 0 {
perms := []model.Permission{
// 资产管理
{Name: "服务器管理", Code: "server:view", Type: "menu", Sort: 1, Status: 1},
{Name: "服务器创建", Code: "server:create", Type: "button", Sort: 2, Status: 1},
{Name: "服务器编辑", Code: "server:update", Type: "button", Sort: 3, Status: 1},
{Name: "服务器删除", Code: "server:delete", Type: "button", Sort: 4, Status: 1},
{Name: "WebShell终端", Code: "server:webshell", Type: "button", Sort: 5, Status: 1},
// 云资源
{Name: "云账号管理", Code: "cloud:account", Type: "menu", Sort: 10, Status: 1},
{Name: "域名管理", Code: "cloud:domain", Type: "menu", Sort: 11, Status: 1},
{Name: "云账单", Code: "cloud:billing", Type: "menu", Sort: 12, Status: 1},
// Kubernetes
{Name: "集群管理", Code: "k8s:cluster", Type: "menu", Sort: 20, Status: 1},
{Name: "节点管理", Code: "k8s:nodes", Type: "menu", Sort: 21, Status: 1},
{Name: "工作负载", Code: "k8s:workloads", Type: "menu", Sort: 22, Status: 1},
{Name: "架构拓扑", Code: "k8s:topology", Type: "menu", Sort: 23, Status: 1},
// 应用发布
{Name: "流水线", Code: "deploy:pipeline", Type: "menu", Sort: 30, Status: 1},
{Name: "应用发布", Code: "deploy:release", Type: "menu", Sort: 31, Status: 1},
// 监控告警
{Name: "告警中心", Code: "monitor:alert", Type: "menu", Sort: 40, Status: 1},
{Name: "告警规则", Code: "monitor:rule", Type: "button", Sort: 41, Status: 1},
{Name: "Agent监控", Code: "agent:monitor", Type: "menu", Sort: 42, Status: 1},
{Name: "Agent告警", Code: "agent:alert", Type: "menu", Sort: 43, Status: 1},
// 自动化运维
{Name: "定时任务", Code: "auto:cron", Type: "menu", Sort: 50, Status: 1},
{Name: "脚本管理", Code: "auto:script", Type: "menu", Sort: 51, Status: 1},
{Name: "Ansible", Code: "auto:ansible", Type: "menu", Sort: 52, Status: 1},
// AIOps
{Name: "智能助手", Code: "aiops:assistant", Type: "menu", Sort: 60, Status: 1},
{Name: "告警分析", Code: "aiops:analysis", Type: "menu", Sort: 61, Status: 1},
{Name: "容量预测", Code: "aiops:forecast", Type: "menu", Sort: 62, Status: 1},
{Name: "Agent CLI", Code: "aiops:agent-cli", Type: "menu", Sort: 63, Status: 1},
{Name: "大模型设置", Code: "aiops:llm-config", Type: "menu", Sort: 64, Status: 1},
// 资源申请
{Name: "资源申请", Code: "approval:apply", Type: "menu", Sort: 70, Status: 1},
{Name: "审批管理", Code: "approval:manage", Type: "button", Sort: 71, Status: 1},
// 系统管理
{Name: "用户管理", Code: "system:user", Type: "menu", Sort: 80, Status: 1},
{Name: "角色权限", Code: "system:role", Type: "menu", Sort: 81, Status: 1},
{Name: "操作审计", Code: "system:audit", Type: "menu", Sort: 82, Status: 1},
{Name: "LDAP配置", Code: "system:ldap", Type: "menu", Sort: 83, Status: 1},
// 仪表盘
{Name: "仪表盘", Code: "dashboard:view", Type: "menu", Sort: 90, Status: 1},
// 安全审计
{Name: "终端审计", Code: "audit:terminal", Type: "menu", Sort: 91, Status: 1},
{Name: "操作审计", Code: "audit:operations", Type: "menu", Sort: 92, Status: 1},
{Name: "登录日志", Code: "audit:login-logs", Type: "menu", Sort: 93, Status: 1},
{Name: "会话阻断", Code: "audit:kill-session", Type: "button", Sort: 94, Status: 1},
}
db.Create(&perms)
zap.L().Info("seeded default permissions")
}
// 5. 创建默认角色(如果不存在)
var roleCount int64
db.Model(&model.Role{}).Count(&roleCount)
if roleCount == 0 {
roles := []model.Role{
{Name: "超级管理员", Code: "super_admin", Description: "系统最高权限,管理所有资源和配置", Status: 1, IsSystem: true},
{Name: "Kubernetes管理员", Code: "k8s_admin", Description: "管理K8s集群、节点、工作负载和存储", Status: 1, IsSystem: true},
{Name: "资源管理员", Code: "resource_admin", Description: "管理服务器、云账号、域名和云资源", Status: 1, IsSystem: true},
{Name: "监控管理员", Code: "monitor_admin", Description: "管理告警、监控指标和采集Agent", Status: 1, IsSystem: true},
{Name: "安全审计员", Code: "security_auditor", Description: "审计终端会话、操作日志和登录记录", Status: 1, IsSystem: true},
{Name: "发布管理员", Code: "release_admin", Description: "管理流水线、应用发布和审批流程", Status: 1, IsSystem: true},
{Name: "只读用户", Code: "viewer", Description: "仅查看仪表盘和资源概览,无操作权限", Status: 1, IsSystem: true},
}
db.Create(&roles)
zap.L().Info("seeded 7 system default roles")
// 为各角色分配权限
var allPerms []model.Permission
db.Find(&allPerms)
for _, role := range roles {
var permIds []uint
switch role.Code {
case "super_admin":
for _, p := range allPerms {
permIds = append(permIds, p.ID)
}
case "k8s_admin":
k8sPrefixes := []string{"k8s:", "server:webshell", "dashboard:view", "deploy:"}
for _, p := range allPerms {
for _, pre := range k8sPrefixes {
if strings.HasPrefix(p.Code, pre) {
permIds = append(permIds, p.ID)
break
}
}
}
case "resource_admin":
resPrefixes := []string{"server:", "cloud:", "dashboard:view", "k8s:topology"}
for _, p := range allPerms {
for _, pre := range resPrefixes {
if strings.HasPrefix(p.Code, pre) {
permIds = append(permIds, p.ID)
break
}
}
}
case "monitor_admin":
monPrefixes := []string{"monitor:", "agent:", "dashboard:view", "server:view"}
for _, p := range allPerms {
for _, pre := range monPrefixes {
if strings.HasPrefix(p.Code, pre) {
permIds = append(permIds, p.ID)
break
}
}
}
case "security_auditor":
auditPrefixes := []string{"audit:", "dashboard:view", "server:view", "system:audit"}
for _, p := range allPerms {
for _, pre := range auditPrefixes {
if strings.HasPrefix(p.Code, pre) {
permIds = append(permIds, p.ID)
break
}
}
}
case "release_admin":
relPrefixes := []string{"deploy:", "approval:", "dashboard:view", "server:view", "k8s:cluster", "k8s:workloads"}
for _, p := range allPerms {
for _, pre := range relPrefixes {
if strings.HasPrefix(p.Code, pre) {
permIds = append(permIds, p.ID)
break
}
}
}
case "viewer":
for _, p := range allPerms {
if p.Code == "dashboard:view" || p.Code == "server:view" || p.Code == "monitor:alert" ||
p.Code == "k8s:cluster" || p.Code == "k8s:topology" || p.Code == "cloud:billing" ||
p.Code == "deploy:pipeline" {
permIds = append(permIds, p.ID)
}
}
}
if len(permIds) > 0 {
permIds = dedupeUint(permIds)
var rolePerms []model.Permission
db.Where("id IN ?", permIds).Find(&rolePerms)
db.Model(&role).Association("Permissions").Append(rolePerms)
}
}
}
// 6. 创建默认 Ansible Playbook 模板(15 个高频运维场景)// Logan.Li
var pbCount int64
db.Model(&model.AnsiblePlaybook{}).Count(&pbCount)
if pbCount == 0 {
playbooks := []model.AnsiblePlaybook{
{Name: "系统信息收集", Description: "收集主机基本信息:OS、内核、CPU、内存、磁盘、网络接口", Category: "maintenance", Tags: `["系统信息","诊断","基础"]`, Content: `---
- name: 系统信息收集
hosts: all
gather_facts: yes
tasks:
- name: 系统基本信息
debug:
msg:
- "主机: {{ ansible_hostname }}"
- "OS: {{ ansible_distribution }} {{ ansible_distribution_version }}"
- "内核: {{ ansible_kernel }} ({{ ansible_architecture }})"
- "CPU: {{ ansible_processor_vcpus }} 核"
- "内存: {{ (ansible_memtotal_mb / 1024) | round(1) }} GB"
- name: 磁盘使用率
shell: df -h / | tail -1 | awk '{print $5}'
register: disk_pct
- name: 系统负载
shell: uptime
register: load
- name: 运行摘要
debug:
msg: "磁盘: {{ disk_pct.stdout }} | 负载: {{ load.stdout.split('load average:')[1].strip() if 'load average:' in load.stdout else 'N/A' }}"`, CreatedBy: "system"},
{Name: "系统安全更新", Description: "安装系统安全补丁(自动识别 apt/yum/dnf)", Category: "security", Tags: `["安全","更新","补丁"]`, Content: `---
- name: 系统安全更新
hosts: all
become: yes
tasks:
- name: 检测包管理器
shell: which apt yum dnf 2>/dev/null | head -1 | xargs basename
register: pkg_mgr
- name: 更新软件包 (APT)
apt: update_cache=yes upgrade=safe
when: pkg_mgr.stdout == "apt"
- name: 更新软件包 (YUM/DNF)
shell: "{{ pkg_mgr.stdout }} update -y --security"
when: pkg_mgr.stdout in ["yum", "dnf"]
- name: 检查重启需求
shell: test -f /var/run/reboot-required && echo "需要重启" || echo "无需重启"
register: reboot
- name: 更新完成
debug: msg="更新完成,{{ reboot.stdout }}"`, CreatedBy: "system"},
{Name: "磁盘空间清理", Description: "清理日志、临时文件、Docker 缓存、包管理器缓存", Category: "maintenance", Tags: `["磁盘","清理","维护"]`, Content: `---
- name: 磁盘空间清理
hosts: all
become: yes
tasks:
- name: 清理前磁盘使用
shell: df -h / | awk 'NR==2{print "使用率:",$5,"可用:",$4}'
register: before
- name: 清理30天前日志
shell: find /var/log -type f \( -name "*.log" -o -name "*.gz" \) -mtime +30 -delete 2>/dev/null; echo "done"
- name: 清理临时文件
shell: find /tmp /var/tmp -type f -mtime +7 -delete 2>/dev/null; echo "done"
- name: 清理 journald (保留3天)
shell: journalctl --vacuum-time=3d 2>/dev/null || true
- name: 清理包管理器缓存
shell: (apt-get clean 2>/dev/null || yum clean all 2>/dev/null || dnf clean all 2>/dev/null); echo "done"
- name: 清理 Docker (如有)
shell: docker system prune -af 2>/dev/null || true
- name: 清理后磁盘使用
shell: df -h / | awk 'NR==2{print "使用率:",$5,"可用:",$4}'
register: after
- name: 清理摘要
debug: msg="清理前 - {{ before.stdout }} | 清理后 - {{ after.stdout }}"`, CreatedBy: "system"},
{Name: "服务状态巡检", Description: "检查关键服务状态,自动启动已停止的服务", Category: "maintenance", Tags: `["服务","巡检","重启"]`, Content: `---
- name: 服务状态巡检
hosts: all
become: yes
vars:
services: [nginx, docker, sshd, cron, rsyslog]
tasks:
- name: 收集服务状态
service_facts:
- name: 检查并启动服务
service:
name: "{{ item }}"
state: started
loop: "{{ services }}"
when: item in ansible_facts.services
- name: 显示服务状态
debug:
msg: "{{ item }}: {{ ansible_facts.services[item].state if item in ansible_facts.services else '未安装' }}"
loop: "{{ services }}"
- name: 检查关键端口
shell: ss -tlnp | awk '{print $4}' | grep -E ':22$|:80$|:443$'
register: ports
- name: 端口监听
debug: msg="监听端口: {{ ports.stdout_lines }}"`, CreatedBy: "system"},
{Name: "用户与SSH管理", Description: "创建运维用户、配置SSH密钥、禁用root密码登录", Category: "security", Tags: `["用户","SSH","安全"]`, Content: `---
- name: 用户与SSH管理
hosts: all
become: yes
vars:
ops_user: devops
ops_ssh_key: ""
tasks:
- name: 创建运维用户
user: name={{ ops_user }} shell=/bin/bash groups=sudo append=yes state=present
- name: 配置SSH密钥
authorized_key: user={{ ops_user }} key="{{ ops_ssh_key }}" state=present
when: ops_ssh_key != ""
- name: sudo免密
copy: content="{{ ops_user }} ALL=(ALL) NOPASSWD:ALL" dest=/etc/sudoers.d/{{ ops_user }} validate="visudo -cf %s"
- name: 禁用root密码登录
lineinfile: path=/etc/ssh/sshd_config regexp="^PermitRootLogin" line="PermitRootLogin prohibit-password"
notify: reload sshd
- name: 可登录用户列表
shell: awk -F: '$$7 !~ /(false|nologin)/ {print $$1}' /etc/passwd
register: users
- name: 用户摘要
debug: msg="可登录用户: {{ users.stdout_lines }}"
handlers:
- name: reload sshd
service: name=sshd state=reloaded`, CreatedBy: "system"},
{Name: "Nginx配置检查", Description: "检查Nginx语法、显示虚拟主机、执行重载", Category: "configuration", Tags: `["Nginx","配置","Web"]`, Content: `---
- name: Nginx配置管理
hosts: all
become: yes
tasks:
- name: Nginx状态
shell: nginx -v 2>&1 || echo "未安装"
register: nginx_ver
- name: 配置语法检查
shell: nginx -t 2>&1
register: nginx_test
when: "'nginx' in nginx_ver.stdout"
- name: 列出站点
shell: ls /etc/nginx/sites-enabled/ 2>/dev/null || ls /etc/nginx/conf.d/ 2>/dev/null
register: sites
- name: 重载Nginx
service: name=nginx state=reloaded
when: nginx_test.stdout is defined and 'successful' in nginx_test.stdout
- name: 检查监听端口
shell: ss -tlnp | grep nginx
register: nginx_ports
- name: 配置摘要
debug:
msg:
- "版本: {{ nginx_ver.stdout }}"
- "站点: {{ sites.stdout_lines }}"
- "端口: {{ nginx_ports.stdout }}"`, CreatedBy: "system"},
{Name: "SSL证书检查", Description: "检查本地证书和HTTPS证书到期时间", Category: "security", Tags: `["SSL","证书","HTTPS"]`, Content: `---
- name: SSL证书到期检查
hosts: all
vars:
domains: []
tasks:
- name: 本地证书检查
shell: |
for f in /etc/nginx/ssl/*.crt /etc/letsencrypt/live/*/fullchain.pem 2>/dev/null; do
[ -f "$$f" ] && echo "$$f: $$(openssl x509 -enddate -noout -in "$$f" | cut -d= -f2)"
done
register: local_certs
- name: 远程HTTPS检查
shell: |
for d in {% for d in target_hosts.split(',') %}{{ d }} {% endfor %}; do
expiry=$$(echo | openssl s_client -servername "$$d" -connect "$$d:443" 2>/dev/null | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
[ -n "$$expiry" ] && echo "$$d: $$expiry"
done
register: remote_certs
when: target_hosts is defined
- name: 证书到期列表
debug:
msg:
- "本地: {{ local_certs.stdout_lines }}"
- "远程: {{ remote_certs.stdout_lines | default([]) }}"`, CreatedBy: "system"},
{Name: "配置文件备份", Description: "备份关键配置到压缩包", Category: "backup", Tags: `["备份","配置"]`, Content: `---
- name: 配置备份
hosts: all
become: yes
vars:
backup_dir: "/tmp/config-backup-{{ ansible_date_time.date }}"
tasks:
- name: 创建备份目录
file: path={{ backup_dir }} state=directory mode=0700
- name: 备份关键配置
archive:
path: "{{ item }}"
dest: "{{ backup_dir }}/{{ item | basename | replace('/', '_') }}.tar.gz"
loop: [/etc/nginx, /etc/ssh/sshd_config, /etc/fstab, /etc/hosts]
ignore_errors: yes
- name: 备份crontab
shell: crontab -l > {{ backup_dir }}/crontab.txt 2>/dev/null || true
- name: 备份汇总
shell: du -sh {{ backup_dir }}
register: size
- name: 备份完成
debug: msg="备份: {{ backup_dir }} ({{ size.stdout.split()[0] }})"`, CreatedBy: "system"},
{Name: "进程健康诊断", Description: "CPU/内存TOP10、僵尸进程、进程总数", Category: "monitoring", Tags: `["进程","性能","诊断"]`, Content: `---
- name: 进程健康诊断
hosts: all
tasks:
- name: CPU TOP10
shell: ps aux --sort=-%cpu | head -11
register: cpu
- name: 内存 TOP10
shell: ps aux --sort=-%mem | head -11
register: mem
- name: 僵尸进程
shell: ps aux | awk '$$8=="Z"' || echo "无僵尸进程"
register: zombies
- name: 进程总数
shell: ps aux | wc -l
register: total
- name: 诊断摘要
debug:
msg:
- "总进程: {{ total.stdout }} | 僵尸: {{ zombies.stdout_lines | length }}"
- "=== CPU TOP10 ==="
- "{{ cpu.stdout }}"
- "=== 内存 TOP10 ==="
- "{{ mem.stdout }}"`, CreatedBy: "system"},
{Name: "Docker环境清理", Description: "清理未使用容器、镜像、构建缓存和网络", Category: "maintenance", Tags: `["Docker","清理","容器"]`, Content: `---
- name: Docker环境清理
hosts: all
become: yes
tasks:
- name: 检查Docker
shell: docker --version 2>/dev/null || echo "NONE"
register: dk
- name: Docker资源概览
shell: |
echo "容器:" && docker ps -a --format "table {{.Names}} {{.Status}}" 2>/dev/null
echo "镜像:" && docker images --format "table {{.Repository}} {{.Size}}" 2>/dev/null
register: status
when: dk.stdout != "NONE"
- name: 清理停止容器
shell: docker container prune -f
when: dk.stdout != "NONE"
- name: 清理未用镜像
shell: docker image prune -a -f
when: dk.stdout != "NONE"
- name: 清理构建缓存
shell: docker builder prune -f
when: dk.stdout != "NONE"
- name: 清理未用网络/卷
shell: docker system prune -f --volumes
when: dk.stdout != "NONE"
- name: 清理完成
debug: msg="Docker清理完成"`, CreatedBy: "system"},
{Name: "防火墙规则管理", Description: "查看/配置防火墙规则(ufw/firewalld/iptables)", Category: "security", Tags: `["防火墙","安全","网络"]`, Content: `---
- name: 防火墙规则管理
hosts: all
become: yes
vars:
open_ports: [22, 80, 443]
tasks:
- name: 防火墙类型
shell: |
ufw status 2>/dev/null | grep -q "active" && echo ufw && exit
firewall-cmd --state 2>/dev/null | grep -q "running" && echo firewalld && exit
echo iptables
register: fw
- name: 当前规则
shell: |
case {{ fw.stdout }} in
ufw) ufw status verbose ;;
firewalld) firewall-cmd --list-all ;;
*) iptables -L -n ;;
esac
register: rules
- name: 开放端口(UFW)
ufw: rule=allow port={{ item }} proto=tcp
loop: "{{ open_ports }}"
when: fw.stdout == "ufw"
- name: 开放端口(firewalld)
firewalld: port={{ item }}/tcp permanent=yes state=enabled immediate=yes
loop: "{{ open_ports }}"
when: fw.stdout == "firewalld"
- name: 防火墙规则
debug: msg="{{ rules.stdout }}"`, CreatedBy: "system"},
{Name: "时间同步检查", Description: "检查NTP/Chrony同步状态和时间一致性", Category: "configuration", Tags: `["时间","NTP","同步"]`, Content: `---
- name: 时间同步检查
hosts: all
become: yes
tasks:
- name: 当前时间
shell: date '+%Y-%m-%d %H:%M:%S %Z'
register: now
- name: 同步服务
shell: |
systemctl is-active chronyd 2>/dev/null && echo "chronyd" ||
systemctl is-active ntpd 2>/dev/null && echo "ntpd" ||
systemctl is-active systemd-timesyncd 2>/dev/null && echo "timesyncd" ||
echo "未配置"
register: svc
- name: 同步状态
shell: |
case {{ svc.stdout }} in
chronyd) chronyc tracking 2>/dev/null | grep -E "Stratum|System time" ;;
ntpd) ntpq -p 2>/dev/null | tail -5 ;;
timesyncd) timedatectl show-timesync 2>/dev/null ;;
*) echo "未同步" ;;
esac
register: sync
- name: 时间摘要
debug:
msg: "时间: {{ now.stdout }} | 服务: {{ svc.stdout }} | {{ sync.stdout }}"`, CreatedBy: "system"},
{Name: "日志轮转配置", Description: "安装logrotate并配置应用日志轮转策略", Category: "configuration", Tags: `["日志","轮转","logrotate"]`, Content: `---
- name: 日志轮转配置
hosts: all
become: yes
vars:
log_path: /var/log/app
keep_days: 30
tasks:
- name: 安装logrotate
package: name=logrotate state=present
- name: 应用日志轮转
copy:
dest: /etc/logrotate.d/app-logs
content: |
{{ log_path }}/*.log {
daily
rotate {{ keep_days }}
missingok
notifempty
compress
delaycompress
sharedscripts
postrotate
systemctl reload app 2>/dev/null || true
endscript
}
- name: 测试配置
shell: logrotate -d /etc/logrotate.conf 2>&1 | head -10
register: test
- name: 配置完成
debug: msg="Logrotate已配置 | {{ test.stdout }}"`, CreatedBy: "system"},
{Name: "内核参数调优", Description: "优化网络/内存/文件句柄等内核参数", Category: "configuration", Tags: `["内核","优化","性能"]`, Content: `---
- name: 内核参数调优
hosts: all
become: yes
tasks:
- name: 网络参数优化
sysctl:
name: "{{ item.name }}"
value: "{{ item.value }}"
state: present
reload: yes
loop:
- { name: net.core.somaxconn, value: '65535' }
- { name: net.ipv4.tcp_tw_reuse, value: '1' }
- { name: net.ipv4.tcp_fin_timeout, value: '30' }
- name: 内存参数
sysctl: name=vm.swappiness value=10 state=present reload=yes
- name: 文件句柄
sysctl: name=fs.file-max value=655350 state=present reload=yes
- name: limits.conf
pam_limits:
domain: '*'
limit_type: "{{ item.t }}"
limit_item: "{{ item.i }}"
value: "{{ item.v }}"
loop:
- { t: soft, i: nofile, v: '65535' }
- { t: hard, i: nofile, v: '65535' }
- name: 调优完成
debug: msg="内核参数已优化"`, CreatedBy: "system"},
{Name: "网络连通性诊断", Description: "DNS解析、Ping延迟、端口检测、路由追踪", Category: "monitoring", Tags: `["网络","诊断","连通性"]`, Content: `---
- name: 网络诊断
hosts: all
vars:
targets: [8.8.8.8, 1.1.1.1]
domains: [baidu.com]
tasks:
- name: DNS解析
shell: |
for d in {% for d in domains %}{{ d }} {% endfor %}; do
echo "$$d: $$(nslookup $$d 2>/dev/null | awk '/^Address/{print $$2}' | tail -1 || echo 'FAIL')"
done
register: dns
- name: Ping延迟
shell: ping -c 2 -W 2 {{ item }} 2>&1 | tail -1
loop: "{{ targets }}"
register: ping
- name: 端口检测
shell: timeout 2 bash -c "echo >/dev/tcp/{{ item }}/53" 2>/dev/null && echo "{{ item }}:53 OK" || echo "{{ item }}:53 FAIL"
loop: "{{ targets }}"
register: port
- name: 诊断结果
debug:
msg:
- "=== DNS ==="
- "{{ dns.stdout_lines }}"
- "=== Ping ==="
- "{{ ping.results | map(attribute='stdout') }}"
- "=== 端口 ==="
- "{{ port.results | map(attribute='stdout') }}"`, CreatedBy: "system"},
}
if err := db.Create(&playbooks).Error; err != nil {
zap.L().Warn("failed to seed playbook templates", zap.Error(err))
} else {
zap.L().Info("seeded 15 Ansible playbook templates (deprecated — replaced by remote exec)")
}
}
// 7. 种子工具配置(kubectl/maven/node/ansible/git/docker)// Logan.Li
ti := toolinstaller.New(db)
ti.SeedTools()
}
// dedupeUint 去重 uint 切片
func dedupeUint(slice []uint) []uint {
seen := make(map[uint]bool)
result := make([]uint, 0, len(slice))
for _, v := range slice {
if !seen[v] {
seen[v] = true
result = append(result, v)
}
}
return result
}