diff --git a/features/cm/ne.go b/features/cm/ne.go index 1dab43d7..50dc704a 100644 --- a/features/cm/ne.go +++ b/features/cm/ne.go @@ -576,7 +576,6 @@ func ImportCmToNF(w http.ResponseWriter, r *http.Request) { } services.ResponseStatusOK204NoContent(w) - return } func DownloadNeBackupFile(w http.ResponseWriter, r *http.Request) { diff --git a/features/cm/software.go b/features/cm/software.go index 76d0667c..d4a1d86f 100644 --- a/features/cm/software.go +++ b/features/cm/software.go @@ -3,6 +3,7 @@ package cm import ( "bytes" "fmt" + "io" "net/http" "os" "os/exec" @@ -185,7 +186,181 @@ func UploadSoftwareFile(w http.ResponseWriter, r *http.Request) { } services.ResponseStatusOK204NoContent(w) - return +} + +func UploadSoftwareMultiFile(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) + + softwarePath := fmt.Sprintf("%s/%s", config.GetYamlConfig().OMC.Software, neTypeLower) + //fileName, err := services.HandleUploadFile(r, softwarePath, "") + + // 解析multipart/form-data请求 + err = r.ParseMultipartForm(100 << 20) // 100MB + if err != nil { + log.Error("Faile to ParseMultipartForm:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + + // 获取文件和数据 + swFile := r.MultipartForm.File["file"] + cmsFile := r.MultipartForm.File["cms"] + data := r.MultipartForm.Value["comment"] + + var softwareFileName, cmsFileName, comment string + + // 处理软件rpm/deb文件 + if len(swFile) > 0 { + file := swFile[0] + // 打开文件 + f, err := file.Open() + if err != nil { + log.Error("Faile to Open:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + defer f.Close() + + // 创建本地文件 + dst, err := os.Create(softwarePath + "/" + file.Filename) + if err != nil { + log.Error("Faile to Create:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + defer dst.Close() + + softwareFileName = file.Filename + // 将文件内容拷贝到本地文件 + _, err = io.Copy(dst, f) + if err != nil { + log.Error("Faile to Copy:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + } + + // 处理cms文件 + if len(cmsFile) > 0 { + file := cmsFile[0] + // 打开文件 + f, err := file.Open() + if err != nil { + log.Error("Faile to Open:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + defer f.Close() + + // 创建本地文件 + dst, err := os.Create(softwarePath + "/" + file.Filename) + if err != nil { + log.Error("Faile to Create:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + defer dst.Close() + + cmsFileName = file.Filename + // 将文件内容拷贝到本地文件 + _, err = io.Copy(dst, f) + if err != nil { + log.Error("Faile to Copy:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + } + + // 处理数据 + if len(data) > 0 { + comment = data[0] + } + + if config.GetYamlConfig().OMC.CheckSign && cmsFileName != "" { + rpmFilePath := softwarePath + "/" + softwareFileName + cmsFileName := cmsFileName + cmsFilePath := softwarePath + "/" + cmsFileName + log.Debugf("cmsFilePath:%s rpmFilePath:%s publicKey:%s", rpmFilePath, cmsFilePath, config.GetYamlConfig().Auth.PublicKey) + result := verify_signature(config.GetYamlConfig().Auth.PublicKey, cmsFilePath, rpmFilePath) + log.Debug("result:", result.String()) + if !strings.Contains(result.String(), SoftwareVerifiedOk) { + err = global.ErrCMNotMatchSignFile + log.Error(err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + // 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: softwareFileName, + Path: softwarePath, + Version: version, + Md5Sum: md5Param, + Comment: comment, + } + + _, err = dborm.XormInsertTableOne("ne_software", neSoftware) + if err != nil { + log.Error("Faile to XormInsertTableOne:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + + services.ResponseStatusOK204NoContent(w) } func DownloadSoftwareFile(w http.ResponseWriter, r *http.Request) { @@ -232,7 +407,6 @@ func DownloadSoftwareFile(w http.ResponseWriter, r *http.Request) { md5Sum := (*neSoftware)[0]["md5_sum"] services.ResponseFileWithNameAndMD5(w, http.StatusOK, fileName, path, md5Sum) - return } func DeleteSoftwareFile(w http.ResponseWriter, r *http.Request) { @@ -293,7 +467,6 @@ func DeleteSoftwareFile(w http.ResponseWriter, r *http.Request) { } services.ResponseStatusOK204NoContent(w) - return } func DistributeSoftwareToNF(w http.ResponseWriter, r *http.Request) { @@ -402,7 +575,7 @@ func DistributeSoftwareToNF(w http.ResponseWriter, r *http.Request) { return } } else { - idNeVersion, err := strconv.Atoi((*neVersion)[0]["id"]) + idNeVersion, _ := strconv.Atoi((*neVersion)[0]["id"]) neVersionData := dborm.NeVersion{ NeType: neTypeUpper, NeId: neInfo.NeId, @@ -496,7 +669,7 @@ func ActiveSoftwareToNF(w http.ResponseWriter, r *http.Request) { 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) + rpmCmd := fmt.Sprintf("sudo rpm -Uvh '%s'", filePath) cmd := exec.Command("ssh", sshHost, rpmCmd) out, err := cmd.CombinedOutput() log.Tracef("Exec output: %v", string(out)) diff --git a/features/ue/ue.go b/features/ue/ue.go index b27bb1d7..15013f85 100644 --- a/features/ue/ue.go +++ b/features/ue/ue.go @@ -32,6 +32,7 @@ type SmfUENum struct { type SmfUEInfo struct { IMSI string `json:"imsi"` MSISDN string `json:"msisdn"` + RatType string `json:"ratType"` PduSessionInfo []struct { PduSessionID int `json:"pduSessionID"` IPv4 string `json:"ipv4"` diff --git a/lib/routes/routes.go b/lib/routes/routes.go index 60e2a7eb..19101921 100644 --- a/lib/routes/routes.go +++ b/lib/routes/routes.go @@ -200,7 +200,8 @@ func init() { // Software management Register("GET", cm.UriSoftware, cm.DownloadSoftwareFile, nil) - Register("POST", cm.UriSoftware, cm.UploadSoftwareFile, nil) + //Register("POST", cm.UriSoftware, cm.UploadSoftwareFile, nil) + Register("POST", cm.UriSoftware, cm.UploadSoftwareMultiFile, nil) Register("DELETE", cm.UriSoftware, cm.DeleteSoftwareFile, nil) Register("POST", cm.UriSoftwareNE, cm.DistributeSoftwareToNF, nil) diff --git a/lib/services/file.go b/lib/services/file.go index d3163235..fef202da 100644 --- a/lib/services/file.go +++ b/lib/services/file.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "mime/multipart" "net/http" "os" @@ -32,14 +31,14 @@ func GetPostFile(w http.ResponseWriter, r *http.Request) { //获取文件流,第三个返回值是错误对象 file, header, _ := r.FormFile("file") //读取文件流为[]byte - b, err := ioutil.ReadAll(file) + b, err := io.ReadAll(file) if err != nil { log.Error("Failed to ReadAll:", err) ResponseInternalServerError500ProcessError(w, err) return } //把文件保存到指定位置 - err = ioutil.WriteFile("./upload/test.zip", b, 0644) + err = os.WriteFile("./upload/test.zip", b, 0644) if err != nil { log.Error("Failed to WriteFile:", err) ResponseInternalServerError500ProcessError(w, err) @@ -112,7 +111,7 @@ func HandleUploadFile(r *http.Request, path, newFileName string) (string, error) log.Debugf("FileName=[%s], FormName=[%s]", part.FileName(), part.FormName()) if part.FileName() == "" { // this is FormData - data, _ := ioutil.ReadAll(part) + data, _ := io.ReadAll(part) log.Debugf("FormData=[%s]", string(data)) } else { // This is FileData @@ -146,6 +145,77 @@ func HandleUploadFile(r *http.Request, path, newFileName string) (string, error) return fileName, nil } +type UploadMultiFileData struct { + SoftwareFileName string `json:"softwareFileName"` + CmsFileName string `json:"cmsFileName"` + Datas map[string][]string `json:"datas"` +} + +func HandleUploadMultiFile(r *http.Request, path, newFileName string) (*UploadMultiFileData, error) { + fileData := new(UploadMultiFileData) + // 解析multipart/form-data请求 + err := r.ParseMultipartForm(100 << 20) // 100MB + if err != nil { + return fileData, err + } + + // 获取文件和数据 + softwareFile := r.MultipartForm.File["file"] + cmsFile := r.MultipartForm.File["cms"] + fileData.Datas = r.MultipartForm.Value + + // 处理文件 + if len(softwareFile) > 0 { + file := softwareFile[0] + // 打开文件 + f, err := file.Open() + if err != nil { + return fileData, err + } + defer f.Close() + + // 创建本地文件 + dst, err := os.Create(path + "/" + file.Filename) + if err != nil { + return fileData, err + } + defer dst.Close() + + fileData.SoftwareFileName = file.Filename + // 将文件内容拷贝到本地文件 + _, err = io.Copy(dst, f) + if err != nil { + return fileData, err + } + } + // 处理文件 + if len(cmsFile) > 0 { + file := cmsFile[0] + // 打开文件 + f, err := file.Open() + if err != nil { + return fileData, err + } + defer f.Close() + + // 创建本地文件 + dst, err := os.Create(path + "/" + file.Filename) + if err != nil { + return fileData, err + } + defer dst.Close() + + fileData.CmsFileName = file.Filename + // 将文件内容拷贝到本地文件 + _, err = io.Copy(dst, f) + if err != nil { + return fileData, err + } + } + + return fileData, nil +} + func HandleUploadFormFile(w http.ResponseWriter, r *http.Request) { r.ParseMultipartForm(32 << 20) //mForm := r.MultipartForm @@ -245,9 +315,6 @@ func PostFileHandler(w http.ResponseWriter, r *http.Request) { http.Error(w, "分片文件"+fileName+chunkNumber+"上传成功", http.StatusOK) } } - return - - http.NotFound(w, r) } // 上传内容大小限制 diff --git a/makefile b/makefile index 7e3f2682..dd8fe6e9 100644 --- a/makefile +++ b/makefile @@ -2,9 +2,9 @@ PROJECT = OMC VERSION = 1.6.1 -RelVer = 1 RelDate = `date +%Y%m%d` -Release = $(RelDate).$(RelVer) +Release = $(RelDate) +RelVer = $(VERSION)-$(RelDate) PLATFORM = amd64 ARMPLATFORM = aarch64 GitLocalRoot = $(HOME)/local.git @@ -44,19 +44,19 @@ BinWriterDir = $(HOME)/bin .PHONY: all $(RESTAGENT) $(CRONTASK) $(SshSvcBin) $(CapTraceBin) all: $(RESTAGENT) $(CRONTASK) $(SshSvcBin) $(CapTraceBin) cd $(RestagentDir) - go build -o $(RESTAGENT) -v -ldflags "-X 'ems.agt/lib/conifg.Version=$(VERSION)' \ + go build -o $(RESTAGENT) -v -ldflags "-X 'ems.agt/lib/conifg.Version=$(RelVer)' \ -X '$(LibDir)/conifg.BuildTime=`date`' \ -X '$(LibDir)/conifg.GoVer=`go version`'" cd $(CrontaskDir) - go build -o $(CRONTASK) -v -ldflags "-X '$(LibDir)/conifg.Version=$(VERSION)' \ + go build -o $(CRONTASK) -v -ldflags "-X '$(LibDir)/conifg.Version=$(RelVer)' \ -X '$(LibDir)/conifg.BuildTime=`date`' \ -X '$(LibDir)/conifg.GoVer=`go version`'" cd $(SshSvcDir) - go build -o $(SshSvcBin) -v -ldflags "-X '$(LibDir)/conifg.Version=$(VERSION)' \ + go build -o $(SshSvcBin) -v -ldflags "-X '$(LibDir)/conifg.Version=$(RelVer)' \ -X '$(LibDir)/conifg.BuildTime=`date`' \ -X '$(LibDir)/conifg.GoVer=`go version`'" cd $(CapTraceDir) - go build -o $(CapTraceBin) -v -ldflags "-X '$(LibDir)/conifg.Version=$(VERSION)' \ + go build -o $(CapTraceBin) -v -ldflags "-X '$(LibDir)/conifg.Version=$(RelVer)' \ -X '$(LibDir)/conifg.BuildTime=`date`' \ -X '$(LibDir)/conifg.GoVer=`go version`'" @@ -98,6 +98,7 @@ deb: $(BINNAME) chmod +x $(DebBuildDir)/usr/local/omc/bin/* cp -rf $(BuildDir)/nginx/* $(DebBuildDir)/etc/nginx/conf.d cp -rf $(BuildDir)/systemd/*.service $(DebBuildDir)/lib/systemd/system/ + sed -i.bak 's/YYYYMMDD/$(`date +%Y%m%d`)/g' $(DebBuildDir)/DEBIAN/control dpkg -b $(DebBuildDir) $(ReleaseDebs)/$(PROJECT)-$(VERSION)-$(Release).$(PLATFORM).deb rpm: $(BINNAME)