Compare commits

...
22 Commits
Author SHA1 Message Date
ouqiang ce6ba171e7 bugfix#任务日志列表搜索-状态为后台运行-结果显示不正确 2017-05-13 16:15:31 +08:00
ouqiang 6cd09d7f38 更新版本号为0.1 2017-05-12 10:52:15 +08:00
ouqiang 0f5c4c3e2a 邮件服务器配置-增加清空功能 2017-05-12 10:42:03 +08:00
ouqiang 428275f813 任务、主机编辑页面增加取消按钮 2017-05-12 10:13:42 +08:00
ouqiang 0be9269b8c 系统安装成功后, 自动创建2个测试任务 2017-05-12 09:59:22 +08:00
ouqiang f699a72c28 异步任务回调成功-发送通知 2017-05-10 17:58:05 +08:00
ouqiang 70bccfaea0 任务日志列表-当任务状态为已结束(成功或失败)才显示[任务结果]按钮 2017-05-10 17:14:57 +08:00
ouqiang 0bc4070762 增加删除N个月前的任务日志API 2017-05-10 16:18:21 +08:00
ouqiang 0dfa998d11 完善文档 2017-05-10 11:59:47 +08:00
ouqiang 1b4a6e8c62 替换二进制包下载链接 2017-05-10 08:23:18 +08:00
ouqiang 190cae9ae7 替换二进制包下载链接 2017-05-10 08:19:04 +08:00
ouqiang d1ecbd9043 CI构建-排除第三方库测试 2017-05-09 21:08:07 +08:00
ouqiang 55060aca67 CI构建-排除第三方库测试 2017-05-09 21:06:03 +08:00
ouqiang 2b2d4b237d 修复第三库测试失败 2017-05-09 20:40:16 +08:00
ouqiang 5276fb9074 完善文档 2017-05-09 17:34:28 +08:00
ouqiang 98bf5ee058 二进制包上传到七牛后,刷新CDN 2017-05-09 14:37:40 +08:00
ouqiang 95ea60f23c HTTP任务执行时间不能超过300秒 2017-05-09 13:42:49 +08:00
ouqiang 6f76d3b17e 二进制包改由七牛存储 2017-05-09 09:45:50 +08:00
ouqiang 85996077ec 任务编辑页面-添加主机链接在新窗口打开 2017-05-08 17:54:30 +08:00
ouqiang 7c3f6a58d4 任务执行前后添加日志 2017-05-08 14:07:06 +08:00
qiang.ouandGitHub bf07c6e2e2 Create LICENSE 2017-05-08 14:00:10 +08:00
ouqiang b2ad507010 完善文档 2017-05-07 11:38:03 +08:00
23 changed files with 279 additions and 83 deletions
+1 -2
View File
@@ -1,5 +1,4 @@
language: go
go:
- 1.7.x
- 1.8.x
- master
script: go test `go list ./... | grep -v vendor`
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 qiang.ou
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+21 -8
View File
@@ -6,7 +6,7 @@
## 功能特性
* 支持任务CURD
* crontab时间表达式,精确到
* crontab时间表达式,精确到秒
* 任务执行失败重试设置
* 任务超时设置
* 任务执行方式
@@ -21,28 +21,31 @@
![Slack](https://raw.githubusercontent.com/ouqiang/gocron/master/screenshot_slack.png)
### 支持平台
> Windows、Linux、OSX
> Windows、Linux、Mac OS
### 环境要求
> MySQL
## 下载
* [Linux-64位](http://opns468ov.bkt.clouddn.com/gocron/gocron-linux-amd64.tar.gz)
* [Mac OS-64位](http://opns468ov.bkt.clouddn.com/gocron/gocron-darwin-amd64.tar.gz)
* [Windows-64位](http://opns468ov.bkt.clouddn.com/gocron/gocron-windows-amd64.zip)
## 安装
### 二进制安装
1. [下载](https://pan.baidu.com/s/1pLNRndx#list/path=%2Fgocron), 解压压缩包
1. 解压压缩包
2. `cd 解压目录`
3. 启动
* Windows: `gocron.exe web`
* Linux、OSX: `./gocron web`
* Linux、Mac OS: `./gocron web`
4. 浏览器访问 http://localhost:5920
### 源码安装
1. `go`语言版本1.7+
2. `go get -d https://github.com/ouqiang/gocron`
2. `go get -d github.com/ouqiang/gocron`
3. 编译 `go build`
4. 启动、访问方式同上
5. 生成压缩包(Windows: gocron.zip, 其他平台: gocron.tar.gz
> ./build.sh -p 平台 -a CPU架构 例 ./build.sh -p darwin -a amd64
### 启动可选参数
@@ -54,3 +57,13 @@
* 使用`https`访问保证数据传输安全, 可在web服务器如nginx中配置https,通过反向代理,访问内部的gocron
* 网站访问设置IP白名单
* SSH登录设置IP白名单
## 程序使用的组件
* web框架 [Macaron](http://go-macaron.com/)
* 定时任务调度 [cron](https://github.com/robfig/cron)
* ORM [Xorm](https://github.com/go-xorm/xorm)
* UI框架 [Semantic UI](https://semantic-ui.com/)
* 依赖管理(所有依赖包放入vendor目录) [govendor](https://github.com/kardianos/govendor)
## 贡献
欢迎提交PR
+1 -1
View File
@@ -4,7 +4,7 @@
# 构建应用, 生成压缩包 gocron.zip或gocron.tar.gz
# ./build.sh -p windows -a amd64
# 参数含义
# -p 指定平台(widows|linux|darwin)
# -p 指定平台(windows|linux|darwin)
# -a 指定体系架构(amd64|386), 默认amd64
+6 -3
View File
@@ -93,12 +93,12 @@ func setEnvironment(ctx *cli.Context) {
}
switch env {
case "prod":
macaron.Env = macaron.PROD
case "test":
macaron.Env = macaron.TEST
case "dev":
macaron.Env = macaron.DEV
default:
macaron.Env = macaron.PROD
}
}
@@ -124,12 +124,15 @@ func shutdown() {
os.Exit(0)
return
}
logger.Info("应用准备退出\n停止任务调度")
logger.Info("应用准备退出, 停止任务调度")
serviceTask := new(service.Task)
// 停止所有任务调度
serviceTask.StopAll()
taskNumInRunning := service.TaskNum.Num()
logger.Infof("正在运行的任务有%d个", taskNumInRunning)
if taskNumInRunning > 0 {
logger.Info("等待所有任务执行完成后退出")
}
for {
if taskNumInRunning <= 0 {
break
+1 -1
View File
@@ -13,7 +13,7 @@ import (
"github.com/ouqiang/gocron/cmd"
)
const AppVersion = "0.0.1"
const AppVersion = "0.1"
func main() {
app := cli.NewApp()
+3 -1
View File
@@ -13,8 +13,9 @@ func (migration *Migration) Exec(dbName string) error {
return errors.New("数据库不存在")
}
setting := new(Setting)
task := new(Task)
tables := []interface{}{
&User{}, &Task{}, &TaskLog{}, &Host{}, setting,&LoginLog{},
&User{}, task, &TaskLog{}, &Host{}, setting,&LoginLog{},
}
for _, table := range tables {
exist, err:= Db.IsTableExist(table)
@@ -30,6 +31,7 @@ func (migration *Migration) Exec(dbName string) error {
}
}
setting.InitBasicField()
task.CreateTestTask()
return nil
}
+28 -2
View File
@@ -4,6 +4,7 @@ import (
"time"
"github.com/ouqiang/gocron/modules/ssh"
"github.com/go-xorm/xorm"
"github.com/ouqiang/gocron/modules/utils"
)
type TaskProtocol int8
@@ -29,9 +30,9 @@ type Task struct {
NotifyType int8 `xorm:"smallint notnull default 0"` // 通知类型 1: 邮件 2: slack
NotifyReceiverId string `xorm:"varchar(256) notnull default '' "` // 通知接受者ID, setting表主键ID,多个ID逗号分隔
Remark string `xorm:"varchar(100) notnull default ''"` // 备注
Status Status `xorm:"tinyint notnull default 0"` // 状态 1:正常 0:停止
Created time.Time `xorm:"datetime notnull created"` // 创建时间
Deleted time.Time `xorm:"datetime deleted"` // 删除时间
Status Status `xorm:"tinyint notnull default 1"` // 状态 1:正常 0:停止
BaseModel `xorm:"-"`
}
@@ -58,8 +59,33 @@ func (task *Task) Create() (insertId int, err error) {
return
}
// 新增测试任务
func (task *Task) CreateTestTask() {
// HTTP任务
task.Name = "测试HTTP任务"
task.Protocol = TaskHTTP
task.Spec = "*/30 * * * * *"
// 查询IP地址区域信息
task.Command = "http://ip.taobao.com/service/getIpInfo.php?ip=117.27.140.253"
task.Status = Enabled
task.Create()
// 系统命令
task.Id = 0
task.Name = "测试系统命令任务"
task.Protocol = TaskLocalCommand
task.Spec = "@every 1m"
task.Status = Enabled
if utils.IsWindows() {
task.Command = "dir"
} else {
task.Command = "ls"
}
task.Create()
}
func (task *Task) UpdateBean(id int) (int64, error) {
return Db.ID(id).Cols("name,spec,protocol,command,timeout,multi,retry_times,host_id,remark,status,notify_status,notify_type,notify_receiver_id").Update(task)
return Db.ID(id).Cols("name,spec,protocol,command,timeout,multi,retry_times,host_id,remark,notify_status,notify_type,notify_receiver_id").Update(task)
}
// 更新
+19 -2
View File
@@ -72,9 +72,26 @@ func (taskLog *TaskLog) List(params CommonMap) ([]TaskLog, error) {
return list, err
}
// 根据通知ID获取任务ID
func (taskLog *TaskLog) GetTaskIdByNotifyId(notifyId string) (taskId int, err error) {
exist, err := Db.Where("notify_id = ?", notifyId).Get(taskLog)
if !exist || err != nil {
return
}
taskId = taskLog.TaskId
return
}
// 清空表
func (TaskLog *TaskLog) Clear() (int64, error) {
return Db.Where("1=1").Delete(TaskLog);
func (taskLog *TaskLog) Clear() (int64, error) {
return Db.Where("1=1").Delete(taskLog);
}
// 删除N个月前的日志
func (taskLog *TaskLog) Remove(id int) (int64, error) {
t := time.Now().AddDate(0, -id, 0)
return Db.Where("start_time <= ?", t.Format(DefaultTimeFormat)).Delete(taskLog)
}
func (taskLog *TaskLog) Total(params CommonMap) (int64, error) {
+1 -1
View File
@@ -66,7 +66,7 @@ func (mail *Mail) send(mailSetting models.Mail, toUsers []string, msg Message)
i += 1
time.Sleep(2 * time.Second)
if i < maxTimes {
logger.Error("mail#发送消息失败#%s#消息内容-%s", err.Error(), msg["content"])
logger.Errorf("mail#发送消息失败#%s#消息内容-%s", err.Error(), msg["content"])
}
}
}
+1 -1
View File
@@ -50,7 +50,7 @@ func (slack *Slack) send(msg Message, slackUrl string, channel string) {
i += 1
time.Sleep(2 * time.Second)
if i < maxTimes {
logger.Error("slack#发送消息失败#%s#消息内容-%s", resp.Body, msg["content"])
logger.Errorf("slack#发送消息失败#%s#消息内容-%s", resp.Body, msg["content"])
}
}
}
+8
View File
@@ -105,6 +105,14 @@ func UpdateMailServer(ctx *macaron.Context, form MailServerForm) string {
return utils.JsonResponseByErr(err)
}
func ClearMailServer(ctx *macaron.Context) string {
jsonByte, _ := json.Marshal(MailServerForm{})
settingModel := new(models.Setting)
_, err := settingModel.UpdateMailServer(string(jsonByte))
return utils.JsonResponseByErr(err)
}
func CreateMailUser(ctx *macaron.Context) string {
username := ctx.QueryTrim("username")
email := ctx.QueryTrim("email")
+9 -3
View File
@@ -80,6 +80,7 @@ func Register(m *macaron.Macaron) {
m.Get("/", manage.Mail)
m.Get("/edit", manage.EditMail)
m.Post("/server", binding.Bind(manage.MailServerForm{}), manage.UpdateMailServer)
m.Post("/server/clear", manage.ClearMailServer)
m.Post("/user", manage.CreateMailUser)
m.Post("/user/remove/:id", manage.RemoveMailUser)
})
@@ -88,7 +89,8 @@ func Register(m *macaron.Macaron) {
// API
m.Group("/api/v1", func() {
m.Get("/tasklog/update-status", tasklog.UpdateStatus)
m.Route("/tasklog/update-status", "GET,POST", tasklog.UpdateStatus)
m.Post("/tasklog/remove/:id", tasklog.Remove)
});
// 404错误
@@ -149,7 +151,9 @@ func RegisterMiddleware(m *macaron.Macaron) {
})
}
// 系统未安装,重定向到安装页面
// region 自定义中间件
/** 系统未安装,重定向到安装页面 **/
func checkAppInstall(m *macaron.Macaron) {
m.Use(func(ctx *macaron.Context) {
installUrl := "/install"
@@ -195,7 +199,9 @@ func userAuth(ctx *macaron.Context, sess session.Store) {
}
}
// 设置共享数据
// endregion
/** 设置共享数据 **/
func setShareData(ctx *macaron.Context, sess session.Store) {
ctx.Data["URI"] = ctx.Req.URL.Path
urlPath := strings.TrimPrefix(ctx.Req.URL.Path, "/")
+21 -27
View File
@@ -13,6 +13,7 @@ import (
"html/template"
"github.com/ouqiang/gocron/routers/base"
"github.com/go-macaron/binding"
"strings"
)
type TaskForm struct {
@@ -26,7 +27,6 @@ type TaskForm struct {
RetryTimes int8
HostId int16
Remark string
Status models.Status `binding:"In(1,2)"`
NotifyStatus int8 `binding:In(1,2,3)`
NotifyType int8 `binding:In(1,2)`
NotifyReceiverId string
@@ -82,11 +82,6 @@ func Create(ctx *macaron.Context) {
// 编辑页面
func Edit(ctx *macaron.Context) {
id := ctx.ParamsInt(":id")
hostModel := new(models.Host)
hosts, err := hostModel.List(models.CommonMap{})
if err != nil || len(hosts) == 0 {
logger.Error(err)
}
taskModel := new(models.Task)
task, err := taskModel.Detail(id)
if err != nil || task.Id != id {
@@ -95,11 +90,7 @@ func Edit(ctx *macaron.Context) {
}
ctx.Data["Task"] = task
ctx.Data["Title"] = "编辑"
ctx.Data["Hosts"] = hosts
if len(hosts) > 0 {
ctx.Data["FirstHostName"] = hosts[0].Name
ctx.Data["FirstHostId"] = hosts[0].Id
}
setHostsToTemplate(ctx)
ctx.HTML(200, "task/task_form")
}
@@ -134,12 +125,8 @@ func Store(ctx *macaron.Context, form TaskForm) string {
taskModel.Command = form.Command
taskModel.Timeout = form.Timeout
taskModel.Remark = form.Remark
taskModel.Status = form.Status
taskModel.Multi = form.Multi
taskModel.RetryTimes = form.RetryTimes
if taskModel.Status != models.Enabled {
taskModel.Status = models.Disabled
}
if taskModel.Multi != 1 {
taskModel.Multi = 0
}
@@ -148,14 +135,30 @@ func Store(ctx *macaron.Context, form TaskForm) string {
taskModel.NotifyReceiverId = form.NotifyReceiverId
taskModel.Spec = form.Spec
if taskModel.NotifyStatus > 0 && taskModel.NotifyReceiverId == "" {
return json.CommonFailure("请至少选择一个接收者", err)
return json.CommonFailure("请至少选择一个接收者")
}
if taskModel.Protocol == models.TaskHTTP && taskModel.Timeout == -1 {
return json.CommonFailure("HTTP任务不支持后台运行", err)
if taskModel.Protocol == models.TaskHTTP {
command := strings.ToLower(taskModel.Command)
if !strings.HasPrefix(command, "http://") && !strings.HasPrefix(command, "https://") {
return json.CommonFailure("请输入正确的URL地址")
}
if taskModel.Timeout == -1 {
return json.CommonFailure("HTTP任务不支持后台运行")
}
if taskModel.Timeout > 300 {
return json.CommonFailure("HTTP任务超时时间不能超过300秒")
}
}
if taskModel.RetryTimes > 10 || taskModel.RetryTimes < 0 {
return json.CommonFailure("任务重试次数取值0-10")
}
if taskModel.Protocol != models.TaskSSH {
taskModel.HostId = 0
}
if id == 0 {
id, err = taskModel.Create()
} else {
@@ -165,11 +168,6 @@ func Store(ctx *macaron.Context, form TaskForm) string {
return json.CommonFailure("保存失败", err)
}
// 任务处于激活状态,加入调度管理
if (taskModel.Status == models.Enabled) {
addTaskToTimer(id)
}
return json.Success("保存成功", nil)
}
@@ -273,8 +271,4 @@ func setHostsToTemplate(ctx *macaron.Context) {
logger.Error(err)
}
ctx.Data["Hosts"] = hosts
if len(hosts) > 0 {
ctx.Data["FirstHostName"] = hosts[0].Name
ctx.Data["FirstHostId"] = hosts[0].Id
}
}
+41 -3
View File
@@ -1,5 +1,7 @@
package tasklog
// 任务日志
import (
"gopkg.in/macaron.v1"
"github.com/ouqiang/gocron/models"
@@ -9,11 +11,10 @@ import (
"fmt"
"html/template"
"github.com/ouqiang/gocron/routers/base"
"github.com/ouqiang/gocron/service"
"errors"
)
// @author qiang.ou<qingqianludao@gmail.com>
// @date 2017/4/7-21:18
func Index(ctx *macaron.Context) {
logModel := new(models.TaskLog)
queryParams := parseQueryParams(ctx)
@@ -49,12 +50,29 @@ func Clear(ctx *macaron.Context) string {
return json.Success(utils.SuccessContent, nil)
}
// 删除N个月前的日志
func Remove(ctx *macaron.Context) string {
month := ctx.ParamsInt(":id")
json := utils.JsonResponse{}
if month < 1 || month > 12 {
return json.CommonFailure("参数取值范围1-12")
}
taskLogModel := new(models.TaskLog)
_, err := taskLogModel.Remove(month)
if err != nil {
return json.CommonFailure("删除失败", err)
}
return json.Success("删除成功", nil)
}
// 更新任务状态
func UpdateStatus(ctx *macaron.Context) string {
id := ctx.QueryTrim("id")
status := ctx.QueryInt("status")
result := ctx.QueryTrim("result")
json := utils.JsonResponse{}
if id == "" {
return json.CommonFailure("任务ID不能为空")
}
@@ -70,6 +88,26 @@ func UpdateStatus(ctx *macaron.Context) string {
return json.CommonFailure("更新任务状态失败")
}
// 发送通知
taskId, err := taskLogModel.GetTaskIdByNotifyId(id)
if err != nil || taskId <= 0 {
logger.Error("异步任务回调#根据notify-id获取taskId失败", err)
return json.Success("success", nil)
}
taskModel := new(models.Task)
task, err := taskModel.Detail(taskId)
if err != nil || task.Id <= 0 {
logger.Error("异步任务回调#根据获取任务详情失败", err)
return json.Success("success", nil)
}
taskResult := service.TaskResult{}
taskResult.Result = result
if status == 0 {
taskResult.Err = errors.New("error")
}
service.SendNotification(task, taskResult)
return json.Success("success", nil)
}
+13 -2
View File
@@ -173,7 +173,13 @@ func (h *LocalCommandHandler) runOnUnix(taskModel models.TaskHost) (string, erro
// HTTP任务
type HTTPHandler struct{}
// http任务执行时间不超过300秒
const HttpExecTimeout = 300
func (h *HTTPHandler) Run(taskModel models.TaskHost) (result string, err error) {
if taskModel.Timeout <= 0 || taskModel.Timeout > HttpExecTimeout {
taskModel.Timeout = HttpExecTimeout
}
resp := httpclient.Get(taskModel.Command, taskModel.Timeout)
// 返回状态码非200,均为失败
if resp.StatusCode != 200 {
@@ -274,7 +280,9 @@ func createJob(taskModel models.TaskHost) cron.FuncJob {
if taskLogId <= 0 {
return
}
logger.Infof("开始执行任务#%s#命令-%s", taskModel.Task.Name, taskModel.Command)
taskResult := execJob(handler, taskModel)
logger.Infof("任务完成#%s#命令-%s", taskModel.Task.Name, taskModel.Command)
afterExecJob(taskModel, taskResult, taskLogId)
}
@@ -338,11 +346,11 @@ func afterExecJob(taskModel models.TaskHost, taskResult TaskResult, taskLogId in
return
}
sendNotification(taskModel, taskResult)
SendNotification(taskModel, taskResult)
}
// 发送任务结果通知
func sendNotification(taskModel models.TaskHost, taskResult TaskResult) {
func SendNotification(taskModel models.TaskHost, taskResult TaskResult) {
var statusName string
// 未开启通知
if taskModel.NotifyStatus == 0 {
@@ -352,6 +360,9 @@ func sendNotification(taskModel models.TaskHost, taskResult TaskResult) {
// 执行失败才发送通知
return
}
if taskModel.NotifyReceiverId == "" {
return
}
if taskResult.Err != nil {
statusName = "失败"
} else {
+1
View File
@@ -68,6 +68,7 @@
</div>
<div class="ui primary submit button">保存</div>
<a class="ui button" onclick="location.href='/task';">取消</a>
</form>
</div>
</div>
+9 -1
View File
@@ -90,9 +90,17 @@
$('.ui.form').form(
{
onSuccess: function(event, fields) {
swal({
title: '',
text: "系统安装中.......",
type: 'info',
showConfirmButton: false
});
util.post('/install/store', fields, function(code, message) {
swal('安装成功');
location.href = "/";
setTimeout(function() {
location.href = "/";
}, 2000)
});
return false;
},
+11 -2
View File
@@ -16,7 +16,7 @@
<div class="four fields">
<div class="field">
<label>
主机名
SMTP服务器
</label>
<div class="ui small input">
<input type="text" name="host" value="{{{.Mail.Host}}}">
@@ -48,6 +48,9 @@
</div>
</div>
<button class="ui primary button">保存</button>
{{{if .Mail.Host}}}
<a class="ui green button" onclick="clearMailServer()">删除</a>
{{{end}}}
<br><br><br>
<div>
<div class="content">邮箱用户</div><p></p>
@@ -98,7 +101,7 @@
util.post('/manage/mail/server',
fields,
function(code, message) {
util.alertSuccess();
location.reload();
}
);
return false;
@@ -188,5 +191,11 @@
location.reload();
});
}
function clearMailServer() {
util.post('/manage/mail/server/clear', {}, function(code, message) {
location.reload();
});
}
</script>
{{{ template "common/footer" . }}}
+1 -1
View File
@@ -62,7 +62,7 @@
<p>cron表达式 {{{.Spec}}}</p>
<p>执行方式: {{{if eq .Protocol 1}}} HTTP {{{else if eq .Protocol 2}}} SSH {{{else if eq .Protocol 3}}}本地命令{{{end}}}</p>
<p class="sensorStatus">命令{{{.Command}}}</p>
<p class="sensorStatus">超时时间{{{if eq .Timeout -1}}}后台运行{{{else if eq .Timeout 0}}}{{{.Timeout}}}{{{else}}}不限制{{{end}}}</p>
<p class="sensorStatus">超时时间{{{if eq .Timeout -1}}}后台运行{{{else if gt .Timeout 0}}}{{{.Timeout}}}{{{else}}}不限制{{{end}}}</p>
<p>重试次数: {{{.RetryTimes}}}</p>
<p class="sensorStatus">是否允许多实例运行{{{if gt .Multi 0}}}{{{else}}}{{{end}}}</p>
{{{if eq .Protocol 2}}}
+3 -3
View File
@@ -42,7 +42,7 @@
<option value="2" {{{if eq .Params.Status 1}}}selected{{{end}}}>执行中</option>
<option value="3" {{{if eq .Params.Status 2}}}selected{{{end}}}>成功</option>
<option value="4" {{{if eq .Params.Status 3}}}selected{{{end}}}>取消</option>
<option value="5" {{{if eq .Params.Status 3}}}selected{{{end}}}>后台运行</option>
<option value="5" {{{if eq .Params.Status 4}}}selected{{{end}}}>后台运行</option>
</select>
</div>
<div class="field">
@@ -72,7 +72,7 @@
<td>{{{.Name}}}</td>
<td>{{{.Spec}}}</td>
<td>{{{if eq .Protocol 1}}} HTTP {{{else if eq .Protocol 2}}} SSH {{{else}}} 系统命令 {{{end}}}</td>
<td>{{{if eq .Timeout -1}}}后台运行{{{else if eq .Timeout 0}}}{{{.Timeout}}}{{{else}}}不限制{{{end}}}</td>
<td>{{{if eq .Timeout -1}}}后台运行{{{else if gt .Timeout 0}}}{{{.Timeout}}}{{{else}}}不限制{{{end}}}</td>
<td>{{{.RetryTimes}}}</td>
<td>{{{.Hostname}}}</td>
<td>
@@ -98,7 +98,7 @@
{{{end}}}
</td>
<td>
{{{if and (ne .Status 1) (ne .Status 3)}}}
{{{if or (eq .Status 2) (eq .Status 0)}}}
<button class="ui small primary button"
onclick="showResult('{{{.Name}}}', '{{{.Command}}}', '{{{.Result}}}')"
>查看结果
+23 -19
View File
@@ -56,14 +56,14 @@
{{{range $i, $v := .Hosts}}}
<option value="{{{.Id}}}" {{{if $.Task}}}{{{if eq $.Task.HostId .Id }}} selected {{{end}}} {{{end}}}>{{{.Alias}}}-{{{.Name}}}</option>
{{{end}}}
</select> &nbsp; <a class="ui blue button" href="/host/create">添加主机</a>
</select> &nbsp; <a class="ui blue button" href="/host/create" target="_blank">添加主机</a>
</div>
</div>
<div class="two fields">
<div class="field">
<label>命令</label>
<textarea rows="5" name="command">{{{.Task.Command}}}</textarea>
<textarea rows="5" name="command" placeholder="请输入系统命令" id="command">{{{.Task.Command}}}</textarea>
</div>
</div>
<div class="six fields">
@@ -81,27 +81,12 @@
<div class="three fields">
<div class="field">
<label>允许多实例同时运行</label>
<div class="ui blue message">
前次任务未执行完成本次任务是否执行
</div>
<select name="multi">
<option value="1"{{{if .Task}}} {{{if eq .Task.Multi 1}}}selected{{{end}}} {{{end}}}></option>
<option value="2" {{{if .Task}}} {{{if eq .Task.Multi 0}}}selected{{{end}}} {{{end}}}></option>
</select>
</div>
</div>
<div class="three fields">
<div class="field">
<label>任务状态</label>
<div class="ui blue message">
任务添加成功后是否立即调度
</div>
<select name="status">
<option value="2"{{{if .Task}}} {{{if eq .Task.Status 0}}}selected{{{end}}} {{{end}}}>停止</option>
<option value="1" {{{if .Task}}} {{{if eq .Task.Status 1}}}selected{{{end}}} {{{end}}}>激活</option>
</select>
</div>
</div>
<div class="three fields">
<div class="field">
<label>任务通知</label>
@@ -129,7 +114,7 @@
<textarea rows="5" name="remark">{{{.Task.Remark}}}</textarea>
</div>
</div>
<div class="ui primary submit button">保存</div>
<div class="ui primary submit button">保存</div> <a class="ui button" onclick="location.href='/task';">取消</a>
</form>
</div>
</div>
@@ -162,14 +147,18 @@
<script type="text/javascript">
$(function() {
changeCommandPlaceholder();
changeProtocol();
showNotify();
});
$('#protocol').change(function() {
changeProtocol();
changeCommandPlaceholder();
changeProtocol();
});
$('#task-status').change(function() {
var selected = $(this).val();
if (selected == 1) {
@@ -185,6 +174,21 @@
changeNotify();
});
function changeCommandPlaceholder() {
var selectedId = $('#protocol').val();
switch (selectedId) {
case '1':
$('#command').attr('placeholder', '请输入URL地址');
break;
case '2':
$('#command').attr('placeholder', '请输入shell命令');
break;
case '3':
$('#command').attr('placeholder', '请输入系统命令');
break;
}
}
function showNotify() {
var notifyStatus = {{{.Task.NotifyStatus}}};
if (notifyStatus > 0) {
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
# set -x -u
# 上传二进制包到七牛
if [[ -z $QINIU_ACCESS_KEY || -z $QINIU_SECRET_KEY || -z $QINIU_URL ]];then
echo 'QINIU_ACCESS_KEY | QINIU_SECRET_KEY | QINIU_URL is need'
exit 1
fi
# 打包
for i in linux darwin windows
do
./build.sh -p $i
if [[ ! $? ]];then
break
fi
done
# 身份认证
qrsctl login $QINIU_ACCESS_KEY $QINIU_SECRET_KEY
# 上传
for i in `ls gocron*.gz gocron*.zip`
do
# 上传文件 qrsctl put bucket key srcFile
KEY=gocron/$i
qrsctl put github $KEY $i
if [[ ! $? ]];then
break
fi
echo "刷新七牛CDN-" $QINIU_URL/$KEY
qrsctl cdn/refresh $QINIU_URL/$KEY
rm $i
done
echo '打包并上传成功'