1.添加windows远程执行任务支持
2.README.md更新windows支持说明 3.sql更新
This commit is contained in:
17
README.md
17
README.md
@@ -71,9 +71,22 @@ mac
|
||||
|
||||
windows
|
||||
|
||||
- 暂不支持
|
||||
1.开启telnet功能
|
||||
|
||||
控制面板->程序和功能->打开或关闭Windows功能,选择Telnet服务端和Telnet客户端
|
||||
|
||||
2.启动telnet服务
|
||||
|
||||
控制面板->管理工具->服务->Telnet->启动类型改为自动并启动
|
||||
|
||||
3.登陆授权
|
||||
|
||||
控制面板->管理工具->本地安全策略,在本地安全策略中,安全设置->本地策略->安全选项->网络访问:本地帐户的共享和安全模型->经典
|
||||
|
||||
控制面板->管理工具->本地安全策略->安全设置->本地策略->安全选项->帐户:使用空密码的本地帐户只允许进行控制台登录->已禁用
|
||||
|
||||
控制面板->管理工具->计算机管理->系统工具->本地用户和组->组->TelnetClients->添加用户
|
||||
|
||||
访问方式
|
||||
----
|
||||
前台访问:http://your_host:8080
|
||||
用户名:admin 密码:123456
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/george518/PPGo_Job/models"
|
||||
"strconv"
|
||||
"strings"
|
||||
"github.com/axgle/mahonia"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -348,3 +349,11 @@ func serverLists(authStr string, adminId int) (sls []serverList) {
|
||||
}
|
||||
return sls
|
||||
}
|
||||
|
||||
func gbkAsUtf8(str string) string {
|
||||
srcDecoder := mahonia.NewDecoder("gbk")
|
||||
desDecoder := mahonia.NewDecoder("utf-8")
|
||||
resStr := srcDecoder.ConvertString(str)
|
||||
_, resBytes, _ := desDecoder.Translate([]byte(resStr), true)
|
||||
return string(resBytes)
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
** @Description: controllers
|
||||
** @Author: haodaquan
|
||||
** @Date: 2018-06-09 16:11
|
||||
** @Last Modified by: haodaquan
|
||||
** @Last Modified time: 2018-06-09 16:11
|
||||
** @Last Modified by: Bee
|
||||
** @Last Modified time: 2019-02-17 22:15:15
|
||||
*************************************************************/
|
||||
package controllers
|
||||
|
||||
@@ -16,6 +16,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"github.com/morganhein/go-telnet"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type ServerController struct {
|
||||
@@ -72,6 +74,7 @@ func (self *ServerController) GetServerByGroupId() {
|
||||
for k, v := range result {
|
||||
row := make(map[string]interface{})
|
||||
row["id"] = v.Id
|
||||
row["connection_type"] = v.ConnectionType
|
||||
row["server_name"] = v.ServerName
|
||||
row["detail"] = v.Detail
|
||||
if serverGroup[v.GroupId] == "" {
|
||||
@@ -94,6 +97,7 @@ func (self *ServerController) Edit() {
|
||||
server, _ := models.TaskServerGetById(id)
|
||||
row := make(map[string]interface{})
|
||||
row["id"] = server.Id
|
||||
row["connection_type"] = server.ConnectionType
|
||||
row["server_name"] = server.ServerName
|
||||
row["group_id"] = server.GroupId
|
||||
row["server_ip"] = server.ServerIp
|
||||
@@ -113,6 +117,7 @@ func (self *ServerController) Edit() {
|
||||
func (self *ServerController) AjaxTestServer() {
|
||||
|
||||
server := new(models.TaskServer)
|
||||
server.ConnectionType, _ = self.GetInt("connection_type")
|
||||
server.ServerName = strings.TrimSpace(self.GetString("server_name"))
|
||||
server.ServerAccount = strings.TrimSpace(self.GetString("server_account"))
|
||||
server.ServerOuterIp = strings.TrimSpace(self.GetString("server_outer_ip"))
|
||||
@@ -126,6 +131,8 @@ func (self *ServerController) AjaxTestServer() {
|
||||
server.GroupId, _ = self.GetInt("group_id")
|
||||
|
||||
var err error
|
||||
|
||||
if server.ConnectionType == 0 {
|
||||
if server.Type == 0 {
|
||||
//密码登录
|
||||
err = RemoteCommandByPassword(server)
|
||||
@@ -140,7 +147,67 @@ func (self *ServerController) AjaxTestServer() {
|
||||
self.ajaxMsg(err.Error(), MSG_ERR)
|
||||
}
|
||||
self.ajaxMsg("Success", MSG_OK)
|
||||
} else if server.ConnectionType == 1 {
|
||||
if server.Type == 0 {
|
||||
//密码登录
|
||||
err = RemoteCommandByTelnetPassword(server)
|
||||
} else {
|
||||
self.ajaxMsg("Telnet方式暂不支持密钥登陆!", MSG_ERR)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
self.ajaxMsg(err.Error(), MSG_ERR)
|
||||
}
|
||||
self.ajaxMsg("Success", MSG_OK)
|
||||
}
|
||||
|
||||
self.ajaxMsg("未知连接方式", MSG_ERR)
|
||||
}
|
||||
|
||||
func RemoteCommandByTelnetPassword(servers *models.TaskServer) error {
|
||||
|
||||
addr := fmt.Sprintf("%s:%d", servers.ServerIp, servers.Port)
|
||||
conn, err := gote.Dial("tcp", addr)
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf := make([]byte, 4096)
|
||||
_, err = conn.Read(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = conn.Write([]byte(servers.ServerAccount + "\r\n"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = conn.Read(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = conn.Write([]byte(servers.Password + "\r\n"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = conn.Read(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
str := gbkAsUtf8(string(buf[:]))
|
||||
|
||||
if strings.Contains(str, ">") {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.Errorf("连接失败!")
|
||||
}
|
||||
|
||||
func RemoteCommandByPassword(servers *models.TaskServer) error {
|
||||
@@ -208,6 +275,7 @@ func (self *ServerController) Copy() {
|
||||
server, _ := models.TaskServerGetById(id)
|
||||
row := make(map[string]interface{})
|
||||
row["id"] = server.Id
|
||||
row["connection_type"] = server.ConnectionType
|
||||
row["server_name"] = server.ServerName
|
||||
row["group_id"] = server.GroupId
|
||||
row["server_ip"] = server.ServerIp
|
||||
@@ -228,6 +296,7 @@ func (self *ServerController) AjaxSave() {
|
||||
server_id, _ := self.GetInt("id")
|
||||
if server_id == 0 {
|
||||
server := new(models.TaskServer)
|
||||
server.ConnectionType, _ = self.GetInt("connection_type")
|
||||
server.ServerName = strings.TrimSpace(self.GetString("server_name"))
|
||||
server.ServerAccount = strings.TrimSpace(self.GetString("server_account"))
|
||||
server.ServerOuterIp = strings.TrimSpace(self.GetString("server_outer_ip"))
|
||||
@@ -256,6 +325,7 @@ func (self *ServerController) AjaxSave() {
|
||||
server.Id = server_id
|
||||
server.UpdateTime = time.Now().Unix()
|
||||
|
||||
server.ConnectionType, _ = self.GetInt("connection_type")
|
||||
server.ServerName = strings.TrimSpace(self.GetString("server_name"))
|
||||
server.ServerAccount = strings.TrimSpace(self.GetString("server_account"))
|
||||
server.ServerOuterIp = strings.TrimSpace(self.GetString("server_outer_ip"))
|
||||
@@ -310,6 +380,11 @@ func (self *ServerController) Table() {
|
||||
"密钥",
|
||||
}
|
||||
|
||||
connectionType := [2]string{
|
||||
"SSH",
|
||||
"Telnet",
|
||||
}
|
||||
|
||||
serverGroup := serverGroupLists(self.serverGroups, self.userId)
|
||||
|
||||
self.pageSize = limit
|
||||
@@ -334,6 +409,7 @@ func (self *ServerController) Table() {
|
||||
for k, v := range result {
|
||||
row := make(map[string]interface{})
|
||||
row["id"] = v.Id
|
||||
row["connection_type"] = connectionType[v.ConnectionType]
|
||||
row["server_name"] = v.ServerName
|
||||
row["detail"] = v.Detail
|
||||
if serverGroup[v.GroupId] == "" {
|
||||
|
||||
97
jobs/job.go
97
jobs/job.go
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* @Author: haodaquan
|
||||
* @Date: 2017-06-21 12:56:08
|
||||
* @Last Modified by: haodaquan
|
||||
* @Last Modified time: 2017-06-21 13:05:57
|
||||
* @Last Modified by: Bee
|
||||
* @Last Modified time: 2019-02-17 22:10:15
|
||||
*/
|
||||
|
||||
package jobs
|
||||
@@ -25,6 +25,9 @@ import (
|
||||
"github.com/george518/PPGo_Job/notify"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"encoding/json"
|
||||
"github.com/axgle/mahonia"
|
||||
"github.com/morganhein/go-telnet"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Job struct {
|
||||
@@ -51,6 +54,7 @@ func NewJobFromTask(task *models.Task) (*Job, error) {
|
||||
}
|
||||
|
||||
server, _ := models.TaskServerGetById(task.ServerId)
|
||||
if server.ConnectionType == 0 {
|
||||
if server.Type == 0 {
|
||||
//密码验证登录服务器
|
||||
job := RemoteCommandJobByPassword(task.Id, task.TaskName, task.Command, server)
|
||||
@@ -63,7 +67,17 @@ func NewJobFromTask(task *models.Task) (*Job, error) {
|
||||
job.task = task
|
||||
job.Concurrent = task.Concurrent == 1
|
||||
return job, nil
|
||||
} else if server.ConnectionType == 1 {
|
||||
if server.Type == 0 {
|
||||
//密码验证登录服务器
|
||||
job := RemoteCommandJobByTelnetPassword(task.Id, task.TaskName, task.Command, server)
|
||||
job.task = task
|
||||
job.Concurrent = task.Concurrent == 1
|
||||
return job, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("未知ConnectionType")
|
||||
}
|
||||
|
||||
func NewCommandJob(id int, name string, command string) *Job {
|
||||
@@ -209,6 +223,77 @@ func RemoteCommandJobByPassword(id int, name string, command string, servers *mo
|
||||
return job
|
||||
}
|
||||
|
||||
func RemoteCommandJobByTelnetPassword(id int, name string, command string, servers *models.TaskServer) *Job {
|
||||
|
||||
job := &Job{
|
||||
id: id,
|
||||
name: name,
|
||||
}
|
||||
job.runFunc = func(timeout time.Duration) (string, string, error, bool) {
|
||||
|
||||
addr := fmt.Sprintf("%s:%d", servers.ServerIp, servers.Port)
|
||||
conn, err := gote.Dial("tcp", addr)
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
if err != nil {
|
||||
return "", "", err, false
|
||||
}
|
||||
|
||||
buf := make([]byte, 4096)
|
||||
_, err = conn.Read(buf)
|
||||
if err != nil {
|
||||
return "", "", err, false
|
||||
}
|
||||
|
||||
_, err = conn.Write([]byte(servers.ServerAccount + "\r\n"))
|
||||
if err != nil {
|
||||
return "", "", err, false
|
||||
}
|
||||
|
||||
_, err = conn.Read(buf)
|
||||
if err != nil {
|
||||
return "", "", err, false
|
||||
}
|
||||
|
||||
_, err = conn.Write([]byte(servers.Password + "\r\n"))
|
||||
if err != nil {
|
||||
return "", "", err, false
|
||||
}
|
||||
|
||||
_, err = conn.Read(buf)
|
||||
if err != nil {
|
||||
return "", "", err, false
|
||||
}
|
||||
|
||||
loginStr := gbkAsUtf8(string(buf[:]))
|
||||
if !strings.Contains(loginStr, ">") {
|
||||
return "", "", errors.Errorf("Login failed!"), false
|
||||
}
|
||||
|
||||
commandArr := strings.Split(command, "\n")
|
||||
|
||||
out := ""
|
||||
for _, c := range commandArr {
|
||||
_, err = conn.Write([]byte(c + "\r\n"))
|
||||
if err != nil {
|
||||
return "", "", err, false
|
||||
}
|
||||
|
||||
_, err = conn.Read(buf)
|
||||
if err != nil {
|
||||
return "", "", err, false
|
||||
}
|
||||
|
||||
out = out + gbkAsUtf8(string(buf[:]))
|
||||
}
|
||||
|
||||
return out, "", nil, false
|
||||
}
|
||||
|
||||
return job
|
||||
}
|
||||
|
||||
func (j *Job) Status() int {
|
||||
return j.status
|
||||
}
|
||||
@@ -429,3 +514,11 @@ func AllAdminInfo(adminIds string) []*adminInfo {
|
||||
|
||||
return adminInfos
|
||||
}
|
||||
|
||||
func gbkAsUtf8(str string) string {
|
||||
srcDecoder := mahonia.NewDecoder("gbk")
|
||||
desDecoder := mahonia.NewDecoder("utf-8")
|
||||
resStr := srcDecoder.ConvertString(str)
|
||||
_, resBytes, _ := desDecoder.Translate([]byte(resStr), true)
|
||||
return string(resBytes)
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
type TaskServer struct {
|
||||
Id int
|
||||
GroupId int
|
||||
ConnectionType int
|
||||
ServerName string
|
||||
ServerAccount string
|
||||
ServerOuterIp string
|
||||
|
||||
@@ -326,4 +326,8 @@ BEGIN;
|
||||
ALTER TABLE `pp_uc_admin` ADD `wechat` VARCHAR(64) NULL COMMENT '微信' AFTER `dingtalk`;
|
||||
COMMIT;
|
||||
|
||||
BEGIN;
|
||||
ALTER TABLE `pp_task_server` ADD `connection_type` TINYINT(1) NOT NULL DEFAULT '0' COMMENT '连接类型 0:SSH;1:Telnet;' AFTER `group_id`;
|
||||
COMMIT;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
@@ -17,6 +17,16 @@
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux"></div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label mw200">连接类型</label>
|
||||
<div class="layui-input-inline mw400">
|
||||
<input type="radio" name="connection_type" lay-verify="type" value="0" title="SSH" checked>
|
||||
<input type="radio" name="connection_type" lay-verify="type" value="1" title="Telnet" >
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux"></div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label mw200">服务器名称</label>
|
||||
<div class="layui-input-inline mw400">
|
||||
@@ -52,7 +62,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label mw200">端口号</label>
|
||||
<div class="layui-input-inline mw400">
|
||||
<input type="text" name="port" id="port" lay-verify="required" autocomplete="off" placeholder="22" class="layui-input" value="">
|
||||
<input type="text" name="port" id="port" lay-verify="required" autocomplete="off" placeholder="22/23" class="layui-input" value="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux"></div>
|
||||
</div>
|
||||
@@ -160,11 +170,9 @@
|
||||
layer.load();
|
||||
var form_data = $("form").serialize();
|
||||
$.post('{{urlfor "ServerController.AjaxTestServer"}}', form_data, function (out) {
|
||||
layer.closeAll('loading');
|
||||
layer.msg(out.message)
|
||||
}, "json");
|
||||
setTimeout(function(){
|
||||
layer.closeAll('loading');
|
||||
}, 2000);
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
@@ -17,6 +17,16 @@
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux"></div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label mw200">连接类型</label>
|
||||
<div class="layui-input-inline mw400">
|
||||
<input type="radio" name="connection_type" lay-verify="type" value="0" title="SSH" {{if eq .server.connection_type 0}}checked{{end}}>
|
||||
<input type="radio" name="connection_type" lay-verify="type" value="1" title="Telnet" {{if eq .server.connection_type 1}}checked{{end}}>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux"></div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label mw200">服务器名称</label>
|
||||
<div class="layui-input-inline mw400">
|
||||
@@ -157,11 +167,9 @@
|
||||
layer.load();
|
||||
var form_data = $("form").serialize();
|
||||
$.post('{{urlfor "ServerController.AjaxTestServer"}}', form_data, function (out) {
|
||||
layer.closeAll('loading');
|
||||
layer.msg(out.message)
|
||||
}, "json");
|
||||
setTimeout(function(){
|
||||
layer.closeAll('loading');
|
||||
}, 2000);
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
@@ -17,6 +17,16 @@
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux"></div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label mw200">连接类型</label>
|
||||
<div class="layui-input-inline mw400">
|
||||
<input type="radio" name="connection_type" lay-verify="type" value="0" title="SSH" {{if eq .server.connection_type 0}}checked{{end}}>
|
||||
<input type="radio" name="connection_type" lay-verify="type" value="1" title="Telnet" {{if eq .server.connection_type 1}}checked{{end}}>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux"></div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label mw200">服务器名称</label>
|
||||
<div class="layui-input-inline mw400">
|
||||
@@ -158,11 +168,9 @@
|
||||
layer.load();
|
||||
var form_data = $("form").serialize();
|
||||
$.post('{{urlfor "ServerController.AjaxTestServer"}}', form_data, function (out) {
|
||||
layer.closeAll('loading');
|
||||
layer.msg(out.message)
|
||||
}, "json");
|
||||
setTimeout(function(){
|
||||
layer.closeAll('loading');
|
||||
}, 2000);
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
{field:'id', title: 'ID', align:'center',sort: true, width:150}
|
||||
,{field:'server_name',title: '资源名称'}
|
||||
,{field:'group_name',title: '分组名称'}
|
||||
,{field:'connection_type', title: '连接类型'}
|
||||
,{field:'type', title: '登录类型'}
|
||||
,{field:'detail', title: '备注'}
|
||||
// ,{field:'status_text', title: '状态'}
|
||||
|
||||
Reference in New Issue
Block a user