feat: iperf支持v2的版本操作
This commit is contained in:
Binary file not shown.
BIN
src/assets/dependency/iperf/rpm/iperf3-3.6-6.ky10.aarch64.rpm
Normal file
BIN
src/assets/dependency/iperf/rpm/iperf3-3.6-6.ky10.aarch64.rpm
Normal file
Binary file not shown.
@@ -37,15 +37,16 @@ type IPerfController struct {
|
|||||||
func (s *IPerfController) Version(c *gin.Context) {
|
func (s *IPerfController) Version(c *gin.Context) {
|
||||||
language := ctx.AcceptLanguage(c)
|
language := ctx.AcceptLanguage(c)
|
||||||
var query struct {
|
var query struct {
|
||||||
NeType string `form:"neType" binding:"required"` // 网元类型
|
NeType string `form:"neType" binding:"required"` // 网元类型
|
||||||
NeID string `form:"neId" binding:"required"` // 网元ID
|
NeId string `form:"neId" binding:"required"` // 网元ID
|
||||||
|
Version string `form:"version" binding:"required,oneof=V2 V3"` // 版本
|
||||||
}
|
}
|
||||||
if err := c.ShouldBindQuery(&query); err != nil {
|
if err := c.ShouldBindQuery(&query); err != nil {
|
||||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := s.iperfService.Version(query.NeType, query.NeID)
|
output, err := s.iperfService.Version(query.NeType, query.NeId, query.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error())))
|
c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error())))
|
||||||
return
|
return
|
||||||
@@ -60,15 +61,16 @@ func (s *IPerfController) Version(c *gin.Context) {
|
|||||||
func (s *IPerfController) Install(c *gin.Context) {
|
func (s *IPerfController) Install(c *gin.Context) {
|
||||||
language := ctx.AcceptLanguage(c)
|
language := ctx.AcceptLanguage(c)
|
||||||
var body struct {
|
var body struct {
|
||||||
NeType string `json:"neType" binding:"required"` // 网元类型
|
NeType string `json:"neType" binding:"required"` // 网元类型
|
||||||
NeID string `json:"neId" binding:"required"` // 网元ID
|
NeId string `json:"neId" binding:"required"` // 网元ID
|
||||||
|
Version string `form:"version" binding:"required,oneof=V2 V3"` // 版本
|
||||||
}
|
}
|
||||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.iperfService.Install(body.NeType, body.NeID); err != nil {
|
if err := s.iperfService.Install(body.NeType, body.NeId, body.Version); err != nil {
|
||||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error())))
|
c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error())))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,17 +22,39 @@ var NewIPerf = &IPerf{}
|
|||||||
type IPerf struct{}
|
type IPerf struct{}
|
||||||
|
|
||||||
// Version 查询版本信息
|
// Version 查询版本信息
|
||||||
func (s *IPerf) Version(meType, neId string) (string, error) {
|
func (s *IPerf) Version(meType, neId, version string) (string, error) {
|
||||||
// 检查是否安装iperf3
|
if version != "V2" && version != "V3" {
|
||||||
output, err := neService.NewNeInfo.NeRunSSHCmd(meType, neId, "iperf3 --version")
|
return "", fmt.Errorf("iperf version is required V2 or V3")
|
||||||
|
}
|
||||||
|
cmd := "iperf3 --version"
|
||||||
|
if version == "V2" {
|
||||||
|
cmd = "iperf -v"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 网元主机的SSH客户端
|
||||||
|
sshClient, err := neService.NewNeInfo.NeRunSSHClient(meType, neId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("iperf3 not installed")
|
return "", err
|
||||||
|
}
|
||||||
|
defer sshClient.Close()
|
||||||
|
|
||||||
|
// 检查是否安装iperf
|
||||||
|
output, err := sshClient.RunCMD(cmd)
|
||||||
|
if err != nil {
|
||||||
|
if version == "V2" && strings.HasSuffix(err.Error(), "status 1") { // V2 版本
|
||||||
|
return strings.TrimSpace(output), nil
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("iperf %s not installed", version)
|
||||||
}
|
}
|
||||||
return strings.TrimSpace(output), err
|
return strings.TrimSpace(output), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install 安装iperf3
|
// Install 安装iperf3
|
||||||
func (s *IPerf) Install(meType, neId string) error {
|
func (s *IPerf) Install(meType, neId, version string) error {
|
||||||
|
if version != "V2" && version != "V3" {
|
||||||
|
return fmt.Errorf("iperf version is required V2 or V3")
|
||||||
|
}
|
||||||
|
|
||||||
// 网元主机的SSH客户端
|
// 网元主机的SSH客户端
|
||||||
sshClient, err := neService.NewNeInfo.NeRunSSHClient(meType, neId)
|
sshClient, err := neService.NewNeInfo.NeRunSSHClient(meType, neId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -59,6 +81,13 @@ func (s *IPerf) Install(meType, neId string) error {
|
|||||||
depPkg = "sudo rpm -Uvh --force"
|
depPkg = "sudo rpm -Uvh --force"
|
||||||
depDir = "assets/dependency/iperf3/rpm"
|
depDir = "assets/dependency/iperf3/rpm"
|
||||||
// yum remove iperf3 iperf3-help.noarch
|
// yum remove iperf3 iperf3-help.noarch
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("iperf %s not supported install", version)
|
||||||
|
}
|
||||||
|
|
||||||
|
// V2版本和V3版本的安装包路径不同
|
||||||
|
if version == "V2" {
|
||||||
|
depDir = strings.Replace(depDir, "iperf3", "iperf", 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从 embed.FS 中读取默认配置文件内容
|
// 从 embed.FS 中读取默认配置文件内容
|
||||||
@@ -72,19 +101,19 @@ func (s *IPerf) Install(meType, neId string) error {
|
|||||||
// 打开本地文件
|
// 打开本地文件
|
||||||
localFile, err := assetsDir.Open(fmt.Sprintf("%s/%s", depDir, d.Name()))
|
localFile, err := assetsDir.Open(fmt.Sprintf("%s/%s", depDir, d.Name()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("iperf3 file local error")
|
return fmt.Errorf("iperf %s file local error", version)
|
||||||
}
|
}
|
||||||
defer localFile.Close()
|
defer localFile.Close()
|
||||||
// 创建远程文件
|
// 创建远程文件
|
||||||
remotePath := fmt.Sprintf("%s/%s", nePath, d.Name())
|
remotePath := fmt.Sprintf("%s/%s", nePath, d.Name())
|
||||||
remoteFile, err := sftpClient.Client.Create(remotePath)
|
remoteFile, err := sftpClient.Client.Create(remotePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("iperf3 file remote error")
|
return fmt.Errorf("iperf %s file remote error", version)
|
||||||
}
|
}
|
||||||
defer remoteFile.Close()
|
defer remoteFile.Close()
|
||||||
// 使用 io.Copy 将嵌入的文件内容复制到目标文件
|
// 使用 io.Copy 将嵌入的文件内容复制到目标文件
|
||||||
if _, err := io.Copy(remoteFile, localFile); err != nil {
|
if _, err := io.Copy(remoteFile, localFile); err != nil {
|
||||||
return fmt.Errorf("iperf3 file copy error")
|
return fmt.Errorf("iperf %s file copy error", version)
|
||||||
}
|
}
|
||||||
neFilePaths = append(neFilePaths, remotePath)
|
neFilePaths = append(neFilePaths, remotePath)
|
||||||
}
|
}
|
||||||
@@ -98,7 +127,7 @@ func (s *IPerf) Install(meType, neId string) error {
|
|||||||
// 安装软件包
|
// 安装软件包
|
||||||
pkgInstall := fmt.Sprintf("%s %s", depPkg, strings.Join(neFilePaths, " "))
|
pkgInstall := fmt.Sprintf("%s %s", depPkg, strings.Join(neFilePaths, " "))
|
||||||
if _, err := sshClient.RunCMD(pkgInstall); err != nil {
|
if _, err := sshClient.RunCMD(pkgInstall); err != nil {
|
||||||
return fmt.Errorf("iperf3 install error")
|
return fmt.Errorf("iperf %s install error", version)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -108,7 +137,7 @@ func (s *IPerf) Run(client *wsModel.WSClient, reqMsg wsModel.WSRequest) {
|
|||||||
// 必传requestId确认消息
|
// 必传requestId确认消息
|
||||||
if reqMsg.RequestID == "" {
|
if reqMsg.RequestID == "" {
|
||||||
msg := "message requestId is required"
|
msg := "message requestId is required"
|
||||||
logger.Infof("ws IPerf3 Run UID %s err: %s", client.BindUid, msg)
|
logger.Infof("ws IPerf Run UID %s err: %s", client.BindUid, msg)
|
||||||
msgByte, _ := json.Marshal(result.ErrMsg(msg))
|
msgByte, _ := json.Marshal(result.ErrMsg(msg))
|
||||||
client.MsgChan <- msgByte
|
client.MsgChan <- msgByte
|
||||||
return
|
return
|
||||||
@@ -126,7 +155,7 @@ func (s *IPerf) Run(client *wsModel.WSClient, reqMsg wsModel.WSRequest) {
|
|||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
client.StopChan <- struct{}{}
|
client.StopChan <- struct{}{}
|
||||||
return
|
return
|
||||||
case "iperf3":
|
case "iperf":
|
||||||
// SSH会话消息接收写入会话
|
// SSH会话消息接收写入会话
|
||||||
var command string
|
var command string
|
||||||
command, err = s.parseOptions(reqMsg.Data)
|
command, err = s.parseOptions(reqMsg.Data)
|
||||||
@@ -155,7 +184,7 @@ func (s *IPerf) Run(client *wsModel.WSClient, reqMsg wsModel.WSRequest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warnf("ws IPerf3 Run UID %s err: %s", client.BindUid, err.Error())
|
logger.Warnf("ws IPerf Run UID %s err: %s", client.BindUid, err.Error())
|
||||||
msgByte, _ := json.Marshal(result.ErrMsg(err.Error()))
|
msgByte, _ := json.Marshal(result.ErrMsg(err.Error()))
|
||||||
client.MsgChan <- msgByte
|
client.MsgChan <- msgByte
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
@@ -175,7 +204,8 @@ func (s *IPerf) parseOptions(reqData any) (string, error) {
|
|||||||
msgByte, _ := json.Marshal(reqData)
|
msgByte, _ := json.Marshal(reqData)
|
||||||
var data struct {
|
var data struct {
|
||||||
Command string `json:"command"` // 命令字符串
|
Command string `json:"command"` // 命令字符串
|
||||||
Client bool `json:"client"` // 服务端或客户端,默认服务端
|
Version string `json:"version"` // 服务版本,默认V3
|
||||||
|
Mode string `json:"mode"` // 服务端或客户端,默认客户端client
|
||||||
Host string `json:"host"` // 客户端连接到的服务端IP地址
|
Host string `json:"host"` // 客户端连接到的服务端IP地址
|
||||||
// Server or Client
|
// Server or Client
|
||||||
Port int `json:"port"` // 服务端口
|
Port int `json:"port"` // 服务端口
|
||||||
@@ -183,17 +213,25 @@ func (s *IPerf) parseOptions(reqData any) (string, error) {
|
|||||||
// Server
|
// Server
|
||||||
OneOff bool `json:"oneOff"` // 只进行一次连接
|
OneOff bool `json:"oneOff"` // 只进行一次连接
|
||||||
// Client
|
// Client
|
||||||
UDP bool `json:"udp"` // use UDP rather than TCP
|
UDP bool `json:"udp"` // use UDP rather than TCP
|
||||||
Time int `json:"time"` // 以秒为单位的传输时间(默认为 10 秒)
|
Time int `json:"time"` // 以秒为单位的传输时间(默认为 10 秒)
|
||||||
Reverse bool `json:"reverse"` // 以反向模式运行(服务器发送,客户端接收)
|
Reverse bool `json:"reverse"` // 以反向模式运行(服务器发送,客户端接收)
|
||||||
Window string `json:"window"` // 设置窗口大小/套接字缓冲区大小
|
Window string `json:"window"` // 设置窗口大小/套接字缓冲区大小
|
||||||
|
Parallel int `json:"parallel"` // 运行的并行客户端流数量
|
||||||
|
Bitrate int `json:"bitrate"` // 以比特/秒为单位(0 表示无限制)
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(msgByte, &data); err != nil {
|
if err := json.Unmarshal(msgByte, &data); err != nil {
|
||||||
logger.Warnf("ws processor parseClient err: %s", err.Error())
|
logger.Warnf("ws processor parseClient err: %s", err.Error())
|
||||||
return "", fmt.Errorf("query data structure error")
|
return "", fmt.Errorf("query data structure error")
|
||||||
}
|
}
|
||||||
|
if data.Version != "V3" && data.Version != "V2" {
|
||||||
|
return "", fmt.Errorf("query data version support V3 or V2")
|
||||||
|
}
|
||||||
|
|
||||||
command := []string{"iperf3"}
|
command := []string{"iperf3"}
|
||||||
|
if data.Version == "V2" {
|
||||||
|
command = []string{"iperf"}
|
||||||
|
}
|
||||||
// 命令字符串高优先级
|
// 命令字符串高优先级
|
||||||
if data.Command != "" {
|
if data.Command != "" {
|
||||||
command = append(command, data.Command)
|
command = append(command, data.Command)
|
||||||
@@ -201,16 +239,14 @@ func (s *IPerf) parseOptions(reqData any) (string, error) {
|
|||||||
return strings.Join(command, " "), nil
|
return strings.Join(command, " "), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.Client && data.Host == "" {
|
if data.Mode != "client" && data.Mode != "server" {
|
||||||
|
return "", fmt.Errorf("query data mode support client or server")
|
||||||
|
}
|
||||||
|
if data.Mode == "client" && data.Host == "" {
|
||||||
return "", fmt.Errorf("query data client host empty")
|
return "", fmt.Errorf("query data client host empty")
|
||||||
}
|
}
|
||||||
if !data.Client {
|
|
||||||
command = append(command, "-s")
|
if data.Mode == "client" {
|
||||||
// Server
|
|
||||||
if data.OneOff {
|
|
||||||
command = append(command, "-1")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
command = append(command, "-c")
|
command = append(command, "-c")
|
||||||
command = append(command, data.Host)
|
command = append(command, data.Host)
|
||||||
// Client
|
// Client
|
||||||
@@ -220,6 +256,12 @@ func (s *IPerf) parseOptions(reqData any) (string, error) {
|
|||||||
if data.Time > 0 {
|
if data.Time > 0 {
|
||||||
command = append(command, fmt.Sprintf("-t %d", data.Time))
|
command = append(command, fmt.Sprintf("-t %d", data.Time))
|
||||||
}
|
}
|
||||||
|
if data.Bitrate > 0 {
|
||||||
|
command = append(command, fmt.Sprintf("-b %d", data.Bitrate))
|
||||||
|
}
|
||||||
|
if data.Parallel > 0 {
|
||||||
|
command = append(command, fmt.Sprintf("-P %d", data.Parallel))
|
||||||
|
}
|
||||||
if data.Reverse {
|
if data.Reverse {
|
||||||
command = append(command, "-R")
|
command = append(command, "-R")
|
||||||
}
|
}
|
||||||
@@ -227,6 +269,13 @@ func (s *IPerf) parseOptions(reqData any) (string, error) {
|
|||||||
command = append(command, fmt.Sprintf("-w %s", data.Window))
|
command = append(command, fmt.Sprintf("-w %s", data.Window))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if data.Mode == "server" {
|
||||||
|
command = append(command, "-s")
|
||||||
|
// Server
|
||||||
|
if data.OneOff {
|
||||||
|
command = append(command, "-1")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Server or Client
|
// Server or Client
|
||||||
if data.Port > 0 {
|
if data.Port > 0 {
|
||||||
|
|||||||
Reference in New Issue
Block a user