mirror of https://github.com/ouqiang/gocron
data, conf, log目录不存在自动创建
parent
750fb49a37
commit
0950fc69f9
|
@ -25,9 +25,9 @@ _testmain.go
|
||||||
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.idea
|
.idea
|
||||||
log/*
|
log
|
||||||
data/*
|
data
|
||||||
conf/*
|
conf
|
||||||
profile/*
|
profile/*
|
||||||
public/resource/javascript/vue.js
|
public/resource/javascript/vue.js
|
||||||
gocron
|
gocron
|
||||||
|
|
|
@ -1,139 +0,0 @@
|
||||||
package ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"golang.org/x/crypto/ssh"
|
|
||||||
"net"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HostAuthType int8 // 认证方式
|
|
||||||
|
|
||||||
const (
|
|
||||||
HostPassword = 1 // 密码认证
|
|
||||||
HostPublicKey = 2 // 公钥认证
|
|
||||||
)
|
|
||||||
|
|
||||||
const SSHConnectTimeout = 10
|
|
||||||
|
|
||||||
type SSHConfig struct {
|
|
||||||
AuthType HostAuthType
|
|
||||||
User string
|
|
||||||
Password string
|
|
||||||
PrivateKey string
|
|
||||||
Host string
|
|
||||||
Port int
|
|
||||||
ExecTimeout int // 执行超时时间
|
|
||||||
}
|
|
||||||
|
|
||||||
type Result struct {
|
|
||||||
Output string
|
|
||||||
Err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseSSHConfig(sshConfig SSHConfig) (config *ssh.ClientConfig, err error) {
|
|
||||||
timeout := time.Duration(SSHConnectTimeout) * time.Second
|
|
||||||
// 密码认证
|
|
||||||
if sshConfig.AuthType == HostPassword {
|
|
||||||
config = &ssh.ClientConfig{
|
|
||||||
User: sshConfig.User,
|
|
||||||
Auth: []ssh.AuthMethod{
|
|
||||||
ssh.Password(sshConfig.Password),
|
|
||||||
},
|
|
||||||
Timeout: timeout,
|
|
||||||
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
signer, err := ssh.ParsePrivateKey([]byte(sshConfig.PrivateKey))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 公钥认证
|
|
||||||
config = &ssh.ClientConfig{
|
|
||||||
User: sshConfig.User,
|
|
||||||
Auth: []ssh.AuthMethod{
|
|
||||||
ssh.PublicKeys(signer),
|
|
||||||
},
|
|
||||||
Timeout: timeout,
|
|
||||||
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 执行shell命令
|
|
||||||
func Exec(sshConfig SSHConfig, cmd string) (output string, err error) {
|
|
||||||
client, err := getClient(sshConfig)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer client.Close()
|
|
||||||
|
|
||||||
session, err := client.NewSession()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer session.Close()
|
|
||||||
|
|
||||||
// 后台运行
|
|
||||||
if sshConfig.ExecTimeout < 0 {
|
|
||||||
go session.CombinedOutput(cmd)
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
// 不限制超时
|
|
||||||
if sshConfig.ExecTimeout == 0 {
|
|
||||||
outputByte, execErr := session.CombinedOutput(cmd)
|
|
||||||
output = string(outputByte)
|
|
||||||
err = execErr
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var resultChan chan Result = make(chan Result)
|
|
||||||
var timeoutChan chan bool = make(chan bool)
|
|
||||||
go func() {
|
|
||||||
output, err := session.CombinedOutput(cmd)
|
|
||||||
resultChan <- Result{string(output), err}
|
|
||||||
}()
|
|
||||||
// todo 等待超时后,如何停止远程正在执行的任务, 使用timeout命令,但不具有通用性
|
|
||||||
go triggerTimeout(timeoutChan, sshConfig.ExecTimeout)
|
|
||||||
select {
|
|
||||||
case result := <-resultChan:
|
|
||||||
output = result.Output
|
|
||||||
err = result.Err
|
|
||||||
case <-timeoutChan:
|
|
||||||
output = ""
|
|
||||||
err = errors.New("timeout")
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func getClient(sshConfig SSHConfig) (*ssh.Client, error) {
|
|
||||||
config, err := parseSSHConfig(sshConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
addr := fmt.Sprintf("%s:%d", sshConfig.Host, sshConfig.Port)
|
|
||||||
|
|
||||||
return ssh.Dial("tcp", addr, config)
|
|
||||||
}
|
|
||||||
|
|
||||||
func triggerTimeout(ch chan bool, timeout int) {
|
|
||||||
// 最长执行时间不能超过24小时
|
|
||||||
if timeout <= 0 || timeout > 86400 {
|
|
||||||
timeout = 86400
|
|
||||||
}
|
|
||||||
time.Sleep(time.Duration(timeout) * time.Second)
|
|
||||||
close(ch)
|
|
||||||
}
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"name": "gocron",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "[![Build Status](https://travis-ci.org/ouqiang/gocron.png)](https://travis-ci.org/ouqiang/gocron) # gocron - 定时任务管理系统",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/ouqiang/gocron.git"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/ouqiang/gocron/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/ouqiang/gocron#readme",
|
||||||
|
"devDependencies": {
|
||||||
|
"cz-conventional-changelog": "^2.0.0"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"commitizen": {
|
||||||
|
"path": "./node_modules/cz-conventional-changelog"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 静态文件目录
|
// 静态文件目录
|
||||||
|
@ -112,7 +113,7 @@ func Register(m *macaron.Macaron) {
|
||||||
m.NotFound(func(ctx *macaron.Context) {
|
m.NotFound(func(ctx *macaron.Context) {
|
||||||
if isGetRequest(ctx) && !isAjaxRequest(ctx) {
|
if isGetRequest(ctx) && !isAjaxRequest(ctx) {
|
||||||
ctx.Data["Title"] = "404 - NOT FOUND"
|
ctx.Data["Title"] = "404 - NOT FOUND"
|
||||||
ctx.HTML(404, "error/404")
|
ctx.HTML(http.StatusNotFound, "error/404")
|
||||||
} else {
|
} else {
|
||||||
json := utils.JsonResponse{}
|
json := utils.JsonResponse{}
|
||||||
ctx.Resp.Write([]byte(json.Failure(utils.NotFound, "您访问的地址不存在")))
|
ctx.Resp.Write([]byte(json.Failure(utils.NotFound, "您访问的地址不存在")))
|
||||||
|
@ -123,7 +124,7 @@ func Register(m *macaron.Macaron) {
|
||||||
logger.Debug("500错误")
|
logger.Debug("500错误")
|
||||||
if isGetRequest(ctx) && !isAjaxRequest(ctx) {
|
if isGetRequest(ctx) && !isAjaxRequest(ctx) {
|
||||||
ctx.Data["Title"] = "500 - INTERNAL SERVER ERROR"
|
ctx.Data["Title"] = "500 - INTERNAL SERVER ERROR"
|
||||||
ctx.HTML(500, "error/500")
|
ctx.HTML(http.StatusInternalServerError, "error/500")
|
||||||
} else {
|
} else {
|
||||||
json := utils.JsonResponse{}
|
json := utils.JsonResponse{}
|
||||||
ctx.Resp.Write([]byte(json.Failure(utils.ServerError, "网站暂时无法访问,请稍后再试")))
|
ctx.Resp.Write([]byte(json.Failure(utils.ServerError, "网站暂时无法访问,请稍后再试")))
|
||||||
|
@ -202,7 +203,7 @@ func ipAuth(ctx *macaron.Context) {
|
||||||
allowIps := strings.Split(allowIpsStr, ",")
|
allowIps := strings.Split(allowIpsStr, ",")
|
||||||
if !utils.InStringSlice(allowIps, clientIp) {
|
if !utils.InStringSlice(allowIps, clientIp) {
|
||||||
logger.Warnf("非法IP访问-%s", clientIp)
|
logger.Warnf("非法IP访问-%s", clientIp)
|
||||||
ctx.Status(403)
|
ctx.Status(http.StatusForbidden)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,7 +252,7 @@ func urlAuth(ctx *macaron.Context, sess session.Store) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Status(403)
|
ctx.Status(http.StatusUnauthorized)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue