From 08a908c3f4e797e1a343d77c788f1c2789972009 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Thu, 26 Oct 2023 09:33:51 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=90=88=E5=B9=B6=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- features/fm/alarm.go | 47 ++++-- features/trace/tcpdump.go | 8 +- lib/global/exec_linux.go | 47 ++++++ lib/global/exec_windows.go | 34 ++++ src/app.go | 2 + src/framework/cron/cron.go | 15 +- src/framework/cron/cron_test.go | 12 +- src/framework/cron/log.go | 121 +++++++++------ src/framework/utils/token/token.go | 4 + src/modules/common/common.go | 3 +- src/modules/common/controller/account.go | 7 +- src/modules/common/controller/common.go | 19 ++- src/modules/common/controller/register.go | 20 ++- src/modules/common/service/account.go | 3 + src/modules/common/service/account.impl.go | 14 ++ src/modules/common/service/commont.go | 7 + src/modules/common/service/commont.impl.go | 45 ++++++ src/modules/common/service/register.go | 2 +- src/modules/common/service/register.impl.go | 15 +- .../backupEtcFromNE/backupEtcFromNE.go | 145 ++++++++++++++++++ src/modules/crontask/crontask.go | 28 ++++ .../delExpiredNeBackup/delExpiredNeBackup.go | 80 ++++++++++ .../deleteExpiredRecord.go | 88 +++++++++++ src/modules/monitor/controller/system_info.go | 1 - src/modules/monitor/model/sys_job.go | 2 + src/modules/monitor/processor/bar/bar.go | 5 +- src/modules/monitor/processor/foo/foo.go | 5 +- .../monitor/processor/simple/simple.go | 5 +- .../monitor/repository/sys_job.impl.go | 9 +- src/modules/monitor/service/system_info.go | 3 - .../monitor/service/system_info.impl.go | 105 +++---------- src/modules/system/controller/sys_config.go | 35 +++++ src/modules/system/controller/sys_user.go | 20 ++- src/modules/system/service/sys_config.go | 3 + src/modules/system/service/sys_config.impl.go | 11 ++ src/modules/system/service/sys_log_login.go | 4 +- .../system/service/sys_log_login.impl.go | 4 +- src/modules/system/system.go | 5 + 38 files changed, 780 insertions(+), 203 deletions(-) create mode 100644 lib/global/exec_linux.go create mode 100644 lib/global/exec_windows.go create mode 100644 src/modules/common/service/commont.go create mode 100644 src/modules/common/service/commont.impl.go create mode 100644 src/modules/crontask/backupEtcFromNE/backupEtcFromNE.go create mode 100644 src/modules/crontask/crontask.go create mode 100644 src/modules/crontask/delExpiredNeBackup/delExpiredNeBackup.go create mode 100644 src/modules/crontask/deleteExpiredRecord/deleteExpiredRecord.go diff --git a/features/fm/alarm.go b/features/fm/alarm.go index 6a317fa..298d3e3 100644 --- a/features/fm/alarm.go +++ b/features/fm/alarm.go @@ -455,13 +455,23 @@ func GetAlarmFromNF(w http.ResponseWriter, r *http.Request) { log.Error("Request error:", err) return } + vars := mux.Vars(r) + neType := vars["elementTypeValue"] + neTypeLower := strings.ToLower(neType) + + // Get alarms from OMC return 204 + if neTypeLower == strings.ToLower(config.GetYamlConfig().OMC.NeType) { + log.Infof("Return no content alarms from %s", neType) + services.ResponseStatusOK204NoContent(w) + return + } //var neInfo *dborm.NeInfo var nes []dborm.NeInfo _, err = dborm.XormGetAllNeInfo(&nes) if err != nil { log.Error("Failed to get all ne info:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) + services.ResponseInternalServerError500ProcessError(w, err) return } @@ -481,15 +491,24 @@ func GetAlarmFromNF(w http.ResponseWriter, r *http.Request) { //services.ResponseInternalServerError500ProcessError(w, err) continue } - body := response.Body() - log.Debug("Request body:", string(body)) + alarmArray := new([]Alarm) - err = json.Unmarshal(body, &alarmArray) - if err != nil { - log.Error("Failed to Unmarshal:", err) - //services.ResponseInternalServerError500ProcessError(w, err) + switch response.StatusCode() { + case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted: + body := response.Body() + log.Debug("Request body:", string(body)) + + err = json.Unmarshal(body, &alarmArray) + if err != nil { + log.Error("Failed to Unmarshal:", err) + //services.ResponseInternalServerError500ProcessError(w, err) + continue + } + default: + log.Error("Failed to get alarms:", response.Status) continue } + valueJson, err := dborm.XormGetAAConfig() if err != nil { log.Error("Failed to XormGetAAConfig:", err) @@ -514,7 +533,7 @@ func GetAlarmFromNF(w http.ResponseWriter, r *http.Request) { exist, err := session.Table("alarm"). Where("ne_type=? and ne_id=? and alarm_id=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.AlarmId). Exist() - if err == nil || exist == false { + if err == nil || !exist { log.Info("Not found active alarm: ne_id=%s, alarm_id=%s", alarmData.NeId, alarmData.AlarmId) continue } @@ -523,7 +542,7 @@ func GetAlarmFromNF(w http.ResponseWriter, r *http.Request) { tm, _ := time.Parse(time.RFC3339, alarmData.EventTime) log.Debugf("EventTime:%s tm:%d tm-datetime:%s", alarmData.EventTime, tm, tm.Local().Format(time.DateTime)) alarmData.ClearTime.Time = tm - if IsNeedToAckAlarm(valueJson, &alarmData) == true { + if IsNeedToAckAlarm(valueJson, &alarmData) { SetAlarmAckInfo(valueJson, &alarmData) log.Debug("alarmData:", alarmData) affected, err := session. @@ -578,7 +597,7 @@ func GetAlarmFromNF(w http.ResponseWriter, r *http.Request) { } log.Debugf("neType=%s, neId=%s, eventTime=%s, severity=%s", alarmData.NeType, alarmData.NeId, alarmData.EventTime, severity) - if has == true && severity > alarmData.OrigSeverity { + if has && severity > alarmData.OrigSeverity { // update exist record _, err := session.Table("alarm"). Where("ne_type=? and ne_id=? and event_time=?", alarmData.NeType, alarmData.NeId, alarmData.EventTime). @@ -597,7 +616,7 @@ func GetAlarmFromNF(w http.ResponseWriter, r *http.Request) { Where("alarm_id=? and ne_type=? and ne_id=? and alarm_status=1", alarmData.AlarmId, alarmData.NeType, alarmData.NeId). Exist() - if err == nil && has == true { + if err == nil && has { log.Warn("Exist the same alarm") continue } @@ -617,7 +636,7 @@ func GetAlarmFromNF(w http.ResponseWriter, r *http.Request) { log.Debugf("neType=%s, neId=%s, currentSeq=%s, activeAlarmNum=%d", alarmData.NeType, alarmData.NeId, currentSeq, activeAlarmNum) - if has == true { + if has { seq, _ := strconv.Atoi(currentSeq) alarmData.AlarmSeq = seq + 1 if alarmData.AlarmSeq > global.MaxInt32Number { @@ -642,7 +661,7 @@ func GetAlarmFromNF(w http.ResponseWriter, r *http.Request) { } log.Debugf("neType=%s, neId=%s, eventTime=%s, severity=%s", alarmData.NeType, alarmData.NeId, alarmData.EventTime, severity) - if has == false || severity == alarmData.OrigSeverity { + if !has || severity == alarmData.OrigSeverity { alarmData.PerceivedSeverity = alarmData.OrigSeverity } else if severity > alarmData.OrigSeverity { alarmData.PerceivedSeverity = alarmData.OrigSeverity @@ -661,7 +680,7 @@ func GetAlarmFromNF(w http.ResponseWriter, r *http.Request) { alarmData.ObjectUid = alarmData.NeId alarmData.ObjectType = "VNFM" alarmData.EventTime = global.GetFmtTimeString(time.RFC3339, alarmData.EventTime, time.DateTime) - if IsNeedToAckAlarm(valueJson, &alarmData) == true { + if IsNeedToAckAlarm(valueJson, &alarmData) { SetAlarmAckInfo(valueJson, &alarmData) } log.Trace("alarmData:", alarmData) diff --git a/features/trace/tcpdump.go b/features/trace/tcpdump.go index 5f13fca..06bc9f5 100644 --- a/features/trace/tcpdump.go +++ b/features/trace/tcpdump.go @@ -272,12 +272,12 @@ func TcpdumpNeUPFTask(w http.ResponseWriter, r *http.Request) { if body.RunType == "start_str" { fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId) filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId) - scriptStr := "#!/bin/expect\nset capcmd [lindex $argv 0]\nspawn telnet localhost 5002\nexpect \"upfd1# \"\nsend \"$capcmd\\n\"\nexpect \"upfd1# \"\nsend \"quit\\n\"\nexpect \"eof\"" + scriptStr := "set capcmd [lindex $argv 0]\nspawn telnet localhost 5002\nexpect \"upfd1# \"\nsend \"$capcmd\\n\"\nexpect \"upfd1# \"\nsend \"quit\\n\"\nexpect \"eof\"" writeLog := fmt.Sprintf(" > %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件输出,避免弹出code 127 capCmdStr := fmt.Sprintf("%s file %s", body.Cmd, filePcapName) - cmdStr := fmt.Sprintf("cd /tmp\n\necho '%s' > cap.sh\n\nchmod +x cap.sh\n\n./cap.sh '%s'%s", scriptStr, capCmdStr, writeLog) + cmdStr := fmt.Sprintf("cd /tmp\n\necho '%s' > cap.sh\n\nchmod +x cap.sh\n\nexpect ./cap.sh '%s'%s", scriptStr, capCmdStr, writeLog) usernameNe := conf.Get("ne.user").(string) // 网元统一用户 sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip) msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr) @@ -303,12 +303,12 @@ func TcpdumpNeUPFTask(w http.ResponseWriter, r *http.Request) { if body.RunType == "stop_str" { fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId) filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId) - scriptStr := "#!/bin/expect\nset capcmd [lindex $argv 0]\nspawn telnet localhost 5002\nexpect \"upfd1# \"\nsend \"$capcmd\\n\"\nexpect \"upfd1# \"\nsend \"quit\\n\"\nexpect \"eof\"" + scriptStr := "set capcmd [lindex $argv 0]\nspawn telnet localhost 5002\nexpect \"upfd1# \"\nsend \"$capcmd\\n\"\nexpect \"upfd1# \"\nsend \"quit\\n\"\nexpect \"eof\"" writeLog := fmt.Sprintf(" > %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件输出,避免弹出code 127 capCmdStr := body.Cmd - cmdStr := fmt.Sprintf("cd /tmp\n\necho '%s' > cap.sh\n\nchmod +x cap.sh\n\n./cap.sh '%s'%s", scriptStr, capCmdStr, writeLog) + cmdStr := fmt.Sprintf("cd /tmp\n\necho '%s' > cap.sh\n\nchmod +x cap.sh\n\nexpect ./cap.sh '%s'%s", scriptStr, capCmdStr, writeLog) usernameNe := conf.Get("ne.user").(string) // 网元统一用户 sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip) diff --git a/lib/global/exec_linux.go b/lib/global/exec_linux.go new file mode 100644 index 0000000..e4aa858 --- /dev/null +++ b/lib/global/exec_linux.go @@ -0,0 +1,47 @@ +//go:build linux +// +build linux + +package global + +import ( + "bytes" + "os/exec" +) + +func ExecCmd(command string) ([]byte, error) { + cmd := exec.Command("/bin/bash", "-c", command) + out, err := cmd.CombinedOutput() + if err != nil { + return nil, err + } + + return out, nil +} + +func ExecShell(command string) error { + in := bytes.NewBuffer(nil) + cmd := exec.Command("sh") + cmd.Stdin = in + in.WriteString(command) + in.WriteString("exit\n") + if err := cmd.Start(); err != nil { + return err + } + return nil +} + +func ExecOsCmd(command, os string) ([]byte, error) { + var cmd *exec.Cmd + switch os { + case "Linux": + cmd = exec.Command(command) + case "Windows": + cmd = exec.Command("cmd", "/C", command) + } + + out, err := cmd.CombinedOutput() + if err != nil { + return nil, err + } + return out, nil +} diff --git a/lib/global/exec_windows.go b/lib/global/exec_windows.go new file mode 100644 index 0000000..285005c --- /dev/null +++ b/lib/global/exec_windows.go @@ -0,0 +1,34 @@ +//go:build windows +// +build windows + +package global + +import ( + "os/exec" +) + +func ExecCmd(command string) ([]byte, error) { + cmd := exec.Command("cmd", "/C", command) + out, err := cmd.CombinedOutput() + if err != nil { + return nil, err + } + + return out, nil +} + +func ExecOsCmd(command, os string) ([]byte, error) { + var cmd *exec.Cmd + switch os { + case "Linux": + cmd = exec.Command(command) + case "Windows": + cmd = exec.Command("cmd", "/C", command) + } + + out, err := cmd.CombinedOutput() + if err != nil { + return nil, err + } + return out, nil +} diff --git a/src/app.go b/src/app.go index c9ef209..2e7260c 100644 --- a/src/app.go +++ b/src/app.go @@ -8,6 +8,7 @@ import ( "ems.agt/src/framework/middleware" "ems.agt/src/framework/middleware/security" "ems.agt/src/modules/common" + "ems.agt/src/modules/crontask" "ems.agt/src/modules/monitor" "ems.agt/src/modules/system" @@ -116,4 +117,5 @@ func initModulesRoute(app *gin.Engine) { common.Setup(app) monitor.Setup(app) system.Setup(app) + crontask.Setup(app) } diff --git a/src/framework/cron/cron.go b/src/framework/cron/cron.go index ac14b05..e835d37 100644 --- a/src/framework/cron/cron.go +++ b/src/framework/cron/cron.go @@ -63,7 +63,9 @@ type Queue struct { // QueueProcessor 队列处理函数接口 type QueueProcessor interface { // Execute 实际执行函数 - Execute(data any) any + // any 返回有效值最终序列化为字符串,记录为成功 + // error 存在错误,记录为失败 + Execute(data any) (any, error) } // RunJob 运行任务,data是传入的数据 @@ -196,7 +198,12 @@ func (s QueueJob) Run() { // 获取队列处理器接口实现 processor := *job.queueProcessor - result := processor.Execute(job.Data) - job.Status = Completed - newLog.Completed(result, "completed", job) + result, err := processor.Execute(job.Data) + if err != nil { + job.Status = Failed + newLog.Error(err, "failed", job) + } else { + job.Status = Completed + newLog.Completed(result, "completed", job) + } } diff --git a/src/framework/cron/cron_test.go b/src/framework/cron/cron_test.go index cb8f777..207cfe1 100644 --- a/src/framework/cron/cron_test.go +++ b/src/framework/cron/cron_test.go @@ -19,10 +19,10 @@ var NewSimple = &Simple{} type Simple struct{} -func (s *Simple) Execute(data any) any { +func (s *Simple) Execute(data any) (any, error) { logger.Infof("执行=> %+v ", data) // 实现任务处理逻辑 - return data + return data, nil } func TestSimple(t *testing.T) { @@ -68,7 +68,7 @@ type FooProcessor struct { count int } -func (s *FooProcessor) Execute(data any) any { +func (s *FooProcessor) Execute(data any) (any, error) { logger.Infof("执行 %d %d => %+v ", s.count, s.progress, data) s.count++ @@ -85,7 +85,7 @@ func (s *FooProcessor) Execute(data any) any { // 改变任务进度 s.progress = i } - return data + return data, nil } func TestFoo(t *testing.T) { @@ -119,7 +119,7 @@ type BarProcessor struct { count int } -func (s *BarProcessor) Execute(data any) any { +func (s *BarProcessor) Execute(data any) (any, error) { logger.Infof("执行 %d %d => %+v ", s.count, s.progress, data) s.count++ @@ -145,7 +145,7 @@ func (s *BarProcessor) Execute(data any) any { s.progress = i } - return data + return data, nil } func TestBar(t *testing.T) { diff --git a/src/framework/cron/log.go b/src/framework/cron/log.go index 0657ab4..b233fed 100644 --- a/src/framework/cron/log.go +++ b/src/framework/cron/log.go @@ -31,33 +31,16 @@ func (s cronlog) Error(err error, msg string, keysAndValues ...any) { // 任务对象 job := keysAndValues[0].(*QueueJob) - // 结果信息序列化字符串 - jsonByte, _ := json.Marshal(map[string]any{ - "name": "failed", - "message": err.Error(), - }) - jobMsg := string(jsonByte) - if len(jobMsg) > 500 { - jobMsg = jobMsg[:500] - } - - // 读取任务信息创建日志对象 + // 读取任务信息进行保存日志 if data, ok := job.Data.(JobData); ok { - duration := time.Since(time.UnixMilli(job.Timestamp)) - sysJob := data.SysJob - if sysJob.JobID == job.Opts.JobId { - sysJobLog := model.SysJobLog{ - JobName: sysJob.JobName, - JobGroup: sysJob.JobGroup, - InvokeTarget: sysJob.InvokeTarget, - TargetParams: sysJob.TargetParams, - Status: common.STATUS_NO, - JobMsg: jobMsg, - CostTime: duration.Milliseconds(), - } - // 插入数据 - repository.NewSysJobLogImpl.InsertJobLog(sysJobLog) + // 日志数据 + jobLog := jobLogData{ + JobID: job.Opts.JobId, + Timestamp: job.Timestamp, + Data: data, + Result: err.Error(), } + jobLog.SaveLog(common.STATUS_NO) } } } @@ -72,37 +55,75 @@ func (s cronlog) Completed(result any, msg string, keysAndValues ...any) { // 任务对象 job := keysAndValues[0].(*QueueJob) - // 结果信息序列化字符串 - jsonByte, _ := json.Marshal(map[string]any{ - "name": "completed", - "message": result, - }) - jobMsg := string(jsonByte) - if len(jobMsg) > 500 { - jobMsg = jobMsg[:500] - } - - // 读取任务信息创建日志对象 + // 读取任务信息进行保存日志 if data, ok := job.Data.(JobData); ok { - duration := time.Since(time.UnixMilli(job.Timestamp)) - sysJob := data.SysJob - if sysJob.JobID == job.Opts.JobId { - sysJobLog := model.SysJobLog{ - JobName: sysJob.JobName, - JobGroup: sysJob.JobGroup, - InvokeTarget: sysJob.InvokeTarget, - TargetParams: sysJob.TargetParams, - Status: common.STATUS_YES, - JobMsg: jobMsg, - CostTime: duration.Milliseconds(), - } - // 插入数据 - repository.NewSysJobLogImpl.InsertJobLog(sysJobLog) + // 日志数据 + jobLog := jobLogData{ + JobID: job.Opts.JobId, + Timestamp: job.Timestamp, + Data: data, + Result: result, } + jobLog.SaveLog(common.STATUS_YES) } } } +// jobLogData 日志记录数据 +type jobLogData struct { + JobID string + Timestamp int64 + Data JobData + Result any +} + +// SaveLog 日志记录保存 +func (jl *jobLogData) SaveLog(status string) { + // 读取任务信息 + sysJob := jl.Data.SysJob + + // 任务ID与任务信息ID不相同 + if jl.JobID == "" || jl.JobID != sysJob.JobID { + return + } + + // 任务日志不需要记录 + if sysJob.SaveLog == "" || sysJob.SaveLog == common.STATUS_NO { + return + } + + // 结果信息key的Name + resultNmae := "failed" + if status == common.STATUS_YES { + resultNmae = "completed" + } + + // 结果信息序列化字符串 + jsonByte, _ := json.Marshal(map[string]any{ + "name": resultNmae, + "crom": jl.Data.Repeat, + "message": jl.Result, + }) + jobMsg := string(jsonByte) + if len(jobMsg) > 500 { + jobMsg = jobMsg[:500] + } + + // 创建日志对象 + duration := time.Since(time.UnixMilli(jl.Timestamp)) + sysJobLog := model.SysJobLog{ + JobName: sysJob.JobName, + JobGroup: sysJob.JobGroup, + InvokeTarget: sysJob.InvokeTarget, + TargetParams: sysJob.TargetParams, + Status: status, + JobMsg: jobMsg, + CostTime: duration.Milliseconds(), + } + // 插入数据 + repository.NewSysJobLogImpl.InsertJobLog(sysJobLog) +} + // JobData 调度任务日志收集结构体,执行任务时传入的接收参数 type JobData struct { // 触发执行cron重复多次 diff --git a/src/framework/utils/token/token.go b/src/framework/utils/token/token.go index b28462e..5d93761 100644 --- a/src/framework/utils/token/token.go +++ b/src/framework/utils/token/token.go @@ -47,6 +47,10 @@ func Create(loginUser *vo.LoginUser, ilobArgs ...string) string { // 设置用户令牌有效期并存入缓存 Cache(loginUser) + // 设置登录IP和登录时间 + loginUser.User.LoginIP = loginUser.IPAddr + loginUser.User.LoginDate = loginUser.LoginTime + // 令牌算法 HS256 HS384 HS512 algorithm := config.Get("jwt.algorithm").(string) var method *jwt.SigningMethodHMAC diff --git a/src/modules/common/common.go b/src/modules/common/common.go index a809084..13f0b9c 100644 --- a/src/modules/common/common.go +++ b/src/modules/common/common.go @@ -63,7 +63,7 @@ func Setup(router *gin.Engine) { Count: 10, Type: middleware.LIMIT_IP, }), - controller.NewRegister.UserName, + controller.NewRegister.Register, ) } @@ -71,6 +71,7 @@ func Setup(router *gin.Engine) { commonGroup := router.Group("/common") { commonGroup.GET("/hash", middleware.PreAuthorize(nil), controller.NewCommont.Hash) + indexGroup.GET("/sysConf", controller.NewCommont.SysConfig) } // 文件操作处理 diff --git a/src/modules/common/controller/account.go b/src/modules/common/controller/account.go index 02e690d..692dd1c 100644 --- a/src/modules/common/controller/account.go +++ b/src/modules/common/controller/account.go @@ -52,7 +52,7 @@ func (s *AccountController) Login(c *gin.Context) { // 根据错误信息,创建系统访问记录 if err != nil { msg := err.Error() + " " + loginBody.Code - s.sysLogLoginService.NewSysLogLogin( + s.sysLogLoginService.CreateSysLogLogin( loginBody.Username, commonConstants.STATUS_NO, msg, ipaddr, location, os, browser, ) @@ -73,7 +73,8 @@ func (s *AccountController) Login(c *gin.Context) { c.JSON(200, result.Err(nil)) return } else { - s.sysLogLoginService.NewSysLogLogin( + s.accountService.UpdateLoginDateAndIP(&loginUser) + s.sysLogLoginService.CreateSysLogLogin( loginBody.Username, commonConstants.STATUS_YES, "登录成功", ipaddr, location, os, browser, ) @@ -133,7 +134,7 @@ func (s *AccountController) Logout(c *gin.Context) { ipaddr, location := ctxUtils.IPAddrLocation(c) os, browser := ctxUtils.UaOsBrowser(c) // 创建系统访问记录 - s.sysLogLoginService.NewSysLogLogin( + s.sysLogLoginService.CreateSysLogLogin( userName, commonConstants.STATUS_YES, "退出成功", ipaddr, location, os, browser, ) diff --git a/src/modules/common/controller/common.go b/src/modules/common/controller/common.go index b3c2708..0e677f8 100644 --- a/src/modules/common/controller/common.go +++ b/src/modules/common/controller/common.go @@ -1,16 +1,23 @@ package controller import ( + "ems.agt/src/framework/vo/result" + commonService "ems.agt/src/modules/common/service" "github.com/gin-gonic/gin" ) // 实例化控制层 CommontController 结构体 -var NewCommont = &CommontController{} +var NewCommont = &CommontController{ + commontService: commonService.NewCommontImpl, +} // 通用请求 // // PATH / -type CommontController struct{} +type CommontController struct { + // 通用请求服务 + commontService commonService.ICommont +} // 哈希加密 // @@ -18,3 +25,11 @@ type CommontController struct{} func (s *CommontController) Hash(c *gin.Context) { c.String(200, "commont Hash") } + +// 系统可暴露的配置信息 +// +// GET /sysConf +func (s *CommontController) SysConfig(c *gin.Context) { + data := s.commontService.SystemConfigInfo() + c.JSON(200, result.OkData(data)) +} diff --git a/src/modules/common/controller/register.go b/src/modules/common/controller/register.go index 2b3e945..3e177e0 100644 --- a/src/modules/common/controller/register.go +++ b/src/modules/common/controller/register.go @@ -1,8 +1,6 @@ package controller import ( - "strings" - commonConstants "ems.agt/src/framework/constants/common" ctxUtils "ems.agt/src/framework/utils/ctx" "ems.agt/src/framework/utils/regular" @@ -32,8 +30,8 @@ type RegisterController struct { // 账号注册 // -// GET /captchaImage -func (s *RegisterController) UserName(c *gin.Context) { +// GET /register +func (s *RegisterController) Register(c *gin.Context) { var registerBody commonModel.RegisterBody if err := c.ShouldBindJSON(®isterBody); err != nil { c.JSON(400, result.ErrMsg("参数错误")) @@ -66,7 +64,7 @@ func (s *RegisterController) UserName(c *gin.Context) { // 根据错误信息,创建系统访问记录 if err != nil { msg := err.Error() + " " + registerBody.Code - s.sysLogLoginService.NewSysLogLogin( + s.sysLogLoginService.CreateSysLogLogin( registerBody.Username, commonConstants.STATUS_NO, msg, ipaddr, location, os, browser, ) @@ -74,15 +72,15 @@ func (s *RegisterController) UserName(c *gin.Context) { return } - infoStr := s.registerService.ByUserName(registerBody.Username, registerBody.Password, registerBody.UserType) - if !strings.HasPrefix(infoStr, "注册") { - msg := registerBody.Username + " 注册成功 " + infoStr - s.sysLogLoginService.NewSysLogLogin( - registerBody.Username, commonConstants.STATUS_NO, msg, + userID, err := s.registerService.ByUserName(registerBody.Username, registerBody.Password, registerBody.UserType) + if err == nil { + msg := registerBody.Username + " 注册成功 " + userID + s.sysLogLoginService.CreateSysLogLogin( + registerBody.Username, commonConstants.STATUS_YES, msg, ipaddr, location, os, browser, ) c.JSON(200, result.OkMsg("注册成功")) return } - c.JSON(200, result.ErrMsg(infoStr)) + c.JSON(200, result.ErrMsg(err.Error())) } diff --git a/src/modules/common/service/account.go b/src/modules/common/service/account.go index 5f8c42f..7a98a24 100644 --- a/src/modules/common/service/account.go +++ b/src/modules/common/service/account.go @@ -10,6 +10,9 @@ type IAccount interface { // LoginByUsername 登录生成token LoginByUsername(username, password string) (vo.LoginUser, error) + // UpdateLoginDateAndIP 更新登录时间和IP + UpdateLoginDateAndIP(loginUser *vo.LoginUser) bool + // ClearLoginRecordCache 清除错误记录次数 ClearLoginRecordCache(username string) bool diff --git a/src/modules/common/service/account.impl.go b/src/modules/common/service/account.impl.go index a598a83..44089df 100644 --- a/src/modules/common/service/account.impl.go +++ b/src/modules/common/service/account.impl.go @@ -13,6 +13,7 @@ import ( "ems.agt/src/framework/utils/crypto" "ems.agt/src/framework/utils/parse" "ems.agt/src/framework/vo" + "ems.agt/src/modules/system/model" systemService "ems.agt/src/modules/system/service" ) @@ -105,6 +106,19 @@ func (s *AccountImpl) LoginByUsername(username, password string) (vo.LoginUser, return loginUser, nil } +// UpdateLoginDateAndIP 更新登录时间和IP +func (s *AccountImpl) UpdateLoginDateAndIP(loginUser *vo.LoginUser) bool { + sysUser := loginUser.User + userInfo := model.SysUser{ + UserID: sysUser.UserID, + LoginIP: sysUser.LoginIP, + LoginDate: sysUser.LoginDate, + UpdateBy: sysUser.UserName, + } + rows := s.sysUserService.UpdateUser(userInfo) + return rows > 0 +} + // ClearLoginRecordCache 清除错误记录次数 func (s *AccountImpl) ClearLoginRecordCache(username string) bool { cacheKey := cachekey.PWD_ERR_CNT_KEY + username diff --git a/src/modules/common/service/commont.go b/src/modules/common/service/commont.go new file mode 100644 index 0000000..5dc1e65 --- /dev/null +++ b/src/modules/common/service/commont.go @@ -0,0 +1,7 @@ +package service + +// 通用请求 服务层接口 +type ICommont interface { + // SystemConfigInfo 系统配置信息 + SystemConfigInfo() map[string]any +} diff --git a/src/modules/common/service/commont.impl.go b/src/modules/common/service/commont.impl.go new file mode 100644 index 0000000..4197298 --- /dev/null +++ b/src/modules/common/service/commont.impl.go @@ -0,0 +1,45 @@ +package service + +import ( + systemService "ems.agt/src/modules/system/service" +) + +// 实例化服务层 CommontImpl 结构体 +var NewCommontImpl = &CommontImpl{ + sysUserService: systemService.NewSysUserImpl, + sysConfigService: systemService.NewSysConfigImpl, +} + +// 通用请求 服务层处理 +type CommontImpl struct { + // 用户信息服务 + sysUserService systemService.ISysUser + // 参数配置服务 + sysConfigService systemService.ISysConfig +} + +// SystemConfigInfo 系统配置信息 +func (s *CommontImpl) SystemConfigInfo() map[string]any { + infoMap := map[string]any{} + // 获取LOGO类型 + logoType := s.sysConfigService.SelectConfigValueByKey("sys.logo.type") + infoMap["logoType"] = logoType + // 获取LOGO文件 + filePathIcon := s.sysConfigService.SelectConfigValueByKey("sys.logo.filePathIcon") + infoMap["filePathIcon"] = filePathIcon + filePathBrand := s.sysConfigService.SelectConfigValueByKey("sys.logo.filePathBrand") + infoMap["filePathBrand"] = filePathBrand + // 获取系统名称 + title := s.sysConfigService.SelectConfigValueByKey("sys.title") + infoMap["title"] = title + // 获取版权声明 + copyright := s.sysConfigService.SelectConfigValueByKey("sys.copyright") + infoMap["copyright"] = copyright + // 获取是否开启用户注册功能 + registerUser := s.sysConfigService.SelectConfigValueByKey("sys.account.registerUser") + infoMap["registerUser"] = registerUser + // 获取登录界面背景 + loginBackground := s.sysConfigService.SelectConfigValueByKey("sys.loginBackground") + infoMap["loginBackground"] = loginBackground + return infoMap +} diff --git a/src/modules/common/service/register.go b/src/modules/common/service/register.go index 6570c50..dc98683 100644 --- a/src/modules/common/service/register.go +++ b/src/modules/common/service/register.go @@ -6,5 +6,5 @@ type IRegister interface { ValidateCaptcha(code, uuid string) error // ByUserName 账号注册 - ByUserName(username, password, userType string) string + ByUserName(username, password, userType string) (string, error) } diff --git a/src/modules/common/service/register.impl.go b/src/modules/common/service/register.impl.go index 5d536fc..25f7765 100644 --- a/src/modules/common/service/register.impl.go +++ b/src/modules/common/service/register.impl.go @@ -52,11 +52,18 @@ func (s *RegisterImpl) ValidateCaptcha(code, uuid string) error { } // ByUserName 账号注册 -func (s *RegisterImpl) ByUserName(username, password, userType string) string { +func (s *RegisterImpl) ByUserName(username, password, userType string) (string, error) { + // 是否开启用户注册功能 true开启,false关闭 + registerUserStr := s.sysConfigService.SelectConfigValueByKey("sys.account.registerUser") + captchaEnabled := parse.Boolean(registerUserStr) + if !captchaEnabled { + return "", fmt.Errorf("注册用户【%s】失败,很抱歉,系统已关闭外部用户注册通道", username) + } + // 检查用户登录账号是否唯一 uniqueUserName := s.sysUserService.CheckUniqueUserName(username, "") if !uniqueUserName { - return fmt.Sprintf("注册用户【%s】失败,注册账号已存在", username) + return "", fmt.Errorf("注册用户【%s】失败,注册账号已存在", username) } sysUser := systemModel.SysUser{ @@ -78,9 +85,9 @@ func (s *RegisterImpl) ByUserName(username, password, userType string) string { insertId := s.sysUserService.InsertUser(sysUser) if insertId != "" { - return insertId + return insertId, nil } - return "注册失败,请联系系统管理人员" + return "", fmt.Errorf("注册用户【%s】失败,请联系系统管理人员", username) } // registerRoleInit 注册初始角色 diff --git a/src/modules/crontask/backupEtcFromNE/backupEtcFromNE.go b/src/modules/crontask/backupEtcFromNE/backupEtcFromNE.go new file mode 100644 index 0000000..fe70d4a --- /dev/null +++ b/src/modules/crontask/backupEtcFromNE/backupEtcFromNE.go @@ -0,0 +1,145 @@ +package backupEtcFromNE + +import ( + "encoding/json" + "fmt" + "os" + "strings" + "time" + + "ems.agt/lib/dborm" + "ems.agt/lib/global" + "ems.agt/lib/log" + "ems.agt/restagent/config" + "ems.agt/src/framework/cron" +) + +var NewProcessor = &BarProcessor{ + progress: 0, + count: 0, +} + +// bar 队列任务处理 +type BarProcessor struct { + // 任务进度 + progress int + // 执行次数 + count int +} + +type BarParams struct { + Duration int `json:"duration"` + TableName string `json:"tableName"` + ColName string `json:"colName"` // column name of time string + Extras string `json:"extras"` // extras condition for where +} + +func (s *BarProcessor) Execute(data any) (any, error) { + log.Infof("execute %d,last progress: %d ", s.count, s.progress) + s.count++ + + options := data.(cron.JobData) + sysJob := options.SysJob + var params BarParams + + err := json.Unmarshal([]byte(sysJob.TargetParams), ¶ms) + if err != nil { + return nil, err + } + + log.Infof("Repeat %v Job ID %s", options.Repeat, sysJob.JobID) + + var nes []dborm.NeInfo + _, err = dborm.XormGetAllNeInfo(&nes) + if err != nil { + return nil, err + } + + var successfulNEs, failureNEs []string + for _, neInfo := range nes { + neTypeUpper := strings.ToUpper(neInfo.NeType) + neTypeLower := strings.ToLower(neInfo.NeType) + nePath := fmt.Sprintf("%s/etc/%s", config.GetYamlConfig().OMC.Backup, neTypeLower) + isExist, err := global.PathExists(nePath) + if err != nil { + log.Errorf("Failed to PathExists:", err) + failureNEs = append(failureNEs, neInfo.NeType+"/"+neInfo.NeId) + continue + } + if isExist { + err = os.RemoveAll(nePath) + if err != nil { + log.Errorf("Failed to RemoveAll:", err) + failureNEs = append(failureNEs, neInfo.NeType+"/"+neInfo.NeId) + continue + } + } + err = os.MkdirAll(nePath, os.ModePerm) + if err != nil { + log.Errorf("Failed to MkdirAll:", err) + failureNEs = append(failureNEs, neInfo.NeType+"/"+neInfo.NeId) + continue + } + + var scpCmd string + ipType := global.ParseIPAddr(neInfo.Ip) + if neTypeLower != "omc" { + if ipType == global.IsIPv4 { + scpCmd = fmt.Sprintf("scp -r %s@%s:%s/%s/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User, + neInfo.Ip, config.GetYamlConfig().NE.EtcDir, + neTypeLower, config.GetYamlConfig().OMC.Backup, neTypeLower) + } else { + scpCmd = fmt.Sprintf("scp -r %s@[%s]:%s/%s/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User, + neInfo.Ip, config.GetYamlConfig().NE.EtcDir, + neTypeLower, config.GetYamlConfig().OMC.Backup, neTypeLower) + } + } else { + if ipType == global.IsIPv4 { + scpCmd = fmt.Sprintf("scp -r %s@%s:%s/etc/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User, + neInfo.Ip, config.GetYamlConfig().NE.OmcDir, config.GetYamlConfig().OMC.Backup, neTypeLower) + } else { + scpCmd = fmt.Sprintf("scp -r %s@[%s]:%s/etc/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User, + neInfo.Ip, config.GetYamlConfig().NE.OmcDir, config.GetYamlConfig().OMC.Backup, neTypeLower) + } + } + + zipFile := fmt.Sprintf("%s-%s-etc-%s.zip", neTypeLower, strings.ToLower(neInfo.NeId), time.Now().Format(global.DateData)) + zipFilePath := config.GetYamlConfig().OMC.Backup + "/" + zipFile + zipCmd := fmt.Sprintf("cd %s/etc && zip -r %s %s/*", config.GetYamlConfig().OMC.Backup, zipFilePath, neTypeLower) + + command := fmt.Sprintf("%s&&%s", scpCmd, zipCmd) + + log.Trace("command:", command) + out, err := global.ExecCmd(command) + if err != nil { + log.Error("Faile to exec command:", err) + failureNEs = append(failureNEs, neInfo.NeType+"/"+neInfo.NeId) + continue + } + log.Trace("command output:", out) + + md5Sum, err := global.GetFileMD5Sum(zipFilePath) + if err != nil { + log.Error("Faile to md5sum:", err) + failureNEs = append(failureNEs, neInfo.NeType+"/"+neInfo.NeId) + continue + } + //log.Debug("md5Str:", md5Sum) + path := config.GetYamlConfig().OMC.Backup + neBackup := dborm.NeBackup{NeType: neTypeUpper, NeId: neInfo.NeId, FileName: zipFile, Path: path, Md5Sum: md5Sum} + _, err = dborm.XormInsertTableOne("ne_backup", neBackup) + if err != nil { + log.Error("Faile to XormInsertTableOne:", err) + failureNEs = append(failureNEs, neInfo.NeType+"/"+neInfo.NeId) + continue + } + successfulNEs = append(successfulNEs, neInfo.NeType+"/"+neInfo.NeId) + } + + log.Infof("successfulNEs: %s failureNEs: %s", successfulNEs, failureNEs) + // result + return map[string]any{ + "successfulNEs": successfulNEs, + "failureNEs": failureNEs, + }, nil +} diff --git a/src/modules/crontask/crontask.go b/src/modules/crontask/crontask.go new file mode 100644 index 0000000..4011eca --- /dev/null +++ b/src/modules/crontask/crontask.go @@ -0,0 +1,28 @@ +package crontask + +import ( + "ems.agt/src/framework/cron" + "ems.agt/src/framework/logger" + "ems.agt/src/modules/crontask/backupEtcFromNE" + "ems.agt/src/modules/crontask/delExpiredNeBackup" + "ems.agt/src/modules/crontask/deleteExpiredRecord" + + "github.com/gin-gonic/gin" +) + +// Setup 模块路由注册 +func Setup(router *gin.Engine) { + logger.Infof("开始加载 ====> monitor 模块路由") + + // 启动时需要的初始参数 + InitCronQueue() + +} + +// InitCronQueue 初始定时任务队列 +func InitCronQueue() { + // delete expired NE backup file + cron.CreateQueue("delExpiredNeBackup", delExpiredNeBackup.NewProcessor) + cron.CreateQueue("deleteExpiredRecord", deleteExpiredRecord.NewProcessor) + cron.CreateQueue("backupEtcFromNE", backupEtcFromNE.NewProcessor) +} diff --git a/src/modules/crontask/delExpiredNeBackup/delExpiredNeBackup.go b/src/modules/crontask/delExpiredNeBackup/delExpiredNeBackup.go new file mode 100644 index 0000000..641641b --- /dev/null +++ b/src/modules/crontask/delExpiredNeBackup/delExpiredNeBackup.go @@ -0,0 +1,80 @@ +package delExpiredNeBackup + +import ( + "encoding/json" + "fmt" + + "ems.agt/lib/dborm" + "ems.agt/lib/log" + "ems.agt/src/framework/cron" +) + +var NewProcessor = &BarProcessor{ + progress: 0, + count: 0, +} + +// bar 队列任务处理 +type BarProcessor struct { + // 任务进度 + progress int + // 执行次数 + count int +} + +type BarParams struct { + Duration int `json:"duration"` +} + +func (s *BarProcessor) Execute(data any) (any, error) { + log.Infof("执行 %d 次,上次进度: %d ", s.count, s.progress) + s.count++ + + options := data.(cron.JobData) + sysJob := options.SysJob + var params BarParams + duration := 60 + + err := json.Unmarshal([]byte(sysJob.TargetParams), ¶ms) + if err == nil { + duration = params.Duration + } + log.Infof("重复 %v 任务ID %s", options.Repeat, sysJob.JobID) + + // // 实现任务处理逻辑 + // i := 0 + // s.progress = i + // for i < 5 { + // // 获取任务进度 + // progress := s.progress + // log.Infof("jonId: %s => 任务进度:%d", sysJob.JobID, progress) + // // 延迟响应 + // time.Sleep(time.Second * 2) + // // 程序中途执行错误 + // if i == 3 { + // // arr := [1]int{1} + // // arr[i] = 3 + // // fmt.Println(arr) + // // return "i = 3" + // panic("程序中途执行错误") + // } + // i++ + // // 改变任务进度 + // s.progress = i + // } + where := fmt.Sprintf("NOW()>ADDDATE(`create_time`,interval %d day)", duration) + affected, err := dborm.XormDeleteDataByWhere(where, "ne_backup") + if err != nil { + // panic(fmt.Sprintf("Failed to XormDeleteDataByWhere:%v", err)) + return nil, err + } + + // delete expired files in backup directory + // todo ... + + // 返回结果,用于记录执行结果 + return map[string]any{ + "msg": "sucess", + "affected": affected, + }, nil +} diff --git a/src/modules/crontask/deleteExpiredRecord/deleteExpiredRecord.go b/src/modules/crontask/deleteExpiredRecord/deleteExpiredRecord.go new file mode 100644 index 0000000..8cae446 --- /dev/null +++ b/src/modules/crontask/deleteExpiredRecord/deleteExpiredRecord.go @@ -0,0 +1,88 @@ +package deleteExpiredRecord + +import ( + "encoding/json" + "fmt" + + "ems.agt/lib/dborm" + "ems.agt/lib/log" + "ems.agt/src/framework/cron" +) + +var NewProcessor = &BarProcessor{ + progress: 0, + count: 0, +} + +// bar 队列任务处理 +type BarProcessor struct { + // 任务进度 + progress int + // 执行次数 + count int +} + +type BarParams struct { + Duration int `json:"duration"` + TableName string `json:"tableName"` + ColName string `json:"colName"` // column name of time string + Extras string `json:"extras"` // extras condition for where +} + +func (s *BarProcessor) Execute(data any) (any, error) { + log.Infof("执行 %d 次,上次进度: %d ", s.count, s.progress) + s.count++ + + options := data.(cron.JobData) + sysJob := options.SysJob + var params BarParams + + err := json.Unmarshal([]byte(sysJob.TargetParams), ¶ms) + if err != nil { + return nil, err + } + + //duration = params.Duration + log.Infof("重复 %v 任务ID %s", options.Repeat, sysJob.JobID) + + // // 实现任务处理逻辑 + // i := 0 + // s.progress = i + // for i < 5 { + // // 获取任务进度 + // progress := s.progress + // log.Infof("jonId: %s => 任务进度:%d", sysJob.JobID, progress) + // // 延迟响应 + // time.Sleep(time.Second * 2) + // // 程序中途执行错误 + // if i == 3 { + // // arr := [1]int{1} + // // arr[i] = 3 + // // fmt.Println(arr) + // // return "i = 3" + // panic("程序中途执行错误") + // } + // i++ + // // 改变任务进度 + // s.progress = i + // } + + var where string + if params.Extras == "" { + where = fmt.Sprintf("NOW()>ADDDATE(`%s`,interval %d day)", params.ColName, params.Duration) + } else { + where = fmt.Sprintf("NOW()>ADDDATE(`%s`,interval %d day) and %s", params.ColName, params.Duration, params.Extras) + } + + affected, err := dborm.XormDeleteDataByWhere(where, params.TableName) + if err != nil { + // panic(fmt.Sprintf("Failed to XormDeleteDataByWhere:%v", err)) + return nil, err + } + + // 返回结果,用于记录执行结果 + return map[string]any{ + "msg": "sucess", + "affected": affected, + }, nil +} diff --git a/src/modules/monitor/controller/system_info.go b/src/modules/monitor/controller/system_info.go index 13004e1..a6cb03c 100644 --- a/src/modules/monitor/controller/system_info.go +++ b/src/modules/monitor/controller/system_info.go @@ -25,7 +25,6 @@ type SystemInfoController struct { // GET / func (s *SystemInfoController) Info(c *gin.Context) { c.JSON(200, result.OkData(map[string]any{ - "project": s.systemInfogService.ProjectInfo(), "cpu": s.systemInfogService.CPUInfo(), "memory": s.systemInfogService.MemoryInfo(), "network": s.systemInfogService.NetworkInfo(), diff --git a/src/modules/monitor/model/sys_job.go b/src/modules/monitor/model/sys_job.go index 598f129..a7f910f 100644 --- a/src/modules/monitor/model/sys_job.go +++ b/src/modules/monitor/model/sys_job.go @@ -20,6 +20,8 @@ type SysJob struct { Concurrent string `json:"concurrent"` // 任务状态(0暂停 1正常) Status string `json:"status"` + // 是否记录任务日志 + SaveLog string `json:"saveLog"` // 创建者 CreateBy string `json:"createBy"` // 创建时间 diff --git a/src/modules/monitor/processor/bar/bar.go b/src/modules/monitor/processor/bar/bar.go index ad2ace1..1d96892 100644 --- a/src/modules/monitor/processor/bar/bar.go +++ b/src/modules/monitor/processor/bar/bar.go @@ -20,7 +20,7 @@ type BarProcessor struct { count int } -func (s *BarProcessor) Execute(data any) any { +func (s *BarProcessor) Execute(data any) (any, error) { logger.Infof("执行 %d 次,上次进度: %d ", s.count, s.progress) s.count++ @@ -51,10 +51,11 @@ func (s *BarProcessor) Execute(data any) any { } // 返回结果,用于记录执行结果 - return map[string]any{ + result := map[string]any{ "repeat": options.Repeat, "jobName": sysJob.JobName, "invokeTarget": sysJob.InvokeTarget, "targetParams": sysJob.TargetParams, } + return result, nil } diff --git a/src/modules/monitor/processor/foo/foo.go b/src/modules/monitor/processor/foo/foo.go index ec6d675..21dd527 100644 --- a/src/modules/monitor/processor/foo/foo.go +++ b/src/modules/monitor/processor/foo/foo.go @@ -20,7 +20,7 @@ type FooProcessor struct { count int } -func (s *FooProcessor) Execute(data any) any { +func (s *FooProcessor) Execute(data any) (any, error) { logger.Infof("执行 %d 次,上次进度: %d ", s.count, s.progress) s.count++ @@ -43,10 +43,11 @@ func (s *FooProcessor) Execute(data any) any { } // 返回结果,用于记录执行结果 - return map[string]any{ + result := map[string]any{ "repeat": options.Repeat, "jobName": sysJob.JobName, "invokeTarget": sysJob.InvokeTarget, "targetParams": sysJob.TargetParams, } + return result, nil } diff --git a/src/modules/monitor/processor/simple/simple.go b/src/modules/monitor/processor/simple/simple.go index d033937..1f997bf 100644 --- a/src/modules/monitor/processor/simple/simple.go +++ b/src/modules/monitor/processor/simple/simple.go @@ -10,17 +10,18 @@ var NewProcessor = &simpleProcessor{} // simple 队列任务处理 type simpleProcessor struct{} -func (s *simpleProcessor) Execute(data any) any { +func (s *simpleProcessor) Execute(data any) (any, error) { options := data.(cron.JobData) sysJob := options.SysJob logger.Infof("重复 %v 任务ID %s", options.Repeat, sysJob.JobID) // 返回结果,用于记录执行结果 - return map[string]any{ + result := map[string]any{ "repeat": options.Repeat, "jobName": sysJob.JobName, "invokeTarget": sysJob.InvokeTarget, "targetParams": sysJob.TargetParams, } + return result, nil } diff --git a/src/modules/monitor/repository/sys_job.impl.go b/src/modules/monitor/repository/sys_job.impl.go index 12eceb2..19ab059 100644 --- a/src/modules/monitor/repository/sys_job.impl.go +++ b/src/modules/monitor/repository/sys_job.impl.go @@ -15,7 +15,7 @@ import ( // 实例化数据层 SysJobImpl 结构体 var NewSysJobImpl = &SysJobImpl{ selectSql: `select job_id, job_name, job_group, invoke_target, target_params, cron_expression, - misfire_policy, concurrent, status, create_by, create_time, remark from sys_job`, + misfire_policy, concurrent, status, save_log, create_by, create_time, remark from sys_job`, resultMap: map[string]string{ "job_id": "JobID", @@ -27,6 +27,7 @@ var NewSysJobImpl = &SysJobImpl{ "misfire_policy": "MisfirePolicy", "concurrent": "Concurrent", "status": "Status", + "save_log": "SaveLog", "create_by": "CreateBy", "create_time": "CreateTime", "update_by": "UpdateBy", @@ -245,6 +246,9 @@ func (r *SysJobImpl) InsertJob(sysJob model.SysJob) string { if sysJob.Status != "" { params["status"] = sysJob.Status } + if sysJob.SaveLog != "" { + params["save_log"] = sysJob.SaveLog + } if sysJob.Remark != "" { params["remark"] = sysJob.Remark } @@ -308,6 +312,9 @@ func (r *SysJobImpl) UpdateJob(sysJob model.SysJob) int64 { if sysJob.Status != "" { params["status"] = sysJob.Status } + if sysJob.SaveLog != "" { + params["save_log"] = sysJob.SaveLog + } if sysJob.Remark != "" { params["remark"] = sysJob.Remark } diff --git a/src/modules/monitor/service/system_info.go b/src/modules/monitor/service/system_info.go index e2be65f..a6e9a51 100644 --- a/src/modules/monitor/service/system_info.go +++ b/src/modules/monitor/service/system_info.go @@ -2,9 +2,6 @@ package service // ISystemInfo 服务器系统相关信息 服务层接口 type ISystemInfo interface { - // ProjectInfo 程序项目信息 - ProjectInfo() map[string]any - // SystemInfo 系统信息 SystemInfo() map[string]any diff --git a/src/modules/monitor/service/system_info.impl.go b/src/modules/monitor/service/system_info.impl.go index c6f3f37..597a5ab 100644 --- a/src/modules/monitor/service/system_info.impl.go +++ b/src/modules/monitor/service/system_info.impl.go @@ -1,7 +1,6 @@ package service import ( - "bufio" "fmt" "os" "runtime" @@ -24,105 +23,43 @@ var NewSystemInfoImpl = &SystemInfoImpl{} // SystemInfoImpl 服务器系统相关信息 服务层处理 type SystemInfoImpl struct{} -// ProjectInfo 程序项目信息 -func (s *SystemInfoImpl) ProjectInfo() map[string]any { - // 获取工作目录 - appDir, err := os.Getwd() - if err != nil { - appDir = "" - } - // 项目依赖 - dependencies := s.dependencies() - return map[string]any{ - "appDir": appDir, - "env": config.Env(), - "name": config.Get("framework.name"), - "version": config.Get("framework.version"), - "dependencies": dependencies, - } -} - -// dependencies 读取mod内项目包依赖 -func (s *SystemInfoImpl) dependencies() map[string]string { - var pkgs = make(map[string]string) - - // 打开 go.mod 文件 - file, err := os.Open("go.mod") - if err != nil { - return pkgs - } - defer file.Close() - - // 使用 bufio.Scanner 逐行读取文件内容 - scanner := bufio.NewScanner(file) - for scanner.Scan() { - line := scanner.Text() - line = strings.TrimSpace(line) - - // 行不为空,不以module\require开头,不带有 // indirect 注释,则解析包名和版本 - prefixLine := strings.HasPrefix(line, "module") || strings.HasPrefix(line, "require") || strings.HasPrefix(line, "go ") - suffixLine := strings.HasSuffix(line, ")") || strings.HasSuffix(line, "// indirect") - if line == "" || prefixLine || suffixLine { - continue - } - - modInfo := strings.Split(line, " ") - if len(modInfo) >= 2 { - moduleName := strings.TrimSpace(modInfo[0]) - version := strings.TrimSpace(modInfo[1]) - pkgs[moduleName] = version - } - } - - if err := scanner.Err(); err != nil { - pkgs["scanner-err"] = err.Error() - } - return pkgs -} - // SystemInfo 系统信息 func (s *SystemInfoImpl) SystemInfo() map[string]any { info, err := host.Info() if err != nil { info.Platform = err.Error() } - // 用户目录 - homeDir, err := os.UserHomeDir() - if err != nil { - homeDir = "" - } - cmd, err := os.Executable() - if err != nil { - cmd = "" - } + // 获取主机运行时间 + bootTime := time.Since(time.Unix(int64(info.BootTime), 0)).Seconds() + // 获取程序运行时间 + runTime := time.Since(config.RunTime()).Abs().Seconds() return map[string]any{ - "platform": info.Platform, - "go": runtime.Version(), - "processId": os.Getpid(), - "arch": info.KernelArch, - "uname": runtime.GOARCH, - "release": info.OS, - "hostname": info.Hostname, - "homeDir": homeDir, - "cmd": cmd, - "execCommand": strings.Join(os.Args, " "), + "platform": info.Platform, + "platformVersion": info.PlatformVersion, + "arch": info.KernelArch, + "archVersion": info.KernelVersion, + "os": info.OS, + "hostname": info.Hostname, + "bootTime": int64(bootTime), + "processId": os.Getpid(), + "runArch": runtime.GOARCH, + "runVersion": runtime.Version(), + "runTime": int64(runTime), } } // TimeInfo 系统时间信息 func (s *SystemInfoImpl) TimeInfo() map[string]string { + now := time.Now() // 获取当前时间 - current := time.Now().Format("2006-01-02 15:04:05") - // 获取程序运行时间 - uptime := time.Since(config.RunTime()).String() + current := now.Format("2006-01-02 15:04:05") // 获取时区 - timezone := time.Now().Format("-0700 MST") + timezone := now.Format("-0700 MST") // 获取时区名称 - timezoneName := time.Now().Format("MST") + timezoneName := now.Format("MST") return map[string]string{ "current": current, - "uptime": uptime, "timezone": timezone, "timezoneName": timezoneName, } @@ -153,12 +90,12 @@ func (s *SystemInfoImpl) MemoryInfo() map[string]any { // CPUInfo CPU信息 func (s *SystemInfoImpl) CPUInfo() map[string]any { - var core int32 = 0 + var core int = 0 var speed string = "未知" var model string = "未知" cpuInfo, err := cpu.Info() if err == nil { - core = cpuInfo[0].Cores + core = runtime.NumCPU() speed = fmt.Sprintf("%.0fMHz", cpuInfo[0].Mhz) model = strings.TrimSpace(cpuInfo[0].ModelName) } diff --git a/src/modules/system/controller/sys_config.go b/src/modules/system/controller/sys_config.go index 7350365..75c569d 100644 --- a/src/modules/system/controller/sys_config.go +++ b/src/modules/system/controller/sys_config.go @@ -218,3 +218,38 @@ func (s *SysConfigController) Export(c *gin.Context) { c.FileAttachment(saveFilePath, fileName) } + +// 参数配置修改配置参数 +// +// PUT /changeConfigValue +func (s *SysConfigController) ConfigValue(c *gin.Context) { + var body struct { + Key string `json:"key" binding:"required"` + Value string `json:"value" binding:"required"` + } + if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil { + c.JSON(400, result.CodeMsg(400, "参数错误")) + return + } + + // 检查是否存在 + info := s.sysConfigService.SelectConfigByKey(body.Key) + if info.ConfigKey != body.Key { + c.JSON(200, result.ErrMsg("无效 key")) + return + } + + // 与旧值相等不变更 + if info.ConfigValue == body.Value { + c.JSON(200, result.ErrMsg("变更状态与旧值相等!")) + return + } + info.ConfigValue = body.Value + info.UpdateBy = ctx.LoginUserToUserName(c) + rows := s.sysConfigService.UpdateConfig(info) + if rows > 0 { + c.JSON(200, result.Ok(nil)) + return + } + c.JSON(200, result.Err(nil)) +} diff --git a/src/modules/system/controller/sys_user.go b/src/modules/system/controller/sys_user.go index 220cd2d..138d4cd 100644 --- a/src/modules/system/controller/sys_user.go +++ b/src/modules/system/controller/sys_user.go @@ -132,6 +132,16 @@ func (s *SysUserController) Add(c *gin.Context) { return } + // 密码单独取,避免序列化输出 + var bodyPassword struct { + Password string `json:"password" binding:"required"` + } + if err := c.ShouldBindBodyWith(&bodyPassword, binding.JSON); err != nil { + c.JSON(400, result.CodeMsg(400, "参数错误")) + return + } + body.Password = bodyPassword.Password + // 检查用户登录账号是否唯一 uniqueUserName := s.sysUserService.CheckUniqueUserName(body.UserName, "") if !uniqueUserName { @@ -246,6 +256,8 @@ func (s *SysUserController) Edit(c *gin.Context) { body.UserName = "" // 忽略修改登录用户名称 body.Password = "" // 忽略修改密码 + body.LoginIP = "" // 忽略登录IP + body.LoginDate = 0 // 忽略登录时间 body.UpdateBy = ctx.LoginUserToUserName(c) rows := s.sysUserService.UpdateUserAndRolePost(body) if rows > 0 { @@ -310,12 +322,12 @@ func (s *SysUserController) ResetPwd(c *gin.Context) { } userName := ctx.LoginUserToUserName(c) - SysUserController := model.SysUser{ + info := model.SysUser{ UserID: body.UserID, Password: body.Password, UpdateBy: userName, } - rows := s.sysUserService.UpdateUser(SysUserController) + rows := s.sysUserService.UpdateUser(info) if rows > 0 { c.JSON(200, result.Ok(nil)) return @@ -350,12 +362,12 @@ func (s *SysUserController) Status(c *gin.Context) { } userName := ctx.LoginUserToUserName(c) - SysUserController := model.SysUser{ + info := model.SysUser{ UserID: body.UserID, Status: body.Status, UpdateBy: userName, } - rows := s.sysUserService.UpdateUser(SysUserController) + rows := s.sysUserService.UpdateUser(info) if rows > 0 { c.JSON(200, result.Ok(nil)) return diff --git a/src/modules/system/service/sys_config.go b/src/modules/system/service/sys_config.go index 4ec80db..6e9be4e 100644 --- a/src/modules/system/service/sys_config.go +++ b/src/modules/system/service/sys_config.go @@ -27,4 +27,7 @@ type ISysConfig interface { // ResetConfigCache 重置参数缓存数据 ResetConfigCache() + + // SelectConfigByKey 查询配置信息BY键 + SelectConfigByKey(configKey string) model.SysConfig } diff --git a/src/modules/system/service/sys_config.impl.go b/src/modules/system/service/sys_config.impl.go index c15eea0..2a50cee 100644 --- a/src/modules/system/service/sys_config.impl.go +++ b/src/modules/system/service/sys_config.impl.go @@ -155,3 +155,14 @@ func (r *SysConfigImpl) clearConfigCache(configKey string) bool { delOk, _ := redis.DelKeys("", keys) return delOk } + +// SelectConfigByKey 查询配置信息BY键 +func (r *SysConfigImpl) SelectConfigByKey(configKey string) model.SysConfig { + sysConf := r.sysConfigRepository.SelectConfigList(model.SysConfig{ + ConfigKey: configKey, + }) + if len(sysConf) > 0 { + return sysConf[0] + } + return model.SysConfig{} +} diff --git a/src/modules/system/service/sys_log_login.go b/src/modules/system/service/sys_log_login.go index f2be50d..90d5d11 100644 --- a/src/modules/system/service/sys_log_login.go +++ b/src/modules/system/service/sys_log_login.go @@ -19,6 +19,6 @@ type ISysLogLogin interface { // CleanSysLogLogin 清空系统登录日志 CleanSysLogLogin() error - // NewSysLogLogin 生成系统登录日志 - NewSysLogLogin(userName, status, msg string, ilobArgs ...string) string + // CreateSysLogLogin 创建系统登录日志 + CreateSysLogLogin(userName, status, msg string, ilobArgs ...string) string } diff --git a/src/modules/system/service/sys_log_login.impl.go b/src/modules/system/service/sys_log_login.impl.go index 4ede16e..e3db000 100644 --- a/src/modules/system/service/sys_log_login.impl.go +++ b/src/modules/system/service/sys_log_login.impl.go @@ -41,8 +41,8 @@ func (s *SysLogLoginImpl) CleanSysLogLogin() error { return s.sysLogLoginService.CleanSysLogLogin() } -// NewSysLogLogin 生成系统登录日志 -func (s *SysLogLoginImpl) NewSysLogLogin(userName, status, msg string, ilobArgs ...string) string { +// CreateSysLogLogin 创建系统登录日志 +func (s *SysLogLoginImpl) CreateSysLogLogin(userName, status, msg string, ilobArgs ...string) string { sysSysLogLogin := model.SysLogLogin{ IPAddr: ilobArgs[0], LoginLocation: ilobArgs[1], diff --git a/src/modules/system/system.go b/src/modules/system/system.go index 07d226c..82cb6a1 100644 --- a/src/modules/system/system.go +++ b/src/modules/system/system.go @@ -56,6 +56,11 @@ func Setup(router *gin.Engine) { collectlogs.OperateLog(collectlogs.OptionNew("参数配置信息", collectlogs.BUSINESS_TYPE_EXPORT)), controller.NewSysConfig.Export, ) + sysConfigGroup.PUT("/changeValue", + middleware.PreAuthorize(map[string][]string{"hasPerms": {"system:config:edit"}}), + collectlogs.OperateLog(collectlogs.OptionNew("参数配置信息", collectlogs.BUSINESS_TYPE_UPDATE)), + controller.NewSysConfig.ConfigValue, + ) } // 部门信息