diff --git a/main.go b/main.go
index 59a6440..b824247 100644
--- a/main.go
+++ b/main.go
@@ -159,6 +159,9 @@ func Run() error {
if err := global.DB.AutoMigrate(&model.Job{}); err != nil {
return err
}
+ if err := global.DB.AutoMigrate(&model.JobLog{}); err != nil {
+ return err
+ }
if len(model.FindAllTemp()) == 0 {
for i := 0; i <= 30; i++ {
@@ -197,24 +200,14 @@ func Run() error {
if err := model.CreateNewJob(&job); err != nil {
return err
}
- }
-
- jobs, err = model.FindJobByFunc(model.FuncDelTimeoutSessionJob)
- if err != nil {
- return err
- }
- if jobs == nil || len(jobs) == 0 {
- job := model.Job{
- ID: utils.UUID(),
- Name: "超时会话检测",
- Func: model.FuncDelTimeoutSessionJob,
- Cron: "0 0 0 * * ?",
- Status: model.JobStatusRunning,
- Created: utils.NowJsonTime(),
- Updated: utils.NowJsonTime(),
- }
- if err := model.CreateNewJob(&job); err != nil {
- return err
+ } else {
+ for i := range jobs {
+ if jobs[i].Status == model.JobStatusRunning {
+ err := model.ChangeJobStatusById(jobs[i].ID, model.JobStatusRunning)
+ if err != nil {
+ return err
+ }
+ }
}
}
diff --git a/pkg/api/job.go b/pkg/api/job.go
index c74ccfd..8d11d50 100644
--- a/pkg/api/job.go
+++ b/pkg/api/job.go
@@ -60,6 +60,14 @@ func JobChangeStatusEndpoint(c echo.Context) error {
return Success(c, "")
}
+func JobExecEndpoint(c echo.Context) error {
+ id := c.Param("id")
+ if err := model.ExecJobById(id); err != nil {
+ return err
+ }
+ return Success(c, "")
+}
+
func JobDeleteEndpoint(c echo.Context) error {
ids := c.Param("id")
@@ -84,3 +92,22 @@ func JobGetEndpoint(c echo.Context) error {
return Success(c, item)
}
+
+func JobGetLogsEndpoint(c echo.Context) error {
+ id := c.Param("id")
+
+ items, err := model.FindJobLogs(id)
+ if err != nil {
+ return err
+ }
+
+ return Success(c, items)
+}
+
+func JobDeleteLogsEndpoint(c echo.Context) error {
+ id := c.Param("id")
+ if err := model.DeleteJobLogByJobId(id); err != nil {
+ return err
+ }
+ return Success(c, "")
+}
diff --git a/pkg/api/routes.go b/pkg/api/routes.go
index df425a3..bb33423 100644
--- a/pkg/api/routes.go
+++ b/pkg/api/routes.go
@@ -150,8 +150,11 @@ func SetupRoutes() *echo.Echo {
jobs.GET("/paging", JobPagingEndpoint)
jobs.PUT("/:id", JobUpdateEndpoint)
jobs.POST("/:id/change-status", JobChangeStatusEndpoint)
+ jobs.POST("/:id/exec", JobExecEndpoint)
jobs.DELETE("/:id", JobDeleteEndpoint)
jobs.GET("/:id", JobGetEndpoint)
+ jobs.GET("/:id/logs", JobGetLogsEndpoint)
+ jobs.DELETE("/:id/logs", JobDeleteLogsEndpoint)
}
return e
diff --git a/pkg/handle/runner.go b/pkg/handle/runner.go
index 78a0967..4142f22 100644
--- a/pkg/handle/runner.go
+++ b/pkg/handle/runner.go
@@ -1,21 +1,61 @@
package handle
import (
+ "github.com/sirupsen/logrus"
"next-terminal/pkg/global"
"next-terminal/pkg/guacd"
"next-terminal/pkg/model"
"next-terminal/pkg/utils"
"os"
+ "strconv"
+ "time"
)
func RunTicker() {
// 每隔一小时删除一次未使用的会话信息
- _, _ = global.Cron.AddJob("0 0 0/1 * * ?", model.DelUnUsedSessionJob{})
- // 每隔一小时检测一次资产状态
- //_, _ = global.Cron.AddJob("0 0 0/1 * * ?", model.CheckAssetStatusJob{})
+ _, _ = global.Cron.AddFunc("0 0 0/1 * * ?", func() {
+ sessions, _ := model.FindSessionByStatusIn([]string{model.NoConnect, model.Connecting})
+ if sessions != nil && len(sessions) > 0 {
+ now := time.Now()
+ for i := range sessions {
+ if now.Sub(sessions[i].ConnectedTime.Time) > time.Hour*1 {
+ _ = model.DeleteSessionById(sessions[i].ID)
+ s := sessions[i].Username + "@" + sessions[i].IP + ":" + strconv.Itoa(sessions[i].Port)
+ logrus.Infof("会话「%v」ID「%v」超过1小时未打开,已删除。", s, sessions[i].ID)
+ }
+ }
+ }
+ })
// 每日凌晨删除超过时长限制的会话
- //_, _ = global.Cron.AddJob("0 0 0 * * ?", model.DelTimeoutSessionJob{})
+ _, _ = global.Cron.AddFunc("0 0 0 * * ?", func() {
+ property, err := model.FindPropertyByName("session-saved-limit")
+ if err != nil {
+ return
+ }
+ if property.Value == "" || property.Value == "-" {
+ return
+ }
+ limit, err := strconv.Atoi(property.Value)
+ if err != nil {
+ return
+ }
+ sessions, err := model.FindOutTimeSessions(limit)
+ if err != nil {
+ return
+ }
+
+ if sessions != nil && len(sessions) > 0 {
+ var sessionIds []string
+ for i := range sessions {
+ sessionIds = append(sessionIds, sessions[i].ID)
+ }
+ err := model.DeleteSessionByIds(sessionIds)
+ if err != nil {
+ logrus.Errorf("删除离线会话失败 %v", err)
+ }
+ }
+ })
global.Cron.Start()
}
diff --git a/pkg/model/job.go b/pkg/model/job.go
index 258f6c5..b024086 100644
--- a/pkg/model/job.go
+++ b/pkg/model/job.go
@@ -2,11 +2,11 @@ package model
import (
"errors"
+ "fmt"
"github.com/robfig/cron/v3"
"github.com/sirupsen/logrus"
"next-terminal/pkg/global"
"next-terminal/pkg/utils"
- "strconv"
"time"
)
@@ -14,20 +14,19 @@ const (
JobStatusRunning = "running"
JobStatusNotRunning = "not-running"
- FuncCheckAssetStatusJob = "check-asset-status-job"
- FuncDelUnUsedSessionJob = "del-unused-session-job"
- FuncDelTimeoutSessionJob = "del-timeout-session-job"
+ FuncCheckAssetStatusJob = "check-asset-status-job"
)
type Job struct {
- ID string `gorm:"primary_key" json:"id"`
- JobId int `json:"jobId"`
- Name string `json:"name"`
- Func string `json:"func"`
- Cron string `json:"cron"`
- Status string `json:"status"`
- Created utils.JsonTime `json:"created"`
- Updated utils.JsonTime `json:"updated"`
+ ID string `gorm:"primary_key" json:"id"`
+ CronJobId int `json:"cronJobId"`
+ Name string `json:"name"`
+ Func string `json:"func"`
+ Cron string `json:"cron"`
+ Status string `json:"status"`
+ Metadata string `json:"metadata"`
+ Created utils.JsonTime `json:"created"`
+ Updated utils.JsonTime `json:"updated"`
}
func (r *Job) TableName() string {
@@ -78,7 +77,7 @@ func CreateNewJob(o *Job) (err error) {
if err != nil {
return err
}
- o.JobId = int(jobId)
+ o.CronJobId = int(jobId)
}
return global.DB.Create(o).Error
@@ -93,7 +92,7 @@ func UpdateJobById(o *Job, id string) (err error) {
}
func UpdateJonUpdatedById(id string) (err error) {
- err = global.DB.Where("id = ?", id).Update("updated = ?", utils.NowJsonTime()).Error
+ err = global.DB.Updates(Job{ID: id, Updated: utils.NowJsonTime()}).Error
return
}
@@ -103,7 +102,7 @@ func ChangeJobStatusById(id, status string) (err error) {
if err != nil {
return err
}
- if status == JobStatusNotRunning {
+ if status == JobStatusRunning {
j, err := getJob(job.ID, job.Func)
if err != nil {
return err
@@ -112,16 +111,29 @@ func ChangeJobStatusById(id, status string) (err error) {
if err != nil {
return err
}
- job.JobId = int(entryID)
- return global.DB.Where("id = ?", id).Update("status = ?", JobStatusRunning).Error
+ job.CronJobId = int(entryID)
+ return global.DB.Updates(Job{ID: id, Status: JobStatusRunning}).Error
} else {
- global.Cron.Remove(cron.EntryID(job.JobId))
- return global.DB.Where("id = ?", id).Update("status = ?", JobStatusNotRunning).Error
+ global.Cron.Remove(cron.EntryID(job.CronJobId))
+ return global.DB.Updates(Job{ID: id, Status: JobStatusNotRunning}).Error
}
}
+func ExecJobById(id string) (err error) {
+ job, err := FindJobById(id)
+ if err != nil {
+ return err
+ }
+ j, err := getJob(id, job.Func)
+ if err != nil {
+ return err
+ }
+ j.Run()
+ return nil
+}
+
func FindJobById(id string) (o Job, err error) {
- err = global.DB.Where("id = ?").First(&o).Error
+ err = global.DB.Where("id = ?", id).First(&o).Error
return
}
@@ -131,21 +143,17 @@ func DeleteJobById(id string) error {
return err
}
if job.Status == JobStatusRunning {
- if err := ChangeJobStatusById(JobStatusNotRunning, id); err != nil {
+ if err := ChangeJobStatusById(id, JobStatusNotRunning); err != nil {
return err
}
}
- return global.DB.Where("id = ?").Delete(Job{}).Error
+ return global.DB.Where("id = ?", id).Delete(Job{}).Error
}
func getJob(id, function string) (job cron.Job, err error) {
switch function {
case FuncCheckAssetStatusJob:
job = CheckAssetStatusJob{ID: id}
- case FuncDelUnUsedSessionJob:
- job = DelUnUsedSessionJob{ID: id}
- case FuncDelTimeoutSessionJob:
- job = DelTimeoutSessionJob{ID: id}
default:
return nil, errors.New("未识别的任务")
}
@@ -159,71 +167,38 @@ type CheckAssetStatusJob struct {
func (r CheckAssetStatusJob) Run() {
assets, _ := FindAllAsset()
if assets != nil && len(assets) > 0 {
+
+ msgChan := make(chan string)
for i := range assets {
asset := assets[i]
- active := utils.Tcping(asset.IP, asset.Port)
- UpdateAssetActiveById(active, asset.ID)
- logrus.Infof("资产「%v」ID「%v」存活状态检测完成,存活「%v」。", asset.Name, asset.ID, active)
+ go func() {
+ t1 := time.Now()
+ active := utils.Tcping(asset.IP, asset.Port)
+ elapsed := time.Since(t1)
+ msg := fmt.Sprintf("资产「%v」存活状态检测完成,存活「%v」,耗时「%v」", asset.Name, active, elapsed)
+
+ UpdateAssetActiveById(active, asset.ID)
+ logrus.Infof(msg)
+ msgChan <- msg
+ }()
}
- }
- if r.ID != "" {
- _ = UpdateJonUpdatedById(r.ID)
- }
-}
-type DelUnUsedSessionJob struct {
- ID string
-}
-
-func (r DelUnUsedSessionJob) Run() {
- sessions, _ := FindSessionByStatusIn([]string{NoConnect, Connecting})
- if sessions != nil && len(sessions) > 0 {
- now := time.Now()
- for i := range sessions {
- if now.Sub(sessions[i].ConnectedTime.Time) > time.Hour*1 {
- _ = DeleteSessionById(sessions[i].ID)
- s := sessions[i].Username + "@" + sessions[i].IP + ":" + strconv.Itoa(sessions[i].Port)
- logrus.Infof("会话「%v」ID「%v」超过1小时未打开,已删除。", s, sessions[i].ID)
+ if r.ID != "" {
+ var message = ""
+ for i := 0; i < len(assets); i++ {
+ message += <-msgChan + "\n"
}
+
+ _ = UpdateJonUpdatedById(r.ID)
+ jobLog := JobLog{
+ ID: utils.UUID(),
+ JobId: r.ID,
+ Timestamp: utils.NowJsonTime(),
+ Message: message,
+ }
+
+ _ = CreateNewJobLog(&jobLog)
}
}
- if r.ID != "" {
- _ = UpdateJonUpdatedById(r.ID)
- }
-}
-type DelTimeoutSessionJob struct {
- ID string
-}
-
-func (r DelTimeoutSessionJob) Run() {
- property, err := FindPropertyByName("session-saved-limit")
- if err != nil {
- return
- }
- if property.Value == "" || property.Value == "-" {
- return
- }
- limit, err := strconv.Atoi(property.Value)
- if err != nil {
- return
- }
- sessions, err := FindOutTimeSessions(limit)
- if err != nil {
- return
- }
-
- if sessions != nil && len(sessions) > 0 {
- var sessionIds []string
- for i := range sessions {
- sessionIds = append(sessionIds, sessions[i].ID)
- }
- err := DeleteSessionByIds(sessionIds)
- if err != nil {
- logrus.Errorf("删除离线会话失败 %v", err)
- }
- }
- if r.ID != "" {
- _ = UpdateJonUpdatedById(r.ID)
- }
}
diff --git a/pkg/model/job_log.go b/pkg/model/job_log.go
new file mode 100644
index 0000000..fb7f923
--- /dev/null
+++ b/pkg/model/job_log.go
@@ -0,0 +1,30 @@
+package model
+
+import (
+ "next-terminal/pkg/global"
+ "next-terminal/pkg/utils"
+)
+
+type JobLog struct {
+ ID string `json:"id"`
+ Timestamp utils.JsonTime `json:"timestamp"`
+ JobId string `json:"jobId"`
+ Message string `json:"message"`
+}
+
+func (r *JobLog) TableName() string {
+ return "job_logs"
+}
+
+func CreateNewJobLog(o *JobLog) error {
+ return global.DB.Create(o).Error
+}
+
+func FindJobLogs(jobId string) (o []JobLog, err error) {
+ err = global.DB.Where("job_id = ?", jobId).Order("timestamp asc").Find(&o).Error
+ return
+}
+
+func DeleteJobLogByJobId(jobId string) error {
+ return global.DB.Where("job_id = ?", jobId).Delete(JobLog{}).Error
+}
diff --git a/web/src/App.css b/web/src/App.css
index a485e9f..976f9a0 100644
--- a/web/src/App.css
+++ b/web/src/App.css
@@ -90,6 +90,6 @@
border-radius: 5%;
}
-.monitor .ant-modal-body{
+.modal-no-padding .ant-modal-body{
padding: 0;
}
\ No newline at end of file
diff --git a/web/src/App.js b/web/src/App.js
index dec53a4..8924646 100644
--- a/web/src/App.js
+++ b/web/src/App.js
@@ -162,6 +162,14 @@ class App extends Component {
+
+ { + this.state.logs.map(item => { + + return <>+ +{item['timestamp']} {item['message']}>; + }) + } +