Files
be.ems/features/cm/software.go
2023-08-14 17:02:50 +08:00

576 lines
16 KiB
Go

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
}