feat: 工具配置增强、站点拨测与日志中心多项改进
- 工具配置:新增卸载 API/UI、Go 工具链、流水线构建自动安装依赖 - 修复 ListTools VerifyTool 递归栈溢出导致获取工具配置失败 - Node.js Alpine 安装改用 unofficial-builds musl 预编译包与 index.json 解析 LTS - 站点拨测:详情页路由、告警自动恢复、并发拨测与默认可观测频率 - 日志中心:RBAC、查询构建器、ES/Loki 增强与审计 request/response 展示 - 发布配置:构建节点、流水线远程执行、Deploy RBAC 导航拆分
This commit is contained in:
1 parent
cde7bbe540
commit
7e1c8f583c
84 files changed
+7729
-1507
No files matched your search
@@ -5,13 +5,17 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"ezops/middleware"
|
||||
"ezops/model"
|
||||
"ezops/pkg/logaccess"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
@@ -40,6 +44,7 @@ func (h *LogDSHandler) List(c *gin.Context) {
|
||||
if sources == nil {
|
||||
sources = []model.LogDataSource{}
|
||||
}
|
||||
sources = logaccess.FilterDataSources(h.db, middleware.GetUserID(c), middleware.GetIsAdmin(c), sources)
|
||||
// 按项目惯例返回 {list,total},前端 listDatasources 取 .list // Logan.Li
|
||||
c.JSON(200, model.Response{Code: 200, Data: model.ListResponse{List: sources, Total: int64(len(sources))}})
|
||||
}
|
||||
@@ -268,6 +273,67 @@ func (h *LogDSHandler) ListIndices(c *gin.Context) {
|
||||
c.JSON(200, model.Response{Code: 200, Data: indices})
|
||||
}
|
||||
|
||||
// ListIndicesByID GET /api/v1/log-datasources/:id/indices — 按数据源 ID 拉取索引(查询面板用)// Logan.Li
|
||||
func (h *LogDSHandler) ListIndicesByID(c *gin.Context) {
|
||||
ds, err := loadLogDS(h, parseUintParam(c.Param("id")))
|
||||
if err != nil {
|
||||
c.JSON(404, model.Response{Code: 404, Message: "数据源不存在"})
|
||||
return
|
||||
}
|
||||
if ds.Type != "elasticsearch" {
|
||||
c.JSON(400, model.Response{Code: 400, Message: "仅 Elasticsearch 数据源支持索引列表"})
|
||||
return
|
||||
}
|
||||
filtered := logaccess.FilterDataSources(h.db, middleware.GetUserID(c), middleware.GetIsAdmin(c), []model.LogDataSource{*ds})
|
||||
if len(filtered) == 0 {
|
||||
c.JSON(403, model.Response{Code: 403, Message: "无权访问该数据源"})
|
||||
return
|
||||
}
|
||||
indices, err := fetchESIndices(ds)
|
||||
if err != nil {
|
||||
c.JSON(502, model.Response{Code: 502, Message: err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(200, model.Response{Code: 200, Data: indices})
|
||||
}
|
||||
|
||||
func fetchESIndices(ds *model.LogDataSource) ([]string, error) {
|
||||
client := newLogHTTPClient(ds.SkipTLSVerify, 15*time.Second)
|
||||
target := strings.TrimRight(ds.URL, "/") + "/_cat/indices?format=json&h=index"
|
||||
httpReq, err := http.NewRequest(http.MethodGet, target, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
applyLogDSAuthV2(httpReq, ds)
|
||||
resp, err := client.Do(httpReq)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询索引失败: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
if resp.StatusCode >= 400 {
|
||||
return nil, fmt.Errorf("ES 错误: %s", string(body))
|
||||
}
|
||||
var raw []map[string]interface{}
|
||||
if err := json.Unmarshal(body, &raw); err != nil {
|
||||
return nil, fmt.Errorf("解析索引列表失败")
|
||||
}
|
||||
indices := make([]string, 0, len(raw))
|
||||
for _, entry := range raw {
|
||||
idx, ok := entry["index"].(string)
|
||||
if !ok || idx == "" || strings.HasPrefix(idx, ".") {
|
||||
continue
|
||||
}
|
||||
indices = append(indices, idx)
|
||||
}
|
||||
return indices, nil
|
||||
}
|
||||
|
||||
func parseUintParam(s string) uint {
|
||||
n, _ := strconv.ParseUint(s, 10, 64)
|
||||
return uint(n)
|
||||
}
|
||||
|
||||
func testLogDSConnection(req model.TestLogDSReq) (bool, string) {
|
||||
client := newLogHTTPClient(req.SkipTLSVerify, 10*time.Second)
|
||||
url := strings.TrimRight(req.URL, "/")
|
||||
|
||||
Reference in new issue
Block a user