package trace import ( "fmt" "net" "net/http" "strings" "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 UriTcpdumpNeUPFTask = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeUPFTask" CustomUriTcpdumpNeUPFTask = config.UriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeUPFTask" // 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, "parameter error")) 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()) writeLog := fmt.Sprintf(" >> %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件,放置弹出code 127 cmdStr := fmt.Sprintf("cd /tmp \ntimeout %d tcpdump -i any %s -s0 -w %s", body.Timeout, body.Cmd, filePcapName) usernameNe := conf.Get("ne.user").(string) // 网元统一用户 sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip) msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr+writeLog) if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) return } ctx.JSON(w, 200, result.OkData(map[string]any{ "cmd": cmdStr, "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, "parameter error")) 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) } // TcpdumpNeUPFTask 网元UPF发送执行 pcap func TcpdumpNeUPFTask(w http.ResponseWriter, r *http.Request) { var body struct { NeType string `json:"neType"` // 网元类型 NeId string `json:"neId"` // 网元ID Cmd string `json:"cmd"` // 命令 RunType string `json:"runType"` // 执行开始start还是停止stop } err := ctx.ShouldBindJSON(r, &body) if err != nil || body.NeType != "UPF" || body.NeId == "" || body.Cmd == "" { ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) return } neInfo, err := NeInfo(body.NeType, body.NeId) if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) return } // 开始 if body.RunType == "start" { // 创建TCP连接 conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", neInfo.Ip, 5002)) if err != nil { conn.Close() ctx.JSON(w, 200, result.ErrMsg(err.Error())) return } filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId) cmdStr := fmt.Sprintf("pcap dispatch trace on max 100000 file %s", filePcapName) fmt.Fprintln(conn, cmdStr) // 读取内容 time.Sleep(time.Duration(200) * time.Millisecond) buf := make([]byte, 1024*8) n, err := conn.Read(buf) if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) } else { str := string(buf[0:n]) s := strings.Index(str, "pcap dispatch trace:") if s != -1 { e := strings.Index(str, "\r\nupfd1#") str = str[s:e] } else { str = fmt.Sprintf("Executed, please stop before proceeding %d", n) } ctx.JSON(w, 200, result.OkData(map[string]any{ "cmd": cmdStr, "msg": str, "fileName": filePcapName, })) } conn.Close() return } // 停止 if body.RunType == "stop" { // 创建TCP连接 conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", neInfo.Ip, 5002)) if err != nil { conn.Close() ctx.JSON(w, 200, result.ErrMsg(err.Error())) return } filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId) cmdStr := "pcap dispatch trace off" fmt.Fprintln(conn, cmdStr) // 读取内容 time.Sleep(time.Duration(200) * time.Millisecond) buf := make([]byte, 1024*8) n, err := conn.Read(buf) if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) } else { str := string(buf[0:n]) s := strings.Index(str, "pcap dispatch trace:") if s == -1 { s = strings.Index(str, "Write ") } if s != -1 { e := strings.Index(str, "\r\nupfd1#") str = str[s:e] } else { str = "No stoppable found" } ctx.JSON(w, 200, result.OkData(map[string]any{ "cmd": cmdStr, "msg": str, "fileName": filePcapName, })) } conn.Close() return } // 开始 -脚本 if body.RunType == "start2" { fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId) filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId) // 复制文件到网元上 err := file.FileSCPLocalToNe(neInfo.Ip, "C:\\AMP\\Probject\\ems_backend\\restagent\\backup\\upf_pcap", "/tmp") if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) return } writeLog := fmt.Sprintf(" >> %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件,放置弹出code 127 cmdStr := fmt.Sprintf("cd /tmp \nchmod +x upf_pcap\n./upf_pcap '192.168.4.139' 'root' 'Admin123@pl' 'pcap dispatch trace on max 100000 file %s' %s ", fileLogName, writeLog) 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())) } else { ctx.JSON(w, 200, result.OkData(map[string]any{ "cmd": cmdStr, "msg": msg, "fileName": filePcapName, })) } return } // 停止 -脚本 if body.RunType == "stop2" { fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId) filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId) // cmdStr := "cd /tmp \nexpect /tmp/cat.sh " err := file.FileSCPLocalToNe(neInfo.Ip, "C:\\AMP\\Probject\\ems_backend\\restagent\\backup\\upf_pcap", "/tmp") if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) return } writeLog := fmt.Sprintf(" >> %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件,放置弹出code 127 cmdStr := fmt.Sprintf("cd /tmp \nchmod +x upf_pcap\n./upf_pcap '192.168.4.139' 'root' 'Admin123@pl' 'pcap dispatch trace off' %s ", writeLog) 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())) } else { ctx.JSON(w, 200, result.OkData(map[string]any{ "cmd": cmdStr, "msg": msg, "fileName": filePcapName, })) } return } ctx.JSON(w, 200, result.ErrMsg("runType is start or stop")) }