package cm import ( "fmt" "io" "net/http" "os" "os/exec" "strings" "be.ems/lib/dborm" "be.ems/lib/log" "be.ems/lib/services" "be.ems/restagent/config" "github.com/gorilla/mux" ) var ( // General License URI UriLicense = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/{elementTypeValue}/license" UriLicenseExt = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/license" CustomUriLicense = config.UriPrefix + "/systemManagement/{apiVersion}/{elementTypeValue}/license" CustomUriLicenseExt = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/license" ) func UploadLicenseFile(w http.ResponseWriter, r *http.Request) { log.Debug("UploadLicenseFile 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) services.ResponseStatusOK204NoContent(w) } func DownloadLicenseFile(w http.ResponseWriter, r *http.Request) { log.Debug("DownloadLicenseFile 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) } func DeleteLcenseFile(w http.ResponseWriter, r *http.Request) { log.Debug("DeleteLcenseFile 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) } // 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... ") // _, 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 // 处理license文件 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 test -f %s/system.ini && cp -f %s/system.ini %s/system.ini.bak||echo 0", neLicensePath, neLicensePath, neLicensePath) cmd = exec.Command("ssh", sshHost, cpCmd) out, err = cmd.CombinedOutput() log.Debugf("Exec output: %v", string(out)) if err != nil { log.Errorf("Faile to execute cp command:%v, cmd:%s", err, cpCmd) services.ResponseInternalServerError500ProcessError(w, err) return } // replace system.ini neFilePath := config.GetYamlConfig().NE.ScpDir + "/" + licenseFileName cpCmd = fmt.Sprintf("sudo mv -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 } /* // 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, 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) }