add: 提交

This commit is contained in:
lichang
2023-08-14 17:02:50 +08:00
parent 897d45d443
commit 5ac2e981ea
163 changed files with 29466 additions and 0 deletions

117
features/aaaa/aaaa.go Normal file
View File

@@ -0,0 +1,117 @@
package aaaa
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"time"
"github.com/go-resty/resty/v2"
"ems.agt/lib/log"
"ems.agt/lib/services"
"ems.agt/restagent/config"
)
var (
UriAAAASSO = config.UriPrefix + "/aaaa/{apiVersion}/security/sso" // for external
)
var client = resty.New()
func init() {
/*
client.
SetTimeout(10 * time.Second).
SetRetryCount(1).
SetRetryWaitTime(1 * time.Second).
SetRetryMaxWaitTime(2 * time.Second).
SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) {
return 0, errors.New("quota exceeded")
})
*/
client.SetTimeout(3 * time.Second)
}
type AAAATicket struct {
Ticket string `json:"ticket"`
}
type SSOResult struct {
SSO struct {
Result string `json:"result"`
ResultMsg string `json:"result_msg"`
Ticket string `json:"ticket"`
ResultMsgcode string `json:"result_msgcode"`
Account []struct {
Accid string `json:"accid"`
} `json:"account"`
} `json:"sso"`
}
// Get system state from NF/NFs
func GetSSOFromAAAA(w http.ResponseWriter, r *http.Request) {
log.Debug("GetSSOFromAAAA processing... ")
vars := r.URL.Query()
ticket := vars["ticket"]
if len(ticket) == 0 {
services.ResponseNotFound404UriNotExist(w, r)
return
}
log.Debug("ticket:", ticket)
log.Debugf("r.RemoteAddr:%s r.Host: %s", r.RemoteAddr, r.Host)
var aaaaIp, omcIp string
addr := strings.Split(r.RemoteAddr, ":")
if len(addr) > 0 {
//aaaaIp := r.RemoteAddr[:strings.Index(r.Host, ":")]
aaaaIp = addr[0]
}
addr = strings.Split(r.Host, ":")
if len(addr) > 0 {
//omcIp := r.Host[:strings.Index(r.Host, ":")]
omcIp = addr[0]
}
log.Debugf("aaaaIp=%s omcIp=%s", aaaaIp, omcIp)
requestURI2NF := fmt.Sprintf("http://%s:8080/qryUserByTicket", aaaaIp)
log.Debug("requestURI2NF:", requestURI2NF)
aaaaTicket := &AAAATicket{
Ticket: ticket[0],
}
body, err := json.Marshal(aaaaTicket)
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
SetBody(body).
Post(requestURI2NF)
if err != nil {
log.Error("Get system state from NF is failed:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
log.Debug("response:", response)
switch response.StatusCode() {
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
ssoResult := new(SSOResult)
json.Unmarshal(response.Body(), ssoResult)
var accid string
if len(ssoResult.SSO.Account) != 0 {
accid = ssoResult.SSO.Account[0].Accid
}
redirectUrl := fmt.Sprintf("http://%s:8888/home.html?user=%s", omcIp, accid)
services.ResponseRedirect(w, redirectUrl)
return
default:
services.ResponseNotFound404UriNotExist(w, r)
return
}
}

66
features/cm/exec_linux.go Normal file
View File

@@ -0,0 +1,66 @@
//go:build linux
// +build linux
package cm
import (
"bytes"
"os/exec"
"ems.agt/lib/log"
)
func ExecCmd(command string) error {
log.Debug("Exec command:", command)
cmd := exec.Command("/bin/bash", "-c", command)
out, err := cmd.CombinedOutput()
log.Tracef("Exec output: %v", string(out))
if err != nil {
log.Error("exe cmd error: ", err)
return err
}
/*
if err := cmd.Start(); err != nil {
log.Error("Start error: ", err)
return err
}
if err := cmd.Wait(); err != nil {
log.Error("Wait error: ", err)
return err
}
*/
return nil
}
func ExecShell(command string) error {
in := bytes.NewBuffer(nil)
cmd := exec.Command("sh")
cmd.Stdin = in
in.WriteString(command)
in.WriteString("exit\n")
if err := cmd.Start(); err != nil {
return err
}
return nil
}
func ExecOsCmd(command, os string) error {
log.Debugf("Exec %s command:%s", os, command)
var cmd *exec.Cmd
switch os {
case "Linux":
cmd = exec.Command(command)
case "Windows":
cmd = exec.Command("cmd", "/C", command)
}
out, err := cmd.CombinedOutput()
log.Tracef("Exec output: %v", string(out))
if err != nil {
log.Error("exe cmd error: ", err)
return err
}
return nil
}

View File

@@ -0,0 +1,53 @@
//go:build windows
// +build windows
package cm
import (
"os/exec"
"ems.agt/lib/log"
)
func ExecCmd(command string) error {
log.Debug("Exec command:", command)
cmd := exec.Command("cmd", "/C", command)
out, err := cmd.CombinedOutput()
log.Tracef("Exec output: %v", string(out))
if err != nil {
log.Error("exe cmd error: ", err)
return err
}
/*
if err := cmd.Start(); err != nil {
log.Error("Start error: ", err)
return err
}
if err := cmd.Wait(); err != nil {
log.Error("Wait error: ", err)
return err
}
*/
return nil
}
func ExecOsCmd(command, os string) error {
log.Debugf("Exec %s command:%s", os, command)
var cmd *exec.Cmd
switch os {
case "Linux":
cmd = exec.Command(command)
case "Windows":
cmd = exec.Command("cmd", "/C", command)
}
out, err := cmd.CombinedOutput()
log.Tracef("Exec output: %v", string(out))
if err != nil {
log.Error("exe cmd error: ", err)
return err
}
return nil
}

148
features/cm/license.go Normal file
View File

@@ -0,0 +1,148 @@
package cm
import (
"net/http"
"ems.agt/lib/log"
"ems.agt/lib/services"
"ems.agt/restagent/config"
"github.com/gorilla/mux"
)
var (
// License
LicenseUri = config.UriPrefix + "/systemManagement/{apiVersion}/{neType}/license"
NeLicenseUri = config.UriPrefix + "/systemManagement/{apiVersion}/{neType}/license/{neId}"
)
func UploadLicenseFile(w http.ResponseWriter, r *http.Request) {
log.Debug("UploadLicenseFile processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Http request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["neType"]
if neType == "" {
log.Error("neType is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
// neTypeUpper := strings.ToUpper(neType)
// neTypeLower := strings.ToLower(neType)
services.ResponseStatusOK204NoContent(w)
return
}
func DownloadLicenseFile(w http.ResponseWriter, r *http.Request) {
log.Debug("DownloadLicenseFile processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["neType"]
if neType == "" {
log.Error("neType is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
// // neTypeUpper := strings.ToUpper(neType)
// //neTypeLower := strings.ToLower(neType)
// version := vars["version"]
// if version == "" {
// log.Error("version is empty")
// services.ResponseNotFound404UriNotExist(w, r)
// return
// }
// sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version)
// neSoftware, err := dborm.XormGetDataBySQL(sql)
// if err != nil {
// log.Error("Faile to XormGetDataBySQL:", err)
// services.ResponseInternalServerError500ProcessError(w, err)
// return
// } else if len(*neSoftware) == 0 {
// err := global.ErrCMNotFoundTargetSoftware
// log.Error(err)
// services.ResponseInternalServerError500ProcessError(w, err)
// return
// }
// fileName := (*neSoftware)[0]["file_name"]
// path := (*neSoftware)[0]["path"]
// md5Sum := (*neSoftware)[0]["md5_sum"]
// services.ResponseFileWithNameAndMD5(w, http.StatusOK, fileName, path, md5Sum)
return
}
func DeleteLcenseFile(w http.ResponseWriter, r *http.Request) {
log.Debug("DeleteLcenseFile processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["neType"]
if neType == "" {
log.Error("neType is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
// neTypeUpper := strings.ToUpper(neType)
// //neTypeLower := strings.ToLower(neType)
// version := vars["version"]
// if version == "" {
// log.Error("version is empty")
// services.ResponseNotFound404UriNotExist(w, r)
// return
// }
// sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version)
// neSoftware, err := dborm.XormGetDataBySQL(sql)
// if err != nil {
// log.Error("Faile to XormGetDataBySQL:", err)
// services.ResponseInternalServerError500ProcessError(w, err)
// return
// } else if len(*neSoftware) == 0 {
// err := global.ErrCMNotFoundTargetSoftware
// log.Error(err)
// services.ResponseInternalServerError500ProcessError(w, err)
// return
// }
// where := fmt.Sprintf("ne_type='%s' and version='%s'", neTypeUpper, version)
// affected, err := dborm.XormDeleteDataByWhere(where, "ne_software")
// if err != nil || affected == 0 {
// log.Error("Faile to XormGetDataBySQL:", err)
// services.ResponseInternalServerError500ProcessError(w, err)
// return
// }
// fileName := (*neSoftware)[0]["file_name"]
// path := (*neSoftware)[0]["path"]
// filePath := fmt.Sprintf("%s/%s", path, fileName)
// err = os.Remove(filePath)
// if err != nil {
// log.Error("Faile to Remove:", err)
// services.ResponseInternalServerError500ProcessError(w, err)
// return
// }
services.ResponseStatusOK204NoContent(w)
return
}

676
features/cm/ne.go Normal file
View File

@@ -0,0 +1,676 @@
package cm
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strings"
"time"
"ems.agt/lib/dborm"
"ems.agt/lib/global"
"ems.agt/lib/log"
"ems.agt/lib/services"
"ems.agt/restagent/config"
"github.com/go-resty/resty/v2"
"github.com/gorilla/mux"
)
var (
UriParamOmcNeConfig = config.UriPrefix + "/systemManagement/v1/elementType/%s/objectType/config/omcNeConfig"
// NE CM export/import
NeCmUri = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/cm"
// NE info
UriNeInfo = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/neInfo"
// NE backup file
UriNeCmFile = config.UriPrefix + "/systemManagement/{apiVersion}/{neType}/neBackup/{fileName}"
)
func init() {
}
func GetNeInfo(w http.ResponseWriter, r *http.Request) {
log.Debug("GetNeInfo processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["elementTypeValue"]
if neType == "" {
log.Error("elementTypeValue is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neId := services.GetUriParamString(r, "ne_id", ",", false, false)
// no, _ := strconv.ParseInt(neId, 10, 64)
neInfo, err := dborm.XormGetNeInfo(neType, neId)
if err != nil {
log.Error("dborm.XormGetNeInfo is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
var response services.DataResponse
response.Data = neInfo
services.ResponseWithJson(w, http.StatusOK, response)
}
type OmcNeConfig struct {
NeId string `json:"neId" xorm:"ne_id"` // 网元标识(内部),
RmUID string `json:"rmUID" xorm:"rm_uid"` // rmUID 网元唯一标识
NeName string `json:"neName" xorm:"ne_name"` // 网元名称(内部)/友好名称(北向资源/性能等使用)
PvFlag string `json:"pvFlag" xorm:"pv_flag"` // 网元虚实性标识 VNF/PNF: 虚拟/物理
Province string `json:"province" xorm:"province"` // 网元所在省份
VendorName string `json:"vendorName" xorm:"vendor_name"` // 厂商名称
// ManagedBy string `json:"managedBy" xorm:"managed_by"` // 管理ManagedElement的ManagementNode对象类的DN值
Dn string `json:"dn" xorm:"dn"` // 资源里边的ManagedBy性能的Dn网络唯一标识
}
func PostNeInfo(w http.ResponseWriter, r *http.Request) {
log.Debug("PostNeInfo processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["elementTypeValue"]
if neType == "" {
log.Error("elementTypeValue is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
log.Debug("Body:", string(body))
neInfo := new(dborm.NeInfo)
_ = json.Unmarshal(body, neInfo)
neInfo.UpdateTime = time.Now().Format(time.DateTime)
log.Debug("NE info:", neInfo)
hostUri := global.CombineHostUri(neInfo.Ip, neInfo.Port)
//hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
apiUri := fmt.Sprintf(UriParamOmcNeConfig, strings.ToLower(neInfo.NeType))
requestURI2NF := fmt.Sprintf("%s%s", hostUri, apiUri)
log.Debug("requestURI2NF:", requestURI2NF)
omcNeConfig := &OmcNeConfig{
NeId: neInfo.NeId,
RmUID: neInfo.RmUID,
NeName: neInfo.NeName,
PvFlag: neInfo.PvFlag,
Province: neInfo.Province,
VendorName: neInfo.VendorName,
Dn: neInfo.Dn,
}
body, _ = json.Marshal(omcNeConfig)
client := resty.New()
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
SetBody(body).
Put(requestURI2NF)
if err != nil {
log.Error("Failed to Put:", err)
services.ResponseInternalServerError500NFConnectRefused(w)
return
}
log.Info("StatusCode: ", response.StatusCode())
if config.GetYamlConfig().OMC.Chk2Ne == false {
affected, err := dborm.XormInsertNeInfo(neInfo)
if err != nil {
log.Error("Failed to insert Ne info:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
mapRow := make(map[string]interface{})
row := map[string]interface{}{"affectedRows": affected}
mapRow["data"] = row
services.ResponseWithJson(w, http.StatusOK, mapRow)
return
} else {
respMsg := make(map[string]interface{})
switch response.StatusCode() {
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
affected, err := dborm.XormInsertNeInfo(neInfo)
if err != nil {
log.Error("Failed to dborm.XormInsertNeInfo:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
} else if affected <= 0 {
log.Infof("Not record affected to insert ne_info")
}
services.ResponseStatusOK204NoContent(w)
return
default:
log.Info("response body:", string(response.Body()))
body := new(map[string]interface{})
_ = json.Unmarshal(response.Body(), &body)
respMsg["error"] = body
}
services.ResponseWithJson(w, response.StatusCode(), respMsg)
return
}
}
func PutNeInfo(w http.ResponseWriter, r *http.Request) {
log.Debug("PutNeInfo processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["elementTypeValue"]
if neType == "" {
log.Error("elementTypeValue is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
neInfo := new(dborm.NeInfo)
_ = json.Unmarshal(body, neInfo)
neInfo.NeType = strings.ToUpper(neType)
neInfo.UpdateTime = time.Now().Format(time.DateTime)
log.Debug("NE info:", neInfo)
hostUri := global.CombineHostUri(neInfo.Ip, neInfo.Port)
//hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
apiUri := fmt.Sprintf(UriParamOmcNeConfig, strings.ToLower(neType))
requestURI2NF := fmt.Sprintf("%s%s", hostUri, apiUri)
log.Debug("requestURI2NF:", requestURI2NF)
omcNeConfig := &OmcNeConfig{
NeId: neInfo.NeId,
RmUID: neInfo.RmUID,
NeName: neInfo.NeName,
PvFlag: neInfo.PvFlag,
Province: neInfo.Province,
VendorName: neInfo.VendorName,
Dn: neInfo.Dn,
}
body, _ = json.Marshal(omcNeConfig)
client := resty.New()
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
SetBody(body).
Put(requestURI2NF)
if err != nil {
log.Error("Failed to Put:", err)
services.ResponseInternalServerError500NFConnectRefused(w)
return
}
log.Info("StatusCode: ", response.StatusCode())
if config.GetYamlConfig().OMC.Chk2Ne == false {
affected, err := dborm.XormUpdateNeInfo(neInfo)
if err != nil {
log.Error("Failed to update Ne info:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
mapRow := make(map[string]interface{})
row := map[string]interface{}{"affectedRows": affected}
mapRow["data"] = row
services.ResponseWithJson(w, http.StatusOK, mapRow)
return
} else {
respMsg := make(map[string]interface{})
switch response.StatusCode() {
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
affected, err := dborm.XormUpdateNeInfo(neInfo)
if err != nil {
log.Error("Failed to dborm.XormUpdateNeInfo:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
} else if affected <= 0 {
log.Infof("Not record affected to insert ne_info")
}
services.ResponseStatusOK204NoContent(w)
return
default:
log.Info("response body:", string(response.Body()))
body := new(map[string]interface{})
_ = json.Unmarshal(response.Body(), &body)
respMsg["error"] = body
}
services.ResponseWithJson(w, response.StatusCode(), respMsg)
return
}
}
func DeleteNeInfo(w http.ResponseWriter, r *http.Request) {
log.Debug("DeleteNeInfo processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["elementTypeValue"]
if neType == "" {
log.Error("elementTypeValue is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
neInfo := new(dborm.NeInfo)
_ = json.Unmarshal(body, neInfo)
neInfo.NeType = strings.ToUpper(neType)
neInfo.NeId = services.GetUriParamString(r, "ne_id", ",", false, false)
neInfo, err = dborm.XormGetNeInfo(neInfo.NeType, neInfo.NeId)
if err != nil || neInfo == nil {
log.Error("Failed to delete Ne info:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
log.Debug("NE info:", neInfo)
// if NE in active status, can't delete NE
if IsActiveNF(neInfo) == false {
affected, err := dborm.XormDeleteNeInfo(neInfo)
if err != nil {
log.Error("Failed to delete Ne info:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
mapRow := make(map[string]interface{})
row := map[string]interface{}{"affectedRows": affected}
mapRow["data"] = row
services.ResponseWithJson(w, http.StatusOK, mapRow)
return
}
err = global.ErrCMCannotDeleteActiveNE
log.Error(err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
func IsActiveNF(neInfo *dborm.NeInfo) bool {
log.Debug("IsActiveNF processing... ")
hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
requestURI := fmt.Sprintf(config.UriPrefix+"/systemManagement/v1/elementType/%s/objectType/systemState",
strings.ToLower(neInfo.NeType))
client := resty.New()
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Get(hostUri + requestURI)
if err != nil {
log.Error("Failed to Get:", err)
}
switch response.StatusCode() {
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
return true
}
return false
}
func ExportCmFromNF(w http.ResponseWriter, r *http.Request) {
log.Debug("ExportCmFromNF processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["elementTypeValue"]
if neType == "" {
log.Error("elementTypeValue is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neTypeUpper := strings.ToUpper(neType)
neTypeLower := strings.ToLower(neType)
neId := services.GetUriParamString(r, "ne_id", ",", false, false)
// neInfo := new(dborm.NeInfo)
neInfo, err := dborm.XormGetNeInfo(neType, neId)
if err != nil {
log.Errorf("Failed to get ne_info:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
log.Debug("neInfo:", neInfo)
nePath := fmt.Sprintf("%s/etc/%s", config.GetYamlConfig().OMC.Backup, neTypeLower)
isExist, err := global.PathExists(nePath)
if err != nil {
log.Errorf("Failed to stat:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
if isExist {
err = os.RemoveAll(nePath)
if err != nil {
log.Errorf("Failed to RemoveAll:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
}
err = os.MkdirAll(nePath, os.ModePerm)
if err != nil {
log.Errorf("Failed to MkdirAll:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
var scpCmd string
ipType := global.ParseIPAddr(neInfo.Ip)
if ipType == global.IsIPv4 {
scpCmd = fmt.Sprintf("scp -r %s@%s:%s/%s/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User,
neInfo.Ip, config.GetYamlConfig().NE.EtcDir,
neTypeLower, config.GetYamlConfig().OMC.Backup, neTypeLower)
} else {
scpCmd = fmt.Sprintf("scp -r %s@[%s]:%s/%s/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User,
neInfo.Ip, config.GetYamlConfig().NE.EtcDir,
neTypeLower, config.GetYamlConfig().OMC.Backup, neTypeLower)
}
zipFile := fmt.Sprintf("%s-%s-etc-%s.zip", neTypeLower, strings.ToLower(neInfo.NeId), time.Now().Format(global.DateData))
zipCmd := fmt.Sprintf("cd %s && zip -r %s etc/%s/*", config.GetYamlConfig().OMC.Backup, zipFile, neTypeLower)
command := fmt.Sprintf("%s&&%s", scpCmd, zipCmd)
log.Debug("command:", command)
err = ExecCmd(command)
if err != nil {
log.Error("Faile to exec command:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
zipFilePath := fmt.Sprintf("%s/%s", config.GetYamlConfig().OMC.Backup, zipFile)
md5Sum, err := global.GetFileMD5Sum(zipFilePath)
if err != nil {
log.Error("Faile to md5sum:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
//log.Debug("md5Str:", md5Sum)
path := config.GetYamlConfig().OMC.Backup
neBackup := dborm.NeBackup{NeType: neTypeUpper, NeId: neId, FileName: zipFile, Path: path, Md5Sum: md5Sum}
_, err = dborm.XormInsertTableOne("ne_backup", neBackup)
if err != nil {
log.Error("Faile to XormInsertTableOne:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
//services.ResponseFileWithNameAndMD5(w, http.StatusOK, zipFile, path, md5Sum)
services.ResponseStatusOK204NoContent(w)
return
}
type ImportCMJson struct {
FileName string `json:"fileName"`
}
func ImportCmToNF(w http.ResponseWriter, r *http.Request) {
log.Debug("ImportCmToNF processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["elementTypeValue"]
if neType == "" {
log.Error("elementTypeValue is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neTypeUpper := strings.ToUpper(neType)
neTypeLower := strings.ToLower(neType)
neId := services.GetUriParamString(r, "ne_id", ",", false, false)
var fileName, path string
if services.IsJsonContentType(r) {
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
log.Debug("Body:", string(body))
importCMJson := new(ImportCMJson)
_ = json.Unmarshal(body, importCMJson)
fileName = importCMJson.FileName
path = config.GetYamlConfig().OMC.Backup
} else {
path = config.GetYamlConfig().OMC.Upload
fileName, err = services.HandleUploadFile(r, path, "")
if err != nil {
log.Error("Faile to HandleUploadFile:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
}
filePath := fmt.Sprintf("%s/%s", path, fileName)
// neInfo := new(dborm.NeInfo)
neInfo, err := dborm.XormGetNeInfo(neType, neId)
if err != nil {
log.Errorf("Failed to get ne_info:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
log.Debug("neInfo:", neInfo)
md5Sum, err := global.GetFileMD5Sum(filePath)
if err != nil {
log.Error("Faile to GetFileMD5Sum:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
//neBackup := dborm.NeBackup{NeType: neType, NeId: neId, Md5Sum: md5Sum}
//log.Debug("neBackup:", neBackup)
where := fmt.Sprintf("ne_type='%s' and ne_id='%s' and md5_sum='%s'", neTypeUpper, neId, md5Sum)
has, err := dborm.XormExistTableOne("ne_backup", where)
if err != nil {
log.Error("Faile to XormInsertTableOne:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
} else if has == false {
err = global.ErrCMInvalidBackupFile
log.Error(err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
nePath := fmt.Sprintf("%s/etc/%s", config.GetYamlConfig().OMC.Upload, neTypeLower)
isExist, err := global.PathExists(nePath)
if err != nil {
log.Errorf("Failed to stat:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
if isExist {
err = os.RemoveAll(nePath)
if err != nil {
log.Errorf("Failed to remove:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
}
unzipCmd := fmt.Sprintf("unzip -o %s -d %s", filePath, config.GetYamlConfig().OMC.Upload)
var scpCmd string
ipType := global.ParseIPAddr(neInfo.Ip)
if ipType == global.IsIPv4 {
scpCmd = fmt.Sprintf("scp -r %s/etc/%s %s@%s:%s", config.GetYamlConfig().OMC.Upload,
neTypeLower, config.GetYamlConfig().NE.User, neInfo.Ip, config.GetYamlConfig().NE.EtcDir)
} else {
scpCmd = fmt.Sprintf("scp -r %s/etc/%s %s@[%s]:%s", config.GetYamlConfig().OMC.Upload,
neTypeLower, config.GetYamlConfig().NE.User, neInfo.Ip, config.GetYamlConfig().NE.EtcDir)
}
err = ExecCmd(fmt.Sprintf("%s && %s", unzipCmd, scpCmd))
if err != nil {
log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
services.ResponseStatusOK204NoContent(w)
return
}
func DownloadNeBackupFile(w http.ResponseWriter, r *http.Request) {
log.Debug("DownloadNeBackupFile processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["neType"]
if neType == "" {
log.Error("neType is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neTypeUpper := strings.ToUpper(neType)
//neTypeLower := strings.ToLower(neType)
fileName := vars["fileName"]
if fileName == "" {
log.Error("fileName is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
sql := fmt.Sprintf("select * from ne_backup where ne_type='%s' and file_name='%s'", neTypeUpper, fileName)
neBackup, err := dborm.XormGetDataBySQL(sql)
if err != nil {
log.Error("Faile to XormGetDataBySQL:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
} else if len(*neBackup) == 0 {
err := global.ErrCMNotFoundTargetBackupFile
log.Error(err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
path := (*neBackup)[0]["path"]
md5Sum := (*neBackup)[0]["md5_sum"]
services.ResponseFileWithNameAndMD5(w, http.StatusOK, fileName, path, md5Sum)
return
}
func DeleteNeBackupFile(w http.ResponseWriter, r *http.Request) {
log.Debug("DeleteNeBackupFile processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["neType"]
if neType == "" {
log.Error("neType is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neTypeUpper := strings.ToUpper(neType)
//neTypeLower := strings.ToLower(neType)
fileName := vars["fileName"]
if fileName == "" {
log.Error("fileName is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
sql := fmt.Sprintf("select * from ne_backup where ne_type='%s' and file_name='%s'", neTypeUpper, fileName)
neBackup, err := dborm.XormGetDataBySQL(sql)
if err != nil {
log.Error("Faile to XormGetDataBySQL:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
} else if len(*neBackup) == 0 {
err := global.ErrCMNotFoundTargetBackupFile
log.Error(err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
where := fmt.Sprintf("ne_type='%s' and file_name='%s'", neTypeUpper, fileName)
affected, err := dborm.XormDeleteDataByWhere(where, "ne_backup")
if err != nil || affected == 0 {
log.Error("Faile to XormGetDataBySQL:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
path := (*neBackup)[0]["path"]
filePath := fmt.Sprintf("%s/%s", path, fileName)
err = os.Remove(filePath)
if err != nil {
log.Error("Faile to Remove:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
services.ResponseStatusOK204NoContent(w)
return
}

241
features/cm/param.go Normal file
View File

@@ -0,0 +1,241 @@
package cm
import (
"ems.agt/lib/dborm"
"ems.agt/lib/global"
"ems.agt/lib/log"
"ems.agt/lib/services"
"ems.agt/restagent/config"
"encoding/json"
"fmt"
"io"
"net/http"
"github.com/go-resty/resty/v2"
"github.com/gorilla/mux"
)
var (
// parameter config management
ParamConfigUri = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/config/{paraName}"
ParamConfigUrl = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/config/{paraName}"
)
func GetParamConfigFromNF(w http.ResponseWriter, r *http.Request) {
log.Debug("GetParamConfigFromNF processing... ")
// data := make([]map[string]interface{}, 1)
var response services.DataResponse
vars := mux.Vars(r)
neType := vars["elementTypeValue"]
if neType == "" {
log.Error("elementTypeValue is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
token, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
restHostPort := fmt.Sprintf("http://127.0.0.1:%d", config.GetYamlConfig().Rest[0].Port)
getNeInfoPattern := fmt.Sprintf(config.UriPrefix+"/databaseManagement/v1/%s/ne_info", config.GetYamlConfig().Database.Name)
getNeInfoURI := restHostPort + getNeInfoPattern
neId := services.GetUriParamString(r, "ne_id", ",", true, false)
if neId == "" {
getNeInfoURI = getNeInfoURI + fmt.Sprintf("?WHERE=status='0'+and+ne_type='%s'", neType)
} else {
getNeInfoURI = getNeInfoURI + fmt.Sprintf("?WHERE=status='0'+and+ne_type='%v'+and+ne_id+in+%v", neType, neId)
}
log.Debug("getNeInfoURI:", getNeInfoURI)
client := resty.New()
resp, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"accessToken": token}).
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Get(getNeInfoURI)
if err != nil {
log.Error("Get from database is failure!")
services.ResponseInternalServerError500NFConnectRefused(w)
return
}
log.Debug("NE info:", string(resp.Body()))
// var neList []dborm.NeInfo
neList, _ := dborm.XormParseResult(resp.Body())
if len(neList) >= 1 {
s := neList[0]
requestURI2NF := fmt.Sprintf("http://%s:%v%s", s.Ip, s.Port, r.RequestURI)
log.Debug("requestURI2NF:", requestURI2NF)
resp, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Get(requestURI2NF)
if err != nil {
log.Error("Get from NF is failure:", err)
services.ResponseInternalServerError500NFConnectRefused(w)
return
} else {
_ = json.Unmarshal(resp.Body(), &response)
}
log.Debug("response:", response)
}
services.ResponseWithJson(w, http.StatusOK, response)
}
func PostParamConfigToNF(w http.ResponseWriter, r *http.Request) {
log.Debug("PostParamConfigToNF processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["elementTypeValue"]
if neType == "" {
log.Error("elementTypeValue is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neId := services.GetUriParamString(r, "ne_id", ",", false, false)
// no, _ := strconv.ParseInt(neId, 10, 64)
neInfo, err := dborm.XormGetNeInfo(neType, neId)
if err != nil {
log.Error("dborm.XormGetNeInfo is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI)
log.Debug("requestURI2NF: POST ", requestURI2NF)
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
client := resty.New()
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
SetBody(body).
Post(requestURI2NF)
if err != nil {
log.Error("Failed to POST to NF:", err)
services.ResponseInternalServerError500NFConnectRefused(w)
return
}
services.ResponseWithJson(w, response.StatusCode(), response)
}
func PutParamConfigToNF(w http.ResponseWriter, r *http.Request) {
log.Debug("PutParamConfigToNF processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["elementTypeValue"]
if neType == "" {
log.Error("elementTypeValue is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neId := services.GetUriParamString(r, "ne_id", ",", false, false)
// no, _ := strconv.ParseInt(neId, 10, 64)
neInfo, err := dborm.XormGetNeInfo(neType, neId)
if err != nil {
log.Error("dborm.XormGetNeInfo is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI)
log.Debug("requestURI2NF: PUT ", requestURI2NF)
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
client := resty.New()
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
SetBody(body).
Put(requestURI2NF)
if err != nil {
log.Error("Put to NF failed:", err)
services.ResponseInternalServerError500NFConnectRefused(w)
return
}
services.ResponseWithJson(w, response.StatusCode(), response)
}
func DeleteParamConfigToNF(w http.ResponseWriter, r *http.Request) {
log.Debug("DeleteParamConfigToNF processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["elementTypeValue"]
if neType == "" {
log.Error("elementTypeValue is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neId := services.GetUriParamString(r, "ne_id", ",", false, false)
// no, _ := strconv.ParseInt(neId, 10, 64)
neInfo, err := dborm.XormGetNeInfo(neType, neId)
if err != nil {
log.Error("dborm.XormGetNeInfo is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI)
log.Debug("requestURI2NF: DELETE ", requestURI2NF)
client := resty.New()
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Delete(requestURI2NF)
if err != nil {
log.Error("Failed to delete parameter:", err)
services.ResponseInternalServerError500NFConnectRefused(w)
return
}
services.ResponseWithJson(w, response.StatusCode(), response)
}

575
features/cm/software.go Normal file
View File

@@ -0,0 +1,575 @@
package cm
import (
"fmt"
"net/http"
"os"
"os/exec"
"strconv"
"strings"
"ems.agt/lib/dborm"
"ems.agt/lib/global"
"ems.agt/lib/log"
"ems.agt/lib/services"
"ems.agt/restagent/config"
"github.com/gorilla/mux"
)
const (
SoftwareStatusUploaded = "Uploaded"
SoftwareStatusInactive = "Inactive"
SoftwareStatusActive = "Active"
DigestsSignOkString = "digests signatures OK"
)
var (
UriSoftware = config.UriPrefix + "/systemManagement/{apiVersion}/{neType}/software/{version}"
UriSoftwareNE = config.UriPrefix + "/systemManagement/{apiVersion}/{neType}/software/{version}/{neId}"
)
func UploadSoftwareFile(w http.ResponseWriter, r *http.Request) {
log.Debug("UploadSoftwareFile processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Http request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["neType"]
if neType == "" {
log.Error("neType is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neTypeUpper := strings.ToUpper(neType)
neTypeLower := strings.ToLower(neType)
version := vars["version"]
if version == "" {
log.Error("version is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
md5Param := services.GetUriParamString(r, "md5Sum", ",", false, false)
// body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
// if err != nil {
// log.Error("io.ReadAll is failed:", err)
// services.ResponseNotFound404UriNotExist(w, r)
// return
// }
// neSWBody := new(dborm.NeSoftware)
// _ = json.Unmarshal(body, neSWBody)
// log.Trace("neSoftware:", neSWBody)
softwarePath := fmt.Sprintf("%s/%s", config.GetYamlConfig().OMC.Software, neTypeLower)
fileName, err := services.HandleUploadFile(r, softwarePath, "")
if err != nil {
log.Error("Faile to HandleUploadFile:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
filePath := fmt.Sprintf("%s/%s", softwarePath, fileName)
md5File, err := global.GetFileMD5Sum(filePath)
if err != nil {
log.Error("Faile to GetFileMD5Sum:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
if md5File != md5Param {
err = global.ErrCMNotMatchMD5File
log.Error(err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
if config.GetYamlConfig().OMC.CheckSign {
cmd := exec.Command("rpm", "-K", filePath)
out, err := cmd.CombinedOutput()
log.Debugf("Exec outpout:%s", string(out))
if err != nil {
log.Error("Failed to execute rpm:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
if !strings.Contains(string(out), DigestsSignOkString) {
err = global.ErrCMNotMatchSignFile
log.Error(err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
}
//neBackup := dborm.NeBackup{NeType: neType, NeId: neId, Md5Sum: md5Sum}
//log.Debug("neBackup:", neBackup)
where := fmt.Sprintf("ne_type='%s' and version='%s'", neTypeUpper, version)
has, err := dborm.XormExistTableOne("ne_software", where)
if err != nil {
log.Error("Faile to XormInsertTableOne:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
} else if has == true {
err = global.ErrCMExistSoftwareFile
log.Error(err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
neSoftware := dborm.NeSoftware{
NeType: neTypeUpper,
FileName: fileName,
Path: softwarePath,
Version: version,
Md5Sum: md5Param,
Comment: neType + " 5GC " + version,
//Comment: neSWBody.Comment,
}
_, err = dborm.XormInsertTableOne("ne_software", neSoftware)
if err != nil {
log.Error("Faile to XormInsertTableOne:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
services.ResponseStatusOK204NoContent(w)
return
}
func DownloadSoftwareFile(w http.ResponseWriter, r *http.Request) {
log.Debug("DownloadSoftwareFile processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["neType"]
if neType == "" {
log.Error("neType is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neTypeUpper := strings.ToUpper(neType)
//neTypeLower := strings.ToLower(neType)
version := vars["version"]
if version == "" {
log.Error("version is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version)
neSoftware, err := dborm.XormGetDataBySQL(sql)
if err != nil {
log.Error("Faile to XormGetDataBySQL:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
} else if len(*neSoftware) == 0 {
err := global.ErrCMNotFoundTargetSoftware
log.Error(err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
fileName := (*neSoftware)[0]["file_name"]
path := (*neSoftware)[0]["path"]
md5Sum := (*neSoftware)[0]["md5_sum"]
services.ResponseFileWithNameAndMD5(w, http.StatusOK, fileName, path, md5Sum)
return
}
func DeleteSoftwareFile(w http.ResponseWriter, r *http.Request) {
log.Debug("DeleteSoftwareFile processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["neType"]
if neType == "" {
log.Error("neType is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neTypeUpper := strings.ToUpper(neType)
//neTypeLower := strings.ToLower(neType)
version := vars["version"]
if version == "" {
log.Error("version is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version)
neSoftware, err := dborm.XormGetDataBySQL(sql)
if err != nil {
log.Error("Faile to XormGetDataBySQL:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
} else if len(*neSoftware) == 0 {
err := global.ErrCMNotFoundTargetSoftware
log.Error(err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
where := fmt.Sprintf("ne_type='%s' and version='%s'", neTypeUpper, version)
affected, err := dborm.XormDeleteDataByWhere(where, "ne_software")
if err != nil || affected == 0 {
log.Error("Faile to XormGetDataBySQL:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
fileName := (*neSoftware)[0]["file_name"]
path := (*neSoftware)[0]["path"]
filePath := fmt.Sprintf("%s/%s", path, fileName)
err = os.Remove(filePath)
if err != nil {
log.Error("Faile to Remove:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
services.ResponseStatusOK204NoContent(w)
return
}
func DistributeSoftwareToNF(w http.ResponseWriter, r *http.Request) {
log.Debug("DistributeSoftwareFile processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Http request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["neType"]
if neType == "" {
log.Error("neType is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neTypeUpper := strings.ToUpper(neType)
neTypeLower := strings.ToLower(neType)
version := vars["version"]
if version == "" {
log.Error("version is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neId := vars["neId"]
if version == "" {
log.Error("neId is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neInfo, err := dborm.XormGetNeInfo(neTypeUpper, neId)
if err != nil {
log.Error("dborm.XormGetNeInfo is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version)
neSoftware, err := dborm.XormGetDataBySQL(sql)
if err != nil {
log.Error("Faile to XormGetDataBySQL:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
} else if len(*neSoftware) == 0 {
err := global.ErrCMNotFoundTargetSoftware
log.Error(err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
log.Debug("neSoftware:", neSoftware)
sql = fmt.Sprintf("select * from ne_version where ne_type='%s' and ne_id='%s'", neTypeUpper, neId)
neVersion, err := dborm.XormGetDataBySQL(sql)
if err != nil {
log.Error("Faile to XormGetDataBySQL:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
log.Debug("neVersion:", neVersion)
sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip)
mkdirCmd := fmt.Sprintf("mkdir -p %s/software/%s", config.GetYamlConfig().NE.OmcDir, neTypeLower)
cmd := exec.Command("ssh", sshHost, mkdirCmd)
out, err := cmd.CombinedOutput()
log.Tracef("Exec output: %v", string(out))
if err != nil {
log.Error("Faile to exec cmd:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
fileName := (*neSoftware)[0]["file_name"]
path := (*neSoftware)[0]["path"]
srcFile := fmt.Sprintf("%s/%s", path, fileName)
dstDir := fmt.Sprintf("%s@%s:%s/software/%s", config.GetYamlConfig().NE.User,
neInfo.Ip, config.GetYamlConfig().NE.OmcDir, neTypeLower)
cmd = exec.Command("scp", "-r", srcFile, dstDir)
out, err = cmd.CombinedOutput()
log.Tracef("Exec output: %v", string(out))
if err != nil {
log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
if len(*neVersion) == 0 {
neVersionData := dborm.NeVersion{
NeType: neTypeUpper,
NeId: neInfo.NeId,
Version: (*neSoftware)[0]["version"],
FilePath: fmt.Sprintf("%s/software/%s/%s", config.GetYamlConfig().NE.OmcDir, neTypeLower, fileName),
PreVersion: "",
PreFile: "",
Status: SoftwareStatusInactive,
}
_, err = dborm.XormInsertTableOne("ne_version", neVersionData)
if err != nil {
log.Error("Faile to XormInsertTableOne:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
} else {
idNeVersion, err := strconv.Atoi((*neVersion)[0]["id"])
neVersionData := dborm.NeVersion{
NeType: neTypeUpper,
NeId: neInfo.NeId,
Version: (*neSoftware)[0]["version"],
FilePath: fmt.Sprintf("%s/software/%s/%s", config.GetYamlConfig().NE.OmcDir, neTypeLower, fileName),
PreVersion: (*neVersion)[0]["version"],
PreFile: (*neVersion)[0]["file_path"],
Status: SoftwareStatusInactive,
}
_, err = dborm.XormUpdateTableById(idNeVersion, "ne_version", neVersionData)
if err != nil {
log.Error("Faile to UpdateTableById:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
}
services.ResponseStatusOK204NoContent(w)
return
}
func ActiveSoftwareToNF(w http.ResponseWriter, r *http.Request) {
log.Debug("ActiveSoftwareToNF processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Http request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["neType"]
if neType == "" {
log.Error("neType is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neTypeUpper := strings.ToUpper(neType)
//neTypeLower := strings.ToLower(neType)
version := vars["version"]
if version == "" {
log.Error("version is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neId := vars["neId"]
if version == "" {
log.Error("neId is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neInfo, err := dborm.XormGetNeInfo(neTypeUpper, neId)
if err != nil {
log.Error("dborm.XormGetNeInfo is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version)
neSoftware, err := dborm.XormGetDataBySQL(sql)
if err != nil {
log.Error("Faile to XormGetDataBySQL:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
} else if len(*neSoftware) == 0 {
err := global.ErrCMNotFoundTargetSoftware
log.Error(err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
log.Debug("neVersion:", neSoftware)
sql = fmt.Sprintf("select * from ne_version where ne_type='%s' and ne_id='%s' and version='%s'", neTypeUpper, neId, version)
neVersion, err := dborm.XormGetDataBySQL(sql)
if err != nil {
log.Error("Faile to XormGetDataBySQL:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
} else if len(*neVersion) == 0 {
err := global.ErrCMNotFoundTargetNeVersion
log.Error(err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
log.Debug("neVersion:", neVersion)
if config.GetYamlConfig().OMC.TestMode == false {
filePath := (*neVersion)[0]["file_path"]
sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip)
rpmCmd := fmt.Sprintf("rpm -Uvh '%s'", filePath)
cmd := exec.Command("ssh", sshHost, rpmCmd)
out, err := cmd.CombinedOutput()
log.Tracef("Exec output: %v", string(out))
if err != nil {
log.Error("Faile to execute rpm command:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
}
idNeVersion, err := strconv.Atoi((*neVersion)[0]["id"])
neVersionData := dborm.NeVersion{
Status: SoftwareStatusActive,
}
_, err = dborm.XormUpdateTableById(idNeVersion, "ne_version", neVersionData)
if err != nil {
log.Error("Faile to UpdateTableById:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
services.ResponseStatusOK204NoContent(w)
return
}
func RollBackSoftwareToNF(w http.ResponseWriter, r *http.Request) {
log.Debug("ActiveSoftwareToNF processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Http request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["neType"]
if neType == "" {
log.Error("neType is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neTypeUpper := strings.ToUpper(neType)
//neTypeLower := strings.ToLower(neType)
version := vars["version"]
if version == "" {
log.Error("version is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neId := vars["neId"]
if version == "" {
log.Error("neId is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
neInfo, err := dborm.XormGetNeInfo(neTypeUpper, neId)
if err != nil {
log.Error("dborm.XormGetNeInfo is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
sql := fmt.Sprintf("select * from ne_version where ne_type='%s' and ne_id='%s'", neTypeUpper, neId)
neVersion, err := dborm.XormGetDataBySQL(sql)
if err != nil {
log.Error("Faile to XormGetDataBySQL:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
} else if len(*neVersion) == 0 {
err := global.ErrCMNotFoundTargetNeVersion
log.Error(err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
log.Debug("neVersion:", neVersion)
filePath := (*neVersion)[0]["pre_file"]
if filePath == "" {
err := global.ErrCMNotFoundRollbackNeVersion
log.Error(err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
if config.GetYamlConfig().OMC.TestMode == false {
sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip)
rpmCmd := fmt.Sprintf("rpm -Uvh --oldpackage '%s'", filePath)
cmd := exec.Command("ssh", sshHost, rpmCmd)
out, err := cmd.CombinedOutput()
log.Tracef("Exec output: %v", string(out))
if err != nil {
log.Error("Faile to execute rpm command:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
}
idNeVersion, err := strconv.Atoi((*neVersion)[0]["id"])
neVersionData := dborm.NeVersion{
Version: (*neVersion)[0]["pre_version"],
FilePath: (*neVersion)[0]["pre_file"],
PreVersion: "-",
PreFile: "-",
NewVersion: (*neVersion)[0]["version"],
NewFile: (*neVersion)[0]["file_path"],
Status: SoftwareStatusActive,
}
_, err = dborm.XormUpdateTableById(idNeVersion, "ne_version", neVersionData)
if err != nil {
log.Error("Faile to UpdateTableById:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
services.ResponseStatusOK204NoContent(w)
return
}

671
features/dbrest/dbrest.go Normal file
View File

@@ -0,0 +1,671 @@
package dbrest
import (
"encoding/json"
"fmt"
"io"
"net/http"
"regexp"
"strings"
"time"
"ems.agt/lib/dborm"
"ems.agt/lib/global"
"ems.agt/lib/log"
"ems.agt/lib/services"
"ems.agt/restagent/config"
"github.com/gorilla/mux"
"xorm.io/xorm"
)
type XormResponse struct {
Data interface{} `json:"data"`
}
type XormInsertResponse struct {
Data interface{} `json:"data"`
}
var (
// database management rest pattern discard
XormGetDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/elementType/{databaseName}/objectType/{tableName}"
XormSelectDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/select/{databaseName}/{tableName}"
XormInsertDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/insert/{databaseName}/{tableName}"
XormUpdateDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/update/{databaseName}/{tableName}"
XormDeleteDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/delete/{databaseName}/{tableName}"
XormCommonUri = config.UriPrefix + "/databaseManagement/{apiVersion}/{databaseName}/{tableName}" // for internal
XormExtDataUri = config.UriPrefix + "/dataManagement/{apiVersion}/{dataStorage}/{dataObject}" // for external
XormDataSQLUri = config.UriPrefix + "/dataManagement/{apiVersion}/{dataStorage}/{dataObject}" // for external
)
var xormResponse XormResponse
// func init() {
// // database management
// routes.Register("GET", XormGetDataUri, DatabaseGetData, nil)
// routes.Register("GET", XormSelectDataUri, DatabaseGetData, nil)
// routes.Register("POST", XormInsertDataUri, DatabaseInsertData, nil)
// routes.Register("PUT", XormUpdateDataUri, DatabaseUpdateData, nil)
// routes.Register("DELETE", XormDeleteDataUri, DatabaseDeleteData, nil)
// // corss orgin domain
// routes.Register("OPTIONS", XormGetDataUri, routes.OptionsProc, nil)
// routes.Register("OPTIONS", XormSelectDataUri, routes.OptionsProc, nil)
// routes.Register("OPTIONS", XormInsertDataUri, routes.OptionsProc, nil)
// routes.Register("OPTIONS", XormUpdateDataUri, routes.OptionsProc, nil)
// routes.Register("OPTIONS", XormDeleteDataUri, routes.OptionsProc, nil)
// routes.Register("GET", XormCommonUri, DatabaseGetData, nil)
// routes.Register("POST", XormCommonUri, DatabaseInsertData, nil)
// routes.Register("PUT", XormCommonUri, DatabaseUpdateData, nil)
// routes.Register("DELETE", XormCommonUri, DatabaseDeleteData, nil)
// // corss orgin domain
// routes.Register("OPTIONS", XormInsertDataUri, routes.OptionsProc, nil)
// routes.Register("OPTIONS", XormUpdateDataUri, routes.OptionsProc, nil)
// routes.Register("OPTIONS", XormDeleteDataUri, routes.OptionsProc, nil)
// routes.Register("OPTIONS", XormCommonUri, routes.OptionsProc, nil)
// }
var XEngine *xorm.Engine
type DatabaseClient struct {
dbType string
dbUrl string
dbConnMaxLifetime time.Duration
dbMaxIdleConns int
dbMaxOpenConns int
IsShowSQL bool
XEngine *xorm.Engine
}
var DbClient DatabaseClient
func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) error {
DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
dbUser, dbPassword, dbHost, dbPort, dbName)
DbClient.dbType = dbType
DbClient.dbConnMaxLifetime = 0
DbClient.dbMaxIdleConns = 0
DbClient.dbMaxOpenConns = 0
if log.GetLevel() == log.LOG_TRACE {
DbClient.IsShowSQL = true
}
log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s??charset=utf8&parseTime=true&loc=Local",
dbType, dbUser, dbHost, dbPort, dbName)
var err error
DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl)
if err != nil {
log.Error("Failed to connet database:", err)
return err
}
DbClient.XEngine.SetConnMaxLifetime(DbClient.dbConnMaxLifetime)
DbClient.XEngine.SetMaxIdleConns(DbClient.dbMaxIdleConns)
DbClient.XEngine.SetMaxOpenConns(DbClient.dbMaxOpenConns)
if DbClient.IsShowSQL {
DbClient.XEngine.ShowSQL(true)
}
XEngine = DbClient.XEngine
return nil
}
func GetUriSQLArray(r *http.Request) []string {
vars := r.URL.Query()
s, ok := vars["SQL"]
if !ok {
log.Info("SQL is not exist")
return nil
}
var sa []string
for _, r := range s {
if r != "" {
sa = append(sa, r)
}
}
log.Debug("SQL array:", sa)
return sa
}
// Get table name from SQL
func GetTableNameFromSQL(s string) string {
ls := strings.ToLower(s)
i1 := strings.Index(ls, "from")
i2 := strings.Index(ls, "where")
var ts string
if i1 > 0 {
if i2 > 0 && i2 > i1 {
ts = ls[i1+4 : i2]
}
if i2 < 0 {
ts = ls[i1+4:]
}
}
tn := strings.Trim(ts, " ")
log.Debug("i1:", i1, "i2:", i2, "tn:", tn)
return tn
}
func GetTableName(sql string) string {
ls := strings.ToLower(sql)
re := regexp.MustCompile(`from\s+(\S+)`)
matches := re.FindStringSubmatch(ls)
if len(matches) < 2 {
return ""
}
return matches[1]
}
func IsQuerySQL(s string) bool {
ts := strings.Trim(strings.ToLower(s), " ")
if strings.Index(ts, "select") != 0 {
return false
}
return true
}
// xorm Get data from database
func ExtDatabaseExecSQL(w http.ResponseWriter, r *http.Request) {
log.Debug("ExtDatabaseExecSQL processing... ")
var sql []string
var err error
_, err = services.CheckExtValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
tblName := vars["dataObject"]
sql = GetUriSQLArray(r)
// select as must, todo ...
if sql == nil {
wc := services.GetUriLocString(r)
if wc == "" {
sql = append(sql, fmt.Sprintf("select * from %s", tblName))
} else {
sql = append(sql, fmt.Sprintf("select * from %s where %s", tblName, wc))
}
}
ls := services.ExtGetUriPageLimitString(r)
// data := make([]map[string]interface{}, 0)
// xormResponse := make([]map[string]interface{}, len(sql))
var xormResponse XormResponse
data := make([]map[string]interface{}, 0)
for i, s := range sql {
log.Tracef("SQL[%d]: %s", i, sql[i])
rows := make([]map[string]interface{}, 0)
mapRows := make(map[string]interface{})
if s != "" {
// err = XEngine.SQL(s).Find(&rows)
// if IsQuerySQL(s) == false {
// services.ResponseNotAcceptable406QuerySQLError(w)
// return
// }
querySQL := s
if i == (len(sql) - 1) {
querySQL = querySQL + " " + ls
}
log.Debug("querySQL:", querySQL)
rows, err = DbClient.XEngine.QueryInterface(querySQL)
if err != nil {
log.Error("SQL failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
tableName := GetTableName(s)
log.Debugf("s:%s tableName:%s", s, tableName)
mapRows[tableName] = rows
data = append(data, mapRows)
log.Trace("data:", data)
}
i++
}
xormResponse.Data = data
services.ResponseWithJson(w, http.StatusOK, xormResponse)
}
// xorm Get data from database
func ExtDatabaseGetData(w http.ResponseWriter, r *http.Request) {
log.Debug("ExtDatabaseGetData processing... ")
var sql []string
token, err := services.CheckExtValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
dbname := vars["dataStorage"]
tbname := vars["dataObject"]
log.Debugf("token:%s, method:%s, dbname:%s, tbname:%s", token, r.Method, dbname, tbname)
exist, err := dborm.IsPermissionDeny(token, strings.ToLower(r.Method), dbname, tbname)
if err != nil {
log.Error("Failed to get permission:", err)
services.ResponseForbidden403NotPermission(w)
return
}
if !exist {
log.Error("Not permission!")
services.ResponseForbidden403NotPermission(w)
return
}
sql = GetUriSQLArray(r)
// select as must, todo ...
if sql == nil {
wc := services.GetUriLocString(r)
if wc == "" {
sql = append(sql, fmt.Sprintf("select * from %s", tbname))
} else {
sql = append(sql, fmt.Sprintf("select * from %s where %s", tbname, wc))
}
}
ls := services.ExtGetUriPageLimitString(r)
// data := make([]map[string]interface{}, 0)
// xormResponse := make([]map[string]interface{}, len(sql))
var xormResponse XormResponse
data := make([]map[string]interface{}, 0)
for i, s := range sql {
log.Tracef("SQL[%d]: %s", i, sql[i])
rows := make([]map[string]interface{}, 0)
mapRows := make(map[string]interface{})
if s != "" {
// err = XEngine.SQL(s).Find(&rows)
if IsQuerySQL(s) == false {
services.ResponseNotAcceptable406QuerySQLError(w)
return
}
querySQL := s
if i == (len(sql) - 1) {
querySQL = querySQL + " " + ls
}
log.Debug("querySQL:", querySQL)
rows, err = DbClient.XEngine.QueryInterface(querySQL)
if err != nil {
log.Error("SQL failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
tableName := GetTableName(s)
log.Debugf("s:%s tableName:%s", s, tableName)
mapRows[tableName] = rows
data = append(data, mapRows)
log.Trace("data:", data)
}
i++
}
xormResponse.Data = data
services.ResponseWithJson(w, http.StatusOK, xormResponse)
}
func ExtDatabaseInsertData(w http.ResponseWriter, r *http.Request) {
log.Debug("ExtDatabaseInsertData processing... ")
token, err := services.CheckExtValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小
if err != nil {
log.Error("io.ReadAll failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
vars := mux.Vars(r)
dbname := vars["dataStorage"]
tbname := vars["dataObject"]
log.Debugf("token:%s, method:%s, dbname:%s, tbname:%s", token, r.Method, dbname, tbname)
exist, err := dborm.IsPermissionDeny(token, strings.ToLower(r.Method), dbname, tbname)
if err != nil {
log.Error("Failed to get permission:", err)
services.ResponseForbidden403NotPermission(w)
return
}
if !exist {
log.Error("Not permission!")
services.ResponseForbidden403NotPermission(w)
return
}
log.Debug("Request body:", string(body), "dataObject:", tbname)
insertData := make(map[string]interface{})
_ = json.Unmarshal(body, &insertData)
tn, sql := dborm.ConstructInsertSQL(tbname, insertData)
log.Tracef("tn: %s sql :%s", tn, sql)
xSession := DbClient.XEngine.NewSession()
defer xSession.Close()
var affected int64
for _, s := range sql {
res, err := xSession.Exec(s)
if err != nil {
log.Error("Insert failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
n, _ := res.RowsAffected()
affected = affected + n
}
xSession.Commit()
// affected, err := InsertDataWithJson(insertData)
mapRow := make(map[string]interface{})
row := map[string]interface{}{"affectedRows": affected}
mapRow[tn] = row
// xormResponse.Data = mapRow
services.ResponseWithJson(w, http.StatusOK, mapRow)
}
func ExtDatabaseUpdateData(w http.ResponseWriter, r *http.Request) {
log.Debug("ExtDatabaseUpdateData processing... ")
token, err := services.CheckExtValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
dbname := vars["dataStorage"]
tbname := vars["dataObject"]
log.Debugf("token:%s, method:%s, dbname:%s, tbname:%s", token, r.Method, dbname, tbname)
exist, err := dborm.IsPermissionDeny(token, strings.ToLower(r.Method), dbname, tbname)
if err != nil {
log.Error("Failed to get permission:", err)
services.ResponseForbidden403NotPermission(w)
return
}
if !exist {
log.Error("Not permission!")
services.ResponseForbidden403NotPermission(w)
return
}
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
wc := services.GetUriLocString(r)
log.Debug("Request body:", string(body), "Tablename:", tbname, "wc:", wc)
updateData := make(map[string]interface{})
_ = json.Unmarshal(body, &updateData)
tn, sql := dborm.ConstructUpdateSQL(tbname, updateData, wc)
log.Tracef("tn: %s sql :%s", tn, sql)
xSession := DbClient.XEngine.NewSession()
defer xSession.Close()
var affected int64
for _, s := range sql {
res, err := xSession.Exec(s)
if err != nil {
log.Error("Update failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
n, _ := res.RowsAffected()
affected = affected + n
}
xSession.Commit()
mapRow := make(map[string]interface{})
row := map[string]interface{}{"affectedRows": affected}
mapRow[tn] = row
services.ResponseWithJson(w, http.StatusOK, mapRow)
}
func ExtDatabaseDeleteData(w http.ResponseWriter, r *http.Request) {
log.Debug("ExtDatabaseDeleteData processing... ")
token, err := services.CheckExtValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
dbname := vars["dataStorage"]
tbname := vars["dataObject"]
log.Debugf("token:%s, method:%s, dbname:%s, tbname:%s", token, r.Method, dbname, tbname)
exist, err := dborm.IsPermissionDeny(token, strings.ToLower(r.Method), dbname, tbname)
if err != nil {
log.Error("Failed to get permission:", err)
services.ResponseForbidden403NotPermission(w)
return
}
if !exist {
log.Error("Not permission!")
services.ResponseForbidden403NotPermission(w)
return
}
wc := services.GetUriLocString(r)
log.Debug("Table name:", tbname, "wc:", wc)
sql := dborm.ConstructDeleteSQL(tbname, wc)
xSession := DbClient.XEngine.NewSession()
defer xSession.Close()
res, err := xSession.Exec(sql)
if err != nil {
log.Error("Update failed, err:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
affected, _ := res.RowsAffected()
xSession.Commit()
mapRow := make(map[string]interface{})
row := map[string]interface{}{"affectedRows": affected}
mapRow["data"] = row
services.ResponseWithJson(w, http.StatusOK, mapRow)
}
// xorm Get data from database
func DatabaseGetData(w http.ResponseWriter, r *http.Request) {
log.Debug("DatabaseGetData processing... ")
var sql []string
var err error
_, err = services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
tblName := vars["tableName"]
sql = GetUriSQLArray(r)
// select as must, todo ...
if sql == nil {
wc := services.GetUriWhereString(r)
if wc == "" {
sql = append(sql, fmt.Sprintf("select * from %s", tblName))
} else {
sql = append(sql, fmt.Sprintf("select * from %s where %s", tblName, wc))
}
}
ls := services.GetUriPageLimitString(r)
// data := make([]map[string]interface{}, 0)
// xormResponse := make([]map[string]interface{}, len(sql))
var xormResponse XormResponse
data := make([]map[string]interface{}, 0)
for i, s := range sql {
log.Tracef("SQL[%d]: %s", i, sql[i])
rows := make([]map[string]interface{}, 0)
mapRows := make(map[string]interface{})
if s != "" {
// err = XEngine.SQL(s).Find(&rows)
if IsQuerySQL(s) == false {
services.ResponseNotAcceptable406QuerySQLError(w)
return
}
querySQL := s
if i == (len(sql) - 1) {
querySQL = querySQL + " " + ls
}
log.Debug("querySQL:", querySQL)
rows, err = DbClient.XEngine.QueryInterface(querySQL)
if err != nil {
log.Error("SQL failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
tableName := GetTableName(s)
log.Debugf("s:%s tableName:%s", s, tableName)
mapRows[tableName] = rows
data = append(data, mapRows)
log.Trace("data:", data)
}
i++
}
xormResponse.Data = data
services.ResponseWithJson(w, http.StatusOK, xormResponse)
}
func DatabaseInsertData(w http.ResponseWriter, r *http.Request) {
log.Debug("DatabaseInsertData processing... ")
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小
if err != nil {
log.Error("io.ReadAll failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
vars := mux.Vars(r)
tableName := vars["tableName"]
log.Debug("Request body:", string(body), "tableName:", tableName)
insertData := make(map[string]interface{})
_ = json.Unmarshal(body, &insertData)
tn, sql := dborm.ConstructInsertSQL(tableName, insertData)
log.Tracef("tn: %s sql :%s", tn, sql)
xSession := DbClient.XEngine.NewSession()
defer xSession.Close()
var affected int64
for _, s := range sql {
res, err := xSession.Exec(s)
if err != nil {
log.Error("Insert failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
n, _ := res.RowsAffected()
affected = affected + n
}
xSession.Commit()
// affected, err := InsertDataWithJson(insertData)
mapRow := make(map[string]interface{})
row := map[string]interface{}{"affectedRows": affected}
mapRow[tn] = row
// xormResponse.Data = mapRow
services.ResponseWithJson(w, http.StatusOK, mapRow)
}
func DatabaseUpdateData(w http.ResponseWriter, r *http.Request) {
log.Debug("DatabaseUpdateData processing... ")
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
vars := mux.Vars(r)
tblName := vars["tableName"]
wc := services.GetUriWhereString(r)
log.Debug("Request body:", string(body), "Table name:", tblName, "wc:", wc)
updateData := make(map[string]interface{})
_ = json.Unmarshal(body, &updateData)
tn, sql := dborm.ConstructUpdateSQL(tblName, updateData, wc)
log.Tracef("tn: %s sql :%s", tn, sql)
xSession := DbClient.XEngine.NewSession()
defer xSession.Close()
var affected int64
for _, s := range sql {
res, err := xSession.Exec(s)
if err != nil {
log.Error("Update failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
n, _ := res.RowsAffected()
affected = affected + n
}
xSession.Commit()
mapRow := make(map[string]interface{})
row := map[string]interface{}{"affectedRows": affected}
mapRow[tn] = row
services.ResponseWithJson(w, http.StatusOK, mapRow)
}
func DatabaseDeleteData(w http.ResponseWriter, r *http.Request) {
log.Debug("DatabaseDeleteData processing... ")
vars := mux.Vars(r)
tblName := vars["tableName"]
wc := services.GetUriWhereString(r)
log.Debug("Table name:", tblName, "wc:", wc)
sql := dborm.ConstructDeleteSQL(tblName, wc)
xSession := DbClient.XEngine.NewSession()
defer xSession.Close()
res, err := xSession.Exec(sql)
if err != nil {
log.Error("Update failed, err:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
affected, _ := res.RowsAffected()
xSession.Commit()
mapRow := make(map[string]interface{})
row := map[string]interface{}{"affectedRows": affected}
mapRow["data"] = row
services.ResponseWithJson(w, http.StatusOK, mapRow)
}

126
features/file/file.go Normal file
View File

@@ -0,0 +1,126 @@
package file
import (
"net/http"
"ems.agt/lib/log"
"ems.agt/lib/services"
"ems.agt/restagent/config"
"github.com/gorilla/mux"
)
var (
// parameter config management
UriFile = config.UriPrefix + "/fileManagement/{apiVersion}/{location}/file"
)
// func init() {
// routes.Register("POST", UriFile, UploadFile, nil)
// routes.Register("GET", UriFile, DownloadFile, nil)
// routes.Register("DELETE", UriFile, DeleteFile, nil)
// }
func UploadFile(w http.ResponseWriter, r *http.Request) {
log.Debug("UploadFile processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Http request error:", err)
return
}
vars := mux.Vars(r)
location := vars["location"]
if location == "" {
log.Error("location is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
params := r.URL.Query()
rename, ok := params["rename"]
if !ok {
log.Info("rename parameter is not exist")
}
log.Debug("rename:", rename)
var path, fileName string
if len(rename) > 0 {
fileName = rename[0]
}
if location == "upload" {
path = config.GetYamlConfig().OMC.Upload
fileName, err = services.HandleUploadFile(r, path, fileName)
if err != nil {
log.Error("Faile to HandleUploadFile:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
} else {
path = config.GetYamlConfig().OMC.FrontUpload
fileName, err = services.HandleUploadFile(r, path, fileName)
if err != nil {
log.Error("Faile to HandleUploadFile:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
}
log.Debugf("upload file=%s to path=%s", fileName, path)
services.ResponseStatusOK204NoContent(w)
return
}
func DownloadFile(w http.ResponseWriter, r *http.Request) {
log.Debug("DownloadFile processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
location := vars["location"]
if location == "" {
log.Error("location is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
params := r.URL.Query()
fileNames, ok := params["loc"]
if !ok {
log.Info("loc parameter is not exist")
}
var path string
if location == "upload" {
path = config.GetYamlConfig().OMC.Upload
} else {
path = config.GetYamlConfig().OMC.FrontUpload
}
for _, fileName := range fileNames {
services.ResponseFileWithNameAndMD5(w, http.StatusOK, fileName, path, "")
}
return
}
func DeleteFile(w http.ResponseWriter, r *http.Request) {
log.Debug("DeleteFile processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["neType"]
if neType == "" {
log.Error("neType is empty")
services.ResponseNotFound404UriNotExist(w, r)
return
}
services.ResponseStatusOK204NoContent(w)
return
}

669
features/fm/alarm.go Normal file
View File

@@ -0,0 +1,669 @@
package fm
import (
"database/sql"
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"strings"
"time"
"ems.agt/lib/dborm"
"ems.agt/lib/global"
"ems.agt/lib/log"
"ems.agt/lib/services"
"ems.agt/restagent/config"
"xorm.io/xorm"
"github.com/go-resty/resty/v2"
_ "github.com/go-sql-driver/mysql"
"github.com/gorilla/mux"
)
const (
AlarmStatusClear = 0
AlarmStatusActive = 1
)
const (
ClearTypeUnclear = 0
ClearTypeAutoClear = 1
ClearTypeManualClear = 2
)
const (
AckStateUnacked = 0
AckStateAcked = 1
)
const (
AlarmTypeCommunicationAlarm = 1
AlarmTypeEquipmentAlarm = 2
AlarmTypeProcessingFailure = 3
AlarmTypeEnvironmentalAlarm = 4
AlarmTypeQualityOfServiceAlarm = 5
)
const (
AlarmPerceivedSeverityCritical = 1
AlarmPerceivedSeverityMajor = 2
AlarmPerceivedSeverityMinor = 3
AlarmPerceivedSeverityWarning = 4
AlarmPerceivedSeverityEvent = 5
)
const (
AlarmSeqBeginNumber = 1
)
type Response struct {
Data interface{} `json:"data"`
}
type Alarm struct {
AlarmSeq int `json:"alarmSeq"`
AlarmId string `json:"alarmId" xorm:"alarm_id"`
NeId string `json:"neId"`
AlarmCode int `json:"alarmCode"`
AlarmTitle string `json:"alarmTitle"`
EventTime string `json:"eventTime"`
AlarmType string `json:"alarmType"`
OrigSeverity string `json:"origSeverity"`
PerceivedSeverity string `json:"perceivedSeverity"`
PVFlag string `json:"pvFlag" xorm:"pv_flag"`
NeName string `json:"neName"`
NeType string `json:"neType"`
ObjectUid string `json:"objectUid" xorm:"object_uid"`
ObjectName string `json:"objectName" xorm:"object_name"`
ObjectType string `json:"objectType" xorm:"object_type"`
LocationInfo string `json:"locationInfo"`
Province string `json:"province"`
AlarmStatus int `json:"alarmStatus"`
SpecificProblem string `json:"specificProblem"`
SpecificProblemID string `json:"specificProblemID" xorm:"specific_problem_id"`
AddInfo string `json:"addInfo"`
AckState int `json:"ackState"`
AckTime sql.NullTime `json:"ackTime"`
AckUser string `json:"ackUser"`
ClearType int `json:"clearType"` // 0: Unclear, 1: Auto clear, 2: Manual clear
ClearTime sql.NullTime `json:"clearTime"`
}
type AlarmLog struct {
NeType string `json:"neType" xorm:"ne_type"`
NeId string `json:"neId" xorm:"ne_id"`
AlarmSeq int `json:"alarmSeq" xorm:"alarm_seq"`
AlarmId string `json:"alarmId" xorm:"alarm_id"`
AlarmCode int `json:"alarmCode" xorm:"alarm_code"`
AlarmStatus int `json:"alarmStatus" xorm:"alarm_status"`
EventTime string `json:"eventTime" xorm:"event_time"`
// ClearTime sql.NullTime `json:"clearTime" xorm:"clear_time"`
LogTime string `json:"logTime" xorm:"-"`
}
var (
// alarm management
UriAlarms = config.UriPrefix + "/faultManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/alarms"
UriAlarmsFmt = config.UriPrefix + "/faultManagement/v1/elementType/%s/objectType/alarms"
)
var xEngine *xorm.Engine
type DatabaseClient struct {
dbType string
dbUrl string
dbConnMaxLifetime time.Duration
dbMaxIdleConns int
dbMaxOpenConns int
IsShowSQL bool
XEngine *xorm.Engine
}
var DbClient DatabaseClient
func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) error {
DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
dbUser, dbPassword, dbHost, dbPort, dbName)
DbClient.dbType = dbType
DbClient.dbConnMaxLifetime = 0
DbClient.dbMaxIdleConns = 0
DbClient.dbMaxOpenConns = 0
if log.GetLevel() == log.LOG_TRACE {
DbClient.IsShowSQL = true
}
log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s??charset=utf8&parseTime=true&loc=Local",
dbType, dbUser, dbHost, dbPort, dbName)
var err error
DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl)
if err != nil {
log.Error("Failed to connet database:", err)
return err
}
DbClient.XEngine.SetConnMaxLifetime(DbClient.dbConnMaxLifetime)
DbClient.XEngine.SetMaxIdleConns(DbClient.dbMaxIdleConns)
DbClient.XEngine.SetMaxOpenConns(DbClient.dbMaxOpenConns)
if DbClient.IsShowSQL {
DbClient.XEngine.ShowSQL(true)
}
xEngine = DbClient.XEngine
return nil
}
func XormConnectDatabase(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) (*xorm.Engine, error) {
sqlStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
dbUser, dbPassword, dbHost, dbPort, dbName)
log.Debugf("dbType:%s Connect to:%s:******@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
dbType, dbUser, dbHost, dbPort, dbName)
var err error
xEngine, err = xorm.NewEngine(dbType, sqlStr) //1、Create xorm engine
if err != nil {
log.Error("Failed to connect database:", err)
return nil, err
}
if log.GetLevel() == log.LOG_TRACE {
xEngine.ShowSQL(true)
}
return xEngine, nil
}
func IsNeedToAckAlarm(valueJson *dborm.ValueJson, alarm *Alarm) bool {
log.Info("IsNeedToAckAlarm processing... ")
if valueJson != nil {
status, _ := strconv.Atoi(valueJson.AlarmStatus)
log.Tracef("alarm.AlarmStatus=%d, alarm.AlarmType=%s, alarm.OrigSeverity=%s", alarm.AlarmStatus, alarm.AlarmType, alarm.OrigSeverity)
log.Tracef("status=%d, valueJson.AlarmType=%s, valueJson.OrigSeverity=%s", status, valueJson.AlarmType, valueJson.OrigSeverity)
if alarm.AlarmStatus == status &&
alarm.AlarmType == valueJson.AlarmType &&
alarm.OrigSeverity == valueJson.OrigSeverity {
return true
}
}
return false
}
func SetAlarmAckInfo(valueJson *dborm.ValueJson, alarm *Alarm) {
log.Info("SetAlarmAckInfo processing... ")
alarm.AckState = AckStateAcked
alarm.AckTime.Valid = true
alarm.AckTime.Time = time.Now()
alarm.AckUser = valueJson.AckUser
}
// process alarm post message from NFs
func PostAlarmFromNF(w http.ResponseWriter, r *http.Request) {
log.Debug("PostAlarmFromNF processing... ")
vars := mux.Vars(r)
apiVer := vars["apiVersion"]
if apiVer != global.ApiVersionV1 {
log.Error("Uri api version is invalid. apiVersion:", apiVer)
services.ResponseNotFound404UriNotExist(w, r)
return
}
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
log.Debug("Request body:", string(body))
alarmArray := new([]Alarm)
err = json.Unmarshal(body, &alarmArray)
if err != nil {
log.Error("Failed to Unmarshal:", err)
services.ResponseBadRequest400InvalidJson(w)
return
}
valueJson, err := dborm.XormGetAAConfig()
if err != nil {
log.Error("Failed to XormGetAAConfig:", err)
//services.ResponseInternalServerError500ProcessError(w, err)
//return
}
log.Debug("valueJson:", valueJson)
session := xEngine.NewSession()
defer session.Close()
for _, alarmData := range *alarmArray {
log.Debug("alarmData:", alarmData)
if alarmData.AlarmStatus == AlarmStatusClear {
alarmData.ClearType = ClearTypeAutoClear
alarmData.ClearTime.Valid = true
tm, _ := time.Parse(time.RFC3339, alarmData.EventTime)
log.Debugf("EventTime:%s tm:%d tm-datetime:%s", alarmData.EventTime, tm, tm.Local().Format(time.DateTime))
alarmData.ClearTime.Time = tm
if IsNeedToAckAlarm(valueJson, &alarmData) == true {
SetAlarmAckInfo(valueJson, &alarmData)
affected, err := session.Where("ne_type=? and ne_id=? and alarm_id=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.AlarmId).
Cols("alarm_status", "clear_type", "clear_time", "ack_state", "ack_time", "ack_user").
Update(alarmData)
if err != nil && affected <= 0 {
log.Error("Failed to update alarm data:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
continue
}
} else {
affected, err := session.Where("ne_type=? and ne_id=? and alarm_id=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.AlarmId).
Cols("alarm_status", "clear_type", "clear_time").
Update(alarmData)
if err != nil && affected <= 0 {
log.Error("Failed to update alarm data:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
continue
}
}
log.Debug("alarmData:", alarmData)
var currentSeq string
var seq int
has, err := xEngine.Table("alarm").
Where("ne_type=? and ne_id=?", alarmData.NeType, alarmData.NeId).
Desc("alarm_seq").
Cols("alarm_seq").
Limit(1).
Get(&currentSeq)
if err != nil {
log.Error("Failed to get alarm:", err)
continue
}
if has == true {
seq, _ = strconv.Atoi(currentSeq)
}
eventTime := global.GetFmtTimeString(time.RFC3339, alarmData.EventTime, time.DateTime)
alarmLog := new(AlarmLog)
alarmLog.NeType = alarmData.NeType
alarmLog.NeId = alarmData.NeId
alarmLog.AlarmSeq = seq
alarmLog.AlarmId = alarmData.AlarmId
alarmLog.AlarmCode = alarmData.AlarmCode
alarmLog.AlarmStatus = alarmData.AlarmStatus
alarmLog.EventTime = eventTime
log.Debug("alarmLog:", alarmLog)
affected, err := session.Insert(alarmLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert alarm_log:", err)
}
// todo: PerceivedSeverity set color
var severity string
has, err = xEngine.Table("alarm").
Where("ne_type=? and ne_id=? and event_time=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
//OrderBy("FIELD(orig_severity, 'Critical', 'Major', 'Minor', 'Warning', 'Event') ASC").
Asc("orig_severity").
Cols("orig_severity").
Limit(1).
Get(&severity)
if err != nil {
log.Error("Failed to get alarm:", err)
continue
}
log.Debugf("neType=%s, neId=%s, eventTime=%s, severity=%s", alarmData.NeType, alarmData.NeId, alarmData.EventTime, severity)
if has == true && severity > alarmData.OrigSeverity {
// update exist record
_, err := session.Table("alarm").
Where("ne_type=? and ne_id=? and event_time=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
Update(&Alarm{PerceivedSeverity: severity})
if err != nil {
log.Error("Failed to update alarm:", err)
continue
}
}
// for alarm forward time format
alarmData.EventTime = eventTime
} else {
has, err := xEngine.Table("alarm").
Where("alarm_id=? and ne_type=? and ne_id=? and alarm_status=1",
alarmData.AlarmId, alarmData.NeType, alarmData.NeId).
Exist()
if err == nil && has == true {
log.Warn("Exist the same alarm")
continue
}
var currentSeq string
has, err = xEngine.Table("alarm").
Where("ne_type=? and ne_id=?", alarmData.NeType, alarmData.NeId).
Desc("alarm_seq").
Cols("alarm_seq").
Limit(1).
Get(&currentSeq)
if err != nil {
log.Error("Failed to get alarm:", err)
continue
}
log.Debugf("neType=%s, neId=%s, currentSeq=%s", alarmData.NeType, alarmData.NeId, currentSeq)
if has == true {
seq, _ := strconv.Atoi(currentSeq)
if seq+1 > global.MaxInt32Number {
alarmData.AlarmSeq = AlarmSeqBeginNumber
} else {
alarmData.AlarmSeq = seq + 1
}
} else {
alarmData.AlarmSeq = AlarmSeqBeginNumber
}
// todo: PerceivedSeverity set color
var severity string
has, err = xEngine.Table("alarm").
Where("ne_type=? and ne_id=? and event_time=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
//OrderBy("FIELD(orig_severity, 'Critical', 'Major', 'Minor', 'Warning', 'Event') ASC").
Asc("orig_severity").
Cols("orig_severity").
Limit(1).
Get(&severity)
if err != nil {
log.Error("Failed to get alarm:", err)
continue
}
log.Debugf("neType=%s, neId=%s, eventTime=%s, severity=%s", alarmData.NeType, alarmData.NeId, alarmData.EventTime, severity)
if has == false || severity == alarmData.OrigSeverity {
alarmData.PerceivedSeverity = alarmData.OrigSeverity
} else if severity > alarmData.OrigSeverity {
alarmData.PerceivedSeverity = alarmData.OrigSeverity
} else {
alarmData.PerceivedSeverity = severity
// update exist record
_, err := session.Table("alarm").
Where("ne_type=? and ne_id=? and event_time=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
Update(&Alarm{PerceivedSeverity: alarmData.PerceivedSeverity})
if err != nil {
log.Error("Failed to update alarm:", err)
continue
}
}
eventTime := global.GetFmtTimeString(time.RFC3339, alarmData.EventTime, time.DateTime)
alarmData.ObjectUid = alarmData.NeId
alarmData.ObjectType = "VNFM"
alarmData.EventTime = eventTime
if IsNeedToAckAlarm(valueJson, &alarmData) == true {
SetAlarmAckInfo(valueJson, &alarmData)
}
log.Debug("alarmData:", alarmData)
affected, err := session.Insert(alarmData)
if err != nil && affected <= 0 {
log.Error("Failed to insert alarm data:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
continue
}
alarmLog := new(AlarmLog)
alarmLog.NeType = alarmData.NeType
alarmLog.NeId = alarmData.NeId
alarmLog.AlarmSeq = alarmData.AlarmSeq
alarmLog.AlarmId = alarmData.AlarmId
alarmLog.AlarmCode = alarmData.AlarmCode
alarmLog.AlarmStatus = alarmData.AlarmStatus
alarmLog.EventTime = eventTime
log.Debug("alarmLog:", alarmLog)
affected, err = session.Insert(alarmLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert alarm_log:", err)
}
}
if config.GetYamlConfig().Alarm.ForwardAlarm {
if err = AlarmEmailForward(&alarmData); err != nil {
log.Error("Failed to AlarmEmailForward:", err)
}
if err = AlarmForwardBySMS(&alarmData); err != nil {
log.Error("Failed to AlarmForwardBySMS:", err)
}
}
}
session.Commit()
services.ResponseStatusOK200Null(w)
}
// process alarm get from NFs
func GetAlarmFromNF(w http.ResponseWriter, r *http.Request) {
log.Debug("GetAlarmFromNF processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
//var neInfo *dborm.NeInfo
var nes []dborm.NeInfo
_, err = dborm.XormGetAllNeInfo(&nes)
if err != nil {
log.Error("Failed to get all ne info:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
for _, ne := range nes {
hostUri := fmt.Sprintf("http://%s:%v", ne.Ip, ne.Port)
apiUri := fmt.Sprintf(UriAlarmsFmt, strings.ToLower(ne.NeType))
requestURI2NF := fmt.Sprintf("%s%s", hostUri, apiUri)
log.Debug("requestURI2NF: Get ", requestURI2NF)
client := resty.New()
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Get(requestURI2NF)
if err != nil {
log.Error("Failed to Get:", err)
//services.ResponseInternalServerError500ProcessError(w, err)
continue
}
body := response.Body()
log.Debug("Request body:", string(body))
alarmArray := new([]Alarm)
_ = json.Unmarshal(body, &alarmArray)
valueJson, err := dborm.XormGetAAConfig()
if err != nil {
log.Error("Failed to XormGetAAConfig:", err)
//services.ResponseInternalServerError500ProcessError(w, err)
continue
}
session := xEngine.NewSession()
defer session.Close()
for _, alarmData := range *alarmArray {
log.Debug("alarmData:", alarmData)
// todo: clear alarm ....
if alarmData.AlarmStatus == AlarmStatusClear {
exist, err := session.Table("alarm").
Where("ne_type=? and ne_id=? and alarm_id=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.AlarmId).
Exist()
if err == nil || exist == false {
log.Info("Not found active alarm: ne_id=%s, alarm_id=%s", alarmData.NeId, alarmData.AlarmId)
continue
}
alarmData.ClearType = ClearTypeAutoClear
alarmData.ClearTime.Valid = true
tm, _ := time.Parse(time.RFC3339, alarmData.EventTime)
log.Debugf("EventTime:%s tm:%d tm-datetime:%s", alarmData.EventTime, tm, tm.Local().Format(time.DateTime))
alarmData.ClearTime.Time = tm
if IsNeedToAckAlarm(valueJson, &alarmData) == true {
SetAlarmAckInfo(valueJson, &alarmData)
log.Debug("alarmData:", alarmData)
affected, err := session.
Where("ne_type=? and ne_id=? and alarm_id=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.AlarmId).
Cols("alarm_status", "clear_type", "clear_time", "ack_state", "ack_time", "ack_user").
Update(alarmData)
if err != nil && affected <= 0 {
log.Error("Failed to update alarm data:", err)
//services.ResponseInternalServerError500DatabaseOperationFailed(w)
continue
}
} else {
affected, err := session.
Where("ne_type=? and ne_id=? and alarm_id=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.AlarmId).
Cols("alarm_status", "clear_type", "clear_time").
Update(alarmData)
if err != nil && affected <= 0 {
log.Error("Failed to update alarm data:", err)
//services.ResponseInternalServerError500DatabaseOperationFailed(w)
continue
}
}
eventTime := global.GetFmtTimeString(time.RFC3339, alarmData.EventTime, time.DateTime)
alarmLog := new(AlarmLog)
alarmLog.NeType = alarmData.NeType
alarmLog.NeId = alarmData.NeId
alarmLog.AlarmSeq = alarmData.AlarmSeq
alarmLog.AlarmId = alarmData.AlarmId
alarmLog.AlarmCode = alarmData.AlarmCode
alarmLog.AlarmStatus = alarmData.AlarmStatus
alarmLog.EventTime = eventTime
log.Debug("alarmLog:", alarmLog)
affected, err := session.Insert(alarmLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert alarm_log:", err)
}
// todo: PerceivedSeverity set color
var severity string
has, err := xEngine.Table("alarm").
Where("ne_type=? and ne_id=? and event_time=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
//OrderBy("FIELD(orig_severity, 'Critical', 'Major', 'Minor', 'Warning', 'Event') ASC").
Asc("orig_severity").
Cols("orig_severity").
Limit(1).
Get(&severity)
if err != nil {
log.Error("Failed to get alarm:", err)
continue
}
log.Debugf("neType=%s, neId=%s, eventTime=%s, severity=%s", alarmData.NeType, alarmData.NeId, alarmData.EventTime, severity)
if has == true && severity > alarmData.OrigSeverity {
// update exist record
_, err := session.Table("alarm").
Where("ne_type=? and ne_id=? and event_time=?", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
Update(&Alarm{PerceivedSeverity: severity})
if err != nil {
log.Error("Failed to update alarm:", err)
continue
}
}
// for alarm forward time format
alarmData.EventTime = eventTime
} else {
has, err := xEngine.Table("alarm").
Where("alarm_id=? and ne_type=? and ne_id=? and alarm_status=1",
alarmData.AlarmId, alarmData.NeType, alarmData.NeId).
Exist()
if err == nil && has == true {
log.Warn("Exist the same alarm")
continue
}
var currentSeq string
has, err = xEngine.Table("alarm").
Where("ne_type=? and ne_id=?", alarmData.NeType, alarmData.NeId).
Desc("alarm_seq").
Cols("alarm_seq").
Limit(1).
Get(&currentSeq)
if err != nil {
log.Error("Failed to get alarm:", err)
continue
}
log.Debugf("neType=%s, neId=%s, currentSeq=%s", alarmData.NeType, alarmData.NeId, currentSeq)
if has == true {
seq, _ := strconv.Atoi(currentSeq)
if seq+1 > global.MaxInt32Number {
alarmData.AlarmSeq = AlarmSeqBeginNumber
} else {
alarmData.AlarmSeq = seq + 1
}
} else {
alarmData.AlarmSeq = AlarmSeqBeginNumber
}
// todo: PerceivedSeverity set color
var severity string
has, err = xEngine.Table("alarm").
Where("ne_type=? and ne_id=? and event_time=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
//OrderBy("FIELD(orig_severity, 'Critical', 'Major', 'Minor', 'Warning', 'Event') ASC").
Asc("orig_severity").
Cols("orig_severity").
Limit(1).
Get(&severity)
if err != nil {
log.Error("Failed to get alarm:", err)
continue
}
log.Debugf("neType=%s, neId=%s, eventTime=%s, severity=%s", alarmData.NeType, alarmData.NeId, alarmData.EventTime, severity)
if has == false || severity == alarmData.OrigSeverity {
alarmData.PerceivedSeverity = alarmData.OrigSeverity
} else if severity > alarmData.OrigSeverity {
alarmData.PerceivedSeverity = alarmData.OrigSeverity
} else {
alarmData.PerceivedSeverity = severity
// update exist record
_, err := session.Table("alarm").
Where("ne_type=? and ne_id=? and event_time=?", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
Update(&Alarm{PerceivedSeverity: alarmData.PerceivedSeverity})
if err != nil {
log.Error("Failed to update alarm:", err)
continue
}
}
alarmData.ObjectUid = alarmData.NeId
alarmData.ObjectType = "VNFM"
alarmData.EventTime = global.GetFmtTimeString(time.RFC3339, alarmData.EventTime, time.DateTime)
if IsNeedToAckAlarm(valueJson, &alarmData) == true {
SetAlarmAckInfo(valueJson, &alarmData)
}
log.Debug("alarmData:", alarmData)
affected, err := session.Insert(alarmData)
if err == nil && affected > 0 {
alarmLog := new(AlarmLog)
alarmLog.NeType = alarmData.NeType
alarmLog.NeId = alarmData.NeId
alarmLog.AlarmSeq = alarmData.AlarmSeq
alarmLog.AlarmId = alarmData.AlarmId
alarmLog.AlarmCode = alarmData.AlarmCode
alarmLog.AlarmStatus = alarmData.AlarmStatus
alarmLog.EventTime = global.GetFmtTimeString(time.RFC3339, alarmData.EventTime, time.DateTime)
log.Debug("alarmLog:", alarmLog)
affected, err = session.Insert(alarmLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert data:", err)
//services.ResponseInternalServerError500DatabaseOperationFailed(w)
continue
}
session.Commit()
if config.GetYamlConfig().Alarm.ForwardAlarm {
if err = AlarmEmailForward(&alarmData); err != nil {
log.Error("Failed to AlarmEmailForward:", err)
}
if err = AlarmForwardBySMS(&alarmData); err != nil {
log.Error("Failed to AlarmForwardBySMS:", err)
}
}
}
log.Warn("Failed to insert alarm data:", err)
}
}
}
services.ResponseStatusOK200Null(w)
}

111
features/fm/email.go Normal file
View File

@@ -0,0 +1,111 @@
package fm
import (
"crypto/tls"
"errors"
"fmt"
"strings"
"ems.agt/lib/dborm"
"ems.agt/lib/log"
"ems.agt/restagent/config"
"gopkg.in/gomail.v2"
)
func AlarmEmailForward(alarmData *Alarm) error {
log.Info("AlarmEmailForward processing... ")
message := `
<p> Hello information,</p>
test, test
<p style="text-indent:2em">Best Wishes!</p>
`
// QQ 邮箱:
// SMTP 服务器地址smtp.qq.comSSL协议端口465/994 | 非SSL协议端口25
// 163 邮箱:
// SMTP 服务器地址smtp.163.com端口25
// host := "mail.agrandtech.com"
// port := 25
// userName := "smtpext@agrandtech.com"
// password := "1000smtp@omc!"
host := config.GetYamlConfig().Alarm.Email.Smtp
port := int(config.GetYamlConfig().Alarm.Email.Port)
userName := config.GetYamlConfig().Alarm.Email.User
password := config.GetYamlConfig().Alarm.Email.Password
m := gomail.NewMessage()
m.SetHeader("From", userName) // 发件人
//m.SetHeader("From", "alias"+"<"+"aliastest"+">") // 增加发件人别名
emails, err := dborm.XormGetAlarmForward("Email")
if err != nil {
log.Error("Failed to XormGetAlarmForward:", err)
return err
} else if emails == nil || len(*emails) == 0 {
err := errors.New("not found forward email list")
log.Error(err)
return err
}
forwardLog := &dborm.AlarmForwardLog{
NeType: alarmData.NeType,
NeID: alarmData.NeId,
AlarmID: alarmData.AlarmId,
AlarmTitle: alarmData.AlarmTitle,
AlarmSeq: alarmData.AlarmSeq,
EventTime: alarmData.EventTime,
ToUser: strings.Join(*emails, ","),
}
for _, email := range *emails {
m.SetHeader("To", email) // 收件人,可以多个收件人,但必须使用相同的 SMTP 连接
}
//m.SetHeader("To", "zhangshuzhong@agrandtech.com", "simonzhangsz@outlook.com") // 收件人,可以多个收件人,但必须使用相同的 SMTP 连接
//m.SetHeader("Cc", "******@qq.com") // 抄送,可以多个
//m.SetHeader("Bcc", "******@qq.com") // 暗送,可以多个
m.SetHeader("Subject", "Alarm from OMC!") // 邮件主题
// text/html 的意思是将文件的 content-type 设置为 text/html 的形式浏览器在获取到这种文件时会自动调用html的解析器对文件进行相应的处理。
// 可以通过 text/html 处理文本格式进行特殊处理,如换行、缩进、加粗等等
//m.SetBody("text/html", fmt.Sprintf(message, *alarm))
m.SetBody("text/html", message)
// text/plain的意思是将文件设置为纯文本的形式浏览器在获取到这种文件时并不会对其进行处理
// m.SetBody("text/plain", "纯文本")
// m.Attach("test.sh") // 附件文件,可以是文件,照片,视频等等
// m.Attach("lolcatVideo.mp4") // 视频
// m.Attach("lolcat.jpg") // 照片
d := gomail.NewDialer(
host,
port,
userName,
password,
)
// 关闭SSL协议认证
d.TLSConfig = &tls.Config{InsecureSkipVerify: true}
if err := d.DialAndSend(m); err != nil {
operResult := fmt.Sprintf("Failed to DialAndSend:%v", err)
log.Error(operResult)
forwardLog.OperResult = operResult
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert data:", err)
}
return err
}
operResult := fmt.Sprintf("Email sent successfully!:", err)
log.Error(operResult)
forwardLog.OperResult = operResult
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert data:", err)
return err
}
return nil
}

103
features/fm/smsforward.go Normal file
View File

@@ -0,0 +1,103 @@
package fm
import (
"errors"
"fmt"
"net/http"
"net/url"
"ems.agt/lib/dborm"
"ems.agt/lib/log"
"ems.agt/restagent/config"
)
func AlarmForwardBySMS(alarmData *Alarm) error {
log.Info("AlarmForwardBySMS processing... ")
SMSFforwardconfig := config.GetYamlConfig().Alarm.SMS
// 阿里云短信API的请求地址
apiURL := SMSFforwardconfig.ApiURL
// 阿里云短信API的AccessKey ID和AccessKey Secret
//accessKeyID := SMSFforwardconfig.AccessKeyID
accessKeySecret := SMSFforwardconfig.AccessKeySecret
toUsers, err := dborm.XormGetAlarmForward("SMS")
if err != nil {
log.Error("Failed to XormGetAlarmForward:", err)
return err
} else if toUsers == nil {
err := errors.New("not found forward phone number")
log.Error(err)
return err
}
for _, toUser := range *toUsers {
// 短信相关参数
params := url.Values{}
params.Set("PhoneNumbers", toUser)
params.Set("SignName", SMSFforwardconfig.SignName)
params.Set("TemplateCode", SMSFforwardconfig.TemplateCode)
params.Set("TemplateParam", `{"message":"alarm"}`)
// 构建请求URL
reqURL := apiURL + "?Action=SendSms&" + params.Encode()
// 创建HTTP请求
req, err := http.NewRequest("GET", reqURL, nil)
if err != nil {
log.Error("Failed to create request:", err)
return err
}
// 添加请求头部
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Authorization", "APPCODE "+accessKeySecret)
forwardLog := &dborm.AlarmForwardLog{
NeType: alarmData.NeType,
NeID: alarmData.NeId,
AlarmID: alarmData.AlarmId,
AlarmTitle: alarmData.AlarmTitle,
AlarmSeq: alarmData.AlarmSeq,
EventTime: alarmData.EventTime,
ToUser: toUser,
}
// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
operResult := fmt.Sprintf("Failed to send request:%v", err)
log.Error(operResult)
forwardLog.OperResult = operResult
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert data:", err)
}
continue
}
defer resp.Body.Close()
// 解析响应
if resp.StatusCode == http.StatusOK {
log.Info("SMS sent successfully!")
operResult := fmt.Sprintf("SMS sent successfully!")
forwardLog.OperResult = operResult
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert data:", err)
continue
}
} else {
operResult := fmt.Sprintf("Failed to send SMS, StatusCode=%d", resp.StatusCode)
log.Error(operResult)
forwardLog.OperResult = operResult
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
if err != nil && affected <= 0 {
log.Error("Failed to insert data:", err)
continue
}
}
}
return nil
}

586
features/handle/handle.go Normal file
View File

@@ -0,0 +1,586 @@
package handle
import (
"bytes"
"encoding/json"
"io"
"net/http"
"strconv"
"strings"
"ems.agt/lib/dborm"
"github.com/gorilla/mux"
g "github.com/gosnmp/gosnmp"
"ems.agt/lib/global"
"ems.agt/lib/log"
"ems.agt/lib/oauth"
"ems.agt/lib/services"
"ems.agt/lib/session"
"ems.agt/restagent/config"
)
var TodoList []stTodo
type stTodo struct {
No string
Item string
Value string
}
type ErrorOAuthResponse struct {
Error map[string]interface{}
}
type FailOAuthResponse struct {
Error struct {
ErrorCode string
ErrorInfo string
}
}
type ApiResponse struct {
ResultCode string
ResultMessage interface{}
}
var globalSession = session.NewSessManager("restagent")
func init() {
conf := config.GetYamlConfig()
// Default is a pointer to a GoSNMP struct that contains sensible defaults
// eg port 161, community public, etc
g.Default.Target = conf.NE.Addr
g.Default.Port = conf.NE.Port
err := g.Default.Connect()
if err != nil {
log.Fatalf("Connect() err: %v", err)
}
//defer g.Default.Conn.Close()
}
/*
func IsValidOAuthInfo(oAuthBody OAuthBody) bool {
log.Debug("IsValidOAuthInfo processing... ")
conf := config.GetYamlConfig()
for _, o := range conf.Auth {
if oAuthBody.GrantType == o.Type && oAuthBody.UserName == o.User && oAuthBody.Value == o.Password {
return true
}
}
return false
}
func IsWrongOAuthInfo(oAuthBody OAuthBody) bool {
log.Debug("IsWrongOAuthInfo processing... ")
if oAuthBody.GrantType == "" || strings.ToLower(oAuthBody.GrantType) != "password" || oAuthBody.UserName == "" || oAuthBody.Value == "" {
return true
}
return false
}
*/
func IsValidOAuthUri(r *http.Request) bool {
vars := mux.Vars(r)
Uri := vars["apiCategory"] + "/" + vars["apiVersion"] // 获取Uri
if Uri != "securityManagement/v1" {
return false
}
return true
}
func IsVallidContentType(r *http.Request) bool {
log.Debug("IsVallidContentType processing ...")
ctype := r.Header["Content-Type"]
if len(ctype) != 0 && !strings.Contains(ctype[0], "application/json") {
return false
}
return true
}
func LoginFromOMC(w http.ResponseWriter, r *http.Request) {
log.Debug("LoginFromOMC processing... ")
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小
if err != nil {
log.Debug(err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
// check media type(content type) only support "application/json"
/* if !IsVallidContentType(r) {
log.Debug("Invalid Content-Type")
services.ResponseUnsupportedMediaType415(w)
return
}
// check extend uri, response 404
if !IsValidOAuthUri(r) {
log.Debug("Uri is invalid")
services.ResponseNotFound404UriNotExist(w, r)
return
}
*/
// Error process ....
// response 400-7
if !json.Valid([]byte(body)) {
log.Debug("Invalid Json Format")
services.ResponseBadRequest400InvalidJson(w)
return
}
var oAuthBody oauth.OAuthBody
_ = json.Unmarshal(body, &oAuthBody) //转为json
log.Debug("body:", string(body), "oAuthBody:", oAuthBody)
defer r.Body.Close()
// response 400-5
if oauth.IsWrongOAuthInfo(oAuthBody) {
log.Debug("Wrong parameter value")
services.ResponseBadRequest400WrongParamValue(w)
return
}
/*
if oauth.IsValidOAuthInfo(oAuthBody) {
plist := config.GetPermissionFromConfig(oAuthBody.UserName, oAuthBody.GrantType)
log.Debug("Permission list:", plist)
token := globalSession.NewSession(w, r, plist)
services.ResponseStatusOK200Login(w, token)
} else {
// response 400-4
log.Debug("Authentication failed, mismatch user or password")
services.ResponseBadRequest400IncorrectLogin(w)
}
*/
validUser, changePassword, _ := dborm.XormCheckLoginUser(oAuthBody.UserName,
oAuthBody.Value, config.GetYamlConfig().Auth.Crypt)
if validUser {
// plist := config.GetPermissionFromConfig(oAuthBody.UserName, oAuthBody.GrantType)
plist := []bool{true, true, true, true}
log.Debug("Permission list:", plist)
token := globalSession.NewSession(w, r, plist)
services.ResponseStatusOK200Login(w, token, changePassword)
} else {
// response 400-4
log.Error("Authentication failed, mismatch user or password")
services.ResponseBadRequest400IncorrectLogin(w)
}
return
}
func LogoutFromOMC(w http.ResponseWriter, r *http.Request) {
log.Debug("LogoutFromOMC processing... ")
// check media type(content type) only support "application/json"
if !IsVallidContentType(r) {
log.Debug("Invalid Content-Type")
services.ResponseUnsupportedMediaType415(w)
return
}
// check extend uri, response 404
if !IsValidOAuthUri(r) {
log.Debug("Uri is invalid")
services.ResponseNotFound404UriNotExist(w, r)
return
}
// error processing ...
// 401-1 response
token, ret := globalSession.IsCarriedToken(r)
if ret == false {
log.Debug("AccessToken is not carried")
services.ResponseUnauthorized401AccessTokenNotCarried(w)
return
}
// 401-2 response
if globalSession.IsValidToken(token) == false {
log.Debug("AccessToken fails or does not exist")
services.ResponseUnauthorized401AccessTokenNotExist(w)
return
}
globalSession.EndSession(w, r)
services.ResponseStatusOK200Null(w)
return
}
func HandshakeFromOMC(w http.ResponseWriter, r *http.Request) {
log.Debug("HandshakeFromOMC processing... ")
// check media type(content type) only support "application/json"
if !IsVallidContentType(r) {
log.Debug("Invalid Content-Type")
services.ResponseUnsupportedMediaType415(w)
return
}
// check extend uri, response 404
if !IsValidOAuthUri(r) {
log.Debug("Uri is invalid")
services.ResponseNotFound404UriNotExist(w, r)
return
}
// error processing ...
// 401-1 response
token, ret := globalSession.IsCarriedToken(r)
if ret == false {
log.Debug("AccessToken is not carried")
services.ResponseUnauthorized401AccessTokenNotCarried(w)
return
}
if !globalSession.ShakeSession(token) {
// 401-2 response
log.Debug("AccessToken fails or does not exist")
services.ResponseUnauthorized401AccessTokenNotExist(w)
return
}
// 200 response
services.ResponseStatusOK200Null(w)
return
}
var (
MAX_RMUID_NUM = config.GetRmUIDMaxNumFromConfig()
MAX_ALARMID_NUM = config.GetAlarmIDMaxNumFromConfig()
MAX_PMUID_NUM = config.GetPmIDMaxNumFromConfig()
MAX_SUBID_NUM = config.GetSubIDMaxNumFromConfig()
MAX_URI_LEN = config.GetUriMaxLenFromConfig()
RMUID_REGEXP = config.GetRmUIDRegexpFromConfig()
)
func CheckParameterName(r *http.Request) []string {
var errorParams []string
vars := r.URL.Query()
for k, v := range vars {
log.Debug("vars:", k, v)
if k != "rmUIDs" && k != "fields" {
errorParams = append(errorParams, k)
}
}
return errorParams
}
func GetRmUIDArr(r *http.Request) []string {
vars := r.URL.Query()
rmUIDs, ok := vars["rmUIDs"]
if !ok {
log.Debug("rmUIDs is not exist")
return nil
}
var rmUIDValues []string
for _, r := range rmUIDs {
if r != "" {
rmUIDValues = global.MergeStringArr(rmUIDValues, strings.Split(r, `,`))
}
}
return rmUIDValues
}
func GetAttrNameArr(r *http.Request) []string {
vars := r.URL.Query()
fields, ok := vars["fields"]
if !ok {
log.Debug("attributeNames does not exist")
return nil
}
var attrNames []string
for _, a := range fields {
if a != "" {
attrNames = global.MergeStringArr(attrNames, strings.Split(a, `,`))
}
}
return attrNames
}
func CheckValidRmUID(rmUIDs []string) []string {
log.Debug("GetLocalRmUID processing... ")
var invalidRmUIDs []string
for _, r := range rmUIDs {
if !global.MatchRmUID(RMUID_REGEXP, r) {
invalidRmUIDs = append(invalidRmUIDs, r)
}
}
return invalidRmUIDs
}
func CheckLocalRmUID(rmUIDs []string) string {
log.Debug("GetLocalRmUID processing... ")
rmUID := config.GetRmUIDFromConfig()
for _, r := range rmUIDs {
if r == rmUID {
return rmUID
}
}
return ""
}
func GetNRMByUri(w http.ResponseWriter, r *http.Request) {
log.Debug("GetNRMByUri processing... ")
// response 414-4 uri too long ? (optional)
// todo ... ?
if bytes.Count([]byte(r.RequestURI), nil) > MAX_URI_LEN {
log.Debug("Request Uri too long:", bytes.Count([]byte(r.RequestURI), nil))
services.ResponseRequestURITooLong414UriTooLong(w)
return
}
// check media type(content type) only support "application/json"
// response 415-1
if !IsVallidContentType(r) {
log.Debug("Invalid Content-Type")
services.ResponseUnsupportedMediaType415(w)
return
}
// error processing ...
// 401-1 response
token, ret := globalSession.IsCarriedToken(r)
if ret == false {
log.Debug("AccessToken is not carried")
services.ResponseUnauthorized401AccessTokenNotCarried(w)
return
}
// 401-2 response
if globalSession.IsValidToken(token) == false {
log.Debug("AccessToken fails or does not exist")
services.ResponseUnauthorized401AccessTokenNotExist(w)
return
}
// response 403 Forbidden, permissions deny
// todo...
plist := globalSession.GetPermissionFromSession(token)
log.Debug("permission list:", plist)
if len(plist) == 0 || plist[0] == false {
log.Debug("User permission deny")
services.ResponseForbidden403NotPermission(w)
return
}
vars := mux.Vars(r)
qeuryUri := vars["apiCategory"] + "/" + vars["elementTypeValue"] + "/" + vars["objectTypeValue"]
log.Debug("Get by Uri: ", qeuryUri)
apiVer := vars["apiVersion"]
if apiVer != "v1" {
log.Debug("Uri is invalid")
services.ResponseNotFound404UriNotExist(w, r)
return
}
// response 406-1
rmUIDValues := GetRmUIDArr(r)
if rmUIDValues == nil {
log.Debug("missing parameter: rmUIDs")
services.ResponseNotAcceptable406MissingParam(w)
return
}
// response 406-2
errorParams := CheckParameterName(r)
if errorParams != nil {
log.Debug("parameter name error: ", errorParams)
services.ResponseNotAcceptable406ParamError(w, errorParams)
return
}
// response 400-5
if len(rmUIDValues) == 0 {
log.Debug("rmUIDs is wrong or NULL")
services.ResponseBadRequest400WrongParamValue(w)
return
}
// response 414-1
if len(rmUIDValues) > MAX_RMUID_NUM {
log.Debug("rmUID greater than", MAX_RMUID_NUM)
services.ResponseRequestURITooLong414NRMNumExceed(w, MAX_RMUID_NUM)
return
}
// response 400-1
// check rmUID is valid
// todo ...
invalidRmUIDs := CheckValidRmUID(rmUIDValues)
if len(invalidRmUIDs) != 0 {
log.Debug("rmUID is invalid")
services.ResponseBadRequest400RmUIDsIsInvalid(w, invalidRmUIDs)
return
}
// response 404-2
rmUID := CheckLocalRmUID(rmUIDValues)
if rmUID == "" {
log.Debug("rmUID does not exist")
services.ResponseNotFound404NRMNotExist(w, rmUIDValues)
return
}
// response 404-1, uri is not exist in map
attrNames := GetAttrNameArr(r)
var Oids []string
Oids = *config.GetOidByFileds(qeuryUri, attrNames, &Oids)
if len(Oids) == 0 {
log.Debug("Nothing of config map")
services.ResponseNotFound404UriNotExist(w, r)
return
}
// response 404-1, uri is not exist in map
var nameOids []config.NameOid
nameOids = *config.GetDataOidByFields(qeuryUri, attrNames, &nameOids)
if len(nameOids) == 0 {
log.Debug("Nothing of config map")
services.ResponseNotFound404UriNotExist(w, r)
return
}
result, err2 := g.Default.Get(Oids) // Get() accepts up to g.MAX_OIDS
if err2 != nil {
log.Fatalf("Get() err: %v", err2)
}
// var nameValues []config.NameValue
var nameValue config.NameValue
nameValues := make(map[string]interface{})
nameValues["rmUID"] = rmUID
for i, variable := range result.Variables {
nameValue.Name = nameOids[i].Name
log.Debugf("%d: oid: %s name: %s\n", i, variable.Name, nameValue.Name)
// if nameOids[i].Oid == variable.Name && global.IsContain(attributeNames, nameValue.Name) {
if nameOids[i].Oid == variable.Name {
// the Value of each variable returned by Get() implements
// interface{}. You could do a type switch...
switch variable.Type {
case g.OctetString:
bytes := variable.Value.([]byte)
log.Debugf("string: %s\n", string(bytes))
nameValue.Value = string(bytes)
nameValues[nameValue.Name] = nameValue.Value
case g.Integer:
value := variable.Value.(int)
log.Debugf("integer: %d\n", value)
nameValue.Value = strconv.Itoa(value)
nameValues[nameValue.Name] = nameValue.Value
case g.IPAddress:
value := variable.Value.(string)
log.Debugf("IPAddress: %s\n", variable.Value)
nameValue.Value = value
nameValues[nameValue.Name] = nameValue.Value
default:
// ... or often you're just interested in numeric values.
// ToBigInt() will return the Value as a BigInt, for plugging
// into your calculations.
log.Debugf("number: %d\n", g.ToBigInt(variable.Value))
}
}
}
getResponse := services.DataResponse{nameValues}
services.ResponseWithJson(w, http.StatusOK, getResponse)
}
func RestfulPut(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
queryNo := vars["no"]
var targetTodo stTodo
for _, Todo := range TodoList {
if Todo.No == queryNo {
targetTodo = Todo
}
}
response := ApiResponse{"200", targetTodo}
services.ResponseWithJson(w, http.StatusOK, response)
}
func RestfulHead(w http.ResponseWriter, r *http.Request) {
var targetTodo stTodo
response := ApiResponse{"200", targetTodo}
services.ResponseWithJson(w, http.StatusOK, response)
}
func RemoveElement(TodoList []stTodo, No string) stTodo {
// var targetTodo stTodo
j := 0
if len(TodoList) == 0 {
return TodoList[j]
}
for i := 0; i < len(TodoList); i++ {
if TodoList[i].No != No {
if i != j {
TodoList[i], TodoList[j] = TodoList[j], TodoList[i]
}
j++
}
}
log.Debug(TodoList[j].No, TodoList[j].Item)
return TodoList[j]
}
func RestfulDelete(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
queryNo := vars["no"] //获取No
log.Debug("RestfulDelete processing... ")
targetTodo := RemoveElement(TodoList, queryNo)
response := ApiResponse{"200", targetTodo}
services.ResponseWithJson(w, http.StatusOK, response)
}
func RestfulOptions(w http.ResponseWriter, r *http.Request) {
var targetTodo stTodo
response := ApiResponse{"200", targetTodo}
services.ResponseWithJson(w, http.StatusOK, response)
}
func RestfulTrace(w http.ResponseWriter, r *http.Request) {
var targetTodo stTodo
response := ApiResponse{"200", targetTodo}
services.ResponseWithJson(w, http.StatusOK, response)
}
func RestfulPatch(w http.ResponseWriter, r *http.Request) {
var targetTodo stTodo
response := ApiResponse{"200", targetTodo}
services.ResponseWithJson(w, http.StatusOK, response)
}

View File

@@ -0,0 +1,322 @@
package maintenance
import (
"encoding/json"
"fmt"
"net/http"
"os"
"os/exec"
"path"
"runtime"
"time"
"ems.agt/lib/dborm"
"ems.agt/lib/log"
"ems.agt/lib/services"
"ems.agt/restagent/config"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/disk"
"github.com/shirou/gopsutil/mem"
)
// (1) OMC能够对相关的文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标进行监控管理
// 对于虚拟化部署OMC系统能够对虚机内存、虚机CPU、虚拟存储空间、文件系统资源、数据库空间等指标进行监控提供界面截图
// (2) 系统监控指标的采样时间和阈值可由用户设定,超过阈值将产生不同级别的告警,提供界面截图
// (3) OMC能够方便的查询数据库连接情况并可手工干预数据库的连接能方便的终结非法的数据库连接
// (4) 用户能方便的查询系统进程、应用进程等的进程名、进程类型、开始时间、运行主机等信息,提供界面截图
// (5) 用户能方便的对系统进程、应用进程等做中断或者启动操作,提供界面截图
// (6) 对于文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标数据要求OMC能够保存至少3个月提供界面截图
// (7) 用户可以按照需求自定义报表模板并生成OMC系统维护数据报表提供界面截图
// (8) OMC具备自身告警管理功能对于传统OMC系统服务器单电源告警存储硬盘告警、OMC系统软件故障等
// 对于虚拟化OMC系统如虚机告警、虚拟硬盘告警等提供界面截图 。
var (
// parameter config management
Uri = config.UriPrefix + "/maintenance/{apiVersion}/zz"
// (1) OMC能够对相关的文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标进行监控管理
UriPref = config.UriPrefix + "/maintenance/{apiVersion}/pref"
// (6) 对于文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标数据要求OMC能够保存至少3个月提供界面截图
UriPrefLog = config.UriPrefix + "/maintenance/{apiVersion}/prefLog"
// (2) 系统监控指标的采样时间和阈值可由用户设定,超过阈值将产生不同级别的告警,提供界面截图
UriConfig = config.UriPrefix + "/maintenance/{apiVersion}/config"
// (3) OMC能够方便的查询数据库连接情况并可手工干预数据库的连接能方便的终结非法的数据库连接
UriSqlClient = config.UriPrefix + "/maintenance/{apiVersion}/sqlClient"
// (4) 用户能方便的查询系统进程、应用进程等的进程名、进程类型、开始时间、运行主机等信息,提供界面截图
// (5) 用户能方便的对系统进程、应用进程等做中断或者启动操作,提供界面截图
UriTop = config.UriPrefix + "/maintenance/{apiVersion}/top"
)
func init() {
// 定時收集 TODO
prefLogSave("")
}
func List(w http.ResponseWriter, r *http.Request) {
fmt.Println("zz List")
services.ResponseStatusOK200Null(w)
}
// 性能指標
func prefInfo(dirName string) map[string]any {
data := make(map[string]any)
// 显示文件資源目录
dirPath := "D://"
if runtime.GOOS == "linux" {
dirPath = "/home"
}
// 訪問下級
if dirName != "" {
dirPath = path.Join(dirPath, dirName)
}
dir_list, e := os.ReadDir(dirPath)
if e != nil {
log.Error(e)
}
list := make([]map[string]any, 0)
for _, v := range dir_list {
o, err := v.Info()
if err != nil {
continue
}
list = append(list, map[string]any{
"name": o.Name(),
"size": o.Size(),
"mode": o.Mode().String(),
"modTime": o.ModTime().Format("2006-01-02 15:04:05"),
"isDir": o.IsDir(),
})
}
data["dirList"] = list
// 文件資源使用率
u, _ := disk.Usage(dirPath)
usedGB := int(u.Used) / (1024 * 1024 * 1024 * 1)
data["dirUse"] = fmt.Sprintf("%d", usedGB)
// CPU使用率
percent, err := cpu.Percent(time.Second, false)
if err != nil {
log.Error(err)
}
data["cpuUse"] = fmt.Sprintf("%.2f", percent[0])
// 内存使用率
memInfo, err := mem.VirtualMemory()
if err != nil {
log.Error(err)
}
data["memUse"] = memInfo.UsedPercent
// 獲取數據庫占用空間
if dborm.DbClient.XEngine != nil {
conf := config.GetYamlConfig()
result, err := dborm.DbClient.XEngine.QueryString(`SELECT
CONCAT(TRUNCATE(SUM(data_length)/1024/1024,2),'MB') AS data_size,
CONCAT(TRUNCATE(SUM(max_data_length)/1024/1024,2),'MB') AS max_data_size,
CONCAT(TRUNCATE(SUM(data_free)/1024/1024,2),'MB') AS data_free,
CONCAT(TRUNCATE(SUM(index_length)/1024/1024,2),'MB') AS index_size
FROM information_schema.tables WHERE TABLE_SCHEMA = ?;
`, conf.Database.Name)
if err == nil {
data["dbInfo"] = result[0]
} else {
data["dbInfo"] = map[string]string{}
}
}
return data
}
// 性能指標存入數據庫
func prefLogSave(dirName string) {
if dborm.DbClient.XEngine != nil {
data := prefInfo(dirName)
dirListByte, err := json.Marshal(data["dirList"])
if err != nil {
log.Error(err)
}
dbInfoByte, err := json.Marshal(data["dbInfo"])
if err != nil {
log.Error(err)
}
rse, err := dborm.DbClient.XEngine.Exec(`INSERT INTO sys_perf_data
(id, create_time, dir_used, dir_list, db_info, mem_used, cpu_used)
VALUES(NULL, NOW(), ?, ?, ?, ?, ?);
`, data["dirUse"], string(dirListByte), string(dbInfoByte), data["memUse"], data["cpuUse"])
if err != nil {
log.Error(err)
}
fmt.Println(rse.LastInsertId())
}
}
// GET http://192.168.21.183:3040/api/rest/maintenance/v1/pref?dir=true
func Pref(w http.ResponseWriter, r *http.Request) {
// 知道下級文件資源目录
dirName := r.URL.Query().Get("dirName")
data := prefInfo(dirName)
services.ResponseWithJson(w, http.StatusOK, data)
}
// GET http://192.168.21.183:3040/api/rest/maintenance/v1/prefLog?pageNum=1&pageSize=10
func PrefLog(w http.ResponseWriter, r *http.Request) {
pageNumb, pageSize := services.GetPageNumSize(r)
result, err := dborm.DbClient.XEngine.QueryString("SELECT * FROM sys_perf_data limit ?,?", (pageNumb-1)*pageSize, pageSize)
if err != nil {
services.ResponseInternalServerError500ProcessError(w, err)
}
services.ResponseWithJson(w, http.StatusOK, result)
}
// POST http://192.168.21.183:3040/api/rest/maintenance/v1/config
func Config(w http.ResponseWriter, r *http.Request) {
// json 請求參數獲取
var bodyArgs struct {
Key string `json:"key"`
Value string `json:"value"`
}
err := services.JSONBody(r, &bodyArgs)
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
// 進行值更新
if dborm.DbClient.XEngine != nil {
result, err := dborm.DbClient.XEngine.QueryString("SELECT * FROM information_schema.processlist")
if err != nil {
fmt.Println(err)
}
fmt.Println(result)
rse, err := dborm.DbClient.XEngine.Exec("UPDATE sys_config SET value = ? where id = ?", "true", 100)
if err != nil {
fmt.Println(err)
}
fmt.Println(rse)
}
services.ResponseStatusOK200Null(w)
}
// http://192.168.21.183:3040/api/rest/maintenance/v1/sqlClient?type=close
// http://192.168.21.183:3040/api/rest/maintenance/v1/sqlClient?type=connet
// http://192.168.21.183:3040/api/rest/maintenance/v1/sqlClient?type=user
func SqlClient(w http.ResponseWriter, r *http.Request) {
// 关闭
isClose := r.URL.Query().Get("type")
if isClose == "close" && dborm.DbClient.XEngine != nil {
dborm.DbClient.XEngine.Close()
}
// 重连
isConnet := r.URL.Query().Get("type")
if isConnet == "connet" && dborm.DbClient.XEngine == nil {
conf := config.GetYamlConfig()
err := dborm.InitDbClient(conf.Database.Type, conf.Database.User, conf.Database.Password,
conf.Database.Host, conf.Database.Port, conf.Database.Name)
if err != nil {
fmt.Println("dborm.initDbClient err:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
}
// 查询实例
isUser := r.URL.Query().Get("type")
if isUser == "user" && dborm.DbClient.XEngine != nil {
result, err := dborm.DbClient.XEngine.QueryString("SELECT * FROM information_schema.processlist")
if err != nil {
fmt.Println(err)
}
fmt.Println(result)
rse, err := dborm.DbClient.XEngine.Exec("KILL CONNECTION CONNECTION_ID()")
if err != nil {
fmt.Println(err)
}
fmt.Println(rse)
}
// 进行连接测试
err := dborm.DbClient.XEngine.Ping()
if err != nil {
fmt.Println(err)
}
services.ResponseStatusOK200Null(w)
}
// GET http://192.168.21.183:3040/api/rest/maintenance/v1/top?grep=
func Top(w http.ResponseWriter, r *http.Request) {
// 過濾命令
grep := r.URL.Query().Get("grep")
// 命令拼接
var cmd *exec.Cmd
switch runtime.GOOS {
case "linux":
command := "ps -ef "
if grep != "" {
command += grep
}
cmd = exec.Command(command)
case "windows":
command := "wmic process list brief "
if grep != "" {
command += grep
}
cmd = exec.Command("cmd", "/C", command)
}
out, err := cmd.CombinedOutput()
fmt.Println(string(out))
if err != nil {
fmt.Println(err)
}
services.ResponseWithJson(w, http.StatusOK, string(out))
}
// PATCH http://192.168.21.183:3040/api/rest/maintenance/v1/top?ops=&name=
func TopOps(w http.ResponseWriter, r *http.Request) {
// json 請求參數獲取
var bodyArgs struct {
Ops string `json:"ops"`
Pid string `json:"pid"`
}
err := services.JSONBody(r, &bodyArgs)
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
// 命令拼接
var cmd *exec.Cmd
switch runtime.GOOS {
case "linux":
switch bodyArgs.Ops {
case "kill":
cmd = exec.Command("kill", "-9", bodyArgs.Pid)
}
case "windows":
switch bodyArgs.Ops {
case "kill":
cmd = exec.Command("cmd", "/C", "taskkill", "-PID", bodyArgs.Pid, "-F")
}
}
out, err := cmd.CombinedOutput()
fmt.Println(string(out))
if err != nil {
fmt.Println(err)
}
services.ResponseWithJson(w, http.StatusOK, string(out))
}

213
features/mml/mml.go Normal file
View File

@@ -0,0 +1,213 @@
package mml
import (
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"strings"
"time"
"ems.agt/lib/dborm"
"ems.agt/lib/global"
"ems.agt/lib/log"
"ems.agt/lib/mmlp"
"ems.agt/lib/services"
"ems.agt/restagent/config"
"github.com/gorilla/mux"
_ "github.com/go-sql-driver/mysql"
)
const (
//经过测试linux下延时需要大于100ms
TIME_DELAY_AFTER_WRITE = 200
)
type Response struct {
Data []string `json:"data"`
}
type MMLRequest struct {
MML []string `json:"mml"`
}
var (
// MML interface
UriMML = config.UriPrefix + "/opeartionManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/mml"
UriNeOmMml = config.UriPrefix + "/omManagement/{apiVersion}/mml/{netype}/{neid}"
UriOmMmlExt = config.UriPrefix + "/opeartionManagement/{apiVersion}/elementType/OMC/objectType/mml"
UriOmMmlInt = config.UriPrefix + "/omManagement/{apiVersion}/mml/{neType}/{neId}"
)
func PostMMLToNF(w http.ResponseWriter, r *http.Request) {
log.Debug("PostMMLToNF processing... ")
vars := mux.Vars(r)
neType := vars["elementTypeValue"]
params := r.URL.Query()
neId := params["ne_id"]
if len(neId) == 0 {
log.Error("NOT FOUND ne_id")
services.ResponseBadRequest400WrongParamValue(w)
return
}
log.Debug("neType:", neType, "neId", neId)
if strings.ToLower(neType) == "omc" {
PostMMLToOMC(w, r)
return
}
_, err := services.CheckExtValidRequest(w, r)
if err != nil {
log.Error("Failed to CheckMmlValidRequest:", err)
return
}
neInfo := new(dborm.NeInfo)
neInfo, err = dborm.XormGetNeInfo(neType, neId[0])
if err != nil {
log.Error("dborm.XormGetNeInfo is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
var buf [8192]byte
var n int
var mmlResult []string
if neInfo != nil {
hostMML := fmt.Sprintf("%s:%d", neInfo.Ip, config.GetYamlConfig().MML.Port)
conn, err := net.Dial("tcp", hostMML)
if err != nil {
errMsg := fmt.Sprintf("Failed to dial %s: %v", hostMML, err)
log.Error(errMsg)
mmlResult = append(mmlResult, errMsg)
response := Response{mmlResult}
services.ResponseWithJson(w, http.StatusOK, response)
return
}
loginStr := fmt.Sprintf("%s\n%s\n", config.GetYamlConfig().MML.User, config.GetYamlConfig().MML.Password)
n, err = conn.Write([]byte(loginStr))
if err != nil {
log.Errorf("Error: %s", err.Error())
return
}
time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE)
n, err = conn.Read(buf[0:])
if err != nil {
log.Errorf("Error: %s", err.Error())
return
}
log.Debug(string(buf[0:n]))
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
log.Debug("Body:", string(body))
mmlRequest := new(MMLRequest)
_ = json.Unmarshal(body, mmlRequest)
for _, mml := range mmlRequest.MML {
mmlCommand := fmt.Sprintf("%s\n", mml)
log.Debug("mml command:", mmlCommand)
n, err = conn.Write([]byte(mmlCommand))
if err != nil {
log.Errorf("Error: %s", err.Error())
return
}
time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE)
n, err = conn.Read(buf[0:])
if err != nil {
log.Errorf("Error: %s", err.Error())
return
}
log.Debug(string(buf[0 : n-len(neType)-2]))
mmlResult = append(mmlResult, string(buf[0:n-len(neType)-2]))
}
}
response := Response{mmlResult}
services.ResponseWithJson(w, http.StatusOK, response)
}
func PostMMLToOMC(w http.ResponseWriter, r *http.Request) {
log.Debug("PostMMLToOMC processing... ")
token, err := services.CheckExtValidRequest(w, r)
if err != nil {
log.Error("Failed to CheckMmlValidRequest:", err)
return
}
params := r.URL.Query()
neId := params["ne_id"]
if len(neId) == 0 {
log.Error("NOT FOUND ne_id ")
services.ResponseBadRequest400WrongParamValue(w)
return
}
neInfo := new(dborm.NeInfo)
neInfo, err = dborm.XormGetNeInfo("OMC", neId[0])
if err != nil {
log.Error("dborm.XormGetNeInfo is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
log.Trace("neInfo:", neInfo)
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
log.Debug("Body:", string(body))
hostUri := fmt.Sprintf("http://%s:%s", neInfo.Ip, neInfo.Port)
omcMmlVar := &mmlp.MmlVar{
Version: "16.1.1",
Output: mmlp.DefaultFormatType,
Limit: 50,
User: "",
SessionToken: token,
HttpUri: hostUri,
UserAgent: config.GetDefaultUserAgent(),
}
mmlRequest := new(MMLRequest)
_ = json.Unmarshal(body, mmlRequest)
var mmlResult []string
mmlLine := strings.Join(mmlRequest.MML, ";")
var mmlCmds []mmlp.MmlCommand
if err = mmlp.ParseMMLCommand(mmlLine, &mmlCmds); err != nil {
response := fmt.Sprintf("parse command error: %v\n", err)
mmlResult = append(mmlResult, response)
}
for _, mmlCmd := range mmlCmds {
output, err := mmlp.TransMml2HttpReq(omcMmlVar, &mmlCmd)
if err != nil {
response := fmt.Sprintf("translate MML command error: %v]\n", err)
mmlResult = append(mmlResult, response)
}
mmlResult = append(mmlResult, string(*output))
}
response := Response{mmlResult}
services.ResponseWithJson(w, http.StatusOK, response)
}

890
features/mml/parse.go.bak Normal file
View File

@@ -0,0 +1,890 @@
package mml
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"math"
"net/http"
"regexp"
"strconv"
"strings"
"ems.agt/lib/dborm"
"ems.agt/lib/global"
"ems.agt/lib/log"
"github.com/go-resty/resty/v2"
)
type Param struct {
Name string `json:"name"`
Value string `json:"value"`
}
type MmlCommand struct {
Operation string `json:"operation"`
Object string `json:"object"`
Params []Param `json:"params"`
PaList []string `json:"paList"`
AaList []string `json:"aaList"`
AaMap map[string]interface{} `json:"aaMap"`
NaMap map[string]interface{} `json:"naMap"`
AaUri []string `json:"aaUri"`
AaLoc []string `json:"aaLoc"` // for loc parameter
}
type MmlVar struct {
Version string `json:"version"`
Output string `json:"output"`
Limit int `json:"limit"`
}
var OmcMmlVar *MmlVar
func init() {
OmcMmlVar = &MmlVar{Version: "16.1.1", Output: DefaultFormatType, Limit: 50}
}
func SetOmcMmlVarOutput(output string) {
OmcMmlVar.Output = output
}
func SetOmcMmlVarLimit(limit int) {
OmcMmlVar.Limit = limit
}
func splitByColon(str string) []string {
return splitBy(str, ':')
}
func splitByComma(str string) []string {
return splitBy(str, ',')
}
func splitBy(str string, sep rune) []string {
var result []string
var stack []string
var current []rune
var quotes, apoFlag bool = false, false
for _, c := range str {
if c == '{' || c == '[' || (c == '\'' && apoFlag == false) || (c == '"' && quotes == false) { // "'"
apoFlag = true
quotes = true
stack = append(stack, string(c))
} else if c == '}' || c == ']' || (c == '\'' && apoFlag == true) || (c == '"' && quotes == true) {
apoFlag = false
quotes = false
if len(stack) > 0 {
stack = stack[:len(stack)-1]
}
}
if c == sep && len(stack) == 0 {
result = append(result, string(current))
current = []rune{}
} else {
current = append(current, c)
}
}
result = append(result, string(current))
return result
}
func ParseMMLCommand(mmlStr string, mmlComms *[]MmlCommand) error {
log.Info("ParseMMLCommand processing ...")
log.Debug("mmlStr: ", mmlStr)
mc := new(MmlCommand)
reg := regexp.MustCompile(`\s*;\s*`)
mmls := reg.Split(mmlStr, -1)
for _, mml := range mmls {
log.Trace("mml:", mml)
if len(mml) == 0 {
continue
}
//reg := regexp.MustCompile(`\s*:\s*`)
//ms := reg.Split(mml, -1)
ms := splitByColon(mml)
if len(ms) < 1 || len(ms) > 2 {
err := global.ErrMmlInvalidCommandFormat
log.Error(err)
return err
}
if len(ms) == 2 {
cmd := strings.Trim(ms[0], " ")
reg = regexp.MustCompile(`\s+`)
cs := reg.Split(cmd, -1)
//cs := strings.Split(cmd, " ")
if len(cs) == 2 {
mc.Operation = cs[0]
mc.Object = cs[1]
} else {
err := global.ErrMmlInvalidCommandFormat
log.Error(err)
return err
}
//reg = regexp.MustCompile(`\s*,\s*`)
//reg = regexp.MustCompile(`(?U)(?<!\{[^{}]*),(?![^{}]*\})|(?<!\"[^\"]*),(?![^\"]*\")|(?<!\[[^\[\]]*),(?![^\[\]]*\])`)
//reg = regexp.MustCompile(`,[^'"\(\)]+`)
//params := reg.Split(ms[1], -1)
params := splitByComma(strings.Trim(ms[1], " "))
//params := strings.Split(ms[1], ",")
for _, p := range params {
log.Trace("p:", p)
if p == "" {
continue
}
mc.PaList = append(mc.PaList, p)
reg = regexp.MustCompile(`\s*=\s*`)
pvs := reg.Split(p, -1)
log.Trace("pvs:", pvs)
if len(pvs) == 2 {
mc.Params = append(mc.Params, Param{Name: pvs[0], Value: pvs[1]})
} else {
err := global.ErrMmlInvalidCommandFormat
log.Error(err)
return err
}
}
} else if len(ms) == 1 {
cmd := ms[0]
reg = regexp.MustCompile(`\s+`)
cs := reg.Split(cmd, -1)
//cs := strings.Split(cmd, " ")
if len(cs) == 2 {
mc.Operation = cs[0]
mc.Object = cs[1]
} else {
err := global.ErrMmlInvalidCommandFormat
log.Error(err)
return err
}
} else {
err := global.ErrMmlInvalidCommandFormat
log.Error(err)
return err
}
err := ParseMMLAlias(mc)
if err != nil {
err := global.ErrMmlInvalidCommandFormat
log.Error(err)
return err
}
*mmlComms = append(*mmlComms, *mc)
}
return nil
}
func ParseMMLAlias(mml *MmlCommand) error {
where := fmt.Sprintf("operation='%s' AND object='%s'", mml.Operation, mml.Object)
mc, err := dborm.XormGetMmlCommand("mml_command", where)
if err != nil {
log.Error("Failed to XormGetMmlCommand: ", err)
return err
}
if mc == nil {
err := errors.New("Not found mml map")
log.Error(err)
return err
}
log.Debug("mml command: ", mc)
aaMap := make(map[string]interface{})
naMap := make(map[string]interface{})
for _, pn := range mml.Params {
log.Trace("pn: ", pn)
for _, param := range mc.ParamJson {
log.Trace("param: ", param)
var pv string
if pn.Name == param.Name {
if param.Apostr == "true" {
pv = fmt.Sprintf("'%v'", pn.Value)
} else {
pv = fmt.Sprintf("%v", pn.Value)
}
var aa, av string
if param.Alias != "" {
aa = fmt.Sprintf("%s=%v", param.Alias, pv)
av = fmt.Sprintf("%v", pv)
switch param.Type {
case "int":
aaMap[param.Alias] = pn.Value
naMap[param.Alias] = pn.Value
default:
aaMap[param.Alias] = pv
naMap[param.Alias] = fmt.Sprintf("%v", pn.Value)
}
} else {
aa = fmt.Sprintf("%s=%v", param.Name, pv)
av = fmt.Sprintf("%v", pv)
switch param.Type {
case "int":
aaMap[param.Name] = pn.Value
naMap[param.Name] = pn.Value
default:
aaMap[param.Name] = pv
naMap[param.Name] = fmt.Sprintf("%v", pn.Value)
}
}
if param.Loc == "" || param.Loc == "true" {
mml.AaLoc = append(mml.AaLoc, aa)
mml.AaUri = append(mml.AaUri, av)
}
//mml.AaMap = append(mml.AaMap, aaMap)
mml.AaList = append(mml.AaList, aa)
break
}
}
}
mml.AaMap = aaMap
mml.NaMap = naMap
log.Trace("mml.AaMap: ", mml.AaMap)
log.Trace("mml.NaMap: ", mml.NaMap)
log.Trace("mml.AaList: ", mml.AaList)
return nil
}
func ParseMMLParams(mmlComms *[]MmlCommand) error {
for _, mml := range *mmlComms {
where := fmt.Sprintf("operation='%s' AND object='%s'", mml.Operation, mml.Object)
mc, err := dborm.XormGetMmlCommand("mml_command", where)
if err != nil {
log.Error("Failed to XormGetMmlCommand: ", err)
return err
}
if mc == nil {
err := errors.New("Not found mml map")
log.Error(err)
return err
}
log.Debug("mml command: ", mc)
for _, pn := range mml.Params {
log.Trace("pn: ", pn)
for _, param := range mc.ParamJson {
log.Trace("param: ", param)
var pv string
if pn.Name == param.Name {
if param.Apostr == "true" {
pv = fmt.Sprintf("'%v'", pn.Value)
} else {
pv = fmt.Sprintf("%v", pn.Value)
}
var aa string
aaMap := make(map[string]interface{})
if param.Alias != "" {
aa = fmt.Sprintf("%s=%v", param.Alias, pv)
switch param.Type {
case "int":
aaMap[param.Alias] = pn.Value
case "string":
aaMap[param.Alias] = pv
}
} else {
aa = fmt.Sprintf("%s=%v", param.Name, pv)
switch param.Type {
case "int":
aaMap[param.Name] = pn.Value
case "string":
aaMap[param.Name] = pv
}
}
//mml.AaMap = append(mml.AaMap, aaMap)
mml.AaList = append(mml.AaList, aa)
break
}
}
}
log.Trace("mml.AaMap: ", mml.AaMap)
log.Trace("mml.AaList: ", mml.AaList)
*mmlComms = append(*mmlComms, mml)
}
return nil
}
func parseRequestUri(httpUri string, mmlMap *dborm.MmlHttpMap, mml *MmlCommand) string {
requestURI := fmt.Sprintf("%s%s", httpUri, mmlMap.URI)
if mmlMap.ExtUri != "" && len(mml.AaUri) > 0 {
extUri := strings.Join(mml.AaUri, "/")
requestURI = requestURI + fmt.Sprintf(mmlMap.ExtUri, extUri)
}
if mmlMap.Params != "" {
params := strings.Join(mml.AaLoc, "+and+")
params = strings.ReplaceAll(params, " ", "+") // replace " " to "+"
requestURI = fmt.Sprintf("%s?%s=%s", requestURI, mmlMap.Params, params)
}
return requestURI
}
func TransMml2HttpReq(httpUri, uerAgent string, mml *MmlCommand) (*[]byte, error) {
log.Info("TransMml2HttpReq processing ...")
log.Debug("mml: ", mml)
where := fmt.Sprintf("operation='%s' AND object='%s'", mml.Operation, mml.Object)
mmlMap, err := dborm.XormGetMmlHttpMap("mml_http_map", where)
if err != nil {
log.Error("Failed to XormGetMmlHttpMap: ", err)
return ParseErrorOutput(err), err
}
if mmlMap == nil {
err := errors.New("Not found mml map")
log.Error(err)
return ParseErrorOutput(err), err
}
log.Trace("mmlMap: ", mmlMap)
if mmlMap.Output == "" {
mmlMap.Output = "{}"
}
outputJson := new(dborm.MmlOutput)
err = json.Unmarshal([]byte(mmlMap.Output), outputJson)
if err != nil {
log.Error("Failed to Unmarshal:", err)
return ParseErrorOutput(err), err
}
log.Trace("outputJson: ", outputJson)
inputJson := new(dborm.MmlInput)
log.Trace("mmlMap.Input: ", mmlMap.Input)
if mmlMap.Input == "" {
mmlMap.Input = "{}"
}
err = json.Unmarshal([]byte(mmlMap.Input), inputJson)
if err != nil {
log.Error("Failed to Unmarshal:", err)
return ParseErrorOutput(err), err
}
log.Trace("inputJson: ", inputJson)
var requestURI string
var output *[]byte
client := resty.New()
switch strings.ToLower(mmlMap.Method) {
case "get":
requestURI = parseRequestUri(httpUri, mmlMap, mml)
log.Debugf("method: Get requestURI: %s", requestURI)
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": uerAgent}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Get(requestURI)
if err != nil {
log.Error("Failed to Get:", err)
output = ParseErrorOutput(err)
} else {
output = ParseOutputResponse(outputJson, response)
}
case "post":
requestURI = parseRequestUri(httpUri, mmlMap, mml)
body := ParseInputBody(inputJson, mml)
log.Debugf("method: Post requestURI: %s", requestURI)
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": uerAgent}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
SetBody(*body).
Post(requestURI)
if err != nil {
log.Error("Failed to Post:", err)
output = ParseErrorOutput(err)
} else {
output = ParseOutputResponse(outputJson, response)
}
case "put":
requestURI = parseRequestUri(httpUri, mmlMap, mml)
body := ParseInputBody(inputJson, mml)
log.Debugf("method: Put requestURI: %s", requestURI)
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": uerAgent}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
SetBody(*body).
Put(requestURI)
if err != nil {
log.Error("Failed to Put:", err)
output = ParseErrorOutput(err)
} else {
output = ParseOutputResponse(outputJson, response)
}
case "delete":
requestURI = parseRequestUri(httpUri, mmlMap, mml)
log.Debugf("method: Delete requestURI: %s", requestURI)
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": uerAgent}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Delete(requestURI)
if err != nil {
log.Error("Failed to Delete:", err)
output = ParseErrorOutput(err)
} else {
output = ParseOutputResponse(outputJson, response)
}
case "patch":
requestURI = parseRequestUri(httpUri, mmlMap, mml)
log.Debugf("method: patch requestURI: %s", requestURI)
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": uerAgent}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Patch(requestURI)
if err != nil {
log.Error("Failed to Patch:", err)
output = ParseErrorOutput(err)
} else {
output = ParseOutputResponse(outputJson, response)
}
default:
err := errors.New("not found mml command")
log.Error(err)
output = ParseErrorOutput(err)
}
return output, nil
}
const (
MaxMmlOutputBufferSize = 1000000
FormatTypeJson = "json"
FormatTypeTable = "table"
DefaultFormatType = FormatTypeTable
)
const (
RetCodeSucceeded = 0
RetCodeFailed = 0
)
func ParseInputBody(inputJson *dborm.MmlInput, mml *MmlCommand) *[]byte {
inputBody := make(map[string]interface{})
log.Trace("mml.NaMap:", mml.NaMap)
log.Trace("mml.AaMap:", mml.AaMap)
if strings.ToLower(inputJson.BodyFmt) == "putdb" {
for _, icol := range inputJson.Cols {
log.Trace("icol:", icol)
mml.NaMap[icol.Name] = icol.Value
}
inputBody[inputJson.BodyKey] = mml.NaMap
} else {
inputParams := make([]map[string]interface{}, 0)
inputParams = append(inputParams, mml.NaMap)
inputBody[inputJson.BodyKey] = inputParams
}
body, err := json.Marshal(inputBody)
if err != nil {
log.Error("Failed to marshal:", err)
}
log.Trace("inputBody:", inputBody)
log.Trace("body:", string(body))
return &body
}
func ParseOutputResponse(outputJson *dborm.MmlOutput, response *resty.Response) *[]byte {
var output []byte
var str bytes.Buffer
switch response.StatusCode() {
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
if OmcMmlVar.Output == FormatTypeJson {
code := fmt.Sprintf("StatusCode = %d status %s\n\n", response.StatusCode(), response.Status())
title := formatTitle(outputJson.Title)
json.Indent(&str, response.Body(), "", " ")
log.Trace(str.String())
output = global.BytesCombine1([]byte(code), []byte(title), str.Bytes(), []byte("\n"))
} else {
log.Trace("Body:", string(response.Body()))
mapDatas := make(map[string]interface{}, 0)
err := json.Unmarshal(response.Body(), &mapDatas)
if err != nil {
log.Error("Failed to json.Unmarshal:", err)
//output = *ParseErrorOutput(err)
output = *ParseErrorOutput(string(response.Body()))
return &output
}
log.Trace("mapDatas:", mapDatas)
switch strings.ToLower(outputJson.RetFmt) {
case "getdb":
if len(mapDatas) > 0 {
var data interface{}
for _, data = range mapDatas {
log.Trace("data:", data)
break
}
if len(data.([]interface{})) > 0 {
table := (data.([]interface{}))[0]
log.Trace("table:", table)
code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded)
title := formatTitle(outputJson.Title)
fmtResults := ParseTableOutput(outputJson, table)
output = global.BytesCombine1([]byte(code), []byte(title), []byte(fmtResults))
}
}
case "deletedb":
var data interface{}
for _, data = range mapDatas {
log.Trace("data:", data)
break
}
if len(data.(map[string]interface{})) > 0 {
table := data.(map[string]interface{})
code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded)
fmtResults := ParseDBOperOutput(outputJson, table)
output = global.BytesCombine1([]byte(code), []byte(fmtResults))
}
case "postdb":
var data interface{}
for _, data = range mapDatas {
log.Trace("data:", data)
break
}
if len(data.(map[string]interface{})) > 0 {
table := data.(map[string]interface{})
code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded)
fmtResults := ParseDBOperOutput(outputJson, table)
output = global.BytesCombine1([]byte(code), []byte(fmtResults))
}
case "putdb":
var data interface{}
for _, data = range mapDatas {
log.Trace("data:", data)
break
}
if len(data.(map[string]interface{})) > 0 {
table := data.(map[string]interface{})
code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded)
fmtResults := ParseDBOperOutput(outputJson, table)
output = global.BytesCombine1([]byte(code), []byte(fmtResults))
}
case "getnf":
if len(mapDatas) > 0 {
var data interface{}
for _, data = range mapDatas {
log.Trace("data:", data)
break
}
if len(data.([]interface{})) > 0 {
//table := (data.([]interface{}))[0]
//log.Trace("table:", table)
code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded)
title := formatTitle(outputJson.Title)
fmtResults := ParseNFTableOutput(outputJson, data)
output = global.BytesCombine1([]byte(code), []byte(title), []byte(fmtResults))
}
}
default:
code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded)
output = global.BytesCombine1([]byte(code))
}
}
default:
if OmcMmlVar.Output == FormatTypeJson {
code := fmt.Sprintf("StatusCode = %d status %s\n\n", response.StatusCode(), response.Status())
//title := formatTitle("Network Element Information")
json.Indent(&str, response.Body(), "", " ")
log.Trace(str.String())
output = global.BytesCombine1([]byte(code), str.Bytes(), []byte("\n"))
} else {
log.Trace("Body:", string(response.Body()))
mapResults := make(map[string]interface{}, 0)
err := json.Unmarshal(response.Body(), &mapResults)
if err != nil {
log.Error("Failed to json.Unmarshal:", err)
output = *ParseErrorOutput(string(response.Body()))
} else {
log.Trace("mapResults:", mapResults)
errResult := mapResults["error"]
log.Trace("errResult:", errResult)
if len(errResult.(map[string]interface{})) > 0 {
errCode, _ := strconv.Atoi(fmt.Sprintf("%v", errResult.(map[string]interface{})["errorCode"]))
errorInfo := errResult.(map[string]interface{})["errorInfo"]
output = []byte(fmt.Sprintf(outputJson.ErrMsg, errCode, errorInfo))
}
}
}
}
return &output
}
func ParseDBOperOutput(outputJson *dborm.MmlOutput, cols any) string {
var colOutput []dborm.ColOutput = outputJson.Cols
var value, retFmtCols string
if len(cols.(map[string]interface{})) > 0 {
if len(colOutput) > 0 {
coln := colOutput[0].Name
value = fmt.Sprintf("%v", cols.(map[string]interface{})[coln])
log.Tracef("coln:%s value:%s", coln, value)
retFmtCols = colOutput[0].Display + " = " + value + "\n\n"
}
}
return retFmtCols
}
func ParseNFTableOutput(outputJson *dborm.MmlOutput, cols any) string {
var colOutput []dborm.ColOutput
var fmtColName string
var colName []string
var spaceNum int = 1
var alignmentM, alignmentSN, alignmentSV string = "Left", "Right", "Left"
if outputJson.SepSpaceNum != 0 {
spaceNum = outputJson.SepSpaceNum
}
if outputJson.AlignmentM != "" {
alignmentM = outputJson.AlignmentM
}
if outputJson.AlignmentSN != "" {
alignmentSN = outputJson.AlignmentSN
}
if outputJson.AlignmentSV != "" {
alignmentSV = outputJson.AlignmentSV
}
maxLength := math.MinInt64
for _, coln := range outputJson.Cols {
log.Trace("coln:", coln)
if len(coln.Display) > maxLength {
maxLength = len(coln.Display)
}
if coln.Length < len(coln.Display) {
coln.Length = len(coln.Display)
}
colName = append(colName, ParseAlignmentOutput(coln.Length, alignmentM, coln.Display))
colOutput = append(colOutput, coln)
}
fmtColName = formatLineBySpace(&colName, spaceNum)
log.Trace("fmtColName:", fmtColName)
var retFmtCols string
var fmtColValues []string
var numberResult int
// for _, colnvs := range cols.([]interface{}) {
// log.Trace("colnvs:", colnvs)
// if colnvs == nil {
// break
// }
numberResult = len(cols.([]interface{}))
if numberResult == 1 && outputJson.SingleList == true {
colnv := cols.([]interface{})[0]
log.Trace("colnv:", colnv)
var fmtNV []string
for _, coln := range colOutput {
fmtName := ParseAlignmentOutput(maxLength, alignmentSN, coln.Display)
log.Tracef("alignmentSN:%s fmtName:%s", alignmentSN, fmtName)
value := fmt.Sprintf("%v", colnv.(map[string]interface{})[coln.Name])
fmtValue := ParseAlignmentOutput(coln.Length, alignmentSV, value)
fmtNV = append(fmtNV, fmtName+": "+fmtValue)
}
fmtResults := strings.Join(fmtNV, "\n")
log.Tracef("fmtResults:\n%s", fmtResults)
fmtEnd := fmt.Sprintf(outputJson.End, numberResult)
retFmtCols = fmtResults + "\n\n" + fmtEnd
log.Tracef("retFmtCols:\n%s", retFmtCols)
return retFmtCols
} else {
for i := 0; i < numberResult; i++ {
colnv := cols.([]interface{})[i]
log.Trace("colnv:", colnv)
var colValues []string
var newVal []string
for _, coln := range colOutput {
value := fmt.Sprintf("%v", colnv.(map[string]interface{})[coln.Name])
if len(coln.Alias) != 0 {
enumVal, _ := strconv.Atoi(value)
value = parseEnumAlias(&(coln.Alias), enumVal)
}
newVal = append(newVal, ParseAlignmentOutput(coln.Length, alignmentM, value))
}
colValues = append(colValues, formatLineBySpace(&newVal, spaceNum))
log.Trace("colValues:", colValues)
fmtColValues = append(fmtColValues, strings.Join(colValues, "\n"))
log.Trace("fmtColValues:", fmtColValues)
}
fmtEnd := fmt.Sprintf(outputJson.End, numberResult)
retFmtCols = fmtColName + "\n\n" + strings.Join(fmtColValues, "\n") + "\n\n" + fmtEnd
log.Tracef("retFmtCols:\n%s", retFmtCols)
return retFmtCols
}
// }
// fmtEnd := fmt.Sprintf(outputJson.End, numberResult)
// retFmtCols = fmtColName + "\n" + strings.Join(fmtColValues, "\n") + "\n\n" + fmtEnd
// log.Tracef("retFmtCols:\n%s", retFmtCols)
// return retFmtCols
}
func ParseTableOutput(outputJson *dborm.MmlOutput, cols any) string {
var colOutput []dborm.ColOutput
var fmtColName string
var colName []string
var spaceNum int = 1
var alignmentM, alignmentSN, alignmentSV string = "Left", "Right", "Left"
if outputJson.SepSpaceNum != 0 {
spaceNum = outputJson.SepSpaceNum
}
if outputJson.AlignmentM != "" {
alignmentM = outputJson.AlignmentM
}
if outputJson.AlignmentSN != "" {
alignmentSN = outputJson.AlignmentSN
}
if outputJson.AlignmentSV != "" {
alignmentSV = outputJson.AlignmentSV
}
maxLength := math.MinInt64
for _, coln := range outputJson.Cols {
log.Trace("coln:", coln)
if len(coln.Display) > maxLength {
maxLength = len(coln.Display)
}
if coln.Length < len(coln.Display) {
coln.Length = len(coln.Display)
}
colName = append(colName, ParseAlignmentOutput(coln.Length, alignmentM, coln.Display))
colOutput = append(colOutput, coln)
}
fmtColName = formatLineBySpace(&colName, spaceNum)
log.Trace("fmtColName:", fmtColName)
var retFmtCols string
var fmtColValues []string
var numberResult int
for _, colnvs := range cols.(map[string]interface{}) {
log.Trace("colnvs:", colnvs)
if colnvs == nil {
break
}
numberResult = len(colnvs.([]interface{}))
if numberResult == 1 && outputJson.SingleList == true {
colnv := colnvs.([]interface{})[0]
log.Trace("colnv:", colnv)
var fmtNV []string
for _, coln := range colOutput {
fmtName := ParseAlignmentOutput(maxLength, alignmentSN, coln.Display)
log.Tracef("alignmentSN:%s fmtName:%s", alignmentSN, fmtName)
value := fmt.Sprintf("%v", colnv.(map[string]interface{})[coln.Name])
fmtValue := ParseAlignmentOutput(coln.Length, alignmentSV, value)
fmtNV = append(fmtNV, fmtName+": "+fmtValue)
}
fmtResults := strings.Join(fmtNV, "\n")
log.Tracef("fmtResults:\n%s", fmtResults)
fmtEnd := fmt.Sprintf(outputJson.End, numberResult)
retFmtCols = fmtResults + "\n\n" + fmtEnd
log.Tracef("retFmtCols:\n%s", retFmtCols)
return retFmtCols
} else {
for i := 0; i < numberResult; i++ {
colnv := colnvs.([]interface{})[i]
log.Trace("colnv:", colnv)
var colValues []string
var newVal []string
for _, coln := range colOutput {
value := fmt.Sprintf("%v", colnv.(map[string]interface{})[coln.Name])
if len(coln.Alias) != 0 {
enumVal, _ := strconv.Atoi(value)
value = parseEnumAlias(&(coln.Alias), enumVal)
}
newVal = append(newVal, ParseAlignmentOutput(coln.Length, alignmentM, value))
}
colValues = append(colValues, formatLineBySpace(&newVal, spaceNum))
log.Trace("colValues:", colValues)
fmtColValues = append(fmtColValues, strings.Join(colValues, "\n"))
log.Trace("fmtColValues:", fmtColValues)
}
fmtEnd := fmt.Sprintf(outputJson.End, numberResult)
retFmtCols = fmtColName + "\n\n" + strings.Join(fmtColValues, "\n") + "\n\n" + fmtEnd
log.Tracef("retFmtCols:\n%s", retFmtCols)
return retFmtCols
}
}
fmtEnd := fmt.Sprintf(outputJson.End, numberResult)
retFmtCols = fmtColName + "\n" + strings.Join(fmtColValues, "\n") + "\n\n" + fmtEnd
log.Tracef("retFmtCols:\n%s", retFmtCols)
return retFmtCols
}
func parseEnumAlias(alias *[]string, enumVal int) string {
return (*alias)[enumVal]
}
func formatLineBySpace(strArray *[]string, spaceNum int) string {
space := strings.Repeat(" ", spaceNum)
return strings.Join(*strArray, space)
}
func ParseAlignmentOutput(length int, alignment string, str string) string {
spaceLen := length - len(str)
if spaceLen < 0 {
log.Warnf("len(str=%s)=%d more length=%d", str, len(str), length)
spaceLen = 0
}
var retStr string
switch alignment {
case "Left":
suffix := strings.Repeat(" ", spaceLen)
retStr = str + suffix
case "Right":
prefix := strings.Repeat(" ", spaceLen)
retStr = prefix + str
log.Tracef("retStr:%s", retStr)
case "Middle":
prefix := strings.Repeat(" ", int(math.Ceil(float64(spaceLen)/2)))
suffix := strings.Repeat(" ", int(math.Floor(float64(spaceLen)/2)))
retStr = prefix + str + suffix
}
log.Tracef("length=%d, spaceLne=%d, alignment=%s, str=%s, retStr=%s", length, spaceLen, alignment, str, retStr)
return retStr
}
func ParseErrorOutput(err any) *[]byte {
var output []byte
var formatType string = DefaultFormatType
if formatType == FormatTypeJson {
output = []byte(fmt.Sprintf("ErrorCode = 1 Error message: %v\n\n", err))
} else {
output = []byte(fmt.Sprintf("RetCode = -1 operation failed: %v\n\n", err))
}
return &output
}
func formatTitle(title string) string {
var builder strings.Builder
builder.WriteString(title)
builder.WriteString("\n")
for i := 0; i < len(title); i++ {
builder.WriteString("-")
}
builder.WriteString("\n")
return builder.String()
}
func formatTableOutput() {
}

View File

@@ -0,0 +1,51 @@
package monitor
import (
"net/http"
websocket2 "ems.agt/lib/websocket"
"ems.agt/restagent/config"
"github.com/gorilla/websocket"
)
var (
// 進程
UriWs = config.UriPrefix + "/monitor/{apiVersion}/process/ws"
)
var wsUpgrade = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
func ProcessWs(w http.ResponseWriter, r *http.Request) {
ws, err := wsUpgrade.Upgrade(w, r, nil)
if err != nil {
return
}
wsClient := websocket2.NewWsClient("processClient", ws)
go wsClient.Read()
go wsClient.Write()
}
// @Tags Process
// @Summary Stop Process
// @Description 停止进程
// @Param request body request.ProcessReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /process/stop [post]
// @x-panel-log {"bodyKeys":["PID"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"结束进程 [PID]","formatEN":"结束进程 [PID]"}
func StopProcess(w http.ResponseWriter, r *http.Request) {
// var req request.ProcessReq
// if err := c.ShouldBindJSON(&req); err != nil {
// helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
// return
// }
// if err := processService.StopProcess(req); err != nil {
// helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
// return
// }
// helper.SuccessWithOutData(c)
}

269
features/nbi/nbi.go Normal file
View File

@@ -0,0 +1,269 @@
package nbi
import (
"bytes"
"fmt"
"net/http"
"strings"
"ems.agt/lib/dborm"
"github.com/go-resty/resty/v2"
"github.com/gorilla/mux"
"ems.agt/lib/global"
"ems.agt/lib/log"
"ems.agt/lib/oauth"
"ems.agt/lib/services"
"ems.agt/lib/session"
"ems.agt/restagent/config"
)
type ErrorOAuthResponse struct {
Error map[string]interface{}
}
type FailOAuthResponse struct {
Error struct {
ErrorCode string
ErrorInfo string
}
}
type ApiResponse struct {
ResultCode string
ResultMessage interface{}
}
var globalSession = session.NewSessManager("restagent")
var (
MAX_RMUID_NUM int
MAX_ALARMID_NUM int
MAX_PMUID_NUM int
MAX_SUBID_NUM int
MAX_URI_LEN int
RMUID_REGEXP string
)
var (
// Northbound interface
GetNRMUri = config.UriPrefix + "/resourceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/{objectTypeValue}"
NorthboundGetAlarmUri = config.UriPrefix + "/faultManagement/{apiVersion}/alarms" // ?alarmIds={alarmIdValues}
)
func CheckParameterName(r *http.Request) []string {
var errorParams []string
vars := r.URL.Query()
for k, v := range vars {
log.Debug("vars:", k, v)
if k != "rmUIDs" && k != "fields" {
errorParams = append(errorParams, k)
}
}
return errorParams
}
func GetRmUIDArr(r *http.Request) []string {
vars := r.URL.Query()
rmUIDs, ok := vars["rmUIDs"]
if !ok {
log.Debug("rmUIDs is not exist")
return nil
}
var rmUIDValues []string
for _, r := range rmUIDs {
if r != "" {
rmUIDValues = global.MergeStringArr(rmUIDValues, strings.Split(r, `,`))
}
}
return rmUIDValues
}
func GetAttrNameArr(r *http.Request) []string {
vars := r.URL.Query()
fields, ok := vars["fields"]
if !ok {
log.Debug("attributeNames does not exist")
return nil
}
var attrNames []string
for _, a := range fields {
if a != "" {
attrNames = global.MergeStringArr(attrNames, strings.Split(a, `,`))
}
}
return attrNames
}
func CheckValidRmUID(rmUIDs []string) []string {
log.Debug("CheckValidRmUID processing... ")
var invalidRmUIDs []string
for _, r := range rmUIDs {
if !global.MatchRmUID(RMUID_REGEXP, r) {
invalidRmUIDs = append(invalidRmUIDs, r)
}
}
return invalidRmUIDs
}
func CheckLocalRmUID(rmUIDs []string) string {
log.Debug("GetLocalRmUID processing... ")
rmUID := config.GetRmUIDFromConfig()
for _, r := range rmUIDs {
if r == rmUID {
return rmUID
}
}
return ""
}
func NBIGetNRMFromNF(w http.ResponseWriter, r *http.Request) {
log.Debug("NorthGetNRMFromNF processing... ")
// response 414-4 uri too long ? (optional)
// todo ... ?
if bytes.Count([]byte(r.RequestURI), nil) > config.GetUriMaxLenFromConfig() {
log.Error("Request Uri too long:", bytes.Count([]byte(r.RequestURI), nil), config.GetUriMaxLenFromConfig())
services.ResponseRequestURITooLong414UriTooLong(w)
return
}
// check media type(content type) only support "application/json"
// response 415-1
if !services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) {
log.Debug("Invalid Content-Type")
services.ResponseUnsupportedMediaType415(w)
return
}
// error processing ...
// 401-1 response
token, ret := oauth.IsCarriedToken(r)
if ret == false {
log.Error("AccessToken is not carried")
services.ResponseUnauthorized401AccessTokenNotCarried(w)
return
}
// 401-2 response
if dborm.XormExistValidToken(token, config.GetExpiresFromConfig()) == false {
log.Error("AccessToken fails or does not exist")
services.ResponseUnauthorized401AccessTokenNotExist(w)
return
}
_, err := dborm.XormUpdateSessionShakeTime(token)
if err != nil {
log.Error("Failed to update session table:", err)
services.ResponseUnauthorized401AccessTokenNotExist(w)
return
}
/*
// response 403 Forbidden, permissions deny
// todo...
plist := globalSession.GetPermissionFromSession(token)
log.Debug("permission list:", plist)
if len(plist) == 0 || plist[0] == false {
log.Debug("User permission deny")
services.ResponseForbidden403NotPermission(w)
return
}
*/
vars := mux.Vars(r)
neType := vars["elementTypeValue"]
apiVer := vars["apiVersion"]
if apiVer != "v1" {
log.Error("Uri is invalid")
services.ResponseNotFound404UriNotExist(w, r)
return
}
// response 406-1
rmUIDValues := GetRmUIDArr(r)
if rmUIDValues == nil {
log.Error("missing parameter: rmUIDs")
services.ResponseNotAcceptable406MissingParam(w)
return
}
// response 406-2
errorParams := CheckParameterName(r)
if errorParams != nil {
log.Error("parameter name error: ", errorParams)
services.ResponseNotAcceptable406ParamError(w, errorParams)
return
}
// response 400-5
if len(rmUIDValues) == 0 {
log.Error("rmUIDs is wrong or NULL")
services.ResponseBadRequest400WrongParamValue(w)
return
}
// response 414-1
if len(rmUIDValues) > config.GetYamlConfig().Params.RmUIDMaxNum {
log.Error("rmUID greater than", config.GetYamlConfig().Params.RmUIDMaxNum)
services.ResponseRequestURITooLong414NRMNumExceed(w, config.GetYamlConfig().Params.RmUIDMaxNum)
return
}
/*
// response 400-1
// check rmUID is valid
// todo ...
invalidRmUIDs := CheckValidRmUID(rmUIDValues)
if len(invalidRmUIDs) != 0 {
log.Debug("rmUID is invalid")
services.ResponseBadRequest400RmUIDsIsInvalid(w, invalidRmUIDs)
return
}
*/
var response *resty.Response
// respMsg := make(map[string]interface{})
for _, rmUID := range rmUIDValues {
neInfo, err := dborm.XormGetNeInfoByRmUID(neType, rmUID)
if err != nil {
log.Error("dborm.XormGetNeInfo is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI)
log.Debug("requestURI2NF: GET ", requestURI2NF)
client := resty.New()
response, err = client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Get(requestURI2NF)
if err != nil {
log.Error("Failed to Get from NF:", err)
services.ResponseInternalServerError500NFConnectRefused(w)
return
}
/*
switch response.StatusCode() {
case http.StatusOK, http.StatusAccepted, http.StatusNoContent, http.StatusCreated:
respMsg["data"] = response
default:
if response != nil {
services.TransportResponse(w, response.StatusCode(), response.Body())
}
}
*/
}
services.TransportResponse(w, response.StatusCode(), response.Body())
}

203
features/nbi/snmp.go Normal file
View File

@@ -0,0 +1,203 @@
package nbi
import (
"bytes"
"fmt"
"net/http"
"strconv"
"github.com/gorilla/mux"
g "github.com/gosnmp/gosnmp"
"ems.agt/lib/log"
"ems.agt/lib/services"
"ems.agt/restagent/config"
)
func init() {
conf := config.GetYamlConfig()
// Default is a pointer to a GoSNMP struct that contains sensible defaults
// eg port 161, community public, etc
g.Default.Target = conf.NE.Addr
g.Default.Port = conf.NE.Port
err := g.Default.Connect()
if err != nil {
fmt.Printf("Connect() err: %v", err)
}
//defer g.Default.Conn.Close()
MAX_RMUID_NUM = config.GetRmUIDMaxNumFromConfig()
MAX_ALARMID_NUM = config.GetAlarmIDMaxNumFromConfig()
MAX_PMUID_NUM = config.GetPmIDMaxNumFromConfig()
MAX_SUBID_NUM = config.GetSubIDMaxNumFromConfig()
MAX_URI_LEN = config.GetUriMaxLenFromConfig()
RMUID_REGEXP = config.GetRmUIDRegexpFromConfig()
}
func GetNRMByUri(w http.ResponseWriter, r *http.Request) {
log.Debug("GetNRMByUri processing... ")
// response 414-4 uri too long ? (optional)
// todo ... ?
if bytes.Count([]byte(r.RequestURI), nil) > MAX_URI_LEN {
log.Error("Request Uri too long:", bytes.Count([]byte(r.RequestURI), nil))
services.ResponseRequestURITooLong414UriTooLong(w)
return
}
// check media type(content type) only support "application/json"
// response 415-1
if !services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) {
log.Debug("Invalid Content-Type")
services.ResponseUnsupportedMediaType415(w)
return
}
// error processing ...
// 401-1 response
token, ret := globalSession.IsCarriedToken(r)
if ret == false {
log.Error("AccessToken is not carried")
services.ResponseUnauthorized401AccessTokenNotCarried(w)
return
}
// 401-2 response
if globalSession.IsValidToken(token) == false {
log.Error("AccessToken fails or does not exist")
services.ResponseUnauthorized401AccessTokenNotExist(w)
return
}
// response 403 Forbidden, permissions deny
// todo...
plist := globalSession.GetPermissionFromSession(token)
log.Debug("permission list:", plist)
if len(plist) == 0 || plist[0] == false {
log.Error("User permission deny")
services.ResponseForbidden403NotPermission(w)
return
}
vars := mux.Vars(r)
qeuryUri := vars["apiCategory"] + "/" + vars["elementTypeValue"] + "/" + vars["objectTypeValue"]
log.Debug("Get by Uri: ", qeuryUri)
apiVer := vars["apiVersion"]
if apiVer != "v1" {
log.Error("Uri is invalid")
services.ResponseNotFound404UriNotExist(w, r)
return
}
// response 406-1
rmUIDValues := GetRmUIDArr(r)
if rmUIDValues == nil {
log.Error("missing parameter: rmUIDs")
services.ResponseNotAcceptable406MissingParam(w)
return
}
// response 406-2
errorParams := CheckParameterName(r)
if errorParams != nil {
log.Error("parameter name error: ", errorParams)
services.ResponseNotAcceptable406ParamError(w, errorParams)
return
}
// response 400-5
if len(rmUIDValues) == 0 {
log.Error("rmUIDs is wrong or NULL")
services.ResponseBadRequest400WrongParamValue(w)
return
}
// response 414-1
if len(rmUIDValues) > MAX_RMUID_NUM {
log.Error("rmUID greater than", MAX_RMUID_NUM)
services.ResponseRequestURITooLong414NRMNumExceed(w, MAX_RMUID_NUM)
return
}
// response 400-1
// check rmUID is valid
// todo ...
invalidRmUIDs := CheckValidRmUID(rmUIDValues)
if len(invalidRmUIDs) != 0 {
log.Error("rmUID is invalid")
services.ResponseBadRequest400RmUIDsIsInvalid(w, invalidRmUIDs)
return
}
// response 404-2
rmUID := CheckLocalRmUID(rmUIDValues)
if rmUID == "" {
log.Error("rmUID does not exist")
services.ResponseNotFound404NRMNotExist(w, rmUIDValues)
return
}
// response 404-1, uri is not exist in map
attrNames := GetAttrNameArr(r)
var Oids []string
Oids = *config.GetOidByFileds(qeuryUri, attrNames, &Oids)
if len(Oids) == 0 {
log.Error("Nothing of config map")
services.ResponseNotFound404UriNotExist(w, r)
return
}
// response 404-1, uri is not exist in map
var nameOids []config.NameOid
nameOids = *config.GetDataOidByFields(qeuryUri, attrNames, &nameOids)
if len(nameOids) == 0 {
log.Error("Nothing of config map")
services.ResponseNotFound404UriNotExist(w, r)
return
}
result, err2 := g.Default.Get(Oids) // Get() accepts up to g.MAX_OIDS
if err2 != nil {
log.Fatalf("Get() err: %v", err2)
}
// var nameValues []config.NameValue
var nameValue config.NameValue
nameValues := make(map[string]interface{})
nameValues["rmUID"] = rmUID
for i, variable := range result.Variables {
nameValue.Name = nameOids[i].Name
log.Debugf("%d: oid: %s name: %s\n", i, variable.Name, nameValue.Name)
// if nameOids[i].Oid == variable.Name && global.IsContain(attributeNames, nameValue.Name) {
if nameOids[i].Oid == variable.Name {
// the Value of each variable returned by Get() implements
// interface{}. You could do a type switch...
switch variable.Type {
case g.OctetString:
bytes := variable.Value.([]byte)
log.Debugf("string: %s\n", string(bytes))
nameValue.Value = string(bytes)
nameValues[nameValue.Name] = nameValue.Value
case g.Integer:
value := variable.Value.(int)
log.Debugf("integer: %d\n", value)
nameValue.Value = strconv.Itoa(value)
nameValues[nameValue.Name] = nameValue.Value
case g.IPAddress:
value := variable.Value.(string)
log.Debugf("IPAddress: %s\n", variable.Value)
nameValue.Value = value
nameValues[nameValue.Name] = nameValue.Value
default:
// ... or often you're just interested in numeric values.
// ToBigInt() will return the Value as a BigInt, for plugging
// into your calculations.
log.Debugf("number: %d\n", g.ToBigInt(variable.Value))
}
}
}
getResponse := services.DataResponse{nameValues}
services.ResponseWithJson(w, http.StatusOK, getResponse)
}

972
features/pm/performance.go Normal file
View File

@@ -0,0 +1,972 @@
package pm
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strconv"
"time"
"ems.agt/lib/dborm"
"ems.agt/lib/global"
"ems.agt/lib/log"
"ems.agt/lib/services"
"ems.agt/restagent/config"
"xorm.io/xorm"
"github.com/go-resty/resty/v2"
_ "github.com/go-sql-driver/mysql"
"github.com/gorilla/mux"
)
type Response struct {
Data interface{} `json:"data"`
}
type KpiReport struct {
Timestamp string `json:"TimeStamp"`
Task struct {
Period struct {
StartTime string `json:"StartTime"`
EndTime string `json:"EndTime"`
} `json:"Period"`
NE struct {
NEName string `json:"NEName"`
RmUID string `json:"rmUID"`
NeType string `json:"NeType"`
KPIs []struct {
KPIID string `json:"KPIID"`
Value int `json:"Value"`
Err string `json:"Err"`
} `json:"KPIs"`
} `json:"NE"`
} `json:"Task"`
}
type GoldKpi struct {
// Id int `json:"-" xorm:"pk 'id' autoincr"`
Date string `json:"date" xorm:"date"`
Index int `json:"index"`
StartTime string `json:"startTime"`
EndTime string `json:"endTime"`
NEName string `json:"neName" xorm:"ne_name"`
RmUid string `json:"rmUid" xorm:"rm_uid"`
NEType string `json:"neType" xorm:"ne_type"`
KpiId string `json:"kpiId" xorm:"kpi_id"`
Value int `json:"value"`
Error string `json:"error"`
Timestamp string `json:"timestamp"`
}
var (
// performance management
PostPerformanceUri = config.UriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/kpiReport/{index}"
// performance management
PostPerformancePattern = config.UriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/kpiReport/{index}"
MeasureTaskUri = config.UriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/measureTask"
MeasureReportUri = config.UriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/measureReport"
MeasureReportFmt = config.UriPrefix + "/performanceManagement/v1/elementType/%s/objectType/measureReport"
MeasurementUri = config.UriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/measurement/{index}"
UriMeasureTask = config.UriPrefix + "/performanceManagement/{apiVersion}/measureTask/{netype}"
)
var xEngine *xorm.Engine
type DatabaseClient struct {
dbType string
dbUrl string
dbConnMaxLifetime time.Duration
dbMaxIdleConns int
dbMaxOpenConns int
IsShowSQL bool
XEngine *xorm.Engine
}
var DbClient DatabaseClient
func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) error {
DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
dbUser, dbPassword, dbHost, dbPort, dbName)
DbClient.dbType = dbType
DbClient.dbConnMaxLifetime = 0
DbClient.dbMaxIdleConns = 0
DbClient.dbMaxOpenConns = 0
if log.GetLevel() == log.LOG_TRACE {
DbClient.IsShowSQL = true
}
log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s??charset=utf8&parseTime=true&loc=Local",
dbType, dbUser, dbHost, dbPort, dbName)
var err error
DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl)
if err != nil {
log.Error("Failed to connet database:", err)
return err
}
DbClient.XEngine.SetConnMaxLifetime(DbClient.dbConnMaxLifetime)
DbClient.XEngine.SetMaxIdleConns(DbClient.dbMaxIdleConns)
DbClient.XEngine.SetMaxOpenConns(DbClient.dbMaxOpenConns)
if DbClient.IsShowSQL {
DbClient.XEngine.ShowSQL(true)
}
xEngine = DbClient.XEngine
return nil
}
func XormConnectDatabase(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) (*xorm.Engine, error) {
sqlStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
dbUser, dbPassword, dbHost, dbPort, dbName)
log.Debugf("dbType:%s Connect to:%s:******@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
dbType, dbUser, dbHost, dbPort, dbName)
var err error
xEngine, err = xorm.NewEngine(dbType, sqlStr) //1、Create xorm engine
if err != nil {
log.Error("Failed to connect database:", err)
return nil, err
}
if log.GetLevel() == log.LOG_TRACE {
xEngine.ShowSQL(true)
}
return xEngine, nil
}
func GetDateFromTimeString(fmtString string, timeString string) string {
t, _ := time.ParseInLocation(fmtString, timeString, time.Local)
return t.Format("2006-01-02")
}
func GetDateTimeFromTimeString(fmtString string, timeString string) string {
t, _ := time.ParseInLocation(fmtString, timeString, time.Local)
return t.Format(global.DateTime)
}
// process alarm post message from NFs
func PostKPIReportFromNF(w http.ResponseWriter, r *http.Request) {
log.Debug("PostKPIReportFromNF processing... ")
vars := mux.Vars(r)
apiVer := vars["apiVersion"]
if apiVer != global.ApiVersionV1 {
log.Error("Uri api version is invalid. apiVersion:", apiVer)
services.ResponseNotFound404UriNotExist(w, r)
return
}
// body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
if err != nil {
log.Error("Faile to io.ReadAll: ", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
log.Debug("Request body:", string(body))
kpiReport := new(KpiReport)
_ = json.Unmarshal(body, &kpiReport)
log.Debug("kpiReport:", kpiReport)
session := xEngine.NewSession()
defer session.Close()
goldKpi := new(GoldKpi)
layout := time.RFC3339Nano
goldKpi.Date = GetDateFromTimeString(layout, kpiReport.Task.Period.StartTime)
goldKpi.Index, _ = strconv.Atoi(vars["index"])
goldKpi.StartTime = global.GetFmtTimeString(layout, kpiReport.Task.Period.StartTime, time.DateTime)
goldKpi.EndTime = global.GetFmtTimeString(layout, kpiReport.Task.Period.EndTime, time.DateTime)
goldKpi.NEName = kpiReport.Task.NE.NEName
goldKpi.RmUid = kpiReport.Task.NE.RmUID
goldKpi.NEType = kpiReport.Task.NE.NeType
goldKpi.Timestamp = global.GetFmtTimeString(layout, kpiReport.Timestamp, time.DateTime)
for _, k := range kpiReport.Task.NE.KPIs {
goldKpi.KpiId = k.KPIID
goldKpi.Value = k.Value
goldKpi.Error = k.Err
log.Trace("goldKpi:", goldKpi)
// 启动事务
err := session.Begin()
if err != nil {
log.Error("Failed to Begin gold_kpi:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
gkpi := &GoldKpi{}
_, err = session.Where("id = ?", 1).ForUpdate().Get(gkpi)
if err != nil {
// 回滚事务
session.Rollback()
log.Error("Failed to ForUpdate gold_kpi:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
affected, err := session.Insert(goldKpi)
if err != nil && affected <= 0 {
session.Rollback()
log.Error("Failed to insert gold_kpi:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
// 提交事务
err = session.Commit()
if err != nil {
log.Error("Failed to Commit gold_kpi:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
}
services.ResponseStatusOK200Null(w)
}
type MeasureTask struct {
Tasks []Task `json:"Tasks"`
NotifyUrl string `json:"NotifyUrl"` /* "http://xEngine.xEngine.xEngine.x:xxxx/api/rest/performanceManagement/v1/elementType/smf/objectType/measureReport */
}
type Task struct {
Id int `json:"Id"`
StartTime string `json:"StartTime"`
EndTime string `json:"EndTime"`
Schedule struct {
Type string `json:"Type"` // 计划类型Weekly/Monthly, 如果type为"", 则任务以StartTime和EndTime为条件进行统计, 否则以Shedule方式进行
Days []int `json:"Days"` // Weekly: [0,1,...,5,6] 星期日为0, Monthly: [1,2,3,...,30,31]
Periods []dborm.Period `json:"Periods"`
/*
Periods []struct {
Start string `json:"Start"` // 零点或者零点加测量粒度的整数倍
End string `json:"End"` //零点加测量粒度的整数倍
} `json:"Periods"`
*/
} `json:"Schedule"`
GranulOption string `json:"GranulOption"` // 测量粒度选项15M/30M/60M/24H
KPISet []dborm.KpiSetJ `json:"KPISet"`
/*
KPISet []struct {
Code string `json:"Code"` // 统计编码 如SMFHA01
KPIs []string `json:"KPIs` // 指标项集合 ["SMF.AttCreatePduSession", "SMF.AttCreatePduSession._Dnn"]
} `json:"KPISet"`
*/
}
type MeasureReport struct {
Id int `json:"Id"`
TimeStamp string `json:"TimeStamp"`
NeName string `json:"NeName"`
RmUID string `json:"rmUID"`
NeType string `json:"NeType"`
Report struct {
Period struct {
StartTime string `json:"StartTime"`
EndTime string `json:"EndTime"`
} `json:"Period"`
Datas []struct {
Code string `json:"Code"` // 统计编码 如SMFHA01
KPIs []struct {
KPIID string `json:"KPIID"` // 指标项, 如: SMF.AttCreatePduSession._Dnn
KPIValues []struct {
Name string `json:"Name"` // 单个的写"Total", 或者指标项有多个测量项如Dnn的名称写对应的Dnn"cmnet"/"ims"
Value int64 `json:"Value"`
} `json:"KPIValues"`
} `json:"KPIs"`
} `json:"Datas"`
} `json:"Report"`
}
type MeasureData struct {
// Id int `json:"id" xorm:"pk 'id' autoincr"`
Id int `json:"id" xorm:"-"`
Date string `json:"date" xorm:"date"`
TaskId int `json:"taskId"`
NeType string `json:"neType" xorm:"ne_type"`
NeName string `json:"neName" xorm:"ne_name"`
RmUid string `json:"rmUid" xorm:"rm_uid"`
GranulOption string `json:"granulOption" xorm:"granul_option"`
StartTime string `json:"startTime"`
EndTime string `json:"endTime"`
KpiCode string `json:"kpiCode" xorm:"kpi_code"`
KpiId string `json:"kpiId" xorm:"kpi_id"`
KpiExt string `json:"kpiExt" xorm:"kpi_ext"`
Value int64 `json:"value"`
Timestamp string `json:"timestamp"`
}
// process measure report from NFs
func PostMeasureReportFromNF(w http.ResponseWriter, r *http.Request) {
log.Debug("PostMeasureReportFromNF processing... ")
// vars := mux.Vars(r)
// neType := vars["elementTypeValue"]
vars := mux.Vars(r)
apiVer := vars["apiVersion"]
if apiVer != global.ApiVersionV1 {
log.Error("Uri api version is invalid. apiVersion:", apiVer)
services.ResponseNotFound404UriNotExist(w, r)
return
}
// body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
if err != nil {
log.Error("Faile to io.ReadAll: ", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
log.Debug("Request body:", string(body))
measureReport := new(MeasureReport)
_ = json.Unmarshal(body, &measureReport)
log.Debug("measureReport:", measureReport)
session := xEngine.NewSession()
defer session.Close()
measureData := new(MeasureData)
layout := global.DateTime
measureData.Date = GetDateFromTimeString(layout, measureReport.Report.Period.StartTime)
measureData.TaskId = measureReport.Id
measureData.StartTime = measureReport.Report.Period.StartTime
measureData.EndTime = measureReport.Report.Period.EndTime
measureData.NeType = measureReport.NeType
measureData.NeName = measureReport.NeName
measureData.RmUid = measureReport.RmUID
measureData.GranulOption, _ = dborm.XormGetSingleCol("measure_task", "granul_option", fmt.Sprintf("id=%d", measureReport.Id))
t, _ := strconv.ParseInt(measureReport.TimeStamp, 10, 64)
timestamp := time.Unix(t, 0)
log.Debug("timestamp:", timestamp.Format(layout))
measureData.Timestamp = timestamp.Format(layout)
log.Debug("Datas:", measureReport.Report.Datas)
for _, d := range measureReport.Report.Datas {
measureData.KpiCode = d.Code
log.Debug("KPIs:", d.KPIs)
for _, k := range d.KPIs {
measureData.KpiId = k.KPIID
log.Debug("KPIValues:", k.KPIValues)
if len(k.KPIValues) != 0 {
for _, v := range k.KPIValues {
measureData.KpiExt = v.Name
measureData.Value = v.Value
log.Debug("measureData:", measureData)
affected, err := session.Insert(measureData)
if err != nil && affected <= 0 {
log.Error("Failed to insert measure_data:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
}
} else {
measureData.Value = 0
log.Debug("measureData:", measureData)
affected, err := session.Insert(measureData)
if err != nil && affected <= 0 {
log.Error("Failed to insert measure_data:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
}
}
}
services.ResponseStatusOK204NoContent(w)
}
func PostMeasureTaskToNF(w http.ResponseWriter, r *http.Request) {
log.Debug("PostMeasureTaskToNF processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["elementTypeValue"]
params := r.URL.Query()
taskIds := params["id"]
log.Debug("taskIds:", taskIds)
var response *resty.Response
client := resty.New()
measureTask := new(MeasureTask)
measureTask.Tasks = make([]Task, 1)
for _, taskId := range taskIds {
id, _ := strconv.Atoi(taskId)
task, err := dborm.GetMeasureTask(id)
if err != nil {
log.Error("Failed to connect database: ", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
log.Debug("Table Task:", task)
measureTask.Tasks[0].Id = task.Id
measureTask.Tasks[0].StartTime = task.StartTime
measureTask.Tasks[0].EndTime = task.EndTime
// v := new(dborm.ScheduleJson)
// _ = json.Unmarshal(task.Schedule, v)
// measureTask.Task[0].Schedule.Type = v.Type
// measureTask.Task[0].Schedule.Days = v.Days
if len(task.Schedule) >= 1 {
measureTask.Tasks[0].Schedule.Type = task.Schedule[0].Type
measureTask.Tasks[0].Schedule.Days = task.Schedule[0].Days
}
//v := new(dborm.ScheduleJ)
//_ = json.Unmarshal(task.Schedule, v)
measureTask.Tasks[0].Schedule.Periods = task.Periods
measureTask.Tasks[0].GranulOption = task.GranulOption
measureTask.Tasks[0].KPISet = task.KpiSet
ips, err := global.GetIps()
if err != nil {
log.Error("Failed to get local IP:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
log.Debug("ips:", ips)
measureTask.NotifyUrl = global.SetNotifyUrl(ips[0], config.GetYamlConfig().Rest[0].Port, fmt.Sprintf(MeasureReportFmt, neType))
log.Debug("Measure Task to NF:", measureTask)
if len(task.NeIds) == 0 {
var neInfos []dborm.NeInfo
err := dborm.XormGetNeInfoByNeType(neType, &neInfos)
if err != nil {
log.Error("Failed to dborm.XormGetNeInfoByNeType:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
for _, neInfo := range neInfos {
task.NeIds = append(task.NeIds, neInfo.NeId)
}
}
for _, neId := range task.NeIds {
var err error
neInfo, err := dborm.XormGetNeInfo(neType, neId)
if err != nil {
log.Error("Failed to dborm.XormGetNeInfo:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
if neInfo == nil {
err := errors.New(fmt.Sprintf("not found target NE neType=%s, neId=%s", neType, neId))
log.Error(err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI)
log.Debug("requestURI2NF: POST ", requestURI2NF)
switch task.Status {
case dborm.MeasureTaskStatusInactive:
body, _ := json.Marshal(measureTask)
log.Debug("body: ", string(body))
log.Debug("User-Agent: ", config.GetDefaultUserAgent())
response, err = client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
SetBody(body).
SetContentLength(true).
Post(requestURI2NF)
if err != nil {
log.Error("Post to NF failed:", err)
services.ResponseInternalServerError500NFConnectRefused(w)
return
}
log.Debug("response info: ")
log.Debug("Status Code:", response.StatusCode())
log.Debug("Status:", response.Status())
log.Debug("Proto:", response.Proto())
log.Debug("Time:", response.Time())
log.Debug("Received At:", response.ReceivedAt())
log.Debug("Size:", response.Size())
case dborm.MeasureTaskStatusSuspend:
body, _ := json.Marshal(measureTask)
log.Debug("body: ", string(body))
response, err = client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
SetBody(body).
SetContentLength(true).
Put(requestURI2NF)
if err != nil {
log.Error("Put to NF failed:", err)
services.ResponseInternalServerError500NFConnectRefused(w)
return
}
default:
err = errors.New(fmt.Sprintf("measure task status must be inactive id=%d", id))
log.Error("Unable to active measure task:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
log.Debug("StatusCode: ", response.StatusCode())
switch response.StatusCode() {
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
taskInfo := new(dborm.MeasureTask)
taskInfo.Status = dborm.MeasureTaskStatusActive
taskInfo.CreateTime = time.Now().Format(time.DateTime)
affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo)
if err != nil {
log.Error("dborm.XormUpdateTableById is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
} else if affected <= 0 {
log.Info("Not record affected in measure_task")
}
default:
log.Error("NF return failure to active measure task")
if response != nil {
log.Info("response body:", string(response.Body()))
services.TransportResponse(w, response.StatusCode(), response.Body())
return
} else {
err = errors.New(fmt.Sprintf("failed to active measure task, NF return error status=%v", response.Status()))
log.Error("Unable to active measure task:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
}
}
}
services.ResponseStatusOK204NoContent(w)
}
func PutMeasureTaskToNF(w http.ResponseWriter, r *http.Request) {
services.ResponseStatusOK200Null(w)
}
func DeleteMeasureTaskToNF(w http.ResponseWriter, r *http.Request) {
log.Debug("DeleteMeasureTaskToNF processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["elementTypeValue"]
params := r.URL.Query()
taskIds := params["id"]
log.Debug("taskIds:", taskIds)
var response *resty.Response
respMsg := make(map[string]interface{})
for _, taskId := range taskIds {
id, _ := strconv.Atoi(taskId)
task, err := dborm.GetMeasureTask(id)
if err != nil {
log.Error("Failed to connect database: ", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
log.Debug("Measure Task:", task)
if len(task.NeIds) == 0 {
var neInfos []dborm.NeInfo
err := dborm.XormGetNeInfoByNeType(neType, &neInfos)
if err != nil {
log.Error("Failed to dborm.XormGetNeInfoByNeType:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
for _, neInfo := range neInfos {
task.NeIds = append(task.NeIds, neInfo.NeId)
}
}
log.Debug("neIds:", task.NeIds)
if len(task.NeIds) == 0 {
log.Warn("Not found target NE in the measure task")
taskInfo := new(dborm.MeasureTask)
taskInfo.Status = dborm.MeasureTaskStatusDeleted
affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo)
if err != nil {
log.Error("dborm.XormUpdateTableById is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
} else if affected <= 0 {
log.Info("Not record affected in measure_task")
}
services.ResponseStatusOK204NoContent(w)
return
}
for _, neId := range task.NeIds {
var err error
neInfo, err := dborm.XormGetNeInfo(neType, neId)
if err != nil {
log.Error("dborm.XormGetNeInfo is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
if neInfo != nil {
requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI)
log.Debug("requestURI2NF: DELETE ", requestURI2NF)
client := resty.New()
response, err = client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Delete(requestURI2NF)
if err != nil {
// to avoid can't delete the task for abnormal NF
log.Error("Failed to resty delete:", err)
taskInfo := new(dborm.MeasureTask)
taskInfo.Status = dborm.MeasureTaskStatusDeleted
affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo)
if err != nil {
log.Error("dborm.XormUpdateTableById is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
} else if affected <= 0 {
log.Info("Not record affected in measure_task")
}
services.ResponseStatusOK204NoContent(w)
return
}
log.Info("StatusCode: ", response.StatusCode())
switch response.StatusCode() {
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
taskInfo := new(dborm.MeasureTask)
taskInfo.Status = dborm.MeasureTaskStatusDeleted
affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo)
if err != nil {
log.Error("dborm.XormUpdateTableById is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
} else if affected <= 0 {
log.Infof("Not record affected in measure_task")
}
services.ResponseStatusOK204NoContent(w)
return
default:
log.Info("response body:", string(response.Body()))
body := new(map[string]interface{})
_ = json.Unmarshal(response.Body(), &body)
respMsg["error"] = body
}
} else {
taskInfo := new(dborm.MeasureTask)
taskInfo.Status = dborm.MeasureTaskStatusDeleted
affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo)
if err != nil {
log.Error("dborm.XormUpdateTableById is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
} else if affected <= 0 {
log.Info("Not record affected in measure_task")
}
services.ResponseStatusOK204NoContent(w)
return
}
}
}
services.ResponseWithJson(w, response.StatusCode(), respMsg)
}
func PatchMeasureTaskToNF(w http.ResponseWriter, r *http.Request) {
log.Debug("PatchMeasureTaskToNF processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
neType := vars["elementTypeValue"]
params := r.URL.Query()
taskIds := params["id"]
log.Debug("taskIds:", taskIds)
var response *resty.Response
respMsg := make(map[string]interface{})
for _, taskId := range taskIds {
id, _ := strconv.Atoi(taskId)
task, err := dborm.GetMeasureTask(id)
if err != nil {
log.Error("Failed to connect database: ", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
log.Debug("Measure Task:", task)
// for neType
if len(task.NeIds) == 0 {
var neInfos []dborm.NeInfo
err := dborm.XormGetNeInfoByNeType(neType, &neInfos)
if err != nil {
log.Error("Failed to dborm.XormGetNeInfoByNeType:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
for _, neInfo := range neInfos {
task.NeIds = append(task.NeIds, neInfo.NeId)
}
}
if len(task.NeIds) == 0 {
taskInfo := new(dborm.MeasureTask)
taskInfo.Status = dborm.MeasureTaskStatusInactive
affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo)
if err != nil {
log.Error("dborm.XormUpdateTableById is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
} else if affected <= 0 {
log.Info("Not record affected in measure_task")
}
services.ResponseStatusOK204NoContent(w)
return
}
for _, neId := range task.NeIds {
var err error
neInfo, err := dborm.XormGetNeInfo(neType, neId)
if err != nil {
log.Error("dborm.XormGetNeInfo is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
if neInfo == nil {
em := errors.New("Not found NE info in database")
log.Error(em)
taskInfo := new(dborm.MeasureTask)
taskInfo.Status = dborm.MeasureTaskStatusInactive
affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo)
if err != nil {
log.Error("dborm.XormUpdateTableById is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
} else if affected <= 0 {
log.Info("Not record affected in measure_task")
}
services.ResponseStatusOK204NoContent(w)
//services.ResponseInternalServerError500ProcessError(w, em)
return
}
requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI)
log.Debug("requestURI2NF: PATCH ", requestURI2NF)
client := resty.New()
response, err = client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Patch(requestURI2NF)
if err != nil {
log.Error("Patch to NF failed:", err)
services.ResponseInternalServerError500NFConnectRefused(w)
return
}
log.Debug("StatusCode: ", response.StatusCode())
switch response.StatusCode() {
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
taskInfo := new(dborm.MeasureTask)
taskInfo.Status = dborm.MeasureTaskStatusInactive
affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo)
if err != nil {
log.Error("dborm.XormUpdateTableById is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
} else if affected <= 0 {
log.Info("Not record affected in measure_task")
}
default:
log.Debug("response body:", string(response.Body()))
body := new(map[string]interface{})
_ = json.Unmarshal(response.Body(), &body)
respMsg["error"] = body
}
}
}
services.ResponseWithJson(w, response.StatusCode(), respMsg)
return
}
type Measurement struct {
Id int `json:"-" xorm:"pk 'id' autoincr"`
Date string `json:"-" xorm:"date"`
Index int `json:"Index"` // 1天中测量时间粒度(如15分钟)的切片索引: 0~95
Timestamp string `json:"TimeStamp" xorm:"-"`
NeName string `json:"NeName"` // UserLabel
RmUID string `json:"RmUID" xorm:"rm_uid"`
NeType string `json:"NeType"` // 网元类型
PmVersion string `json:"PmVersion"` // 性能数据版本号
Dn string `json:"Dn"` // (???)网元标识, 如:RJN-CMZJ-TZ,SubNetwork=5GC88,ManagedElement=SMF53456,SmfFunction=53456
Period string `json:"Period"` // 测量时间粒度选项5/15/30/60
TimeZone string `json:"TimeZone"`
StartTime string `json:"StartTime"`
Datas []Data `json:"Datas"`
}
type KPIValue struct {
Name string `json:"Name"` // 单个的写"Total", 或者指标项有多个测量项如Dnn的名称写对应的Dnn"cmnet"/"ims"
Value int64 `json:"Value"`
}
type KPI struct {
KPIID string `json:"KPIID"` // 指标项, 如: SMF.AttCreatePduSession._Dnn
KPIValues []KPIValue `json:"KPIValues"`
}
type Data struct {
ObjectType string `json:"ObjectType"` // 网络资源类别名称, Pm指标项列表中为空间粒度 如SmfFunction
KPIs []KPI `json:"KPIs"` // 指标项, 如: SMF.AttCreatePduSession._Dnn
}
// process measurement post message from NFs
func PostMeasurementFromNF(w http.ResponseWriter, r *http.Request) {
log.Debug("PostMeasurementFromNF processing... ")
vars := mux.Vars(r)
apiVer := vars["apiVersion"]
if apiVer != global.ApiVersionV1 {
log.Error("Uri api version is invalid. apiVersion:", apiVer)
services.ResponseNotFound404UriNotExist(w, r)
return
}
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
if err != nil {
log.Error("Faile to io.ReadAll: ", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
log.Debug("Request body:", string(body))
// measurement := new(dborm.NorthboundPm)
measurement := new(dborm.NorthboundPm)
_ = json.Unmarshal(body, &measurement)
log.Debug("measurement:", measurement)
session := dborm.DbClient.XEngine.NewSession()
defer session.Close()
// layout := global.DateTime
layout := time.RFC3339
measurement.Date = GetDateFromTimeString(layout, measurement.StartTime)
measurement.StartTime = GetDateTimeFromTimeString(layout, measurement.StartTime)
affected, err := session.Table("northbound_pm").Insert(measurement)
if err != nil && affected <= 0 {
log.Error("Failed to insert northbound_pm:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
services.ResponseStatusOK204NoContent(w)
}
// get measurement message from NFs
func GetMeasurementFromNF(w http.ResponseWriter, r *http.Request) {
log.Debug("GetMeasurementFromNF processing... ")
_, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
vars := mux.Vars(r)
apiVer := vars["apiVersion"]
if apiVer != global.ApiVersionV1 {
log.Error("Uri api version is invalid. apiVersion:", apiVer)
services.ResponseNotFound404UriNotExist(w, r)
return
}
neType := vars["elementTypeValue"]
if neType == "" {
log.Error("elementTypeValue is null.")
services.ResponseNotFound404UriNotExist(w, r)
return
}
params := r.URL.Query()
neIds := params["ne_id"]
if len(neIds) == 0 {
log.Error("ne_id NOT FOUND")
services.ResponseBadRequest400WrongParamValue(w)
return
}
log.Debugf("neType: %s neId:%s", neType, neIds)
//var neInfo *dborm.NeInfo
neInfo := new(dborm.NeInfo)
neInfo, err = dborm.XormGetNeInfo(neType, neIds[0])
if err != nil {
log.Error("dborm.XormGetNeInfo is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI)
log.Debug("requestURI2NF: GET ", requestURI2NF)
client := resty.New()
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Get(requestURI2NF)
if err != nil {
log.Error("Failed to Get from NF:", err)
services.ResponseInternalServerError500NFConnectRefused(w)
return
}
respMsg := make(map[string]interface{})
switch response.StatusCode() {
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
log.Debug("response:", response)
// measurement := new(dborm.NorthboundPm)
measurement := new(dborm.NorthboundPm)
_ = json.Unmarshal(response.Body(), &measurement)
log.Debug("measurement:", measurement)
session := dborm.DbClient.XEngine.NewSession()
defer session.Close()
layout := time.RFC3339
measurement.Date = GetDateFromTimeString(layout, measurement.StartTime)
measurement.StartTime = GetDateTimeFromTimeString(layout, measurement.StartTime)
affected, err := session.Table("northbound_pm").Insert(measurement)
if err != nil && affected <= 0 {
log.Error("Failed to insert northbound_pm:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
default:
log.Debug("response body:", string(response.Body()))
body := new(map[string]interface{})
_ = json.Unmarshal(response.Body(), &body)
respMsg["error"] = body
}
services.ResponseWithJson(w, response.StatusCode(), respMsg)
}

View File

@@ -0,0 +1,175 @@
package security
import (
"encoding/json"
"io"
"net/http"
"ems.agt/lib/dborm"
"ems.agt/lib/global"
"ems.agt/lib/log"
"ems.agt/lib/oauth"
"ems.agt/lib/services"
"ems.agt/restagent/config"
)
var (
UriOauthToken = config.UriPrefix + "/securityManagement/{apiVersion}/oauth/token"
UriOauthHandshake = config.UriPrefix + "/securityManagement/{apiVersion}/oauth/handshake"
)
func LoginFromOMC(w http.ResponseWriter, r *http.Request) {
log.Info("LoginFromOMC processing... ")
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小
if err != nil {
log.Error("Failed to ReadAll:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
// check media type(content type) only support "application/json"
if !services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) {
log.Debug("Invalid Content-Type")
services.ResponseUnsupportedMediaType415(w)
return
}
// // check extend uri, response 404
// if !IsValidOAuthUri(r) {
// log.Debug("Uri is invalid")
// services.ResponseNotFound404UriNotExist(w, r)
// return
// }
// Error process ....
// response 400-7
if !json.Valid([]byte(body)) {
log.Error("Invalid Json Format")
services.ResponseBadRequest400InvalidJson(w)
return
}
var oAuthBody oauth.OAuthBody
_ = json.Unmarshal(body, &oAuthBody) //转为json
//log.Debug("body:", string(body), "oAuthBody:", oAuthBody)
defer r.Body.Close()
// response 400-5
if oauth.IsWrongOAuthInfo(oAuthBody) {
log.Error("Wrong parameter value")
services.ResponseBadRequest400WrongParamValue(w)
return
}
/*
if oauth.IsValidOAuthInfo(oAuthBody) {
plist := config.GetPermissionFromConfig(oAuthBody.UserName, oAuthBody.GrantType)
log.Debug("Permission list:", plist)
token := globalSession.NewSession(w, r, plist)
services.ResponseStatusOK200Login(w, token)
} else {
// response 400-4
log.Debug("Authentication failed, mismatch user or password")
services.ResponseBadRequest400IncorrectLogin(w)
}
*/
validUser, user, _ := dborm.XormCheckLoginUser(oAuthBody.UserName,
oAuthBody.Value, config.GetYamlConfig().Auth.Crypt)
if !validUser {
// response 400-4
log.Error("Authentication failed, mismatch user or password")
services.ResponseBadRequest400IncorrectLogin(w)
return
}
token := oauth.GenRandToken() // Generate new token to session ID
sourceAddr := r.RemoteAddr
affected, err := dborm.XormInsertSession(oAuthBody.UserName, sourceAddr, token,
config.GetExpiresFromConfig(), config.GetYamlConfig().Auth.Session)
if err != nil {
log.Error("Failed to XormInsertSession:", err)
if affected == -1 {
services.ResponseForbidden403MultiLoginNotAllowed(w)
} else {
services.ResponseBadRequest400IncorrectLogin(w)
}
return
}
services.ResponseStatusOK200Login(w, token, user)
return
}
func LogoutFromOMC(w http.ResponseWriter, r *http.Request) {
log.Info("LogoutFromOMC processing... ")
// check media type(content type) only support "application/json"
if services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) == false {
log.Error("Invalid Content-Type")
services.ResponseUnsupportedMediaType415(w)
return
}
// check extend uri, response 404
if !services.IsValidOAuthUri(r) {
log.Error("Uri is invalid")
services.ResponseNotFound404UriNotExist(w, r)
return
}
// error processing ...
// 401-1 response
token, ret := oauth.IsCarriedToken(r)
if ret == false {
log.Error("AccessToken is not carried")
services.ResponseUnauthorized401AccessTokenNotCarried(w)
return
}
_, err := dborm.XormLogoutUpdateSession(token)
if err != nil {
log.Error("Uri is invalid")
services.ResponseNotFound404UriNotExist(w, r)
return
}
services.ResponseStatusOK200Null(w)
return
}
func HandshakeFromOMC(w http.ResponseWriter, r *http.Request) {
log.Info("HandshakeFromOMC processing... ")
// check media type(content type) only support "application/json"
if !services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) {
log.Debug("Invalid Content-Type")
services.ResponseUnsupportedMediaType415(w)
return
}
// check extend uri, response 404
if !services.IsValidOAuthUri(r) {
log.Error("Uri is invalid")
services.ResponseNotFound404UriNotExist(w, r)
return
}
// error processing ...
// 401-1 response
token, ret := oauth.IsCarriedToken(r)
if ret == false {
log.Error("AccessToken is not carried")
services.ResponseUnauthorized401AccessTokenNotCarried(w)
return
}
_, err := dborm.XormUpdateSessionShakeTime(token)
if err != nil {
log.Error("Uri is invalid")
services.ResponseNotFound404UriNotExist(w, r)
return
}
services.ResponseStatusOK200Null(w)
return
}

109
features/sm/backup.go Normal file
View File

@@ -0,0 +1,109 @@
package sm
import (
"database/sql"
"fmt"
"os"
"os/exec"
"time"
"ems.agt/lib/log"
"ems.agt/restagent/config"
_ "github.com/go-sql-driver/mysql"
)
var dbConfig = config.GetYamlConfig().Database
func DatabaseWhoreBackup() {
// MySQL数据库连接信息
sqlStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
dbConfig.User, dbConfig.Password, dbConfig.Host, dbConfig.Port, dbConfig.Name)
db, err := sql.Open("mysql", sqlStr)
if err != nil {
log.Error("Failed to connect to database:", err)
return
}
defer db.Close()
// 备份SQL文件路径
backupFile := dbConfig.Backup + "/" + "whore_backup_" + dbConfig.Name + ".sql"
// 执行mysqldump命令进行备份
cmd := exec.Command("mysqldump", "-u", dbConfig.User, "-p"+dbConfig.Password, "-h", dbConfig.Host, dbConfig.Name)
output, err := cmd.Output()
if err != nil {
log.Error("Failed to execute mysqldump command:", err)
return
}
// 将备份结果写入SQL文件
file, err := os.Create(backupFile)
if err != nil {
log.Error("Failed to create backup file:", err)
return
}
defer file.Close()
_, err = file.Write(output)
if err != nil {
log.Error("Failed to write backup file:", err)
return
}
log.Info("Backup completed successfully.")
}
func DatabaseIncrementalBackup() {
// MySQL数据库连接信息
sqlStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
dbConfig.User, dbConfig.Password, dbConfig.Host, dbConfig.Port, dbConfig.Name)
db, err := sql.Open("mysql", sqlStr)
if err != nil {
log.Error("Failed to connect to database:", err)
return
}
defer db.Close()
// 备份SQL文件路径
backupFile := dbConfig.Backup + "/" + "incremental_backup_" + dbConfig.Name + ".sql"
// 上次备份的时间点
lastBackupTime := time.Date(2022, time.January, 1, 0, 0, 0, 0, time.Local)
// 构建增量备份SQL语句
query := fmt.Sprintf("SELECT * FROM table WHERE modified_at > '%s'", lastBackupTime.Format("2006-01-02 15:04:05"))
// 执行查询
rows, err := db.Query(query)
if err != nil {
log.Error("Failed to execute query:", err)
return
}
defer rows.Close()
// 创建增量备份SQL文件
file, err := os.Create(backupFile)
if err != nil {
log.Error("Failed to create backup file:", err)
return
}
defer file.Close()
// 将查询结果写入SQL文件
for rows.Next() {
var data string
err := rows.Scan(&data)
if err != nil {
log.Error("Failed to scan row:", err)
return
}
_, err = file.WriteString(data + "\n")
if err != nil {
log.Error("Failed to write backup file:", err)
return
}
}
log.Info("Incremental backup completed successfully.")
}

845
features/state/getstate.go Normal file
View File

@@ -0,0 +1,845 @@
package state
import (
"encoding/json"
"fmt"
"net/http"
"os"
"strconv"
"strings"
"time"
"github.com/go-resty/resty/v2"
"github.com/gorilla/mux"
"ems.agt/lib/dborm"
"ems.agt/lib/global"
"ems.agt/lib/log"
"ems.agt/lib/services"
"ems.agt/restagent/config"
)
type CpuUsage struct {
NfCpuUsage uint16 `json:"nfCpuUsage"`
SysCpuUsage uint16 `json:"sysCpuUsage"`
}
type MemUsage struct {
TotalMem uint32 `json:"totalMem"`
NfUsedMem uint32 `json:"nfUsedMem"`
SysMemUsage uint16 `json:"sysMemUsage"`
}
type PartitionInfo struct {
Total uint32 `json:"total"` // MB
Used uint32 `json:"used"` // MB
}
type DiskSpace struct {
PartitionNum uint8 `json:"partitionNum"`
PartitionInfo []PartitionInfo `json:"partitionInfo"`
}
type HardwareInfo struct {
CPUs int `json:"cpus"`
Memory int `json:"memory"`
}
type SysState struct {
HostName string `json:"hostName"` // linux命令: hostname
OsInfo string `json:"osInfo"` // linux命令: uname -a
DbInfo string `json:"dbInfo"` // 网元如果有db, 显示数据库名和版本信息, OMC: mysql --version
Version string `json:"version"` // 软件版本信息: 16.1.1
IpAddr []string `json:"ipAddr"` // 网管的ipv4和ipv6列表
Port uint16 `json:"port"` // 用于网管的port
Capability uint32 `json:"capability"`
SerialNum string `json:"serialNum"`
ExpiryDate string `json:"expiryDate"`
HardwareInfo HardwareInfo `json:"hardwareInfo"`
CpuUsage CpuUsage `json:"cpuUsage"`
MemUsage MemUsage `json:"memUsage"`
DiskSpace DiskSpace `json:"diskSpace"`
//Timestamp string `json:"timestamp"`
}
type SystemState struct {
HostName string `json:"hostName"` // linux命令: hostname
OsInfo string `json:"osInfo"` // linux命令: uname -a
DbInfo string `json:"dbInfo"` // 网元如果有db, 显示数据库名和版本信息, OMC: mysql --version
Version string `json:"version"` // 软件版本信息: 16.1.1
IpAddr []string `json:"ipAddr"` // 网管的ipv4和ipv6列表
Port uint16 `json:"port"` // 用于网管的port
Capability uint32 `json:"capability"`
SerialNum string `json:"serialNum"`
ExpiryDate string `json:"expiryDate"`
HardwareInfo struct {
CPUs int `json:"cpus"` // 主机(裸机/虚拟机)的cpu个数
Memory int `json:"memory"` // 主机(裸机/虚拟机): 配置的内存
} `json:"hardwareInfo"`
CpuUsage struct {
NfCpuUsage uint16 `json:"nfCpuUsage"`
SysCpuUsage uint16 `json:"sysCpuUsage"`
} `json:"cpuUsage"`
MemUsage struct {
TotalMem uint32 `json:"totalMem"`
NfUsedMem uint32 `json:"nfUsedMem"`
SysMemUsage uint16 `json:"sysMemUsage"`
} `json:"memUsage"`
DiskSpace struct {
PartitionNum uint8 `json:"partitionNum"`
PartitionInfo []struct {
Total uint32 `json:"total"` // MB
Used uint32 `json:"used"` // MB
} `json:"partitionInfo"`
} `json:"diskSpace"`
//Timestamp string `json:"timestamp"`
}
type SystemInfo struct {
NeType string `json:"neType" map:"neType, omitempty"`
NeId string `json:"neId" map:"neId, omitempty"`
HostName string `json:"hostName" map:"hostName, omitempty"` // linux命令: hostname
OsInfo string `json:"osInfo" map:"osInfo, omitempty"` // linux命令: uname -a
DbInfo string `json:"dbInfo" map:"dbInfo, omitempty"` // 网元如果有db, 显示数据库名和版本信息, OMC: mysql --version
Version string `json:"version" map:"version, omitempty"` // 软件版本信息: 16.1.1
IpAddr string `json:"ipAddr" map:"ipAddr, omitempty"` // 网管的ipv4和ipv6列表
Port uint16 `json:"port" map:"port, omitempty"` // 用于网管的port
CPUs int `json:"cpus" map:"cpus, omitempty"`
TotalMem int `json:"totalMem" map:"totalMem, omitempty"`
PvFlag string `json:"pvFlag" map:"pvFlag, omitempty"`
Status string `json:"status" map:"status, omitempty"`
}
type LicenseInfo struct {
NeType string `json:"neType"`
NeId string `json:"neId"`
SerialNum string `json:"serialNum"`
Capability uint32 `json:"capability"`
CapUsed uint32 `json:"capUsed"`
FeatureEnabled []string `json:"featureEnabled"`
ExpiryDate string `json:"expiryDate"`
}
type Response struct {
Data interface{} `json:"data"`
}
var (
UriSysState = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/systemState"
UriSysState2 = config.UriPrefix + "/systemManagement/{apiVersion}/systemState/{elementTypeValue}"
UriSysInfoAll = config.UriPrefix + "/systemManagement/{apiVersion}/sysInfo"
UriSysInfoOne = config.UriPrefix + "/systemManagement/{apiVersion}/sysInfo/{neType}/{neId}"
UriLicenseInfoAll = config.UriPrefix + "/systemManagement/{apiVersion}/licenseInfo"
UriLicenseInfoOne = config.UriPrefix + "/systemManagement/{apiVersion}/licenseInfo/{neType}/{neId}"
)
var client = resty.New()
func init() {
/*
client.
SetTimeout(10 * time.Second).
SetRetryCount(1).
SetRetryWaitTime(1 * time.Second).
SetRetryMaxWaitTime(2 * time.Second).
SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) {
return 0, errors.New("quota exceeded")
})
*/
client.SetTimeout(3 * time.Second)
}
func NeStatusEnumToStr(intStatus int) string {
switch intStatus {
case 0:
return "active"
case 1:
return "offline"
case 2:
return "standby"
case 3:
return "maintain"
default:
return "unkown"
}
}
// Get system state from NF/NFs
func GetOneLicenseInfoFromNF(w http.ResponseWriter, r *http.Request) {
log.Debug("GetOneLicenseInfoFromNF processing... ")
data := make([]map[string]interface{}, 0)
vars := mux.Vars(r)
neType := vars["neType"]
neId := vars["neId"]
if neType == "" || neId == "" {
services.ResponseNotFound404UriNotExist(w, r)
return
}
token, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
log.Debug("AccessToken:", token)
neInfo, err := dborm.XormGetNeInfo(neType, neId)
if err != nil {
log.Error("Failed to XormGetNeInfo:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
} else if neInfo == nil {
err := global.ErrCMNotFoundTargetNE
log.Error(global.ErrCMNotFoundTargetNE)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
log.Trace("neInfo:", neInfo)
//systemState := make(map[string]interface{})
systemState := &SysState{}
result := make(map[string]interface{})
//sysInfo := &SystemInfo{}
omcNeTypeLower := "omc"
if config.GetYamlConfig().OMC.NeType != "" {
omcNeTypeLower = strings.ToLower(config.GetYamlConfig().OMC.NeType)
}
if neType != omcNeTypeLower {
log.Debugf("r.RemoteAddr: %s omcNeTypeLower: %s", r.RemoteAddr, omcNeTypeLower)
var requestURI2NF string
if config.GetYamlConfig().OMC.TestMode == true && strings.ToLower(neType) != "udm" {
var udmNEs []dborm.NeInfo
err := dborm.XormGetNeInfoByNeType("UDM", &udmNEs)
if err != nil {
log.Error("Get system state from NF is failed:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
if len(udmNEs) > 0 {
udmNe := udmNEs[0]
hostUri := fmt.Sprintf("http://%s:%v", udmNe.Ip, udmNe.Port)
requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
hostUri, strings.ToLower(udmNe.NeType))
}
} else {
hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
hostUri, strings.ToLower(neInfo.NeType))
}
log.Debug("requestURI2NF:", requestURI2NF)
resp, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"accessToken": token}).
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Get(requestURI2NF)
if err != nil {
log.Error("Get system state from NF is failed:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
} else {
log.Trace("resp.Body():", string(resp.Body()))
_ = json.Unmarshal(resp.Body(), &systemState)
log.Trace("systemState:", systemState)
capUsed := config.TDatas[neInfo.NeType].CapUsed
log.Tracef("neInfo.NeType:%s capUsed: %v", capUsed)
licenseInfo := &LicenseInfo{
NeType: neInfo.NeType,
NeId: neInfo.NeId,
SerialNum: systemState.SerialNum,
Capability: systemState.Capability,
CapUsed: capUsed,
FeatureEnabled: config.TDatas[neInfo.NeType].FeatureEnabled,
ExpiryDate: systemState.ExpiryDate,
}
//neItem := strings.ToUpper(neType) + "/" + neId
result, err = global.ToMap(*licenseInfo, "json")
}
} else {
systemState := GetEMSState(neInfo.Ip)
licenseInfo := &LicenseInfo{
NeType: neInfo.NeType,
NeId: neInfo.NeId,
SerialNum: systemState.SerialNum,
Capability: systemState.Capability,
CapUsed: config.TDatas[neInfo.NeType].CapUsed,
FeatureEnabled: config.TDatas[neInfo.NeType].FeatureEnabled,
ExpiryDate: systemState.ExpiryDate,
}
result, err = global.ToMap(*licenseInfo, "json")
// neItem := strings.ToUpper(neType) + "/" + neId
// result[neItem] = sysInfo
}
data = append(data, result)
log.Trace("data:", data)
var response Response
response.Data = data
services.ResponseWithJson(w, http.StatusOK, response)
}
// Get system state from NF/NFs
func GetAllLicenseInfoFromNF(w http.ResponseWriter, r *http.Request) {
log.Debug("GetAllLicenseInfoFromNF processing... ")
data := make([]map[string]interface{}, 0)
token, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
log.Debug("AccessToken:", token)
var neList []dborm.NeInfo
_, err = dborm.XormGetAllNeInfo(&neList)
omcNeTypeLower := "omc"
if config.GetYamlConfig().OMC.NeType != "" {
omcNeTypeLower = strings.ToLower(config.GetYamlConfig().OMC.NeType)
}
for _, ne := range neList {
result := make(map[string]interface{})
log.Debugf("r.RemoteAddr: %s omcNeTypeLower: %s", r.RemoteAddr, omcNeTypeLower)
log.Debug("ne: ", ne)
//if strings.ToLower(ne.NeType) != omcNeTypeLower || !strings.Contains(r.RemoteAddr, ne.Ip) {
if strings.ToLower(ne.NeType) != omcNeTypeLower {
// hostUri := fmt.Sprintf("http://%s:%v", ne.Ip, ne.Port)
// requestURI2NF := fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
// hostUri, strings.ToLower(ne.NeType))
var requestURI2NF string
if config.GetYamlConfig().OMC.TestMode == true && strings.ToLower(ne.NeType) != "udm" {
var udmNEs []dborm.NeInfo
err := dborm.XormGetNeInfoByNeType("UDM", &udmNEs)
if err != nil {
log.Error("Get system state from NF is failed:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
if len(udmNEs) > 0 {
udmNe := udmNEs[0]
hostUri := fmt.Sprintf("http://%s:%v", udmNe.Ip, udmNe.Port)
requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
hostUri, strings.ToLower(udmNe.NeType))
}
} else {
hostUri := fmt.Sprintf("http://%s:%v", ne.Ip, ne.Port)
requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
hostUri, strings.ToLower(ne.NeType))
}
log.Debug("requestURI2NF:", requestURI2NF)
resp, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"accessToken": token}).
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Get(requestURI2NF)
if err != nil {
log.Error("Get system state from NF is failed:", err)
// errorMessage := services.ErrorMessage{
// ErrorCode: "1", ErrorInfo: "Internal server error, NF connnect refused",
// }
// //result["error"] = errorMessage
continue
} else {
systemState := &SysState{}
_ = json.Unmarshal(resp.Body(), &systemState)
licenseInfo := &LicenseInfo{
NeType: ne.NeType,
NeId: ne.NeId,
SerialNum: systemState.SerialNum,
Capability: systemState.Capability,
CapUsed: config.TDatas[ne.NeType].CapUsed,
FeatureEnabled: config.TDatas[ne.NeType].FeatureEnabled,
ExpiryDate: systemState.ExpiryDate,
}
result, err = global.ToMap(*licenseInfo, "json")
// neItem := strings.ToUpper(ne.NeType) + "/" + ne.NeId
// result[neItem] = sysInfo
}
} else {
systemState := GetEMSState(ne.Ip)
licenseInfo := &LicenseInfo{
NeType: ne.NeType,
NeId: ne.NeId,
SerialNum: systemState.SerialNum,
Capability: systemState.Capability,
CapUsed: config.TDatas[ne.NeType].CapUsed,
FeatureEnabled: config.TDatas[ne.NeType].FeatureEnabled,
ExpiryDate: systemState.ExpiryDate,
}
result, err = global.ToMap(*licenseInfo, "json")
// neItem := strings.ToUpper(ne.NeType) + "/" + ne.NeId
// result[neItem] = sysInfo
}
data = append(data, result)
log.Trace("data:", data)
}
var response Response
response.Data = data
services.ResponseWithJson(w, http.StatusOK, response)
}
// Get system state from NF/NFs
func GetOneSysinfoFromNF(w http.ResponseWriter, r *http.Request) {
log.Debug("GetOneSysinfoFromNF processing... ")
data := make([]map[string]interface{}, 0)
vars := mux.Vars(r)
neType := vars["neType"]
neId := vars["neId"]
if neType == "" || neId == "" {
services.ResponseNotFound404UriNotExist(w, r)
return
}
token, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
log.Debug("AccessToken:", token)
neInfo, err := dborm.XormGetNeInfo(neType, neId)
if err != nil {
log.Error("Failed to XormGetNeInfo:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
} else if neInfo == nil {
err := global.ErrCMNotFoundTargetNE
log.Error(global.ErrCMNotFoundTargetNE)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
log.Trace("neInfo:", neInfo)
//systemState := make(map[string]interface{})
systemState := &SysState{}
result := make(map[string]interface{})
//sysInfo := &SystemInfo{}
omcNeTypeLower := "omc"
if config.GetYamlConfig().OMC.NeType != "" {
omcNeTypeLower = strings.ToLower(config.GetYamlConfig().OMC.NeType)
}
if neType != omcNeTypeLower {
log.Debugf("r.RemoteAddr: %s omcNeTypeLower: %s", r.RemoteAddr, omcNeTypeLower)
var requestURI2NF string
if config.GetYamlConfig().OMC.TestMode == true && strings.ToLower(neType) != "udm" {
var udmNEs []dborm.NeInfo
err := dborm.XormGetNeInfoByNeType("UDM", &udmNEs)
if err != nil {
log.Error("Get system state from NF is failed:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
if len(udmNEs) > 0 {
udmNe := udmNEs[0]
hostUri := fmt.Sprintf("http://%s:%v", udmNe.Ip, udmNe.Port)
requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
hostUri, strings.ToLower(udmNe.NeType))
}
} else {
hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
hostUri, strings.ToLower(neInfo.NeType))
}
log.Debug("requestURI2NF:", requestURI2NF)
resp, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"accessToken": token}).
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Get(requestURI2NF)
if err != nil {
log.Error("Get system state from NF is failed:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
} else {
log.Trace("resp.Body():", string(resp.Body()))
_ = json.Unmarshal(resp.Body(), &systemState)
log.Trace("systemState:", systemState)
hostName := "5gc"
if systemState.HostName != "" {
hostName = systemState.HostName
}
osInfo := "Linux 5gc 4.15.0-29-generic #31-Ubuntu SMP Tue Jul 17 15:39:52 UTC 2018 x86_64 GNU/Linux"
if systemState.OsInfo != "" {
osInfo = systemState.OsInfo
}
dbInfo := "adb v1.0.1"
if systemState.OsInfo != "" {
dbInfo = systemState.DbInfo
}
port, _ := strconv.Atoi(neInfo.Port)
cpus := 4
if systemState.HardwareInfo.CPUs != 0 {
cpus = systemState.HardwareInfo.CPUs
}
totalMem := 34029125632
if systemState.HardwareInfo.Memory != 0 {
totalMem = systemState.HardwareInfo.Memory
}
sysInfo := &SystemInfo{
NeType: neInfo.NeType,
NeId: neInfo.NeId,
HostName: hostName,
OsInfo: osInfo,
DbInfo: dbInfo,
Version: systemState.Version,
IpAddr: neInfo.Ip,
Port: uint16(port),
CPUs: cpus,
TotalMem: totalMem,
PvFlag: neInfo.PvFlag,
Status: NeStatusEnumToStr(neInfo.Status),
}
//neItem := strings.ToUpper(neType) + "/" + neId
result, err = global.ToMap(*sysInfo, "json")
}
} else {
systemState := GetEMSState(neInfo.Ip)
sysInfo := &SystemInfo{
NeType: neInfo.NeType,
NeId: neInfo.NeId,
HostName: systemState.HostName,
OsInfo: systemState.OsInfo,
DbInfo: systemState.DbInfo,
Version: systemState.Version,
IpAddr: neInfo.Ip,
Port: systemState.Port,
CPUs: systemState.HardwareInfo.CPUs,
TotalMem: systemState.HardwareInfo.Memory,
PvFlag: neInfo.PvFlag,
Status: NeStatusEnumToStr(neInfo.Status),
}
result, err = global.ToMap(*sysInfo, "json")
// neItem := strings.ToUpper(neType) + "/" + neId
// result[neItem] = sysInfo
}
data = append(data, result)
log.Trace("data:", data)
var response Response
response.Data = data
services.ResponseWithJson(w, http.StatusOK, response)
}
// Get system state from NF/NFs
func GetAllSysinfoFromNF(w http.ResponseWriter, r *http.Request) {
log.Debug("GetAllSysinfoFromNF processing... ")
data := make([]map[string]interface{}, 0)
token, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
log.Debug("AccessToken:", token)
var neList []dborm.NeInfo
_, err = dborm.XormGetAllNeInfo(&neList)
omcNeTypeLower := "omc"
if config.GetYamlConfig().OMC.NeType != "" {
omcNeTypeLower = strings.ToLower(config.GetYamlConfig().OMC.NeType)
}
for _, ne := range neList {
result := make(map[string]interface{})
log.Debugf("r.RemoteAddr: %s omcNeTypeLower: %s", r.RemoteAddr, omcNeTypeLower)
log.Debug("ne: ", ne)
//if strings.ToLower(ne.NeType) != omcNeTypeLower || !strings.Contains(r.RemoteAddr, ne.Ip) {
if strings.ToLower(ne.NeType) != omcNeTypeLower {
// hostUri := fmt.Sprintf("http://%s:%v", ne.Ip, ne.Port)
// requestURI2NF := fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
// hostUri, strings.ToLower(ne.NeType))
var requestURI2NF string
if config.GetYamlConfig().OMC.TestMode == true && strings.ToLower(ne.NeType) != "udm" {
var udmNEs []dborm.NeInfo
err := dborm.XormGetNeInfoByNeType("UDM", &udmNEs)
if err != nil {
log.Error("Get system state from NF is failed:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
if len(udmNEs) > 0 {
udmNe := udmNEs[0]
hostUri := fmt.Sprintf("http://%s:%v", udmNe.Ip, udmNe.Port)
requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
hostUri, strings.ToLower(udmNe.NeType))
}
} else {
hostUri := fmt.Sprintf("http://%s:%v", ne.Ip, ne.Port)
requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
hostUri, strings.ToLower(ne.NeType))
}
log.Debug("requestURI2NF:", requestURI2NF)
resp, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"accessToken": token}).
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Get(requestURI2NF)
if err != nil {
log.Error("Get system state from NF is failed:", err)
// errorMessage := services.ErrorMessage{
// ErrorCode: "1", ErrorInfo: "Internal server error, NF connnect refused",
// }
// //result["error"] = errorMessage
continue
} else {
systemState := &SysState{}
_ = json.Unmarshal(resp.Body(), &systemState)
hostName := "5gc"
if systemState.HostName != "" {
hostName = systemState.HostName
}
osInfo := "Linux 5gc 4.15.0-29-generic #31-Ubuntu SMP Tue Jul 17 15:39:52 UTC 2018 x86_64 GNU/Linux"
if systemState.OsInfo != "" {
osInfo = systemState.OsInfo
}
dbInfo := "adb v1.0.1"
if systemState.OsInfo != "" {
dbInfo = systemState.DbInfo
}
port, _ := strconv.Atoi(ne.Port)
cpus := 4
if systemState.HardwareInfo.CPUs != 0 {
cpus = systemState.HardwareInfo.CPUs
}
totalMem := 34029125632
if systemState.HardwareInfo.Memory != 0 {
totalMem = systemState.HardwareInfo.Memory
}
sysInfo := &SystemInfo{
NeType: ne.NeType,
NeId: ne.NeId,
HostName: hostName,
OsInfo: osInfo,
DbInfo: dbInfo,
Version: systemState.Version,
IpAddr: ne.Ip,
Port: uint16(port),
CPUs: cpus,
TotalMem: totalMem,
PvFlag: ne.PvFlag,
Status: NeStatusEnumToStr(ne.Status),
}
// neItem := strings.ToUpper(ne.NeType) + "/" + ne.NeId
// result[neItem] = sysInfo
result, err = global.ToMap(*sysInfo, "json")
}
} else {
port, _ := strconv.Atoi(ne.Port)
systemState := GetEMSState(ne.Ip)
sysInfo := &SystemInfo{
NeType: ne.NeType,
NeId: ne.NeId,
HostName: systemState.HostName,
OsInfo: systemState.OsInfo,
DbInfo: systemState.DbInfo,
Version: systemState.Version,
IpAddr: ne.Ip,
Port: (uint16(port)),
CPUs: systemState.HardwareInfo.CPUs,
TotalMem: systemState.HardwareInfo.Memory,
PvFlag: ne.PvFlag,
Status: NeStatusEnumToStr(ne.Status),
}
// neItem := strings.ToUpper(ne.NeType) + "/" + ne.NeId
// result[neItem] = sysInfo
result, err = global.ToMap(*sysInfo, "json")
}
data = append(data, result)
log.Trace("data:", data)
}
var response Response
response.Data = data
services.ResponseWithJson(w, http.StatusOK, response)
}
// Get system state from NF/NFs
func GetStateFromNF(w http.ResponseWriter, r *http.Request) {
log.Debug("GetStateFromNF processing... ")
data := make([]map[string]interface{}, 0)
vars := mux.Vars(r)
neType := vars["elementTypeValue"]
var neList []dborm.NeInfo
if neType == "" {
services.ResponseNotFound404UriNotExist(w, r)
return
}
token, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
log.Debug("AccessToken:", token)
switch strings.ToLower(neType) {
case "all":
// query all NFs
// create rest client
restHostPort := fmt.Sprintf("http://127.0.0.1:%d", config.GetYamlConfig().Rest[0].Port)
getNeInfoPattern := fmt.Sprintf(config.UriPrefix+"/databaseManagement/v1/elementType/%s/objectType/ne_info",
config.GetYamlConfig().Database.Name)
getNeInfoURI := restHostPort + getNeInfoPattern + "?WHERE=status='0'"
log.Debug("getNeInfoPattern:", getNeInfoPattern)
resp, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"AccessToken": token}).
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Get(getNeInfoURI)
if err != nil {
log.Error("Get ne_info from DB is failed:", err)
services.ResponseInternalServerError500NFConnectRefused(w)
return
}
neList, _ = dborm.XormParseResult(resp.Body())
default:
restHostPort := fmt.Sprintf("http://127.0.0.1:%d", config.GetYamlConfig().Rest[0].Port)
getNeInfoPattern := fmt.Sprintf(config.UriPrefix+"/databaseManagement/v1/elementType/%s/objectType/ne_info",
config.GetYamlConfig().Database.Name)
getNeInfoURI := restHostPort + getNeInfoPattern
neId := services.GetUriParamString(r, "ne_id", ",", true, false)
if neId == "" {
getNeInfoURI = getNeInfoURI + fmt.Sprintf("?WHERE=status='0'+and+ne_type='%s'", neType)
} else {
getNeInfoURI = getNeInfoURI + fmt.Sprintf("?WHERE=status='0'+and+ne_type='%v'+and+ne_id+in+%v", neType, neId)
}
log.Debug("getNeInfoURI:", getNeInfoURI)
resp, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"accessToken": token}).
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Get(getNeInfoURI)
if err != nil {
log.Error("Get ne_info from DB is failed:", err)
services.ResponseInternalServerError500NFConnectRefused(w)
return
}
neList, _ = dborm.XormParseResult(resp.Body())
}
omcNeTypeLower := "omc"
if config.GetYamlConfig().OMC.NeType != "" {
omcNeTypeLower = strings.ToLower(config.GetYamlConfig().OMC.NeType)
}
for _, ne := range neList {
result := make(map[string]interface{})
log.Debugf("r.RemoteAddr: %s omcNeTypeLower: %s", r.RemoteAddr, omcNeTypeLower)
log.Debug("ne: ", ne)
//if strings.ToLower(ne.NeType) != omcNeTypeLower || !strings.Contains(r.RemoteAddr, ne.Ip) {
if strings.ToLower(ne.NeType) != omcNeTypeLower {
hostUri := fmt.Sprintf("http://%s:%v", ne.Ip, ne.Port)
requestURI2NF := fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
hostUri, ne.NeType)
log.Debug("requestURI2NF:", requestURI2NF)
result["ipAddress"] = ne.Ip
resp, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"accessToken": token}).
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Get(requestURI2NF)
if err != nil {
log.Error("Get system state from NF is failed:", err)
errorMessage := services.ErrorMessage{
ErrorCode: "1", ErrorInfo: "Internal server error, NF connnect refused",
}
result["error"] = errorMessage
} else {
systemState := make(map[string]interface{})
_ = json.Unmarshal(resp.Body(), &systemState)
result["systemState"] = systemState
}
} else {
result["ipAddress"] = ne.Ip
emsState := GetEMSState(ne.Ip)
result["systemState"] = emsState
}
neItem := strings.ToUpper(ne.NeType) + "/" + ne.NeId
mapState := make(map[string]interface{})
mapState[neItem] = result
data = append(data, mapState)
log.Trace("data:", data)
}
var response Response
response.Data = data
services.ResponseWithJson(w, http.StatusOK, response)
}
func GetEMSState(ip string) *SysState {
log.Debug("GetEMSState processing... ")
sysInfo := new(SysInfo)
err := GetSysInfo(sysInfo)
if err != nil {
log.Error("Failed to GetSysInfo:", err)
return nil
}
cpuUsage := &CpuUsage{
NfCpuUsage: sysInfo.MyCpuPercent,
SysCpuUsage: sysInfo.SysCpuPercent,
}
memUsage := &MemUsage{
TotalMem: sysInfo.SysTotalRam,
NfUsedMem: sysInfo.MyUsedRam,
SysMemUsage: sysInfo.SysRamUsedPercent,
}
diskSpace := &DiskSpace{
PartitionNum: sysInfo.PartitionNum,
PartitionInfo: sysInfo.PartitionInfo,
}
version := "16.1.1"
if global.Version != "" {
version = global.Version
}
hostName, _ := os.Hostname()
emsState := &SysState{
HostName: hostName,
OsInfo: getUnameStr(),
DbInfo: "mysql Ver 15.1 Distrib 10.3.35-MariaDB, for Linux (aarch64) using readline 5.1",
IpAddr: []string{ip},
Port: 3030,
Version: version,
Capability: 9999999,
SerialNum: config.GetYamlConfig().OMC.Sn,
ExpiryDate: "-",
HardwareInfo: HardwareInfo{CPUs: getCpuNumber(), Memory: getTotalMemory()},
CpuUsage: *cpuUsage,
MemUsage: *memUsage,
DiskSpace: *diskSpace,
}
//getSystemInfo()
return emsState
}

View File

@@ -0,0 +1,243 @@
//go:build linux
// +build linux
package state
import (
"encoding/binary"
"fmt"
"os"
"runtime"
"syscall"
"time"
"ems.agt/lib/log"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/disk"
"github.com/shirou/gopsutil/mem"
"github.com/shirou/gopsutil/process"
)
type SysInfo struct {
SysCpuPercent uint16 // x%
MyCpuPercent uint16 // x%, CPU percent of current proccess
SysTotalRam uint32 // KB
MyUsedRam uint32 // RAM usage of current proccess, KB
SysRamUsedPercent uint16 // x%
PartitionNum byte
PartitionInfo []PartitionInfo // usage of each partition
}
const MAX_PARTITION_NUM byte = 32
func GetSysStat() ([]byte, int) {
// Get sys info
var sysInfo SysInfo
err := GetSysInfo(&sysInfo)
if err != nil {
return nil, 0
}
//log.Tracef("current sys info: %v", sysInfo)
// build ems buffer
var data []byte = make([]byte, 1024)
var len int
var i byte
binary.BigEndian.PutUint16(data[0:], sysInfo.MyCpuPercent) //x% * 100
binary.BigEndian.PutUint16(data[2:], sysInfo.SysCpuPercent) //x% * 100
binary.BigEndian.PutUint32(data[4:], sysInfo.SysTotalRam) // KB
binary.BigEndian.PutUint32(data[8:], sysInfo.MyUsedRam) // KB
binary.BigEndian.PutUint16(data[12:], sysInfo.SysRamUsedPercent) //x% * 100
data[14] = sysInfo.PartitionNum
for i = 0; i < sysInfo.PartitionNum; i++ {
binary.BigEndian.PutUint32(data[15+8*(i):], sysInfo.PartitionInfo[i].Total) // MB
binary.BigEndian.PutUint32(data[15+8*(i)+4:], sysInfo.PartitionInfo[i].Used) // MB
}
len = int(15 + 8*sysInfo.PartitionNum)
//log.Tracef("current sys stat buf: %v, len: %d", data, len)
return data, len
}
var pProc *process.Process = nil
func GetSYsCpuPercent() float64 {
totalPercent, err := cpu.Percent(0, false) //(2*time.Second, false)
if err != nil {
return 0.0
} else {
return totalPercent[0]
}
}
func GetSysInfo(sysInfo *SysInfo) error {
// sys cpu percent
totalPercent, err := cpu.Percent(0, false) //(2*time.Second, false)
if err != nil {
sysInfo.SysCpuPercent = 0
} else {
sysInfo.SysCpuPercent = uint16(totalPercent[0] * 100)
}
if pProc == nil {
checkPid := os.Getpid()
pProc, err = process.NewProcess(int32(checkPid))
if err != nil {
log.Tracef("get process info error %v", err)
return err
}
}
// self cpu percent
percent, err := pProc.Percent(0) //(2*time.Second)
if err != nil {
log.Tracef("get process cpu percent error %v", err)
sysInfo.MyCpuPercent = 0
} else {
sysInfo.MyCpuPercent = uint16(percent * 100)
}
// self RAM(KB)
myRam, err := pProc.MemoryInfo()
if err != nil {
log.Tracef("get self memory info error %v", err)
sysInfo.MyUsedRam = 0
} else {
sysInfo.MyUsedRam = uint32(myRam.RSS / 1024)
}
// system RAM(KB)
sysRam, err := mem.VirtualMemory()
if err != nil {
log.Tracef("gett sys memory info error %v", err)
sysInfo.SysTotalRam = 0
sysInfo.SysRamUsedPercent = 0
} else {
sysInfo.SysTotalRam = uint32(sysRam.Total / 1024)
sysInfo.SysRamUsedPercent = uint16(sysRam.UsedPercent * 100)
}
// partition usage
GetPartitions(sysInfo)
return nil
}
func getProcess() process.Process {
checkPid := os.Getpid()
ret, _ := process.NewProcess(int32(checkPid))
return *ret
}
func GetSystemCpuInfo() {
physicalCnt, _ := cpu.Counts(false)
logicalCnt, _ := cpu.Counts(true)
log.Tracef("physical count:%d logical count:%d", physicalCnt, logicalCnt)
totalPercent, _ := cpu.Percent(3*time.Second, false) // per cpu is false
perPercents, _ := cpu.Percent(3*time.Second, true) // per cpu is true
log.Tracef("total percent:%v per percents:%v", totalPercent, perPercents)
}
func GetProcessCpuPercent() {
p := getProcess()
percent, err := p.Percent(0)
if err != nil {
log.Tracef("error %v", err)
}
numcpu := runtime.NumCPU()
// if percent < 0.0 || percent > 100.0*float64(numcpu) { // TODO
if percent < 0.0 {
log.Tracef("Err CPU Percent of Process: %f, CPU num: %d", percent, numcpu)
} else {
log.Tracef("get process CPU percent: %f, CPU num: %d", percent, numcpu)
}
}
func GetProcessMemoryInfo() {
p := getProcess()
v, err := p.MemoryInfo()
if err != nil {
log.Tracef("getting memory info error %v", err)
}
log.Tracef("get process memory info %v", v)
info, _ := mem.VirtualMemory()
fmt.Println(info)
}
func GetPartitions(sysInfo *SysInfo) {
sysInfo.PartitionNum = 0
//sysInfo.PartitionInfo = make([]PartitionInfo, MAX_PARTITION_NUM, MAX_PARTITION_NUM)
infos, _ := disk.Partitions(true)
for _, info := range infos {
GetOnePartitionUsage(info.Mountpoint, sysInfo)
if sysInfo.PartitionNum >= MAX_PARTITION_NUM {
break
}
}
}
func GetOnePartitionUsage(path string, sysInfo *SysInfo) int {
info, err := disk.Usage(path)
if err != nil {
return -1
}
if info.Total <= 0 { // info.Used/(1024 * 1024)MB
return 0
}
var partition PartitionInfo
partition.Total = uint32(info.Total / 1024 / 1024)
partition.Used = uint32(info.Used / 1024 / 1024)
sysInfo.PartitionInfo = append(sysInfo.PartitionInfo, partition)
sysInfo.PartitionNum++
/*data, err := json.MarshalIndent(info, "", " ")
if err != nil {
return -1
}
fmt.Println(string(data))*/
return 1
}
func getOS() string {
var osname string
if runtime.GOOS == "linux" {
osname = "GNU/Linux"
}
return osname
}
func utsnameToString(unameArray [65]int8) string {
var byteString [65]byte
var indexLength int
for ; unameArray[indexLength] != 0 && indexLength < 65; indexLength++ {
byteString[indexLength] = uint8(unameArray[indexLength])
}
return string(byteString[:indexLength])
}
func getUnameStr() string {
var utsname = syscall.Utsname{}
err := syscall.Uname(&utsname)
if err == nil {
name := utsnameToString(utsname.Sysname)
node := utsnameToString(utsname.Nodename)
release := utsnameToString(utsname.Release)
version := utsnameToString(utsname.Version)
machine := utsnameToString(utsname.Machine)
//domain:= utsnameToString(utsname.Domainname)
osName := getOS()
return fmt.Sprintf("%s %s %s %s %s %s", name, node,
release, version, machine, osName)
}
return ""
}

View File

@@ -0,0 +1,231 @@
//go:build windows
// +build windows
package state
import (
"encoding/binary"
"fmt"
"os"
"runtime"
"syscall"
"time"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/disk"
"github.com/shirou/gopsutil/mem"
"github.com/shirou/gopsutil/process"
)
type SysInfo struct {
SysCpuPercent uint16 // x%
MyCpuPercent uint16 // x%, CPU percent of current proccess
SysTotalRam uint32 // KB
MyUsedRam uint32 // RAM usage of current proccess, KB
SysRamUsedPercent uint16 // x%
PartitionNum byte
PartitionInfo []PartitionInfo // usage of each partition
}
const MAX_PARTITION_NUM byte = 32
func GetSysStat() ([]byte, int) {
// Get sys info
var sysInfo SysInfo
err := GetSysInfo(&sysInfo)
if err != nil {
return nil, 0
}
//fmt.Printf("current sys info: %v", sysInfo)
// build ems buffer
var data []byte = make([]byte, 1024)
var len int
var i byte
binary.BigEndian.PutUint16(data[0:], sysInfo.MyCpuPercent) //x% * 100
binary.BigEndian.PutUint16(data[2:], sysInfo.SysCpuPercent) //x% * 100
binary.BigEndian.PutUint32(data[4:], sysInfo.SysTotalRam) // KB
binary.BigEndian.PutUint32(data[8:], sysInfo.MyUsedRam) // KB
binary.BigEndian.PutUint16(data[12:], sysInfo.SysRamUsedPercent) //x% * 100
data[14] = sysInfo.PartitionNum
for i = 0; i < sysInfo.PartitionNum; i++ {
binary.BigEndian.PutUint32(data[15+8*(i):], sysInfo.PartitionInfo[i].Total) // MB
binary.BigEndian.PutUint32(data[15+8*(i)+4:], sysInfo.PartitionInfo[i].Used) // MB
}
len = int(15 + 8*sysInfo.PartitionNum)
//fmt.Printf("current sys stat buf: %v, len: %d", data, len)
return data, len
}
var pProc *process.Process = nil
func GetSYsCpuPercent() float64 {
totalPercent, err := cpu.Percent(0, false) //(2*time.Second, false)
if err != nil {
return 0.0
} else {
return totalPercent[0]
}
}
func GetSysInfo(sysInfo *SysInfo) error {
// sys cpu percent
totalPercent, err := cpu.Percent(0, false) //(2*time.Second, false)
if err != nil {
sysInfo.SysCpuPercent = 0
} else {
sysInfo.SysCpuPercent = uint16(totalPercent[0] * 100)
}
if pProc == nil {
checkPid := os.Getpid()
pProc, err = process.NewProcess(int32(checkPid))
if err != nil {
fmt.Printf("get process info error %v", err)
return err
}
}
// self cpu percent
percent, err := pProc.Percent(0) //(2*time.Second)
if err != nil {
fmt.Printf("get process cpu percent error %v", err)
sysInfo.MyCpuPercent = 0
} else {
sysInfo.MyCpuPercent = uint16(percent * 100)
}
// self RAM(KB)
myRam, err := pProc.MemoryInfo()
if err != nil {
fmt.Printf("get self memory info error %v", err)
sysInfo.MyUsedRam = 0
} else {
sysInfo.MyUsedRam = uint32(myRam.RSS / 1024)
}
// system RAM(KB)
sysRam, err := mem.VirtualMemory()
if err != nil {
fmt.Printf("gett sys memory info error %v", err)
sysInfo.SysTotalRam = 0
sysInfo.SysRamUsedPercent = 0
} else {
sysInfo.SysTotalRam = uint32(sysRam.Total / 1024)
sysInfo.SysRamUsedPercent = uint16(sysRam.UsedPercent * 100)
}
// partition usage
GetPartitions(sysInfo)
return nil
}
func getProcess() process.Process {
checkPid := os.Getpid()
ret, _ := process.NewProcess(int32(checkPid))
return *ret
}
func GetSystemCpuInfo() {
physicalCnt, _ := cpu.Counts(false)
logicalCnt, _ := cpu.Counts(true)
fmt.Printf("physical count:%d logical count:%d\n", physicalCnt, logicalCnt)
totalPercent, _ := cpu.Percent(3*time.Second, false) // per cpu is false
perPercents, _ := cpu.Percent(3*time.Second, true) // per cpu is true
fmt.Printf("total percent:%v per percents:%v\n", totalPercent, perPercents)
}
func GetProcessCpuPercent() {
p := getProcess()
percent, err := p.Percent(0)
if err != nil {
fmt.Printf("error %v", err)
}
numcpu := runtime.NumCPU()
// if percent < 0.0 || percent > 100.0*float64(numcpu) { // TODO
if percent < 0.0 {
fmt.Printf("Err CPU Percent of Process: %f, CPU num: %d", percent, numcpu)
} else {
fmt.Printf("get process CPU percent: %f, CPU num: %d", percent, numcpu)
}
}
func GetProcessMemoryInfo() {
p := getProcess()
v, err := p.MemoryInfo()
if err != nil {
fmt.Printf("getting memory info error %v", err)
}
fmt.Printf("get process memory info %v\n", v)
info, _ := mem.VirtualMemory()
fmt.Println(info)
}
func GetPartitions(sysInfo *SysInfo) {
sysInfo.PartitionNum = 0
//sysInfo.PartitionInfo = make([]PartitionInfo, MAX_PARTITION_NUM, MAX_PARTITION_NUM)
infos, _ := disk.Partitions(true)
for _, info := range infos {
GetOnePartitionUsage(info.Mountpoint, sysInfo)
if sysInfo.PartitionNum >= MAX_PARTITION_NUM {
break
}
}
}
func GetOnePartitionUsage(path string, sysInfo *SysInfo) int {
info, err := disk.Usage(path)
if err != nil {
return -1
}
if info.Total <= 0 { // info.Used/(1024 * 1024)MB
return 0
}
var partition PartitionInfo
partition.Total = uint32(info.Total / 1024 / 1024)
partition.Used = uint32(info.Used / 1024 / 1024)
sysInfo.PartitionInfo = append(sysInfo.PartitionInfo, partition)
sysInfo.PartitionNum++
/*data, err := json.MarshalIndent(info, "", " ")
if err != nil {
return -1
}
fmt.Println(string(data))*/
return 1
}
func getOS() string {
var osname string
if runtime.GOOS == "linux" {
osname = "GNU/Linux"
}
return osname
}
func utsnameToString(unameArray [65]int8) string {
var byteString [65]byte
var indexLength int
for ; unameArray[indexLength] != 0 && indexLength < 65; indexLength++ {
byteString[indexLength] = uint8(unameArray[indexLength])
}
return string(byteString[:indexLength])
}
func getUnameStr() string {
osInfo, _ := syscall.GetVersion()
return fmt.Sprintf("Widnows %d", osInfo)
}

74
features/state/sysinfo.go Normal file
View File

@@ -0,0 +1,74 @@
package state
import (
"ems.agt/lib/log"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/disk"
"github.com/shirou/gopsutil/host"
"github.com/shirou/gopsutil/mem"
)
func getSystemInfo() {
// 获取主机信息
hostInfo, err := host.Info()
if err != nil {
log.Errorf("Failed to get host info: %v", err)
return
}
log.Tracef("Host info: %+v", hostInfo)
// 获取CPU信息
cpuInfo, err := cpu.Info()
if err != nil {
log.Errorf("Failed to get CPU info: %v", err)
return
}
log.Tracef("CPU info: %+v", cpuInfo)
// 获取内存信息
memInfo, err := mem.VirtualMemory()
if err != nil {
log.Errorf("Failed to get memory info: %v", err)
return
}
log.Tracef("Memory info: %+v", memInfo)
// 获取磁盘分区信息
diskPartitions, err := disk.Partitions(true)
if err != nil {
log.Errorf("Failed to get disk partitions: %v", err)
return
}
log.Tracef("Disk partitions: %+v", diskPartitions)
for _, partition := range diskPartitions {
// 获取每个磁盘分区的使用情况
usage, err := disk.Usage(partition.Mountpoint)
if err != nil {
log.Errorf("Failed to get disk usage for %s: %v", partition.Mountpoint, err)
continue
}
log.Tracef("%s usage: %+v", partition.Mountpoint, usage)
}
}
func getCpuNumber() int {
// 获取CPU信息
cpuInfo, err := cpu.Info()
if err != nil {
log.Errorf("Failed to get CPU info: %v", err)
return 0
}
log.Tracef("CPU info: %+v", cpuInfo)
return len(cpuInfo)
}
func getTotalMemory() int {
// 获取内存信息
memInfo, err := mem.VirtualMemory()
if err != nil {
log.Errorf("Failed to get memory info: %v", err)
return 0
}
log.Tracef("Memory info: %+v", memInfo)
return int(memInfo.Total)
}

369
features/trace/trace.go Normal file
View File

@@ -0,0 +1,369 @@
package trace
import (
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"github.com/go-resty/resty/v2"
"ems.agt/lib/dborm"
"ems.agt/lib/global"
"ems.agt/lib/log"
"ems.agt/lib/services"
"ems.agt/restagent/config"
)
var (
UriTraceTaskV1 = config.UriPrefix + "/traceManagement/v1/subscriptions"
UriTraceTask = config.UriPrefix + "/traceManagement/{apiVersion}/subscriptions"
)
type TraceTask struct {
Id int `json:"id" xorm:"pk 'id' autoincr"`
TraceType string `json:"traceType"`
StartTime string `json:"startTime"`
EndTime string `json:"endTime"`
Imsi string `json:"imsi"`
Msisdn string `json:"msisdn"`
SrcIp string `json:"srcIp"`
DstIp string `json:"dstIp"`
SignalPort int16 `json:"signalPort"`
NeType string `json:"neType"`
NeId string `json:"neId"`
UeIp string `json:"ueIp"`
Interfaces []string `json:"interfaces"`
NotifyUrl string `json:"notifyUrl" xorm:"-"`
Status string `json:"-" xorm:"status"`
SuccNEs []string `json:"-" xorm:"succ_nes"`
FailNEs []string `json:"-" xorm:"fail_nes"`
UpdateTime string `json:"-" xorm:"-"`
}
var client = resty.New()
/*
func init() {
client.SetTimeout(3 * time.Second)
}
*/
// Post trace task to NF/NFs
func PostTraceTaskToNF(w http.ResponseWriter, r *http.Request) {
log.Debug("PostTraceTaskToNF processing... ")
//vars := mux.Vars(r)
token, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
log.Debug("AccessToken:", token)
body, err := io.ReadAll(io.LimitReader(r.Body, int64(config.GetYamlConfig().Params.UriMaxLen)))
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
log.Trace("body:", string(body))
traceTask := new(TraceTask)
_ = json.Unmarshal(body, traceTask)
log.Debug("traceTask:", traceTask)
var neTypes []string
// do not set device
if traceTask.NeType == "" {
// query neType by interface
if len(traceTask.Interfaces) > 0 {
err := dborm.XormGetSingleColStringArrayByIn("trace_info", "ne_type", "interface", traceTask.Interfaces, &neTypes)
if err != nil {
log.Error("Failed to dborm.XormGetSingleCol:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
}
} else {
neTypes = append(neTypes, traceTask.NeType)
}
log.Debug("neTypes:", neTypes)
traceTask.Status = "Inactive"
_, err = dborm.XormInsertTableOne("trace_task", traceTask)
if err != nil {
log.Error("Failed to dborm.XormInsertTableOne:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
traceTask.NotifyUrl = config.GetYamlConfig().OMC.GtpUri
log.Trace("traceTask:", traceTask)
for _, neType := range neTypes {
var neInfos []dborm.NeInfo
if traceTask.NeId == "" {
err := dborm.XormGetNeInfoByNeType(neType, &neInfos)
if err != nil {
log.Error("Failed to dborm.XormGetNeInfoByNeType:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
} else {
neInfo, err := dborm.XormGetNeInfo(neType, traceTask.NeId)
if err != nil {
log.Error("Failed to dborm.XormGetNeInfoByNeType:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
neInfos = append(neInfos, *neInfo)
}
for _, neInfo := range neInfos {
hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
requestURI2NF := fmt.Sprintf("%s%s", hostUri, UriTraceTaskV1)
log.Debug("requestURI2NF:", requestURI2NF)
body, _ := json.Marshal(traceTask)
log.Debug("body:", string(body))
resp, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
SetBody(body).
Post(requestURI2NF)
if err != nil {
log.Error("Failed to Post:", err)
failNE := fmt.Sprintf("%s.%s", neInfo.NeType, neInfo.NeId)
traceTask.FailNEs = append(traceTask.FailNEs, failNE)
} else {
switch resp.StatusCode() {
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
succNE := fmt.Sprintf("%s.%s", neInfo.NeType, neInfo.NeId)
traceTask.SuccNEs = append(traceTask.SuccNEs, succNE)
default:
log.Warn("Post return code:%d, message:%s", resp.StatusCode(), string(resp.Body()))
failNE := fmt.Sprintf("%s.%s", neInfo.NeType, neInfo.NeId)
traceTask.FailNEs = append(traceTask.FailNEs, failNE)
}
}
}
}
if len(traceTask.SuccNEs) > 0 {
traceTask.Status = "Active"
_, err = dborm.XormUpdateTableById(traceTask.Id, "trace_task", traceTask)
if err != nil {
log.Error("Failed to dborm.XormUpdateTableById:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
services.ResponseStatusOK204NoContent(w)
} else {
traceTask.Status = "Failed"
_, err = dborm.XormUpdateTableById(traceTask.Id, "trace_task", traceTask)
if err != nil {
log.Error("Failed to dborm.XormUpdateTableById:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
err = global.ErrTraceFailedDistributeToNEs
log.Error(err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
}
func PutTraceTaskToNF(w http.ResponseWriter, r *http.Request) {
log.Debug("PutTraceTaskToNF processing... ")
//vars := mux.Vars(r)
token, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
log.Debug("AccessToken:", token)
body, err := io.ReadAll(io.LimitReader(r.Body, int64(config.GetYamlConfig().Params.UriMaxLen)))
if err != nil {
log.Error("io.ReadAll is failed:", err)
services.ResponseNotFound404UriNotExist(w, r)
return
}
traceTask := new(TraceTask)
_ = json.Unmarshal(body, traceTask)
traceTask.NotifyUrl = config.GetYamlConfig().OMC.GtpUri
log.Debug("traceTask:", traceTask)
var neTypes []string
// do not set device
if traceTask.NeType == "" {
// query neType by interface
if len(traceTask.Interfaces) > 0 {
err := dborm.XormGetSingleColStringArrayByIn("trace_info", "ne_type", "interface", traceTask.Interfaces, &neTypes)
if err != nil {
log.Error("Failed to dborm.XormGetSingleColStringArrayByIn:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
}
} else {
neTypes = append(neTypes, traceTask.NeType)
}
log.Debug("neTypes:", neTypes)
for _, neType := range neTypes {
var neInfos []dborm.NeInfo
if traceTask.NeId == "" {
err := dborm.XormGetNeInfoByNeType(neType, &neInfos)
if err != nil {
log.Error("Failed to dborm.XormGetNeInfoByNeType:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
} else {
neInfo, err := dborm.XormGetNeInfo(neType, traceTask.NeId)
if err != nil {
log.Error("Failed to dborm.XormGetNeInfoByNeType:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
neInfos = append(neInfos, *neInfo)
}
for _, neInfo := range neInfos {
hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
requestURI2NF := fmt.Sprintf("%s%s", hostUri, UriTraceTaskV1)
log.Debug("requestURI2NF:", requestURI2NF)
body, _ := json.Marshal(traceTask)
log.Debug("body:", string(body))
resp, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
SetBody(body).
Put(requestURI2NF)
if err != nil {
log.Error("Failed to Put:", err)
failNE := fmt.Sprintf("%s.%s", neInfo.NeType, neInfo.NeId)
traceTask.FailNEs = append(traceTask.FailNEs, failNE)
} else {
switch resp.StatusCode() {
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
succNE := fmt.Sprintf("%s.%s", neInfo.NeType, neInfo.NeId)
traceTask.SuccNEs = append(traceTask.SuccNEs, succNE)
default:
log.Warn("Post return code:%d, message:%s", resp.StatusCode(), string(resp.Body()))
failNE := fmt.Sprintf("%s.%s", neInfo.NeType, neInfo.NeId)
traceTask.FailNEs = append(traceTask.FailNEs, failNE)
}
}
}
}
if len(traceTask.SuccNEs) > 0 {
traceTask.Status = "Active"
_, err = dborm.XormUpdateTableById(traceTask.Id, "trace_task", traceTask)
if err != nil {
log.Error("Failed to dborm.XormUpdateTableById:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
services.ResponseStatusOK204NoContent(w)
} else {
traceTask.Status = "Failed"
_, err = dborm.XormUpdateTableById(traceTask.Id, "trace_task", traceTask)
if err != nil {
log.Error("Failed to dborm.XormUpdateTableById:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
err = global.ErrTraceFailedDistributeToNEs
log.Error(err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
}
func DeleteTraceTaskToNF(w http.ResponseWriter, r *http.Request) {
log.Debug("DeleteTraceTaskToNF processing... ")
token, err := services.CheckFrontValidRequest(w, r)
if err != nil {
log.Error("Request error:", err)
return
}
log.Debug("AccessToken:", token)
vars := r.URL.Query()
ids, ok := vars["id"]
if !ok || len(ids) == 0 {
err = global.ErrTraceNotCarriedTaskID
log.Error(err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
log.Debug("ids:", ids)
for _, id := range ids {
log.Debug("id:", id)
var succNes []string
err = dborm.XormGetColStringArrayByWhere("trace_task", "succ_nes", fmt.Sprintf("id=%s", id), &succNes)
if err != nil {
log.Error("Failed to dborm.XormGetSingleColStringArrayByWhere:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
log.Debug("succNes:", succNes)
nes := new([]string)
if len(succNes) > 0 {
_ = json.Unmarshal([]byte(succNes[0]), nes)
}
log.Debug("nes:", nes)
for _, ne := range *nes {
i := strings.Index(ne, ".")
neType := ne[0:i]
neId := ne[i+1:]
log.Debugf("ne:%s neType:%s neId:%s", ne, neType, neId)
neInfo, err := dborm.XormGetNeInfo(neType, neId)
if err != nil {
log.Error("Failed to dborm.XormGetNeInfo:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
requestURI2NF := fmt.Sprintf("%s%s?id=%s", hostUri, UriTraceTaskV1, id)
log.Debug("requestURI2NF:", requestURI2NF)
_, err = client.R().
EnableTrace().
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Delete(requestURI2NF)
if err != nil {
log.Error("Failed to Delete:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
}
_, err = dborm.XormDeleteDataByWhere(fmt.Sprintf("id=%s", id), "trace_task")
if err != nil {
log.Error("Failed to dborm.XormDeleteDataByWhere:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
}
services.ResponseStatusOK204NoContent(w)
return
}