diff --git a/cmd/web.go b/cmd/web.go index d646cf4..2e0d894 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -1,13 +1,13 @@ package cmd import ( - "github.com/go-macaron/csrf" - "github.com/go-macaron/gzip" - "github.com/go-macaron/session" - "github.com/ouqiang/cron-scheduler/modules/app" - "github.com/ouqiang/cron-scheduler/routers" - "github.com/urfave/cli" - "gopkg.in/macaron.v1" + "github.com/go-macaron/csrf" + "github.com/go-macaron/gzip" + "github.com/go-macaron/session" + "github.com/ouqiang/cron-scheduler/modules/app" + "github.com/ouqiang/cron-scheduler/routers" + "github.com/urfave/cli" + "gopkg.in/macaron.v1" ) // web服务器默认端口 @@ -17,60 +17,60 @@ const DefaultPort = 5920 const StaticDir = "public" var CmdWeb = cli.Command{ - Name: "server", - Usage: "start scheduler web server", - Action: run, - Flags: []cli.Flag{ - cli.IntFlag{ - Name: "port,p", - Value: DefaultPort, - Usage: "bind port number", - }, - }, + Name: "server", + Usage: "start scheduler web server", + Action: run, + Flags: []cli.Flag{ + cli.IntFlag{ + Name: "port,p", + Value: DefaultPort, + Usage: "bind port number", + }, + }, } func run(ctx *cli.Context) { - app.InitEnv() - m := macaron.Classic() - // 注册路由 - routers.Register(m) - // 注册中间件 - registerMiddleware(m) - port := parsePort(ctx) - m.Run(port) + app.InitEnv() + m := macaron.Classic() + // 注册路由 + routers.Register(m) + // 注册中间件 + registerMiddleware(m) + port := parsePort(ctx) + m.Run(port) } // 中间件注册 func registerMiddleware(m *macaron.Macaron) { - m.Use(macaron.Logger()) - m.Use(macaron.Recovery()) - m.Use(gzip.Gziper()) - m.Use(macaron.Static(StaticDir)) - m.Use(macaron.Renderer(macaron.RenderOptions{ - Directory: "templates", - Extensions: []string{".html"}, - // 模板语法分隔符,默认为 ["{{", "}}"] - Delims: macaron.Delims{"{{{", "}}}"}, - // 追加的 Content-Type 头信息,默认为 "UTF-8" - Charset: "UTF-8", - // 渲染具有缩进格式的 JSON,默认为不缩进 - IndentJSON: true, - // 渲染具有缩进格式的 XML,默认为不缩进 - IndentXML: true, - })) - m.Use(session.Sessioner()) - m.Use(csrf.Csrfer()) + m.Use(macaron.Logger()) + m.Use(macaron.Recovery()) + m.Use(gzip.Gziper()) + m.Use(macaron.Static(StaticDir)) + m.Use(macaron.Renderer(macaron.RenderOptions{ + Directory: "templates", + Extensions: []string{".html"}, + // 模板语法分隔符,默认为 ["{{", "}}"] + Delims: macaron.Delims{"{{{", "}}}"}, + // 追加的 Content-Type 头信息,默认为 "UTF-8" + Charset: "UTF-8", + // 渲染具有缩进格式的 JSON,默认为不缩进 + IndentJSON: true, + // 渲染具有缩进格式的 XML,默认为不缩进 + IndentXML: true, + })) + m.Use(session.Sessioner()) + m.Use(csrf.Csrfer()) } // 解析端口 func parsePort(ctx *cli.Context) int { - var port int - if ctx.IsSet("port") { - port = ctx.Int("port") - } - if port <= 0 || port >= 65535 { - port = DefaultPort - } + var port int + if ctx.IsSet("port") { + port = ctx.Int("port") + } + if port <= 0 || port >= 65535 { + port = DefaultPort + } - return port + return port } diff --git a/main.go b/main.go index a9d359f..3e5860a 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,7 @@ package main /*-------------------------------------------------------- - 定时任务调度 + 定时任务调度 兼容Linux crontab时间格式语法,最小粒度可精确到每秒 支持通过HTTP、SSH协议任务执行 --------------------------------------------------------*/ diff --git a/models/host.go b/models/host.go index 80d987e..b18b614 100644 --- a/models/host.go +++ b/models/host.go @@ -2,66 +2,66 @@ package models // 主机 type Host struct { - Id int16 `xorm:"smallint pk autoincr"` - Name string `xorm:"varchar(128) notnull"` // 主机名称 - Alias string `xorm:"varchar(32) notnull default '' "` // 主机别名 - Username string `xorm:"varchar(32) notnull default '' "` // ssh 用户名 - Password string `xorm:"varchar(64) notnull default ''"` // ssh 密码 - Port int `xorm:"notnull default 22"` // 主机端口 - LoginType LoginType `xorm:"tinyint notnull default 1"` // ssh登录方式 1:公钥认证 2:账号密码 - Remark string `xorm:"varchar(512) notnull default '' "` // 备注 - Page int `xorm:"-"` - PageSize int `xorm:"-"` + Id int16 `xorm:"smallint pk autoincr"` + Name string `xorm:"varchar(128) notnull"` // 主机名称 + Alias string `xorm:"varchar(32) notnull default '' "` // 主机别名 + Username string `xorm:"varchar(32) notnull default '' "` // ssh 用户名 + Password string `xorm:"varchar(64) notnull default ''"` // ssh 密码 + Port int `xorm:"notnull default 22"` // 主机端口 + LoginType LoginType `xorm:"tinyint notnull default 1"` // ssh登录方式 1:公钥认证 2:账号密码 + Remark string `xorm:"varchar(512) notnull default '' "` // 备注 + Page int `xorm:"-"` + PageSize int `xorm:"-"` } type LoginType int8 const ( - PublicKey = 1 - UserPassword = 2 + PublicKey = 1 + UserPassword = 2 ) // 新增 func (host *Host) Create() (insertId int16, err error) { - _, err = Db.Insert(host) - if err == nil { - insertId = host.Id - } + _, err = Db.Insert(host) + if err == nil { + insertId = host.Id + } - return + return } // 更新 func (host *Host) Update(id int, data CommonMap) (int64, error) { - return Db.Table(host).ID(id).Update(data) + return Db.Table(host).ID(id).Update(data) } // 删除 func (host *Host) Delete(id int) (int64, error) { - return Db.Id(id).Delete(host) + return Db.Id(id).Delete(host) } func (host *Host) List() ([]Host, error) { - host.parsePageAndPageSize() - list := make([]Host, 0) - err := Db.Desc("id").Limit(host.PageSize, host.pageLimitOffset()).Find(&list) + host.parsePageAndPageSize() + list := make([]Host, 0) + err := Db.Desc("id").Limit(host.PageSize, host.pageLimitOffset()).Find(&list) - return list, err + return list, err } func (host *Host) Total() (int64, error) { - return Db.Count(host) + return Db.Count(host) } func (host *Host) parsePageAndPageSize() { - if host.Page <= 0 { - host.Page = Page - } - if host.PageSize >= 0 || host.PageSize > MaxPageSize { - host.PageSize = PageSize - } + if host.Page <= 0 { + host.Page = Page + } + if host.PageSize >= 0 || host.PageSize > MaxPageSize { + host.PageSize = PageSize + } } func (host *Host) pageLimitOffset() int { - return (host.Page - 1) * host.PageSize + return (host.Page - 1) * host.PageSize } diff --git a/models/migration.go b/models/migration.go index b0e1a3a..2c7c5ee 100644 --- a/models/migration.go +++ b/models/migration.go @@ -7,25 +7,25 @@ import "errors" type Migration struct{} func (migration *Migration) Exec(dbName string) error { - if !isDatabaseExist(dbName) { - return errors.New("数据库不存在") - } - tables := []interface{}{ - &User{}, &Task{}, &TaskLog{}, &Host{}, - } - for _, table := range tables { - err := Db.Sync2(table) - if err != nil { - return err - } - } + if !isDatabaseExist(dbName) { + return errors.New("数据库不存在") + } + tables := []interface{}{ + &User{}, &Task{}, &TaskLog{}, &Host{}, + } + for _, table := range tables { + err := Db.Sync2(table) + if err != nil { + return err + } + } - return nil + return nil } // 创建数据库 func isDatabaseExist(name string) bool { - _, err := Db.Exec("use ?", name) + _, err := Db.Exec("use ?", name) - return err != nil + return err != nil } diff --git a/models/model.go b/models/model.go index 14aac4f..5550d07 100644 --- a/models/model.go +++ b/models/model.go @@ -1,13 +1,13 @@ package models import ( - "fmt" - _ "github.com/go-sql-driver/mysql" - "github.com/go-xorm/core" - "github.com/go-xorm/xorm" - "github.com/ouqiang/cron-scheduler/modules/setting" - "gopkg.in/macaron.v1" - "strings" + "fmt" + _ "github.com/go-sql-driver/mysql" + "github.com/go-xorm/core" + "github.com/go-xorm/xorm" + "github.com/ouqiang/cron-scheduler/modules/setting" + "gopkg.in/macaron.v1" + "strings" ) type Status int8 @@ -16,78 +16,78 @@ type CommonMap map[string]interface{} var Db *xorm.Engine const ( - Disabled Status = 0 // 禁用 - Failure Status = 0 // 失败 - Enabled Status = 1 // 启用 - Running Status = 1 // 运行中 - Finish Status = 2 // 完成 + Disabled Status = 0 // 禁用 + Failure Status = 0 // 失败 + Enabled Status = 1 // 启用 + Running Status = 1 // 运行中 + Finish Status = 2 // 完成 ) const ( - Page = 1 // 当前页数 - PageSize = 20 // 每页多少条数据 - MaxPageSize = 100000 // 每次最多取多少条 + Page = 1 // 当前页数 + PageSize = 20 // 每页多少条数据 + MaxPageSize = 100000 // 每次最多取多少条 ) // 创建Db func CreateDb(configFile string) *xorm.Engine { - config := getDbConfig(configFile) - dsn := getDbEngineDSN(config["engine"], config) - engine, err := xorm.NewEngine(config["engine"], dsn) - if err != nil { - panic(err) - } - if config["prefix"] != "" { - // 设置表前缀 - mapper := core.NewPrefixMapper(core.SnakeMapper{}, config["prefix"]) - engine.SetTableMapper(mapper) - } - // 本地环境开始日志 - if macaron.Env == macaron.DEV { - engine.ShowSQL(true) - engine.Logger().SetLevel(core.LOG_DEBUG) - } + config := getDbConfig(configFile) + dsn := getDbEngineDSN(config["engine"], config) + engine, err := xorm.NewEngine(config["engine"], dsn) + if err != nil { + panic(err) + } + if config["prefix"] != "" { + // 设置表前缀 + mapper := core.NewPrefixMapper(core.SnakeMapper{}, config["prefix"]) + engine.SetTableMapper(mapper) + } + // 本地环境开始日志 + if macaron.Env == macaron.DEV { + engine.ShowSQL(true) + engine.Logger().SetLevel(core.LOG_DEBUG) + } - return engine + return engine } // 获取数据库引擎DSN mysql,sqlite func getDbEngineDSN(engine string, config map[string]string) string { - engine = strings.ToLower(engine) - var dsn string = "" - switch engine { - case "mysql": - dsn = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s", - config["user"], - config["password"], - config["host"], - config["port"], - config["database"], - config["charset"]) - } + engine = strings.ToLower(engine) + var dsn string = "" + switch engine { + case "mysql": + dsn = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s", + config["user"], + config["password"], + config["host"], + config["port"], + config["database"], + config["charset"]) + } - return dsn + return dsn } // 获取数据库配置 func getDbConfig(configFile string) map[string]string { - config, err := setting.Read(configFile) - if err != nil { - panic(err) - } - section := config.Section("db") - if err != nil { - panic(err) - } - var db map[string]string = make(map[string]string) - db["user"] = section.Key("user").String() - db["password"] = section.Key("password").String() - db["host"] = section.Key("host").String() - db["port"] = section.Key("port").String() - db["database"] = section.Key("database").String() - db["charset"] = section.Key("charset").String() - db["prefix"] = section.Key("prefix").String() - db["engine"] = section.Key("engine").String() + config, err := setting.Read(configFile) + if err != nil { + panic(err) + } + section := config.Section("db") + if err != nil { + panic(err) + } + var db map[string]string = make(map[string]string) + db["user"] = section.Key("user").String() + db["password"] = section.Key("password").String() + db["host"] = section.Key("host").String() + db["port"] = section.Key("port").String() + db["database"] = section.Key("database").String() + db["charset"] = section.Key("charset").String() + db["prefix"] = section.Key("prefix").String() + db["engine"] = section.Key("engine").String() - return db + return db } diff --git a/models/task.go b/models/task.go index a054bdb..304c906 100644 --- a/models/task.go +++ b/models/task.go @@ -1,7 +1,7 @@ package models import ( - "time" + "time" ) type Protocol int8 @@ -9,96 +9,96 @@ type Protocol int8 type TaskType int8 const ( - HTTP Protocol = 1 - SSHCommand Protocol = 2 - SSHScript Protocol = 3 + HTTP Protocol = 1 + SSHCommand Protocol = 2 + SSHScript Protocol = 3 ) const ( - Timing TaskType = 1 - Delay TaskType = 2 + Timing TaskType = 1 + Delay TaskType = 2 ) // 任务 type Task struct { - Id int `xorm:"int pk autoincr"` - Name string `xorm:"varchar(64) notnull"` // 任务名称 - Spec string `xorm:"varchar(64) notnull"` // crontab 时间格式 - Protocol Protocol `xorm:"tinyint notnull"` // 协议 1:http 2:ssh-command 3:ssh-script - Type TaskType `xorm:"tinyint notnull default 1"` // 任务类型 1: 定时任务 2: 延时任务 - Command string `xorm:"varchar(512) notnull"` // URL地址或shell命令 - Timeout int `xorm:"mediumint notnull default 0"` // 任务执行超时时间(单位秒),0不限制 - Delay int `xorm:"int notnull default 0"` // 延时任务,延时时间(单位秒) - SshHosts string `xorm:"varchar(512) notnull defalut '' "` // SSH主机名, host id,逗号分隔 - Remark string `xorm:"varchar(512) notnull default ''"` // 备注 - Created time.Time `xorm:"datetime notnull created"` // 创建时间 - Deleted time.Time `xorm:"datetime deleted"` // 删除时间 - Status Status `xorm:"tinyint notnull default 1"` // 状态 1:正常 0:停止 - Page int `xorm:"-"` - PageSize int `xorm:"-"` + Id int `xorm:"int pk autoincr"` + Name string `xorm:"varchar(64) notnull"` // 任务名称 + Spec string `xorm:"varchar(64) notnull"` // crontab 时间格式 + Protocol Protocol `xorm:"tinyint notnull"` // 协议 1:http 2:ssh-command 3:ssh-script + Type TaskType `xorm:"tinyint notnull default 1"` // 任务类型 1: 定时任务 2: 延时任务 + Command string `xorm:"varchar(512) notnull"` // URL地址或shell命令 + Timeout int `xorm:"mediumint notnull default 0"` // 任务执行超时时间(单位秒),0不限制 + Delay int `xorm:"int notnull default 0"` // 延时任务,延时时间(单位秒) + SshHosts string `xorm:"varchar(512) notnull defalut '' "` // SSH主机名, host id,逗号分隔 + Remark string `xorm:"varchar(512) notnull default ''"` // 备注 + Created time.Time `xorm:"datetime notnull created"` // 创建时间 + Deleted time.Time `xorm:"datetime deleted"` // 删除时间 + Status Status `xorm:"tinyint notnull default 1"` // 状态 1:正常 0:停止 + Page int `xorm:"-"` + PageSize int `xorm:"-"` } // 新增 func (task *Task) Create() (insertId int, err error) { - task.Status = Enabled + task.Status = Enabled - _, err = Db.Insert(task) - if err == nil { - insertId = task.Id - } + _, err = Db.Insert(task) + if err == nil { + insertId = task.Id + } - return + return } // 更新 func (task *Task) Update(id int, data CommonMap) (int64, error) { - return Db.Table(task).ID(id).Update(data) + return Db.Table(task).ID(id).Update(data) } // 删除 func (task *Task) Delete(id int) (int64, error) { - return Db.Id(id).Delete(task) + return Db.Id(id).Delete(task) } // 禁用 func (task *Task) Disable(id int) (int64, error) { - return task.Update(id, CommonMap{"status": Disabled}) + return task.Update(id, CommonMap{"status": Disabled}) } // 激活 func (task *Task) Enable(id int) (int64, error) { - return task.Update(id, CommonMap{"status": Enabled}) + return task.Update(id, CommonMap{"status": Enabled}) } func (task *Task) ActiveList() ([]Task, error) { - task.parsePageAndPageSize() - list := make([]Task, 0) - err := Db.Where("status = ?", Enabled).Desc("id").Find(&list) + task.parsePageAndPageSize() + list := make([]Task, 0) + err := Db.Where("status = ?", Enabled).Desc("id").Find(&list) - return list, err + return list, err } func (task *Task) List() ([]Task, error) { - task.parsePageAndPageSize() - list := make([]Task, 0) - err := Db.Desc("id").Limit(task.PageSize, task.pageLimitOffset()).Find(&list) + task.parsePageAndPageSize() + list := make([]Task, 0) + err := Db.Desc("id").Limit(task.PageSize, task.pageLimitOffset()).Find(&list) - return list, err + return list, err } func (taskLog *TaskLog) Total() (int64, error) { - return Db.Count(taskLog) + return Db.Count(taskLog) } func (taskLog *TaskLog) parsePageAndPageSize() { - if taskLog.Page <= 0 { - taskLog.Page = Page - } - if taskLog.PageSize >= 0 || taskLog.PageSize > MaxPageSize { - taskLog.PageSize = PageSize - } + if taskLog.Page <= 0 { + taskLog.Page = Page + } + if taskLog.PageSize >= 0 || taskLog.PageSize > MaxPageSize { + taskLog.PageSize = PageSize + } } func (taskLog *TaskLog) pageLimitOffset() int { - return (taskLog.Page - 1) * taskLog.PageSize + return (taskLog.Page - 1) * taskLog.PageSize } diff --git a/models/task_log.go b/models/task_log.go index d133e93..0b691c9 100644 --- a/models/task_log.go +++ b/models/task_log.go @@ -1,62 +1,62 @@ package models import ( - "time" + "time" ) // 任务执行日志 type TaskLog struct { - Id int `xorm:"int pk autoincr"` - TaskId int `xorm:"int not null"` // 任务ID - StartTime time.Time `xorm:"datetime created"` // 开始执行时间 - EndTime time.Time `xorm:"datetime updated"` // 执行完成(失败)时间 - Status Status `xorm:"tinyint notnull default 1"` // 状态 1:执行中 2:执行完毕 0:执行失败 - Result string `xorm:"varchar(65535) notnull defalut '' "` // 执行结果 - Page int `xorm:"-"` - PageSize int `xorm:"-"` + Id int `xorm:"int pk autoincr"` + TaskId int `xorm:"int not null"` // 任务ID + StartTime time.Time `xorm:"datetime created"` // 开始执行时间 + EndTime time.Time `xorm:"datetime updated"` // 执行完成(失败)时间 + Status Status `xorm:"tinyint notnull default 1"` // 状态 1:执行中 2:执行完毕 0:执行失败 + Result string `xorm:"varchar(65535) notnull defalut '' "` // 执行结果 + Page int `xorm:"-"` + PageSize int `xorm:"-"` } func (taskLog *TaskLog) Create() (insertId int, err error) { - taskLog.Status = Running + taskLog.Status = Running - _, err = Db.Insert(taskLog) - if err == nil { - insertId = taskLog.Id - } + _, err = Db.Insert(taskLog) + if err == nil { + insertId = taskLog.Id + } - return + return } // 更新 func (taskLog *TaskLog) Update(id int, data CommonMap) (int64, error) { - return Db.Table(taskLog).ID(id).Update(data) + return Db.Table(taskLog).ID(id).Update(data) } func (taskLog *TaskLog) setStatus(id int, status Status) (int64, error) { - return taskLog.Update(id, CommonMap{"status": status}) + return taskLog.Update(id, CommonMap{"status": status}) } func (taskLog *TaskLog) List() ([]TaskLog, error) { - taskLog.parsePageAndPageSize() - list := make([]TaskLog, 0) - err := Db.Desc("id").Limit(taskLog.PageSize, taskLog.pageLimitOffset()).Find(&list) + taskLog.parsePageAndPageSize() + list := make([]TaskLog, 0) + err := Db.Desc("id").Limit(taskLog.PageSize, taskLog.pageLimitOffset()).Find(&list) - return list, err + return list, err } func (task *Task) Total() (int64, error) { - return Db.Count(task) + return Db.Count(task) } func (task *Task) parsePageAndPageSize() { - if task.Page <= 0 { - task.Page = Page - } - if task.PageSize >= 0 || task.PageSize > MaxPageSize { - task.PageSize = PageSize - } + if task.Page <= 0 { + task.Page = Page + } + if task.PageSize >= 0 || task.PageSize > MaxPageSize { + task.PageSize = PageSize + } } func (task *Task) pageLimitOffset() int { - return (task.Page - 1) * task.PageSize + return (task.Page - 1) * task.PageSize } diff --git a/models/user.go b/models/user.go index 384023f..d48e97b 100644 --- a/models/user.go +++ b/models/user.go @@ -1,118 +1,118 @@ package models import ( - "github.com/ouqiang/cron-scheduler/modules/utils" - "time" + "github.com/ouqiang/cron-scheduler/modules/utils" + "time" ) const PasswordSaltLength = 6 // 用户model type User struct { - Id int `xorm:"pk autoincr notnull "` - Name string `xorm:"varchar(32) notnull unique"` // 用户名 - Password string `xorm:"char(32) notnull "` // 密码 - Salt string `xorm:"char(6) notnull "` // 密码盐值 - Email string `xorm:"varchar(50) notnull unique default '' "` // 邮箱 - Created time.Time `xorm:"datetime notnull created"` - Updated time.Time `xorm:"datetime updated"` - Deleted time.Time `xorm:"datetime deleted"` - IsAdmin int8 `xorm:"tinyint notnull default 0"` // 是否是管理员 1:管理员 0:普通用户 - Status Status `xorm:"tinyint notnull default 1"` // 1: 正常 0:禁用 - Page int `xorm:"-"` - PageSize int `xorm:"-"` + Id int `xorm:"pk autoincr notnull "` + Name string `xorm:"varchar(32) notnull unique"` // 用户名 + Password string `xorm:"char(32) notnull "` // 密码 + Salt string `xorm:"char(6) notnull "` // 密码盐值 + Email string `xorm:"varchar(50) notnull unique default '' "` // 邮箱 + Created time.Time `xorm:"datetime notnull created"` + Updated time.Time `xorm:"datetime updated"` + Deleted time.Time `xorm:"datetime deleted"` + IsAdmin int8 `xorm:"tinyint notnull default 0"` // 是否是管理员 1:管理员 0:普通用户 + Status Status `xorm:"tinyint notnull default 1"` // 1: 正常 0:禁用 + Page int `xorm:"-"` + PageSize int `xorm:"-"` } // 新增 func (user *User) Create() (insertId int, err error) { - user.Status = Enabled - user.Salt = user.generateSalt() - user.Password = user.encryptPassword(user.Password, user.Salt) + user.Status = Enabled + user.Salt = user.generateSalt() + user.Password = user.encryptPassword(user.Password, user.Salt) - _, err = Db.Insert(user) - if err == nil { - insertId = user.Id - } + _, err = Db.Insert(user) + if err == nil { + insertId = user.Id + } - return + return } // 更新 func (user *User) Update(id int, data CommonMap) (int64, error) { - return Db.Table(user).ID(id).Update(data) + return Db.Table(user).ID(id).Update(data) } // 删除 func (user *User) Delete(id int) (int64, error) { - return Db.Id(id).Delete(user) + return Db.Id(id).Delete(user) } // 禁用 func (user *User) Disable(id int) (int64, error) { - return user.Update(id, CommonMap{"status": Disabled}) + return user.Update(id, CommonMap{"status": Disabled}) } // 激活 func (user *User) Enable(id int) (int64, error) { - return user.Update(id, CommonMap{"status": Enabled}) + return user.Update(id, CommonMap{"status": Enabled}) } // 验证用户名和密码 func (user *User) Match(username, password string) bool { - where := "(name = ? OR email = ?)" - _, err := Db.Where(where, username, username).Get(user) - if err != nil { - return false - } - hashPassword := user.encryptPassword(password, user.Salt) - if hashPassword != user.Password { - return false - } + where := "(name = ? OR email = ?)" + _, err := Db.Where(where, username, username).Get(user) + if err != nil { + return false + } + hashPassword := user.encryptPassword(password, user.Salt) + if hashPassword != user.Password { + return false + } - return true + return true } // 用户名是否存在 func (user *User) UsernameExists(username string) (int64, error) { - return Db.Where("name = ?", username).Count(user) + return Db.Where("name = ?", username).Count(user) } // 邮箱地址是否存在 func (user *User) EmailExists(email string) (int64, error) { - return Db.Where("email = ?", email).Count(user) + return Db.Where("email = ?", email).Count(user) } func (user *User) List() ([]User, error) { - user.parsePageAndPageSize() - list := make([]User, 0) - err := Db.Desc("id").Limit(user.PageSize, user.pageLimitOffset()).Find(&list) + user.parsePageAndPageSize() + list := make([]User, 0) + err := Db.Desc("id").Limit(user.PageSize, user.pageLimitOffset()).Find(&list) - return list, err + return list, err } func (user *User) Total() (int64, error) { - return Db.Count(user) + return Db.Count(user) } func (user *User) parsePageAndPageSize() { - if user.Page <= 0 { - user.Page = Page - } - if user.PageSize >= 0 || user.PageSize > MaxPageSize { - user.PageSize = PageSize - } + if user.Page <= 0 { + user.Page = Page + } + if user.PageSize >= 0 || user.PageSize > MaxPageSize { + user.PageSize = PageSize + } } func (user *User) pageLimitOffset() int { - return (user.Page - 1) * user.PageSize + return (user.Page - 1) * user.PageSize } // 密码加密 func (user *User) encryptPassword(password, salt string) string { - return utils.Md5(password + salt) + return utils.Md5(password + salt) } // 生成密码盐值 func (user *User) generateSalt() string { - return utils.RandString(PasswordSaltLength) + return utils.RandString(PasswordSaltLength) } diff --git a/modules/ansible/ansible.go b/modules/ansible/ansible.go index 0fccc9e..ff8202b 100644 --- a/modules/ansible/ansible.go +++ b/modules/ansible/ansible.go @@ -3,8 +3,8 @@ package ansible // ansible ad-hoc 命令封装 import ( - "errors" - "github.com/ouqiang/cron-scheduler/modules/utils" + "errors" + "github.com/ouqiang/cron-scheduler/modules/utils" ) /** @@ -15,30 +15,30 @@ import ( * args 传递给module的参数 */ func ExecCommand(hosts string, hostFile string, module string, args ...string) (output string, err error) { - if hosts == "" || hostFile == "" || module == "" { - err = errors.New("参数不完整") - return - } - commandArgs := []string{hosts, "-i", hostFile, "-m", module} - if len(args) > 0 { - commandArgs = append(commandArgs, args...) - } - output, err = utils.ExecShell("ansible", commandArgs...) + if hosts == "" || hostFile == "" || module == "" { + err = errors.New("参数不完整") + return + } + commandArgs := []string{hosts, "-i", hostFile, "-m", module} + if len(args) > 0 { + commandArgs = append(commandArgs, args...) + } + output, err = utils.ExecShell("ansible", commandArgs...) - return + return } // 执行shell命令 func Shell(hosts string, hostFile string, args ...string) (output string, err error) { - return ExecCommand(hosts, hostFile, "shell", args...) + return ExecCommand(hosts, hostFile, "shell", args...) } // 复制本地脚本到远程执行 func Script(hosts string, hostFile string, args ...string) (output string, err error) { - return ExecCommand(hosts, hostFile, "script", args...) + return ExecCommand(hosts, hostFile, "script", args...) } // 测试主机是否可通 func Ping(hosts string, hostFile string) (output string, err error) { - return ExecCommand(hosts, hostFile, "ping") + return ExecCommand(hosts, hostFile, "ping") } diff --git a/modules/ansible/host.go b/modules/ansible/host.go index 7c143ee..ea1d108 100644 --- a/modules/ansible/host.go +++ b/modules/ansible/host.go @@ -1,67 +1,67 @@ package ansible import ( - "bytes" - "github.com/ouqiang/cron-scheduler/models" - "github.com/ouqiang/cron-scheduler/modules/utils" - "io/ioutil" - "strconv" - "sync" + "bytes" + "github.com/ouqiang/cron-scheduler/models" + "github.com/ouqiang/cron-scheduler/modules/utils" + "io/ioutil" + "strconv" + "sync" ) // 主机名 var DefaultHosts *Hosts type Hosts struct { - sync.RWMutex - filename string + sync.RWMutex + filename string } func NewHosts(hostFilename string) *Hosts { - h := &Hosts{sync.RWMutex{}, hostFilename} - h.Write() + h := &Hosts{sync.RWMutex{}, hostFilename} + h.Write() - return h + return h } // 获取hosts文件名 func (h *Hosts) GetFilename() string { - h.RLock() - defer h.RUnlock() + h.RLock() + defer h.RUnlock() - return h.filename + return h.filename } // 写入hosts func (h *Hosts) Write() { - host := new(models.Host) - hostModels, err := host.List() - if err != nil { - utils.RecordLog(err) - return - } - if len(hostModels) == 0 { - utils.RecordLog("hosts内容为空") - return - } - buffer := bytes.Buffer{} - for _, hostModel := range hostModels { - buffer.WriteString(strconv.Itoa(int(hostModel.Id))) - buffer.WriteString(" ansible_ssh_host=") - buffer.WriteString(hostModel.Name) - buffer.WriteString(" ansible_ssh_port=") - buffer.WriteString(strconv.Itoa(hostModel.Port)) - buffer.WriteString(" ansible_ssh_user=") - buffer.WriteString(hostModel.Username) - if hostModel.LoginType != models.PublicKey && hostModel.Password != "" { - buffer.WriteString(" ansible_ssh_pass=") - buffer.WriteString(hostModel.Password) - } - buffer.WriteString("\n") - } - h.Lock() - defer h.Unlock() - err = ioutil.WriteFile(h.filename, buffer.Bytes(), 0644) + host := new(models.Host) + hostModels, err := host.List() + if err != nil { + utils.RecordLog(err) + return + } + if len(hostModels) == 0 { + utils.RecordLog("hosts内容为空") + return + } + buffer := bytes.Buffer{} + for _, hostModel := range hostModels { + buffer.WriteString(strconv.Itoa(int(hostModel.Id))) + buffer.WriteString(" ansible_ssh_host=") + buffer.WriteString(hostModel.Name) + buffer.WriteString(" ansible_ssh_port=") + buffer.WriteString(strconv.Itoa(hostModel.Port)) + buffer.WriteString(" ansible_ssh_user=") + buffer.WriteString(hostModel.Username) + if hostModel.LoginType != models.PublicKey && hostModel.Password != "" { + buffer.WriteString(" ansible_ssh_pass=") + buffer.WriteString(hostModel.Password) + } + buffer.WriteString("\n") + } + h.Lock() + defer h.Unlock() + err = ioutil.WriteFile(h.filename, buffer.Bytes(), 0644) - return + return } diff --git a/modules/app/app.go b/modules/app/app.go index 6e2823a..418a1fb 100644 --- a/modules/app/app.go +++ b/modules/app/app.go @@ -1,108 +1,108 @@ package app import ( - "os" - "runtime" + "os" + "runtime" - "github.com/ouqiang/cron-scheduler/models" - "github.com/ouqiang/cron-scheduler/modules/ansible" - "github.com/ouqiang/cron-scheduler/modules/crontask" - "github.com/ouqiang/cron-scheduler/modules/utils" - "github.com/ouqiang/cron-scheduler/service" + "github.com/ouqiang/cron-scheduler/models" + "github.com/ouqiang/cron-scheduler/modules/ansible" + "github.com/ouqiang/cron-scheduler/modules/crontask" + "github.com/ouqiang/cron-scheduler/modules/utils" + "github.com/ouqiang/cron-scheduler/service" ) var ( - AppDir string // 应用根目录 - ConfDir string // 配置目录 - LogDir string // 日志目录 - DataDir string // 数据目录,存放session文件等 - AppConfig string // 应用配置文件 - AnsibleHosts string // ansible hosts文件 - Installed bool // 应用是否安装过 + AppDir string // 应用根目录 + ConfDir string // 配置目录 + LogDir string // 日志目录 + DataDir string // 数据目录,存放session文件等 + AppConfig string // 应用配置文件 + AnsibleHosts string // ansible hosts文件 + Installed bool // 应用是否安装过 ) func InitEnv() { - CheckEnv() - wd, err := os.Getwd() - if err != nil { - panic(err) - } - AppDir = wd - ConfDir = AppDir + "/conf" - LogDir = AppDir + "/log" - DataDir = AppDir + "/data" - AppConfig = ConfDir + "/app.ini" - AnsibleHosts = ConfDir + "/ansible_hosts.ini" - checkDirExists(ConfDir, LogDir, DataDir) - // ansible配置文件目录 - os.Setenv("ANSIBLE_CONFIG", ConfDir) - Installed = IsInstalled() - if Installed { - InitDb() - InitResource() - } + CheckEnv() + wd, err := os.Getwd() + if err != nil { + panic(err) + } + AppDir = wd + ConfDir = AppDir + "/conf" + LogDir = AppDir + "/log" + DataDir = AppDir + "/data" + AppConfig = ConfDir + "/app.ini" + AnsibleHosts = ConfDir + "/ansible_hosts.ini" + checkDirExists(ConfDir, LogDir, DataDir) + // ansible配置文件目录 + os.Setenv("ANSIBLE_CONFIG", ConfDir) + Installed = IsInstalled() + if Installed { + InitDb() + InitResource() + } } // 判断应用是否安装过 func IsInstalled() bool { - _, err := os.Stat(ConfDir + "/install.lock") - if os.IsNotExist(err) { - return false - } + _, err := os.Stat(ConfDir + "/install.lock") + if os.IsNotExist(err) { + return false + } - return true + return true } // 检测环境 func CheckEnv() { - // ansible不支持安装在windows上, windows只能作为被控机 - if runtime.GOOS == "windows" { - panic("不支持在windows上运行") - } - _, err := utils.ExecShell("ansible", "--version") - if err != nil { - panic(err) - } - _, err = utils.ExecShell("ansible-playbook", "--version") - if err != nil { - panic(err) - } + // ansible不支持安装在windows上, windows只能作为被控机 + if runtime.GOOS == "windows" { + panic("不支持在windows上运行") + } + _, err := utils.ExecShell("ansible", "--version") + if err != nil { + panic(err) + } + _, err = utils.ExecShell("ansible-playbook", "--version") + if err != nil { + panic(err) + } } // 创建安装锁文件 func CreateInstallLock() error { - _, err := os.Create(ConfDir + "/install.lock") - if err != nil { - utils.RecordLog("创建安装锁文件失败") - } + _, err := os.Create(ConfDir + "/install.lock") + if err != nil { + utils.RecordLog("创建安装锁文件失败") + } - return err + return err } // 初始化资源 func InitResource() { - // 初始化ansible Hosts - ansible.DefaultHosts = ansible.NewHosts(AnsibleHosts) - // 初始化定时任务 - crontask.DefaultCronTask = crontask.NewCronTask() - serviceTask := new(service.Task) - serviceTask.Initialize() + // 初始化ansible Hosts + ansible.DefaultHosts = ansible.NewHosts(AnsibleHosts) + // 初始化定时任务 + crontask.DefaultCronTask = crontask.NewCronTask() + serviceTask := new(service.Task) + serviceTask.Initialize() } // 初始化DB func InitDb() { - models.Db = models.CreateDb(AppConfig) + models.Db = models.CreateDb(AppConfig) } // 检测目录是否存在 func checkDirExists(path ...string) { - for _, value := range path { - _, err := os.Stat(value) - if os.IsNotExist(err) { - panic(value + "目录不存在") - } - if os.IsPermission(err) { - panic(value + "目录无权限操作") - } - } + for _, value := range path { + _, err := os.Stat(value) + if os.IsNotExist(err) { + panic(value + "目录不存在") + } + if os.IsPermission(err) { + panic(value + "目录无权限操作") + } + } } diff --git a/modules/crontask/cron_task.go b/modules/crontask/cron_task.go index c85f49e..63b033c 100644 --- a/modules/crontask/cron_task.go +++ b/modules/crontask/cron_task.go @@ -1,10 +1,10 @@ package crontask import ( - "errors" - "github.com/robfig/cron" - "strings" - "sync" + "errors" + "github.com/robfig/cron" + "strings" + "sync" ) var DefaultCronTask *CronTask @@ -12,76 +12,76 @@ var DefaultCronTask *CronTask type CronMap map[string]*cron.Cron type CronTask struct { - sync.RWMutex - tasks CronMap + sync.RWMutex + tasks CronMap } func NewCronTask() *CronTask { - return &CronTask{ - sync.RWMutex{}, - make(CronMap), - } + return &CronTask{ + sync.RWMutex{}, + make(CronMap), + } } // 新增定时任务,如果name存在,则添加失败 // name 任务名称 // spec crontab时间格式定义 可定义多个时间\n分隔 func (cronTask *CronTask) Add(name string, spec string, cmd cron.FuncJob) (err error) { - if name == "" || spec == "" || cmd == nil { - return errors.New("参数不完整") - } - if cronTask.IsExist(name) { - return errors.New("任务已存在") - } + if name == "" || spec == "" || cmd == nil { + return errors.New("参数不完整") + } + if cronTask.IsExist(name) { + return errors.New("任务已存在") + } - spec = strings.TrimSpace(spec) - cronTask.Lock() - defer cronTask.Unlock() - cronTask.tasks[name] = cron.New() - specs := strings.Split(spec, "|||") - for _, item := range specs { - _, err = cron.Parse(item) - if err != nil { - return err - } - } - for _, item := range specs { - err = cronTask.tasks[name].AddFunc(item, cmd) - } - cronTask.tasks[name].Start() + spec = strings.TrimSpace(spec) + cronTask.Lock() + defer cronTask.Unlock() + cronTask.tasks[name] = cron.New() + specs := strings.Split(spec, "|||") + for _, item := range specs { + _, err = cron.Parse(item) + if err != nil { + return err + } + } + for _, item := range specs { + err = cronTask.tasks[name].AddFunc(item, cmd) + } + cronTask.tasks[name].Start() - return err + return err } // 任务不存在则新增,任务已存在则删除后新增 func (cronTask *CronTask) AddOrReplace(name string, spec string, cmd cron.FuncJob) error { - if cronTask.IsExist(name) { - cronTask.Delete(name) - } + if cronTask.IsExist(name) { + cronTask.Delete(name) + } - return cronTask.Add(name, spec, cmd) + return cronTask.Add(name, spec, cmd) } // 判断任务是否存在 func (cronTask *CronTask) IsExist(name string) bool { - cronTask.RLock() - defer cronTask.RUnlock() - _, ok := cronTask.tasks[name] + cronTask.RLock() + defer cronTask.RUnlock() + _, ok := cronTask.tasks[name] - return ok + return ok } // 停止任务 func (cronTask *CronTask) Stop(name string) { - if cronTask.IsExist(name) { - cronTask.tasks[name].Stop() - } + if cronTask.IsExist(name) { + cronTask.tasks[name].Stop() + } } // 删除任务 func (cronTask *CronTask) Delete(name string) { - cronTask.Stop(name) - cronTask.Lock() - defer cronTask.Unlock() - delete(cronTask.tasks, name) + cronTask.Stop(name) + cronTask.Lock() + defer cronTask.Unlock() + delete(cronTask.tasks, name) } diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 1815c93..457a429 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -1,43 +1,43 @@ package setting import ( - "errors" - "gopkg.in/ini.v1" + "errors" + "gopkg.in/ini.v1" ) // 读取配置 func Read(filename string) (config *ini.File, err error) { - config, err = ini.Load(filename) - if err != nil { - return - } + config, err = ini.Load(filename) + if err != nil { + return + } - return + return } // 写入配置 func Write(config map[string]map[string]string, filename string) error { - if len(config) == 0 { - return errors.New("参数不能为空") - } + if len(config) == 0 { + return errors.New("参数不能为空") + } - file := ini.Empty() - for sectionName, items := range config { - if sectionName == "" { - return errors.New("节名称不能为空") - } - section, err := file.NewSection(sectionName) - if err != nil { - return err - } - for key, value := range items { - _, err = section.NewKey(key, value) - if err != nil { - return err - } - } - } - err := file.SaveTo(filename) + file := ini.Empty() + for sectionName, items := range config { + if sectionName == "" { + return errors.New("节名称不能为空") + } + section, err := file.NewSection(sectionName) + if err != nil { + return err + } + for key, value := range items { + _, err = section.NewKey(key, value) + if err != nil { + return err + } + } + } + err := file.SaveTo(filename) - return err + return err } diff --git a/modules/utils/json.go b/modules/utils/json.go index 3aedd59..d89aaee 100644 --- a/modules/utils/json.go +++ b/modules/utils/json.go @@ -5,9 +5,9 @@ import "encoding/json" // json 格式输出 type response struct { - Code int `json:"code"` // 状态码 0:成功 非0:失败 - Message string `json:"message"` // 信息 - Data interface{} `json:"data"` // 数据 + Code int `json:"code"` // 状态码 0:成功 非0:失败 + Message string `json:"message"` // 信息 + Data interface{} `json:"data"` // 数据 } type Json struct{} @@ -16,24 +16,24 @@ const ResponseSuccess = 0 const ResponseFailure = 1 func (j *Json) Success(message string, data interface{}) string { - return j.response(ResponseSuccess, message, data) + return j.response(ResponseSuccess, message, data) } func (j *Json) Failure(code int, message string) string { - return j.response(code, message, nil) + return j.response(code, message, nil) } func (j *Json) response(code int, message string, data interface{}) string { - resp := response{ - Code: code, - Message: message, - Data: data, - } + resp := response{ + Code: code, + Message: message, + Data: data, + } - result, err := json.Marshal(resp) - if err != nil { - RecordLog(err) - } + result, err := json.Marshal(resp) + if err != nil { + RecordLog(err) + } - return string(result) + return string(result) } diff --git a/modules/utils/utils.go b/modules/utils/utils.go index 31ced62..7db3f36 100644 --- a/modules/utils/utils.go +++ b/modules/utils/utils.go @@ -1,52 +1,52 @@ package utils import ( - "crypto/md5" - "encoding/hex" - "log" - "math/rand" - "os/exec" - "time" + "crypto/md5" + "encoding/hex" + "log" + "math/rand" + "os/exec" + "time" ) // 执行shell命令 func ExecShell(command string, args ...string) (string, error) { - result, err := exec.Command(command, args...).CombinedOutput() + result, err := exec.Command(command, args...).CombinedOutput() - return string(result), err + return string(result), err } // 生成长度为length的随机字符串 func RandString(length int64) string { - sources := []byte("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") - result := []byte{} - r := rand.New(rand.NewSource(time.Now().UnixNano())) - sourceLength := len(sources) - var i int64 = 0 - for ; i < length; i++ { - result = append(result, sources[r.Intn(sourceLength)]) - } + sources := []byte("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + result := []byte{} + r := rand.New(rand.NewSource(time.Now().UnixNano())) + sourceLength := len(sources) + var i int64 = 0 + for ; i < length; i++ { + result = append(result, sources[r.Intn(sourceLength)]) + } - return string(result) + return string(result) } // 生成32位MD5摘要 func Md5(str string) string { - m := md5.New() - m.Write([]byte(str)) + m := md5.New() + m.Write([]byte(str)) - return hex.EncodeToString(m.Sum(nil)) + return hex.EncodeToString(m.Sum(nil)) } // 生成0-max之间随机数 func RandNumber(max int) int { - r := rand.New(rand.NewSource(time.Now().UnixNano())) + r := rand.New(rand.NewSource(time.Now().UnixNano())) - return r.Intn(max) + return r.Intn(max) } // 日志记录 // todo 保存到哪里 文件,数据库还是elasticsearch?,暂时输出到终端 func RecordLog(v ...interface{}) { - log.Println(v) + log.Println(v) } diff --git a/modules/utils/utils_test.go b/modules/utils/utils_test.go index 25a5c7a..f9a9cdd 100644 --- a/modules/utils/utils_test.go +++ b/modules/utils/utils_test.go @@ -3,29 +3,29 @@ package utils import "testing" func TestExecShell(t *testing.T) { - _, err := ExecShell("ls") - if err != nil { - t.Fatal(err) - } + _, err := ExecShell("ls") + if err != nil { + t.Fatal(err) + } } func TestRandString(t *testing.T) { - str := RandString(32) - if len(str) != 32 { - t.Fatalf("长度不匹配,目标长度32, 实际%d-%s", len(str), str) - } + str := RandString(32) + if len(str) != 32 { + t.Fatalf("长度不匹配,目标长度32, 实际%d-%s", len(str), str) + } } func TestMd5(t *testing.T) { - str := Md5("123456") - if len(str) != 32 { - t.Fatalf("长度不匹配,目标长度32, 实际%d-%s", len(str), str) - } + str := Md5("123456") + if len(str) != 32 { + t.Fatalf("长度不匹配,目标长度32, 实际%d-%s", len(str), str) + } } func TestRandNumber(t *testing.T) { - num := RandNumber(10000) - if num <= 0 && num >= 10000 { - t.Fatalf("随机数不在有效范围内-%d", num) - } + num := RandNumber(10000) + if num <= 0 && num >= 10000 { + t.Fatalf("随机数不在有效范围内-%d", num) + } } diff --git a/routers/install/install.go b/routers/install/install.go index d9e540e..2758b37 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -1,108 +1,108 @@ package install import ( - "github.com/ouqiang/cron-scheduler/models" - "github.com/ouqiang/cron-scheduler/modules/app" - "github.com/ouqiang/cron-scheduler/modules/setting" - "github.com/ouqiang/cron-scheduler/modules/utils" - "gopkg.in/macaron.v1" - "strconv" + "github.com/ouqiang/cron-scheduler/models" + "github.com/ouqiang/cron-scheduler/modules/app" + "github.com/ouqiang/cron-scheduler/modules/setting" + "github.com/ouqiang/cron-scheduler/modules/utils" + "gopkg.in/macaron.v1" + "strconv" ) // 系统安装 type InstallForm struct { - DbType string `binding:"IN(mysql)"` - DbHost string `binding:"Required"` - DbPort int `binding:"Required"` - DbUsername string `binding:"Required"` - DbPassword string `binding:"Required"` - DbName string `binding:"Required"` - DbTablePrefix string - AdminUsername string `binding:"Required;MinSize(3)"` - AdminPassword string `binding:"Required;MinSize(6)"` - AdminEmail string `binding:"Email"` + DbType string `binding:"IN(mysql)"` + DbHost string `binding:"Required"` + DbPort int `binding:"Required"` + DbUsername string `binding:"Required"` + DbPassword string `binding:"Required"` + DbName string `binding:"Required"` + DbTablePrefix string + AdminUsername string `binding:"Required;MinSize(3)"` + AdminPassword string `binding:"Required;MinSize(6)"` + AdminEmail string `binding:"Email"` } // 显示安装页面 func Show(ctx *macaron.Context) { - if app.Installed { - ctx.Redirect("/") - } - ctx.Data["Title"] = "安装" - ctx.Data["DisableNav"] = true - ctx.HTML(200, "install/show") + if app.Installed { + ctx.Redirect("/") + } + ctx.Data["Title"] = "安装" + ctx.Data["DisableNav"] = true + ctx.HTML(200, "install/show") } // 安装, func Install(ctx *macaron.Context, form InstallForm) string { - json := utils.Json{} - if app.Installed { - return json.Failure(utils.ResponseFailure, "系统已安装成功") - } - // 写入数据库配置 - err := writeConfig(form) - if err != nil { - utils.RecordLog(err) - return json.Failure(utils.ResponseFailure, "数据库配置写入文件失败") - } + json := utils.Json{} + if app.Installed { + return json.Failure(utils.ResponseFailure, "系统已安装成功") + } + // 写入数据库配置 + err := writeConfig(form) + if err != nil { + utils.RecordLog(err) + return json.Failure(utils.ResponseFailure, "数据库配置写入文件失败") + } - // 初始化Db - app.InitDb() - // 创建数据库表 - migration := new(models.Migration) - err = migration.Exec(form.DbName) - if err != nil { - utils.RecordLog(err) - return json.Failure(utils.ResponseFailure, "创建数据库表失败") - } + // 初始化Db + app.InitDb() + // 创建数据库表 + migration := new(models.Migration) + err = migration.Exec(form.DbName) + if err != nil { + utils.RecordLog(err) + return json.Failure(utils.ResponseFailure, "创建数据库表失败") + } - // 创建管理员账号 - err = createAdminUser(form) - if err != nil { - utils.RecordLog(err) - return json.Failure(utils.ResponseFailure, "创建管理员账号失败") - } + // 创建管理员账号 + err = createAdminUser(form) + if err != nil { + utils.RecordLog(err) + return json.Failure(utils.ResponseFailure, "创建管理员账号失败") + } - // 创建安装锁 - err = app.CreateInstallLock() - if err != nil { - utils.RecordLog(err) - return json.Failure(utils.ResponseFailure, "创建文件安装锁失败") - } + // 创建安装锁 + err = app.CreateInstallLock() + if err != nil { + utils.RecordLog(err) + return json.Failure(utils.ResponseFailure, "创建文件安装锁失败") + } - // 初始化定时任务等 - app.InitResource() + // 初始化定时任务等 + app.InitResource() - return json.Success("安装成功", nil) + return json.Success("安装成功", nil) } // 数据库配置写入文件 func writeConfig(form InstallForm) error { - dbConfig := map[string]map[string]string{ - "db": map[string]string{ - "engine": form.DbType, - "host": form.DbHost, - "port": strconv.Itoa(form.DbPort), - "user": form.DbUsername, - "password": form.DbPassword, - "database": form.DbName, - "prefix": form.DbTablePrefix, - "charset": "utf8", - }, - } + dbConfig := map[string]map[string]string{ + "db": map[string]string{ + "engine": form.DbType, + "host": form.DbHost, + "port": strconv.Itoa(form.DbPort), + "user": form.DbUsername, + "password": form.DbPassword, + "database": form.DbName, + "prefix": form.DbTablePrefix, + "charset": "utf8", + }, + } - return setting.Write(dbConfig, app.AppConfig) + return setting.Write(dbConfig, app.AppConfig) } // 创建管理员账号 func createAdminUser(form InstallForm) error { - user := new(models.User) - user.Name = form.AdminUsername - user.Password = form.AdminPassword - user.Email = form.AdminEmail - user.IsAdmin = 1 - _, err := user.Create() + user := new(models.User) + user.Name = form.AdminUsername + user.Password = form.AdminPassword + user.Email = form.AdminEmail + user.IsAdmin = 1 + _, err := user.Create() - return err + return err } diff --git a/routers/routers.go b/routers/routers.go index 965515f..f4e7f06 100644 --- a/routers/routers.go +++ b/routers/routers.go @@ -1,30 +1,30 @@ package routers import ( - "github.com/go-macaron/binding" - "github.com/ouqiang/cron-scheduler/routers/install" - "gopkg.in/macaron.v1" + "github.com/go-macaron/binding" + "github.com/ouqiang/cron-scheduler/routers/install" + "gopkg.in/macaron.v1" ) // 路由注册 func Register(m *macaron.Macaron) { - // 所有GET方法,自动注册HEAD方法 - m.SetAutoHead(true) - // 404错误 - m.NotFound(func(ctx *macaron.Context) { - ctx.HTML(404, "error/404") - }) - // 50x错误 - m.InternalServerError(func(ctx *macaron.Context) { - ctx.HTML(500, "error/500") - }) - // 首页 - m.Get("/", func(ctx *macaron.Context) string { - return "go home" - }) - // 系统安装 - m.Group("/install", func() { - m.Get("", install.Show) - m.Post("", binding.Bind(install.InstallForm{}), install.Install) - }) + // 所有GET方法,自动注册HEAD方法 + m.SetAutoHead(true) + // 404错误 + m.NotFound(func(ctx *macaron.Context) { + ctx.HTML(404, "error/404") + }) + // 50x错误 + m.InternalServerError(func(ctx *macaron.Context) { + ctx.HTML(500, "error/500") + }) + // 首页 + m.Get("/", func(ctx *macaron.Context) string { + return "go home" + }) + // 系统安装 + m.Group("/install", func() { + m.Get("", install.Show) + m.Post("", binding.Bind(install.InstallForm{}), install.Install) + }) } diff --git a/service/task.go b/service/task.go index af47131..c640048 100644 --- a/service/task.go +++ b/service/task.go @@ -1,175 +1,175 @@ package service import ( - "fmt" - "github.com/ouqiang/cron-scheduler/models" - "github.com/ouqiang/cron-scheduler/modules/ansible" - "github.com/ouqiang/cron-scheduler/modules/crontask" - "github.com/ouqiang/cron-scheduler/modules/utils" - "github.com/robfig/cron" - "io/ioutil" - "net/http" - "strconv" - "time" + "fmt" + "github.com/ouqiang/cron-scheduler/models" + "github.com/ouqiang/cron-scheduler/modules/ansible" + "github.com/ouqiang/cron-scheduler/modules/crontask" + "github.com/ouqiang/cron-scheduler/modules/utils" + "github.com/robfig/cron" + "io/ioutil" + "net/http" + "strconv" + "time" ) type Task struct{} // 初始化任务, 从数据库取出所有任务, 添加到定时任务并运行 func (task *Task) Initialize() { - taskModel := new(models.Task) - taskList, err := taskModel.ActiveList() - if err != nil { - utils.RecordLog("获取任务列表错误-", err.Error()) - return - } - if len(taskList) == 0 { - utils.RecordLog("任务列表为空") - return - } - for _, item := range taskList { - task.Add(item) - } + taskModel := new(models.Task) + taskList, err := taskModel.ActiveList() + if err != nil { + utils.RecordLog("获取任务列表错误-", err.Error()) + return + } + if len(taskList) == 0 { + utils.RecordLog("任务列表为空") + return + } + for _, item := range taskList { + task.Add(item) + } } // 添加任务 func (task *Task) Add(taskModel models.Task) { - taskFunc := createHandlerJob(taskModel) - if taskFunc == nil { - utils.RecordLog("添加任务#不存在的任务协议编号", taskModel.Protocol) - return - } - // 定时任务 - if taskModel.Type == models.Timing { - err := crontask.DefaultCronTask.AddOrReplace(strconv.Itoa(taskModel.Id), taskModel.Spec, taskFunc) - if err != nil { - utils.RecordLog(err) - } - } else if taskModel.Type == models.Delay { - // 延时任务 - time.AfterFunc(time.Duration(taskModel.Delay)*time.Second, taskFunc) - } + taskFunc := createHandlerJob(taskModel) + if taskFunc == nil { + utils.RecordLog("添加任务#不存在的任务协议编号", taskModel.Protocol) + return + } + // 定时任务 + if taskModel.Type == models.Timing { + err := crontask.DefaultCronTask.AddOrReplace(strconv.Itoa(taskModel.Id), taskModel.Spec, taskFunc) + if err != nil { + utils.RecordLog(err) + } + } else if taskModel.Type == models.Delay { + // 延时任务 + time.AfterFunc(time.Duration(taskModel.Delay)*time.Second, taskFunc) + } } type Handler interface { - Run(taskModel models.Task) (string, error) + Run(taskModel models.Task) (string, error) } // HTTP任务 type HTTPHandler struct{} func (h *HTTPHandler) Run(taskModel models.Task) (result string, err error) { - client := &http.Client{} - if taskModel.Timeout > 0 { - client.Timeout = time.Duration(taskModel.Timeout) * time.Second - } - req, err := http.NewRequest("POST", taskModel.Command, nil) - if err != nil { - utils.RecordLog("创建HTTP请求错误-", err.Error()) - return - } - req.Header.Set("Content-type", "application/x-www-form-urlencoded") - req.Header.Set("User-Agent", "golang-cron/scheduler") + client := &http.Client{} + if taskModel.Timeout > 0 { + client.Timeout = time.Duration(taskModel.Timeout) * time.Second + } + req, err := http.NewRequest("POST", taskModel.Command, nil) + if err != nil { + utils.RecordLog("创建HTTP请求错误-", err.Error()) + return + } + req.Header.Set("Content-type", "application/x-www-form-urlencoded") + req.Header.Set("User-Agent", "golang-cron/scheduler") - resp, err := client.Do(req) - defer func() { - if resp != nil { - resp.Body.Close() - } - }() - if err != nil { - utils.RecordLog("HTTP请求错误-", err.Error()) - return - } - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - utils.RecordLog("读取HTTP请求返回值失败-", err.Error()) - } + resp, err := client.Do(req) + defer func() { + if resp != nil { + resp.Body.Close() + } + }() + if err != nil { + utils.RecordLog("HTTP请求错误-", err.Error()) + return + } + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + utils.RecordLog("读取HTTP请求返回值失败-", err.Error()) + } - return string(body), err + return string(body), err } // SSH-command任务 type SSHCommandHandler struct{} func (ssh *SSHCommandHandler) Run(taskModel models.Task) (string, error) { - return execSSHHandler("shell", taskModel) + return execSSHHandler("shell", taskModel) } // SSH-script任务 type SSHScriptHandler struct{} func (ssh *SSHScriptHandler) Run(taskModel models.Task) (string, error) { - return execSSHHandler("script", taskModel) + return execSSHHandler("script", taskModel) } // SSH任务 func execSSHHandler(module string, taskModel models.Task) (string, error) { - var args []string = []string{taskModel.Command} - if taskModel.Timeout > 0 { - // -B 异步执行超时时间, -P 轮询时间 - args = append(args, "-B", strconv.Itoa(taskModel.Timeout), "-P", "10") - } - if module == "shell" { - return ansible.Shell(taskModel.SshHosts, ansible.DefaultHosts.GetFilename(), args...) - } - if module == "script" { - return ansible.Script(taskModel.SshHosts, ansible.DefaultHosts.GetFilename(), args...) - } + var args []string = []string{taskModel.Command} + if taskModel.Timeout > 0 { + // -B 异步执行超时时间, -P 轮询时间 + args = append(args, "-B", strconv.Itoa(taskModel.Timeout), "-P", "10") + } + if module == "shell" { + return ansible.Shell(taskModel.SshHosts, ansible.DefaultHosts.GetFilename(), args...) + } + if module == "script" { + return ansible.Script(taskModel.SshHosts, ansible.DefaultHosts.GetFilename(), args...) + } - return "", nil + return "", nil } func createTaskLog(taskId int) (int, error) { - taskLogModel := new(models.TaskLog) - taskLogModel.TaskId = taskId - taskLogModel.StartTime = time.Now() - taskLogModel.Status = models.Running - insertId, err := taskLogModel.Create() + taskLogModel := new(models.TaskLog) + taskLogModel.TaskId = taskId + taskLogModel.StartTime = time.Now() + taskLogModel.Status = models.Running + insertId, err := taskLogModel.Create() - return insertId, err + return insertId, err } func updateTaskLog(taskLogId int, result string, err error) (int64, error) { - fmt.Println(taskLogId) - taskLogModel := new(models.TaskLog) - var status models.Status - if err != nil { - result = err.Error() + " " + result - status = models.Failure - } else { - status = models.Finish - } - return taskLogModel.Update(taskLogId, models.CommonMap{ - "status": status, - "result": result, - }) + fmt.Println(taskLogId) + taskLogModel := new(models.TaskLog) + var status models.Status + if err != nil { + result = err.Error() + " " + result + status = models.Failure + } else { + status = models.Finish + } + return taskLogModel.Update(taskLogId, models.CommonMap{ + "status": status, + "result": result, + }) } func createHandlerJob(taskModel models.Task) cron.FuncJob { - var handler Handler = nil - switch taskModel.Protocol { - case models.HTTP: - handler = new(HTTPHandler) - case models.SSHCommand: - handler = new(SSHCommandHandler) - case models.SSHScript: - handler = new(SSHScriptHandler) - } - taskFunc := func() { - taskLogId, err := createTaskLog(taskModel.Id) - if err != nil { - utils.RecordLog("写入任务日志失败-", err) - return - } - // err != nil 执行失败 - result, err := handler.Run(taskModel) - _, err = updateTaskLog(int(taskLogId), result, err) - if err != nil { - utils.RecordLog("更新任务日志失败-", err) - } - } + var handler Handler = nil + switch taskModel.Protocol { + case models.HTTP: + handler = new(HTTPHandler) + case models.SSHCommand: + handler = new(SSHCommandHandler) + case models.SSHScript: + handler = new(SSHScriptHandler) + } + taskFunc := func() { + taskLogId, err := createTaskLog(taskModel.Id) + if err != nil { + utils.RecordLog("写入任务日志失败-", err) + return + } + // err != nil 执行失败 + result, err := handler.Run(taskModel) + _, err = updateTaskLog(int(taskLogId), result, err) + if err != nil { + utils.RecordLog("更新任务日志失败-", err) + } + } - return taskFunc + return taskFunc }