From c6962cf5373a6708efbdc9056864449f87abee0c Mon Sep 17 00:00:00 2001 From: simonzhangsz Date: Wed, 11 Oct 2023 10:24:33 +0800 Subject: [PATCH] license --- .gitignore | 1 + database/upgrade/zupgrade.sql | 8 +- features/cm/license.go | 198 ++++++++++++++++++++++++++++++++-- lib/dborm/dborm.go | 17 ++- lib/routes/routes.go | 14 +-- 5 files changed, 216 insertions(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index c3c377d2..2b03653d 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ restagent/log/ restagent/upload/ restagent/software/ restagent/database/ +restagent/license/ restagent/restagent sshsvc/sshsvc diff --git a/database/upgrade/zupgrade.sql b/database/upgrade/zupgrade.sql index bb05b2f3..54956ca6 100644 --- a/database/upgrade/zupgrade.sql +++ b/database/upgrade/zupgrade.sql @@ -84,4 +84,10 @@ ALTER TABLE `omc_db`.`trace_data` MODIFY COLUMN `timestamp` bigint NULL DEFAULT NULL AFTER `msg_direct`; ALTER TABLE `omc_db`.`param_config` -MODIFY COLUMN `method` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT 'method allow: \"get\", \"get,post,put\", \"delete\"' AFTER `top_display`; \ No newline at end of file +MODIFY COLUMN `method` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT 'method allow: \"get\", \"get,post,put\", \"delete\"' AFTER `top_display`; + +ALTER TABLE `omc_db`.`ne_license` +MODIFY COLUMN `status` enum('ACTIVE','INACTIVE','PENDING') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'ACTIVE' AFTER `expiration_date`, +ADD COLUMN IF NOT EXISTS `path` varchar(128) NULL AFTER `status`, +ADD COLUMN IF NOT EXISTS `file_name` varchar(64) NULL AFTER `path`, +ADD COLUMN IF NOT EXISTS `comment` varchar(255) NULL AFTER `file_name`; \ No newline at end of file diff --git a/features/cm/license.go b/features/cm/license.go index e691a903..15edc728 100644 --- a/features/cm/license.go +++ b/features/cm/license.go @@ -1,8 +1,14 @@ package cm import ( + "fmt" + "io" "net/http" + "os" + "os/exec" + "strings" + "ems.agt/lib/dborm" "ems.agt/lib/log" "ems.agt/lib/services" "ems.agt/restagent/config" @@ -11,12 +17,12 @@ import ( ) var ( - // License - LicenseUri = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/{neType}/license" - NeLicenseUri = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/{neType}/license/{neId}" + // General License URI + UriLicense = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/{elementTypeValue}/license" + UriLicenseExt = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/license" - CustomLicenseUri = config.UriPrefix + "/systemManagement/{apiVersion}/{neType}/license" - CustomNeLicenseUri = config.UriPrefix + "/systemManagement/{apiVersion}/{neType}/license/{neId}" + CustomUriLicense = config.UriPrefix + "/systemManagement/{apiVersion}/{elementTypeValue}/license" + CustomUriLicenseExt = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/license" ) func UploadLicenseFile(w http.ResponseWriter, r *http.Request) { @@ -39,7 +45,6 @@ func UploadLicenseFile(w http.ResponseWriter, r *http.Request) { // neTypeLower := strings.ToLower(neType) services.ResponseStatusOK204NoContent(w) - return } func DownloadLicenseFile(w http.ResponseWriter, r *http.Request) { @@ -86,7 +91,6 @@ func DownloadLicenseFile(w http.ResponseWriter, r *http.Request) { // md5Sum := (*neSoftware)[0]["md5_sum"] // services.ResponseFileWithNameAndMD5(w, http.StatusOK, fileName, path, md5Sum) - return } func DeleteLcenseFile(w http.ResponseWriter, r *http.Request) { @@ -147,5 +151,183 @@ func DeleteLcenseFile(w http.ResponseWriter, r *http.Request) { // } services.ResponseStatusOK204NoContent(w) - return +} + +func UploadLicenseFileData(w http.ResponseWriter, r *http.Request) { + log.Info("UploadLicenseFileData processing... ") + + _, err := services.CheckFrontValidRequest(w, r) + if err != nil { + log.Error("Http 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) + + //md5Param := services.GetUriParamString(r, "md5Sum", ",", false, false) + + neId := services.GetUriParamString(r, "neId", ",", false, false) + + neInfo, err := dborm.XormGetNeInfo(neType, neId) + if err != nil { + log.Errorf("Failed to get ne_info:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + log.Debug("neInfo:", neInfo) + + licensePath := fmt.Sprintf("%s/%s", config.GetYamlConfig().OMC.License, neTypeLower) + err = os.MkdirAll(licensePath, os.ModePerm) + if err != nil { + log.Error("Failed to Mkdir:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + //fileName, err := services.HandleUploadFile(r, softwarePath, "") + + // 解析multipart/form-data请求 + err = r.ParseMultipartForm(10 << 20) // 10MB + if err != nil { + log.Error("Faile to ParseMultipartForm:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + + // 获取文件和数据 + licFile := r.MultipartForm.File["file"] + data := r.MultipartForm.Value["comment"] + + var licenseFileName, comment string + + // 处理软件rpm/deb文件 + if len(licFile) > 0 { + file := licFile[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(licensePath + "/" + file.Filename) + if err != nil { + log.Error("Faile to Create:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + defer dst.Close() + + licenseFileName = 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] + } + + neLicensePath := strings.ReplaceAll(config.GetYamlConfig().NE.LicenseDir, "{neType}", neTypeLower) + + srcFile := fmt.Sprintf("%s/%s", licensePath, licenseFileName) + scpDir := fmt.Sprintf("%s@%s:%s", config.GetYamlConfig().NE.User, neInfo.Ip, config.GetYamlConfig().NE.ScpDir) + cmd := exec.Command("scp", "-r", srcFile, scpDir) + out, err := cmd.CombinedOutput() + log.Debugf("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 + } + // backup system.ini to system.ini.bak + sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip) + cpCmd := fmt.Sprintf("sudo cp -f %s/system.ini %s/system.ini.bak", neLicensePath, neLicensePath) + cmd = exec.Command("ssh", sshHost, cpCmd) + out, err = cmd.CombinedOutput() + log.Debugf("Exec output: %v", string(out)) + if err != nil { + log.Error("Faile to execute cp command:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + + // replace system.ini + neFilePath := config.GetYamlConfig().NE.ScpDir + "/" + licenseFileName + cpCmd = fmt.Sprintf("sudo cp -f %s %s/system.ini", neFilePath, neLicensePath) + cmd = exec.Command("ssh", sshHost, cpCmd) + out, err = cmd.CombinedOutput() + log.Debugf("Exec output: %v", string(out)) + if err != nil { + log.Error("Faile to execute cp command:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + + switch neTypeLower { + case "omc": + restartCmd := fmt.Sprintf("sudo %s/bin/omcsvc.sh restart", config.GetYamlConfig().NE.OmcDir) + cmd := exec.Command("ssh", sshHost, restartCmd) + out, err := cmd.CombinedOutput() + log.Debugf("Exec output: %v", string(out)) + if err != nil { + log.Error("Faile to execute ssh restart omc:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + case "ims": + restartCmd := "sudo ims-stop && sudo ims-start" + cmd := exec.Command("ssh", sshHost, restartCmd) + out, err := cmd.CombinedOutput() + log.Debugf("Exec output: %v", string(out)) + if err != nil { + log.Error("Faile to execute ssh sudo systemctl command:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + default: + restartCmd := fmt.Sprintf("sudo systemctl restart %s.service", neTypeLower) + cmd := exec.Command("ssh", sshHost, restartCmd) + out, err := cmd.CombinedOutput() + log.Debugf("Exec output: %v", string(out)) + if err != nil { + log.Error("Faile to execute ssh sudo systemctl command:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + } + + neLicense := dborm.NeLicense{ + NeType: neTypeUpper, + NeID: neId, + Status: "ACTIVE", + Path: licensePath, + FileName: licenseFileName, + Comment: comment, + } + + log.Debug("neLicense:", neLicense) + _, err = dborm.XormInsertTableOne("ne_license", neLicense) + if err != nil { + log.Error("Faile to XormInsertTableOne:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + + services.ResponseStatusOK204NoContent(w) } diff --git a/lib/dborm/dborm.go b/lib/dborm/dborm.go index 58f43567..4c132a75 100644 --- a/lib/dborm/dborm.go +++ b/lib/dborm/dborm.go @@ -1630,9 +1630,20 @@ func IsPermissionAllowed(token, method, module, dbname, tbname, pack string) (bo } type NeLicense struct { - NeType string `json:"neType" xorm:"ne_type"` - NeID string `json:"neID" xorm:"ne_id"` - Capability int `json:"capability"` + NeType string `json:"neType" xorm:"ne_type"` + NeID string `json:"neID" xorm:"ne_id"` + SerialNo string `json:"serialNo" xorm:"serial_no"` + Capcity int `json:"capcity" xorm:"capcity"` + Used int `json:"used" xorm:"used"` + FeatureEnabled string `json:"featureEnabled" xorm:"feature_enabled"` + ExpirationDate string `json:"expirationDate" xorm:"expiration_date"` + Status string `json:"status" xorm:"status"` + Path string `json:"path" xorm:"path"` + FileName string `json:"file_name" xorm:"file_name"` + Comment string `json:"comment" xorm:"comment"` + CreatedAt string `json:"createdAt" xorm:"-"` + UpdatedAt string `json:"updatedAt" xorm:"-"` + DeletedAt string `json:"deletedAt" xorm:"-"` } func XormAdjustmentNeLicense(neType, neID string, value int) (int64, error) { diff --git a/lib/routes/routes.go b/lib/routes/routes.go index d371e5b6..b0e187e2 100644 --- a/lib/routes/routes.go +++ b/lib/routes/routes.go @@ -220,17 +220,11 @@ func init() { Register("PATCH", cm.CustomUriSoftwareNE, cm.RollBackSoftwareToNF, nil) // License management - Register("GET", cm.LicenseUri, cm.ExportCmFromNF, nil) - Register("POST", cm.LicenseUri, cm.ImportCmToNF, nil) - Register("DELETE", cm.LicenseUri, cm.ImportCmToNF, nil) + Register("POST", cm.UriLicense, cm.UploadLicenseFileData, nil) + Register("POST", cm.UriLicenseExt, cm.UploadLicenseFileData, nil) - Register("POST", cm.NeLicenseUri, cm.ExportCmFromNF, nil) - Register("PUT", cm.NeLicenseUri, cm.ImportCmToNF, nil) - Register("PATCH", cm.NeLicenseUri, cm.ImportCmToNF, nil) - - Register("POST", cm.CustomNeLicenseUri, cm.ExportCmFromNF, nil) - Register("PUT", cm.CustomNeLicenseUri, cm.ImportCmToNF, nil) - Register("PATCH", cm.CustomNeLicenseUri, cm.ImportCmToNF, nil) + Register("POST", cm.CustomUriLicense, cm.UploadLicenseFileData, nil) + Register("POST", cm.CustomUriLicenseExt, cm.UploadLicenseFileData, nil) // Trace management Register("POST", trace.UriTraceTask, trace.PostTraceTaskToNF, nil)