diff --git a/features/trace/tcpdump.go b/features/trace/tcpdump.go new file mode 100644 index 00000000..8d95a2ed --- /dev/null +++ b/features/trace/tcpdump.go @@ -0,0 +1,104 @@ +package trace + +import ( + "fmt" + "net/http" + "time" + + "ems.agt/lib/core/cmd" + "ems.agt/lib/core/conf" + "ems.agt/lib/core/file" + "ems.agt/lib/core/utils/ctx" + "ems.agt/lib/core/vo/result" + "ems.agt/lib/dborm" + "ems.agt/lib/log" + "ems.agt/restagent/config" +) + +var ( + UriTcpdumpTask = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeTask" + CustomUriTcpdumpTask = config.UriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeTask" // decode message api + + UriTcpdumpPcapDownload = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/tcpdumpPcapDownload" + CustomUriTcpdumpPcapDownload = config.UriPrefix + "/traceManagement/{apiVersion}/tcpdumpPcapDownload" // decode message api +) + +// NeInfo 网元信息 +func NeInfo(neType, neId string) (*dborm.NeInfo, error) { + neInfo, err := dborm.XormGetNeInfo(neType, neId) + if err != nil { + log.Error("dborm.XormGetNeInfo is failed:", err) + return nil, err + } + if neInfo == nil || neInfo.Ip == "" { + return nil, fmt.Errorf("not ne_info or not IP") + } + return neInfo, nil +} + +// TcpdumpNeTask 网元发送执行 pcap +func TcpdumpNeTask(w http.ResponseWriter, r *http.Request) { + var body struct { + NeType string `json:"neType"` // 网元类型 + NeId string `json:"neId"` // 网元ID + Timeout int `json:"timeout"` // 超时时间 + Cmd string `json:"cmd"` // 命令 + } + err := ctx.ShouldBindJSON(r, &body) + if err != nil || body.NeType == "" || body.NeId == "" || body.Timeout < 5 || body.Cmd == "" { + ctx.JSON(w, 400, result.CodeMsg(400, "参数错误")) + return + } + + neInfo, err := NeInfo(body.NeType, body.NeId) + if err != nil { + ctx.JSON(w, 200, result.ErrMsg(err.Error())) + return + } + + filePcapName := fmt.Sprintf("tmp_%s_%s_%d.pcap", body.NeType, body.NeId, time.Now().UnixMilli()) + fileLogName := fmt.Sprintf("tmp_%s_%s_%d.log", body.NeType, body.NeId, time.Now().UnixMilli()) + cmdStr := fmt.Sprintf("cd /tmp \n timeout %d tcpdump -i any %s -s0 -w %s >> %s 2>&1 \n cat %s", body.Timeout, body.Cmd, filePcapName, fileLogName, fileLogName) + usernameNe := conf.Get("ne.user").(string) // 网元统一用户 + sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip) + msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr) + if err != nil { + ctx.JSON(w, 200, result.ErrMsg(err.Error())) + return + } + + ctx.JSON(w, 200, result.OkData(map[string]any{ + "msg": msg, + "fileName": filePcapName, + })) +} + +// TcpdumpPcapDownload 网元抓包pcap文件下载 +func TcpdumpPcapDownload(w http.ResponseWriter, r *http.Request) { + var body struct { + NeType string `json:"neType"` // 网元类型 + NeId string `json:"neId"` // 网元ID + FileName string `json:"fileName"` // 文件名 + } + err := ctx.ShouldBindJSON(r, &body) + if err != nil || body.NeType == "" || body.NeId == "" || body.FileName == "" { + ctx.JSON(w, 400, result.CodeMsg(400, "参数错误")) + return + } + + neInfo, err := NeInfo(body.NeType, body.NeId) + if err != nil { + ctx.JSON(w, 200, result.ErrMsg(err.Error())) + return + } + + nePath := fmt.Sprintf("/tmp/%s", body.FileName) + localPath := fmt.Sprintf("%s/tcpdump/pcap/%s", conf.Get("ne.omcdir"), body.FileName) + err = file.FileSCPNeToLocal(neInfo.Ip, nePath, localPath) + if err != nil { + ctx.JSON(w, 200, result.ErrMsg(err.Error())) + return + } + + ctx.FileAttachment(w, r, localPath, body.FileName) +} diff --git a/lib/routes/routes.go b/lib/routes/routes.go index 19101921..b81905c6 100644 --- a/lib/routes/routes.go +++ b/lib/routes/routes.go @@ -239,6 +239,13 @@ func init() { Register("PUT", trace.CustomUriTraceTask, trace.PutTraceTaskToNF, nil) Register("DELETE", trace.CustomUriTraceTask, trace.DeleteTraceTaskToNF, nil) + // 网元发送执行 pcap抓包 + Register("POST", trace.UriTcpdumpTask, trace.TcpdumpNeTask, nil) + Register("POST", trace.CustomUriTcpdumpTask, trace.TcpdumpNeTask, nil) + // 网元发送执行 抓包下载pcap文件 + Register("POST", trace.UriTcpdumpPcapDownload, trace.TcpdumpPcapDownload, nil) + Register("POST", trace.CustomUriTcpdumpPcapDownload, trace.TcpdumpPcapDownload, nil) + // file management Register("POST", file.UriFile, file.UploadFile, nil) Register("GET", file.UriFile, file.DownloadFile, nil)