feat: 接口网元状态/网元列表

This commit is contained in:
TsMask
2023-12-21 20:42:50 +08:00
parent 509fdbba95
commit f5c852d801
10 changed files with 480 additions and 5 deletions

View File

@@ -0,0 +1,243 @@
package fetch
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/url"
"os"
"strings"
"time"
)
// Get 发送 GET 请求
// timeout 超时时间(秒)
func Get(url string, headers map[string]string, timeout uint8) ([]byte, error) {
if timeout < 1 || timeout > 180 {
timeout = 1
}
client := &http.Client{
Timeout: time.Duration(timeout) * time.Second, // 设置超时时间为 5 秒
}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
for key, value := range headers {
req.Header.Set(key, value)
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, errors.New(resp.Status)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
}
// Post 发送 POST 请求
func Post(url string, data url.Values, headers map[string]string) ([]byte, error) {
client := &http.Client{}
req, err := http.NewRequest("POST", url, strings.NewReader(data.Encode()))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
for key, value := range headers {
req.Header.Set(key, value)
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, errors.New(resp.Status)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
}
// PostJSON 发送 POST 请求,并将请求体序列化为 JSON 格式
func PostJSON(url string, data any, headers map[string]string) ([]byte, error) {
client := &http.Client{}
jsonData, err := json.Marshal(data)
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", url, bytes.NewReader(jsonData))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
for key, value := range headers {
req.Header.Set(key, value)
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, errors.New(resp.Status)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
}
// UploadFile 上传文件函数,接收 URL 地址、表单参数和文件对象,返回响应内容或错误信息
func PostUploadFile(url string, params map[string]string, file *os.File) ([]byte, error) {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("file", file.Name())
if err != nil {
return nil, fmt.Errorf("failed to create form file: %v", err)
}
_, err = io.Copy(part, file)
if err != nil {
return nil, fmt.Errorf("failed to copy file content: %v", err)
}
for key, value := range params {
err = writer.WriteField(key, value)
if err != nil {
return nil, fmt.Errorf("failed to write form field: %v", err)
}
}
err = writer.Close()
if err != nil {
return nil, fmt.Errorf("failed to close writer: %v", err)
}
req, err := http.NewRequest("POST", url, body)
if err != nil {
return nil, fmt.Errorf("failed to create HTTP request: %v", err)
}
req.Header.Set("Content-Type", writer.FormDataContentType())
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("HTTP request failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("HTTP request returned status: %s", resp.Status)
}
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body: %v", err)
}
return responseBody, nil
}
// PutJSON 发送 PUT 请求,并将请求体序列化为 JSON 格式
func PutJSON(url string, data any, headers map[string]string) ([]byte, error) {
client := &http.Client{}
jsonData, err := json.Marshal(data)
if err != nil {
return nil, err
}
req, err := http.NewRequest("PUT", url, bytes.NewReader(jsonData))
if err != nil {
return nil, err
}
for key, value := range headers {
req.Header.Set(key, value)
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, errors.New(resp.Status)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
}
// Delete 发送 DELETE 请求
func Delete(url string, headers map[string]string) ([]byte, error) {
client := &http.Client{}
req, err := http.NewRequest("DELETE", url, nil)
if err != nil {
return nil, err
}
for key, value := range headers {
req.Header.Set(key, value)
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, errors.New(resp.Status)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
}

View File

@@ -1,6 +1,7 @@
package service package service
import ( import (
"ems.agt/lib/global"
systemService "ems.agt/src/modules/system/service" systemService "ems.agt/src/modules/system/service"
) )
@@ -21,6 +22,10 @@ type CommontImpl struct {
// SystemConfigInfo 系统配置信息 // SystemConfigInfo 系统配置信息
func (s *CommontImpl) SystemConfigInfo() map[string]string { func (s *CommontImpl) SystemConfigInfo() map[string]string {
infoMap := map[string]string{} infoMap := map[string]string{}
// 获取打包注入的全局变量信息
infoMap["version"] = global.Version
infoMap["buildTime"] = global.BuildTime
infoMap["goVer"] = global.GoVer
// 获取LOGO类型 // 获取LOGO类型
logoType := s.sysConfigService.SelectConfigValueByKey("sys.logo.type") logoType := s.sysConfigService.SelectConfigValueByKey("sys.logo.type")
infoMap["logoType"] = logoType infoMap["logoType"] = logoType

View File

@@ -3,7 +3,9 @@ package controller
import ( import (
"ems.agt/src/framework/i18n" "ems.agt/src/framework/i18n"
"ems.agt/src/framework/utils/ctx" "ems.agt/src/framework/utils/ctx"
"ems.agt/src/framework/utils/parse"
"ems.agt/src/framework/vo/result" "ems.agt/src/framework/vo/result"
"ems.agt/src/modules/network_element/model"
neService "ems.agt/src/modules/network_element/service" neService "ems.agt/src/modules/network_element/service"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@@ -21,22 +23,86 @@ type NeInfoController struct {
neInfoService neService.INeInfo neInfoService neService.INeInfo
} }
// 网元状态
//
// GET /state
func (s *NeInfoController) NeState(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var querys struct {
NeType string `form:"neType" binding:"required"`
NeID string `form:"neId" binding:"required"`
}
if err := c.ShouldBindQuery(&querys); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID)
if neInfo.NeId != querys.NeID || neInfo.IP == "" {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
resData, err := neService.NeState(neInfo)
if err != nil {
c.JSON(200, result.ErrMsg("connection failure"))
return
}
c.JSON(200, result.OkData(resData))
}
// 网元neType和neID查询 // 网元neType和neID查询
// //
// GET /info // GET /info
func (s *NeInfoController) NeTypeAndID(c *gin.Context) { func (s *NeInfoController) NeTypeAndID(c *gin.Context) {
language := ctx.AcceptLanguage(c) language := ctx.AcceptLanguage(c)
neType := c.Query("neType") var querys struct {
neId := c.Query("neId") NeType string `form:"neType" binding:"required"`
if neType == "" || neId == "" { NeID string `form:"neId" binding:"required"`
}
if err := c.ShouldBindQuery(&querys); 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
} }
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId) neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID)
if neInfo.NeId != neId || neInfo.IP == "" { if neInfo.NeId != querys.NeID || neInfo.IP == "" {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return return
} }
c.JSON(200, result.OkData(neInfo)) c.JSON(200, result.OkData(neInfo))
} }
// 网元列表
//
// GET /list
func (s *NeInfoController) NeList(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var querys struct {
NeType string `form:"neType"`
NeId string `form:"neId"`
BandStatus string `form:"bandStatus"`
}
if err := c.ShouldBindQuery(&querys); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 查询实体参数
ne := model.NeInfo{}
if querys.NeType != "" {
ne.NeType = querys.NeType
}
if querys.NeId != "" {
ne.NeId = querys.NeId
}
bandStatus := parse.Boolean(querys.BandStatus)
neList := s.neInfoService.SelectNeList(ne, bandStatus)
if len(neList) == 0 {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
c.JSON(200, result.OkData(neList))
}

View File

@@ -16,4 +16,9 @@ type NeInfo struct {
NeAddress string `json:"neAddress"` NeAddress string `json:"neAddress"`
Status string `json:"status"` // 0: 在线 1: 下线 2: 备用 3: 工程 Status string `json:"status"` // 0: 在线 1: 下线 2: 备用 3: 工程
UpdateTime string `json:"updateTime"` UpdateTime string `json:"updateTime"`
// ====== 非数据库字段属性 ======
// 服务状态
ServerState map[string]any `json:"serverState,omitempty"`
} }

View File

@@ -20,6 +20,14 @@ func Setup(router *gin.Engine) {
middleware.PreAuthorize(nil), middleware.PreAuthorize(nil),
controller.NewNeInfo.NeTypeAndID, controller.NewNeInfo.NeTypeAndID,
) )
neGroup.GET("/state",
middleware.PreAuthorize(nil),
controller.NewNeInfo.NeState,
)
neGroup.GET("/list",
middleware.PreAuthorize(nil),
controller.NewNeInfo.NeList,
)
} }
// 网元处理 // 网元处理

View File

@@ -8,4 +8,7 @@ import (
type INeInfo interface { type INeInfo interface {
// SelectNeInfoByNeTypeAndNeID 通过ne_type和ne_id查询网元信息 // SelectNeInfoByNeTypeAndNeID 通过ne_type和ne_id查询网元信息
SelectNeInfoByNeTypeAndNeID(neType, neID string) model.NeInfo SelectNeInfoByNeTypeAndNeID(neType, neID string) model.NeInfo
// SelectNeList 查询网元列表
SelectNeList(ne model.NeInfo) []model.NeInfo
} }

View File

@@ -1,12 +1,33 @@
package repository package repository
import ( import (
"sort"
"strings"
"ems.agt/src/framework/datasource" "ems.agt/src/framework/datasource"
"ems.agt/src/framework/logger" "ems.agt/src/framework/logger"
"ems.agt/src/framework/utils/repo" "ems.agt/src/framework/utils/repo"
"ems.agt/src/modules/network_element/model" "ems.agt/src/modules/network_element/model"
) )
// neListSort 网元列表预设排序
var neListSort = []string{
"OMC",
"MME",
"AMF",
"AUSF",
"UDM",
"SMF",
"PCF",
"UPF",
"NRF",
"NSSF",
"IMS",
"N3IWF",
"NEF",
"LMF",
}
// 实例化数据层 NeInfoImpl 结构体 // 实例化数据层 NeInfoImpl 结构体
var NewNeInfoImpl = &NeInfoImpl{ var NewNeInfoImpl = &NeInfoImpl{
selectSql: `select id, ne_type, ne_id, rm_uid, ne_name, ip, port, pv_flag, province, vendor_name, dn, ne_address, status, update_time from ne_info`, selectSql: `select id, ne_type, ne_id, rm_uid, ne_name, ip, port, pv_flag, province, vendor_name, dn, ne_address, status, update_time from ne_info`,
@@ -49,6 +70,31 @@ func (r *NeInfoImpl) convertResultRows(rows []map[string]any) []model.NeInfo {
} }
arr = append(arr, item) arr = append(arr, item)
} }
// 排序
sort.Slice(arr, func(i, j int) bool {
// 前一个
after := arr[i]
afterIndex := 0
for i, v := range neListSort {
if after.NeType == v {
afterIndex = i
break
}
}
// 后一个
befter := arr[j]
befterIndex := 0
for i, v := range neListSort {
if befter.NeType == v {
befterIndex = i
break
}
}
// 升序
return afterIndex < befterIndex
})
return arr return arr
} }
@@ -67,3 +113,34 @@ func (r *NeInfoImpl) SelectNeInfoByNeTypeAndNeID(neType, neID string) model.NeIn
} }
return model.NeInfo{} return model.NeInfo{}
} }
// SelectNeList 查询网元列表
func (r *NeInfoImpl) SelectNeList(ne model.NeInfo) []model.NeInfo {
// 查询条件拼接
var conditions []string
var params []any
if ne.NeType != "" {
conditions = append(conditions, "ne_type = ?")
params = append(params, ne.NeType)
}
if ne.NeId != "" {
conditions = append(conditions, "ne_id = ?")
params = append(params, ne.NeId)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
// 查询数据
querySql := r.selectSql + whereSql + " order by ne_type asc "
results, err := datasource.RawDB("", querySql, params)
if err != nil {
logger.Errorf("query err => %v", err)
}
// 转换实体
return r.convertResultRows(results)
}

View File

@@ -0,0 +1,44 @@
package service
import (
"encoding/json"
"fmt"
"strings"
"time"
"ems.agt/src/framework/logger"
"ems.agt/src/framework/utils/fetch"
"ems.agt/src/modules/network_element/model"
)
// NeState 获取网元端服务状态
func NeState(neInfo model.NeInfo) (map[string]any, error) {
// 网元直连
neUrl := fmt.Sprintf("http://%s:%d/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", neInfo.IP, neInfo.Port, strings.ToLower(neInfo.NeType))
resBytes, err := fetch.Get(neUrl, nil, 1)
if err != nil {
logger.Warnf("NeState %s", err.Error())
return nil, err
}
// 序列化结果
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Warnf("NeState Unmarshal %s", err.Error())
return nil, err
}
return map[string]any{
"neType": neInfo.NeType,
"neId": neInfo.NeId,
"neName": neInfo.NeName,
"refreshTime": time.Now().UnixMilli(), // 获取时间
"version": resData["version"],
"capability": resData["capability"],
"sn": resData["serialNum"],
"expire": resData["expiryDate"],
"cpu": resData["cpuUsage"],
"mem": resData["memUsage"],
}, nil
}

