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 }