diff --git a/build.sh b/build.sh index 2d71eea..881425b 100644 --- a/build.sh +++ b/build.sh @@ -86,6 +86,8 @@ done rm -rf $TEMP_DIR/$APP_NAME/conf/* rm -rf $TEMP_DIR/$APP_NAME/log/* rm -rf $TEMP_DIR/$APP_NAME/data/sessions/* +rm -rf $TEMP_DIR/$APP_NAME/data/password/* +rm -rf $TEMP_DIR/$APP_NAME/data/private_key/* echo '压缩文件' # 压缩文件 diff --git a/cmd/web.go b/cmd/web.go index d01a0ca..db4afeb 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -9,6 +9,8 @@ import ( "os/signal" "syscall" "github.com/ouqiang/gocron/modules/logger" + "github.com/ouqiang/gocron/service" + "github.com/ouqiang/gocron/models" ) // web服务器默认端口 @@ -37,6 +39,8 @@ func run(ctx *cli.Context) { setEnvironment(ctx) // 初始化应用 app.InitEnv() + // 初始化模块 DB、定时任务等 + initModule() // 捕捉信号,配置热更新等 go catchSignal() m := macaron.Classic() @@ -48,6 +52,14 @@ func run(ctx *cli.Context) { m.Run(port) } +func initModule() { + models.Db = models.CreateDb() + + // 初始化定时任务 + serviceTask := new(service.Task) + serviceTask.Initialize() +} + // 解析端口 func parsePort(ctx *cli.Context) int { var port int = DefaultPort diff --git a/data/ssh/password/.gitkeep b/data/ssh/password/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/ssh/private_key/.gitkeep b/data/ssh/private_key/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/host.go b/models/host.go index a3f1fda..10def5f 100644 --- a/models/host.go +++ b/models/host.go @@ -3,6 +3,12 @@ package models import ( "github.com/ouqiang/gocron/modules/ssh" "github.com/go-xorm/xorm" + "github.com/ouqiang/gocron/modules/app" + "github.com/ouqiang/gocron/modules/utils" + "errors" + "io/ioutil" + "strings" + "github.com/ouqiang/gocron/modules/logger" ) // 主机 @@ -11,11 +17,9 @@ type Host struct { Name string `xorm:"varchar(64) 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"` // 主机端口 Remark string `xorm:"varchar(100) notnull default '' "` // 备注 AuthType ssh.HostAuthType `xorm:"tinyint notnull default 1"` // 认证方式 1: 密码 2: 公钥 - PrivateKey string `xorm:"varchar(4096) notnull default '' "` // 私钥 BaseModel `xorm:"-"` } @@ -30,7 +34,7 @@ func (host *Host) Create() (insertId int16, err error) { } func (host *Host) UpdateBean(id int16) (int64, error) { - return Db.ID(id).Cols("name,alias,username,password,port,remark,auth_type,private_key").Update(host) + return Db.ID(id).Cols("name,alias,username,port,remark,auth_type").Update(host) } @@ -83,6 +87,38 @@ func (host *Host) Total(params CommonMap) (int64, error) { return session.Count(host) } +func (h *Host) GetPasswordByHost(host string) (string, error) { + path := app.DataDir + "/ssh/password/" + host + + + return h.readFile(path) +} + +func (h *Host) GetPrivateKeyByHost(host string) (string,error) { + path := app.DataDir + "/ssh/private_key/" + host + + return h.readFile(path) +} + +func (host *Host) readFile(file string) (string, error) { + logger.Debug("认证文件路径: ", file) + if !utils.FileExist(file) { + return "", errors.New(file + "-认证文件不存在或无权限访问") + } + + contentByte, err := ioutil.ReadFile(file) + if err != nil { + return "", err + } + content := string(contentByte) + content = strings.TrimSpace(content) + if content == "" { + return "", errors.New("密码为空") + } + + return content, nil +} + // 解析where func (host *Host) parseWhere(session *xorm.Session, params CommonMap) { if len(params) == 0 { diff --git a/models/model.go b/models/model.go index 949a713..cbcbb32 100644 --- a/models/model.go +++ b/models/model.go @@ -8,6 +8,9 @@ import ( "gopkg.in/macaron.v1" "strings" "time" + "github.com/ouqiang/gocron/modules/logger" + "github.com/ouqiang/gocron/modules/setting" + "github.com/ouqiang/gocron/modules/app" ) type Status int8 @@ -60,7 +63,8 @@ func (model *BaseModel) pageLimitOffset() int { } // 创建Db -func CreateDb(config map[string]string) *xorm.Engine { +func CreateDb() *xorm.Engine { + config := getDbConfig() dsn := getDbEngineDSN(config["engine"], config) engine, err := xorm.NewEngine(config["engine"], dsn) if err != nil { @@ -115,4 +119,27 @@ func keepDbAlived(engine *xorm.Engine) { <- t engine.Ping() } +} + +// 获取数据库配置 +func getDbConfig() map[string]string { + config, err := setting.Read(app.AppConfig) + if err != nil { + logger.Fatal(err) + } + section := config.Section("db") + if err != nil { + logger.Fatal(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 } \ No newline at end of file diff --git a/models/task.go b/models/task.go index 8683fd0..e1bc9c9 100644 --- a/models/task.go +++ b/models/task.go @@ -40,10 +40,8 @@ type TaskHost struct { Name string Port int Username string - Password string Alias string AuthType ssh.HostAuthType - PrivateKey string } func (TaskHost) TableName() string { @@ -87,7 +85,7 @@ func (task *Task) Enable(id int) (int64, error) { // 获取所有激活任务 func (task *Task) ActiveList() ([]TaskHost, error) { list := make([]TaskHost, 0) - fields := "t.*, host.alias,host.name,host.username,host.password,host.port,host.auth_type,host.private_key" + fields := "t.*, host.alias,host.name,host.username,host.port,host.auth_type" err := Db.Alias("t").Join("LEFT", hostTableName(), "t.host_id=host.id").Where("t.status = ?", Enabled).Cols(fields).Find(&list) return list, err @@ -96,7 +94,7 @@ func (task *Task) ActiveList() ([]TaskHost, error) { // 获取某个主机下的所有激活任务 func (task *Task) ActiveListByHostId(hostId int16) ([]TaskHost, error) { list := make([]TaskHost, 0) - fields := "t.*, host.alias,host.name,host.username,host.password,host.port,host.auth_type,host.private_key" + fields := "t.*, host.alias,host.name,host.username,host.port,host.auth_type" err := Db.Alias("t").Join("LEFT", hostTableName(), "t.host_id=host.id").Where("t.status = ? AND t.host_id = ?", Enabled, hostId).Cols(fields).Find(&list) return list, err @@ -122,7 +120,7 @@ func (task *Task) NameExist(name string, id int) (bool, error) { func(task *Task) Detail(id int) (TaskHost, error) { taskHost := TaskHost{} - fields := "t.*, host.alias,host.name,host.username,host.password,host.port,host.auth_type,host.private_key" + fields := "t.*, host.alias,host.name,host.username,host.port,host.auth_type" _, err := Db.Alias("t").Join("LEFT", hostTableName(), "t.host_id=host.id").Where("t.id=?", id).Cols(fields).Get(&taskHost) return taskHost, err diff --git a/modules/app/app.go b/modules/app/app.go index a18cb23..da9203c 100644 --- a/modules/app/app.go +++ b/modules/app/app.go @@ -3,11 +3,9 @@ package app import ( "os" - "github.com/ouqiang/gocron/models" - "github.com/ouqiang/gocron/service" - "github.com/ouqiang/gocron/modules/setting" "github.com/ouqiang/gocron/modules/logger" "runtime" + "github.com/ouqiang/gocron/modules/utils" ) var ( @@ -33,10 +31,6 @@ func InitEnv() { AppConfig = ConfDir + "/app.ini" checkDirExists(ConfDir, LogDir, DataDir) Installed = IsInstalled() - if Installed { - InitDb() - InitResource() - } } // 判断应用是否安装过 @@ -59,51 +53,11 @@ func CreateInstallLock() error { return err } -// 初始化资源 -func InitResource() { - // 初始化定时任务 - serviceTask := new(service.Task) - serviceTask.Initialize() -} - -// 初始化DB -func InitDb() { - dbConfig := getDbConfig(AppConfig) - models.Db = models.CreateDb(dbConfig) -} - // 检测目录是否存在 func checkDirExists(path ...string) { for _, value := range path { - _, err := os.Stat(value) - if os.IsNotExist(err) { - logger.Fatal(value + "目录不存在") - } - if os.IsPermission(err) { - logger.Fatal(value + "目录无权限操作") + if !utils.FileExist(value) { + logger.Fatal(value + "目录不存在或无权限访问") } } -} - -// 获取数据库配置 -func getDbConfig(configFile string) map[string]string { - config, err := setting.Read(configFile) - if err != nil { - logger.Fatal(err) - } - section := config.Section("db") - if err != nil { - logger.Fatal(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 -} +} \ No newline at end of file diff --git a/modules/utils/utils.go b/modules/utils/utils.go index 150a12c..70c2c19 100644 --- a/modules/utils/utils.go +++ b/modules/utils/utils.go @@ -9,6 +9,7 @@ import ( "runtime" "github.com/Tang-RoseChild/mahonia" "strings" + "os" ) @@ -105,4 +106,16 @@ func EscapeJson(s string) string { replaceChars := []string{ "\\\\", "\\b", "\\f", "\\n", "\\r", "\\t", "\\\"",} return ReplaceStrings(s, specialChars, replaceChars) +} + +func FileExist(file string) bool { + _, err := os.Stat(file) + if os.IsNotExist(err) { + return false + } + if os.IsPermission(err) { + return false + } + + return true } \ No newline at end of file diff --git a/routers/host/host.go b/routers/host/host.go index 0f656ce..f173ad3 100644 --- a/routers/host/host.go +++ b/routers/host/host.go @@ -64,15 +64,28 @@ func Ping(ctx *macaron.Context) string { return json.CommonFailure("主机不存在", err) } - sshConfig := ssh.SSHConfig{ - User: hostModel.Username, - Password: hostModel.Password, - Host: hostModel.Name, - Port: hostModel.Port, - ExecTimeout: 5, - AuthType: hostModel.AuthType, - PrivateKey: hostModel.PrivateKey, + sshConfig := ssh.SSHConfig{} + sshConfig.User = hostModel.Username + sshConfig.Host = hostModel.Name + sshConfig.Port = hostModel.Port + sshConfig.ExecTimeout = 5 + sshConfig.AuthType = hostModel.AuthType + var password string + var privateKey string + if hostModel.AuthType == ssh.HostPassword { + password, err = hostModel.GetPasswordByHost(hostModel.Name) + if err != nil { + return json.CommonFailure(err.Error(), err) + } + sshConfig.Password = password + } else { + privateKey, err = hostModel.GetPrivateKeyByHost(hostModel.Name) + if err != nil { + return json.CommonFailure(err.Error(), err) + } + sshConfig.PrivateKey = privateKey } + _, err = ssh.Exec(sshConfig, "pwd") if err != nil { return json.CommonFailure("连接失败-" + err.Error(), err) @@ -86,10 +99,8 @@ type HostForm struct { Name string `binding:"Required;MaxSize(100)"` Alias string `binding:"Required;MaxSize(32)"` Username string `binding:"Required;MaxSize(32)"` - Password string Port int `binding:"Required;Range(1-65535)"` AuthType ssh.HostAuthType `binding:"Required:Range(1,2)"` - PrivateKey string Remark string } @@ -108,16 +119,9 @@ func Store(ctx *macaron.Context, form HostForm) string { hostModel.Name = form.Name hostModel.Alias = form.Alias hostModel.Username = form.Username - hostModel.Password = form.Password hostModel.Port = form.Port hostModel.Remark = form.Remark - hostModel.PrivateKey = form.PrivateKey hostModel.AuthType = form.AuthType - if hostModel.AuthType == ssh.HostPublicKey { - hostModel.Password = "" - } else { - hostModel.PrivateKey = "" - } isCreate := false if id > 0 { _, err = hostModel.UpdateBean(id) diff --git a/routers/install/install.go b/routers/install/install.go index 2a91e0d..87926ac 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -10,6 +10,7 @@ import ( "github.com/ouqiang/gocron/modules/logger" "github.com/go-macaron/binding" "fmt" + "github.com/ouqiang/gocron/service" ) // 系统安装 @@ -60,7 +61,7 @@ func Store(ctx *macaron.Context, form InstallForm) string { return json.CommonFailure("数据库配置写入文件失败", err) } - app.InitDb() + models.Db = models.CreateDb() // 创建数据库表 migration := new(models.Migration) err = migration.Exec(form.DbName) @@ -81,8 +82,9 @@ func Store(ctx *macaron.Context, form InstallForm) string { } app.Installed = true - // 初始化定时任务等 - app.InitResource() + // 初始化定时任务 + serviceTask := new(service.Task) + serviceTask.Initialize() return json.Success("安装成功", nil) } diff --git a/service/task.go b/service/task.go index 1e2d08c..750156d 100644 --- a/service/task.go +++ b/service/task.go @@ -149,15 +149,33 @@ func (h *HTTPHandler) Run(taskModel models.TaskHost) (result string, err error) type SSHCommandHandler struct{} func (h *SSHCommandHandler) Run(taskModel models.TaskHost) (string, error) { - sshConfig := ssh.SSHConfig{ - User: taskModel.Username, - Password: taskModel.Password, - Host: taskModel.Name, - Port: taskModel.Port, - ExecTimeout: taskModel.Timeout, - AuthType: taskModel.AuthType, - PrivateKey: taskModel.PrivateKey, + hostModel := new(models.Host) + err := hostModel.Find(int(taskModel.HostId)) + if err != nil { + return "", err } + sshConfig := ssh.SSHConfig{} + sshConfig.User = hostModel.Username + sshConfig.Host = hostModel.Name + sshConfig.Port = hostModel.Port + sshConfig.ExecTimeout = 5 + sshConfig.AuthType = hostModel.AuthType + var password string + var privateKey string + if hostModel.AuthType == ssh.HostPassword { + password, err = hostModel.GetPasswordByHost(hostModel.Name) + if err != nil { + return "", err + } + sshConfig.Password = password + } else { + privateKey, err = hostModel.GetPrivateKeyByHost(hostModel.Name) + if err != nil { + return "", err + } + sshConfig.PrivateKey = privateKey + } + return ssh.Exec(sshConfig, taskModel.Command) } diff --git a/templates/host/host_form.html b/templates/host/host_form.html index 994e16c..e2c35fc 100644 --- a/templates/host/host_form.html +++ b/templates/host/host_form.html @@ -43,8 +43,14 @@ -