From 05559e2c168f862e028b6d0910197c67647c7b5f Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Sat, 28 Oct 2023 20:05:18 +0800 Subject: [PATCH] =?UTF-8?q?marge:=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/email.go | 36 ++- features/sys_menu/service/service_sys_menu.go | 12 +- features/udm_user/api_udm_user.go | 20 +- lib/routes/routes.go | 92 +++--- restagent/config/config.go | 11 +- src/app.go | 4 +- src/lib_features/session/session.go | 4 +- src/modules/common/common.go | 4 +- src/modules/common/controller/common.go | 2 +- src/modules/common/service/register.impl.go | 2 +- .../backupEtcFromNE/backupEtcFromNE.go | 2 +- src/modules/crontask/crontask.go | 20 +- .../delExpiredNeBackup/delExpiredNeBackup.go | 22 +- .../backupEtcFromNE/backupEtcFromNE.go | 145 +++++++++ .../delExpiredNeBackup/delExpiredNeBackup.go | 80 +++++ .../deleteExpiredRecord.go | 88 ++++++ .../monitor_sys_resource.go | 56 ++++ src/modules/crontask/processor/processor.go | 19 ++ src/modules/monitor/controller/monitor.go | 57 ++++ src/modules/monitor/model/monitor_base.go | 29 ++ src/modules/monitor/model/monitor_io.go | 27 ++ src/modules/monitor/model/monitor_network.go | 23 ++ src/modules/monitor/monitor.go | 9 + src/modules/monitor/repository/monitor.go | 33 ++ .../monitor/repository/monitor.impl.go | 103 +++++++ src/modules/monitor/service/monitor.go | 14 + src/modules/monitor/service/monitor.impl.go | 287 ++++++++++++++++++ src/modules/system/service/sys_config.impl.go | 4 +- src/modules/system/service/sys_menu.impl.go | 12 +- 29 files changed, 1109 insertions(+), 108 deletions(-) create mode 100644 src/modules/crontask/processor/backupEtcFromNE/backupEtcFromNE.go create mode 100644 src/modules/crontask/processor/delExpiredNeBackup/delExpiredNeBackup.go create mode 100644 src/modules/crontask/processor/deleteExpiredRecord/deleteExpiredRecord.go create mode 100644 src/modules/crontask/processor/monitor_sys_resource/monitor_sys_resource.go create mode 100644 src/modules/crontask/processor/processor.go create mode 100644 src/modules/monitor/controller/monitor.go create mode 100644 src/modules/monitor/model/monitor_base.go create mode 100644 src/modules/monitor/model/monitor_io.go create mode 100644 src/modules/monitor/model/monitor_network.go create mode 100644 src/modules/monitor/repository/monitor.go create mode 100644 src/modules/monitor/repository/monitor.impl.go create mode 100644 src/modules/monitor/service/monitor.go create mode 100644 src/modules/monitor/service/monitor.impl.go diff --git a/features/fm/email.go b/features/fm/email.go index 79665a2..24af203 100644 --- a/features/fm/email.go +++ b/features/fm/email.go @@ -16,11 +16,27 @@ import ( func AlarmEmailForward(alarmData *Alarm) error { log.Info("AlarmEmailForward processing... ") - message := ` -

Hello information,

- test, test -

Best Wishes!

- ` + message := fmt.Sprintf(` +

Alarm information

+

Sequence: %d

+

NE name: %s

+

Title: %s

+

Severity: %s

+

Event Time: %s

+

Automatic send by OMC, don't reply!

+ `, alarmData.AlarmSeq, alarmData.NeName, alarmData.AlarmTitle, alarmData.OrigSeverity, alarmData.EventTime) + + // message := fmt.Sprintf(` + // Alarm information + + // Sequence: %d + // NE name: %s + // Title: %s + // Severity: %s + // Event Time: %s + + // Automatic send by OMC, don't reply! + // `, alarmData.AlarmSeq, alarmData.NeName, alarmData.AlarmTitle, alarmData.OrigSeverity, alarmData.EventTime) // QQ 邮箱: // SMTP 服务器地址:smtp.qq.com(SSL协议端口:465/994 | 非SSL协议端口:25) @@ -74,7 +90,7 @@ func AlarmEmailForward(alarmData *Alarm) error { m.SetBody("text/html", message) // text/plain的意思是将文件设置为纯文本的形式,浏览器在获取到这种文件时并不会对其进行处理 - // m.SetBody("text/plain", "纯文本") + //m.SetBody("text/plain", message) // m.Attach("test.sh") // 附件文件,可以是文件,照片,视频等等 // m.Attach("lolcatVideo.mp4") // 视频 // m.Attach("lolcat.jpg") // 照片 @@ -87,6 +103,10 @@ func AlarmEmailForward(alarmData *Alarm) error { ) // 关闭SSL协议认证 d.TLSConfig = &tls.Config{InsecureSkipVerify: true} + if !config.GetYamlConfig().Alarm.Email.TlsSkipVerify { + // 打开SSL协议认证 + d.TLSConfig = &tls.Config{InsecureSkipVerify: false} + } if err := d.DialAndSend(m); err != nil { operResult := fmt.Sprintf("Failed to DialAndSend:%v", err) @@ -99,9 +119,7 @@ func AlarmEmailForward(alarmData *Alarm) error { return err } - operResult := fmt.Sprintf("Email sent successfully!:", err) - log.Error(operResult) - forwardLog.OperResult = operResult + forwardLog.OperResult = "Email sent successfully!" affected, err := dborm.XormInsertAlarmForwardLog(forwardLog) if err != nil && affected <= 0 { log.Error("Failed to insert data:", err) diff --git a/features/sys_menu/service/service_sys_menu.go b/features/sys_menu/service/service_sys_menu.go index 3c71d17..7ca1fd6 100644 --- a/features/sys_menu/service/service_sys_menu.go +++ b/features/sys_menu/service/service_sys_menu.go @@ -49,7 +49,17 @@ func (r *ServiceSysMenu) SelectMenuTreeByUserId(userId string) []model.SysMenu { // SelectMenuTreeSelectByUserId 根据用户ID查询菜单树结构信息 func (r *ServiceSysMenu) SelectMenuTreeSelectByUserId(sysMenu model.SysMenu, userId string) []vo.TreeSelect { sysMenus := r.sysMenuRepository.SelectMenuList(sysMenu, userId) - menus := r.parseDataToTree(sysMenus) + + // 过滤旧前端菜单 + sysMenusF := []model.SysMenu{} + for _, v := range sysMenus { + if v.Perms != "page" { + continue + } + sysMenusF = append(sysMenusF, v) + } + + menus := r.parseDataToTree(sysMenusF) tree := make([]vo.TreeSelect, 0) for _, menu := range menus { tree = append(tree, sysMenuTreeSelect(menu)) diff --git a/features/udm_user/api_udm_user.go b/features/udm_user/api_udm_user.go index dd58d08..0d8f16e 100644 --- a/features/udm_user/api_udm_user.go +++ b/features/udm_user/api_udm_user.go @@ -12,7 +12,6 @@ import ( "ems.agt/lib/core/conf" mmlclient "ems.agt/lib/core/mml_client" "ems.agt/lib/core/utils/ctx" - "ems.agt/lib/core/utils/parse" "ems.agt/lib/core/vo/result" "ems.agt/lib/dborm" "ems.agt/lib/log" @@ -212,15 +211,6 @@ func (s *UdmUserApi) UdmAuthUserList(w http.ResponseWriter, r *http.Request) { querys := ctx.QueryMap(r) querys["neId"] = "" data := s.authUser.Page(querys) - // 遍历安全掩码 - rows := data["rows"].([]model.UdmAuthUser) - maskRows := []model.UdmAuthUser{} - for _, v := range rows { - v.Ki = parse.SafeContent(v.Ki) - v.Opc = parse.SafeContent(v.Opc) - maskRows = append(maskRows, v) - } - data["rows"] = maskRows ctx.JSON(w, 200, result.Ok(data)) } @@ -280,8 +270,6 @@ func (s *UdmUserApi) UdmAuthUserInfo(w http.ResponseWriter, r *http.Request) { s.authUser.Insert(neId, userInfo) } - userInfo.Ki = parse.SafeContent(userInfo.Ki) - userInfo.Opc = parse.SafeContent(userInfo.Opc) ctx.JSON(w, 200, result.OkData(userInfo)) } @@ -519,9 +507,7 @@ func (s *UdmUserApi) UdmAuthUserExport(w http.ResponseWriter, r *http.Request) { data := [][]string{} data = append(data, []string{"imsi", "ki", "amf", "algo", "opc"}) for _, v := range list { - maskKi := parse.SafeContent(v.Ki) - maskOpc := parse.SafeContent(v.Opc) - data = append(data, []string{v.Imsi, maskKi, v.Amf, v.AlgoIndex, maskOpc}) + data = append(data, []string{v.Imsi, v.Ki, v.Amf, v.AlgoIndex, v.Opc}) } // 输出到文件 err := file.WriterCSVFile(data, filePath) @@ -535,9 +521,7 @@ func (s *UdmUserApi) UdmAuthUserExport(w http.ResponseWriter, r *http.Request) { // 转换数据 data := [][]string{} for _, v := range list { - maskKi := parse.SafeContent(v.Ki) - maskOpc := parse.SafeContent(v.Opc) - data = append(data, []string{v.Imsi, maskKi, v.Amf, v.AlgoIndex, maskOpc}) + data = append(data, []string{v.Imsi, v.Ki, v.Amf, v.AlgoIndex, v.Opc}) } // 输出到文件 err = file.WriterTxtFile(data, filePath) diff --git a/lib/routes/routes.go b/lib/routes/routes.go index f55ade6..b3f5d3d 100644 --- a/lib/routes/routes.go +++ b/lib/routes/routes.go @@ -71,52 +71,46 @@ func init() { Register("GET", sm.UriOMCLocalTime, sm.GetOMCLocalTime, nil) Register("GET", sm.CustomUriOMCLocalTime, sm.GetOMCLocalTime, nil) - // 数据库直连操作权限 - selectPermission := midware.Authorize(map[string][]string{}) - updatePermission := midware.Authorize(map[string][]string{}) - insertPermission := midware.Authorize(map[string][]string{}) - deletePermission := midware.Authorize(map[string][]string{}) - // database management - Register("GET", dbrest.XormGetDataUri, dbrest.DatabaseGetData, selectPermission) - Register("GET", dbrest.XormSelectDataUri, dbrest.DatabaseGetData, selectPermission) - Register("POST", dbrest.XormInsertDataUri, dbrest.DatabaseInsertData, insertPermission) - Register("PUT", dbrest.XormUpdateDataUri, dbrest.DatabaseUpdateData, updatePermission) - Register("DELETE", dbrest.XormDeleteDataUri, dbrest.DatabaseDeleteData, deletePermission) + Register("GET", dbrest.XormGetDataUri, dbrest.DatabaseGetData, nil) + Register("GET", dbrest.XormSelectDataUri, dbrest.DatabaseGetData, nil) + Register("POST", dbrest.XormInsertDataUri, dbrest.DatabaseInsertData, nil) + Register("PUT", dbrest.XormUpdateDataUri, dbrest.DatabaseUpdateData, nil) + Register("DELETE", dbrest.XormDeleteDataUri, dbrest.DatabaseDeleteData, nil) - Register("GET", dbrest.CustomXormGetDataUri, dbrest.DatabaseGetData, selectPermission) - Register("GET", dbrest.CustomXormSelectDataUri, dbrest.DatabaseGetData, selectPermission) - Register("POST", dbrest.CustomXormInsertDataUri, dbrest.DatabaseInsertData, insertPermission) - Register("PUT", dbrest.CustomXormUpdateDataUri, dbrest.DatabaseUpdateData, updatePermission) - Register("DELETE", dbrest.CustomXormDeleteDataUri, dbrest.DatabaseDeleteData, deletePermission) + Register("GET", dbrest.CustomXormGetDataUri, dbrest.DatabaseGetData, nil) + Register("GET", dbrest.CustomXormSelectDataUri, dbrest.DatabaseGetData, nil) + Register("POST", dbrest.CustomXormInsertDataUri, dbrest.DatabaseInsertData, nil) + Register("PUT", dbrest.CustomXormUpdateDataUri, dbrest.DatabaseUpdateData, nil) + Register("DELETE", dbrest.CustomXormDeleteDataUri, dbrest.DatabaseDeleteData, nil) - Register("GET", dbrest.XormCommonUri, dbrest.DatabaseGetData, selectPermission) - Register("POST", dbrest.XormCommonUri, dbrest.DatabaseInsertData, insertPermission) - Register("PUT", dbrest.XormCommonUri, dbrest.DatabaseUpdateData, updatePermission) - Register("DELETE", dbrest.XormCommonUri, dbrest.DatabaseDeleteData, deletePermission) + Register("GET", dbrest.XormCommonUri, dbrest.DatabaseGetData, nil) + Register("POST", dbrest.XormCommonUri, dbrest.DatabaseInsertData, nil) + Register("PUT", dbrest.XormCommonUri, dbrest.DatabaseUpdateData, nil) + Register("DELETE", dbrest.XormCommonUri, dbrest.DatabaseDeleteData, nil) - Register("GET", dbrest.XormDatabaseUri, dbrest.TaskDatabaseGetData, selectPermission) - Register("POST", dbrest.XormDatabaseUri, dbrest.TaskDatabaseInsertData, insertPermission) - Register("PUT", dbrest.XormDatabaseUri, dbrest.TaskDatabaseUpdateData, updatePermission) - Register("DELETE", dbrest.XormDatabaseUri, dbrest.TaskDatabaseDeleteData, deletePermission) + Register("GET", dbrest.XormDatabaseUri, dbrest.TaskDatabaseGetData, nil) + Register("POST", dbrest.XormDatabaseUri, dbrest.TaskDatabaseInsertData, nil) + Register("PUT", dbrest.XormDatabaseUri, dbrest.TaskDatabaseUpdateData, nil) + Register("DELETE", dbrest.XormDatabaseUri, dbrest.TaskDatabaseDeleteData, nil) - Register("GET", dbrest.CustomXormCommonUri, dbrest.DatabaseGetData, selectPermission) - Register("POST", dbrest.CustomXormCommonUri, dbrest.DatabaseInsertData, insertPermission) - Register("PUT", dbrest.CustomXormCommonUri, dbrest.DatabaseUpdateData, updatePermission) - Register("DELETE", dbrest.CustomXormCommonUri, dbrest.DatabaseDeleteData, deletePermission) + Register("GET", dbrest.CustomXormCommonUri, dbrest.DatabaseGetData, nil) + Register("POST", dbrest.CustomXormCommonUri, dbrest.DatabaseInsertData, nil) + Register("PUT", dbrest.CustomXormCommonUri, dbrest.DatabaseUpdateData, nil) + Register("DELETE", dbrest.CustomXormCommonUri, dbrest.DatabaseDeleteData, nil) - Register("GET", dbrest.XormExtDataUri, dbrest.ExtDatabaseGetData, selectPermission) - Register("POST", dbrest.XormExtDataUri, dbrest.ExtDatabaseInsertData, insertPermission) - Register("PUT", dbrest.XormExtDataUri, dbrest.ExtDatabaseUpdateData, updatePermission) - Register("DELETE", dbrest.XormExtDataUri, dbrest.ExtDatabaseDeleteData, deletePermission) + Register("GET", dbrest.XormExtDataUri, dbrest.ExtDatabaseGetData, nil) + Register("POST", dbrest.XormExtDataUri, dbrest.ExtDatabaseInsertData, nil) + Register("PUT", dbrest.XormExtDataUri, dbrest.ExtDatabaseUpdateData, nil) + Register("DELETE", dbrest.XormExtDataUri, dbrest.ExtDatabaseDeleteData, nil) - Register("GET", dbrest.CustomXormExtDataUri, dbrest.ExtDatabaseGetData, selectPermission) - Register("POST", dbrest.CustomXormExtDataUri, dbrest.ExtDatabaseInsertData, insertPermission) - Register("PUT", dbrest.CustomXormExtDataUri, dbrest.ExtDatabaseUpdateData, updatePermission) - Register("DELETE", dbrest.CustomXormExtDataUri, dbrest.ExtDatabaseDeleteData, deletePermission) + Register("GET", dbrest.CustomXormExtDataUri, dbrest.ExtDatabaseGetData, nil) + Register("POST", dbrest.CustomXormExtDataUri, dbrest.ExtDatabaseInsertData, nil) + Register("PUT", dbrest.CustomXormExtDataUri, dbrest.ExtDatabaseUpdateData, nil) + Register("DELETE", dbrest.CustomXormExtDataUri, dbrest.ExtDatabaseDeleteData, nil) // alarm restful Register - Register("POST", fm.UriAlarms, fm.PostAlarmFromNF, nil) + Register("POST", fm.UriAlarms, fm.PostAlarmFromNF, midware.LogOperate(collectlogs.OptionNew("Alarm", collectlogs.BUSINESS_TYPE_UPDATE))) Register("Get", fm.UriAlarms, fm.GetAlarmFromNF, nil) Register("POST", fm.CustomUriAlarms, fm.PostAlarmFromNF, nil) @@ -156,9 +150,9 @@ func init() { // Get/Create/Modify/Delete NE info Register("GET", cm.UriNeInfo, cm.GetNeInfo, nil) - Register("POST", cm.UriNeInfo, cm.PostNeInfo, nil) - Register("PUT", cm.UriNeInfo, cm.PutNeInfo, nil) - Register("DELETE", cm.UriNeInfo, cm.DeleteNeInfo, nil) + Register("POST", cm.UriNeInfo, cm.PostNeInfo, midware.LogOperate(collectlogs.OptionNew("NE info", collectlogs.BUSINESS_TYPE_INSERT))) + Register("PUT", cm.UriNeInfo, cm.PutNeInfo, midware.LogOperate(collectlogs.OptionNew("NE info", collectlogs.BUSINESS_TYPE_UPDATE))) + Register("DELETE", cm.UriNeInfo, cm.DeleteNeInfo, midware.LogOperate(collectlogs.OptionNew("NE info", collectlogs.BUSINESS_TYPE_DELETE))) // Get/Create/Modify/Delete NE info Register("GET", cm.CustomUriNeInfo, cm.GetNeInfo, nil) @@ -183,10 +177,10 @@ func init() { // Import/Export NF CM Register("GET", cm.NeCmUri, cm.ExportCmFromNF, nil) - Register("POST", cm.NeCmUri, cm.ImportCmToNF, nil) + Register("POST", cm.NeCmUri, cm.ImportCmToNF, midware.LogOperate(collectlogs.OptionNew("Import NF", collectlogs.BUSINESS_TYPE_INSERT))) Register("GET", cm.UriNeCmFile, cm.DownloadNeBackupFile, nil) - Register("DELETE", cm.UriNeCmFile, cm.DeleteNeBackupFile, nil) + Register("DELETE", cm.UriNeCmFile, cm.DeleteNeBackupFile, midware.LogOperate(collectlogs.OptionNew("Delete NF Backup", collectlogs.BUSINESS_TYPE_DELETE))) Register("GET", cm.CustomNeCmUri, cm.ExportCmFromNF, nil) Register("POST", cm.CustomNeCmUri, cm.ImportCmToNF, nil) @@ -197,12 +191,12 @@ func init() { // Software management Register("GET", cm.UriSoftware, cm.DownloadSoftwareFile, nil) //Register("POST", cm.UriSoftware, cm.UploadSoftwareFile, nil) - Register("POST", cm.UriSoftware, cm.UploadSoftwareMultiFile, nil) - Register("DELETE", cm.UriSoftware, cm.DeleteSoftwareFile, nil) + Register("POST", cm.UriSoftware, cm.UploadSoftwareMultiFile, midware.LogOperate(collectlogs.OptionNew("Software management", collectlogs.BUSINESS_TYPE_UPDATE))) + Register("DELETE", cm.UriSoftware, cm.DeleteSoftwareFile, midware.LogOperate(collectlogs.OptionNew("Software management", collectlogs.BUSINESS_TYPE_DELETE))) - Register("POST", cm.UriSoftwareNE, cm.DistributeSoftwareToNF, nil) - Register("PUT", cm.UriSoftwareNE, cm.ActiveSoftwareToNF, nil) - Register("PATCH", cm.UriSoftwareNE, cm.RollBackSoftwareToNF, nil) + Register("POST", cm.UriSoftwareNE, cm.DistributeSoftwareToNF, midware.LogOperate(collectlogs.OptionNew("Software management", collectlogs.BUSINESS_TYPE_OTHER))) + Register("PUT", cm.UriSoftwareNE, cm.ActiveSoftwareToNF, midware.LogOperate(collectlogs.OptionNew("Software management", collectlogs.BUSINESS_TYPE_OTHER))) + Register("PATCH", cm.UriSoftwareNE, cm.RollBackSoftwareToNF, midware.LogOperate(collectlogs.OptionNew("Software management", collectlogs.BUSINESS_TYPE_OTHER))) Register("GET", cm.CustomUriSoftware, cm.DownloadSoftwareFile, nil) Register("POST", cm.CustomUriSoftware, cm.UploadSoftwareFile, nil) @@ -213,8 +207,8 @@ func init() { Register("PATCH", cm.CustomUriSoftwareNE, cm.RollBackSoftwareToNF, nil) // License management - Register("POST", cm.UriLicense, cm.UploadLicenseFileData, nil) - Register("POST", cm.UriLicenseExt, cm.UploadLicenseFileData, nil) + Register("POST", cm.UriLicense, cm.UploadLicenseFileData, midware.LogOperate(collectlogs.OptionNew("License management", collectlogs.BUSINESS_TYPE_INSERT))) + Register("POST", cm.UriLicenseExt, cm.UploadLicenseFileData, midware.LogOperate(collectlogs.OptionNew("License management", collectlogs.BUSINESS_TYPE_INSERT))) Register("POST", cm.CustomUriLicense, cm.UploadLicenseFileData, nil) Register("POST", cm.CustomUriLicenseExt, cm.UploadLicenseFileData, nil) diff --git a/restagent/config/config.go b/restagent/config/config.go index 2e5fd60..4df8dfc 100644 --- a/restagent/config/config.go +++ b/restagent/config/config.go @@ -66,6 +66,8 @@ type YamlConfig struct { Chk2Ne bool `yaml:"chk2ne"` Sn string `yaml:"sn"` CheckSign bool `yaml:"checksign"` + RootDir string `yaml:"rootDir"` + BinDir string `yaml:"binDir"` Backup string `yaml:"backup"` Upload string `yaml:"upload"` FrontUpload string `yaml:"frontUpload"` @@ -82,10 +84,11 @@ type YamlConfig struct { Alarm struct { ForwardAlarm bool `yaml:"forwardAlarm"` Email struct { - Smtp string `yaml:"smtp"` - Port uint16 `yaml:"port"` - User string `yaml:"user"` - Password string `yaml:"password"` + Smtp string `yaml:"smtp"` + Port uint16 `yaml:"port"` + User string `yaml:"user"` + Password string `yaml:"password"` + TlsSkipVerify bool `yaml:"tlsSkipVerify"` } `json:"email"` SMS struct { ApiURL string `yaml:"apiURL"` diff --git a/src/app.go b/src/app.go index 05f0a4e..78b6ddf 100644 --- a/src/app.go +++ b/src/app.go @@ -114,8 +114,6 @@ func initDefeat(app *gin.Engine) { func initModulesRoute(app *gin.Engine) { // 通用模块 common.Setup(app) - // 监控模块 - monitor.Setup(app) // 系统模块 system.Setup(app) // 网元模块 @@ -124,4 +122,6 @@ func initModulesRoute(app *gin.Engine) { trace.Setup(app) // 调度任务模块--暂无接口 crontask.Setup(app) + // 监控模块 - 含调度处理加入队列,放最后 + monitor.Setup(app) } diff --git a/src/lib_features/session/session.go b/src/lib_features/session/session.go index fbb4541..f2ec700 100644 --- a/src/lib_features/session/session.go +++ b/src/lib_features/session/session.go @@ -12,8 +12,8 @@ import ( func SessionHeader() gin.HandlerFunc { return func(c *gin.Context) { // 读取登录生成的会话token - token, err := redis.Get("", "session_token") - if token != "" || err == nil { + token, _ := redis.Get("", "session_token") + if token != "" { // 过期时间单位秒 配置1800是半小时 expireTime := time.Duration(int64(libConfig.GetExpiresFromConfig())) * time.Second redis.SetByExpire("", "session_token", token, expireTime) diff --git a/src/modules/common/common.go b/src/modules/common/common.go index 13f0b9c..ffdec89 100644 --- a/src/modules/common/common.go +++ b/src/modules/common/common.go @@ -23,6 +23,9 @@ func Setup(router *gin.Engine) { controller.NewIndex.Handler, ) + // 系统可暴露的配置信息 + indexGroup.GET("/sys-conf", controller.NewCommont.SysConfig) + // 验证码操作处理 indexGroup.GET("/captchaImage", middleware.RateLimit(middleware.LimitOption{ @@ -71,7 +74,6 @@ 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/common.go b/src/modules/common/controller/common.go index 0e677f8..8975ced 100644 --- a/src/modules/common/controller/common.go +++ b/src/modules/common/controller/common.go @@ -28,7 +28,7 @@ func (s *CommontController) Hash(c *gin.Context) { // 系统可暴露的配置信息 // -// GET /sysConf +// GET /sys-conf func (s *CommontController) SysConfig(c *gin.Context) { data := s.commontService.SystemConfigInfo() c.JSON(200, result.OkData(data)) diff --git a/src/modules/common/service/register.impl.go b/src/modules/common/service/register.impl.go index 25f7765..c70204c 100644 --- a/src/modules/common/service/register.impl.go +++ b/src/modules/common/service/register.impl.go @@ -41,7 +41,7 @@ func (s *RegisterImpl) ValidateCaptcha(code, uuid string) error { } verifyKey := cachekey.CAPTCHA_CODE_KEY + uuid captcha, err := redis.Get("", verifyKey) - if captcha == "" || err != nil { + if err != nil { return errors.New("验证码已失效") } redis.Del("", verifyKey) diff --git a/src/modules/crontask/backupEtcFromNE/backupEtcFromNE.go b/src/modules/crontask/backupEtcFromNE/backupEtcFromNE.go index fe70d4a..02bc273 100644 --- a/src/modules/crontask/backupEtcFromNE/backupEtcFromNE.go +++ b/src/modules/crontask/backupEtcFromNE/backupEtcFromNE.go @@ -116,7 +116,7 @@ func (s *BarProcessor) Execute(data any) (any, error) { failureNEs = append(failureNEs, neInfo.NeType+"/"+neInfo.NeId) continue } - log.Trace("command output:", out) + log.Tracef("command output:%s", out) md5Sum, err := global.GetFileMD5Sum(zipFilePath) if err != nil { diff --git a/src/modules/crontask/crontask.go b/src/modules/crontask/crontask.go index 0eea775..53fd16e 100644 --- a/src/modules/crontask/crontask.go +++ b/src/modules/crontask/crontask.go @@ -1,11 +1,8 @@ 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" + "ems.agt/src/modules/crontask/processor" "github.com/gin-gonic/gin" ) @@ -14,14 +11,13 @@ import ( func Setup(router *gin.Engine) { logger.Infof("开始加载 ====> crontask 模块路由") - // 初始定时任务队列 - InitCronQueue() + // 启动时需要的初始参数 + InitLoad() + } -// InitCronQueue 初始定时任务队列 -func InitCronQueue() { - // delete expired NE backup file - cron.CreateQueue("delExpiredNeBackup", delExpiredNeBackup.NewProcessor) - cron.CreateQueue("deleteExpiredRecord", deleteExpiredRecord.NewProcessor) - cron.CreateQueue("backupEtcFromNE", backupEtcFromNE.NewProcessor) +// InitLoad 初始参数 +func InitLoad() { + // 初始化定时任务处理 + processor.InitCronQueue() } diff --git a/src/modules/crontask/delExpiredNeBackup/delExpiredNeBackup.go b/src/modules/crontask/delExpiredNeBackup/delExpiredNeBackup.go index 641641b..4d4857d 100644 --- a/src/modules/crontask/delExpiredNeBackup/delExpiredNeBackup.go +++ b/src/modules/crontask/delExpiredNeBackup/delExpiredNeBackup.go @@ -5,7 +5,9 @@ import ( "fmt" "ems.agt/lib/dborm" + "ems.agt/lib/global" "ems.agt/lib/log" + "ems.agt/restagent/config" "ems.agt/src/framework/cron" ) @@ -27,7 +29,7 @@ type BarParams struct { } func (s *BarProcessor) Execute(data any) (any, error) { - log.Infof("执行 %d 次,上次进度: %d ", s.count, s.progress) + log.Infof("count: %d ,progress: %d ", s.count, s.progress) s.count++ options := data.(cron.JobData) @@ -39,7 +41,7 @@ func (s *BarProcessor) Execute(data any) (any, error) { if err == nil { duration = params.Duration } - log.Infof("重复 %v 任务ID %s", options.Repeat, sysJob.JobID) + log.Infof("Repeat: %v JobID: %s", options.Repeat, sysJob.JobID) // // 实现任务处理逻辑 // i := 0 @@ -71,10 +73,22 @@ func (s *BarProcessor) Execute(data any) (any, error) { // delete expired files in backup directory // todo ... + // command := fmt.Sprintf("find . -name '*.zip' -mtime +%d -type f -print | xargs rm -rf", duration) + + command := fmt.Sprintf("%s/rmexpfiles.sh %s %d", config.GetYamlConfig().OMC.BinDir, config.GetYamlConfig().OMC.Backup, duration) + + log.Trace("command:", command) + out, err := global.ExecCmd(command) + if err != nil { + log.Error("Faile to exec command:", err) + return nil, err + } + log.Tracef("command output:%s", out) // 返回结果,用于记录执行结果 return map[string]any{ - "msg": "sucess", - "affected": affected, + "msg": "success", + "cmdoutput": string(out), + "affected": affected, }, nil } diff --git a/src/modules/crontask/processor/backupEtcFromNE/backupEtcFromNE.go b/src/modules/crontask/processor/backupEtcFromNE/backupEtcFromNE.go new file mode 100644 index 0000000..fe70d4a --- /dev/null +++ b/src/modules/crontask/processor/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/processor/delExpiredNeBackup/delExpiredNeBackup.go b/src/modules/crontask/processor/delExpiredNeBackup/delExpiredNeBackup.go new file mode 100644 index 0000000..641641b --- /dev/null +++ b/src/modules/crontask/processor/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/processor/deleteExpiredRecord/deleteExpiredRecord.go b/src/modules/crontask/processor/deleteExpiredRecord/deleteExpiredRecord.go new file mode 100644 index 0000000..8cae446 --- /dev/null +++ b/src/modules/crontask/processor/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/crontask/processor/monitor_sys_resource/monitor_sys_resource.go b/src/modules/crontask/processor/monitor_sys_resource/monitor_sys_resource.go new file mode 100644 index 0000000..58ecfd0 --- /dev/null +++ b/src/modules/crontask/processor/monitor_sys_resource/monitor_sys_resource.go @@ -0,0 +1,56 @@ +package monitorsysresource + +import ( + "encoding/json" + "fmt" + + "ems.agt/src/framework/cron" + "ems.agt/src/framework/logger" + monitorService "ems.agt/src/modules/monitor/service" +) + +var NewProcessor = &MonitorSysResourceProcessor{ + monitorService: monitorService.NewMonitorImpl, + count: 0, + openDataCancel: false, +} + +// MonitorSysResourceProcessor 系统资源CPU/IO/Netword收集 +type MonitorSysResourceProcessor struct { + // 服务器系统相关信息服务 + monitorService monitorService.IMonitor + // 执行次数 + count int + // 是否已经开启数据通道 + openDataCancel bool +} + +func (s *MonitorSysResourceProcessor) Execute(data any) (any, error) { + s.count++ // 执行次数加一 + options := data.(cron.JobData) + sysJob := options.SysJob + logger.Infof("重复 %v 任务ID %s", options.Repeat, sysJob.JobID) + + // 读取参数值 + var params struct { + Interval float64 `json:"interval"` + } + err := json.Unmarshal([]byte(sysJob.TargetParams), ¶ms) + if err != nil { + return nil, fmt.Errorf("json params 'interval' err: %v", err) + } + + // 避免重复开启chan通道 + if !s.openDataCancel { + s.monitorService.RunMonitorDataCancel(false, params.Interval) + s.openDataCancel = true + } + + s.monitorService.RunMonitor() + + // 返回结果,用于记录执行结果 + result := map[string]any{ + "count": s.count, + } + return result, nil +} diff --git a/src/modules/crontask/processor/processor.go b/src/modules/crontask/processor/processor.go new file mode 100644 index 0000000..4a0d8ae --- /dev/null +++ b/src/modules/crontask/processor/processor.go @@ -0,0 +1,19 @@ +package processor + +import ( + "ems.agt/src/framework/cron" + "ems.agt/src/modules/crontask/processor/backupEtcFromNE" + "ems.agt/src/modules/crontask/processor/delExpiredNeBackup" + "ems.agt/src/modules/crontask/processor/deleteExpiredRecord" + monitorsysresource "ems.agt/src/modules/crontask/processor/monitor_sys_resource" +) + +// InitCronQueue 初始定时任务队列 +func InitCronQueue() { + // 监控-系统资源 + cron.CreateQueue("monitor_sys_resource", monitorsysresource.NewProcessor) + // 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/monitor/controller/monitor.go b/src/modules/monitor/controller/monitor.go new file mode 100644 index 0000000..a69efe7 --- /dev/null +++ b/src/modules/monitor/controller/monitor.go @@ -0,0 +1,57 @@ +package controller + +import ( + "ems.agt/src/framework/vo/result" + "ems.agt/src/modules/monitor/service" + + "github.com/gin-gonic/gin" +) + +// 实例化控制层 MonitorInfoController 结构体 +var NewMonitor = &MonitorController{ + monitorService: service.NewMonitorImpl, +} + +// 服务器资源监控信息 +// +// PATH /monitor +type MonitorController struct { + // 服务器系统相关信息服务 + monitorService service.IMonitor +} + +// 资源监控信息加载 +// +// GET /load +func (s *MonitorController) Load(c *gin.Context) { + var querys struct { + // 数据类型all/cpu/memory/io/network + Type string `form:"type" binding:"required,oneof=all cpu memory io network"` + // 开始时间 + StartTime int64 `form:"startTime" binding:"required"` + // 结束时间 + EndTime int64 `form:"endTime" binding:"required"` + // 网元类型 + NeType string `form:"neType"` + // 网元ID + NeID string `form:"neId"` + // 名称,networ和iok时有效 + Name string `form:"name"` + } + err := c.ShouldBindQuery(&querys) + if err != nil { + c.JSON(400, result.CodeMsg(400, "参数错误")) + return + } + + // 查询数据 + data := s.monitorService.SelectMonitorInfo(map[string]any{ + "type": querys.Type, + "startTime": querys.StartTime, + "endTime": querys.EndTime, + "neType": querys.NeType, + "neId": querys.NeID, + "name": querys.Name, + }) + c.JSON(200, result.OkData(data)) +} diff --git a/src/modules/monitor/model/monitor_base.go b/src/modules/monitor/model/monitor_base.go new file mode 100644 index 0000000..7669afa --- /dev/null +++ b/src/modules/monitor/model/monitor_base.go @@ -0,0 +1,29 @@ +package model + +// MonitorBase 监控_基本信息 monitor_base +type MonitorBase struct { + // id + ID int64 `json:"id" gorm:"primaryKey"` + // 创建时间 + CreateTime int64 `json:"createTime"` + // cpu使用率 + CPU float64 `json:"cpu"` + // cpu平均使用率 + LoadUsage float64 `json:"loadUsage"` + // cpu使用1分钟 + CPULoad1 float64 `json:"cpuLoad1"` + // cpu使用5分钟 + CPULoad5 float64 `json:"cpuLoad5"` + // cpu使用15分钟 + CPULoad15 float64 `json:"cpuLoad15"` + // 内存使用率 + Memory float64 `json:"memory"` + // 网元ID + NeType string `json:"neType"` + // 网元类型 + NeID string `json:"neId"` +} + +func (MonitorBase) TableName() string { + return "monitor_base" +} diff --git a/src/modules/monitor/model/monitor_io.go b/src/modules/monitor/model/monitor_io.go new file mode 100644 index 0000000..cc52b72 --- /dev/null +++ b/src/modules/monitor/model/monitor_io.go @@ -0,0 +1,27 @@ +package model + +// MonitorIO 监控_磁盘IO monitor_io +type MonitorIO struct { + // id + ID int64 `json:"id" gorm:"primaryKey"` + // 创建时间 + CreateTime int64 `json:"createTime"` + // 磁盘名 + Name string `json:"name"` + // 读取K + Read int64 `json:"read"` + // 写入K + Write int64 `json:"write"` + // 次数 + Count int64 `json:"count"` + // 耗时 + Time int64 `json:"time"` + // 网元ID + NeType string `json:"neType"` + // 网元类型 + NeID string `json:"neId"` +} + +func (MonitorIO) TableName() string { + return "monitor_io" +} diff --git a/src/modules/monitor/model/monitor_network.go b/src/modules/monitor/model/monitor_network.go new file mode 100644 index 0000000..b505880 --- /dev/null +++ b/src/modules/monitor/model/monitor_network.go @@ -0,0 +1,23 @@ +package model + +// MonitorNetwork 监控_网络IO monitor_network +type MonitorNetwork struct { + // id + ID int64 `json:"id" gorm:"primaryKey"` + // 创建时间 + CreateTime int64 `json:"createTime"` + // 网卡名 + Name string `json:"name"` + // 上行 + Up float64 `json:"up"` + // 下行 + Down float64 `json:"down"` + // 网元ID + NeType string `json:"neType"` + // 网元类型 + NeID string `json:"neId"` +} + +func (MonitorNetwork) TableName() string { + return "monitor_network" +} diff --git a/src/modules/monitor/monitor.go b/src/modules/monitor/monitor.go index 549de18..2a279bc 100644 --- a/src/modules/monitor/monitor.go +++ b/src/modules/monitor/monitor.go @@ -19,6 +19,15 @@ func Setup(router *gin.Engine) { // 启动时需要的初始参数 InitLoad() + // 服务器资源监控信息 + monitorGroup := router.Group("/monitor") + { + monitorGroup.GET("/load", + // middleware.PreAuthorize(nil), + controller.NewMonitor.Load, + ) + } + // 服务器服务信息 router.GET("/monitor/system-info", middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:system:info"}}), diff --git a/src/modules/monitor/repository/monitor.go b/src/modules/monitor/repository/monitor.go new file mode 100644 index 0000000..a293efe --- /dev/null +++ b/src/modules/monitor/repository/monitor.go @@ -0,0 +1,33 @@ +package repository + +import "ems.agt/src/modules/monitor/model" + +// IMonitor 监控服务资源相关信息 数据接口 +type IMonitor interface { + // CreateMonitorBase 创建监控_基本信息 + CreateMonitorBase(m model.MonitorBase) error + + // DelMonitorBase 删除监控_基本信息 + DelMonitorBase(ltTime int64) error + + // SelectMonitorBase 查询监控_基本信息 + SelectMonitorBase(query map[string]any) []model.MonitorBase + + // BatchCreateMonitorIO 批量创建监控_IO + BatchCreateMonitorIO(ioList []model.MonitorIO) error + + // DelMonitorIO 删除监控_IO + DelMonitorIO(ltTime int64) error + + // SelectMonitorIO 查询监控_IO + SelectMonitorIO(query map[string]any) []model.MonitorIO + + // BatchCreateMonitorNet 批量创建监控_网络 + BatchCreateMonitorNet(netList []model.MonitorNetwork) error + + // DelMonitorNet 删除监控_网络 + DelMonitorNet(ltTime int64) error + + // SelectMonitorNetwork 查询监控_网络 + SelectMonitorNetwork(query map[string]any) []model.MonitorNetwork +} diff --git a/src/modules/monitor/repository/monitor.impl.go b/src/modules/monitor/repository/monitor.impl.go new file mode 100644 index 0000000..c113be6 --- /dev/null +++ b/src/modules/monitor/repository/monitor.impl.go @@ -0,0 +1,103 @@ +package repository + +import ( + "ems.agt/src/framework/datasource" + "ems.agt/src/framework/logger" + "ems.agt/src/modules/monitor/model" + "gorm.io/gorm" +) + +// 实例化数据层 MonitorImpl 结构体 +var NewMonitorImpl = &MonitorImpl{ + db: datasource.DefaultDB, +} + +// MonitorImpl 监控服务资源相关信息 数据层处理 +type MonitorImpl struct { + // 数据库实例 + db func() *gorm.DB +} + +// CreateMonitorBase 创建监控_基本信息 +func (r *MonitorImpl) CreateMonitorBase(m model.MonitorBase) error { + return r.db().Create(&m).Error +} + +// DelMonitorBase 删除监控_基本信息 +func (r *MonitorImpl) DelMonitorBase(ltTime int64) error { + return r.db().Where("create_time < ?", ltTime).Delete(&model.MonitorBase{}).Error +} + +// SelectMonitorBase 查询监控_基本信息 +func (r *MonitorImpl) SelectMonitorBase(query map[string]any) []model.MonitorBase { + var bases []model.MonitorBase + dbConn := r.db() + if query["neType"] != "" && query["neId"] != "" { + dbConn = dbConn.Where("ne_type = ? and ne_id = ?", query["neType"], query["neId"]) + } + dbConn = dbConn.Where("create_time >= ? and create_time <= ?", query["startTime"], query["endTime"]) + err := dbConn.Order("create_time desc").Find(&bases).Error + if err != nil { + logger.Errorf("SelectMonitorBase %v", err) + return bases + } + return bases +} + +// BatchCreateMonitorIO 批量创建监控_IO +func (r *MonitorImpl) BatchCreateMonitorIO(ioList []model.MonitorIO) error { + return r.db().CreateInBatches(ioList, len(ioList)).Error +} + +// DelMonitorIO 删除监控_IO +func (r *MonitorImpl) DelMonitorIO(ltTime int64) error { + return r.db().Where("create_time < ?", ltTime).Delete(&model.MonitorIO{}).Error +} + +// SelectMonitorIO 查询监控_IO +func (r *MonitorImpl) SelectMonitorIO(query map[string]any) []model.MonitorIO { + var ios []model.MonitorIO + dbConn := r.db() + if query["name"] != "" { + dbConn = dbConn.Where("name = ?", query["name"]) + } + if query["neType"] != "" && query["neId"] != "" { + dbConn = dbConn.Where("ne_type = ? and ne_id = ?", query["neType"], query["neId"]) + } + dbConn = dbConn.Where("create_time >= ? and create_time <= ?", query["startTime"], query["endTime"]) + err := dbConn.Order("create_time desc").Find(&ios).Error + if err != nil { + logger.Errorf("SelectMonitorIO %v", err) + return ios + } + return ios +} + +// BatchCreateMonitorNet 批量创建监控_网络 +func (r *MonitorImpl) BatchCreateMonitorNet(netList []model.MonitorNetwork) error { + return r.db().CreateInBatches(netList, len(netList)).Error +} + +// DelMonitorNet 删除监控_网络 +func (r *MonitorImpl) DelMonitorNet(ltTime int64) error { + return r.db().Where("create_time < ?", ltTime).Delete(&model.MonitorNetwork{}).Error +} + +// SelectMonitorNetwork 查询监控_网络 +func (r *MonitorImpl) SelectMonitorNetwork(query map[string]any) []model.MonitorNetwork { + var networks []model.MonitorNetwork + dbConn := r.db() + if query["name"] != "" { + dbConn = dbConn.Where("name = ?", query["name"]) + } + if query["neType"] != "" && query["neId"] != "" { + dbConn = dbConn.Where("ne_type = ? and ne_id = ?", query["neType"], query["neId"]) + } + dbConn = dbConn.Where("create_time >= ? and create_time <= ?", query["startTime"], query["endTime"]) + err := dbConn.Order("create_time desc").Find(&networks).Error + if err != nil { + logger.Errorf("SelectMonitorNetwork %v", err) + return networks + } + return networks +} diff --git a/src/modules/monitor/service/monitor.go b/src/modules/monitor/service/monitor.go new file mode 100644 index 0000000..0ed1454 --- /dev/null +++ b/src/modules/monitor/service/monitor.go @@ -0,0 +1,14 @@ +package service + +// IMonitor 服务器系统相关信息 服务层接口 +type IMonitor interface { + // RunMonitor 执行资源监控 + RunMonitor() + + // RunMonitorDataCancel 启动资源监控数据存储io/network通道 移除之前的chan上下文后在设置新的均值 + // interval 采集的平均值(分钟) + RunMonitorDataCancel(removeBefore bool, interval float64) + + // SelectMonitorInfo 查询监控资源信息 + SelectMonitorInfo(query map[string]any) map[string]MonitorData +} diff --git a/src/modules/monitor/service/monitor.impl.go b/src/modules/monitor/service/monitor.impl.go new file mode 100644 index 0000000..b391745 --- /dev/null +++ b/src/modules/monitor/service/monitor.impl.go @@ -0,0 +1,287 @@ +package service + +import ( + "context" + "strconv" + "time" + + "ems.agt/src/framework/logger" + "ems.agt/src/modules/monitor/model" + "ems.agt/src/modules/monitor/repository" + systemService "ems.agt/src/modules/system/service" + "github.com/shirou/gopsutil/cpu" + "github.com/shirou/gopsutil/disk" + "github.com/shirou/gopsutil/load" + "github.com/shirou/gopsutil/net" + "github.com/shirou/gopsutil/v3/mem" +) + +// 实例化服务层 MonitorImpl 结构体 +var NewMonitorImpl = &MonitorImpl{ + sysConfigService: systemService.NewSysConfigImpl, + monitorRepository: repository.NewMonitorImpl, + diskIO: make(chan []disk.IOCountersStat, 2), + netIO: make(chan []net.IOCountersStat, 2), +} + +// MonitorImpl 服务器系统相关信息 服务层处理 +type MonitorImpl struct { + // 参数配置服务 + sysConfigService systemService.ISysConfig + // 监控服务资源数据信息 + monitorRepository repository.IMonitor + // 磁盘网络IO 数据通道 + diskIO chan ([]disk.IOCountersStat) + netIO chan ([]net.IOCountersStat) +} + +// RunMonitor 执行资源监控 +func (s *MonitorImpl) RunMonitor() { + var itemModel model.MonitorBase + itemModel.CreateTime = time.Now().UnixMilli() + totalPercent, _ := cpu.Percent(3*time.Second, false) + if len(totalPercent) == 1 { + itemModel.CPU = totalPercent[0] + } + cpuCount, _ := cpu.Counts(false) + + loadInfo, _ := load.Avg() + itemModel.CPULoad1 = loadInfo.Load1 + itemModel.CPULoad5 = loadInfo.Load5 + itemModel.CPULoad15 = loadInfo.Load15 + itemModel.LoadUsage = loadInfo.Load1 / (float64(cpuCount*2) * 0.75) * 100 + + memoryInfo, _ := mem.VirtualMemory() + itemModel.Memory = memoryInfo.UsedPercent + if err := s.monitorRepository.CreateMonitorBase(itemModel); err != nil { + logger.Errorf("CreateMonitorBase err: %v", err) + } + + // 将当前资源发送到chan中处理保存 + s.loadDiskIO() + s.loadNetIO() + + // 监控系统资源-保留天数 + storeDays := s.sysConfigService.SelectConfigValueByKey("monitor.sysResource.storeDays") + if storeDays != "" { + storeDays, _ := strconv.Atoi(storeDays) + ltTime := time.Now().AddDate(0, 0, -storeDays).UnixMilli() + _ = s.monitorRepository.DelMonitorBase(ltTime) + _ = s.monitorRepository.DelMonitorIO(ltTime) + _ = s.monitorRepository.DelMonitorNet(ltTime) + } +} + +func (s *MonitorImpl) loadDiskIO() { + ioStat, _ := disk.IOCounters() + var diskIOList []disk.IOCountersStat + for _, io := range ioStat { + diskIOList = append(diskIOList, io) + } + s.diskIO <- diskIOList +} + +func (s *MonitorImpl) loadNetIO() { + netStat, _ := net.IOCounters(true) + netStatAll, _ := net.IOCounters(false) + var netList []net.IOCountersStat + netList = append(netList, netStat...) + netList = append(netList, netStatAll...) + s.netIO <- netList +} + +// monitorCancel 监控搜集IO/Network上下文 +var monitorCancel context.CancelFunc + +// RunMonitorDataCancel 启动资源监控数据存储io/network通道 移除之前的chan上下文后在设置新的均值 +// interval 采集的平均值(分钟) +func (s *MonitorImpl) RunMonitorDataCancel(removeBefore bool, interval float64) { + // 是否取消之前的 + if removeBefore { + monitorCancel() + } + + // 上下文控制 + ctx, cancel := context.WithCancel(context.Background()) + monitorCancel = cancel + + // chanl 通道进行存储数据 + go s.saveIODataToDB(ctx, interval) + go s.saveNetDataToDB(ctx, interval) +} + +func (s *MonitorImpl) saveIODataToDB(ctx context.Context, interval float64) { + defer close(s.diskIO) + for { + select { + case <-ctx.Done(): + return + case ioStat := <-s.diskIO: + select { + case <-ctx.Done(): + return + case ioStat2 := <-s.diskIO: + var ioList []model.MonitorIO + timeMilli := time.Now().UnixMilli() + for _, io2 := range ioStat2 { + for _, io1 := range ioStat { + if io2.Name == io1.Name { + var itemIO model.MonitorIO + itemIO.CreateTime = timeMilli + itemIO.Name = io1.Name + if io2.ReadBytes != 0 && io1.ReadBytes != 0 && io2.ReadBytes > io1.ReadBytes { + itemIO.Read = int64(float64(io2.ReadBytes-io1.ReadBytes) / interval / 60) + } + if io2.WriteBytes != 0 && io1.WriteBytes != 0 && io2.WriteBytes > io1.WriteBytes { + itemIO.Write = int64(float64(io2.WriteBytes-io1.WriteBytes) / interval / 60) + } + + if io2.ReadCount != 0 && io1.ReadCount != 0 && io2.ReadCount > io1.ReadCount { + itemIO.Count = int64(float64(io2.ReadCount-io1.ReadCount) / interval / 60) + } + writeCount := int64(0) + if io2.WriteCount != 0 && io1.WriteCount != 0 && io2.WriteCount > io1.WriteCount { + writeCount = int64(float64(io2.WriteCount-io1.WriteCount) / interval * 60) + } + if writeCount > itemIO.Count { + itemIO.Count = writeCount + } + + if io2.ReadTime != 0 && io1.ReadTime != 0 && io2.ReadTime > io1.ReadTime { + itemIO.Time = int64(float64(io2.ReadTime-io1.ReadTime) / interval / 60) + } + writeTime := int64(0) + if io2.WriteTime != 0 && io1.WriteTime != 0 && io2.WriteTime > io1.WriteTime { + writeTime = int64(float64(io2.WriteTime-io1.WriteTime) / interval / 60) + } + if writeTime > itemIO.Time { + itemIO.Time = writeTime + } + ioList = append(ioList, itemIO) + break + } + } + } + if err := s.monitorRepository.BatchCreateMonitorIO(ioList); err != nil { + logger.Errorf("BatchCreateMonitorIO err: %v", err) + } + s.diskIO <- ioStat2 + } + } + } +} + +func (s *MonitorImpl) saveNetDataToDB(ctx context.Context, interval float64) { + defer close(s.netIO) + for { + select { + case <-ctx.Done(): + return + case netStat := <-s.netIO: + select { + case <-ctx.Done(): + return + case netStat2 := <-s.netIO: + var netList []model.MonitorNetwork + timeMilli := time.Now().UnixMilli() + for _, net2 := range netStat2 { + for _, net1 := range netStat { + if net2.Name == net1.Name { + var itemNet model.MonitorNetwork + itemNet.CreateTime = timeMilli + itemNet.Name = net1.Name + + if net2.BytesSent != 0 && net1.BytesSent != 0 && net2.BytesSent > net1.BytesSent { + itemNet.Up = float64(net2.BytesSent-net1.BytesSent) / 1024 / interval / 60 + } + if net2.BytesRecv != 0 && net1.BytesRecv != 0 && net2.BytesRecv > net1.BytesRecv { + itemNet.Down = float64(net2.BytesRecv-net1.BytesRecv) / 1024 / interval / 60 + } + netList = append(netList, itemNet) + break + } + } + } + + if err := s.monitorRepository.BatchCreateMonitorNet(netList); err != nil { + logger.Errorf("BatchCreateMonitorNet err: %v", err) + } + s.netIO <- netStat2 + } + } + } +} + +// MonitorData 监控资源信息 +type MonitorData struct { + Date []int64 `json:"date"` + Value []any `json:"value"` +} + +// SelectMonitorInfo 查询监控资源信息 +func (s *MonitorImpl) SelectMonitorInfo(query map[string]any) map[string]MonitorData { + infoType := query["type"] + startTimeMilli := query["startTime"] + endTimeMilli := query["endTime"] + neType := query["neType"] + neId := query["neId"] + name := query["name"] + + // 返回数据 + backdatas := map[string]MonitorData{} + + // 基本信息 + if infoType == "all" || infoType == "cpu" || infoType == "memory" { + rows := s.monitorRepository.SelectMonitorBase(map[string]any{ + "startTime": startTimeMilli, + "endTime": endTimeMilli, + "neType": neType, + "neId": neId, + }) + // 组装数据 + var itemData MonitorData + for _, base := range rows { + itemData.Date = append(itemData.Date, base.CreateTime) + itemData.Value = append(itemData.Value, base) + } + backdatas["base"] = itemData + } + + // 磁盘IO + if infoType == "all" || infoType == "io" { + rows := s.monitorRepository.SelectMonitorIO(map[string]any{ + "startTime": startTimeMilli, + "endTime": endTimeMilli, + "neType": neType, + "neId": neId, + "name": name, + }) + // 组装数据 + var itemData MonitorData + for _, base := range rows { + itemData.Date = append(itemData.Date, base.CreateTime) + itemData.Value = append(itemData.Value, base) + } + backdatas["io"] = itemData + } + + // 网络 + if infoType == "all" || infoType == "network" { + rows := s.monitorRepository.SelectMonitorNetwork(map[string]any{ + "startTime": startTimeMilli, + "endTime": endTimeMilli, + "neType": neType, + "neId": neId, + "name": name, + }) + // 组装数据 + var itemData MonitorData + for _, base := range rows { + itemData.Date = append(itemData.Date, base.CreateTime) + itemData.Value = append(itemData.Value, base) + } + backdatas["network"] = itemData + } + + return backdatas +} diff --git a/src/modules/system/service/sys_config.impl.go b/src/modules/system/service/sys_config.impl.go index 2a50cee..eb19367 100644 --- a/src/modules/system/service/sys_config.impl.go +++ b/src/modules/system/service/sys_config.impl.go @@ -34,8 +34,8 @@ func (r *SysConfigImpl) SelectConfigList(sysConfig model.SysConfig) []model.SysC func (r *SysConfigImpl) SelectConfigValueByKey(configKey string) string { cacheKey := r.getCacheKey(configKey) // 从缓存中读取 - cacheValue, err := redis.Get("", cacheKey) - if cacheValue != "" || err != nil { + cacheValue, _ := redis.Get("", cacheKey) + if cacheValue != "" { return cacheValue } // 无缓存时读取数据放入缓存中 diff --git a/src/modules/system/service/sys_menu.impl.go b/src/modules/system/service/sys_menu.impl.go index 6d4d5c2..f516595 100644 --- a/src/modules/system/service/sys_menu.impl.go +++ b/src/modules/system/service/sys_menu.impl.go @@ -49,7 +49,17 @@ func (r *SysMenuImpl) SelectMenuTreeByUserId(userId string) []model.SysMenu { // SelectMenuTreeSelectByUserId 根据用户ID查询菜单树结构信息 func (r *SysMenuImpl) SelectMenuTreeSelectByUserId(sysMenu model.SysMenu, userId string) []vo.TreeSelect { sysMenus := r.sysMenuRepository.SelectMenuList(sysMenu, userId) - menus := r.parseDataToTree(sysMenus) + + // 过滤旧前端菜单 + sysMenusF := []model.SysMenu{} + for _, v := range sysMenus { + if v.Perms == "page" { + continue + } + sysMenusF = append(sysMenusF, v) + } + + menus := r.parseDataToTree(sysMenusF) tree := make([]vo.TreeSelect, 0) for _, menu := range menus { tree = append(tree, vo.SysMenuTreeSelect(menu))