From 8c6450e7e851f792d3332366c7584ba5b024ca6d Mon Sep 17 00:00:00 2001 From: simonzhangsz Date: Thu, 22 Feb 2024 15:48:51 +0800 Subject: [PATCH] fix: no restart service after license upload --- features/cm/license.go | 257 +++++++++++++++++++++++++++++++++++------ 1 file changed, 224 insertions(+), 33 deletions(-) diff --git a/features/cm/license.go b/features/cm/license.go index ad2cf1e9..abad2f35 100644 --- a/features/cm/license.go +++ b/features/cm/license.go @@ -7,6 +7,7 @@ import ( "os" "os/exec" "strings" + "time" "ems.agt/lib/dborm" "ems.agt/lib/log" @@ -153,6 +154,22 @@ func DeleteLcenseFile(w http.ResponseWriter, r *http.Request) { services.ResponseStatusOK204NoContent(w) } +type MMLRequest struct { + MML []string `json:"mml"` +} + +var TIME_DELAY_AFTER_WRITE time.Duration = 200 +var TIME_DEAD_LINE time.Duration = 10 + +func init() { + if config.GetYamlConfig().MML.Sleep != 0 { + TIME_DELAY_AFTER_WRITE = time.Duration(config.GetYamlConfig().MML.Sleep) + } + if config.GetYamlConfig().MML.DeadLine != 0 { + TIME_DEAD_LINE = time.Duration(config.GetYamlConfig().MML.DeadLine) + } +} + func UploadLicenseFileData(w http.ResponseWriter, r *http.Request) { log.Info("UploadLicenseFileData processing... ") @@ -207,7 +224,7 @@ func UploadLicenseFileData(w http.ResponseWriter, r *http.Request) { var licenseFileName, comment string - // 处理软件rpm/deb文件 + // 处理license文件 if len(licFile) > 0 { file := licFile[0] // 打开文件 @@ -279,39 +296,213 @@ func UploadLicenseFileData(w http.ResponseWriter, r *http.Request) { 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 - } - } + /* + // judge license if expired + isRestart := false + hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) + requestURI2NF := fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", + hostUri, neTypeLower) + log.Debug("requestURI2NF:", requestURI2NF) + resp, err := client.R(). + EnableTrace(). + SetHeaders(map[string]string{tokenConst.HEADER_KEY: r.Header.Get(tokenConst.HEADER_KEY)}). + //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("Failed to get system state:", err) + isRestart = true + } else { + systemState := make(map[string]interface{}) + _ = json.Unmarshal(resp.Body(), &systemState) + expiryDate := fmt.Sprintf("%v", systemState["expiryDate"]) + t1_expiry, _ := time.ParseInLocation(time.DateOnly, expiryDate, time.Local) + nowDate := time.Now().Local() + nowDate.Format(time.DateOnly) + isRestart = t1_expiry.Before(nowDate) + } + // case non-expired license: send NE reload license MML + if !isRestart { + // send reload license MML + var buf [20 * 1024]byte + //buf := make([]byte, 0) + var n int + if neInfo != nil { + switch strings.ToLower(neType) { + case "ims": + 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) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + defer conn.Close() + + conn.SetDeadline(time.Now().Add(TIME_DEAD_LINE * time.Second)) + + _, err = conn.Write([]byte(config.GetYamlConfig().MML.User + "\r\n")) + if err != nil { + log.Error("Failed to write:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) + + n, err = conn.Read(buf[0:]) + if err != nil { + log.Error("Failed to read:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + log.Trace(string(buf[0:n])) + + _, err = conn.Write([]byte(config.GetYamlConfig().MML.Password + "\r\n")) + if err != nil { + log.Error("Failed to write:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) + + n, err = conn.Read(buf[0:]) + if err != nil { + log.Error("Failed to read:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + log.Trace(string(buf[0 : n-len(neType)-2])) + + mmlCommand := "check lic\r\n" + + _, err = conn.Write([]byte(mmlCommand)) + if err != nil { + log.Error("Failed to write:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) + + n, err = conn.Read(buf[0:]) + if err != nil { + log.Error("Failed to read:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + log.Trace(string(buf[0 : n-len(neType)-2])) + + re1 := regexp.MustCompile(`\x1B\[[0-9;]*[a-zA-Z]`) // 匹配包含␛的控制字符 + //re2 := regexp.MustCompile(`\x00`) // 匹配空字符 + re2 := regexp.MustCompile(`[\x00-\x08\x0B\x0C\x0E-\x1F\x7F\x1B]`) // 匹配空字符和包含␛的控制字符 + //re := regexp.MustCompile(`[\x00-\x1F\x7F]`) + // upf telnet buffer只能读取一次,需要去掉前面的多余字符 + result := re1.ReplaceAllString(string(buf[0:n-len(neType)-2]), "") + result = re2.ReplaceAllString(result, "") + if !strings.Contains(result, "COMMAND OK") { + err = fmt.Errorf("failed to check license, %s", result) + log.Error(err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + default: + 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) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + defer conn.Close() + + conn.SetDeadline(time.Now().Add(TIME_DEAD_LINE * time.Second)) + loginStr := fmt.Sprintf("%s\n%s\n", config.GetYamlConfig().MML.User, config.GetYamlConfig().MML.Password) + _, err = conn.Write([]byte(loginStr)) + if err != nil { + log.Error("Failed to write:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + + time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) + + n, err = conn.Read(buf[0:]) + if err != nil { + log.Error("Failed to read:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + log.Trace(string(buf[0:n])) + + mmlCommand := "check lic\n" + _, err = conn.Write([]byte(mmlCommand)) + if err != nil { + log.Error("Failed to write:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) + + n, err = conn.Read(buf[0:]) + if err != nil { + log.Error("Failed to read:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + log.Trace(string(buf[0 : n-len(neType)-2])) + re1 := regexp.MustCompile(`\x1B\[[0-9;]*[a-zA-Z]`) // 匹配包含␛的控制字符 + //re2 := regexp.MustCompile(`\x00`) // 匹配空字符 + re2 := regexp.MustCompile(`[\x00-\x08\x0B\x0C\x0E-\x1F\x7F\x1B]`) // 匹配空字符和包含␛的控制字符 + //re := regexp.MustCompile(`[\x00-\x1F\x7F]`) + result := re1.ReplaceAllString(string(buf[0:n-len(neType)-2]), "") + result = re2.ReplaceAllString(result, "") + if !strings.Contains(result, "COMMAND OK") { + err = fmt.Errorf("failed to check license, %s", result) + log.Error(err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + } + } + } else { + // case expired license: restart NE service + 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,