View File

@@ -6,4 +6,7 @@ import "ems.agt/src/modules/network_element/model"
type INeInfo interface { type INeInfo interface {
// SelectNeInfoByNeTypeAndNeID 通过ne_type和ne_id查询网元信息 // SelectNeInfoByNeTypeAndNeID 通过ne_type和ne_id查询网元信息
SelectNeInfoByNeTypeAndNeID(neType, neID string) model.NeInfo SelectNeInfoByNeTypeAndNeID(neType, neID string) model.NeInfo
// SelectNeList 查询网元列表
SelectNeList(ne model.NeInfo, bandStatus bool) []model.NeInfo
} }

View File

@@ -20,3 +20,24 @@ type NeInfoImpl struct {
func (r *NeInfoImpl) SelectNeInfoByNeTypeAndNeID(neType, neID string) model.NeInfo { func (r *NeInfoImpl) SelectNeInfoByNeTypeAndNeID(neType, neID string) model.NeInfo {
return r.NeInfoRepository.SelectNeInfoByNeTypeAndNeID(neType, neID) return r.NeInfoRepository.SelectNeInfoByNeTypeAndNeID(neType, neID)
} }
// SelectNeList 查询网元列表
func (r *NeInfoImpl) SelectNeList(ne model.NeInfo, bandStatus bool) []model.NeInfo {
list := r.NeInfoRepository.SelectNeList(ne)
// 网元直连读取网元服务状态
if bandStatus {
neList := &list
for i := range *neList {
v := (*neList)[i]
result, err := NeState(v)
if err != nil {
(*neList)[i].ServerState = map[string]any{}
continue
}
(*neList)[i].ServerState = result
}
}
return list
}